Merge branch 'master' into development
This commit is contained in:
commit
1155851481
81 changed files with 2357 additions and 974 deletions
55
.travis.yml
55
.travis.yml
|
@ -1,19 +1,45 @@
|
|||
env:
|
||||
global:
|
||||
# keep Arduino IDE version at 1.8.1 until https://github.com/per1234/arduino-ci-script/issues/1 is resolved
|
||||
- ARDUINO_IDE_VERSION="1.8.1"
|
||||
- ARDUINO_IDE_VERSION="1.8.9"
|
||||
matrix:
|
||||
# see https://github.com/arduino/Arduino/blob/master/build/shared/manpage.adoc#options
|
||||
# and https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5-3rd-party-Hardware-specification#boardstxt
|
||||
- BOARD="esp32:esp32:esp32"
|
||||
- BOARD="STM32:stm32:GenF1:pnum=BLUEPILL_F103C6"
|
||||
- BOARD="esp8266:esp8266:generic:xtal=80,ResetMethod=ck,CrystalFreq=26,FlashFreq=40,FlashMode=qio,eesz=512K"
|
||||
- BOARD="arduino:samd:arduino_zero_native"
|
||||
- BOARD="arduino:avr:uno"
|
||||
- BOARD="arduino:avr:leonardo"
|
||||
- BOARD="arduino:avr:mega:cpu=atmega2560"
|
||||
|
||||
before_install:
|
||||
# install Arduino IDE
|
||||
- wget http://downloads.arduino.cc/arduino-$ARDUINO_IDE_VERSION-linux64.tar.xz
|
||||
- wget https://downloads.arduino.cc/arduino-$ARDUINO_IDE_VERSION-linux64.tar.xz
|
||||
- tar xf arduino-$ARDUINO_IDE_VERSION-linux64.tar.xz
|
||||
- mv arduino-$ARDUINO_IDE_VERSION $HOME/arduino-ide
|
||||
- export PATH=$PATH:$HOME/arduino-ide
|
||||
|
||||
# firewall Arduino IDE noise (https://github.com/per1234/arduino-ci-script/issues/1#issuecomment-504158113)
|
||||
- sudo iptables -P INPUT DROP
|
||||
- sudo iptables -P FORWARD DROP
|
||||
- sudo iptables -P OUTPUT ACCEPT
|
||||
- sudo iptables -A INPUT -i lo -j ACCEPT
|
||||
- sudo iptables -A OUTPUT -o lo -j ACCEPT
|
||||
- sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
|
||||
|
||||
# install 3rd party boards
|
||||
- arduino --pref "boardsmanager.additional.urls=http://arduino.esp8266.com/stable/package_esp8266com_index.json,https://dl.espressif.com/dl/package_esp32_index.json,https://github.com/stm32duino/BoardManagerFiles/raw/master/STM32/package_stm_index.json" --save-prefs 2>&1
|
||||
- if [[ "$BOARD" =~ "esp8266:esp8266:" ]]; then
|
||||
arduino --install-boards esp8266:esp8266;
|
||||
export SKIP_PAT='(HTTP|MQTT).*ino';
|
||||
elif [[ "$BOARD" =~ "esp32:esp32:" ]]; then
|
||||
arduino --install-boards esp32:esp32;
|
||||
elif [[ "$BOARD" =~ "STM32:stm32:" ]]; then
|
||||
arduino --install-boards STM32:stm32;
|
||||
elif [[ "$BOARD" =~ "arduino:samd:" ]]; then
|
||||
arduino --install-boards arduino:samd;
|
||||
fi
|
||||
|
||||
# create directory to save the library and create symbolic link
|
||||
install:
|
||||
- mkdir -p $HOME/Arduino/libraries
|
||||
|
@ -26,16 +52,25 @@ branches:
|
|||
|
||||
script:
|
||||
# build all example sketches
|
||||
- for example in $(find $PWD/examples -name '*.ino' | sort); do
|
||||
echo -e "\n\033[1;33mBuilding ${example##*/} ... \033[0m";
|
||||
arduino --verify --board $BOARD $example;
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "\033[1;31m${example##*/} build FAILED\033[0m\n";
|
||||
exit 1;
|
||||
- |
|
||||
for example in $(find $PWD/examples -name '*.ino' | sort); do
|
||||
# check whether to skip this sketch
|
||||
if [ ! -z "$SKIP_PAT" ] && [[ ${example} =~ $SKIP_PAT ]]; then
|
||||
# skip sketch
|
||||
echo -e "\n\033[1;33mSkipped ${example##*/} (matched with $SKIP_PAT)\033[0m";
|
||||
else
|
||||
echo -e "\033[1;32m${example##*/} build PASSED\033[0m\n";
|
||||
# build sketch
|
||||
echo -e "\n\033[1;33mBuilding ${example##*/} ... \033[0m";
|
||||
arduino --verify --board $BOARD $example;
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "\033[1;31m${example##*/} build FAILED\033[0m\n";
|
||||
exit 1;
|
||||
else
|
||||
echo -e "\033[1;32m${example##*/} build PASSED\033[0m\n";
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# generate Doxygen documentation (only for Arduino UNO)
|
||||
- if [ $BOARD = "arduino:avr:uno" ]; then
|
||||
sudo apt-get update;
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
First of all, thank you very much for taking the time to contribute! All feedback and ideas are greatly appreciated.
|
||||
To keep this library organized, please follow these rules.
|
||||
|
||||
## Issues
|
||||
|
||||
The following rules guide submission of new issues. These rules are in place mainly so that the issue author can get help as quickly as possible.
|
||||
|
||||
1. **Questions are welcome, spam is not.**
|
||||
Any issues without description will be considered spam and as such will be **CLOSED** and **LOCKED** immediately!
|
||||
2. **This repository has issue templates.**
|
||||
|
@ -11,3 +15,52 @@ To report bugs or suggest new features, use the provided issue templates. Use th
|
|||
Issues with generic titles (e.g. "not working", "lora", etc.) will be **CLOSED** until the title is fixed, since the title is supposed to categorize the issue. The same applies for issues with very little information and extensive grammatical or formatting errors that make it difficult to find out what is the actual issue.
|
||||
4. **Issues deserve some attention too.**
|
||||
Issues that are left for 2 weeks without response by the original author when asked for further information will be closed due to inactivity. This is to keep track of important issues, the author is encouraged to reopen the issue at a later date.
|
||||
|
||||
## Code style guidelines
|
||||
|
||||
I like pretty code! Or at least, I like *consistent* code style. When creating pull requests, please follow these style guidelines, they're in place to keep high code readability.
|
||||
|
||||
1. **Bracket style**
|
||||
This library uses the following style of bracket indentation (1TBS, or "javascript" style):
|
||||
```c++
|
||||
if (foo) {
|
||||
bar();
|
||||
} else {
|
||||
baz();
|
||||
}
|
||||
```
|
||||
|
||||
2. **Tabs**
|
||||
Use 2 space characters for tabs.
|
||||
|
||||
3. **Single-line comments**
|
||||
Comments can be very useful - and they can become the bane of readability. Every single-line comment should start at new line, have one space between comment delimiter `//` and the start of the comment itself. The comment should also start with a lower-case letter.
|
||||
```c++
|
||||
// this function does something
|
||||
foo("bar");
|
||||
|
||||
// here it does something else
|
||||
foo(12345);
|
||||
```
|
||||
|
||||
4. **Split code into blocks**
|
||||
It is very easy to write code that machine can read. It is much harder to write one that humans can read. That's why it's a great idea to split code into blocks - even if the block is just a single line!
|
||||
```c++
|
||||
// build a temporary buffer (first block)
|
||||
uint8_t* data = new uint8_t[len + 1];
|
||||
if(!data) {
|
||||
return(ERR_MEMORY_ALLOCATION_FAILED);
|
||||
}
|
||||
|
||||
// read the received data (second block)
|
||||
state = readData(data, len);
|
||||
|
||||
// add null terminator (third block)
|
||||
data[len] = 0;
|
||||
```
|
||||
|
||||
5. **Doxygen**
|
||||
If you're adding a new method, make sure to add appropriate Doxygen comments, so that the documentation is always complete.
|
||||
|
||||
6. **Keywords**
|
||||
This is an Arduino library, so it needs to comply with the Arduino library specification. To add a new keyword to the Arduino IDE syntax highlighting, add it to the keywords.txt file. **Use true tabs in keywords.txt! No spaces there!"
|
||||
|
|
51
README.md
51
README.md
|
@ -1,4 +1,49 @@
|
|||
# RadioLib Development
|
||||
### _One radio library to rule them all!_
|
||||
|
||||
## WARNING: Here there be dragons ... and work-in-progress code!
|
||||
Code in this branch is untested, unverified and often incomplete. If you only want to use RadioLib, [master branch](https://github.com/jgromes/RadioLib) is what you're looking for. If you're a contributor (or just curious), feel free to have a look around. Just don't expect the code to work.
|
||||
## Universal wireless communication library for Arduino
|
||||
|
||||
## See the [Wiki](https://github.com/jgromes/RadioLib/wiki) for further information. See the [GitHub Pages](https://jgromes.github.io/RadioLib) for detailed and up-to-date API reference.
|
||||
|
||||
RadioLib allows its users to integrate all sorts of different wireless communication modules into a single consistent system.
|
||||
Want to add a Bluetooth interface to your ZigBee network? Sure thing! Need to connect LoRa network to the Internet with a GSM module? RadioLib has got your back!
|
||||
|
||||
RadioLib was originally created as a driver for [__RadioShield__](https://github.com/jgromes/RadioShield), but it can be used to control as many different wireless modules as you like - or at least as many as your Arduino can handle!
|
||||
|
||||
### Supported modules:
|
||||
* __CC1101__ FSK radio module
|
||||
* __ESP8266__ WiFi module
|
||||
* __HC05__ Bluetooth module
|
||||
* __JDY08__ BLE module
|
||||
* __nRF24L01__ 2.4 GHz module
|
||||
* __RF69__ FSK/OOK radio module
|
||||
* __RFM9x__ series LoRa modules (RFM95, RM96, RFM97, RFM98)
|
||||
* __SX127x__ series LoRa modules (SX1272, SX1273, SX1276, SX1277, SX1278, SX1279)
|
||||
* __SX126x__ series LoRa modules (SX1261, SX1262, SX1268)
|
||||
* __SX1231__ FSK/OOK radio module
|
||||
* __XBee__ modules (S2B)
|
||||
|
||||
### Supported protocols:
|
||||
* __MQTT__ for modules: ESP8266
|
||||
* __HTTP__ for modules: ESP8266
|
||||
* __RTTY__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101 and nRF24L01
|
||||
* __Morse Code__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101 and nRF24L01
|
||||
|
||||
### Supported platforms:
|
||||
* __Arduino AVR boards__ - tested on Uno, Mega and Leonardo
|
||||
* __ESP8266 boards__ - NodeMCU, Wemos D1, etc.
|
||||
* __ESP32 boards__ - tested on ESP-WROOM-32
|
||||
* __STM32 boards__ - tested on BluePill F103C6
|
||||
* __SAMD boards__ - Arduino Zero
|
||||
|
||||
### In development:
|
||||
* __SIM800C__ GSM module
|
||||
* __LoRaWAN__ protocol for SX127x, RFM9x and SX126x modules
|
||||
* ___and more!___
|
||||
|
||||
## Frequently Asked Questions
|
||||
|
||||
### Where should I start?
|
||||
First of all, take a look at the [examples](https://github.com/jgromes/RadioLib/tree/master/examples) and the [Wiki](https://github.com/jgromes/RadioLib/wiki) - especially the [Basics](https://github.com/jgromes/RadioLib/wiki/Basics) page. There's a lot of useful information over there. Also, you should check out [RadioShield](https://github.com/jgromes/RadioShield) - open source Arduino shield that will allow you to easily connect any two wireless modules supported by RadioLib!
|
||||
|
||||
### RadioLib doesn't support my module! What should I do?
|
||||
Start by creating new issue (if it doesn't exist yet). If you have some experience with Arduino and C/C++ in general, you can try to add the support yourself! Use the template files in `/extras/` folder to get started. This is by far the fastest way to implement new modules into RadioLib, since I can't be working on everything all the time. If you don't trust your programming skills enough to have a go at it yourself, don't worry. I will try to implement all requested modules, but it will take me a while.
|
||||
|
|
|
@ -1,15 +1,30 @@
|
|||
/*
|
||||
RadioLib CC1101 Receive Example
|
||||
|
||||
This example receives packets using CC1101 FSK radio
|
||||
module.
|
||||
This example receives packets using CC1101 FSK radio module.
|
||||
To successfully receive data, the following settings have to be the same
|
||||
on both transmitter and receiver:
|
||||
- carrier frequency
|
||||
- bit rate
|
||||
- frequency deviation
|
||||
- sync word
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// CC1101 is in slot A on the shield
|
||||
CC1101 cc = RadioShield.ModuleA;
|
||||
// CC1101 has the following connections:
|
||||
// NSS pin: 10
|
||||
// GDO0 pin: 2
|
||||
// GDO2 pin: 3
|
||||
CC1101 cc = new Module(10, 2, 3);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//CC1101 cc = RadioShield.ModuleA;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
@ -67,5 +82,10 @@ void loop() {
|
|||
// packet was received, but is malformed
|
||||
Serial.println(F("CRC error!"));
|
||||
|
||||
} else {
|
||||
// some other error occurred
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,13 +6,23 @@
|
|||
destination node. After setting node address, this node
|
||||
will automatically filter out any packets that do not
|
||||
contain either node address or broadcast addresses.
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// CC1101 is in slot A on the shield
|
||||
CC1101 cc = RadioShield.ModuleA;
|
||||
// CC1101 has the following connections:
|
||||
// NSS pin: 10
|
||||
// GDO0 pin: 2
|
||||
// GDO2 pin: 3
|
||||
CC1101 cc = new Module(10, 2, 3);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//CC1101 cc = RadioShield.ModuleA;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
@ -102,5 +112,10 @@ void loop() {
|
|||
// packet was received, but is malformed
|
||||
Serial.println(F("CRC error!"));
|
||||
|
||||
} else {
|
||||
// some other error occurred
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,13 +4,30 @@
|
|||
This example listens for FSK transmissions and tries to
|
||||
receive them. Once a packet is received, an interrupt is
|
||||
triggered.
|
||||
|
||||
To successfully receive data, the following settings have to be the same
|
||||
on both transmitter and receiver:
|
||||
- carrier frequency
|
||||
- bit rate
|
||||
- frequency deviation
|
||||
- sync word
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// CC1101 module is in slot A on the shield
|
||||
CC1101 cc = RadioShield.ModuleA;
|
||||
// CC1101 has the following connections:
|
||||
// NSS pin: 10
|
||||
// GDO0 pin: 2
|
||||
// GDO2 pin: 3
|
||||
CC1101 cc = new Module(10, 2, 3);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//CC1101 cc = RadioShield.ModuleA;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
@ -113,6 +130,16 @@ void loop() {
|
|||
// of the last received packet, lower is better
|
||||
Serial.print(F("[CC1101] LQI:\t\t"));
|
||||
Serial.println(cc.getLQI());
|
||||
|
||||
} else if (state == ERR_CRC_MISMATCH) {
|
||||
// packet was received, but is malformed
|
||||
Serial.println(F("CRC error!"));
|
||||
|
||||
} else {
|
||||
// some other error occurred
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
|
||||
}
|
||||
|
||||
// we're ready to receive more packets,
|
||||
|
|
|
@ -10,20 +10,23 @@
|
|||
- allowed frequency deviation
|
||||
- output power during transmission
|
||||
- sync word
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// CC1101 module is in slot A on the shield
|
||||
CC1101 cc1 = RadioShield.ModuleA;
|
||||
// CC1101 has the following connections:
|
||||
// NSS pin: 10
|
||||
// GDO0 pin: 2
|
||||
// GDO2 pin: 3
|
||||
CC1101 cc1 = new Module(10, 2, 3);
|
||||
|
||||
// if you're not using RadioShield, you can specify
|
||||
// the connection yourself
|
||||
// NSS pin: 6
|
||||
// DIO0 pin: 4
|
||||
// DIO1 pin: 5
|
||||
CC1101 cc2 = new Module(6, 4, 5);
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
CC1101 cc2 = RadioShield.ModuleB;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
|
|
@ -2,13 +2,27 @@
|
|||
RadioLib CC1101 Transmit Example
|
||||
|
||||
This example transmits packets using CC1101 FSK radio module.
|
||||
Each packet contains up to 64 bytes of data, in the form of:
|
||||
- Arduino String
|
||||
- null-terminated char array (C-string)
|
||||
- arbitrary binary data (byte array)
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// CC1101 is in slot A on the shield
|
||||
CC1101 cc = RadioShield.ModuleA;
|
||||
// CC1101 has the following connections:
|
||||
// NSS pin: 10
|
||||
// GDO0 pin: 2
|
||||
// GDO2 pin: 3
|
||||
CC1101 cc = new Module(10, 2, 3);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//CC1101 cc = RadioShield.ModuleA;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
@ -44,11 +58,16 @@ void loop() {
|
|||
|
||||
if (state == ERR_NONE) {
|
||||
// the packet was successfully transmitted
|
||||
Serial.println(F(" success!"));
|
||||
Serial.println(F("success!"));
|
||||
|
||||
} else if (state == ERR_PACKET_TOO_LONG) {
|
||||
// the supplied packet was longer than 255 bytes
|
||||
Serial.println(F(" too long!"));
|
||||
// the supplied packet was longer than 64 bytes
|
||||
Serial.println(F("too long!"));
|
||||
|
||||
} else {
|
||||
// some other error occurred
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -6,13 +6,23 @@
|
|||
destination node. After setting node address, this node
|
||||
will automatically filter out any packets that do not
|
||||
contain either node address or broadcast addresses.
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// CC1101 is in slot A on the shield
|
||||
CC1101 cc = RadioShield.ModuleA;
|
||||
// CC1101 has the following connections:
|
||||
// NSS pin: 10
|
||||
// GDO0 pin: 2
|
||||
// GDO2 pin: 3
|
||||
CC1101 cc = new Module(10, 2, 3);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//CC1101 cc = RadioShield.ModuleA;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
@ -86,6 +96,11 @@ void loop() {
|
|||
// the supplied packet was longer than 255 bytes
|
||||
Serial.println(F(" too long!"));
|
||||
|
||||
} else {
|
||||
// some other error occurred
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
|
||||
}
|
||||
|
||||
// wait for a second before transmitting again
|
||||
|
|
|
@ -1,19 +1,32 @@
|
|||
/*
|
||||
RadioLib CC1101 Transmit with Interrupts Example
|
||||
|
||||
This example transmits FSK packets with one second delays
|
||||
between them. Each packet contains up to 64 bytes
|
||||
of data, in the form of:
|
||||
This example transmits packets using CC1101 FSK radio module.
|
||||
Once a packet is transmitted, an interrupt is triggered.
|
||||
Each packet contains up to 64 bytes of data, in the form of:
|
||||
- Arduino String
|
||||
- null-terminated char array (C-string)
|
||||
- arbitrary binary data (byte array)
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// CC1101 module is in slot A on the shield
|
||||
CC1101 cc = RadioShield.ModuleA;
|
||||
// CC1101 has the following connections:
|
||||
// NSS pin: 10
|
||||
// GDO0 pin: 2
|
||||
// GDO2 pin: 3
|
||||
CC1101 cc = new Module(10, 2, 3);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//CC1101 cc = RadioShield.ModuleA;
|
||||
|
||||
// save transmission state between loops
|
||||
int transmissionState = ERR_NONE;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
@ -34,7 +47,7 @@ void setup() {
|
|||
while (true);
|
||||
}
|
||||
|
||||
// set the function that will be called
|
||||
// set the function that will be called
|
||||
// when packet transmission is finished
|
||||
cc.setGdo0Action(setFlag);
|
||||
|
||||
|
@ -43,7 +56,7 @@ void setup() {
|
|||
|
||||
// you can transmit C-string or Arduino string up to
|
||||
// 64 characters long
|
||||
state = cc.startTransmit("Hello World!");
|
||||
transmissionState = cc.startTransmit("Hello World!");
|
||||
|
||||
// you can also transmit byte array up to 64 bytes long
|
||||
/*
|
||||
|
@ -51,47 +64,71 @@ void setup() {
|
|||
0x78, 0xAB, 0xCD, 0xEF};
|
||||
state = cc.transmit(byteArr, 8);
|
||||
*/
|
||||
|
||||
if (state != ERR_NONE) {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
}
|
||||
}
|
||||
|
||||
// flag to indicate that a packet was received
|
||||
// flag to indicate that a packet was sent
|
||||
volatile bool transmittedFlag = false;
|
||||
|
||||
// disable interrupt when it's not needed
|
||||
volatile bool enableInterrupt = true;
|
||||
|
||||
// this function is called when a complete packet
|
||||
// is transmitted by the module
|
||||
// IMPORTANT: this function MUST be 'void' type
|
||||
// and MUST NOT have any arguments!
|
||||
void setFlag(void) {
|
||||
// packet transmission is finished, set the flag
|
||||
// check if the interrupt is enabled
|
||||
if(!enableInterrupt) {
|
||||
return;
|
||||
}
|
||||
|
||||
// we sent a packet, set the flag
|
||||
transmittedFlag = true;
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// check if the previous transmission finished
|
||||
if(transmittedFlag) {
|
||||
Serial.println(F("[CC1101] Packet transmission finished!"));
|
||||
// disable the interrupt service routine while
|
||||
// processing the data
|
||||
enableInterrupt = false;
|
||||
|
||||
// wait one second before next transmission
|
||||
// reset flag
|
||||
transmittedFlag = false;
|
||||
|
||||
if (transmissionState == ERR_NONE) {
|
||||
// packet was successfully sent
|
||||
Serial.println(F("transmission finished!"));
|
||||
|
||||
// NOTE: when using interrupt-driven transmit method,
|
||||
// it is not possible to automatically measure
|
||||
// transmission data rate using getDataRate()
|
||||
|
||||
} else {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(transmissionState);
|
||||
|
||||
}
|
||||
|
||||
// wait a second before transmitting again
|
||||
delay(1000);
|
||||
|
||||
// send another packet
|
||||
// send another one
|
||||
Serial.print(F("[CC1101] Sending another packet ... "));
|
||||
|
||||
// you can transmit C-string or Arduino string up to
|
||||
// 64 characters long
|
||||
int state = cc.startTransmit("Hello World!");
|
||||
|
||||
// 256 characters long
|
||||
transmissionState = cc.startTransmit("Hello World!");
|
||||
|
||||
// you can also transmit byte array up to 256 bytes long
|
||||
/*
|
||||
byte byteArr[] = {0x01, 0x23, 0x45, 0x56,
|
||||
0x78, 0xAB, 0xCD, 0xEF};
|
||||
int state = cc.transmit(byteArr, 8);
|
||||
*/
|
||||
|
||||
if (state != ERR_NONE) {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
}
|
||||
}
|
||||
|
||||
// we're ready to send more packets,
|
||||
// enable interrupt service routine
|
||||
enableInterrupt = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,14 +3,23 @@
|
|||
|
||||
This example sends data using HC05 Bluetooth module.
|
||||
HC05 works exactly like a Serial line, data are sent to the paired device.
|
||||
The default pairing code for HC05 is 1234.
|
||||
The default pairing code for HC05 is 1234 or 1111.
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// HC05 module is in slot A on the shield
|
||||
HC05 bluetooth = RadioShield.ModuleA;
|
||||
// HC05 has the following connections:
|
||||
// TX pin: 9
|
||||
// RX pin: 8
|
||||
HC05 bluetooth = new Module(9, 8);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//HC05 bluetooth = RadioShield.ModuleA;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
|
|
@ -8,13 +8,22 @@
|
|||
|
||||
IMPORTANT: Before uploading this example, make sure that the ESP8266 module is running
|
||||
AT firmware (can be found in the /extras folder of the library)!
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// ESP8266 module is in slot A on the shield
|
||||
ESP8266 wifi = RadioShield.ModuleA;
|
||||
// ESP8266 has the following connections:
|
||||
// TX pin: 9
|
||||
// RX pin: 8
|
||||
ESP8266 wifi = new Module(9, 8);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//ESP8266 wifi = RadioShield.ModuleA;
|
||||
|
||||
// create HTTP client instance using the wifi module
|
||||
// the default port used for HTTP is 80
|
||||
|
|
|
@ -1,20 +1,29 @@
|
|||
/*
|
||||
RadioLib HTTP POST Example
|
||||
|
||||
|
||||
This example sends HTTP POST request using ESP8266 WiFi module.
|
||||
|
||||
|
||||
Please note that the response will be saved including header. HTTP header size
|
||||
can easily exceed Arduino resources and cause the program to behave erratically.
|
||||
|
||||
|
||||
IMPORTANT: Before uploading this example, make sure that the ESP8266 module is running
|
||||
AT firmware (can be found in the /extras folder of the library)!
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// ESP8266 module is in slot A on the shield
|
||||
ESP8266 wifi = RadioShield.ModuleA;
|
||||
// ESP8266 has the following connections:
|
||||
// TX pin: 9
|
||||
// RX pin: 8
|
||||
ESP8266 wifi = new Module(9, 8);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//ESP8266 wifi = RadioShield.ModuleA;
|
||||
|
||||
// create HTTP client instance using the wifi module
|
||||
// the default port used for HTTP is 80
|
||||
|
@ -22,7 +31,7 @@ HTTPClient http(&wifi, 80);
|
|||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
||||
|
||||
// initialize ESP8266
|
||||
Serial.print(F("[ESP8266] Initializing ... "));
|
||||
// baudrate: 9600 baud
|
||||
|
@ -75,4 +84,3 @@ void loop() {
|
|||
// wait for a second before sending new request
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,13 +2,23 @@
|
|||
RadioLib JDY08 Example
|
||||
|
||||
This example sends data using JDY08 Bluetooth module.
|
||||
JDY08 works exactly like a Serial line, data are sent to the paired device.
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// JDY08 module is in slot A on the shield
|
||||
JDY08 ble = RadioShield.ModuleA;
|
||||
// JDY08 has the following connections:
|
||||
// TX pin: 9
|
||||
// RX pin: 8
|
||||
JDY08 ble = new Module(9, 8);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//JDY08 ble = RadioShield.ModuleA;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
|
|
@ -8,13 +8,22 @@
|
|||
|
||||
IMPORTANT: Before uploading this example, make sure that the ESP8266 module is running
|
||||
AT firmware (can be found in the /extras folder of the library)!
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// ESP8266 module is in slot A on the shield
|
||||
ESP8266 wifi = RadioShield.ModuleA;
|
||||
// ESP8266 has the following connections:
|
||||
// TX pin: 9
|
||||
// RX pin: 8
|
||||
ESP8266 wifi = new Module(9, 8);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//ESP8266 wifi = RadioShield.ModuleA;
|
||||
|
||||
// create MQTT client instance using the wifi module
|
||||
// the default port used for MQTT is 1883
|
||||
|
@ -80,4 +89,3 @@ void loop() {
|
|||
// wait for a second before publishing again
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,13 +8,22 @@
|
|||
|
||||
IMPORTANT: Before uploading this example, make sure that the ESP8266 module is running
|
||||
AT firmware (can be found in the /extras folder of the library)!
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// ESP8266 module is in slot A on the shield
|
||||
ESP8266 wifi = RadioShield.ModuleA;
|
||||
// ESP8266 has the following connections:
|
||||
// TX pin: 9
|
||||
// RX pin: 8
|
||||
ESP8266 wifi = new Module(9, 8);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//ESP8266 wifi = RadioShield.ModuleA;
|
||||
|
||||
// create MQTT client instance using the wifi module
|
||||
// the default port used for MQTT is 1883
|
||||
|
|
|
@ -16,8 +16,15 @@
|
|||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// SX1278 module is in slot A on the shield
|
||||
SX1278 fsk = RadioShield.ModuleA;
|
||||
// SX1278 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO0 pin: 2
|
||||
// DIO1 pin: 3
|
||||
SX1278 fsk = new Module(10, 2, 3);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//SX1278 fsk = RadioShield.ModuleA;
|
||||
|
||||
// create Morse client instance using the FSK module
|
||||
MorseClient morse(&fsk);
|
||||
|
@ -35,6 +42,11 @@ void setup() {
|
|||
// current limit: 100 mA
|
||||
// sync word: 0x2D 0x01
|
||||
int state = fsk.beginFSK();
|
||||
|
||||
// when using one of the non-LoRa modules for Morse code
|
||||
// (RF69, CC1101, etc.), use the basic begin() method
|
||||
// int state = fsk.begin();
|
||||
|
||||
if(state == ERR_NONE) {
|
||||
Serial.println(F("success!"));
|
||||
} else {
|
||||
|
|
|
@ -2,13 +2,29 @@
|
|||
RadioLib RF69 Receive Example
|
||||
|
||||
This example receives packets using RF69 FSK radio module.
|
||||
To successfully receive data, the following settings have to be the same
|
||||
on both transmitter and receiver:
|
||||
- carrier frequency
|
||||
- bit rate
|
||||
- frequency deviation
|
||||
- sync word
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// RF69 module is in slot A on the shield
|
||||
RF69 rf = RadioShield.ModuleA;
|
||||
// RF69 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO0 pin: 2
|
||||
// DIO1 pin: 3
|
||||
RF69 rf = new Module(10, 2, 3);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//RF69 rf = RadioShield.ModuleA;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
@ -60,5 +76,10 @@ void loop() {
|
|||
// packet was received, but is malformed
|
||||
Serial.println(F("CRC error!"));
|
||||
|
||||
} else {
|
||||
// some other error occurred
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,13 +4,23 @@
|
|||
This example receives packets using RF69 FSK radio module.
|
||||
Packets are decrypted using hardware AES.
|
||||
NOTE: When using address filtering, the address byte is NOT encrypted!
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// RF69 module is in slot A on the shield
|
||||
RF69 rf = RadioShield.ModuleA;
|
||||
// RF69 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO0 pin: 2
|
||||
// DIO1 pin: 3
|
||||
RF69 rf = new Module(10, 2, 3);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//RF69 rf = RadioShield.ModuleA;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
@ -35,8 +45,7 @@ void setup() {
|
|||
// set AES key that will be used to decrypt the packet
|
||||
// NOTE: the key must be exactly 16 bytes long!
|
||||
uint8_t key[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
|
||||
};
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
|
||||
rf.setAESKey(key);
|
||||
|
||||
// enable AES encryption
|
||||
|
@ -77,5 +86,10 @@ void loop() {
|
|||
// packet was received, but is malformed
|
||||
Serial.println(F("CRC error!"));
|
||||
|
||||
} else {
|
||||
// some other error occurred
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,13 +6,23 @@
|
|||
After setting node (or broadcast) address, this node will
|
||||
automatically filter out any packets that do not contain
|
||||
either node address or broadcast address.
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// RF69 module is in slot A on the shield
|
||||
RF69 rf = RadioShield.ModuleA;
|
||||
// RF69 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO0 pin: 2
|
||||
// DIO1 pin: 3
|
||||
RF69 rf = new Module(10, 2, 3);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//RF69 rf = RadioShield.ModuleA;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
@ -105,5 +115,10 @@ void loop() {
|
|||
// packet was received, but is malformed
|
||||
Serial.println(F("CRC error!"));
|
||||
|
||||
} else {
|
||||
// some other error occurred
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,13 +4,23 @@
|
|||
This example listens for FSK transmissions and tries to
|
||||
receive them. Once a packet is received, an interrupt is
|
||||
triggered.
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// RF69 module is in slot A on the shield
|
||||
RF69 rf = RadioShield.ModuleA;
|
||||
// RF69 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO0 pin: 2
|
||||
// DIO1 pin: 3
|
||||
RF69 rf = new Module(10, 2, 3);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//RF69 rf = RadioShield.ModuleA;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
@ -103,6 +113,16 @@ void loop() {
|
|||
// print data of the packet
|
||||
Serial.print(F("[RF69] Data:\t\t\t"));
|
||||
Serial.println(str);
|
||||
|
||||
} else if (state == ERR_CRC_MISMATCH) {
|
||||
// packet was received, but is malformed
|
||||
Serial.println(F("CRC error!"));
|
||||
|
||||
} else {
|
||||
// some other error occurred
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
|
||||
}
|
||||
|
||||
// we're ready to receive more packets,
|
||||
|
|
|
@ -10,20 +10,23 @@
|
|||
- allowed frequency deviation
|
||||
- output power during transmission
|
||||
- sync word
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// RF69 module is in slot A on the shield
|
||||
RF69 rf1 = RadioShield.ModuleA;
|
||||
// RF69 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO0 pin: 2
|
||||
// DIO1 pin: 3
|
||||
RF69 rf1 = new Module(10, 2, 3);
|
||||
|
||||
// if you're not using RadioShield, you can specify
|
||||
// the connection yourself
|
||||
// NSS pin: 6
|
||||
// DIO0 pin: 4
|
||||
// DIO1 pin: 5
|
||||
RF69 rf2 = new Module(6, 4, 5);
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
RF69 rf2 = RadioShield.ModuleB;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
|
|
@ -2,13 +2,27 @@
|
|||
RadioLib RF69 Transmit Example
|
||||
|
||||
This example transmits packets using RF69 FSK radio module.
|
||||
Each packet contains up to 64 bytes of data, in the form of:
|
||||
- Arduino String
|
||||
- null-terminated char array (C-string)
|
||||
- arbitrary binary data (byte array)
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// RF69 module is in slot A on the shield
|
||||
RF69 rf = RadioShield.ModuleA;
|
||||
// RF69 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO0 pin: 2
|
||||
// DIO1 pin: 3
|
||||
RF69 rf = new Module(10, 2, 3);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//RF69 rf = RadioShield.ModuleA;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
@ -45,11 +59,16 @@ void loop() {
|
|||
|
||||
if (state == ERR_NONE) {
|
||||
// the packet was successfully transmitted
|
||||
Serial.println(F(" success!"));
|
||||
Serial.println(F("success!"));
|
||||
|
||||
} else if (state == ERR_PACKET_TOO_LONG) {
|
||||
// the supplied packet was longer than 64 bytes
|
||||
Serial.println(F(" too long!"));
|
||||
Serial.println(F("too long!"));
|
||||
|
||||
} else {
|
||||
// some other error occurred
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -4,13 +4,23 @@
|
|||
This example transmits packets using RF69 FSK radio module.
|
||||
Packets are encrypted using hardware AES.
|
||||
NOTE: When using address filtering, the address byte is NOT encrypted!
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// RF69 module is in slot A on the shield
|
||||
RF69 rf = RadioShield.ModuleA;
|
||||
// RF69 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO0 pin: 2
|
||||
// DIO1 pin: 3
|
||||
RF69 rf = new Module(10, 2, 3);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//RF69 rf = RadioShield.ModuleA;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
@ -35,8 +45,7 @@ void setup() {
|
|||
// set AES key to encrypt the packet
|
||||
// NOTE: the key must be exactly 16 bytes long!
|
||||
uint8_t key[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
|
||||
};
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
|
||||
rf.setAESKey(key);
|
||||
|
||||
// enable AES encryption
|
||||
|
@ -65,9 +74,14 @@ void loop() {
|
|||
Serial.println(F(" success!"));
|
||||
|
||||
} else if (state == ERR_PACKET_TOO_LONG) {
|
||||
// the supplied packet was longer than 256 bytes
|
||||
// the supplied packet was longer than 64 bytes
|
||||
Serial.println(F(" too long!"));
|
||||
|
||||
} else {
|
||||
// some other error occurred
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
|
||||
}
|
||||
|
||||
// wait for a second before transmitting again
|
||||
|
|
|
@ -6,13 +6,23 @@
|
|||
After setting node (or broadcast) address, this node will
|
||||
automatically filter out any packets that do not contain
|
||||
either node address or broadcast address.
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// RF69 module is in slot A on the shield
|
||||
RF69 rf = RadioShield.ModuleA;
|
||||
// RF69 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO0 pin: 2
|
||||
// DIO1 pin: 3
|
||||
RF69 rf = new Module(10, 2, 3);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//RF69 rf = RadioShield.ModuleA;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
@ -35,7 +45,7 @@ void setup() {
|
|||
}
|
||||
|
||||
// set node address
|
||||
// NOTE: calling this method will autmatically enable
|
||||
// NOTE: calling this method will automatically enable
|
||||
// address filtering (node address only)
|
||||
Serial.print(F("[RF69] Setting node address ... "));
|
||||
state = rf.setNodeAddress(0x01);
|
||||
|
@ -104,9 +114,14 @@ void loop() {
|
|||
Serial.println(F(" success!"));
|
||||
|
||||
} else if (state == ERR_PACKET_TOO_LONG) {
|
||||
// the supplied packet was longer than 256 bytes
|
||||
// the supplied packet was longer than 64 bytes
|
||||
Serial.println(F(" too long!"));
|
||||
|
||||
} else {
|
||||
// some other error occurred
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
|
||||
}
|
||||
|
||||
// wait for a second before transmitting again
|
||||
|
|
|
@ -7,13 +7,26 @@
|
|||
- Arduino String
|
||||
- null-terminated char array (C-string)
|
||||
- arbitrary binary data (byte array)
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// RF69 module is in slot A on the shield
|
||||
RF69 rf = RadioShield.ModuleA;
|
||||
// RF69 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO0 pin: 2
|
||||
// DIO1 pin: 3
|
||||
RF69 rf = new Module(10, 2, 3);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//RF69 rf = RadioShield.ModuleA;
|
||||
|
||||
// save transmission state between loops
|
||||
int transmissionState = ERR_NONE;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
@ -35,7 +48,7 @@ void setup() {
|
|||
while (true);
|
||||
}
|
||||
|
||||
// set the function that will be called
|
||||
// set the function that will be called
|
||||
// when packet transmission is finished
|
||||
rf.setDio0Action(setFlag);
|
||||
|
||||
|
@ -44,7 +57,7 @@ void setup() {
|
|||
|
||||
// you can transmit C-string or Arduino string up to
|
||||
// 64 characters long
|
||||
state = rf.startTransmit("Hello World!");
|
||||
transmissionState = rf.startTransmit("Hello World!");
|
||||
|
||||
// you can also transmit byte array up to 64 bytes long
|
||||
/*
|
||||
|
@ -52,47 +65,71 @@ void setup() {
|
|||
0x78, 0xAB, 0xCD, 0xEF};
|
||||
state = rf.transmit(byteArr, 8);
|
||||
*/
|
||||
|
||||
if (state != ERR_NONE) {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
}
|
||||
}
|
||||
|
||||
// flag to indicate that a packet was received
|
||||
// flag to indicate that a packet was sent
|
||||
volatile bool transmittedFlag = false;
|
||||
|
||||
// disable interrupt when it's not needed
|
||||
volatile bool enableInterrupt = true;
|
||||
|
||||
// this function is called when a complete packet
|
||||
// is transmitted by the module
|
||||
// IMPORTANT: this function MUST be 'void' type
|
||||
// and MUST NOT have any arguments!
|
||||
void setFlag(void) {
|
||||
// packet transmission is finished, set the flag
|
||||
// check if the interrupt is enabled
|
||||
if(!enableInterrupt) {
|
||||
return;
|
||||
}
|
||||
|
||||
// we sent a packet, set the flag
|
||||
transmittedFlag = true;
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// check if the previous transmission finished
|
||||
if(transmittedFlag) {
|
||||
Serial.println(F("[RF69] Packet transmission finished!"));
|
||||
// disable the interrupt service routine while
|
||||
// processing the data
|
||||
enableInterrupt = false;
|
||||
|
||||
// wait one second before next transmission
|
||||
// reset flag
|
||||
transmittedFlag = false;
|
||||
|
||||
if (transmissionState == ERR_NONE) {
|
||||
// packet was successfully sent
|
||||
Serial.println(F("transmission finished!"));
|
||||
|
||||
// NOTE: when using interrupt-driven transmit method,
|
||||
// it is not possible to automatically measure
|
||||
// transmission data rate using getDataRate()
|
||||
|
||||
} else {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(transmissionState);
|
||||
|
||||
}
|
||||
|
||||
// wait a second before transmitting again
|
||||
delay(1000);
|
||||
|
||||
// send another packet
|
||||
// send another one
|
||||
Serial.print(F("[RF69] Sending another packet ... "));
|
||||
|
||||
// you can transmit C-string or Arduino string up to
|
||||
// 64 characters long
|
||||
int state = rf.startTransmit("Hello World!");
|
||||
|
||||
// 256 characters long
|
||||
transmissionState = rf.startTransmit("Hello World!");
|
||||
|
||||
// you can also transmit byte array up to 256 bytes long
|
||||
/*
|
||||
byte byteArr[] = {0x01, 0x23, 0x45, 0x56,
|
||||
0x78, 0xAB, 0xCD, 0xEF};
|
||||
int state = rf.transmit(byteArr, 8);
|
||||
*/
|
||||
|
||||
if (state != ERR_NONE) {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
}
|
||||
}
|
||||
|
||||
// we're ready to send more packets,
|
||||
// enable interrupt service routine
|
||||
enableInterrupt = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,13 +10,24 @@
|
|||
- SX1231
|
||||
- CC1101
|
||||
- SX126x
|
||||
- nRF24
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// SX1278 module is in slot A on the shield
|
||||
SX1278 fsk = RadioShield.ModuleA;
|
||||
// SX1278 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO0 pin: 2
|
||||
// DIO1 pin: 3
|
||||
SX1278 fsk = new Module(10, 2, 3);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//SX1278 fsk = RadioShield.ModuleA;
|
||||
|
||||
// create RTTY client instance using the FSK module
|
||||
RTTYClient rtty(&fsk);
|
||||
|
@ -34,6 +45,11 @@ void setup() {
|
|||
// current limit: 100 mA
|
||||
// sync word: 0x2D 0x01
|
||||
int state = fsk.beginFSK();
|
||||
|
||||
// when using one of the non-LoRa modules for RTTY
|
||||
// (RF69, CC1101, etc.), use the basic begin() method
|
||||
// int state = fsk.begin();
|
||||
|
||||
if(state == ERR_NONE) {
|
||||
Serial.println(F("success!"));
|
||||
} else {
|
||||
|
|
|
@ -6,13 +6,23 @@
|
|||
NOTE: SX1231 offers the same features as RF69 and has the same
|
||||
interface. Please see RF69 examples for examples on AES,
|
||||
address filtering, interrupts and settings.
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// SX1231 module is in slot A on the shield
|
||||
SX1231 rf = RadioShield.ModuleA;
|
||||
// SX1231 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO0 pin: 2
|
||||
// DIO1 pin: 3
|
||||
SX1231 rf = new Module(10, 2, 3);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//SX1231 rf = RadioShield.ModuleA;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
@ -64,5 +74,10 @@ void loop() {
|
|||
// packet was received, but is malformed
|
||||
Serial.println(F("CRC error!"));
|
||||
|
||||
} else {
|
||||
// some other error occurred
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,13 +6,23 @@
|
|||
NOTE: SX1231 offers the same features as RF69 and has the same
|
||||
interface. Please see RF69 examples for examples on AES,
|
||||
address filtering, interrupts and settings.
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// SX1231 module is in slot A on the shield
|
||||
SX1231 rf = RadioShield.ModuleA;
|
||||
// SX1231 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO0 pin: 2
|
||||
// DIO1 pin: 3
|
||||
SX1231 rf = new Module(10, 2, 3);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//SX1231 rf = RadioShield.ModuleA;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
|
|
@ -1,20 +1,30 @@
|
|||
/*
|
||||
RadioLib SX126x Channel Activity Detection Example
|
||||
|
||||
This example scans the current LoRa channel and detects
|
||||
valid LoRa preambles. Preamble is the first part of
|
||||
LoRa transmission, so this can be used to check
|
||||
if the LoRa channel is free, or if you should start
|
||||
receiving a message.
|
||||
This example uses SX1262 to scan the current LoRa
|
||||
channel and detect ongoing LoRa transmissions.
|
||||
Unlike SX127x CAD, SX126x can detect any part
|
||||
of LoRa transmission, not just the preamble.
|
||||
|
||||
Other modules from SX126x family can also be used.
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// SX1262 module is in slot A on the shield
|
||||
SX1262 lora = RadioShield.ModuleA;
|
||||
// SX1262 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO1 pin: 2
|
||||
// DIO2 pin: 3
|
||||
// BUSY pin: 9
|
||||
SX1262 lora = new Module(10, 2, 3, 9);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//SX1262 lora = RadioShield.ModuleA;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
@ -48,11 +58,16 @@ void loop() {
|
|||
|
||||
if (state == LORA_DETECTED) {
|
||||
// LoRa preamble was detected
|
||||
Serial.println(F(" detected!"));
|
||||
Serial.println(F("detected!"));
|
||||
|
||||
} else if (state == CHANNEL_FREE) {
|
||||
// no preamble was detected, channel is free
|
||||
Serial.println(F(" channel is free!"));
|
||||
Serial.println(F("channel is free!"));
|
||||
|
||||
} else {
|
||||
// some other error occurred
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -2,19 +2,30 @@
|
|||
RadioLib SX126x FSK Modem Example
|
||||
|
||||
This example shows how to use FSK modem in SX126x chips.
|
||||
|
||||
|
||||
NOTE: The sketch below is just a guide on how to use
|
||||
FSK modem, so this code should not be run directly!
|
||||
Instead, modify the other examples to use FSK
|
||||
modem and use the appropriate configuration
|
||||
methods.
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// SX1262 module is in slot A on the shield
|
||||
SX1262 fsk = RadioShield.ModuleA;
|
||||
// SX1262 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO1 pin: 2
|
||||
// DIO2 pin: 3
|
||||
// BUSY pin: 9
|
||||
SX1262 fsk = new Module(10, 2, 3, 9);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//SX1262 fsk = RadioShield.ModuleA;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
@ -45,7 +56,7 @@ void setup() {
|
|||
// lora.begin() start LoRa mode (and disable FSK)
|
||||
// lora.beginFSK() start FSK mode (and disable LoRa)
|
||||
|
||||
// the following settings can also
|
||||
// the following settings can also
|
||||
// be modified at run-time
|
||||
state = fsk.setFrequency(433.5);
|
||||
state = fsk.setBitRate(100.0);
|
||||
|
@ -54,7 +65,7 @@ void setup() {
|
|||
state = fsk.setOutputPower(10.0);
|
||||
state = fsk.setCurrentLimit(100.0);
|
||||
state = fsk.setDataShaping(1.0);
|
||||
uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67,
|
||||
uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67,
|
||||
0x89, 0xAB, 0xCD, 0xEF};
|
||||
state = fsk.setSyncWord(syncWord, 8);
|
||||
if (state != ERR_NONE) {
|
||||
|
@ -62,6 +73,13 @@ void setup() {
|
|||
Serial.println(state);
|
||||
while (true);
|
||||
}
|
||||
|
||||
// FSK modem on SX126x can handle the sync word setting in bits, not just
|
||||
// whole bytes. The value used is left-justified.
|
||||
// This makes same result as fsk.setSyncWord(syncWord, 8):
|
||||
state = fsk.setSyncBits(syncWord, 64);
|
||||
// This will use 0x012 as sync word (12 bits only):
|
||||
state = fsk.setSyncBits(syncWord, 12);
|
||||
|
||||
// FSK modem allows advanced CRC configuration
|
||||
// Default is CCIT CRC16 (2 bytes, initial 0x1D0F, polynomial 0x1021, inverted)
|
||||
|
@ -75,7 +93,7 @@ void setup() {
|
|||
void loop() {
|
||||
// FSK modem can use the same transmit/receive methods
|
||||
// as the LoRa modem, even their interrupt-driven versions
|
||||
|
||||
|
||||
// transmit FSK packet
|
||||
int state = fsk.transmit("Hello World!");
|
||||
/*
|
||||
|
@ -116,7 +134,7 @@ void loop() {
|
|||
// it can be enabled by setting node address, broadcast
|
||||
// address, or both
|
||||
//
|
||||
// to transmit packet to a particular address,
|
||||
// to transmit packet to a particular address,
|
||||
// use the following methods:
|
||||
//
|
||||
// fsk.transmit("Hello World!", address);
|
||||
|
|
|
@ -12,13 +12,24 @@
|
|||
- preamble length
|
||||
|
||||
Other modules from SX126x family can also be used.
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// SX1262 module is in slot A on the shield
|
||||
SX1262 lora = RadioShield.ModuleA;
|
||||
// SX1262 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO1 pin: 2
|
||||
// DIO2 pin: 3
|
||||
// BUSY pin: 9
|
||||
SX1262 lora = new Module(10, 2, 3, 9);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//SX1262 lora = RadioShield.ModuleA;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
@ -88,5 +99,10 @@ void loop() {
|
|||
// packet was received, but is malformed
|
||||
Serial.println(F("CRC error!"));
|
||||
|
||||
} else {
|
||||
// some other error occurred
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,13 +13,24 @@
|
|||
- sync word
|
||||
|
||||
Other modules from SX126x/RFM9x family can also be used.
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// SX1262 module is in slot A on the shield
|
||||
SX1262 lora = RadioShield.ModuleA;
|
||||
// SX1262 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO1 pin: 2
|
||||
// DIO2 pin: 3
|
||||
// BUSY pin: 9
|
||||
SX1262 lora = new Module(10, 2, 3, 9);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//SX1262 lora = RadioShield.ModuleA;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
@ -131,6 +142,11 @@ void loop() {
|
|||
// packet was received, but is malformed
|
||||
Serial.println(F("CRC error!"));
|
||||
|
||||
} else {
|
||||
// some other error occurred
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
|
||||
}
|
||||
|
||||
// we're ready to receive more packets,
|
||||
|
|
|
@ -13,29 +13,33 @@
|
|||
- CRC
|
||||
- preamble length
|
||||
- TCXO voltage
|
||||
- DIO2 RF switch control
|
||||
|
||||
Other modules from SX126x family can also be used.
|
||||
Other modules from SX126x family can also be used.
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// SX1268 module is in slot A on the shield
|
||||
SX1268 loraSX1268 = RadioShield.ModuleA;
|
||||
// SX1262 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO1 pin: 2
|
||||
// DIO2 pin: 3
|
||||
// BUSY pin: 9
|
||||
SX1262 loraSX1262 = new Module(10, 2, 3, 9);
|
||||
|
||||
// if you're not using RadioShield, you can specify
|
||||
// the connection yourself
|
||||
// NSS pin: 6
|
||||
// DIO1 pin: 4
|
||||
// DIO2 pin: 5
|
||||
// BUSY pin: 7
|
||||
SX1262 loraSX1262 = new Module(6, 4, 5, 7);
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
SX1268 loraSX1268 = RadioShield.ModuleB;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
||||
// initialize SX1268 with default settings
|
||||
Serial.print(F("[SX1268] Initializing ... "));
|
||||
Serial.print(F("[SX1262] Initializing ... "));
|
||||
// carrier frequency: 434.0 MHz
|
||||
// bandwidth: 125.0 kHz
|
||||
// spreading factor: 9
|
||||
|
@ -45,7 +49,7 @@ void setup() {
|
|||
// current limit: 60 mA
|
||||
// preamble length: 8 symbols
|
||||
// CRC: enabled
|
||||
int state = loraSX1268.begin();
|
||||
int state = loraSX1262.begin();
|
||||
if (state == ERR_NONE) {
|
||||
Serial.println(F("success!"));
|
||||
} else {
|
||||
|
@ -58,7 +62,7 @@ void setup() {
|
|||
// non-default settings
|
||||
// this LoRa link will have high data rate,
|
||||
// but lower range
|
||||
Serial.print(F("[SX1262] Initializing ... "));
|
||||
Serial.print(F("[SX1268] Initializing ... "));
|
||||
// carrier frequency: 915.0 MHz
|
||||
// bandwidth: 500.0 kHz
|
||||
// spreading factor: 6
|
||||
|
@ -68,7 +72,7 @@ void setup() {
|
|||
// current limit: 50 mA
|
||||
// preamble length: 20 symbols
|
||||
// CRC: enabled
|
||||
state = loraSX1262.begin(915.0, 500.0, 6, 5, 0x3444, 50, 20);
|
||||
state = loraSX1268.begin(915.0, 500.0, 6, 5, 0x3444, 50, 20);
|
||||
if (state == ERR_NONE) {
|
||||
Serial.println(F("success!"));
|
||||
} else {
|
||||
|
@ -81,68 +85,76 @@ void setup() {
|
|||
// and check if the configuration was changed successfully
|
||||
|
||||
// set carrier frequency to 433.5 MHz
|
||||
if (loraSX1268.setFrequency(433.5) == ERR_INVALID_FREQUENCY) {
|
||||
if (loraSX1262.setFrequency(433.5) == ERR_INVALID_FREQUENCY) {
|
||||
Serial.println(F("Selected frequency is invalid for this module!"));
|
||||
while (true);
|
||||
}
|
||||
|
||||
// set bandwidth to 250 kHz
|
||||
if (loraSX1268.setBandwidth(250.0) == ERR_INVALID_BANDWIDTH) {
|
||||
if (loraSX1262.setBandwidth(250.0) == ERR_INVALID_BANDWIDTH) {
|
||||
Serial.println(F("Selected bandwidth is invalid for this module!"));
|
||||
while (true);
|
||||
}
|
||||
|
||||
// set spreading factor to 10
|
||||
if (loraSX1268.setSpreadingFactor(10) == ERR_INVALID_SPREADING_FACTOR) {
|
||||
if (loraSX1262.setSpreadingFactor(10) == ERR_INVALID_SPREADING_FACTOR) {
|
||||
Serial.println(F("Selected spreading factor is invalid for this module!"));
|
||||
while (true);
|
||||
}
|
||||
|
||||
// set coding rate to 6
|
||||
if (loraSX1268.setCodingRate(6) == ERR_INVALID_CODING_RATE) {
|
||||
if (loraSX1262.setCodingRate(6) == ERR_INVALID_CODING_RATE) {
|
||||
Serial.println(F("Selected coding rate is invalid for this module!"));
|
||||
while (true);
|
||||
}
|
||||
|
||||
// set LoRa sync word to 0x1234
|
||||
if (loraSX1268.setSyncWord(0x1234) != ERR_NONE) {
|
||||
if (loraSX1262.setSyncWord(0x1234) != ERR_NONE) {
|
||||
Serial.println(F("Unable to set sync word!"));
|
||||
while (true);
|
||||
}
|
||||
|
||||
// set output power to 10 dBm (accepted range is -17 - 22 dBm)
|
||||
if (loraSX1268.setOutputPower(10) == ERR_INVALID_OUTPUT_POWER) {
|
||||
if (loraSX1262.setOutputPower(10) == ERR_INVALID_OUTPUT_POWER) {
|
||||
Serial.println(F("Selected output power is invalid for this module!"));
|
||||
while (true);
|
||||
}
|
||||
|
||||
// set over current protection limit to 80 mA (accepted range is 45 - 240 mA)
|
||||
// NOTE: set value to 0 to disable overcurrent protection
|
||||
if (loraSX1268.setCurrentLimit(80) == ERR_INVALID_CURRENT_LIMIT) {
|
||||
if (loraSX1262.setCurrentLimit(80) == ERR_INVALID_CURRENT_LIMIT) {
|
||||
Serial.println(F("Selected current limit is invalid for this module!"));
|
||||
while (true);
|
||||
}
|
||||
|
||||
// set LoRa preamble length to 15 symbols (accepted range is 0 - 65535)
|
||||
if (loraSX1268.setPreambleLength(15) == ERR_INVALID_PREAMBLE_LENGTH) {
|
||||
if (loraSX1262.setPreambleLength(15) == ERR_INVALID_PREAMBLE_LENGTH) {
|
||||
Serial.println(F("Selected preamble length is invalid for this module!"));
|
||||
while (true);
|
||||
}
|
||||
|
||||
// disable CRC
|
||||
if (loraSX1268.setCRC(false) == ERR_INVALID_CRC_CONFIGURATION) {
|
||||
if (loraSX1262.setCRC(false) == ERR_INVALID_CRC_CONFIGURATION) {
|
||||
Serial.println(F("Selected CRC is invalid for this module!"));
|
||||
while (true);
|
||||
}
|
||||
|
||||
// Some SX126x have TCXO (temperature compensated crystal
|
||||
// Some SX126x modules have TCXO (temperature compensated crystal
|
||||
// oscillator). To configure TCXO reference voltage,
|
||||
// the following method can be used.
|
||||
if (loraSX1268.setTCXO(2.4) == ERR_INVALID_TCXO_VOLTAGE) {
|
||||
if (loraSX1262.setTCXO(2.4) == ERR_INVALID_TCXO_VOLTAGE) {
|
||||
Serial.println(F("Selected TCXO voltage is invalid for this module!"));
|
||||
while (true);
|
||||
}
|
||||
|
||||
// Some SX126x modules use DIO2 as RF switch. To enable
|
||||
// this feature, the following method can be used.
|
||||
// NOTE: As long as DIO2 is configured to control RF switch,
|
||||
// it can't be used as interrupt pin!
|
||||
if (loraSX1262.setDio2AsRfSwitch() != ERR_NONE) {
|
||||
Serial.println(F("Failed to set DIO2 as RF switch!"));
|
||||
while (true);
|
||||
}
|
||||
|
||||
Serial.println(F("All settings succesfully changed!"));
|
||||
}
|
||||
|
|
|
@ -8,13 +8,24 @@
|
|||
- arbitrary binary data (byte array)
|
||||
|
||||
Other modules from SX126x family can also be used.
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// SX1262 module is in slot A on the shield
|
||||
SX1262 lora = RadioShield.ModuleA;
|
||||
// SX1262 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO1 pin: 2
|
||||
// DIO2 pin: 3
|
||||
// BUSY pin: 9
|
||||
SX1262 lora = new Module(10, 2, 3, 9);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//SX1262 lora = RadioShield.ModuleA;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
@ -45,20 +56,22 @@ void setup() {
|
|||
// control must be enabled by calling
|
||||
// setTCXO() and specifying the reference
|
||||
// voltage.
|
||||
|
||||
/*
|
||||
Serial.print(F("[SX1262] Setting TCXO reference ... "));
|
||||
// enable TCXO
|
||||
// reference voltage: 1.6 V
|
||||
// timeout: 5000 us
|
||||
state = lora.setTCXO(1.6);
|
||||
if (state == ERR_NONE) {
|
||||
Serial.println(F("success!"));
|
||||
} else {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
while (true);
|
||||
}
|
||||
Serial.print(F("[SX1262] Setting TCXO reference ... "));
|
||||
// enable TCXO
|
||||
// reference voltage: 1.6 V
|
||||
// timeout: 5000 us
|
||||
state = lora.setTCXO(1.6);
|
||||
if (state == ERR_NONE) {
|
||||
Serial.println(F("success!"));
|
||||
} else {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
while (true);
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
@ -79,7 +92,7 @@ void loop() {
|
|||
|
||||
if (state == ERR_NONE) {
|
||||
// the packet was successfully transmitted
|
||||
Serial.println(F(" success!"));
|
||||
Serial.println(F("success!"));
|
||||
|
||||
// print measured data rate
|
||||
Serial.print(F("[SX1262] Datarate:\t"));
|
||||
|
@ -88,11 +101,16 @@ void loop() {
|
|||
|
||||
} else if (state == ERR_PACKET_TOO_LONG) {
|
||||
// the supplied packet was longer than 256 bytes
|
||||
Serial.println(F(" too long!"));
|
||||
Serial.println(F("too long!"));
|
||||
|
||||
} else if (state == ERR_TX_TIMEOUT) {
|
||||
// timeout occured while transmitting packet
|
||||
Serial.println(F(" timeout!"));
|
||||
Serial.println(F("timeout!"));
|
||||
|
||||
} else {
|
||||
// some other error occurred
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -9,13 +9,23 @@
|
|||
- arbitrary binary data (byte array)
|
||||
|
||||
Other modules from SX126x family can also be used.
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// SX1262 module is in slot A on the shield
|
||||
SX1262 lora = RadioShield.ModuleA;
|
||||
// SX1262 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO1 pin: 2
|
||||
// DIO2 pin: 3
|
||||
// BUSY pin: 9
|
||||
SX1262 lora = new Module(10, 2, 3, 9);
|
||||
|
||||
// save transmission state between loops
|
||||
int transmissionState = ERR_NONE;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
@ -49,7 +59,7 @@ void setup() {
|
|||
|
||||
// you can transmit C-string or Arduino string up to
|
||||
// 256 characters long
|
||||
state = lora.startTransmit("Hello World!");
|
||||
transmissionState = lora.startTransmit("Hello World!");
|
||||
|
||||
// you can also transmit byte array up to 256 bytes long
|
||||
/*
|
||||
|
@ -57,51 +67,71 @@ void setup() {
|
|||
0x78, 0xAB, 0xCD, 0xEF};
|
||||
state = lora.transmit(byteArr, 8);
|
||||
*/
|
||||
|
||||
if (state != ERR_NONE) {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
}
|
||||
}
|
||||
|
||||
// flag to indicate that a packet was received
|
||||
// flag to indicate that a packet was sent
|
||||
volatile bool transmittedFlag = false;
|
||||
|
||||
// disable interrupt when it's not needed
|
||||
volatile bool enableInterrupt = true;
|
||||
|
||||
// this function is called when a complete packet
|
||||
// is transmitted by the module
|
||||
// IMPORTANT: this function MUST be 'void' type
|
||||
// and MUST NOT have any arguments!
|
||||
void setFlag(void) {
|
||||
// packet transmission is finished, set the flag
|
||||
// check if the interrupt is enabled
|
||||
if(!enableInterrupt) {
|
||||
return;
|
||||
}
|
||||
|
||||
// we sent a packet, set the flag
|
||||
transmittedFlag = true;
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// check if the previous transmission finished
|
||||
if(transmittedFlag) {
|
||||
Serial.println(F("packet transmission finished!"));
|
||||
// disable the interrupt service routine while
|
||||
// processing the data
|
||||
enableInterrupt = false;
|
||||
|
||||
// wait one second before next transmission
|
||||
// reset flag
|
||||
transmittedFlag = false;
|
||||
|
||||
if (transmissionState == ERR_NONE) {
|
||||
// packet was successfully sent
|
||||
Serial.println(F("transmission finished!"));
|
||||
|
||||
// NOTE: when using interrupt-driven transmit method,
|
||||
// it is not possible to automatically measure
|
||||
// transmission data rate using getDataRate()
|
||||
|
||||
} else {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(transmissionState);
|
||||
|
||||
}
|
||||
|
||||
// wait a second before transmitting again
|
||||
delay(1000);
|
||||
|
||||
// send another packet
|
||||
// send another one
|
||||
Serial.print(F("[SX1262] Sending another packet ... "));
|
||||
|
||||
// you can transmit C-string or Arduino string up to
|
||||
// 256 characters long
|
||||
int state = lora.startTransmit("Hello World!");
|
||||
transmissionState = lora.startTransmit("Hello World!");
|
||||
|
||||
// you can also transmit byte array up to 256 bytes long
|
||||
/*
|
||||
byte byteArr[] = {0x01, 0x23, 0x45, 0x56,
|
||||
0x78, 0xAB, 0xCD, 0xEF};
|
||||
int state = lora.startTransmit(byteArr, 8);
|
||||
int state = lora.transmit(byteArr, 8);
|
||||
*/
|
||||
|
||||
// NOTE: when using interrupt-driven transmit method,
|
||||
// it is not possible to automatically measure
|
||||
// transmission data rate using getDataRate()
|
||||
|
||||
if (state != ERR_NONE) {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
}
|
||||
// we're ready to send more packets,
|
||||
// enable interrupt service routine
|
||||
enableInterrupt = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,13 +8,23 @@
|
|||
receiving a message.
|
||||
|
||||
Other modules from SX127x/RFM9x family can also be used.
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// SX1278 module is in slot A on the shield
|
||||
SX1278 lora = RadioShield.ModuleA;
|
||||
// SX1278 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO0 pin: 2
|
||||
// DIO1 pin: 3
|
||||
SX1278 lora = new Module(10, 2, 3);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//SX1278 lora = RadioShield.ModuleA;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
|
|
@ -8,13 +8,23 @@
|
|||
Instead, modify the other examples to use FSK
|
||||
modem and use the appropriate configuration
|
||||
methods.
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// SX1278 module is in slot A on the shield
|
||||
SX1278 fsk = RadioShield.ModuleA;
|
||||
// SX1278 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO0 pin: 2
|
||||
// DIO1 pin: 3
|
||||
SX1278 fsk = new Module(10, 2, 3);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//SX1278 fsk = RadioShield.ModuleA;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
|
|
@ -12,13 +12,23 @@
|
|||
- preamble length
|
||||
|
||||
Other modules from SX127x/RFM9x family can also be used.
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// SX1278 module is in slot A on the shield
|
||||
SX1278 lora = RadioShield.ModuleA;
|
||||
// SX1278 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO0 pin: 2
|
||||
// DIO1 pin: 3
|
||||
SX1278 lora = new Module(10, 2, 3);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//SX1278 lora = RadioShield.ModuleA;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
@ -65,24 +75,24 @@ void loop() {
|
|||
Serial.println(F("success!"));
|
||||
|
||||
// print the data of the packet
|
||||
Serial.print(F("[SX1278] Data:\t\t"));
|
||||
Serial.print(F("[SX1278] Data:\t\t\t"));
|
||||
Serial.println(str);
|
||||
|
||||
// print the RSSI (Received Signal Strength Indicator)
|
||||
// of the last received packet
|
||||
Serial.print(F("[SX1278] RSSI:\t\t"));
|
||||
Serial.print(F("[SX1278] RSSI:\t\t\t"));
|
||||
Serial.print(lora.getRSSI());
|
||||
Serial.println(F(" dBm"));
|
||||
|
||||
// print the SNR (Signal-to-Noise Ratio)
|
||||
// of the last received packet
|
||||
Serial.print(F("[SX1278] SNR:\t\t"));
|
||||
Serial.print(F("[SX1278] SNR:\t\t\t"));
|
||||
Serial.print(lora.getSNR());
|
||||
Serial.println(F(" dBm"));
|
||||
|
||||
// print frequency error
|
||||
// of the last received packet
|
||||
Serial.print(F("Frequency error:\t"));
|
||||
Serial.print(F("[SX1278] Frequency error:\t"));
|
||||
Serial.print(lora.getFrequencyError());
|
||||
Serial.println(F(" Hz"));
|
||||
|
||||
|
@ -94,5 +104,10 @@ void loop() {
|
|||
// packet was received, but is malformed
|
||||
Serial.println(F("CRC error!"));
|
||||
|
||||
} else {
|
||||
// some other error occurred
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,13 +13,23 @@
|
|||
- sync word
|
||||
|
||||
Other modules from SX127x/RFM9x family can also be used.
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// SX1278 module is in slot A on the shield
|
||||
SX1278 lora = RadioShield.ModuleA;
|
||||
// SX1278 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO0 pin: 2
|
||||
// DIO1 pin: 3
|
||||
SX1278 lora = new Module(10, 2, 3);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//SX1278 lora = RadioShield.ModuleA;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
@ -134,7 +144,12 @@ void loop() {
|
|||
|
||||
} else if (state == ERR_CRC_MISMATCH) {
|
||||
// packet was received, but is malformed
|
||||
Serial.println(F("CRC error!"));
|
||||
Serial.println(F("[SX1278] CRC error!"));
|
||||
|
||||
} else {
|
||||
// some other error occurred
|
||||
Serial.print(F("[SX1278] Failed, code "));
|
||||
Serial.println(state);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -12,20 +12,24 @@
|
|||
- output power during transmission
|
||||
|
||||
Other modules from SX127x/RFM9x family can also be used.
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// SX1278 module is in slot A on the shield
|
||||
SX1278 loraSX1278 = RadioShield.ModuleA;
|
||||
// SX1278 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO1 pin: 2
|
||||
// DIO2 pin: 3
|
||||
// BUSY pin: 9
|
||||
SX1278 loraSX1278 = new Module(10, 2, 3, 9);
|
||||
|
||||
// if you're not using RadioShield, you can specify
|
||||
// the connection yourself
|
||||
// NSS pin: 6
|
||||
// DIO1 pin: 4
|
||||
// DIO2 pin: 5
|
||||
SX1272 loraSX1272 = new Module(6, 4, 5);
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
SX1272 loraSX1272 = RadioShield.ModuleB;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
|
|
@ -8,13 +8,23 @@
|
|||
- arbitrary binary data (byte array)
|
||||
|
||||
Other modules from SX127x/RFM9x family can also be used.
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// SX1278 module is in slot A on the shield
|
||||
SX1278 lora = RadioShield.ModuleA;
|
||||
// SX1278 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO0 pin: 2
|
||||
// DIO1 pin: 3
|
||||
SX1278 lora = new Module(10, 2, 3);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//SX1278 lora = RadioShield.ModuleA;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
@ -73,6 +83,11 @@ void loop() {
|
|||
// timeout occured while transmitting packet
|
||||
Serial.println(F(" timeout!"));
|
||||
|
||||
} else {
|
||||
// some other error occurred
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
|
||||
}
|
||||
|
||||
// wait for a second before transmitting again
|
||||
|
|
|
@ -9,13 +9,26 @@
|
|||
- arbitrary binary data (byte array)
|
||||
|
||||
Other modules from SX127x/RFM9x family can also be used.
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// SX1278 module is in slot A on the shield
|
||||
SX1278 lora = RadioShield.ModuleA;
|
||||
// SX1278 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO0 pin: 2
|
||||
// DIO1 pin: 3
|
||||
SX1278 lora = new Module(10, 2, 3);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//SX1278 lora = RadioShield.ModuleA;
|
||||
|
||||
// save transmission state between loops
|
||||
int transmissionState = ERR_NONE;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
@ -49,7 +62,7 @@ void setup() {
|
|||
|
||||
// you can transmit C-string or Arduino string up to
|
||||
// 256 characters long
|
||||
state = lora.startTransmit("Hello World!");
|
||||
transmissionState = lora.startTransmit("Hello World!");
|
||||
|
||||
// you can also transmit byte array up to 256 bytes long
|
||||
/*
|
||||
|
@ -57,35 +70,61 @@ void setup() {
|
|||
0x78, 0xAB, 0xCD, 0xEF};
|
||||
state = lora.transmit(byteArr, 8);
|
||||
*/
|
||||
|
||||
if (state != ERR_NONE) {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
}
|
||||
}
|
||||
|
||||
// flag to indicate that a packet was received
|
||||
// flag to indicate that a packet was sent
|
||||
volatile bool transmittedFlag = false;
|
||||
|
||||
// disable interrupt when it's not needed
|
||||
volatile bool enableInterrupt = true;
|
||||
|
||||
// this function is called when a complete packet
|
||||
// is transmitted by the module
|
||||
// IMPORTANT: this function MUST be 'void' type
|
||||
// and MUST NOT have any arguments!
|
||||
void setFlag(void) {
|
||||
// packet transmission is finished, set the flag
|
||||
// check if the interrupt is enabled
|
||||
if(!enableInterrupt) {
|
||||
return;
|
||||
}
|
||||
|
||||
// we sent a packet, set the flag
|
||||
transmittedFlag = true;
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// check if the previous transmission finished
|
||||
if(transmittedFlag) {
|
||||
Serial.println(F("[SX1278] Packet transmission finished!"));
|
||||
// disable the interrupt service routine while
|
||||
// processing the data
|
||||
enableInterrupt = false;
|
||||
|
||||
// wait one second before next transmission
|
||||
// reset flag
|
||||
transmittedFlag = false;
|
||||
|
||||
if (transmissionState == ERR_NONE) {
|
||||
// packet was successfully sent
|
||||
Serial.println(F("transmission finished!"));
|
||||
|
||||
// NOTE: when using interrupt-driven transmit method,
|
||||
// it is not possible to automatically measure
|
||||
// transmission data rate using getDataRate()
|
||||
|
||||
} else {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(transmissionState);
|
||||
|
||||
}
|
||||
|
||||
// wait a second before transmitting again
|
||||
delay(1000);
|
||||
|
||||
// send another packet
|
||||
// send another one
|
||||
Serial.print(F("[SX1278] Sending another packet ... "));
|
||||
|
||||
// you can transmit C-string or Arduino string up to
|
||||
// 256 characters long
|
||||
int state = lora.startTransmit("Hello World!");
|
||||
transmissionState = lora.startTransmit("Hello World!");
|
||||
|
||||
// you can also transmit byte array up to 256 bytes long
|
||||
/*
|
||||
|
@ -94,14 +133,8 @@ void loop() {
|
|||
int state = lora.transmit(byteArr, 8);
|
||||
*/
|
||||
|
||||
// NOTE: when using interrupt-driven transmit method,
|
||||
// it is not possible to automatically measure
|
||||
// transmission data rate using getDataRate()
|
||||
|
||||
if (state != ERR_NONE) {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
}
|
||||
// we're ready to send more packets,
|
||||
// enable interrupt service routine
|
||||
enableInterrupt = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,13 +6,23 @@
|
|||
|
||||
IMPORTANT: Before uploading this example, make sure that the XBee module
|
||||
is running API ROUTER/ENDPOINT firmware!
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// XBee module is in slot A on the shield
|
||||
XBee bee = RadioShield.ModuleA;
|
||||
// XBee has the following connections:
|
||||
// TX pin: 9
|
||||
// RX pin: 8
|
||||
// RESET pin: 3
|
||||
XBee bee = new Module(9, 8);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//XBee bee = RadioShield.ModuleA;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
|
|
@ -6,13 +6,23 @@
|
|||
|
||||
IMPORTANT: Before uploading this example, make sure that the XBee module
|
||||
is running API COORDINATOR firmware!
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// XBee module is in slot A on the shield
|
||||
XBee bee = RadioShield.ModuleA;
|
||||
// XBee has the following connections:
|
||||
// TX pin: 9
|
||||
// RX pin: 8
|
||||
// RESET pin: 3
|
||||
XBee bee = new Module(9, 8);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//XBee bee = RadioShield.ModuleA;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
|
|
@ -8,13 +8,23 @@
|
|||
|
||||
IMPORTANT: Before uploading this example, make sure that the XBee modules
|
||||
are running AT COORDINATOR and AT ROUTER firmware!
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// XBee module is in slot A on the shield
|
||||
XBeeSerial bee = RadioShield.ModuleA;
|
||||
// XBee has the following connections:
|
||||
// TX pin: 9
|
||||
// RX pin: 8
|
||||
// RESET pin: 3
|
||||
XBeeSerial bee = new Module(9, 8);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//XBeeSerial bee = RadioShield.ModuleA;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
|
|
@ -8,13 +8,23 @@
|
|||
- data rate
|
||||
- transmit pipe on transmitter must match receive pipe
|
||||
on receiver
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// nRF24 is in slot A on the shield
|
||||
nRF24 nrf = RadioShield.ModuleA;
|
||||
// nRF24 has the following connections:
|
||||
// NSS pin: 10
|
||||
// CE pin: 2
|
||||
// IRQ pin: 3
|
||||
nRF24 nrf = new Module(10, 2, 3);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//nRF24 nrf = RadioShield.ModuleA;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
@ -35,7 +45,7 @@ void setup() {
|
|||
}
|
||||
|
||||
// set receive pipe 0 address
|
||||
// NOTE: address width in bytes MUST be equal to the
|
||||
// NOTE: address width in bytes MUST be equal to the
|
||||
// width set in begin() or setAddressWidth()
|
||||
// methods (5 by default)
|
||||
Serial.print(F("[nRF24] Setting address for receive pipe 0 ... "));
|
||||
|
@ -78,5 +88,10 @@ void loop() {
|
|||
// timeout occurred while waiting for a packet
|
||||
Serial.println(F("timeout!"));
|
||||
|
||||
} else {
|
||||
// some other error occurred
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,13 +8,23 @@
|
|||
- arbitrary binary data (byte array)
|
||||
|
||||
Packet delivery is automatically acknowledged by the receiver.
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// nRF24 is in slot A on the shield
|
||||
nRF24 nrf = RadioShield.ModuleA;
|
||||
// nRF24 has the following connections:
|
||||
// NSS pin: 10
|
||||
// CE pin: 2
|
||||
// IRQ pin: 3
|
||||
nRF24 nrf = new Module(10, 2, 3);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//nRF24 nrf = RadioShield.ModuleA;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
@ -74,6 +84,11 @@ void loop() {
|
|||
// timed out while transmitting
|
||||
Serial.println(F("timeout!"));
|
||||
|
||||
} else {
|
||||
// some other error occurred
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
|
||||
}
|
||||
|
||||
// wait for a second before transmitting again
|
||||
|
|
|
@ -104,6 +104,9 @@ setGdo1Action KEYWORD2
|
|||
# SX126x-specific
|
||||
setDio2Action KEYWORD2
|
||||
setTCXO KEYWORD2
|
||||
setDio2AsRfSwitch KEYWORD2
|
||||
getTimeOnAir KEYWORD2
|
||||
setSyncBits KEYWORD2
|
||||
|
||||
# ESP8266
|
||||
join KEYWORD2
|
||||
|
@ -161,7 +164,7 @@ ERR_NONE LITERAL1
|
|||
ERR_UNKNOWN LITERAL1
|
||||
|
||||
ERR_CHIP_NOT_FOUND LITERAL1
|
||||
ERR_EEPROM_NOT_INITIALIZED LITERAL1
|
||||
ERR_MEMORY_ALLOCATION_FAILED LITERAL1
|
||||
ERR_PACKET_TOO_LONG LITERAL1
|
||||
ERR_TX_TIMEOUT LITERAL1
|
||||
ERR_RX_TIMEOUT LITERAL1
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name=RadioLib
|
||||
version=1.0.0
|
||||
version=1.6.1
|
||||
author=Jan Gromes <gromes.jan@gmail.com>
|
||||
maintainer=Jan Gromes <gromes.jan@gmail.com>
|
||||
sentence=Universal wireless communication library for Arduino
|
||||
|
|
|
@ -9,7 +9,11 @@ void ISerial::begin(long speed) {
|
|||
}
|
||||
|
||||
bool ISerial::listen() {
|
||||
#if defined ( ESP32 ) || defined (SAMD_SERIES) || defined (ARDUINO_ARCH_STM32)
|
||||
return true;
|
||||
#else
|
||||
return(_mod->ModuleSerial->listen());
|
||||
#endif
|
||||
}
|
||||
|
||||
void ISerial::end() {
|
||||
|
@ -17,15 +21,27 @@ void ISerial::end() {
|
|||
}
|
||||
|
||||
bool ISerial::isListening() {
|
||||
#if defined( ESP32 ) || defined ( SAMD_SERIES ) || defined (ARDUINO_ARCH_STM32)
|
||||
return true;
|
||||
#else
|
||||
return(_mod->ModuleSerial->isListening());
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ISerial::stopListening() {
|
||||
#if defined( ESP32 ) || defined ( SAMD_SERIES ) || defined (ARDUINO_ARCH_STM32)
|
||||
return true;
|
||||
#else
|
||||
return(_mod->ModuleSerial->stopListening());
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ISerial::overflow() {
|
||||
#if defined( ESP32 ) || defined ( SAMD_SERIES ) || defined (ARDUINO_ARCH_STM32)
|
||||
return false;
|
||||
#else
|
||||
return(_mod->ModuleSerial->overflow());
|
||||
#endif
|
||||
}
|
||||
|
||||
int ISerial::peek() {
|
||||
|
@ -139,4 +155,3 @@ size_t ISerial::println(const Printable& x) {
|
|||
size_t ISerial::println(void) {
|
||||
return(_mod->ModuleSerial->println());
|
||||
}
|
||||
|
|
@ -1,13 +1,17 @@
|
|||
#include "Module.h"
|
||||
|
||||
Module::Module(int rx, int tx) {
|
||||
Module::Module(int rx, int tx, HardwareSerial* useSer) {
|
||||
_cs = -1;
|
||||
_rx = rx;
|
||||
_tx = tx;
|
||||
_int0 = -1;
|
||||
_int1 = -1;
|
||||
|
||||
#if defined(ESP32) || defined(SAMD_SERIES) || defined (ARDUINO_ARCH_STM32)
|
||||
ModuleSerial = useSer;
|
||||
#else
|
||||
ModuleSerial = new SoftwareSerial(_rx, _tx);
|
||||
#endif
|
||||
}
|
||||
|
||||
Module::Module(int cs, int int0, int int1, SPIClass& spi, SPISettings spiSettings) {
|
||||
|
@ -20,7 +24,7 @@ Module::Module(int cs, int int0, int int1, SPIClass& spi, SPISettings spiSetting
|
|||
_spiSettings = spiSettings;
|
||||
}
|
||||
|
||||
Module::Module(int cs, int int0, int int1, int rx, int tx, SPIClass& spi, SPISettings spiSettings) {
|
||||
Module::Module(int cs, int int0, int int1, int rx, int tx, SPIClass& spi, SPISettings spiSettings, HardwareSerial* useSer) {
|
||||
_cs = cs;
|
||||
_rx = rx;
|
||||
_tx = tx;
|
||||
|
@ -29,7 +33,11 @@ Module::Module(int cs, int int0, int int1, int rx, int tx, SPIClass& spi, SPISet
|
|||
_spi = &spi;
|
||||
_spiSettings = spiSettings;
|
||||
|
||||
#if defined(ESP32) || defined(SAMD_SERIES) || defined (ARDUINO_ARCH_STM32)
|
||||
ModuleSerial = useSer;
|
||||
#else
|
||||
ModuleSerial = new SoftwareSerial(_rx, _tx);
|
||||
#endif
|
||||
}
|
||||
|
||||
Module::Module(int cs, int int0, int int1, int int2, SPIClass& spi, SPISettings spiSettings) {
|
||||
|
@ -51,7 +59,11 @@ void Module::init(uint8_t interface, uint8_t gpio) {
|
|||
_spi->begin();
|
||||
break;
|
||||
case USE_UART:
|
||||
#if defined(ESP32)
|
||||
ModuleSerial->begin(baudrate, SERIAL_8N1, _rx, _tx);
|
||||
#else
|
||||
ModuleSerial->begin(baudrate);
|
||||
#endif
|
||||
break;
|
||||
case USE_I2C:
|
||||
break;
|
||||
|
@ -207,17 +219,30 @@ void Module::SPItransfer(uint8_t cmd, uint8_t reg, uint8_t* dataOut, uint8_t* da
|
|||
|
||||
// send SPI register address with access command
|
||||
_spi->transfer(reg | cmd);
|
||||
DEBUG_PRINT(reg | cmd, HEX);
|
||||
DEBUG_PRINT('\t');
|
||||
DEBUG_PRINT(reg | cmd, BIN);
|
||||
DEBUG_PRINT('\t');
|
||||
|
||||
// send data or get response
|
||||
if(cmd == SPIwriteCommand) {
|
||||
for(size_t n = 0; n < numBytes; n++) {
|
||||
_spi->transfer(dataOut[n]);
|
||||
DEBUG_PRINT(dataOut[n], HEX);
|
||||
DEBUG_PRINT('\t');
|
||||
DEBUG_PRINT(dataOut[n], BIN);
|
||||
DEBUG_PRINT('\t');
|
||||
}
|
||||
} else if (cmd == SPIreadCommand) {
|
||||
for(size_t n = 0; n < numBytes; n++) {
|
||||
dataIn[n] = _spi->transfer(0x00);
|
||||
DEBUG_PRINT(dataIn[n], HEX);
|
||||
DEBUG_PRINT('\t');
|
||||
DEBUG_PRINT(dataIn[n], BIN);
|
||||
DEBUG_PRINT('\t');
|
||||
}
|
||||
}
|
||||
DEBUG_PRINTLN();
|
||||
|
||||
// release CS
|
||||
digitalWrite(_cs, HIGH);
|
||||
|
|
24
src/Module.h
24
src/Module.h
|
@ -3,7 +3,10 @@
|
|||
|
||||
#include <SPI.h>
|
||||
//#include <Wire.h>
|
||||
#if defined(ESP32) || defined(SAMD_SERIES) || defined (ARDUINO_ARCH_STM32)
|
||||
#else
|
||||
#include <SoftwareSerial.h>
|
||||
#endif
|
||||
|
||||
#include "TypeDef.h"
|
||||
|
||||
|
@ -22,8 +25,14 @@ class Module {
|
|||
\param tx Arduino pin to be used as Tx pin for SoftwareSerial communication.
|
||||
|
||||
\param rx Arduino pin to be used as Rx pin for SoftwareSerial communication.
|
||||
|
||||
\param serial HardwareSerial to be used on ESP32 and SAMD. Defaults to 1
|
||||
*/
|
||||
Module(int tx, int rx);
|
||||
#if defined(ESP32) || defined(SAMD_SERIES) || defined (ARDUINO_ARCH_STM32)
|
||||
Module(int tx, int rx, HardwareSerial* useSer = &Serial1);
|
||||
#else
|
||||
Module(int tx, int rx, HardwareSerial* useSer = nullptr);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
\brief SPI-based module constructor.
|
||||
|
@ -73,15 +82,26 @@ class Module {
|
|||
\param spi SPI interface to be used. Defaults to Arduino hardware SPI interface, can also use software SPI implementations.
|
||||
|
||||
\param spiSettings SPI interface settings. Defaults to 2 MHz clock, MSB first, mode 0.
|
||||
|
||||
\param serial HardwareSerial to be used on ESP32 and SAMD. Defaults to 1
|
||||
*/
|
||||
Module(int cs, int int0, int int1, int rx, int tx, SPIClass& spi = SPI, SPISettings spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0));
|
||||
#if defined(ESP32) || defined(SAMD_SERIES) || defined (ARDUINO_ARCH_STM32)
|
||||
Module(int cs, int int0, int int1, int rx, int tx, SPIClass& spi = SPI, SPISettings spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0), HardwareSerial* useSer = &Serial1);
|
||||
#else
|
||||
Module(int cs, int int0, int int1, int rx, int tx, SPIClass& spi = SPI, SPISettings spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0), HardwareSerial* useSer = nullptr);
|
||||
#endif
|
||||
|
||||
|
||||
// public member variables
|
||||
|
||||
/*!
|
||||
\brief Internal SoftwareSerial instance.
|
||||
*/
|
||||
#if defined(ESP32) || defined(SAMD_SERIES) || defined (ARDUINO_ARCH_STM32)
|
||||
HardwareSerial* ModuleSerial;
|
||||
#else
|
||||
SoftwareSerial* ModuleSerial;
|
||||
#endif
|
||||
|
||||
/*!
|
||||
\brief Baud rate of SoftwareSerial UART communication. Defaults to 9600 baud.
|
||||
|
|
|
@ -39,7 +39,9 @@
|
|||
#include "Module.h"
|
||||
|
||||
#include "modules/CC1101.h"
|
||||
#ifndef ESP8266
|
||||
#include "modules/ESP8266.h"
|
||||
#endif
|
||||
#include "modules/HC05.h"
|
||||
#include "modules/JDY08.h"
|
||||
#include "modules/nRF24.h"
|
||||
|
@ -68,9 +70,11 @@
|
|||
#include "protocols/PSK.h"
|
||||
|
||||
// transport layer protocols
|
||||
#ifndef ESP8266
|
||||
#include "protocols/TransportLayer.h"
|
||||
#include "protocols/HTTP.h"
|
||||
#include "protocols/MQTT.h"
|
||||
#endif
|
||||
|
||||
// RadioShield pin definitions
|
||||
#define RADIOSHIELD_CS_A 10
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#if ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#error "Unsupported Arduino version (< 1.0.0)"
|
||||
#endif
|
||||
|
||||
//#define RADIOLIB_DEBUG
|
||||
|
@ -71,52 +71,52 @@
|
|||
/*!
|
||||
\brief Use 1 bit stop.
|
||||
*/
|
||||
#define UART_STOPBIT_1 0x01
|
||||
#define RADIOLIB_UART_STOPBIT_1 0x01
|
||||
|
||||
/*!
|
||||
\brief Use 1.5 bit stop.
|
||||
*/
|
||||
#define UART_STOPBIT_1_5 0x02
|
||||
#define RADIOLIB_UART_STOPBIT_1_5 0x02
|
||||
|
||||
/*!
|
||||
\brief Use 2 bit stop.
|
||||
*/
|
||||
#define UART_STOPBIT_2 0x03
|
||||
#define RADIOLIB_UART_STOPBIT_2 0x03
|
||||
|
||||
/*!
|
||||
\brief No parity.
|
||||
*/
|
||||
#define UART_PARITY_NONE 0x00
|
||||
#define RADIOLIB_UART_PARITY_NONE 0x00
|
||||
|
||||
/*!
|
||||
\brief Odd parity.
|
||||
*/
|
||||
#define UART_PARITY_ODD 0x01
|
||||
#define RADIOLIB_UART_PARITY_ODD 0x01
|
||||
|
||||
/*!
|
||||
\brief Even parity.
|
||||
*/
|
||||
#define UART_PARITY_EVEN 0x02
|
||||
#define RADIOLIB_UART_PARITY_EVEN 0x02
|
||||
|
||||
/*!
|
||||
\brief No flow control.
|
||||
*/
|
||||
#define UART_FLOW_NONE 0x00
|
||||
#define RADIOLIB_UART_FLOW_NONE 0x00
|
||||
|
||||
/*!
|
||||
\brief RTS only.
|
||||
*/
|
||||
#define UART_FLOW_RTS 0x01
|
||||
#define RADIOLIB_UART_FLOW_RTS 0x01
|
||||
|
||||
/*!
|
||||
\brief CTS only.
|
||||
*/
|
||||
#define UART_FLOW_CTS 0x02
|
||||
#define RADIOLIB_UART_FLOW_CTS 0x02
|
||||
|
||||
/*!
|
||||
\brief Both RTS and CTS.
|
||||
*/
|
||||
#define UART_FLOW_BOTH 0x03
|
||||
#define RADIOLIB_UART_FLOW_BOTH 0x03
|
||||
|
||||
/*!
|
||||
\}
|
||||
|
@ -139,7 +139,7 @@
|
|||
\brief There was an unexpected, unknown error. If you see this, something went incredibly wrong.
|
||||
Your Arduino may be possessed, contact your local exorcist to resolve this error.
|
||||
*/
|
||||
#define ERR_UNKNOWN -1
|
||||
#define ERR_UNKNOWN -1
|
||||
|
||||
// SX127x/RFM9x status codes
|
||||
|
||||
|
@ -150,9 +150,9 @@
|
|||
#define ERR_CHIP_NOT_FOUND -2
|
||||
|
||||
/*!
|
||||
\brief Deprecated.
|
||||
\brief Failed to allocate memory for temporary buffer. This can be cause by not enough RAM or by passing invalid pointer.
|
||||
*/
|
||||
#define ERR_EEPROM_NOT_INITIALIZED -3
|
||||
#define ERR_MEMORY_ALLOCATION_FAILED -3
|
||||
|
||||
/*!
|
||||
\brief Packet supplied to transmission method was longer than limit.
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
#include "CC1101.h"
|
||||
|
||||
CC1101::CC1101(Module* module) : PhysicalLayer(CC1101_CRYSTAL_FREQ, CC1101_DIV_EXPONENT) {
|
||||
CC1101::CC1101(Module* module) : PhysicalLayer(CC1101_CRYSTAL_FREQ, CC1101_DIV_EXPONENT, CC1101_MAX_PACKET_LENGTH) {
|
||||
_mod = module;
|
||||
_packetLengthQueried = false;
|
||||
}
|
||||
|
||||
int16_t CC1101::begin(float freq, float br, float rxBw, float freqDev, int8_t power) {
|
||||
|
@ -175,7 +176,7 @@ void CC1101::setGdo2Action(void (*func)(void), uint8_t dir) {
|
|||
|
||||
int16_t CC1101::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
|
||||
// check packet length
|
||||
if(len > 63) {
|
||||
if(len > CC1101_MAX_PACKET_LENGTH) {
|
||||
return(ERR_PACKET_TOO_LONG);
|
||||
}
|
||||
|
||||
|
@ -230,7 +231,10 @@ int16_t CC1101::startReceive() {
|
|||
|
||||
int16_t CC1101::readData(uint8_t* data, size_t len) {
|
||||
// get packet length
|
||||
size_t length = SPIreadRegister(CC1101_REG_RXBYTES) - 2;
|
||||
size_t length = len;
|
||||
if(len == CC1101_MAX_PACKET_LENGTH) {
|
||||
length = getPacketLength();
|
||||
}
|
||||
|
||||
// check address filtering
|
||||
uint8_t filter = SPIgetRegValue(CC1101_REG_PKTCTRL1, 1, 0);
|
||||
|
@ -239,12 +243,6 @@ int16_t CC1101::readData(uint8_t* data, size_t len) {
|
|||
}
|
||||
|
||||
// read packet data
|
||||
if(len == 0) {
|
||||
// argument len equal to zero indicates String call, which means dynamically allocated data array
|
||||
// dispose of the original and create a new one
|
||||
delete[] data;
|
||||
data = new uint8_t[length + 1];
|
||||
}
|
||||
SPIreadRegisterBurst(CC1101_REG_FIFO, length, data);
|
||||
|
||||
// read RSSI byte
|
||||
|
@ -260,6 +258,9 @@ int16_t CC1101::readData(uint8_t* data, size_t len) {
|
|||
// flush Rx FIFO
|
||||
SPIsendCommand(CC1101_CMD_FLUSH_RX);
|
||||
|
||||
// clear internal flag so getPacketLength can return the new packet length
|
||||
_packetLengthQueried = false;
|
||||
|
||||
// set mode to standby
|
||||
standby();
|
||||
|
||||
|
@ -474,6 +475,15 @@ uint8_t CC1101::getLQI() {
|
|||
return(_rawLQI);
|
||||
}
|
||||
|
||||
size_t CC1101::getPacketLength(bool update) {
|
||||
if(!_packetLengthQueried && update) {
|
||||
_packetLength = _mod->SPIreadRegister(CC1101_REG_FIFO);
|
||||
_packetLengthQueried = true;
|
||||
}
|
||||
|
||||
return(_packetLength);
|
||||
}
|
||||
|
||||
int16_t CC1101::config() {
|
||||
// enable automatic frequency synthesizer calibration
|
||||
int16_t state = SPIsetRegValue(CC1101_REG_MCSM0, CC1101_FS_AUTOCAL_IDLE_TO_RXTX, 5, 4);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
// CC1101 physical layer properties
|
||||
#define CC1101_CRYSTAL_FREQ 26.0
|
||||
#define CC1101_DIV_EXPONENT 16
|
||||
#define CC1101_MAX_PACKET_LENGTH 63
|
||||
|
||||
// CC1101 SPI commands
|
||||
#define CC1101_CMD_READ 0b10000000
|
||||
|
@ -729,6 +730,15 @@ class CC1101: public PhysicalLayer {
|
|||
*/
|
||||
uint8_t getLQI();
|
||||
|
||||
/*!
|
||||
\brief Query modem for the packet length of received payload.
|
||||
|
||||
\param update Update received packet length. Will return cached value when set to false.
|
||||
|
||||
\returns Length of last received packet in bytes.
|
||||
*/
|
||||
size_t getPacketLength(bool update = true);
|
||||
|
||||
private:
|
||||
Module* _mod;
|
||||
|
||||
|
@ -736,6 +746,9 @@ class CC1101: public PhysicalLayer {
|
|||
uint8_t _rawRSSI;
|
||||
uint8_t _rawLQI;
|
||||
|
||||
size_t _packetLength;
|
||||
bool _packetLengthQueried;
|
||||
|
||||
int16_t config();
|
||||
int16_t directMode();
|
||||
void getExpMant(float target, uint16_t mantOffset, uint8_t divExp, uint8_t expMax, uint8_t& exp, uint8_t& mant);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#ifndef ESP8266
|
||||
#include "ESP8266.h"
|
||||
|
||||
ESP8266::ESP8266(Module* module) {
|
||||
|
@ -9,15 +10,15 @@ int16_t ESP8266::begin(long speed) {
|
|||
_mod->AtLineFeed = "\r\n";
|
||||
_mod->baudrate = speed;
|
||||
_mod->init(USE_UART, INT_NONE);
|
||||
|
||||
|
||||
// empty UART buffer (garbage data)
|
||||
_mod->ATemptyBuffer();
|
||||
|
||||
|
||||
// test AT setup
|
||||
if(!_mod->ATsendCommand("AT")) {
|
||||
return(ERR_AT_FAILED);
|
||||
}
|
||||
|
||||
|
||||
return(ERR_NONE);
|
||||
}
|
||||
|
||||
|
@ -26,10 +27,10 @@ int16_t ESP8266::reset() {
|
|||
if(!_mod->ATsendCommand("AT+RST")) {
|
||||
return(ERR_AT_FAILED);
|
||||
}
|
||||
|
||||
|
||||
// wait for the module to start
|
||||
delay(2000);
|
||||
|
||||
|
||||
// test AT setup
|
||||
uint32_t start = millis();
|
||||
while (millis() - start < 3000) {
|
||||
|
@ -39,7 +40,7 @@ int16_t ESP8266::reset() {
|
|||
return(ERR_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return(ERR_AT_FAILED);
|
||||
}
|
||||
|
||||
|
@ -48,29 +49,29 @@ int16_t ESP8266::join(const char* ssid, const char* password) {
|
|||
if(!_mod->ATsendCommand("AT+CWMODE_CUR=3")) {
|
||||
return(ERR_AT_FAILED);
|
||||
}
|
||||
|
||||
|
||||
// build AT command
|
||||
const char* atStr = "AT+CWJAP_CUR=\"";
|
||||
uint8_t cmdLen = strlen(atStr) + strlen(ssid) + strlen(password) + 4;
|
||||
char* cmd = new char[cmdLen];
|
||||
char* cmd = new char[cmdLen + 1];
|
||||
strcpy(cmd, atStr);
|
||||
strcat(cmd, ssid);
|
||||
strcat(cmd, "\",\"");
|
||||
strcat(cmd, password);
|
||||
strcat(cmd, "\"");
|
||||
|
||||
|
||||
// send command
|
||||
bool res = _mod->ATsendCommand(cmd);
|
||||
delete[] cmd;
|
||||
if(!res) {
|
||||
return(ERR_AT_FAILED);
|
||||
}
|
||||
|
||||
|
||||
// disable multiple connection mode
|
||||
if(!_mod->ATsendCommand("AT+CIPMUX=0")) {
|
||||
return(ERR_AT_FAILED);
|
||||
}
|
||||
|
||||
|
||||
return(ERR_NONE);
|
||||
}
|
||||
|
||||
|
@ -79,14 +80,14 @@ int16_t ESP8266::openTransportConnection(const char* host, const char* protocol,
|
|||
itoa(port, portStr, 10);
|
||||
char tcpKeepAliveStr[6];
|
||||
itoa(tcpKeepAlive, tcpKeepAliveStr, 10);
|
||||
|
||||
|
||||
// build AT command
|
||||
const char* atStr = "AT+CIPSTART=\"";
|
||||
uint8_t cmdLen = strlen(atStr) + strlen(protocol) + strlen(host) + strlen(portStr) + 5;
|
||||
if((strcmp(protocol, "TCP") == 0) && (tcpKeepAlive > 0)) {
|
||||
cmdLen += strlen(tcpKeepAliveStr) + 1;
|
||||
}
|
||||
char* cmd = new char[cmdLen];
|
||||
char* cmd = new char[cmdLen + 1];
|
||||
strcpy(cmd, atStr);
|
||||
strcat(cmd, protocol);
|
||||
strcat(cmd, "\",\"");
|
||||
|
@ -97,14 +98,14 @@ int16_t ESP8266::openTransportConnection(const char* host, const char* protocol,
|
|||
strcat(cmd, ",");
|
||||
strcat(cmd, tcpKeepAliveStr);
|
||||
}
|
||||
|
||||
|
||||
// send command
|
||||
bool res = _mod->ATsendCommand(cmd);
|
||||
delete[] cmd;
|
||||
if(!res) {
|
||||
return(ERR_AT_FAILED);
|
||||
}
|
||||
|
||||
|
||||
return(ERR_NONE);
|
||||
}
|
||||
|
||||
|
@ -121,22 +122,22 @@ int16_t ESP8266::send(const char* data) {
|
|||
char lenStr[8];
|
||||
itoa(strlen(data), lenStr, 10);
|
||||
const char* atStr = "AT+CIPSEND=";
|
||||
char* cmd = new char[strlen(atStr) + strlen(lenStr)];
|
||||
char* cmd = new char[strlen(atStr) + strlen(lenStr) + 1];
|
||||
strcpy(cmd, atStr);
|
||||
strcat(cmd, lenStr);
|
||||
|
||||
|
||||
// send command
|
||||
bool res = _mod->ATsendCommand(cmd);
|
||||
delete[] cmd;
|
||||
if(!res) {
|
||||
return(ERR_AT_FAILED);
|
||||
}
|
||||
|
||||
|
||||
// send data
|
||||
if(!_mod->ATsendCommand(data)) {
|
||||
return(ERR_AT_FAILED);
|
||||
}
|
||||
|
||||
|
||||
return(ERR_NONE);
|
||||
}
|
||||
|
||||
|
@ -145,29 +146,29 @@ int16_t ESP8266::send(uint8_t* data, uint32_t len) {
|
|||
char lenStr[8];
|
||||
itoa(len, lenStr, 10);
|
||||
const char atStr[] = "AT+CIPSEND=";
|
||||
char* cmd = new char[strlen(atStr) + strlen(lenStr)];
|
||||
char* cmd = new char[strlen(atStr) + strlen(lenStr) + 1];
|
||||
strcpy(cmd, atStr);
|
||||
strcat(cmd, lenStr);
|
||||
|
||||
|
||||
// send command
|
||||
bool res = _mod->ATsendCommand(cmd);
|
||||
delete[] cmd;
|
||||
if(!res) {
|
||||
return(ERR_AT_FAILED);
|
||||
}
|
||||
|
||||
|
||||
// send data
|
||||
if(!_mod->ATsendData(data, len)) {
|
||||
return(ERR_AT_FAILED);
|
||||
}
|
||||
|
||||
|
||||
return(ERR_NONE);
|
||||
}
|
||||
|
||||
size_t ESP8266::receive(uint8_t* data, size_t len, uint32_t timeout) {
|
||||
size_t i = 0;
|
||||
uint32_t start = millis();
|
||||
|
||||
|
||||
// wait until the required number of bytes is received or until timeout
|
||||
while((millis() - start < timeout) && (i < len)) {
|
||||
while(_mod->ModuleSerial->available() > 0) {
|
||||
|
@ -180,7 +181,7 @@ size_t ESP8266::receive(uint8_t* data, size_t len, uint32_t timeout) {
|
|||
return(i);
|
||||
}
|
||||
|
||||
uint16_t ESP8266::getNumBytes(uint32_t timeout, size_t minBytes) {
|
||||
size_t ESP8266::getNumBytes(uint32_t timeout, size_t minBytes) {
|
||||
// wait for available data
|
||||
uint32_t start = millis();
|
||||
while(_mod->ModuleSerial->available() < (int16_t)minBytes) {
|
||||
|
@ -188,7 +189,7 @@ uint16_t ESP8266::getNumBytes(uint32_t timeout, size_t minBytes) {
|
|||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// read response
|
||||
char rawStr[20];
|
||||
uint8_t i = 0;
|
||||
|
@ -205,17 +206,18 @@ uint16_t ESP8266::getNumBytes(uint32_t timeout, size_t minBytes) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// get the number of bytes in response
|
||||
char* pch = strtok(rawStr, ",:");
|
||||
if(pch == NULL) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
pch = strtok(NULL, ",:");
|
||||
if(pch == NULL) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
return(atoi(pch));
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#ifndef _RADIOLIB_ESP8266_H
|
||||
#if !defined(_RADIOLIB_ESP8266_H) && !defined(ESP8266)
|
||||
#define _RADIOLIB_ESP8266_H
|
||||
|
||||
#include "Module.h"
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
#include "RF69.h"
|
||||
|
||||
RF69::RF69(Module* module) : PhysicalLayer(RF69_CRYSTAL_FREQ, RF69_DIV_EXPONENT) {
|
||||
RF69::RF69(Module* module) : PhysicalLayer(RF69_CRYSTAL_FREQ, RF69_DIV_EXPONENT, RF69_MAX_PACKET_LENGTH) {
|
||||
_mod = module;
|
||||
_tempOffset = 0;
|
||||
_packetLengthQueried = false;
|
||||
}
|
||||
|
||||
int16_t RF69::begin(float freq, float br, float rxBw, float freqDev, int8_t power) {
|
||||
|
@ -102,7 +103,7 @@ int16_t RF69::transmit(uint8_t* data, size_t len, uint8_t addr) {
|
|||
|
||||
int16_t RF69::receive(uint8_t* data, size_t len) {
|
||||
// start reception
|
||||
int16_t state = startReceive();
|
||||
int16_t state = startReceive(true);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
@ -191,27 +192,31 @@ int16_t RF69::disableAES() {
|
|||
return(_mod->SPIsetRegValue(RF69_REG_PACKET_CONFIG_2, RF69_AES_OFF, 0, 0));
|
||||
}
|
||||
|
||||
int16_t RF69::startReceive() {
|
||||
int16_t RF69::startReceive(bool timeout) {
|
||||
// set mode to standby
|
||||
int16_t state = setMode(RF69_STANDBY);
|
||||
|
||||
// set DIO pin mapping
|
||||
state |= _mod->SPIsetRegValue(RF69_REG_DIO_MAPPING_1, RF69_DIO0_PACK_PAYLOAD_READY, 7, 6);
|
||||
|
||||
// clear interrupt flags
|
||||
clearIRQFlags();
|
||||
|
||||
// disable RX timeouts
|
||||
state |= _mod->SPIsetRegValue(RF69_REG_RX_TIMEOUT_1, RF69_TIMEOUT_RX_START_OFF);
|
||||
state |= _mod->SPIsetRegValue(RF69_REG_RX_TIMEOUT_2, RF69_TIMEOUT_RSSI_THRESH_OFF);
|
||||
// set RX timeouts and DIO pin mapping
|
||||
if(timeout) {
|
||||
state = _mod->SPIsetRegValue(RF69_REG_DIO_MAPPING_1, RF69_DIO0_PACK_PAYLOAD_READY | RF69_DIO1_PACK_TIMEOUT, 7, 4);
|
||||
state |= _mod->SPIsetRegValue(RF69_REG_RX_TIMEOUT_1, RF69_TIMEOUT_RX_START);
|
||||
state |= _mod->SPIsetRegValue(RF69_REG_RX_TIMEOUT_2, RF69_TIMEOUT_RSSI_THRESH);
|
||||
} else {
|
||||
state = _mod->SPIsetRegValue(RF69_REG_DIO_MAPPING_1, RF69_DIO0_PACK_PAYLOAD_READY, 7, 6);
|
||||
state |= _mod->SPIsetRegValue(RF69_REG_RX_TIMEOUT_1, RF69_TIMEOUT_RX_START_OFF);
|
||||
state |= _mod->SPIsetRegValue(RF69_REG_RX_TIMEOUT_2, RF69_TIMEOUT_RSSI_THRESH_OFF);
|
||||
}
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
// clear interrupt flags
|
||||
clearIRQFlags();
|
||||
|
||||
// set mode to receive
|
||||
state = setMode(RF69_RX);
|
||||
state |= _mod->SPIsetRegValue(RF69_REG_TEST_PA1, RF69_PA1_NORMAL);
|
||||
state = _mod->SPIsetRegValue(RF69_REG_TEST_PA1, RF69_PA1_NORMAL);
|
||||
state |= _mod->SPIsetRegValue(RF69_REG_TEST_PA2, RF69_PA2_NORMAL);
|
||||
state |= setMode(RF69_RX);
|
||||
|
||||
return(state);
|
||||
}
|
||||
|
@ -226,7 +231,7 @@ void RF69::setDio1Action(void (*func)(void)) {
|
|||
|
||||
int16_t RF69::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
|
||||
// check packet length
|
||||
if(len > 64) {
|
||||
if(len > RF69_MAX_PACKET_LENGTH) {
|
||||
return(ERR_PACKET_TOO_LONG);
|
||||
}
|
||||
|
||||
|
@ -264,7 +269,10 @@ int16_t RF69::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
|
|||
|
||||
int16_t RF69::readData(uint8_t* data, size_t len) {
|
||||
// get packet length
|
||||
size_t length = _mod->SPIreadRegister(RF69_REG_FIFO);
|
||||
size_t length = len;
|
||||
if(len == RF69_MAX_PACKET_LENGTH) {
|
||||
length = getPacketLength();
|
||||
}
|
||||
|
||||
// check address filtering
|
||||
uint8_t filter = _mod->SPIgetRegValue(RF69_REG_PACKET_CONFIG_1, 2, 1);
|
||||
|
@ -273,12 +281,6 @@ int16_t RF69::readData(uint8_t* data, size_t len) {
|
|||
}
|
||||
|
||||
// read packet data
|
||||
if(len == 0) {
|
||||
// argument len equal to zero indicates String call, which means dynamically allocated data array
|
||||
// dispose of the original and create a new one
|
||||
delete[] data;
|
||||
data = new uint8_t[length + 1];
|
||||
}
|
||||
_mod->SPIreadRegisterBurst(RF69_REG_FIFO, length, data);
|
||||
|
||||
// add terminating null
|
||||
|
@ -287,6 +289,9 @@ int16_t RF69::readData(uint8_t* data, size_t len) {
|
|||
// update RSSI
|
||||
lastPacketRSSI = -1.0 * (_mod->SPIgetRegValue(RF69_REG_RSSI_VALUE)/2.0);
|
||||
|
||||
// clear internal flag so getPacketLength can return the new packet length
|
||||
_packetLengthQueried = false;
|
||||
|
||||
// clear interrupt flags
|
||||
clearIRQFlags();
|
||||
|
||||
|
@ -443,9 +448,9 @@ int16_t RF69::setFrequencyDeviation(float freqDev) {
|
|||
|
||||
// set frequency deviation from carrier frequency
|
||||
uint32_t base = 1;
|
||||
uint32_t FDEV = (freqDev * (base << 19)) / 32000;
|
||||
int16_t state = _mod->SPIsetRegValue(RF69_REG_FDEV_MSB, (FDEV & 0xFF00) >> 8, 5, 0);
|
||||
state |= _mod->SPIsetRegValue(RF69_REG_FDEV_LSB, FDEV & 0x00FF, 7, 0);
|
||||
uint32_t fdev = (freqDev * (base << 19)) / 32000;
|
||||
int16_t state = _mod->SPIsetRegValue(RF69_REG_FDEV_MSB, (fdev & 0xFF00) >> 8, 5, 0);
|
||||
state |= _mod->SPIsetRegValue(RF69_REG_FDEV_LSB, fdev & 0x00FF, 7, 0);
|
||||
|
||||
return(state);
|
||||
}
|
||||
|
@ -556,6 +561,15 @@ int16_t RF69::getTemperature() {
|
|||
return(0 - (rawTemp + _tempOffset));
|
||||
}
|
||||
|
||||
size_t RF69::getPacketLength(bool update) {
|
||||
if(!_packetLengthQueried && update) {
|
||||
_packetLength = _mod->SPIreadRegister(RF69_REG_FIFO);
|
||||
_packetLengthQueried = true;
|
||||
}
|
||||
|
||||
return(_packetLength);
|
||||
}
|
||||
|
||||
int16_t RF69::config() {
|
||||
int16_t state = ERR_NONE;
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
// RF69 physical layer properties
|
||||
#define RF69_CRYSTAL_FREQ 32.0
|
||||
#define RF69_DIV_EXPONENT 19
|
||||
#define RF69_MAX_PACKET_LENGTH 64
|
||||
|
||||
// RF69 register map
|
||||
#define RF69_REG_FIFO 0x00
|
||||
|
@ -580,9 +581,11 @@ class RF69: public PhysicalLayer {
|
|||
/*!
|
||||
\brief Interrupt-driven receive method. GDO0 will be activated when full packet is received.
|
||||
|
||||
\param timeout Enable module-driven timeout. Set to false for listen mode.
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t startReceive();
|
||||
int16_t startReceive(bool timeout = false);
|
||||
|
||||
/*!
|
||||
\brief Reads data received after calling startReceive method.
|
||||
|
@ -694,6 +697,15 @@ class RF69: public PhysicalLayer {
|
|||
*/
|
||||
int16_t getTemperature();
|
||||
|
||||
/*!
|
||||
\brief Query modem for the packet length of received payload.
|
||||
|
||||
\param update Update received packet length. Will return cached value when set to false.
|
||||
|
||||
\returns Length of last received packet in bytes.
|
||||
*/
|
||||
size_t getPacketLength(bool update = true);
|
||||
|
||||
protected:
|
||||
Module* _mod;
|
||||
|
||||
|
@ -701,6 +713,9 @@ class RF69: public PhysicalLayer {
|
|||
float _rxBw;
|
||||
int16_t _tempOffset;
|
||||
|
||||
size_t _packetLength;
|
||||
bool _packetLengthQueried;
|
||||
|
||||
int16_t config();
|
||||
int16_t directMode();
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ SX1262::SX1262(Module* mod) : SX126x(mod) {
|
|||
|
||||
int16_t SX1262::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, int8_t power, float currentLimit, uint16_t preambleLength) {
|
||||
// execute common part
|
||||
int16_t state = SX126x::begin(bw, sf, cr, syncWord, preambleLength);
|
||||
int16_t state = SX126x::begin(bw, sf, cr, syncWord, currentLimit, preambleLength);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
@ -22,18 +22,12 @@ int16_t SX1262::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint16_t syn
|
|||
return(state);
|
||||
}
|
||||
|
||||
// OCP must be configured after PA
|
||||
state = SX126x::setCurrentLimit(currentLimit);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
return(state);
|
||||
}
|
||||
|
||||
int16_t SX1262::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, float currentLimit, uint16_t preambleLength, float dataShaping) {
|
||||
// execute common part
|
||||
int16_t state = SX126x::beginFSK(br, freqDev, rxBw, preambleLength, dataShaping);
|
||||
int16_t state = SX126x::beginFSK(br, freqDev, rxBw, currentLimit, preambleLength, dataShaping);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
@ -49,21 +43,42 @@ int16_t SX1262::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t
|
|||
return(state);
|
||||
}
|
||||
|
||||
// OCP must be configured after PA
|
||||
state = SX126x::setCurrentLimit(currentLimit);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
return(state);
|
||||
}
|
||||
|
||||
int16_t SX1262::setFrequency(float freq) {
|
||||
int16_t SX1262::setFrequency(float freq, bool calibrate) {
|
||||
// check frequency range
|
||||
if((freq < 150.0) || (freq > 960.0)) {
|
||||
return(ERR_INVALID_FREQUENCY);
|
||||
}
|
||||
|
||||
int16_t state = ERR_NONE;
|
||||
|
||||
// calibrate image
|
||||
if(calibrate) {
|
||||
uint8_t data[2];
|
||||
if(freq > 900.0) {
|
||||
data[0] = SX126X_CAL_IMG_902_MHZ_1;
|
||||
data[1] = SX126X_CAL_IMG_902_MHZ_2;
|
||||
} else if(freq > 850.0) {
|
||||
data[0] = SX126X_CAL_IMG_863_MHZ_1;
|
||||
data[1] = SX126X_CAL_IMG_863_MHZ_2;
|
||||
} else if(freq > 770.0) {
|
||||
data[0] = SX126X_CAL_IMG_779_MHZ_1;
|
||||
data[1] = SX126X_CAL_IMG_779_MHZ_2;
|
||||
} else if(freq > 460.0) {
|
||||
data[0] = SX126X_CAL_IMG_470_MHZ_1;
|
||||
data[1] = SX126X_CAL_IMG_470_MHZ_2;
|
||||
} else {
|
||||
data[0] = SX126X_CAL_IMG_430_MHZ_1;
|
||||
data[1] = SX126X_CAL_IMG_430_MHZ_2;
|
||||
}
|
||||
state = SX126x::calibrateImage(data);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
}
|
||||
|
||||
// set frequency
|
||||
return(SX126x::setFrequencyRaw(freq));
|
||||
}
|
||||
|
@ -74,6 +89,13 @@ int16_t SX1262::setOutputPower(int8_t power) {
|
|||
return(ERR_INVALID_OUTPUT_POWER);
|
||||
}
|
||||
|
||||
// get current OCP configuration
|
||||
uint8_t ocp = 0;
|
||||
int16_t state = readRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
// enable high power PA for output power higher than 14 dBm
|
||||
if(power > 13) {
|
||||
SX126x::setPaConfig(0x04, SX126X_PA_CONFIG_SX1262);
|
||||
|
@ -84,5 +106,7 @@ int16_t SX1262::setOutputPower(int8_t power) {
|
|||
// set output power
|
||||
// TODO power ramp time configuration
|
||||
SX126x::setTxParams(power);
|
||||
return(ERR_NONE);
|
||||
|
||||
// restore OCP configuration
|
||||
return(writeRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1));
|
||||
}
|
||||
|
|
|
@ -78,9 +78,11 @@ class SX1262: public SX126x {
|
|||
|
||||
\param freq Carrier frequency to be set in MHz.
|
||||
|
||||
\param calibrate Run image calibration.
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setFrequency(float freq);
|
||||
int16_t setFrequency(float freq, bool calibrate = true);
|
||||
|
||||
/*!
|
||||
\brief Sets output power. Allowed values are in range from -17 to 22 dBm.
|
||||
|
|
101
src/modules/SX1268.cpp
Normal file
101
src/modules/SX1268.cpp
Normal file
|
@ -0,0 +1,101 @@
|
|||
#include "SX1268.h"
|
||||
|
||||
SX1268::SX1268(Module* mod) : SX126x(mod) {
|
||||
|
||||
}
|
||||
|
||||
int16_t SX1268::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, int8_t power, float currentLimit, uint16_t preambleLength) {
|
||||
// execute common part
|
||||
int16_t state = SX126x::begin(bw, sf, cr, syncWord, currentLimit, preambleLength);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
// configure publicly accessible settings
|
||||
state = setFrequency(freq);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
state = setOutputPower(power);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
return(state);
|
||||
}
|
||||
int16_t SX1268::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, float currentLimit, uint16_t preambleLength, float dataShaping) {
|
||||
// execute common part
|
||||
int16_t state = SX126x::beginFSK(br, freqDev, rxBw, currentLimit, preambleLength, dataShaping);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
// configure publicly accessible settings
|
||||
state = setFrequency(freq);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
state = setOutputPower(power);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
return(state);
|
||||
}
|
||||
|
||||
int16_t SX1268::setFrequency(float freq, bool calibrate) {
|
||||
// check frequency range
|
||||
if((freq < 410.0) || (freq > 810.0)) {
|
||||
return(ERR_INVALID_FREQUENCY);
|
||||
}
|
||||
|
||||
int16_t state = ERR_NONE;
|
||||
|
||||
// calibrate image
|
||||
if(calibrate) {
|
||||
uint8_t data[2];
|
||||
if(freq > 770.0) {
|
||||
data[0] = SX126X_CAL_IMG_779_MHZ_1;
|
||||
data[1] = SX126X_CAL_IMG_779_MHZ_2;
|
||||
} else if(freq > 460.0) {
|
||||
data[0] = SX126X_CAL_IMG_470_MHZ_1;
|
||||
data[1] = SX126X_CAL_IMG_470_MHZ_2;
|
||||
} else {
|
||||
data[0] = SX126X_CAL_IMG_430_MHZ_1;
|
||||
data[1] = SX126X_CAL_IMG_430_MHZ_2;
|
||||
}
|
||||
state = SX126x::calibrateImage(data);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
}
|
||||
|
||||
// set frequency
|
||||
return(SX126x::setFrequencyRaw(freq));
|
||||
}
|
||||
|
||||
int16_t SX1268::setOutputPower(int8_t power) {
|
||||
// check allowed power range
|
||||
if(!((power >= -9) && (power <= 22))) {
|
||||
return(ERR_INVALID_OUTPUT_POWER);
|
||||
}
|
||||
|
||||
// get current OCP configuration
|
||||
uint8_t ocp = 0;
|
||||
int16_t state = readRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
// enable high power PA
|
||||
SX126x::setPaConfig(0x04, SX126X_PA_CONFIG_SX1268);
|
||||
|
||||
// set output power
|
||||
// TODO power ramp time configuration
|
||||
SX126x::setTxParams(power);
|
||||
|
||||
// restore OCP configuration
|
||||
return(writeRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1));
|
||||
}
|
|
@ -4,13 +4,93 @@
|
|||
#include "TypeDef.h"
|
||||
#include "Module.h"
|
||||
#include "SX126x.h"
|
||||
#include "SX1262.h"
|
||||
|
||||
//SX126X_CMD_SET_PA_CONFIG
|
||||
#define SX126X_PA_CONFIG_SX1261 0x01
|
||||
#define SX126X_PA_CONFIG_SX1262 0x00
|
||||
#define SX126X_PA_CONFIG_SX1268 0x00
|
||||
|
||||
// TODO: implement SX1268 class
|
||||
using SX1268 = SX1262;
|
||||
/*!
|
||||
\class SX1268
|
||||
|
||||
\brief Derived class for %SX1268 modules.
|
||||
*/
|
||||
class SX1268: public SX126x {
|
||||
public:
|
||||
/*!
|
||||
\brief Default constructor.
|
||||
|
||||
\param mod Instance of Module that will be used to communicate with the radio.
|
||||
*/
|
||||
SX1268(Module* mod);
|
||||
|
||||
// basic methods
|
||||
|
||||
/*!
|
||||
\brief Initialization method for LoRa modem.
|
||||
|
||||
\param freq Carrier frequency in MHz. Defaults to 434.0 MHz.
|
||||
|
||||
\param bw LoRa bandwidth in kHz. Defaults to 125.0 kHz.
|
||||
|
||||
\param sf LoRa spreading factor. Defaults to 9.
|
||||
|
||||
\param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7).
|
||||
|
||||
\param syncWord 2-byte LoRa sync word. Defaults to SX126X_SYNC_WORD_PRIVATE (0x1424).
|
||||
|
||||
\param power Output power in dBm. Defaults to 14 dBm.
|
||||
|
||||
\param currentLimit Current protection limit in mA. Defaults to 60.0 mA.
|
||||
|
||||
\param preambleLength LoRa preamble length in symbols.Defaults to 8 symbols.
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint16_t syncWord = SX126X_SYNC_WORD_PRIVATE, int8_t power = 14, float currentLimit = 60.0, uint16_t preambleLength = 8);
|
||||
|
||||
/*!
|
||||
\brief Initialization method for FSK modem.
|
||||
|
||||
\param freq Carrier frequency in MHz. Defaults to 434.0 MHz.
|
||||
|
||||
\param br FSK bit rate in kbps. Defaults to 48.0 kbps.
|
||||
|
||||
\param freqDev Frequency deviation from carrier frequency in kHz. Defaults to 50.0 kHz.
|
||||
|
||||
\param rxBw Receiver bandwidth in kHz. Defaults to 156.2 kHz.
|
||||
|
||||
\param power Output power in dBm. Defaults to 14 dBm.
|
||||
|
||||
\param currentLimit Current protection limit in mA. Defaults to 60.0 mA.
|
||||
|
||||
\parma preambleLength FSK preamble length in bits. Defaults to 16 bits.
|
||||
|
||||
\param dataShaping Time-bandwidth product of the Gaussian filter to be used for shaping. Defaults to 0.5.
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t beginFSK(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 156.2, int8_t power = 14, float currentLimit = 60.0, uint16_t preambleLength = 16, float dataShaping = 0.5);
|
||||
|
||||
// configuration methods
|
||||
|
||||
/*!
|
||||
\brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz.
|
||||
|
||||
\param freq Carrier frequency to be set in MHz.
|
||||
|
||||
\param calibrate Run image calibration.
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setFrequency(float freq, bool calibrate = true);
|
||||
|
||||
/*!
|
||||
\brief Sets output power. Allowed values are in range from -17 to 22 dBm.
|
||||
|
||||
\param power Output power to be set in dBm.
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setOutputPower(int8_t power);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
#include "SX126x.h"
|
||||
|
||||
SX126x::SX126x(Module* mod) : PhysicalLayer(SX126X_CRYSTAL_FREQ, SX126X_DIV_EXPONENT) {
|
||||
SX126x::SX126x(Module* mod) : PhysicalLayer(SX126X_CRYSTAL_FREQ, SX126X_DIV_EXPONENT, SX126X_MAX_PACKET_LENGTH) {
|
||||
_mod = mod;
|
||||
}
|
||||
|
||||
int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, uint16_t preambleLength) {
|
||||
int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, float currentLimit, uint16_t preambleLength) {
|
||||
// set module properties
|
||||
_mod->init(USE_SPI, INT_BOTH);
|
||||
pinMode(_mod->getRx(), INPUT);
|
||||
|
@ -53,12 +53,23 @@ int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, uint1
|
|||
return(state);
|
||||
}
|
||||
|
||||
state = setCurrentLimit(currentLimit);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
state = setPreambleLength(preambleLength);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
// set publicly accessible settings that are not a part of begin method
|
||||
state = setDio2AsRfSwitch(false);
|
||||
|
||||
return(state);
|
||||
}
|
||||
|
||||
int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleLength, float dataShaping) {
|
||||
int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, float currentLimit, uint16_t preambleLength, float dataShaping) {
|
||||
// set module properties
|
||||
_mod->init(USE_SPI, INT_BOTH);
|
||||
pinMode(_mod->getRx(), INPUT);
|
||||
|
@ -101,6 +112,11 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleL
|
|||
return(state);
|
||||
}
|
||||
|
||||
state = setCurrentLimit(currentLimit);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
state = setDataShaping(dataShaping);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
|
@ -111,9 +127,14 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleL
|
|||
return(state);
|
||||
}
|
||||
|
||||
// set default sync word 0x2D01 - not a beginFSK attribute
|
||||
// set publicly accessible settings that are not a part of begin method
|
||||
uint8_t sync[] = {0x2D, 0x01};
|
||||
state = setSyncWord(sync, 2);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
state = setDio2AsRfSwitch(false);
|
||||
|
||||
return(state);
|
||||
}
|
||||
|
@ -126,7 +147,7 @@ int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) {
|
|||
}
|
||||
|
||||
// check packet length
|
||||
if(len >= 256) {
|
||||
if(len > SX126X_MAX_PACKET_LENGTH) {
|
||||
return(ERR_PACKET_TOO_LONG);
|
||||
}
|
||||
|
||||
|
@ -136,25 +157,11 @@ int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) {
|
|||
uint8_t modem = getPacketType();
|
||||
if(modem == SX126X_PACKET_TYPE_LORA) {
|
||||
// calculate timeout (150% of expected time-on-air)
|
||||
float symbolLength = (float)((uint32_t)(1) << _sf) / (float)_bwKhz;
|
||||
float sfCoeff1 = 4.25;
|
||||
float sfCoeff2 = 8.0;
|
||||
if(_sf == 5 || _sf == 6) {
|
||||
sfCoeff1 = 6.25;
|
||||
sfCoeff2 = 0.0;
|
||||
}
|
||||
uint8_t sfDivisor = 4*_sf;
|
||||
if(symbolLength >= 16.0) {
|
||||
sfDivisor = 4*(_sf - 2);
|
||||
}
|
||||
float nSymbol = _preambleLength + sfCoeff1 + 8 + ceil(max(8.0 * len + (_crcType * 16.0) - 4.0 * _sf + sfCoeff2 + 20.0, 0.0) / sfDivisor) * (_cr + 4);
|
||||
timeout = (uint32_t)(symbolLength * nSymbol * 1500.0);
|
||||
timeout = (float)getTimeOnAir(len) * 1.5;
|
||||
|
||||
} else if(modem == SX126X_PACKET_TYPE_GFSK) {
|
||||
|
||||
// calculate timeout (500% of expected time-on-air)
|
||||
float brBps = ((float)(SX126X_CRYSTAL_FREQ) * 1000000.0 * 32.0) / (float)_br;
|
||||
timeout = (uint32_t)(((len * 8.0) / brBps) * 1000000.0 * 5.0);
|
||||
timeout = (float)getTimeOnAir(len) * 5.0;
|
||||
|
||||
} else {
|
||||
return(ERR_UNKNOWN);
|
||||
|
@ -281,7 +288,7 @@ int16_t SX126x::scanChannel() {
|
|||
}
|
||||
|
||||
// set DIO pin mapping
|
||||
state = setDioIrqParams(SX126X_IRQ_CAD_DETECTED | SX126X_IRQ_CAD_DONE, SX126X_IRQ_CAD_DONE, SX126X_IRQ_CAD_DETECTED);
|
||||
state = setDioIrqParams(SX126X_IRQ_CAD_DETECTED | SX126X_IRQ_CAD_DONE, SX126X_IRQ_CAD_DETECTED | SX126X_IRQ_CAD_DONE);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
@ -299,22 +306,26 @@ int16_t SX126x::scanChannel() {
|
|||
}
|
||||
|
||||
// wait for channel activity detected or timeout
|
||||
while(!digitalRead(_mod->getInt0())) {
|
||||
if(digitalRead(_mod->getInt1())) {
|
||||
clearIrqStatus();
|
||||
return(LORA_DETECTED);
|
||||
}
|
||||
while(!digitalRead(_mod->getInt0()));
|
||||
|
||||
// check CAD result
|
||||
uint16_t cadResult = getIrqStatus();
|
||||
if(cadResult & SX126X_IRQ_CAD_DETECTED) {
|
||||
// detected some LoRa activity
|
||||
clearIrqStatus();
|
||||
return(LORA_DETECTED);
|
||||
} else if(cadResult & SX126X_IRQ_CAD_DONE) {
|
||||
// channel is free
|
||||
clearIrqStatus();
|
||||
return(CHANNEL_FREE);
|
||||
}
|
||||
|
||||
// clear interrupt flags
|
||||
clearIrqStatus();
|
||||
|
||||
return(CHANNEL_FREE);
|
||||
return(ERR_UNKNOWN);
|
||||
}
|
||||
|
||||
int16_t SX126x::sleep() {
|
||||
uint8_t data[] = {SX126X_SLEEP_START_COLD | SX126X_SLEEP_RTC_OFF};
|
||||
int16_t state = SPIwriteCommand(SX126X_CMD_SET_SLEEP, data, 1);
|
||||
int16_t state = SPIwriteCommand(SX126X_CMD_SET_SLEEP, data, 1, false);
|
||||
|
||||
// wait for SX126x to safely enter sleep mode
|
||||
delayMicroseconds(500);
|
||||
|
@ -344,7 +355,7 @@ int16_t SX126x::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
|
|||
(void)addr;
|
||||
|
||||
// check packet length
|
||||
if(len >= 256) {
|
||||
if(len > SX126X_MAX_PACKET_LENGTH) {
|
||||
return(ERR_PACKET_TOO_LONG);
|
||||
}
|
||||
|
||||
|
@ -432,29 +443,17 @@ int16_t SX126x::readData(uint8_t* data, size_t len) {
|
|||
}
|
||||
|
||||
// get packet length
|
||||
uint8_t rxBufStatus[2];
|
||||
int16_t state = SPIreadCommand(SX126X_CMD_GET_RX_BUFFER_STATUS, rxBufStatus, 2);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
size_t length = len;
|
||||
if(len == SX126X_MAX_PACKET_LENGTH) {
|
||||
length = getPacketLength();
|
||||
}
|
||||
|
||||
size_t length = rxBufStatus[0];
|
||||
|
||||
// read packet data
|
||||
if(len == 0) {
|
||||
// argument 'len' equal to zero indicates String call, which means dynamically allocated data array
|
||||
// dispose of the original and create a new one
|
||||
delete[] data;
|
||||
data = new uint8_t[length + 1];
|
||||
}
|
||||
state = readBuffer(data, length);
|
||||
int16_t state = readBuffer(data, length);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
// add terminating null
|
||||
data[length] = 0;
|
||||
|
||||
// clear interrupt flags
|
||||
state = clearIrqStatus();
|
||||
|
||||
|
@ -576,9 +575,9 @@ int16_t SX126x::setFrequencyDeviation(float freqDev) {
|
|||
uint32_t freqDevRaw = (uint32_t)(((freqDev * 1000.0) * (float)((uint32_t)(1) << 25)) / (SX126X_CRYSTAL_FREQ * 1000000.0));
|
||||
|
||||
// check modulation parameters
|
||||
if(2 * freqDevRaw + _br > _rxBwKhz * 1000.0) {
|
||||
/*if(2 * freqDevRaw + _br > _rxBwKhz * 1000.0) {
|
||||
return(ERR_INVALID_MODULATION_PARAMETERS);
|
||||
}
|
||||
}*/
|
||||
_freqDev = freqDevRaw;
|
||||
|
||||
// update modulation parameters
|
||||
|
@ -600,9 +599,9 @@ int16_t SX126x::setBitRate(float br) {
|
|||
uint32_t brRaw = (uint32_t)((SX126X_CRYSTAL_FREQ * 1000000.0 * 32.0) / (br * 1000.0));
|
||||
|
||||
// check modulation parameters
|
||||
if(2 * _freqDev + brRaw > _rxBwKhz * 1000.0) {
|
||||
/*if(2 * _freqDev + brRaw > _rxBwKhz * 1000.0) {
|
||||
return(ERR_INVALID_MODULATION_PARAMETERS);
|
||||
}
|
||||
}*/
|
||||
_br = brRaw;
|
||||
|
||||
// update modulation parameters
|
||||
|
@ -616,9 +615,9 @@ int16_t SX126x::setRxBandwidth(float rxBw) {
|
|||
}
|
||||
|
||||
// check modulation parameters
|
||||
if(2 * _freqDev + _br > rxBw * 1000.0) {
|
||||
/*if(2 * _freqDev + _br > rxBw * 1000.0) {
|
||||
return(ERR_INVALID_MODULATION_PARAMETERS);
|
||||
}
|
||||
}*/
|
||||
_rxBwKhz = rxBw;
|
||||
|
||||
// check alowed receiver bandwidth values
|
||||
|
@ -722,6 +721,35 @@ int16_t SX126x::setSyncWord(uint8_t* syncWord, uint8_t len) {
|
|||
return(state);
|
||||
}
|
||||
|
||||
int16_t SX126x::setSyncBits(uint8_t *syncWord, uint8_t bitsLen) {
|
||||
// check active modem
|
||||
if(getPacketType() != SX126X_PACKET_TYPE_GFSK) {
|
||||
return(ERR_WRONG_MODEM);
|
||||
}
|
||||
|
||||
// check sync word Length
|
||||
if(bitsLen > 0x40) {
|
||||
return(ERR_INVALID_SYNC_WORD);
|
||||
}
|
||||
|
||||
uint8_t bytesLen = bitsLen / 8;
|
||||
if ((bitsLen % 8) != 0) {
|
||||
bytesLen++;
|
||||
}
|
||||
|
||||
// write sync word
|
||||
int16_t state = writeRegister(SX126X_REG_SYNC_WORD_0, syncWord, bytesLen);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
// update packet parameters
|
||||
_syncWordLength = bitsLen;
|
||||
state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp);
|
||||
|
||||
return(state);
|
||||
}
|
||||
|
||||
int16_t SX126x::setNodeAddress(uint8_t nodeAddr) {
|
||||
// check active modem
|
||||
if(getPacketType() != SX126X_PACKET_TYPE_GFSK) {
|
||||
|
@ -771,67 +799,67 @@ int16_t SX126x::disableAddressFiltering() {
|
|||
return(setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp));
|
||||
}
|
||||
|
||||
int16_t SX126x::setCRC(bool enableCRC) {
|
||||
// check active modem
|
||||
if(getPacketType() != SX126X_PACKET_TYPE_LORA) {
|
||||
return(ERR_WRONG_MODEM);
|
||||
}
|
||||
|
||||
// update packet parameters
|
||||
if(enableCRC) {
|
||||
_crcType = SX126X_LORA_CRC_ON;
|
||||
} else {
|
||||
_crcType = SX126X_LORA_CRC_OFF;
|
||||
}
|
||||
return(setPacketParams(_preambleLength, _crcType));
|
||||
}
|
||||
|
||||
int16_t SX126x::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool inverted) {
|
||||
// check active modem
|
||||
if(getPacketType() != SX126X_PACKET_TYPE_GFSK) {
|
||||
return(ERR_WRONG_MODEM);
|
||||
}
|
||||
uint8_t modem = getPacketType();
|
||||
|
||||
if(modem == SX126X_PACKET_TYPE_GFSK) {
|
||||
// update packet parameters
|
||||
switch(len) {
|
||||
case 0:
|
||||
_crcTypeFSK = SX126X_GFSK_CRC_OFF;
|
||||
break;
|
||||
case 1:
|
||||
if(inverted) {
|
||||
_crcTypeFSK = SX126X_GFSK_CRC_1_BYTE_INV;
|
||||
} else {
|
||||
_crcTypeFSK = SX126X_GFSK_CRC_1_BYTE;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if(inverted) {
|
||||
_crcTypeFSK = SX126X_GFSK_CRC_2_BYTE_INV;
|
||||
} else {
|
||||
_crcTypeFSK = SX126X_GFSK_CRC_2_BYTE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return(ERR_INVALID_CRC_CONFIGURATION);
|
||||
}
|
||||
|
||||
int16_t state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
// write initial CRC value
|
||||
uint8_t data[2] = {(uint8_t)((initial >> 8) & 0xFF), (uint8_t)(initial & 0xFF)};
|
||||
state = writeRegister(SX126X_REG_CRC_INITIAL_MSB, data, 2);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
// write CRC polynomial value
|
||||
data[0] = (uint8_t)((polynomial >> 8) & 0xFF);
|
||||
data[1] = (uint8_t)(polynomial & 0xFF);
|
||||
state = writeRegister(SX126X_REG_CRC_POLYNOMIAL_MSB, data, 2);
|
||||
|
||||
// update packet parameters
|
||||
switch(len) {
|
||||
case 0:
|
||||
_crcTypeFSK = SX126X_GFSK_CRC_OFF;
|
||||
break;
|
||||
case 1:
|
||||
if(inverted) {
|
||||
_crcTypeFSK = SX126X_GFSK_CRC_1_BYTE_INV;
|
||||
} else {
|
||||
_crcTypeFSK = SX126X_GFSK_CRC_1_BYTE;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if(inverted) {
|
||||
_crcTypeFSK = SX126X_GFSK_CRC_2_BYTE_INV;
|
||||
} else {
|
||||
_crcTypeFSK = SX126X_GFSK_CRC_2_BYTE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return(ERR_INVALID_CRC_CONFIGURATION);
|
||||
}
|
||||
int16_t state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
|
||||
} else if(modem == SX126X_PACKET_TYPE_LORA) {
|
||||
// LoRa CRC doesn't allow to set CRC polynomial, inital value, or inversion
|
||||
|
||||
// update packet parameters
|
||||
if(len) {
|
||||
_crcType = SX126X_LORA_CRC_ON;
|
||||
} else {
|
||||
_crcType = SX126X_LORA_CRC_OFF;
|
||||
}
|
||||
|
||||
return(setPacketParams(_preambleLength, _crcType));
|
||||
}
|
||||
|
||||
// write initial CRC value
|
||||
uint8_t data[2] = {(uint8_t)((initial >> 8) & 0xFF), (uint8_t)(initial & 0xFF)};
|
||||
state = writeRegister(SX126X_REG_CRC_INITIAL_MSB, data, 2);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
// write CRC polynomial value
|
||||
data[0] = (uint8_t)((polynomial >> 8) & 0xFF);
|
||||
data[1] = (uint8_t)(polynomial & 0xFF);
|
||||
state = writeRegister(SX126X_REG_CRC_POLYNOMIAL_MSB, data, 2);
|
||||
|
||||
return(state);
|
||||
return(ERR_UNKNOWN);
|
||||
}
|
||||
|
||||
float SX126x::getDataRate() {
|
||||
|
@ -857,6 +885,34 @@ float SX126x::getSNR() {
|
|||
return(snrPkt/4.0);
|
||||
}
|
||||
|
||||
size_t SX126x::getPacketLength(bool update) {
|
||||
(void)update;
|
||||
uint8_t rxBufStatus[2];
|
||||
SPIreadCommand(SX126X_CMD_GET_RX_BUFFER_STATUS, rxBufStatus, 2);
|
||||
return((size_t)rxBufStatus[0]);
|
||||
}
|
||||
|
||||
uint32_t SX126x::getTimeOnAir(size_t len) {
|
||||
if(getPacketType() == SX126X_PACKET_TYPE_LORA) {
|
||||
float symbolLength = (float)((uint32_t)(1) << _sf) / (float)_bwKhz;
|
||||
float sfCoeff1 = 4.25;
|
||||
float sfCoeff2 = 8.0;
|
||||
if(_sf == 5 || _sf == 6) {
|
||||
sfCoeff1 = 6.25;
|
||||
sfCoeff2 = 0.0;
|
||||
}
|
||||
uint8_t sfDivisor = 4*_sf;
|
||||
if(symbolLength >= 16.0) {
|
||||
sfDivisor = 4*(_sf - 2);
|
||||
}
|
||||
float nSymbol = _preambleLength + sfCoeff1 + 8 + ceil(max(8.0 * len + (_crcType * 16.0) - 4.0 * _sf + sfCoeff2 + 20.0, 0.0) / sfDivisor) * (_cr + 4);
|
||||
return((uint32_t)(symbolLength * nSymbol * 1000.0));
|
||||
} else {
|
||||
float brBps = ((float)(SX126X_CRYSTAL_FREQ) * 1000000.0 * 32.0) / (float)_br;
|
||||
return((uint32_t)(((len * 8.0) / brBps) * 1000000.0));
|
||||
}
|
||||
}
|
||||
|
||||
int16_t SX126x::setTCXO(float voltage, uint32_t timeout) {
|
||||
// set mode to standby
|
||||
standby();
|
||||
|
@ -895,6 +951,16 @@ int16_t SX126x::setTCXO(float voltage, uint32_t timeout) {
|
|||
return(ERR_NONE);
|
||||
}
|
||||
|
||||
int16_t SX126x::setDio2AsRfSwitch(bool enable) {
|
||||
uint8_t data = 0;
|
||||
if(enable) {
|
||||
data = SX126X_DIO2_AS_RF_SWITCH;
|
||||
} else {
|
||||
data = SX126X_DIO2_AS_IRQ;
|
||||
}
|
||||
return(SPIwriteCommand(SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, &data, 1));
|
||||
}
|
||||
|
||||
int16_t SX126x::setTx(uint32_t timeout) {
|
||||
uint8_t data[3] = {(uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF)};
|
||||
return(SPIwriteCommand(SX126X_CMD_SET_TX, data, 3));
|
||||
|
@ -924,6 +990,11 @@ int16_t SX126x::writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) {
|
|||
return(state);
|
||||
}
|
||||
|
||||
int16_t SX126x::readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) {
|
||||
uint8_t cmd[] = {SX126X_CMD_READ_REGISTER, (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF)};
|
||||
return(SX126x::SPItransfer(cmd, 3, false, NULL, data, numBytes, true));
|
||||
}
|
||||
|
||||
int16_t SX126x::writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) {
|
||||
uint8_t* dat = new uint8_t[1 + numBytes];
|
||||
dat[0] = offset;
|
||||
|
@ -955,7 +1026,7 @@ int16_t SX126x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t di
|
|||
uint16_t SX126x::getIrqStatus() {
|
||||
uint8_t data[2];
|
||||
SPIreadCommand(SX126X_CMD_GET_IRQ_STATUS, data, 2);
|
||||
return(((uint16_t)(data[1]) << 8) | data[0]);
|
||||
return(((uint16_t)(data[0]) << 8) | data[1]);
|
||||
}
|
||||
|
||||
int16_t SX126x::clearIrqStatus(uint16_t clearIrqParams) {
|
||||
|
@ -968,6 +1039,10 @@ int16_t SX126x::setRfFrequency(uint32_t frf) {
|
|||
return(SPIwriteCommand(SX126X_CMD_SET_RF_FREQUENCY, data, 4));
|
||||
}
|
||||
|
||||
int16_t SX126x::calibrateImage(uint8_t* data) {
|
||||
return(SPIwriteCommand(SX126X_CMD_CALIBRATE_IMAGE, data, 2));
|
||||
}
|
||||
|
||||
uint8_t SX126x::getPacketType() {
|
||||
uint8_t data = 0xFF;
|
||||
SPIreadCommand(SX126X_CMD_GET_PACKET_TYPE, &data, 1);
|
||||
|
@ -983,6 +1058,9 @@ int16_t SX126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t
|
|||
// calculate symbol length and enable low data rate optimization, if needed
|
||||
if(ldro == 0xFF) {
|
||||
float symbolLength = (float)(uint32_t(1) << _sf) / (float)_bwKhz;
|
||||
DEBUG_PRINT("Symbol length: ");
|
||||
DEBUG_PRINT(symbolLength);
|
||||
DEBUG_PRINTLN(" ms");
|
||||
if(symbolLength >= 16.0) {
|
||||
_ldro = SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON;
|
||||
} else {
|
||||
|
@ -1044,34 +1122,7 @@ int16_t SX126x::clearDeviceErrors() {
|
|||
return(SPIwriteCommand(SX126X_CMD_CLEAR_DEVICE_ERRORS, data, 1));
|
||||
}
|
||||
|
||||
int16_t SX126x::setFrequencyRaw(float freq, bool calibrate) {
|
||||
int16_t state = ERR_NONE;
|
||||
|
||||
// calibrate image
|
||||
if(calibrate) {
|
||||
uint8_t data[2];
|
||||
if(freq > 900.0) {
|
||||
data[0] = SX126X_CAL_IMG_902_MHZ_1;
|
||||
data[1] = SX126X_CAL_IMG_902_MHZ_2;
|
||||
} else if(freq > 850.0) {
|
||||
data[0] = SX126X_CAL_IMG_863_MHZ_1;
|
||||
data[1] = SX126X_CAL_IMG_863_MHZ_2;
|
||||
} else if(freq > 770.0) {
|
||||
data[0] = SX126X_CAL_IMG_779_MHZ_1;
|
||||
data[1] = SX126X_CAL_IMG_779_MHZ_2;
|
||||
} else if(freq > 460.0) {
|
||||
data[0] = SX126X_CAL_IMG_470_MHZ_1;
|
||||
data[1] = SX126X_CAL_IMG_470_MHZ_2;
|
||||
} else {
|
||||
data[0] = SX126X_CAL_IMG_430_MHZ_1;
|
||||
data[1] = SX126X_CAL_IMG_430_MHZ_2;
|
||||
}
|
||||
state = SPIwriteCommand(SX126X_CMD_CALIBRATE_IMAGE, data, 2);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
}
|
||||
|
||||
int16_t SX126x::setFrequencyRaw(float freq) {
|
||||
// calculate raw value
|
||||
uint32_t frf = (freq * (uint32_t(1) << SX126X_DIV_EXPONENT)) / SX126X_CRYSTAL_FREQ;
|
||||
setRfFrequency(frf);
|
||||
|
@ -1079,17 +1130,10 @@ int16_t SX126x::setFrequencyRaw(float freq, bool calibrate) {
|
|||
}
|
||||
|
||||
int16_t SX126x::config(uint8_t modem) {
|
||||
// set DIO2 as IRQ
|
||||
uint8_t* data = new uint8_t[1];
|
||||
data[0] = SX126X_DIO2_AS_IRQ;
|
||||
int16_t state = SPIwriteCommand(SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, data, 1);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
// set regulator mode
|
||||
uint8_t* data = new uint8_t[1];
|
||||
data[0] = SX126X_REGULATOR_DC_DC;
|
||||
state = SPIwriteCommand(SX126X_CMD_SET_REGULATOR_MODE, data, 1);
|
||||
int16_t state = SPIwriteCommand(SX126X_CMD_SET_REGULATOR_MODE, data, 1);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
@ -1155,33 +1199,41 @@ int16_t SX126x::config(uint8_t modem) {
|
|||
}
|
||||
|
||||
int16_t SX126x::SPIwriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy) {
|
||||
return(SX126x::SPItransfer(cmd, true, data, NULL, numBytes, waitForBusy));
|
||||
uint8_t cmdBuffer[] = {cmd};
|
||||
return(SX126x::SPItransfer(cmdBuffer, 1, true, data, NULL, numBytes, waitForBusy));
|
||||
}
|
||||
|
||||
int16_t SX126x::SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy) {
|
||||
return(SX126x::SPItransfer(cmd, false, NULL, data, numBytes, waitForBusy));
|
||||
uint8_t cmdBuffer[] = {cmd};
|
||||
return(SX126x::SPItransfer(cmdBuffer, 1, false, NULL, data, numBytes, waitForBusy));
|
||||
}
|
||||
|
||||
int16_t SX126x::SPItransfer(uint8_t cmd, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForBusy) {
|
||||
int16_t SX126x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForBusy, uint32_t timeout) {
|
||||
// get pointer to used SPI interface and the settings
|
||||
SPIClass* spi = _mod->getSpi();
|
||||
SPISettings spiSettings = _mod->getSpiSettings();
|
||||
|
||||
// ensure BUSY is low (state meachine ready)
|
||||
// TODO timeout
|
||||
while(digitalRead(_mod->getRx()));
|
||||
uint32_t start = millis();
|
||||
while(digitalRead(_mod->getRx())) {
|
||||
if(millis() - start >= timeout) {
|
||||
return(ERR_SPI_CMD_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
// start transfer
|
||||
digitalWrite(_mod->getCs(), LOW);
|
||||
spi->beginTransaction(spiSettings);
|
||||
|
||||
// send command byte
|
||||
spi->transfer(cmd);
|
||||
DEBUG_PRINT(cmd, HEX);
|
||||
DEBUG_PRINT('\t');
|
||||
// send command byte(s)
|
||||
for(uint8_t n = 0; n < cmdLen; n++) {
|
||||
spi->transfer(cmd[n]);
|
||||
DEBUG_PRINT(cmd[n], HEX);
|
||||
DEBUG_PRINT('\t');
|
||||
}
|
||||
|
||||
// variable to save error during SPI transfer
|
||||
uint8_t status;
|
||||
uint8_t status = 0;
|
||||
|
||||
// send/receive all bytes
|
||||
if(write) {
|
||||
|
@ -1230,10 +1282,14 @@ int16_t SX126x::SPItransfer(uint8_t cmd, bool write, uint8_t* dataOut, uint8_t*
|
|||
digitalWrite(_mod->getCs(), HIGH);
|
||||
|
||||
// wait for BUSY to go high and then low
|
||||
// TODO timeout
|
||||
if(waitForBusy) {
|
||||
delayMicroseconds(1);
|
||||
while(digitalRead(_mod->getRx()));
|
||||
start = millis();
|
||||
while(digitalRead(_mod->getRx())) {
|
||||
if(millis() - start >= timeout) {
|
||||
return(ERR_SPI_CMD_TIMEOUT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// parse status
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
// SX126X physical layer properties
|
||||
#define SX126X_CRYSTAL_FREQ 32.0
|
||||
#define SX126X_DIV_EXPONENT 25
|
||||
#define SX126X_MAX_PACKET_LENGTH 255
|
||||
|
||||
// SX126X SPI commands
|
||||
// operational modes commands
|
||||
|
@ -150,7 +151,6 @@
|
|||
|
||||
//SX126X_CMD_SET_PA_CONFIG
|
||||
#define SX126X_PA_CONFIG_HP_MAX 0x07
|
||||
#define SX126X_PA_CONFIG_SX1268 0x01
|
||||
#define SX126X_PA_CONFIG_PA_LUT 0x01
|
||||
|
||||
//SX126X_CMD_SET_RX_TX_FALLBACK_MODE
|
||||
|
@ -351,11 +351,13 @@ class SX126x: public PhysicalLayer {
|
|||
|
||||
\param syncWord 2-byte LoRa sync word.
|
||||
|
||||
\param currentLimit Current protection limit in mA.
|
||||
|
||||
\param preambleLength LoRa preamble length in symbols. Allowed values range from 1 to 65535.
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, uint16_t preambleLength);
|
||||
int16_t begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, float currentLimit, uint16_t preambleLength);
|
||||
|
||||
/*!
|
||||
\brief Initialization method for FSK modem.
|
||||
|
@ -366,13 +368,15 @@ class SX126x: public PhysicalLayer {
|
|||
|
||||
\param rxBw Receiver bandwidth in kHz. Allowed values are 4.8, 5.8, 7.3, 9.7, 11.7, 14.6, 19.5, 23.4, 29.3, 39.0, 46.9, 58.6, 78.2, 93.8, 117.3, 156.2, 187.2, 234.3, 312.0, 373.6 and 467.0 kHz.
|
||||
|
||||
\parma preambleLength FSK preamble length in bits. Allowed values range from 0 to 65535.
|
||||
\param currentLimit Current protection limit in mA.
|
||||
|
||||
\param preambleLength FSK preamble length in bits. Allowed values range from 0 to 65535.
|
||||
|
||||
\param dataShaping Time-bandwidth product of the Gaussian filter to be used for shaping. Allowed values are 0.3, 0.5, 0.7 and 1.0. Set to 0 to disable shaping.
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t beginFSK(float br, float freqDev, float rxBw, uint16_t preambleLength, float dataShaping);
|
||||
int16_t beginFSK(float br, float freqDev, float rxBw, float currentLimit, uint16_t preambleLength, float dataShaping);
|
||||
|
||||
/*!
|
||||
\brief Blocking binary transmit method.
|
||||
|
@ -600,6 +604,17 @@ class SX126x: public PhysicalLayer {
|
|||
*/
|
||||
int16_t setSyncWord(uint8_t* syncWord, uint8_t len);
|
||||
|
||||
/*!
|
||||
\brief Sets FSK sync word in the form of array of up to 8 bytes.
|
||||
|
||||
\param syncWord FSK sync word to be set.
|
||||
|
||||
\param bitsLen FSK sync word length in bits. If length is not divisible by 8, least significant bits of syncWord will be ignored.
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setSyncBits(uint8_t *syncWord, uint8_t bitsLen);
|
||||
|
||||
/*!
|
||||
\brief Sets node address. Calling this method will also enable address filtering for node address only.
|
||||
|
||||
|
@ -626,24 +641,15 @@ class SX126x: public PhysicalLayer {
|
|||
int16_t disableAddressFiltering();
|
||||
|
||||
/*!
|
||||
\brief Sets LoRa CRC.
|
||||
\brief Sets CRC configuration.
|
||||
|
||||
\param enableCRC Enable or disable LoRa CRC.
|
||||
\param len CRC length in bytes, Allowed values are 1 or 2, set to 0 to disable CRC.
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setCRC(bool enableCRC);
|
||||
\param initial Initial CRC value. FSK only. Defaults to 0x1D0F (CCIT CRC).
|
||||
|
||||
/*!
|
||||
\brief Sets FSK CRC configuration.
|
||||
\param polynomial Polynomial for CRC calculation. FSK only. Defaults to 0x1021 (CCIT CRC).
|
||||
|
||||
\param len CRC length in bytes, Allowed values are 1 or 2, set to 0 to disable FSK CRC.
|
||||
|
||||
\param initial Initial CRC value. Defaults to 0x1D0F (CCIT CRC).
|
||||
|
||||
\param polynomial Polynomial for CRC calculation. Defaults to 0x1021 (CCIT CRC).
|
||||
|
||||
\param inverted Invert CRC bytes. Defaults to true (CCIT CRC)
|
||||
\param inverted Invert CRC bytes. FSK only. Defaults to true (CCIT CRC).
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
|
@ -658,6 +664,13 @@ class SX126x: public PhysicalLayer {
|
|||
*/
|
||||
int16_t setTCXO(float voltage, uint32_t timeout = 5000);
|
||||
|
||||
/*!
|
||||
\brief Set DIO2 to function as RF switch (default in Semtech example designs).
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setDio2AsRfSwitch(bool enable = true);
|
||||
|
||||
/*!
|
||||
\brief Gets effective data rate for the last transmitted packet. The value is calculated only for payload bytes.
|
||||
|
||||
|
@ -679,6 +692,24 @@ class SX126x: public PhysicalLayer {
|
|||
*/
|
||||
float getSNR();
|
||||
|
||||
/*!
|
||||
\brief Query modem for the packet length of received payload.
|
||||
|
||||
\param update Update received packet length. Will return cached value when set to false.
|
||||
|
||||
\returns Length of last received packet in bytes.
|
||||
*/
|
||||
size_t getPacketLength(bool update = true);
|
||||
|
||||
/*!
|
||||
\brief Get expected time-on-air for a given size of payload
|
||||
|
||||
\param len Payload length in bytes.
|
||||
|
||||
\returns Expected time-on-air in microseconds.
|
||||
*/
|
||||
uint32_t getTimeOnAir(size_t len);
|
||||
|
||||
protected:
|
||||
// SX1276x SPI command implementations
|
||||
int16_t setTx(uint32_t timeout = 0);
|
||||
|
@ -686,12 +717,14 @@ class SX126x: public PhysicalLayer {
|
|||
int16_t setCad();
|
||||
int16_t setPaConfig(uint8_t paDutyCycle, uint8_t deviceSel, uint8_t hpMax = SX126X_PA_CONFIG_HP_MAX, uint8_t paLut = SX126X_PA_CONFIG_PA_LUT);
|
||||
int16_t writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes);
|
||||
int16_t readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes);
|
||||
int16_t writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset = 0x00);
|
||||
int16_t readBuffer(uint8_t* data, uint8_t numBytes);
|
||||
int16_t setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask = SX126X_IRQ_NONE, uint16_t dio3Mask = SX126X_IRQ_NONE);
|
||||
uint16_t getIrqStatus();
|
||||
int16_t clearIrqStatus(uint16_t clearIrqParams = SX126X_IRQ_ALL);
|
||||
int16_t setRfFrequency(uint32_t frf);
|
||||
int16_t calibrateImage(uint8_t* data);
|
||||
uint8_t getPacketType();
|
||||
int16_t setTxParams(uint8_t power, uint8_t rampTime = SX126X_PA_RAMP_200U);
|
||||
int16_t setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro = 0xFF);
|
||||
|
@ -704,7 +737,7 @@ class SX126x: public PhysicalLayer {
|
|||
uint16_t getDeviceErrors();
|
||||
int16_t clearDeviceErrors();
|
||||
|
||||
int16_t setFrequencyRaw(float freq, bool calibrate = true);
|
||||
int16_t setFrequencyRaw(float freq);
|
||||
|
||||
private:
|
||||
Module* _mod;
|
||||
|
@ -725,7 +758,7 @@ class SX126x: public PhysicalLayer {
|
|||
// common low-level SPI interface
|
||||
int16_t SPIwriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy = true);
|
||||
int16_t SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy = true);
|
||||
int16_t SPItransfer(uint8_t cmd, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForBusy);
|
||||
int16_t SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForBusy, uint32_t timeout = 5000);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -58,9 +58,9 @@ int16_t SX1272::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync
|
|||
return(state);
|
||||
}
|
||||
|
||||
int16_t SX1272::beginFSK(float freq, float br, float rxBw, float freqDev, int8_t power, uint8_t currentLimit, bool enableOOK) {
|
||||
int16_t SX1272::beginFSK(float freq, float br, float rxBw, float freqDev, int8_t power, uint8_t currentLimit, uint16_t preambleLength, bool enableOOK) {
|
||||
// execute common part
|
||||
int16_t state = SX127x::beginFSK(SX1272_CHIP_VERSION, br, rxBw, freqDev, currentLimit, enableOOK);
|
||||
int16_t state = SX127x::beginFSK(SX1272_CHIP_VERSION, br, rxBw, freqDev, currentLimit, preambleLength, enableOOK);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
@ -122,6 +122,17 @@ int16_t SX1272::setBandwidth(float bw) {
|
|||
int16_t state = SX1272::setBandwidthRaw(newBandwidth);
|
||||
if(state == ERR_NONE) {
|
||||
SX127x::_bw = bw;
|
||||
|
||||
// calculate symbol length and set low data rate optimization, if needed
|
||||
float symbolLength = (float)(uint32_t(1) << SX127x::_sf) / (float)SX127x::_bw;
|
||||
DEBUG_PRINT("Symbol length: ");
|
||||
DEBUG_PRINT(symbolLength);
|
||||
DEBUG_PRINTLN(" ms");
|
||||
if(symbolLength >= 16.0) {
|
||||
state = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_LOW_DATA_RATE_OPT_ON, 0, 0);
|
||||
} else {
|
||||
state = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0);
|
||||
}
|
||||
}
|
||||
return(state);
|
||||
}
|
||||
|
@ -165,6 +176,17 @@ int16_t SX1272::setSpreadingFactor(uint8_t sf) {
|
|||
int16_t state = SX1272::setSpreadingFactorRaw(newSpreadingFactor);
|
||||
if(state == ERR_NONE) {
|
||||
SX127x::_sf = sf;
|
||||
|
||||
// calculate symbol length and set low data rate optimization, if needed
|
||||
float symbolLength = (float)(uint32_t(1) << SX127x::_sf) / (float)SX127x::_bw;
|
||||
DEBUG_PRINT("Symbol length: ");
|
||||
DEBUG_PRINT(symbolLength);
|
||||
DEBUG_PRINTLN(" ms");
|
||||
if(symbolLength >= 16.0) {
|
||||
state = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_LOW_DATA_RATE_OPT_ON, 0, 0);
|
||||
} else {
|
||||
state = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0);
|
||||
}
|
||||
}
|
||||
return(state);
|
||||
}
|
||||
|
@ -272,13 +294,14 @@ int16_t SX1272::setDataShaping(float sh) {
|
|||
int16_t state = SX127x::standby();
|
||||
|
||||
// set data shaping
|
||||
sh *= 10.0;
|
||||
if(abs(sh - 0.0) <= 0.001) {
|
||||
state |= _mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX1272_NO_SHAPING, 4, 3);
|
||||
} else if(abs(sh - 0.3) <= 0.001) {
|
||||
} else if(abs(sh - 3.0) <= 0.001) {
|
||||
state |= _mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX1272_FSK_GAUSSIAN_0_3, 4, 3);
|
||||
} else if(abs(sh - 0.5) <= 0.001) {
|
||||
} else if(abs(sh - 5.0) <= 0.001) {
|
||||
state |= _mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX1272_FSK_GAUSSIAN_0_5, 4, 3);
|
||||
} else if(abs(sh - 1.0) <= 0.001) {
|
||||
} else if(abs(sh - 10.0) <= 0.001) {
|
||||
state |= _mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX1272_FSK_GAUSSIAN_1_0, 4, 3);
|
||||
} else {
|
||||
return(ERR_INVALID_DATA_SHAPING);
|
||||
|
@ -392,24 +415,6 @@ int16_t SX1272::setCodingRateRaw(uint8_t newCodingRate) {
|
|||
return(state);
|
||||
}
|
||||
|
||||
int16_t SX1272::config() {
|
||||
// configure common registers
|
||||
int16_t state = SX127x::config();
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
// calculate symbol length and set low data rate optimization, if needed
|
||||
uint16_t base = 1;
|
||||
float symbolLength = (float)(base << _sf) / (float)_bw;
|
||||
if(symbolLength >= 16.0) {
|
||||
state = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_LOW_DATA_RATE_OPT_ON, 0, 0);
|
||||
} else {
|
||||
state = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0);
|
||||
}
|
||||
return(state);
|
||||
}
|
||||
|
||||
int16_t SX1272::configFSK() {
|
||||
// configure common registers
|
||||
int16_t state = SX127x::configFSK();
|
||||
|
|
|
@ -86,178 +86,179 @@
|
|||
/*!
|
||||
\class SX1272
|
||||
|
||||
\brief Derived class for %SX1272 modules. Also used as base class for SX1273.
|
||||
\brief Derived class for %SX1272 modules. Also used as base class for SX1273.
|
||||
Both modules use the same basic hardware and only differ in parameter ranges.
|
||||
*/
|
||||
class SX1272: public SX127x {
|
||||
public:
|
||||
|
||||
|
||||
// constructor
|
||||
|
||||
|
||||
/*!
|
||||
\brief Default constructor. Called from Arduino sketch when creating new LoRa instance.
|
||||
|
||||
|
||||
\param mod Instance of Module that will be used to communicate with the %LoRa chip.
|
||||
*/
|
||||
SX1272(Module* mod);
|
||||
|
||||
|
||||
// basic methods
|
||||
|
||||
|
||||
/*!
|
||||
\brief %LoRa modem initialization method. Must be called at least once from Arduino sketch to initialize the module.
|
||||
|
||||
|
||||
\param freq Carrier frequency in MHz. Allowed values range from 860.0 MHz to 1020.0 MHz.
|
||||
|
||||
|
||||
\param bw %LoRa link bandwidth in kHz. Allowed values are 125, 250 and 500 kHz.
|
||||
|
||||
|
||||
\param sf %LoRa link spreading factor. Allowed values range from 6 to 12.
|
||||
|
||||
|
||||
\param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8.
|
||||
|
||||
|
||||
\param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks.
|
||||
|
||||
|
||||
\param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm.
|
||||
|
||||
\param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA.
|
||||
|
||||
\param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA.
|
||||
Set to 0 to disable OCP (not recommended).
|
||||
|
||||
\param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number.
|
||||
|
||||
\param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number.
|
||||
Allowed values range from 6 to 65535.
|
||||
|
||||
|
||||
\param gain Gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain.
|
||||
Set to 0 to enable automatic gain control (recommended).
|
||||
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 17, uint8_t currentLimit = 100, uint16_t preambleLength = 8, uint8_t gain = 0);
|
||||
|
||||
|
||||
/*!
|
||||
\brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module.
|
||||
|
||||
|
||||
\param freq Carrier frequency in MHz. Allowed values range from 860.0 MHz to 1020.0 MHz.
|
||||
|
||||
|
||||
\param br Bit rate of the FSK transmission in kbps (kilobits per second). Allowed values range from 1.2 to 300.0 kbps.
|
||||
|
||||
\param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.6 to 200.0 kHz.
|
||||
|
||||
\param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.6 to 200.0 kHz.
|
||||
Note that the allowed range changes based on bit rate setting, so that the condition FreqDev + BitRate/2 <= 250 kHz is always met.
|
||||
|
||||
|
||||
\param rxBw Receiver bandwidth in kHz. Allowed values are 2.6, 3.1, 3.9, 5.2, 6.3, 7.8, 10.4, 12.5, 15.6, 20.8, 25, 31.3, 41.7, 50, 62.5, 83.3, 100, 125, 166.7, 200 and 250 kHz.
|
||||
|
||||
|
||||
\param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm.
|
||||
|
||||
\param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA.
|
||||
|
||||
\param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA.
|
||||
Set to 0 to disable OCP (not recommended).
|
||||
|
||||
|
||||
\param preambleLength Length of FSK preamble in bits.
|
||||
|
||||
\param enableOOK Use OOK modulation instead of FSK.
|
||||
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t beginFSK(float freq = 915.0, float br = 48.0, float rxBw = 125.0, float freqDev = 50.0, int8_t power = 13, uint8_t currentLimit = 100, bool enableOOK = false);
|
||||
|
||||
int16_t beginFSK(float freq = 915.0, float br = 48.0, float rxBw = 125.0, float freqDev = 50.0, int8_t power = 13, uint8_t currentLimit = 100, uint16_t preambleLength = 16, bool enableOOK = false);
|
||||
|
||||
// configuration methods
|
||||
|
||||
|
||||
/*!
|
||||
\brief Sets carrier frequency. Allowed values range from 860.0 MHz to 1020.0 MHz.
|
||||
|
||||
|
||||
\param freq Carrier frequency to be set in MHz.
|
||||
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setFrequency(float freq);
|
||||
|
||||
|
||||
/*!
|
||||
\brief Sets %LoRa link bandwidth. Allowed values are 125, 250 and 500 kHz. Only available in %LoRa mode.
|
||||
|
||||
|
||||
\param bw %LoRa link bandwidth to be set in kHz.
|
||||
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setBandwidth(float bw);
|
||||
|
||||
|
||||
/*!
|
||||
\brief Sets %LoRa link spreading factor. Allowed values range from 6 to 12. Only available in %LoRa mode.
|
||||
|
||||
|
||||
\param sf %LoRa link spreading factor to be set.
|
||||
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setSpreadingFactor(uint8_t sf);
|
||||
|
||||
|
||||
/*!
|
||||
\brief Sets %LoRa link coding rate denominator. Allowed values range from 5 to 8. Only available in %LoRa mode.
|
||||
|
||||
|
||||
\param cr %LoRa link coding rate denominator to be set.
|
||||
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setCodingRate(uint8_t cr);
|
||||
|
||||
|
||||
/*!
|
||||
\brief Sets transmission output power. Allowed values range from 2 to 17 dBm.
|
||||
|
||||
|
||||
\param power Transmission output power in dBm.
|
||||
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setOutputPower(int8_t power);
|
||||
|
||||
|
||||
/*!
|
||||
\brief Sets gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain.
|
||||
Set to 0 to enable automatic gain control (recommended). Only available in %LoRa mode.
|
||||
|
||||
|
||||
\param gain Gain of receiver LNA (low-noise amplifier) to be set.
|
||||
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setGain(uint8_t gain);
|
||||
|
||||
|
||||
/*!
|
||||
\brief Sets Gaussian filter bandwidth-time product that will be used for data shaping.
|
||||
\brief Sets Gaussian filter bandwidth-time product that will be used for data shaping.
|
||||
Allowed values are 0.3, 0.5 or 1.0. Set to 0 to disable data shaping. Only available in FSK mode with FSK modulation.
|
||||
|
||||
|
||||
\param sh Gaussian shaping bandwidth-time product that will be used for data shaping
|
||||
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setDataShaping(float sh);
|
||||
|
||||
|
||||
/*!
|
||||
\brief Sets filter cutoff frequency that will be used for data shaping.
|
||||
\brief Sets filter cutoff frequency that will be used for data shaping.
|
||||
Allowed values are 1 for frequency equal to bit rate and 2 for frequency equal to 2x bit rate. Set to 0 to disable data shaping.
|
||||
Only available in FSK mode with OOK modulation.
|
||||
|
||||
|
||||
\param sh Cutoff frequency that will be used for data shaping
|
||||
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setDataShapingOOK(uint8_t sh);
|
||||
|
||||
|
||||
/*!
|
||||
\brief Gets recorded signal strength indicator of the latest received packet.
|
||||
|
||||
|
||||
\returns Last packet recorded signal strength indicator (RSSI).
|
||||
*/
|
||||
int8_t getRSSI();
|
||||
|
||||
|
||||
/*!
|
||||
\brief Enables/disables CRC check of received packets.
|
||||
|
||||
|
||||
\param enableCRC Enable (true) or disable (false) CRC.
|
||||
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setCRC(bool enableCRC);
|
||||
|
||||
|
||||
protected:
|
||||
int16_t setBandwidthRaw(uint8_t newBandwidth);
|
||||
int16_t setSpreadingFactorRaw(uint8_t newSpreadingFactor);
|
||||
int16_t setCodingRateRaw(uint8_t newCodingRate);
|
||||
|
||||
int16_t config();
|
||||
|
||||
int16_t configFSK();
|
||||
|
||||
private:
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -51,9 +51,9 @@ int16_t SX1278::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync
|
|||
return(state);
|
||||
}
|
||||
|
||||
int16_t SX1278::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t currentLimit, bool enableOOK) {
|
||||
int16_t SX1278::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t currentLimit, uint16_t preambleLength, bool enableOOK) {
|
||||
// execute common part
|
||||
int16_t state = SX127x::beginFSK(SX1278_CHIP_VERSION, br, freqDev, rxBw, currentLimit, enableOOK);
|
||||
int16_t state = SX127x::beginFSK(SX1278_CHIP_VERSION, br, freqDev, rxBw, currentLimit, preambleLength, enableOOK);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
@ -192,6 +192,17 @@ int16_t SX1278::setBandwidth(float bw) {
|
|||
int16_t state = SX1278::setBandwidthRaw(newBandwidth);
|
||||
if(state == ERR_NONE) {
|
||||
SX127x::_bw = bw;
|
||||
|
||||
// calculate symbol length and set low data rate optimization, if needed
|
||||
float symbolLength = (float)(uint32_t(1) << SX127x::_sf) / (float)SX127x::_bw;
|
||||
DEBUG_PRINT("Symbol length: ");
|
||||
DEBUG_PRINT(symbolLength);
|
||||
DEBUG_PRINTLN(" ms");
|
||||
if(symbolLength >= 16.0) {
|
||||
state = _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_LOW_DATA_RATE_OPT_ON, 3, 3);
|
||||
} else {
|
||||
state = _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3);
|
||||
}
|
||||
}
|
||||
return(state);
|
||||
}
|
||||
|
@ -235,6 +246,17 @@ int16_t SX1278::setSpreadingFactor(uint8_t sf) {
|
|||
int16_t state = SX1278::setSpreadingFactorRaw(newSpreadingFactor);
|
||||
if(state == ERR_NONE) {
|
||||
SX127x::_sf = sf;
|
||||
|
||||
// calculate symbol length and set low data rate optimization, if needed
|
||||
float symbolLength = (float)(uint32_t(1) << SX127x::_sf) / (float)SX127x::_bw;
|
||||
DEBUG_PRINT("Symbol length: ");
|
||||
DEBUG_PRINT(symbolLength);
|
||||
DEBUG_PRINTLN(" ms");
|
||||
if(symbolLength >= 16.0) {
|
||||
state = _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_LOW_DATA_RATE_OPT_ON, 3, 3);
|
||||
} else {
|
||||
state = _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3);
|
||||
}
|
||||
}
|
||||
return(state);
|
||||
}
|
||||
|
@ -342,13 +364,14 @@ int16_t SX1278::setDataShaping(float sh) {
|
|||
int16_t state = SX127x::standby();
|
||||
|
||||
// set data shaping
|
||||
sh *= 10.0;
|
||||
if(abs(sh - 0.0) <= 0.001) {
|
||||
state |= _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_NO_SHAPING, 6, 5);
|
||||
} else if(abs(sh - 0.3) <= 0.001) {
|
||||
} else if(abs(sh - 3.0) <= 0.001) {
|
||||
state |= _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_FSK_GAUSSIAN_0_3, 6, 5);
|
||||
} else if(abs(sh - 0.5) <= 0.001) {
|
||||
} else if(abs(sh - 5.0) <= 0.001) {
|
||||
state |= _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_FSK_GAUSSIAN_0_5, 6, 5);
|
||||
} else if(abs(sh - 1.0) <= 0.001) {
|
||||
} else if(abs(sh - 10.0) <= 0.001) {
|
||||
state |= _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_FSK_GAUSSIAN_1_0, 6, 5);
|
||||
} else {
|
||||
return(ERR_INVALID_DATA_SHAPING);
|
||||
|
@ -468,24 +491,6 @@ int16_t SX1278::setCodingRateRaw(uint8_t newCodingRate) {
|
|||
return(state);
|
||||
}
|
||||
|
||||
int16_t SX1278::config() {
|
||||
// configure common registers
|
||||
int16_t state = SX127x::config();
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
// calculate symbol length and set low data rate optimization, if needed
|
||||
uint16_t base = 1;
|
||||
float symbolLength = (float)(base << _sf) / (float)_bw;
|
||||
if(symbolLength >= 16.0) {
|
||||
state = _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_LOW_DATA_RATE_OPT_ON, 0, 0);
|
||||
} else {
|
||||
state = _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_LOW_DATA_RATE_OPT_OFF, 0, 0);
|
||||
}
|
||||
return(state);
|
||||
}
|
||||
|
||||
int16_t SX1278::configFSK() {
|
||||
// configure common registers
|
||||
int16_t state = SX127x::configFSK();
|
||||
|
|
|
@ -100,173 +100,174 @@
|
|||
*/
|
||||
class SX1278: public SX127x {
|
||||
public:
|
||||
|
||||
|
||||
// constructor
|
||||
|
||||
|
||||
/*!
|
||||
\brief Default constructor. Called from Arduino sketch when creating new LoRa instance.
|
||||
|
||||
|
||||
\param mod Instance of Module that will be used to communicate with the %LoRa chip.
|
||||
*/
|
||||
SX1278(Module* mod);
|
||||
|
||||
|
||||
// basic methods
|
||||
|
||||
|
||||
/*!
|
||||
\brief %LoRa modem initialization method. Must be called at least once from Arduino sketch to initialize the module.
|
||||
|
||||
|
||||
\param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 525.0 MHz.
|
||||
|
||||
|
||||
\param bw %LoRa link bandwidth in kHz. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz.
|
||||
|
||||
|
||||
\param sf %LoRa link spreading factor. Allowed values range from 6 to 12.
|
||||
|
||||
|
||||
\param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8.
|
||||
|
||||
|
||||
\param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks.
|
||||
|
||||
|
||||
\param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm.
|
||||
|
||||
\param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA.
|
||||
|
||||
\param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA.
|
||||
Set to 0 to disable OCP (not recommended).
|
||||
|
||||
\param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number.
|
||||
|
||||
\param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number.
|
||||
Allowed values range from 6 to 65535.
|
||||
|
||||
|
||||
\param gain Gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain.
|
||||
Set to 0 to enable automatic gain control (recommended).
|
||||
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 17, uint8_t currentLimit = 100, uint16_t preambleLength = 8, uint8_t gain = 0);
|
||||
|
||||
|
||||
/*!
|
||||
\brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module.
|
||||
|
||||
|
||||
\param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 525.0 MHz.
|
||||
|
||||
|
||||
\param br Bit rate of the FSK transmission in kbps (kilobits per second). Allowed values range from 1.2 to 300.0 kbps.
|
||||
|
||||
\param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.6 to 200.0 kHz.
|
||||
|
||||
\param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.6 to 200.0 kHz.
|
||||
Note that the allowed range changes based on bit rate setting, so that the condition FreqDev + BitRate/2 <= 250 kHz is always met.
|
||||
|
||||
|
||||
\param rxBw Receiver bandwidth in kHz. Allowed values are 2.6, 3.1, 3.9, 5.2, 6.3, 7.8, 10.4, 12.5, 15.6, 20.8, 25, 31.3, 41.7, 50, 62.5, 83.3, 100, 125, 166.7, 200 and 250 kHz.
|
||||
|
||||
|
||||
\param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm.
|
||||
|
||||
\param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA.
|
||||
|
||||
\param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA.
|
||||
Set to 0 to disable OCP (not recommended).
|
||||
|
||||
|
||||
\param preambleLength Length of FSK preamble in bits.
|
||||
|
||||
\param enableOOK Use OOK modulation instead of FSK.
|
||||
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t beginFSK(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 125.0, int8_t power = 13, uint8_t currentLimit = 100, bool enableOOK = false);
|
||||
|
||||
int16_t beginFSK(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 125.0, int8_t power = 13, uint8_t currentLimit = 100, uint16_t preambleLength = 16, bool enableOOK = false);
|
||||
|
||||
// configuration methods
|
||||
|
||||
|
||||
/*!
|
||||
\brief Sets carrier frequency. Allowed values range from 137.0 MHz to 525.0 MHz.
|
||||
|
||||
|
||||
\param freq Carrier frequency to be set in MHz.
|
||||
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setFrequency(float freq);
|
||||
|
||||
|
||||
/*!
|
||||
\brief Sets %LoRa link bandwidth. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz. Only available in %LoRa mode.
|
||||
|
||||
|
||||
\param bw %LoRa link bandwidth to be set in kHz.
|
||||
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setBandwidth(float bw);
|
||||
|
||||
|
||||
/*!
|
||||
\brief Sets %LoRa link spreading factor. Allowed values range from 6 to 12. Only available in %LoRa mode.
|
||||
|
||||
|
||||
\param sf %LoRa link spreading factor to be set.
|
||||
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setSpreadingFactor(uint8_t sf);
|
||||
|
||||
|
||||
/*!
|
||||
\brief Sets %LoRa link coding rate denominator. Allowed values range from 5 to 8. Only available in %LoRa mode.
|
||||
|
||||
|
||||
\param cr %LoRa link coding rate denominator to be set.
|
||||
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setCodingRate(uint8_t cr);
|
||||
|
||||
|
||||
/*!
|
||||
\brief Sets transmission output power. Allowed values range from 2 to 17 dBm.
|
||||
|
||||
|
||||
\param power Transmission output power in dBm.
|
||||
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setOutputPower(int8_t power);
|
||||
|
||||
|
||||
/*!
|
||||
\brief Sets gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain.
|
||||
Set to 0 to enable automatic gain control (recommended). Only available in %LoRa mode.
|
||||
|
||||
|
||||
\param gain Gain of receiver LNA (low-noise amplifier) to be set.
|
||||
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setGain(uint8_t gain);
|
||||
|
||||
|
||||
/*!
|
||||
\brief Sets Gaussian filter bandwidth-time product that will be used for data shaping.
|
||||
\brief Sets Gaussian filter bandwidth-time product that will be used for data shaping.
|
||||
Allowed values are 0.3, 0.5 or 1.0. Set to 0 to disable data shaping. Only available in FSK mode with FSK modulation.
|
||||
|
||||
|
||||
\param sh Gaussian shaping bandwidth-time product that will be used for data shaping
|
||||
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setDataShaping(float sh);
|
||||
|
||||
|
||||
/*!
|
||||
\brief Sets filter cutoff frequency that will be used for data shaping.
|
||||
\brief Sets filter cutoff frequency that will be used for data shaping.
|
||||
Allowed values are 1 for frequency equal to bit rate and 2 for frequency equal to 2x bit rate. Set to 0 to disable data shaping.
|
||||
Only available in FSK mode with OOK modulation.
|
||||
|
||||
|
||||
\param sh Cutoff frequency that will be used for data shaping
|
||||
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setDataShapingOOK(uint8_t sh);
|
||||
|
||||
|
||||
/*!
|
||||
\brief Gets recorded signal strength indicator of the latest received packet.
|
||||
|
||||
|
||||
\returns Last packet recorded signal strength indicator (RSSI).
|
||||
*/
|
||||
int8_t getRSSI();
|
||||
|
||||
|
||||
/*!
|
||||
\brief Enables/disables CRC check of received packets.
|
||||
|
||||
|
||||
\param enableCRC Enable (true) or disable (false) CRC.
|
||||
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setCRC(bool enableCRC);
|
||||
|
||||
|
||||
protected:
|
||||
int16_t setBandwidthRaw(uint8_t newBandwidth);
|
||||
int16_t setSpreadingFactorRaw(uint8_t newSpreadingFactor);
|
||||
int16_t setCodingRateRaw(uint8_t newCodingRate);
|
||||
|
||||
int16_t config();
|
||||
|
||||
int16_t configFSK();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
#include "SX127x.h"
|
||||
|
||||
SX127x::SX127x(Module* mod) : PhysicalLayer(SX127X_CRYSTAL_FREQ, SX127X_DIV_EXPONENT) {
|
||||
SX127x::SX127x(Module* mod) : PhysicalLayer(SX127X_CRYSTAL_FREQ, SX127X_DIV_EXPONENT, SX127X_MAX_PACKET_LENGTH) {
|
||||
_mod = mod;
|
||||
_packetLengthQueried = false;
|
||||
}
|
||||
|
||||
int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint8_t currentLimit, uint16_t preambleLength) {
|
||||
|
@ -48,7 +49,7 @@ int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint8_t currentLimi
|
|||
return(state);
|
||||
}
|
||||
|
||||
int16_t SX127x::beginFSK(uint8_t chipVersion, float br, float freqDev, float rxBw, uint8_t currentLimit, bool enableOOK) {
|
||||
int16_t SX127x::beginFSK(uint8_t chipVersion, float br, float freqDev, float rxBw, uint8_t currentLimit, uint16_t preambleLength, bool enableOOK) {
|
||||
// set module properties
|
||||
_mod->init(USE_SPI, INT_BOTH);
|
||||
|
||||
|
@ -95,6 +96,12 @@ int16_t SX127x::beginFSK(uint8_t chipVersion, float br, float freqDev, float rxB
|
|||
return(state);
|
||||
}
|
||||
|
||||
// set preamble length
|
||||
state = SX127x::setPreambleLength(preambleLength);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
// default sync word value 0x2D01 is the same as the default in LowPowerLab RFM69 library
|
||||
uint8_t syncWord[] = {0x2D, 0x01};
|
||||
state = setSyncWord(syncWord, 2);
|
||||
|
@ -119,10 +126,10 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) {
|
|||
int16_t state = setMode(SX127X_STANDBY);
|
||||
|
||||
int16_t modem = getActiveModem();
|
||||
uint32_t start = 0;
|
||||
if(modem == SX127X_LORA) {
|
||||
// calculate timeout (150 % of expected time-one-air)
|
||||
uint16_t base = 1;
|
||||
float symbolLength = (float)(base << _sf) / (float)_bw;
|
||||
float symbolLength = (float)(uint32_t(1) <<_sf) / (float)_bw;
|
||||
float de = 0;
|
||||
if(symbolLength >= 16.0) {
|
||||
de = 1;
|
||||
|
@ -131,7 +138,7 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) {
|
|||
float crc = (float)(_mod->SPIgetRegValue(SX127X_REG_MODEM_CONFIG_2, 2, 2) >> 2);
|
||||
float n_pre = (float)((_mod->SPIgetRegValue(SX127X_REG_PREAMBLE_MSB) << 8) | _mod->SPIgetRegValue(SX127X_REG_PREAMBLE_LSB));
|
||||
float n_pay = 8.0 + max(ceil((8.0 * (float)len - 4.0 * (float)_sf + 28.0 + 16.0 * crc - 20.0 * ih)/(4.0 * (float)_sf - 8.0 * de)) * (float)_cr, 0.0);
|
||||
uint32_t timeout = ceil(symbolLength * (n_pre + n_pay + 4.25) * 1.5);
|
||||
uint32_t timeout = ceil(symbolLength * (n_pre + n_pay + 4.25) * 1500.0);
|
||||
|
||||
// start transmission
|
||||
state = startTransmit(data, len, addr);
|
||||
|
@ -140,26 +147,17 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) {
|
|||
}
|
||||
|
||||
// wait for packet transmission or timeout
|
||||
uint32_t start = millis();
|
||||
start = micros();
|
||||
while(!digitalRead(_mod->getInt0())) {
|
||||
if(millis() - start > timeout) {
|
||||
if(micros() - start > timeout) {
|
||||
clearIRQFlags();
|
||||
return(ERR_TX_TIMEOUT);
|
||||
}
|
||||
}
|
||||
uint32_t elapsed = millis() - start;
|
||||
|
||||
// update data rate
|
||||
_dataRate = (len*8.0)/((float)elapsed/1000.0);
|
||||
|
||||
// clear interrupt flags
|
||||
clearIRQFlags();
|
||||
|
||||
return(ERR_NONE);
|
||||
|
||||
} else if(modem == SX127X_FSK_OOK) {
|
||||
// calculate timeout (150 % of expected time-on-air)
|
||||
uint32_t timeout = (uint32_t)((((float)(len * 8)) / (_br * 1000.0)) * 1500.0);
|
||||
// calculate timeout (5ms + 500 % of expected time-on-air)
|
||||
uint32_t timeout = 5000000 + (uint32_t)((((float)(len * 8)) / (_br * 1000.0)) * 5000000.0);
|
||||
|
||||
// start transmission
|
||||
state = startTransmit(data, len, addr);
|
||||
|
@ -168,25 +166,25 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) {
|
|||
}
|
||||
|
||||
// wait for transmission end or timeout
|
||||
uint32_t start = millis();
|
||||
start = micros();
|
||||
while(!digitalRead(_mod->getInt0())) {
|
||||
if(millis() - start > timeout) {
|
||||
if(micros() - start > timeout) {
|
||||
clearIRQFlags();
|
||||
standby();
|
||||
return(ERR_TX_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
// clear interrupt flags
|
||||
clearIRQFlags();
|
||||
|
||||
// set mode to standby to disable transmitter
|
||||
state |= standby();
|
||||
|
||||
return(state);
|
||||
}
|
||||
|
||||
return(ERR_UNKNOWN);
|
||||
// update data rate
|
||||
uint32_t elapsed = micros() - start;
|
||||
_dataRate = (len*8.0)/((float)elapsed/1000000.0);
|
||||
|
||||
// clear interrupt flags
|
||||
clearIRQFlags();
|
||||
|
||||
// set mode to standby to disable transmitter
|
||||
return(standby());
|
||||
}
|
||||
|
||||
int16_t SX127x::receive(uint8_t* data, size_t len) {
|
||||
|
@ -196,7 +194,7 @@ int16_t SX127x::receive(uint8_t* data, size_t len) {
|
|||
int16_t modem = getActiveModem();
|
||||
if(modem == SX127X_LORA) {
|
||||
// set mode to receive
|
||||
state = startReceive(SX127X_RXSINGLE);
|
||||
state = startReceive(len, SX127X_RXSINGLE);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
@ -209,37 +207,30 @@ int16_t SX127x::receive(uint8_t* data, size_t len) {
|
|||
}
|
||||
}
|
||||
|
||||
// read the received data
|
||||
return(readData(data, len));
|
||||
|
||||
} else if(modem == SX127X_FSK_OOK) {
|
||||
// calculate timeout (500 % of expected time-one-air)
|
||||
size_t maxLen = len;
|
||||
if(len == 0) {
|
||||
maxLen = 0xFF;
|
||||
}
|
||||
uint32_t timeout = (uint32_t)((((float)(maxLen * 8)) / (_br * 1000.0)) * 5000.0);
|
||||
uint32_t timeout = (uint32_t)((((float)(len * 8)) / (_br * 1000.0)) * 5000000.0);
|
||||
|
||||
// set mode to receive
|
||||
state = startReceive(SX127X_RX);
|
||||
state = startReceive(len, SX127X_RX);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
// wait for packet reception or timeout
|
||||
uint32_t start = millis();
|
||||
uint32_t start = micros();
|
||||
while(!digitalRead(_mod->getInt0())) {
|
||||
if(millis() - start > timeout) {
|
||||
if(micros() - start > timeout) {
|
||||
clearIRQFlags();
|
||||
return(ERR_RX_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
// read the received data
|
||||
return(readData(data, len));
|
||||
}
|
||||
|
||||
return(ERR_UNKNOWN);
|
||||
// read the received data
|
||||
state = readData(data, len);
|
||||
|
||||
return(state);
|
||||
}
|
||||
|
||||
int16_t SX127x::scanChannel() {
|
||||
|
@ -352,7 +343,7 @@ int16_t SX127x::packetMode() {
|
|||
return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_2, SX127X_DATA_MODE_PACKET, 6, 6));
|
||||
}
|
||||
|
||||
int16_t SX127x::startReceive(uint8_t mode) {
|
||||
int16_t SX127x::startReceive(uint8_t len, uint8_t mode) {
|
||||
// set mode to standby
|
||||
int16_t state = setMode(SX127X_STANDBY);
|
||||
|
||||
|
@ -361,6 +352,11 @@ int16_t SX127x::startReceive(uint8_t mode) {
|
|||
// set DIO pin mapping
|
||||
state |= _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_RX_DONE | SX127X_DIO1_RX_TIMEOUT, 7, 4);
|
||||
|
||||
// set expected packet length for SF6
|
||||
if(_sf == 6) {
|
||||
state |= _mod->SPIsetRegValue(SX127X_REG_PAYLOAD_LENGTH, len);
|
||||
}
|
||||
|
||||
// clear interrupt flags
|
||||
clearIRQFlags();
|
||||
|
||||
|
@ -470,7 +466,13 @@ int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
|
|||
int16_t SX127x::readData(uint8_t* data, size_t len) {
|
||||
int16_t modem = getActiveModem();
|
||||
size_t length = len;
|
||||
|
||||
if(modem == SX127X_LORA) {
|
||||
// len set to maximum indicates unknown packet length, read the number of actually received bytes
|
||||
if(len == SX127X_MAX_PACKET_LENGTH) {
|
||||
length = getPacketLength();
|
||||
}
|
||||
|
||||
// check integrity CRC
|
||||
if(_mod->SPIgetRegValue(SX127X_REG_IRQ_FLAGS, 5, 5) == SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR) {
|
||||
// clear interrupt flags
|
||||
|
@ -479,14 +481,9 @@ int16_t SX127x::readData(uint8_t* data, size_t len) {
|
|||
return(ERR_CRC_MISMATCH);
|
||||
}
|
||||
|
||||
// get packet length
|
||||
if(_sf != 6) {
|
||||
length = _mod->SPIgetRegValue(SX127X_REG_RX_NB_BYTES);
|
||||
}
|
||||
|
||||
} else if(modem == SX127X_FSK_OOK) {
|
||||
// get packet length
|
||||
length = _mod->SPIreadRegister(SX127X_REG_FIFO);
|
||||
// read packet length (always required in FSK)
|
||||
length = getPacketLength();
|
||||
|
||||
// check address filtering
|
||||
uint8_t filter = _mod->SPIgetRegValue(SX127X_REG_PACKET_CONFIG_1, 2, 1);
|
||||
|
@ -496,16 +493,16 @@ int16_t SX127x::readData(uint8_t* data, size_t len) {
|
|||
}
|
||||
|
||||
// read packet data
|
||||
if(len == 0) {
|
||||
// argument len equal to zero indicates String call, which means dynamically allocated data array
|
||||
// dispose of the original and create a new one
|
||||
delete[] data;
|
||||
data = new uint8_t[length + 1];
|
||||
}
|
||||
_mod->SPIreadRegisterBurst(SX127X_REG_FIFO, length, data);
|
||||
|
||||
// add terminating null
|
||||
data[length] = 0;
|
||||
// dump bytes that weren't requested
|
||||
size_t packetLength = getPacketLength();
|
||||
if(packetLength > length) {
|
||||
clearFIFO(packetLength - length);
|
||||
}
|
||||
|
||||
// clear internal flag so getPacketLength can return the new packet length
|
||||
_packetLengthQueried = false;
|
||||
|
||||
// clear interrupt flags
|
||||
clearIRQFlags();
|
||||
|
@ -551,23 +548,33 @@ int16_t SX127x::setCurrentLimit(uint8_t currentLimit) {
|
|||
}
|
||||
|
||||
int16_t SX127x::setPreambleLength(uint16_t preambleLength) {
|
||||
// check active modem
|
||||
if(getActiveModem() != SX127X_LORA) {
|
||||
return(ERR_WRONG_MODEM);
|
||||
}
|
||||
|
||||
// check allowed range
|
||||
if(preambleLength < 6) {
|
||||
return(ERR_INVALID_PREAMBLE_LENGTH);
|
||||
}
|
||||
|
||||
// set mode to standby
|
||||
int16_t state = setMode(SX127X_STANDBY);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
// set preamble length
|
||||
state |= _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_MSB, (preambleLength & 0xFF00) >> 8);
|
||||
state |= _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_LSB, preambleLength & 0x00FF);
|
||||
return(state);
|
||||
// check active modem
|
||||
uint8_t modem = getActiveModem();
|
||||
if(modem == SX127X_LORA) {
|
||||
// check allowed range
|
||||
if(preambleLength < 6) {
|
||||
return(ERR_INVALID_PREAMBLE_LENGTH);
|
||||
}
|
||||
|
||||
// set preamble length
|
||||
state = _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_MSB, (uint8_t)((preambleLength >> 8) & 0xFF));
|
||||
state |= _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_LSB, (uint8_t)(preambleLength & 0xFF));
|
||||
return(state);
|
||||
|
||||
} else if(modem == SX127X_FSK_OOK) {
|
||||
// set preamble length
|
||||
state = _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_MSB_FSK, (uint8_t)((preambleLength >> 8) & 0xFF));
|
||||
state |= _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_LSB_FSK, (uint8_t)(preambleLength & 0xFF));
|
||||
return(state);
|
||||
}
|
||||
|
||||
return(ERR_UNKNOWN);
|
||||
}
|
||||
|
||||
float SX127x::getFrequencyError(bool autoCorrect) {
|
||||
|
@ -575,7 +582,7 @@ float SX127x::getFrequencyError(bool autoCorrect) {
|
|||
if(modem == SX127X_LORA) {
|
||||
// get raw frequency error
|
||||
uint32_t raw = (uint32_t)_mod->SPIgetRegValue(SX127X_REG_FEI_MSB, 3, 0) << 16;
|
||||
raw |= _mod->SPIgetRegValue(SX127X_REG_FEI_MID) << 8;
|
||||
raw |= (uint16_t)_mod->SPIgetRegValue(SX127X_REG_FEI_MID) << 8;
|
||||
raw |= _mod->SPIgetRegValue(SX127X_REG_FEI_LSB);
|
||||
|
||||
uint32_t base = (uint32_t)2 << 23;
|
||||
|
@ -601,7 +608,7 @@ float SX127x::getFrequencyError(bool autoCorrect) {
|
|||
|
||||
} else if(modem == SX127X_FSK_OOK) {
|
||||
// get raw frequency error
|
||||
uint16_t raw = _mod->SPIgetRegValue(SX127X_REG_FEI_MSB_FSK) << 8;
|
||||
uint16_t raw = (uint16_t)_mod->SPIgetRegValue(SX127X_REG_FEI_MSB_FSK) << 8;
|
||||
raw |= _mod->SPIgetRegValue(SX127X_REG_FEI_LSB_FSK);
|
||||
|
||||
uint32_t base = 1;
|
||||
|
@ -635,11 +642,6 @@ float SX127x::getSNR() {
|
|||
}
|
||||
|
||||
float SX127x::getDataRate() {
|
||||
// check active modem
|
||||
if(getActiveModem() != SX127X_LORA) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
return(_dataRate);
|
||||
}
|
||||
|
||||
|
@ -741,7 +743,6 @@ int16_t SX127x::setRxBandwidth(float rxBw) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return(ERR_UNKNOWN);
|
||||
}
|
||||
|
||||
|
@ -752,7 +753,7 @@ int16_t SX127x::setSyncWord(uint8_t* syncWord, size_t len) {
|
|||
}
|
||||
|
||||
// check constraints
|
||||
if(len > 8) {
|
||||
if((len > 8) || (len < 1)) {
|
||||
return(ERR_INVALID_SYNC_WORD);
|
||||
}
|
||||
|
||||
|
@ -765,7 +766,7 @@ int16_t SX127x::setSyncWord(uint8_t* syncWord, size_t len) {
|
|||
|
||||
// enable sync word recognition
|
||||
int16_t state = _mod->SPIsetRegValue(SX127X_REG_SYNC_CONFIG, SX127X_SYNC_ON, 4, 4);
|
||||
state |= _mod->SPIsetRegValue(SX127X_REG_SYNC_CONFIG, len, 2, 0);
|
||||
state |= _mod->SPIsetRegValue(SX127X_REG_SYNC_CONFIG, len - 1, 2, 0);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
@ -863,6 +864,30 @@ int16_t SX127x::setFrequencyRaw(float newFreq) {
|
|||
return(state);
|
||||
}
|
||||
|
||||
size_t SX127x::getPacketLength(bool update) {
|
||||
int16_t modem = getActiveModem();
|
||||
|
||||
if(modem == SX127X_LORA) {
|
||||
if(_sf != 6) {
|
||||
// get packet length for SF7 - SF12
|
||||
return(_mod->SPIreadRegister(SX127X_REG_RX_NB_BYTES));
|
||||
|
||||
} else {
|
||||
// return the maximum value for SF6
|
||||
return(SX127X_MAX_PACKET_LENGTH);
|
||||
}
|
||||
|
||||
} else if(modem == SX127X_FSK_OOK) {
|
||||
// get packet length
|
||||
if(!_packetLengthQueried && update) {
|
||||
_packetLength = _mod->SPIreadRegister(SX127X_REG_FIFO);
|
||||
_packetLengthQueried = true;
|
||||
}
|
||||
}
|
||||
|
||||
return(_packetLength);
|
||||
}
|
||||
|
||||
int16_t SX127x::config() {
|
||||
// turn off frequency hopping
|
||||
int16_t state = _mod->SPIsetRegValue(SX127X_REG_HOP_PERIOD, SX127X_HOP_PERIOD_OFF);
|
||||
|
@ -880,12 +905,18 @@ int16_t SX127x::configFSK() {
|
|||
_mod->SPIwriteRegister(SX127X_REG_IRQ_FLAGS_2, SX127X_FLAG_FIFO_OVERRUN);
|
||||
|
||||
// set packet configuration
|
||||
state = _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_PACKET_VARIABLE | SX127X_DC_FREE_NONE | SX127X_CRC_ON | SX127X_CRC_AUTOCLEAR_ON, 7, 3);
|
||||
state = _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_PACKET_VARIABLE | SX127X_DC_FREE_WHITENING | SX127X_CRC_ON | SX127X_CRC_AUTOCLEAR_ON | SX127X_ADDRESS_FILTERING_OFF | SX127X_CRC_WHITENING_TYPE_CCITT, 7, 0);
|
||||
state |= _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_2, SX127X_DATA_MODE_PACKET | SX127X_IO_HOME_OFF, 6, 5);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
// set preamble polarity
|
||||
state =_mod->SPIsetRegValue(SX127X_REG_SYNC_CONFIG, SX127X_PREAMBLE_POLARITY_55, 5, 5);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
// set FIFO threshold
|
||||
state = _mod->SPIsetRegValue(SX127X_REG_FIFO_THRESH, SX127X_TX_START_FIFO_NOT_EMPTY, 7, 7);
|
||||
state |= _mod->SPIsetRegValue(SX127X_REG_FIFO_THRESH, SX127X_FIFO_THRESH, 5, 0);
|
||||
|
@ -902,7 +933,7 @@ int16_t SX127x::configFSK() {
|
|||
}
|
||||
|
||||
// enable preamble detector and set preamble length
|
||||
state = _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_DETECT, SX127X_PREAMBLE_DETECTOR_ON | SX127X_PREAMBLE_DETECTOR_1_BYTE | SX127X_PREAMBLE_DETECTOR_TOL);
|
||||
state = _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_DETECT, SX127X_PREAMBLE_DETECTOR_ON | SX127X_PREAMBLE_DETECTOR_2_BYTE | SX127X_PREAMBLE_DETECTOR_TOL);
|
||||
state |= _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_MSB_FSK, SX127X_PREAMBLE_SIZE_MSB);
|
||||
state |= _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_LSB_FSK, SX127X_PREAMBLE_SIZE_LSB);
|
||||
if(state != ERR_NONE) {
|
||||
|
@ -970,6 +1001,13 @@ void SX127x::clearIRQFlags() {
|
|||
}
|
||||
}
|
||||
|
||||
void SX127x::clearFIFO(size_t count) {
|
||||
while(count) {
|
||||
_mod->SPIreadRegister(SX127X_REG_FIFO);
|
||||
count--;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef RADIOLIB_DEBUG
|
||||
void SX127x::regDump() {
|
||||
Serial.println();
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
// SX127x physical layer properties
|
||||
#define SX127X_CRYSTAL_FREQ 32.0
|
||||
#define SX127X_DIV_EXPONENT 19
|
||||
#define SX127X_MAX_PACKET_LENGTH 256
|
||||
|
||||
// SX127x series common LoRa registers
|
||||
#define SX127X_REG_FIFO 0x00
|
||||
|
@ -574,11 +575,13 @@ class SX127x: public PhysicalLayer {
|
|||
|
||||
\param currentLimit Trim value for OCP (over current protection) in mA.
|
||||
|
||||
\param preambleLength Length of FSK preamble in bits.
|
||||
|
||||
\param enableOOK Flag to specify OOK mode. This modulation is similar to FSK.
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t beginFSK(uint8_t chipVersion, float br, float freqDev, float rxBw, uint8_t currentLimit, bool enableOOK);
|
||||
int16_t beginFSK(uint8_t chipVersion, float br, float freqDev, float rxBw, uint8_t currentLimit, uint16_t preambleLength, bool enableOOK);
|
||||
|
||||
/*!
|
||||
\brief Binary transmit method. Will transmit arbitrary binary data up to 255 bytes long using %LoRa or up to 63 bytes using FSK modem.
|
||||
|
@ -686,14 +689,16 @@ class SX127x: public PhysicalLayer {
|
|||
/*!
|
||||
\brief Interrupt-driven receive method. DIO0 will be activated when full valid packet is received.
|
||||
|
||||
\param len Expected length of packet to be received. Required for LoRa spreading factor 6.
|
||||
|
||||
\param mode Receive mode to be used. Defaults to RxContinuous.
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t startReceive(uint8_t mode = SX127X_RXCONTINUOUS);
|
||||
int16_t startReceive(uint8_t len = 0, uint8_t mode = SX127X_RXCONTINUOUS);
|
||||
|
||||
/*!
|
||||
\brief Reads data that was received after calling startReceive method.
|
||||
\brief Reads data that was received after calling startReceive method. This method reads len characters.
|
||||
|
||||
\param data Pointer to array to save the received binary data.
|
||||
|
||||
|
@ -828,6 +833,15 @@ class SX127x: public PhysicalLayer {
|
|||
*/
|
||||
int16_t setOOK(bool enableOOK);
|
||||
|
||||
/*!
|
||||
\brief Query modem for the packet length of received payload.
|
||||
|
||||
\param update Update received packet length. Will return cached value when set to false.
|
||||
|
||||
\returns Length of last received packet in bytes.
|
||||
*/
|
||||
size_t getPacketLength(bool update = true);
|
||||
|
||||
#ifdef RADIOLIB_DEBUG
|
||||
void regDump();
|
||||
#endif
|
||||
|
@ -849,13 +863,17 @@ class SX127x: public PhysicalLayer {
|
|||
int16_t getActiveModem();
|
||||
int16_t directMode();
|
||||
|
||||
|
||||
private:
|
||||
float _dataRate;
|
||||
size_t _packetLength;
|
||||
bool _packetLengthQueried; // FSK packet length is the first byte in FIFO, length can only be queried once
|
||||
|
||||
bool findChip(uint8_t ver);
|
||||
int16_t setMode(uint8_t mode);
|
||||
int16_t setActiveModem(uint8_t modem);
|
||||
void clearIRQFlags();
|
||||
void clearFIFO(size_t count); // used mostly to clear remaining bytes in FIFO after a packet read
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "nRF24.h"
|
||||
|
||||
nRF24::nRF24(Module* mod) : PhysicalLayer(NRF24_CRYSTAL_FREQ, NRF24_DIV_EXPONENT) {
|
||||
nRF24::nRF24(Module* mod) : PhysicalLayer(NRF24_CRYSTAL_FREQ, NRF24_DIV_EXPONENT, NRF24_MAX_PACKET_LENGTH) {
|
||||
_mod = mod;
|
||||
}
|
||||
|
||||
|
@ -161,7 +161,7 @@ int16_t nRF24::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
|
|||
(void)addr;
|
||||
|
||||
// check packet length
|
||||
if(len > 32) {
|
||||
if(len > NRF24_MAX_PACKET_LENGTH) {
|
||||
return(ERR_PACKET_TOO_LONG);
|
||||
}
|
||||
|
||||
|
@ -239,19 +239,13 @@ int16_t nRF24::readData(uint8_t* data, size_t len) {
|
|||
return(state);
|
||||
}
|
||||
|
||||
// read payload length
|
||||
uint8_t buff[1];
|
||||
SPItransfer(NRF24_CMD_READ_RX_PAYLOAD_WIDTH, false, NULL, buff, 1);
|
||||
|
||||
size_t length = buff[0];
|
||||
// get packet length
|
||||
size_t length = len;
|
||||
if(len == NRF24_MAX_PACKET_LENGTH) {
|
||||
length = getPacketLength();
|
||||
}
|
||||
|
||||
// read packet data
|
||||
if(len == 0) {
|
||||
// argument 'len' equal to zero indicates String call, which means dynamically allocated data array
|
||||
// dispose of the original and create a new one
|
||||
delete[] data;
|
||||
data = new uint8_t[length + 1];
|
||||
}
|
||||
SPIreadRxPayload(data, length);
|
||||
|
||||
// add terminating null
|
||||
|
@ -479,6 +473,13 @@ int16_t nRF24::setFrequencyDeviation(float freqDev) {
|
|||
return(ERR_NONE);
|
||||
}
|
||||
|
||||
size_t nRF24::getPacketLength(bool update) {
|
||||
(void)update;
|
||||
uint8_t length = 0;
|
||||
SPItransfer(NRF24_CMD_READ_RX_PAYLOAD_WIDTH, false, NULL, &length, 1);
|
||||
return((size_t)length);
|
||||
}
|
||||
|
||||
void nRF24::clearIRQ() {
|
||||
// clear status bits
|
||||
_mod->SPIsetRegValue(NRF24_REG_STATUS, NRF24_RX_DR | NRF24_TX_DS | NRF24_MAX_RT, 6, 4);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
// nRF24 physical layer properties (dummy only)
|
||||
#define NRF24_CRYSTAL_FREQ 1.0
|
||||
#define NRF24_DIV_EXPONENT 0
|
||||
#define NRF24_MAX_PACKET_LENGTH 32
|
||||
|
||||
// nRF24 SPI commands
|
||||
#define NRF24_CMD_READ 0b00000000
|
||||
|
@ -398,6 +399,15 @@ class nRF24: public PhysicalLayer {
|
|||
*/
|
||||
int16_t setFrequencyDeviation(float freqDev);
|
||||
|
||||
/*!
|
||||
\brief Query modem for the packet length of received payload.
|
||||
|
||||
\param update Update received packet length. Will return cached value when set to false.
|
||||
|
||||
\returns Length of last received packet in bytes.
|
||||
*/
|
||||
size_t getPacketLength(bool update = true);
|
||||
|
||||
private:
|
||||
Module* _mod;
|
||||
|
||||
|
|
|
@ -21,8 +21,8 @@ int16_t HTTPClient::get(const char* url, String& response) {
|
|||
char* hostEnd = strchr(hostStart + 1, '/');
|
||||
host = new char[hostEnd - hostStart];
|
||||
strncpy(host, hostStart + 1, hostEnd - hostStart - 1);
|
||||
host[hostEnd - hostStart - 1] = 0x00;
|
||||
|
||||
host[hostEnd - hostStart - 1] = '\0';
|
||||
|
||||
// find the endpoint string
|
||||
endpoint = new char[url + strlen(url) - hostEnd + 1];
|
||||
strcpy(endpoint, hostEnd);
|
||||
|
@ -31,23 +31,23 @@ int16_t HTTPClient::get(const char* url, String& response) {
|
|||
char* hostEnd = strchr(url, '/');
|
||||
host = new char[hostEnd - url + 1];
|
||||
strncpy(host, url, hostEnd - url);
|
||||
host[hostEnd - url] = 0x00;
|
||||
|
||||
host[hostEnd - url] = '\0';
|
||||
|
||||
// find the endpoint string
|
||||
endpoint = new char[url + strlen(url) - hostEnd + 1];
|
||||
strcpy(endpoint, hostEnd);
|
||||
}
|
||||
|
||||
|
||||
// build the GET request
|
||||
char* request = new char[strlen(endpoint) + strlen(host) + 25];
|
||||
char* request = new char[strlen(endpoint) + strlen(host) + 25 + 1];
|
||||
strcpy(request, "GET ");
|
||||
strcat(request, endpoint);
|
||||
strcat(request, " HTTP/1.1\r\nHost: ");
|
||||
strcat(request, host);
|
||||
strcat(request, "\r\n\r\n");
|
||||
|
||||
|
||||
delete[] endpoint;
|
||||
|
||||
|
||||
// create TCP connection
|
||||
int16_t state = _tl->openTransportConnection(host, "TCP", _port);
|
||||
delete[] host;
|
||||
|
@ -55,49 +55,49 @@ int16_t HTTPClient::get(const char* url, String& response) {
|
|||
delete[] request;
|
||||
return(state);
|
||||
}
|
||||
|
||||
|
||||
// send the GET request
|
||||
state = _tl->send(request);
|
||||
delete[] request;
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
|
||||
//delay(1000);
|
||||
|
||||
|
||||
// get the response length
|
||||
size_t numBytes = _tl->getNumBytes();
|
||||
if(numBytes == 0) {
|
||||
return(ERR_RESPONSE_MALFORMED_AT);
|
||||
}
|
||||
|
||||
|
||||
// read the response
|
||||
char* raw = new char[numBytes];
|
||||
char* raw = new char[numBytes + 1];
|
||||
size_t rawLength = _tl->receive((uint8_t*)raw, numBytes);
|
||||
if(rawLength == 0) {
|
||||
delete[] raw;
|
||||
return(ERR_RESPONSE_MALFORMED);
|
||||
}
|
||||
|
||||
|
||||
// close the tl connection
|
||||
state = _tl->closeTransportConnection();
|
||||
if(state != ERR_NONE) {
|
||||
delete[] raw;
|
||||
return(state);
|
||||
}
|
||||
|
||||
|
||||
// get the response body
|
||||
char* responseStart = strstr(raw, "\r\n");
|
||||
if(responseStart == NULL) {
|
||||
delete[] raw;
|
||||
return(ERR_RESPONSE_MALFORMED);
|
||||
}
|
||||
char* responseStr = new char[raw + rawLength - responseStart - 1];
|
||||
char* responseStr = new char[raw + rawLength - responseStart - 1 + 1];
|
||||
strncpy(responseStr, responseStart + 2, raw + rawLength - responseStart - 1);
|
||||
responseStr[raw + rawLength - responseStart - 2] = 0x00;
|
||||
responseStr[raw + rawLength - responseStart - 2] = '\0';
|
||||
response = String(responseStr);
|
||||
delete[] responseStr;
|
||||
|
||||
|
||||
// return the HTTP status code
|
||||
char* statusStart = strchr(raw, ' ');
|
||||
delete[] raw;
|
||||
|
@ -122,8 +122,8 @@ int16_t HTTPClient::post(const char* url, const char* content, String& response,
|
|||
char* hostEnd = strchr(hostStart + 1, '/');
|
||||
host = new char[hostEnd - hostStart];
|
||||
strncpy(host, hostStart + 1, hostEnd - hostStart - 1);
|
||||
host[hostEnd - hostStart - 1] = 0x00;
|
||||
|
||||
host[hostEnd - hostStart - 1] = '\0';
|
||||
|
||||
// find the endpoint string
|
||||
endpoint = new char[url + strlen(url) - hostEnd + 1];
|
||||
strcpy(endpoint, hostEnd);
|
||||
|
@ -132,17 +132,17 @@ int16_t HTTPClient::post(const char* url, const char* content, String& response,
|
|||
char* hostEnd = strchr(url, '/');
|
||||
host = new char[hostEnd - url + 1];
|
||||
strncpy(host, url, hostEnd - url);
|
||||
host[hostEnd - url] = 0x00;
|
||||
|
||||
host[hostEnd - url] = '\0';
|
||||
|
||||
// find the endpoint string
|
||||
endpoint = new char[url + strlen(url) - hostEnd + 1];
|
||||
strcpy(endpoint, hostEnd);
|
||||
}
|
||||
|
||||
|
||||
// build the POST request
|
||||
char contentLengthStr[8];
|
||||
itoa(strlen(content), contentLengthStr, 10);
|
||||
char* request = new char[strlen(endpoint) + strlen(host) + strlen(contentType) + strlen(contentLengthStr) + strlen(content) + 64];
|
||||
char* request = new char[strlen(endpoint) + strlen(host) + strlen(contentType) + strlen(contentLengthStr) + strlen(content) + 64 + 1];
|
||||
strcpy(request, "POST ");
|
||||
strcat(request, endpoint);
|
||||
strcat(request, " HTTP/1.1\r\nHost: ");
|
||||
|
@ -154,29 +154,30 @@ int16_t HTTPClient::post(const char* url, const char* content, String& response,
|
|||
strcat(request, "\r\n\r\n");
|
||||
strcat(request, content);
|
||||
strcat(request, "\r\n\r\n");
|
||||
|
||||
|
||||
delete[] endpoint;
|
||||
|
||||
|
||||
// create TCP connection
|
||||
int16_t state = _tl->openTransportConnection(host, "TCP", _port);
|
||||
delete[] host;
|
||||
if(state != ERR_NONE) {
|
||||
delete[] request;
|
||||
return(state);
|
||||
}
|
||||
|
||||
|
||||
// send the POST request
|
||||
state = _tl->send(request);
|
||||
delete[] request;
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
|
||||
// get the response length
|
||||
size_t numBytes = _tl->getNumBytes();
|
||||
if(numBytes == 0) {
|
||||
return(ERR_RESPONSE_MALFORMED_AT);
|
||||
}
|
||||
|
||||
|
||||
// read the response
|
||||
char* raw = new char[numBytes];
|
||||
size_t rawLength = _tl->receive((uint8_t*)raw, numBytes);
|
||||
|
@ -184,14 +185,14 @@ int16_t HTTPClient::post(const char* url, const char* content, String& response,
|
|||
delete[] raw;
|
||||
return(ERR_RESPONSE_MALFORMED);
|
||||
}
|
||||
|
||||
|
||||
// close the tl connection
|
||||
state = _tl->closeTransportConnection();
|
||||
if(state != ERR_NONE) {
|
||||
delete[] raw;
|
||||
return(state);
|
||||
}
|
||||
|
||||
|
||||
// get the response body
|
||||
char* responseStart = strstr(raw, "\r\n");
|
||||
if(responseStart == NULL) {
|
||||
|
@ -203,7 +204,7 @@ int16_t HTTPClient::post(const char* url, const char* content, String& response,
|
|||
responseStr[raw + rawLength - responseStart - 2] = 0x00;
|
||||
response = String(responseStr);
|
||||
delete[] responseStr;
|
||||
|
||||
|
||||
// return the HTTP status code
|
||||
char* statusStart = strchr(raw, ' ');
|
||||
delete[] raw;
|
||||
|
|
|
@ -6,66 +6,66 @@
|
|||
*/
|
||||
struct Morse_t {
|
||||
char c; // ASCII character
|
||||
const char* m; // Morse code representation
|
||||
char m[7]; // Morse code representation
|
||||
};
|
||||
/*!
|
||||
\endcond
|
||||
*/
|
||||
|
||||
// array of all Morse code characters
|
||||
static const Morse_t MorseTable[MORSE_LENGTH] = {
|
||||
{.c = 'A', .m = ".-"},
|
||||
{.c = 'B', .m = "-..."},
|
||||
{.c = 'C', .m = "-.-."},
|
||||
{.c = 'D', .m = "-.."},
|
||||
{.c = 'E', .m = "."},
|
||||
{.c = 'F', .m = "..-."},
|
||||
{.c = 'G', .m = "--."},
|
||||
{.c = 'H', .m = "...."},
|
||||
{.c = 'I', .m = ".."},
|
||||
{.c = 'J', .m = ".---"},
|
||||
{.c = 'K', .m = "-.-"},
|
||||
{.c = 'L', .m = ".-.."},
|
||||
{.c = 'M', .m = "--"},
|
||||
{.c = 'N', .m = "-."},
|
||||
{.c = 'O', .m = "---"},
|
||||
{.c = 'P', .m = ".--."},
|
||||
{.c = 'Q', .m = "--.-"},
|
||||
{.c = 'R', .m = ".-."},
|
||||
{.c = 'S', .m = "..."},
|
||||
{.c = 'T', .m = "-"},
|
||||
{.c = 'U', .m = "..-"},
|
||||
{.c = 'V', .m = "...-"},
|
||||
{.c = 'W', .m = ".--"},
|
||||
{.c = 'X', .m = "-..-"},
|
||||
{.c = 'Y', .m = "-.--"},
|
||||
{.c = 'Z', .m = "--.."},
|
||||
{.c = '1', .m = ".----"},
|
||||
{.c = '2', .m = "..---"},
|
||||
{.c = '3', .m = "...--"},
|
||||
{.c = '4', .m = "....-"},
|
||||
{.c = '5', .m = "....."},
|
||||
{.c = '6', .m = "-...."},
|
||||
{.c = '7', .m = "--..."},
|
||||
{.c = '8', .m = "---.."},
|
||||
{.c = '9', .m = "----."},
|
||||
{.c = '0', .m = "-----"},
|
||||
{.c = '.', .m = ".-.-.-"},
|
||||
{.c = ',', .m = "--..--"},
|
||||
{.c = ':', .m = "---..."},
|
||||
{.c = '?', .m = "..--.."},
|
||||
{.c = '\'', .m = ".----."},
|
||||
{.c = '-', .m = "-....-"},
|
||||
{.c = '/', .m = "-..-."},
|
||||
{.c = '(', .m = "-.--."},
|
||||
{.c = ')', .m = "-.--.-"},
|
||||
{.c = '\"', .m = ".-..-."},
|
||||
{.c = '=', .m = "-...-"},
|
||||
{.c = '+', .m = ".-.-."},
|
||||
{.c = '@', .m = ".--.-."},
|
||||
{.c = ' ', .m = "_"}, // space is used to separate words
|
||||
{.c = 0x01, .m = "-.-.-"}, // ASCII SOH (start of heading) is used as alias for start signal
|
||||
{.c = 0x02, .m = ".-.-."} // ASCII EOT (end of transmission) is used as alias for stop signal
|
||||
const Morse_t MorseTable[MORSE_LENGTH] PROGMEM = {
|
||||
{'A', ".-"},
|
||||
{'B',"-..."},
|
||||
{'C', "-.-."},
|
||||
{'D',"-.."},
|
||||
{'E',"."},
|
||||
{'F',"..-."},
|
||||
{'G',"--."},
|
||||
{'H',"...."},
|
||||
{'I',".."},
|
||||
{'J',".---"},
|
||||
{'K',"-.-"},
|
||||
{'L',".-.."},
|
||||
{'M',"--"},
|
||||
{'N',"-."},
|
||||
{'O',"---"},
|
||||
{'P',".--."},
|
||||
{'Q',"--.-"},
|
||||
{'R',".-."},
|
||||
{'S',"..."},
|
||||
{'T',"-"},
|
||||
{'U',"..-"},
|
||||
{'V',"...-"},
|
||||
{'W',".--"},
|
||||
{'X',"-..-"},
|
||||
{'Y',"-.--"},
|
||||
{'Z',"--.."},
|
||||
{'1',".----"},
|
||||
{'2',"..---"},
|
||||
{'3',"...--"},
|
||||
{'4',"....-"},
|
||||
{'5',"....."},
|
||||
{'6',"-...."},
|
||||
{'7',"--..."},
|
||||
{'8',"---.."},
|
||||
{'9',"----."},
|
||||
{'0',"-----"},
|
||||
{'.',".-.-.-"},
|
||||
{',',"--..--"},
|
||||
{':',"---..."},
|
||||
{'?',"..--.."},
|
||||
{'\'',".----."},
|
||||
{'-',"-....-"},
|
||||
{'/',"-..-."},
|
||||
{'(',"-.--."},
|
||||
{')',"-.--.-"},
|
||||
{'\"',".-..-."},
|
||||
{'=',"-...-"},
|
||||
{'+',".-.-."},
|
||||
{'@',".--.-."},
|
||||
{' ',"_"}, // space is used to separate words
|
||||
{0x01,"-.-.-"}, // ASCII SOH (start of heading) is used as alias for start signal
|
||||
{0x02,".-.-."} // ASCII EOT (end of transmission) is used as alias for stop signal
|
||||
};
|
||||
|
||||
MorseClient::MorseClient(PhysicalLayer* phy) {
|
||||
|
@ -107,19 +107,25 @@ size_t MorseClient::write(uint8_t* buff, size_t len) {
|
|||
|
||||
size_t MorseClient::write(uint8_t b) {
|
||||
// find the correct Morse code in array
|
||||
uint8_t pos;
|
||||
Morse_t mc;
|
||||
bool found = false;
|
||||
for(pos = 0; pos < MORSE_LENGTH; pos++) {
|
||||
if(MorseTable[pos].c == toupper(b)) {
|
||||
for(uint8_t pos = 0; pos < MORSE_LENGTH; pos++) {
|
||||
memcpy_P(&mc, &MorseTable[pos], sizeof(Morse_t));
|
||||
if(mc.c == toupper(b)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// check if the requested code was found in the array
|
||||
if(found) {
|
||||
DEBUG_PRINT(mc.c);
|
||||
DEBUG_PRINT('\t');
|
||||
DEBUG_PRINTLN(mc.m);
|
||||
|
||||
// iterate over Morse code representation and output appropriate tones
|
||||
for(uint8_t i = 0; i < strlen(MorseTable[pos].m); i++) {
|
||||
switch(MorseTable[pos].m[i]) {
|
||||
for(uint8_t i = 0; i < strlen(mc.m); i++) {
|
||||
switch(mc.m[i]) {
|
||||
case '.':
|
||||
_phy->transmitDirect(_base);
|
||||
delay(_dotLength);
|
||||
|
@ -139,6 +145,7 @@ size_t MorseClient::write(uint8_t b) {
|
|||
}
|
||||
|
||||
// letter space
|
||||
DEBUG_PRINTLN();
|
||||
delay(_dotLength * 3);
|
||||
|
||||
return(1);
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
#include "PhysicalLayer.h"
|
||||
|
||||
PhysicalLayer::PhysicalLayer(float crysFreq, uint8_t divExp) {
|
||||
PhysicalLayer::PhysicalLayer(float crysFreq, uint8_t divExp, size_t maxPacketLength) {
|
||||
_crystalFreq = crysFreq;
|
||||
_divExponent = divExp;
|
||||
_maxPacketLength = maxPacketLength;
|
||||
}
|
||||
|
||||
int16_t PhysicalLayer::transmit(__FlashStringHelper* fstr, uint8_t addr) {
|
||||
|
@ -49,30 +50,76 @@ int16_t PhysicalLayer::startTransmit(const char* str, uint8_t addr) {
|
|||
}
|
||||
|
||||
int16_t PhysicalLayer::readData(String& str, size_t len) {
|
||||
// create temporary array to store received data
|
||||
char* data = new char[len + 1];
|
||||
int16_t state = readData((uint8_t*)data, len);
|
||||
int16_t state = ERR_NONE;
|
||||
|
||||
// if packet was received successfully, copy data into String
|
||||
if(state == ERR_NONE) {
|
||||
str = String(data);
|
||||
// read the number of actually received bytes
|
||||
size_t length = getPacketLength();
|
||||
|
||||
if((len < length) && (len != 0)) {
|
||||
// user requested less bytes than were received, this is allowed (but frowned upon)
|
||||
// requests for more data than were received will only return the number of actually received bytes (unlike PhysicalLayer::receive())
|
||||
length = len;
|
||||
}
|
||||
|
||||
// build a temporary buffer
|
||||
uint8_t* data = new uint8_t[length + 1];
|
||||
if(!data) {
|
||||
return(ERR_MEMORY_ALLOCATION_FAILED);
|
||||
}
|
||||
|
||||
// read the received data
|
||||
state = readData(data, length);
|
||||
|
||||
if(state == ERR_NONE) {
|
||||
// add null terminator
|
||||
data[length] = 0;
|
||||
|
||||
// initialize Arduino String class
|
||||
str = String((char*)data);
|
||||
}
|
||||
|
||||
// deallocate temporary buffer
|
||||
delete[] data;
|
||||
|
||||
return(state);
|
||||
}
|
||||
|
||||
int16_t PhysicalLayer::receive(String& str, size_t len) {
|
||||
// create temporary array to store received data
|
||||
char* data = new char[len + 1];
|
||||
int16_t state = receive((uint8_t*)data, len);
|
||||
int16_t state = ERR_NONE;
|
||||
|
||||
// if packet was received successfully, copy data into String
|
||||
if(state == ERR_NONE) {
|
||||
str = String(data);
|
||||
// user can override the length of data to read
|
||||
size_t length = len;
|
||||
|
||||
if(len == 0) {
|
||||
// unknown packet length, set to maximum
|
||||
length = _maxPacketLength;
|
||||
}
|
||||
|
||||
// build a temporary buffer
|
||||
uint8_t* data = new uint8_t[length + 1];
|
||||
if(!data) {
|
||||
return(ERR_MEMORY_ALLOCATION_FAILED);
|
||||
}
|
||||
|
||||
// attempt packet reception
|
||||
state = receive(data, length);
|
||||
|
||||
if(state == ERR_NONE) {
|
||||
// read the number of actually received bytes (for unknown packets)
|
||||
if(len == 0) {
|
||||
length = getPacketLength(false);
|
||||
}
|
||||
|
||||
// add null terminator
|
||||
data[length] = 0;
|
||||
|
||||
// initialize Arduino String class
|
||||
str = String((char*)data);
|
||||
}
|
||||
|
||||
// deallocate temporary buffer
|
||||
delete[] data;
|
||||
|
||||
return(state);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,8 +21,10 @@ class PhysicalLayer {
|
|||
\param crysFreq Frequency of crystal oscillator inside the module in MHz.
|
||||
|
||||
\param divExp Exponent of module frequency divider.
|
||||
|
||||
\param maxPacketLength Maximum length of packet that can be received by the module-
|
||||
*/
|
||||
PhysicalLayer(float crysFreq, uint8_t divExp);
|
||||
PhysicalLayer(float crysFreq, uint8_t divExp, size_t maxPacketLength);
|
||||
|
||||
// basic methods
|
||||
|
||||
|
@ -77,12 +79,19 @@ class PhysicalLayer {
|
|||
|
||||
\param str Address of Arduino String to save the received data.
|
||||
|
||||
\param len Expected number of characters in the message.
|
||||
\param len Expected number of characters in the message. Leave as 0 if expecting a unknown size packet
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t receive(String& str, size_t len = 0);
|
||||
|
||||
/*!
|
||||
\brief Sets module to standby.
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
virtual int16_t standby() = 0;
|
||||
|
||||
/*!
|
||||
\brief Binary receive method. Must be implemented in module class.
|
||||
|
||||
|
@ -94,13 +103,6 @@ class PhysicalLayer {
|
|||
*/
|
||||
virtual int16_t receive(uint8_t* data, size_t len) = 0;
|
||||
|
||||
/*!
|
||||
\brief Sets module to standby.
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
virtual int16_t standby() = 0;
|
||||
|
||||
/*!
|
||||
\brief Interrupt-driven Arduino String transmit method. Unlike the standard transmit method, this one is non-blocking.
|
||||
Interrupt pin will be activated when transmission finishes.
|
||||
|
@ -204,9 +206,19 @@ class PhysicalLayer {
|
|||
*/
|
||||
uint8_t getDivExponent();
|
||||
|
||||
/*!
|
||||
\brief Query modem for the packet length of received payload.
|
||||
|
||||
\param update Update received packet length. Will return cached value when set to false.
|
||||
|
||||
\returns Length of last received packet in bytes.
|
||||
*/
|
||||
virtual size_t getPacketLength(bool update = true) = 0;
|
||||
|
||||
private:
|
||||
float _crystalFreq;
|
||||
uint8_t _divExponent;
|
||||
size_t _maxPacketLength;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -84,11 +84,11 @@ uint16_t ITA2String::getBits(char c) {
|
|||
// search ITA2 table
|
||||
uint16_t code = 0x0000;
|
||||
for(uint8_t i = 0; i < ITA2_LENGTH; i++) {
|
||||
if(ITA2Table[i][0] == c) {
|
||||
if(pgm_read_byte(&ITA2Table[i][0]) == c) {
|
||||
// character is in letter shift
|
||||
code = (ITA2_LTRS << 5) | i;
|
||||
break;
|
||||
} else if(ITA2Table[i][1] == c) {
|
||||
} else if(pgm_read_byte(&ITA2Table[i][1]) == c) {
|
||||
// character is in figures shift
|
||||
code = (ITA2_FIGS << 5) | i;
|
||||
break;
|
||||
|
|
|
@ -11,10 +11,10 @@
|
|||
// ITA2 character table: - position in array corresponds to 5-bit ITA2 code
|
||||
// - characters to the left are in letters shift, characters to the right in figures shift
|
||||
// - characters marked 0x7F do not have ASCII equivalent
|
||||
static const char ITA2Table[ITA2_LENGTH][2] = {{'\0', '\0'}, {'E', '3'}, {'\n', '\n'}, {'A', '-'}, {' ', ' '}, {'S', '\''}, {'I', '8'}, {'U', '7'},
|
||||
{'\r', '\r'}, {'D', 0x05}, {'R', '4'}, {'J', '\a'}, {'N', ','}, {'F', '!'}, {'C', ':'}, {'K', '('},
|
||||
{'T', '5'}, {'Z', '+'}, {'L', ')'}, {'W', '2'}, {'H', 0x7F}, {'Y', '6'}, {'P', '0'}, {'Q', '1'},
|
||||
{'O', '9'}, {'B', '?'}, {'G', '&'}, {0x7F, 0x7F}, {'M', '.'}, {'X', '/'}, {'V', ';'}, {0x7F, 0x7F}};
|
||||
static const char ITA2Table[ITA2_LENGTH][2] PROGMEM = {{'\0', '\0'}, {'E', '3'}, {'\n', '\n'}, {'A', '-'}, {' ', ' '}, {'S', '\''}, {'I', '8'}, {'U', '7'},
|
||||
{'\r', '\r'}, {'D', 0x05}, {'R', '4'}, {'J', '\a'}, {'N', ','}, {'F', '!'}, {'C', ':'}, {'K', '('},
|
||||
{'T', '5'}, {'Z', '+'}, {'L', ')'}, {'W', '2'}, {'H', 0x7F}, {'Y', '6'}, {'P', '0'}, {'Q', '1'},
|
||||
{'O', '9'}, {'B', '?'}, {'G', '&'}, {0x7F, 0x7F}, {'M', '.'}, {'X', '/'}, {'V', ';'}, {0x7F, 0x7F}};
|
||||
|
||||
/*!
|
||||
\class ITA2String
|
||||
|
|
Loading…
Add table
Reference in a new issue