Merge branch 'master' into development

This commit is contained in:
jgromes 2019-09-17 17:58:43 +02:00
commit 1155851481
81 changed files with 2357 additions and 974 deletions

View file

@ -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;

View file

@ -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!"

View file

@ -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.

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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,

View file

@ -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);

View file

@ -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);
}

View file

@ -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

View file

@ -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;
}
}

View file

@ -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);

View file

@ -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

View file

@ -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);
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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

View file

@ -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 {

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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,

View file

@ -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);

View file

@ -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);
}

View file

@ -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

View file

@ -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

View file

@ -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;
}
}

View file

@ -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 {

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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);

View file

@ -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);
}
}

View file

@ -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,

View file

@ -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!"));
}

View file

@ -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);
}

View file

@ -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;
}
}

View file

@ -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);

View file

@ -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);

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -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);

View file

@ -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

View file

@ -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;
}
}

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);
}
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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());
}

View file

@ -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);

View file

@ -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.

View file

@ -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

View file

@ -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.

View file

@ -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);

View file

@ -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);

View file

@ -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

View file

@ -1,4 +1,4 @@
#ifndef _RADIOLIB_ESP8266_H
#if !defined(_RADIOLIB_ESP8266_H) && !defined(ESP8266)
#define _RADIOLIB_ESP8266_H
#include "Module.h"

View file

@ -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;

View file

@ -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();

View file

@ -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));
}

View file

@ -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
View 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));
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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();

View file

@ -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

View file

@ -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();

View file

@ -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

View file

@ -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();

View file

@ -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

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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);
}

View file

@ -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

View file

@ -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;

View file

@ -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