Merge branch 'master' into development

This commit is contained in:
jgromes 2020-02-21 07:46:21 +01:00
commit 8a791d269e
88 changed files with 3064 additions and 1847 deletions

View file

@ -11,7 +11,7 @@ assignees: ''
Before submitting new issue, please check the [Wiki](https://github.com/jgromes/RadioLib/wiki) and the [API documentation](https://jgromes.github.io/RadioLib/). You might find a solution to your issue there.
**Describe the bug**
A clear and concise description of what the bug is.
A clear and concise description of what the bug is. When applicable, please include debug mode output: uncomment [debug macro definitions in TypeDef.h](https://github.com/jgromes/RadioLib/blob/master/src/TypeDef.h#L36) and post the output.
**To Reproduce**
Minimal Arduino sketch to reproduce the behavior. Please user Markdown to style the code to make it readable (see [Markdown Cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#code)).

View file

@ -7,6 +7,7 @@ env:
- BOARD="esp32:esp32:esp32"
- BOARD="STM32:stm32:GenF3:pnum=BLACKPILL_F303CC"
- BOARD="esp8266:esp8266:generic:xtal=80,ResetMethod=ck,CrystalFreq=26,FlashFreq=40,FlashMode=qio,eesz=512K"
# - BOARD="SparkFun:apollo3:amap3redboard"
- BOARD="arduino:samd:arduino_zero_native"
- BOARD="arduino:sam:arduino_due_x"
- BOARD="arduino:avr:uno"
@ -29,7 +30,7 @@ before_install:
- 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://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json,https://github.com/stm32duino/BoardManagerFiles/raw/master/STM32/package_stm_index.json" --save-prefs 2>&1
- arduino --pref "boardsmanager.additional.urls=http://arduino.esp8266.com/stable/package_esp8266com_index.json,https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json,https://github.com/stm32duino/BoardManagerFiles/raw/master/STM32/package_stm_index.json,https://raw.githubusercontent.com/sparkfun/Arduino_Boards/master/IDE_Board_Manager/package_sparkfun_index.json" --save-prefs 2>&1
- if [[ "$BOARD" =~ "esp8266:esp8266:" ]]; then
arduino --install-boards esp8266:esp8266;
export SKIP_PAT='(HTTP|MQTT).*ino';
@ -41,6 +42,8 @@ before_install:
arduino --install-boards arduino:samd;
elif [[ "$BOARD" =~ "arduino:sam:" ]]; then
arduino --install-boards arduino:sam;
elif [[ "$BOARD" =~ "SparkFun:apollo3:" ]]; then
arduino --install-boards SparkFun:apollo3;
fi
# create directory to save the library and create symbolic link

View file

@ -15,8 +15,6 @@ 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.
5. **LoRaLib is a separate project.**
RadioLib was created as an extension of LoRaLib for radios other than SX127x. However, LoRaLib project is still active and RadioLib is reusing its code. **Because of that, please open issues/PRs related to SX127x in [LoRaLib](https://github.com/jgromes/LoRaLib)**.
## Code style guidelines

View file

@ -27,14 +27,21 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github
* __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
* __AX.25__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231 and CC1101
### 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 Nucleo L452RE-P
* __SAMD boards__ - Arduino Zero
* __SAM boards__ - Arduino Due
* __AVR__ - tested with hardware on Uno, Mega and Leonardo
* __ESP8266__ - tested with hardware on NodeMCU and Wemos D1
* __ESP32__ - tested with hardware on ESP-WROOM-32
* __STM32__ - tested with hardware on Nucleo L452RE-P
* __SAMD__ - Arduino Zero, Arduino MKR boards, M0 Pro etc.
* __SAM__ - Arduino Due
* __nRF52__ - Adafruit Bluefruit Feather etc.
* _Intel Curie_ - Arduino 101
* _megaAVR_ - Arduino Uno WiFi Rev.2 etc.
* _Apollo3_ - SparkFun Artemis Redboard etc.
The list above is by no means exhaustive. Most of RadioLib code is independent of the used platform, so as long as your board is running some Arduino-compatible core, RadioLib should work. Compilation of all examples is tested for all platoforms in __bold__ on each git push. Platforms in _italic_ are not tested on each push, but do compile and should be working.
### In development:
* __SIM800C__ GSM module
@ -46,5 +53,8 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github
### 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!
### Help, my module isn't working!
The fastest way to get help is by creating an [issue](https://github.com/jgromes/RadioLib/issues/new?assignees=&labels=&template=bug_report.md&title=) using the appropriate template. It is also highly recommended to try running the examples first - their functionality is tested from time to time and they should work. Finally, RadioLib is still under development, which means that sometimes, backwards-incompatible changes might be introduced. Though these are kept at minimum, sometimes it is unavoidable. You can check the [release changelog](https://github.com/jgromes/RadioLib/releases) to find out if there's been such a major change recently.
### 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

@ -0,0 +1,167 @@
/*
RadioLib AX.25 Frame Example
This example shows how to send various
AX.25 frames using SX1278's FSK modem.
Other modules that can be used for AX.25:
- SX127x/RFM9x
- RF69
- SX1231
- CC1101
- SX126x
- nRF24
Using raw AX.25 frames requires some
knowledge of the protocol, refer to
AX25_Transmit for basic operation.
Frames shown in this example are not
exhaustive; all possible AX.25 frames
should be supported.
*/
// include the library
#include <RadioLib.h>
// SX1278 has the following connections:
// NSS pin: 10
// DIO0 pin: 2
// RESET pin: 9
// DIO1 pin: 3
SX1278 fsk = new Module(10, 2, 9, 3);
// or using RadioShield
// https://github.com/jgromes/RadioShield
//SX1278 fsk = RadioShield.ModuleA;
// create AX.25 client instance using the FSK module
AX25Client ax25(&fsk);
void setup() {
Serial.begin(9600);
// initialize SX1278
Serial.print(F("[SX1278] Initializing ... "));
// carrier frequency: 434.0 MHz
// bit rate: 1.2 kbps (1200 baud AFSK AX.25)
// frequency deviation: 0.5 kHz (1200 baud AFSK AX.25)
int state = fsk.beginFSK(434.0, 1.2, 0.5);
// when using one of the non-LoRa modules for AX.25
// (RF69, CC1101, etc.), use the basic begin() method
// int state = fsk.begin();
if(state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while(true);
}
// initialize AX.25 client
Serial.print(F("[AX.25] Initializing ... "));
// source station callsign: "N7LEM"
// source station SSID: 0
// preamble length: 8 bytes
state = ax25.begin("N7LEM");
if(state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while(true);
}
}
void loop() {
// create AX.25 Unnumbered Information frame
// destination station callsign: "NJ7P"
// destination station SSID: 0
// source station callsign: "N7LEM"
// source station SSID: 0
// control field: UI, P/F not used, unnumbered frame
// protocol identifier: no layer 3 protocol implemented
// information field: "Hello World!"
AX25Frame frameUI("NJ7P", 0, "N7LEM", 0, AX25_CONTROL_U_UNNUMBERED_INFORMATION |
AX25_CONTROL_POLL_FINAL_DISABLED | AX25_CONTROL_UNNUMBERED_FRAME,
AX25_PID_NO_LAYER_3, "Hello World (unnumbered)!");
// send the frame
Serial.print(F("[AX.25] Sending UI frame ... "));
int state = ax25.sendFrame(&frameUI);
if (state == ERR_NONE) {
// the packet was successfully transmitted
Serial.println(F("success!"));
} else {
// some error occurred
Serial.print(F("failed, code "));
Serial.println(state);
}
delay(1000);
// create AX.25 Receive Ready frame
// destination station callsign: "NJ7P"
// destination station SSID: 0
// source station callsign: "N7LEM"
// source station SSID: 0
// control field: RR, P/F not used, supervisory frame
AX25Frame frameRR("NJ7P", 0, "N7LEM", 0, AX25_CONTROL_S_RECEIVE_READY |
AX25_CONTROL_POLL_FINAL_DISABLED | AX25_CONTROL_SUPERVISORY_FRAME);
// set receive sequence number (0 - 7)
frameRR.setRecvSequence(0);
// send the frame
Serial.print(F("[AX.25] Sending RR frame ... "));
state = ax25.sendFrame(&frameRR);
if (state == ERR_NONE) {
// the packet was successfully transmitted
Serial.println(F("success!"));
} else {
// some error occurred
Serial.print(F("failed, code "));
Serial.println(state);
}
delay(1000);
// create AX.25 Information frame
// destination station callsign: "NJ7P"
// destination station SSID: 0
// source station callsign: "N7LEM"
// source station SSID: 0
// control field: P/F not used, information frame
// protocol identifier: no layer 3 protocol implemented
// information field: "Hello World (numbered)!"
AX25Frame frameI("NJ7P", 0, "N7LEM", 0, AX25_CONTROL_POLL_FINAL_DISABLED |
AX25_CONTROL_INFORMATION_FRAME, AX25_PID_NO_LAYER_3,
"Hello World (numbered)!");
// set receive sequence number (0 - 7)
frameI.setRecvSequence(0);
// set send sequence number (0 - 7)
frameI.setSendSequence(0);
// send the frame
Serial.print(F("[AX.25] Sending I frame ... "));
state = ax25.sendFrame(&frameI);
if (state == ERR_NONE) {
// the packet was successfully transmitted
Serial.println(F("success!"));
} else {
// some error occurred
Serial.print(F("failed, code "));
Serial.println(state);
}
delay(1000);
}

View file

@ -0,0 +1,88 @@
/*
RadioLib AX.25 Transmit Example
This example sends AX.25 messages using
SX1278's FSK modem.
Other modules that can be used for AX.25:
- SX127x/RFM9x
- RF69
- SX1231
- CC1101
- SX126x
- nRF24
*/
// include the library
#include <RadioLib.h>
// SX1278 has the following connections:
// NSS pin: 10
// DIO0 pin: 2
// RESET pin: 9
// DIO1 pin: 3
SX1278 fsk = new Module(10, 2, 9, 3);
// or using RadioShield
// https://github.com/jgromes/RadioShield
//SX1278 fsk = RadioShield.ModuleA;
// create AX.25 client instance using the FSK module
AX25Client ax25(&fsk);
void setup() {
Serial.begin(9600);
// initialize SX1278
Serial.print(F("[SX1278] Initializing ... "));
// carrier frequency: 434.0 MHz
// bit rate: 1.2 kbps (1200 baud AFSK AX.25)
// frequency deviation: 0.5 kHz (1200 baud AFSK AX.25)
int state = fsk.beginFSK(434.0, 1.2, 0.5);
// when using one of the non-LoRa modules for AX.25
// (RF69, CC1101, etc.), use the basic begin() method
// int state = fsk.begin();
if(state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while(true);
}
// initialize AX.25 client
Serial.print(F("[AX.25] Initializing ... "));
// source station callsign: "N7LEM"
// source station SSID: 0
// preamble length: 8 bytes
state = ax25.begin("N7LEM");
if(state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while(true);
}
}
void loop() {
// send AX.25 unnumbered infomration frame
Serial.print(F("[AX.25] Sending UI frame ... "));
// destination station callsign: "NJ7P"
// destination station SSID: 0
int state = ax25.transmit("Hello World!", "NJ7P");
if (state == ERR_NONE) {
// the packet was successfully transmitted
Serial.println(F("success!"));
} else {
// some error occurred
Serial.print(F("failed, code "));
Serial.println(state);
}
delay(1000);
}

View file

@ -17,10 +17,11 @@
#include <RadioLib.h>
// CC1101 has the following connections:
// NSS pin: 10
// CS pin: 10
// GDO0 pin: 2
// GDO2 pin: 3
CC1101 cc = new Module(10, 2, 3);
// RST pin: unused
// GDO2 pin: 3 (optional)
CC1101 cc = new Module(10, 2, NC, 3);
// or using RadioShield
// https://github.com/jgromes/RadioShield
@ -33,8 +34,8 @@ void setup() {
Serial.print(F("[CC1101] Initializing ... "));
// carrier frequency: 868.0 MHz
// bit rate: 4.8 kbps
// Rx bandwidth: 325.0 kHz
// frequency deviation: 48.0 kHz
// Rx bandwidth: 325.0 kHz
// sync word: 0xD391
int state = cc.begin();
if (state == ERR_NONE) {

View file

@ -15,10 +15,11 @@
#include <RadioLib.h>
// CC1101 has the following connections:
// NSS pin: 10
// CS pin: 10
// GDO0 pin: 2
// GDO2 pin: 3
CC1101 cc = new Module(10, 2, 3);
// RST pin: unused
// GDO2 pin: 3 (optional)
CC1101 cc = new Module(10, 2, NC, 3);
// or using RadioShield
// https://github.com/jgromes/RadioShield
@ -31,8 +32,8 @@ void setup() {
Serial.print(F("[CC1101] Initializing ... "));
// carrier frequency: 868.0 MHz
// bit rate: 4.8 kbps
// Rx bandwidth: 325.0 kHz
// frequency deviation: 48.0 kHz
// Rx bandwidth: 325.0 kHz
// sync word: 0xD391
int state = cc.begin();
if (state == ERR_NONE) {

View file

@ -20,10 +20,11 @@
#include <RadioLib.h>
// CC1101 has the following connections:
// NSS pin: 10
// CS pin: 10
// GDO0 pin: 2
// GDO2 pin: 3
CC1101 cc = new Module(10, 2, 3);
// RST pin: unused
// GDO2 pin: 3 (optional)
CC1101 cc = new Module(10, 2, NC, 3);
// or using RadioShield
// https://github.com/jgromes/RadioShield
@ -36,8 +37,8 @@ void setup() {
Serial.print(F("[CC1101] Initializing ... "));
// carrier frequency: 868.0 MHz
// bit rate: 4.8 kbps
// Rx bandwidth: 325.0 kHz
// frequency deviation: 48.0 kHz
// Rx bandwidth: 325.0 kHz
// sync word: 0xD391
int state = cc.begin();
if (state == ERR_NONE) {
@ -110,7 +111,7 @@ void loop() {
// you can also read received data as byte array
/*
byte byteArr[8];
int state = cc.receive(byteArr, 8);
int state = cc.readData(byteArr, 8);
*/
if (state == ERR_NONE) {

View file

@ -19,14 +19,22 @@
#include <RadioLib.h>
// CC1101 has the following connections:
// NSS pin: 10
// CS pin: 10
// GDO0 pin: 2
// GDO2 pin: 3
CC1101 cc1 = new Module(10, 2, 3);
// RST pin: unused
// GDO2 pin: 3 (optional)
CC1101 cc1 = new Module(10, 2, NC, 3);
// second CC1101 has different connections:
// CS pin: 9
// GDO0 pin: 4
// RST pin: unused
// GDO2 pin: 5 (optional)
CC1101 cc2 = new Module(9, 4, NC, 53);
// or using RadioShield
// https://github.com/jgromes/RadioShield
CC1101 cc2 = RadioShield.ModuleB;
//CC1101 cc3 = RadioShield.ModuleB;
void setup() {
Serial.begin(9600);
@ -35,8 +43,8 @@ void setup() {
Serial.print(F("[CC1101] Initializing ... "));
// carrier frequency: 868.0 MHz
// bit rate: 4.8 kbps
// Rx bandwidth: 325.0 kHz
// frequency deviation: 48.0 kHz
// Rx bandwidth: 325.0 kHz
// sync word: 0xD391
int state = cc1.begin();
if (state == ERR_NONE) {
@ -51,10 +59,10 @@ void setup() {
Serial.print(F("[CC1101] Initializing ... "));
// carrier frequency: 434.0 MHz
// bit rate: 32.0 kbps
// Rx bandwidth: 250.0 kHz
// frequency deviation: 60.0 kHz
// Rx bandwidth: 250.0 kHz
// sync word: 0xD391
state = cc2.begin(434.0, 32.0, 250.0, 60.0);
state = cc2.begin(434.0, 32.0, 60.0, 250.0);
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {

View file

@ -15,10 +15,11 @@
#include <RadioLib.h>
// CC1101 has the following connections:
// NSS pin: 10
// CS pin: 10
// GDO0 pin: 2
// GDO2 pin: 3
CC1101 cc = new Module(10, 2, 3);
// RST pin: unused
// GDO2 pin: 3 (optional)
CC1101 cc = new Module(10, 2, NC, 3);
// or using RadioShield
// https://github.com/jgromes/RadioShield
@ -31,8 +32,8 @@ void setup() {
Serial.print(F("[CC1101] Initializing ... "));
// carrier frequency: 868.0 MHz
// bit rate: 4.8 kbps
// Rx bandwidth: 325.0 kHz
// frequency deviation: 48.0 kHz
// Rx bandwidth: 325.0 kHz
// sync word: 0xD391
int state = cc.begin();
if (state == ERR_NONE) {

View file

@ -15,10 +15,11 @@
#include <RadioLib.h>
// CC1101 has the following connections:
// NSS pin: 10
// CS pin: 10
// GDO0 pin: 2
// GDO2 pin: 3
CC1101 cc = new Module(10, 2, 3);
// RST pin: unused
// GDO2 pin: 3 (optional)
CC1101 cc = new Module(10, 2, NC, 3);
// or using RadioShield
// https://github.com/jgromes/RadioShield
@ -31,8 +32,8 @@ void setup() {
Serial.print(F("[CC1101] Initializing ... "));
// carrier frequency: 868.0 MHz
// bit rate: 4.8 kbps
// Rx bandwidth: 325.0 kHz
// frequency deviation: 48.0 kHz
// Rx bandwidth: 325.0 kHz
// sync word: 0xD391
int state = cc.begin();
if (state == ERR_NONE) {

View file

@ -16,10 +16,11 @@
#include <RadioLib.h>
// CC1101 has the following connections:
// NSS pin: 10
// CS pin: 10
// GDO0 pin: 2
// GDO2 pin: 3
CC1101 cc = new Module(10, 2, 3);
// RST pin: unused
// GDO2 pin: 3 (optional)
CC1101 cc = new Module(10, 2, NC, 3);
// or using RadioShield
// https://github.com/jgromes/RadioShield
@ -35,8 +36,8 @@ void setup() {
Serial.print(F("[CC1101] Initializing ... "));
// carrier frequency: 868.0 MHz
// bit rate: 4.8 kbps
// Rx bandwidth: 325.0 kHz
// frequency deviation: 48.0 kHz
// Rx bandwidth: 325.0 kHz
// sync word: 0xD391
int state = cc.begin();
if (state == ERR_NONE) {
@ -62,7 +63,7 @@ void setup() {
/*
byte byteArr[] = {0x01, 0x23, 0x45, 0x56,
0x78, 0xAB, 0xCD, 0xEF};
state = cc.transmit(byteArr, 8);
state = cc.startTransmit(byteArr, 8);
*/
}
@ -124,7 +125,7 @@ void loop() {
/*
byte byteArr[] = {0x01, 0x23, 0x45, 0x56,
0x78, 0xAB, 0xCD, 0xEF};
int state = cc.transmit(byteArr, 8);
int state = cc.startTransmit(byteArr, 8);
*/
// we're ready to send more packets,

View file

@ -19,8 +19,9 @@
// SX1278 has the following connections:
// NSS pin: 10
// DIO0 pin: 2
// RESET pin: 9
// DIO1 pin: 3
SX1278 fsk = new Module(10, 2, 3);
SX1278 fsk = new Module(10, 2, 9, 3);
// or using RadioShield
// https://github.com/jgromes/RadioShield
@ -104,7 +105,7 @@ void loop() {
// floating point number
// NOTE: When using println(), the transmission will be
// terminated with cross signal (.-.-.).
// terminated with end-of-work signal (...-.-).
float f = -3.1415;
morse.println(f, 3);

View file

@ -17,9 +17,9 @@
#include <RadioLib.h>
// RF69 has the following connections:
// NSS pin: 10
// CS pin: 10
// DIO0 pin: 2
// DIO1 pin: 3
// RESET pin: 3
RF69 rf = new Module(10, 2, 3);
// or using RadioShield
@ -33,8 +33,8 @@ void setup() {
Serial.print(F("[RF69] Initializing ... "));
// carrier frequency: 434.0 MHz
// bit rate: 48.0 kbps
// Rx bandwidth: 125.0 kHz
// frequency deviation: 50.0 kHz
// Rx bandwidth: 125.0 kHz
// output power: 13 dBm
// sync word: 0x2D01
int state = rf.begin();

View file

@ -13,9 +13,9 @@
#include <RadioLib.h>
// RF69 has the following connections:
// NSS pin: 10
// CS pin: 10
// DIO0 pin: 2
// DIO1 pin: 3
// RESET pin: 3
RF69 rf = new Module(10, 2, 3);
// or using RadioShield
@ -29,8 +29,8 @@ void setup() {
Serial.print(F("[RF69] Initializing ... "));
// carrier frequency: 434.0 MHz
// bit rate: 48.0 kbps
// Rx bandwidth: 125.0 kHz
// frequency deviation: 50.0 kHz
// Rx bandwidth: 125.0 kHz
// output power: 13 dBm
// sync word: 0x2D01
int state = rf.begin();

View file

@ -15,9 +15,9 @@
#include <RadioLib.h>
// RF69 has the following connections:
// NSS pin: 10
// CS pin: 10
// DIO0 pin: 2
// DIO1 pin: 3
// RESET pin: 3
RF69 rf = new Module(10, 2, 3);
// or using RadioShield
@ -31,8 +31,8 @@ void setup() {
Serial.print(F("[RF69] Initializing ... "));
// carrier frequency: 434.0 MHz
// bit rate: 48.0 kbps
// Rx bandwidth: 125.0 kHz
// frequency deviation: 50.0 kHz
// Rx bandwidth: 125.0 kHz
// output power: 13 dBm
// sync word: 0x2D01
int state = rf.begin();

View file

@ -13,9 +13,9 @@
#include <RadioLib.h>
// RF69 has the following connections:
// NSS pin: 10
// CS pin: 10
// DIO0 pin: 2
// DIO1 pin: 3
// RESET pin: 3
RF69 rf = new Module(10, 2, 3);
// or using RadioShield
@ -29,8 +29,8 @@ void setup() {
Serial.print(F("[RF69] Initializing ... "));
// carrier frequency: 434.0 MHz
// bit rate: 48.0 kbps
// Rx bandwidth: 125.0 kHz
// frequency deviation: 50.0 kHz
// Rx bandwidth: 125.0 kHz
// output power: 13 dBm
// sync word: 0x2D01
int state = rf.begin();
@ -104,7 +104,7 @@ void loop() {
// you can also read received data as byte array
/*
byte byteArr[8];
int state = lora.receive(byteArr, 8);
int state = lora.readData(byteArr, 8);
*/
if (state == ERR_NONE) {

View file

@ -19,14 +19,20 @@
#include <RadioLib.h>
// RF69 has the following connections:
// NSS pin: 10
// CS pin: 10
// DIO0 pin: 2
// DIO1 pin: 3
// RESET pin: 3
RF69 rf1 = new Module(10, 2, 3);
// second CC1101 has different connections:
// CS pin: 9
// DIO0 pin: 4
// RESET pin: 5
RF69 rf2 = new Module(9, 4, 5);
// or using RadioShield
// https://github.com/jgromes/RadioShield
RF69 rf2 = RadioShield.ModuleB;
//RF69 rf3 = RadioShield.ModuleB;
void setup() {
Serial.begin(9600);
@ -35,8 +41,8 @@ void setup() {
Serial.print(F("[RF69] Initializing ... "));
// carrier frequency: 434.0 MHz
// bit rate: 48.0 kbps
// Rx bandwidth: 125.0 kHz
// frequency deviation: 50.0 kHz
// Rx bandwidth: 125.0 kHz
// output power: 13 dBm
// sync word: 0x2D01
int state = rf1.begin();
@ -52,11 +58,11 @@ void setup() {
Serial.print(F("[RF69] Initializing ... "));
// carrier frequency: 868.0 MHz
// bit rate: 300.0 kbps
// Rx bandwidth: 250.0 kHz
// frequency deviation: 60.0 kHz
// Rx bandwidth: 250.0 kHz
// output power: 17 dBm
// sync word: 0x2D01
state = rf2.begin(868.0, 300.0, 250.0, 60.0, 17);
state = rf2.begin(868.0, 300.0, 60.0, 250.0, 17);
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {

View file

@ -15,9 +15,9 @@
#include <RadioLib.h>
// RF69 has the following connections:
// NSS pin: 10
// CS pin: 10
// DIO0 pin: 2
// DIO1 pin: 3
// RESET pin: 3
RF69 rf = new Module(10, 2, 3);
// or using RadioShield
@ -31,8 +31,8 @@ void setup() {
Serial.print(F("[RF69] Initializing ... "));
// carrier frequency: 434.0 MHz
// bit rate: 48.0 kbps
// Rx bandwidth: 125.0 kHz
// frequency deviation: 50.0 kHz
// Rx bandwidth: 125.0 kHz
// output power: 13 dBm
// sync word: 0x2D01
int state = rf.begin();

View file

@ -13,9 +13,9 @@
#include <RadioLib.h>
// RF69 has the following connections:
// NSS pin: 10
// CS pin: 10
// DIO0 pin: 2
// DIO1 pin: 3
// RESET pin: 3
RF69 rf = new Module(10, 2, 3);
// or using RadioShield
@ -29,8 +29,8 @@ void setup() {
Serial.print(F("[RF69] Initializing ... "));
// carrier frequency: 434.0 MHz
// bit rate: 48.0 kbps
// Rx bandwidth: 125.0 kHz
// frequency deviation: 50.0 kHz
// Rx bandwidth: 125.0 kHz
// output power: 13 dBm
// sync word: 0x2D01
int state = rf.begin();

View file

@ -15,9 +15,9 @@
#include <RadioLib.h>
// RF69 has the following connections:
// NSS pin: 10
// CS pin: 10
// DIO0 pin: 2
// DIO1 pin: 3
// RESET pin: 3
RF69 rf = new Module(10, 2, 3);
// or using RadioShield
@ -31,8 +31,8 @@ void setup() {
Serial.print(F("[RF69] Initializing ... "));
// carrier frequency: 434.0 MHz
// bit rate: 48.0 kbps
// Rx bandwidth: 125.0 kHz
// frequency deviation: 50.0 kHz
// Rx bandwidth: 125.0 kHz
// output power: 13 dBm
// sync word: 0x2D01
int state = rf.begin();

View file

@ -16,9 +16,9 @@
#include <RadioLib.h>
// RF69 has the following connections:
// NSS pin: 10
// CS pin: 10
// DIO0 pin: 2
// DIO1 pin: 3
// RESET pin: 3
RF69 rf = new Module(10, 2, 3);
// or using RadioShield
@ -35,8 +35,8 @@ void setup() {
Serial.print(F("[RF69] Initializing ... "));
// carrier frequency: 434.0 MHz
// bit rate: 48.0 kbps
// Rx bandwidth: 125.0 kHz
// frequency deviation: 50.0 kHz
// Rx bandwidth: 125.0 kHz
// output power: 13 dBm
// sync word: 0x2D01
int state = rf.begin();
@ -63,7 +63,7 @@ void setup() {
/*
byte byteArr[] = {0x01, 0x23, 0x45, 0x56,
0x78, 0xAB, 0xCD, 0xEF};
state = rf.transmit(byteArr, 8);
state = rf.startTransmit(byteArr, 8);
*/
}
@ -121,11 +121,11 @@ void loop() {
// 256 characters long
transmissionState = rf.startTransmit("Hello World!");
// you can also transmit byte array up to 256 bytes long
// you can also transmit byte array up to 64 bytes long
/*
byte byteArr[] = {0x01, 0x23, 0x45, 0x56,
0x78, 0xAB, 0xCD, 0xEF};
int state = rf.transmit(byteArr, 8);
int state = rf.startTransmit(byteArr, 8);
*/
// we're ready to send more packets,

View file

@ -22,8 +22,9 @@
// SX1278 has the following connections:
// NSS pin: 10
// DIO0 pin: 2
// RESET pin: 9
// DIO1 pin: 3
SX1278 fsk = new Module(10, 2, 3);
SX1278 fsk = new Module(10, 2, 9, 3);
// or using RadioShield
// https://github.com/jgromes/RadioShield

View file

@ -15,9 +15,9 @@
#include <RadioLib.h>
// SX1231 has the following connections:
// NSS pin: 10
// CS pin: 10
// DIO0 pin: 2
// DIO1 pin: 3
// RESET pin: 3
SX1231 rf = new Module(10, 2, 3);
// or using RadioShield
@ -35,7 +35,7 @@ void setup() {
// frequency deviation: 50.0 kHz
// output power: 13 dBm
// sync word: 0x2D01
byte state = rf.begin();
int state = rf.begin();
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {

View file

@ -15,9 +15,9 @@
#include <RadioLib.h>
// SX1231 has the following connections:
// NSS pin: 10
// CS pin: 10
// DIO0 pin: 2
// DIO1 pin: 3
// RESET pin: 3
SX1231 rf = new Module(10, 2, 3);
// or using RadioShield

View file

@ -1,9 +1,9 @@
/*
RadioLib SX126x Channel Activity Detection Example
This example uses SX1262 to scan the current LoRa
This example uses SX1262 to scan the current LoRa
channel and detect ongoing LoRa transmissions.
Unlike SX127x CAD, SX126x can detect any part
Unlike SX127x CAD, SX126x can detect any part
of LoRa transmission, not just the preamble.
Other modules from SX126x family can also be used.
@ -18,7 +18,7 @@
// SX1262 has the following connections:
// NSS pin: 10
// DIO1 pin: 2
// DIO2 pin: 3
// NRST pin: 3
// BUSY pin: 9
SX1262 lora = new Module(10, 2, 3, 9);
@ -35,10 +35,12 @@ void setup() {
// bandwidth: 125.0 kHz
// spreading factor: 9
// coding rate: 7
// sync word: 0x1424 (private network)
// sync word: 0x12 (private network)
// output power: 14 dBm
// current limit: 60 mA
// preamble length: 8 symbols
// TCXO voltage: 1.6 V (set to 0 to not use TCXO)
// regulator: DC-DC (set to true to use LDO)
// CRC: enabled
int state = lora.begin();
if (state == ERR_NONE) {

View file

@ -19,7 +19,7 @@
// SX1262 has the following connections:
// NSS pin: 10
// DIO1 pin: 2
// DIO2 pin: 3
// NRST pin: 3
// BUSY pin: 9
SX1262 fsk = new Module(10, 2, 3, 9);
@ -40,6 +40,8 @@ void setup() {
// current limit: 60.0 mA
// preamble length: 16 bits
// data shaping: Gaussian, BT = 0.5
// TCXO voltage: 1.6 V (set to 0 to not use TCXO)
// regulator: DC-DC (set to true to use LDO)
// sync word: 0x2D 0x01
// CRC: enabled, CRC16 (CCIT)
int state = fsk.beginFSK();
@ -73,7 +75,7 @@ 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):

View file

@ -23,7 +23,7 @@
// SX1262 has the following connections:
// NSS pin: 10
// DIO1 pin: 2
// DIO2 pin: 3
// NRST pin: 3
// BUSY pin: 9
SX1262 lora = new Module(10, 2, 3, 9);
@ -40,10 +40,12 @@ void setup() {
// bandwidth: 125.0 kHz
// spreading factor: 9
// coding rate: 7
// sync word: 0x1424 (private network)
// sync word: 0x12 (private network)
// output power: 14 dBm
// current limit: 60 mA
// preamble length: 8 symbols
// TCXO voltage: 1.6 V (set to 0 to not use TCXO)
// regulator: DC-DC (set to true to use LDO)
// CRC: enabled
int state = lora.begin();
if (state == ERR_NONE) {
@ -53,28 +55,6 @@ void setup() {
Serial.println(state);
while (true);
}
// NOTE: Some SX126x modules use TCXO
// (Temprature-Compensated Crystal Oscillator).
// To be able to use these modules, TCXO
// 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);
}
*/
}
void loop() {

View file

@ -24,7 +24,7 @@
// SX1262 has the following connections:
// NSS pin: 10
// DIO1 pin: 2
// DIO2 pin: 3
// NRST pin: 3
// BUSY pin: 9
SX1262 lora = new Module(10, 2, 3, 9);
@ -41,10 +41,12 @@ void setup() {
// bandwidth: 125.0 kHz
// spreading factor: 9
// coding rate: 7
// sync word: 0x1424 (private network)
// sync word: 0x12 (private network)
// output power: 14 dBm
// current limit: 60 mA
// preamble length: 8 symbols
// TCXO voltage: 1.6 V (set to 0 to not use TCXO)
// regulator: DC-DC (set to true to use LDO)
// CRC: enabled
int state = lora.begin();
if (state == ERR_NONE) {
@ -118,7 +120,7 @@ void loop() {
// you can also read received data as byte array
/*
byte byteArr[8];
int state = lora.receive(byteArr, 8);
int state = lora.readData(byteArr, 8);
*/
if (state == ERR_NONE) {

View file

@ -27,13 +27,20 @@
// SX1262 has the following connections:
// NSS pin: 10
// DIO1 pin: 2
// DIO2 pin: 3
// NRST pin: 3
// BUSY pin: 9
SX1262 loraSX1262 = new Module(10, 2, 3, 9);
// SX12628 has different connections:
// NSS pin: 8
// DIO1 pin: 4
// NRST pin: 5
// BUSY pin: 6
SX1268 loraSX1268 = new Module(8, 4, 5, 6);
// or using RadioShield
// https://github.com/jgromes/RadioShield
SX1268 loraSX1268 = RadioShield.ModuleB;
//SX1261 loraSX1261 = RadioShield.ModuleB;
void setup() {
Serial.begin(9600);
@ -44,10 +51,12 @@ void setup() {
// bandwidth: 125.0 kHz
// spreading factor: 9
// coding rate: 7
// sync word: 0x1424 (private network)
// sync word: 0x12 (private network)
// output power: 14 dBm
// current limit: 60 mA
// preamble length: 8 symbols
// TCXO voltage: 1.6 V (set to 0 to not use TCXO)
// regulator: DC-DC (set to true to use LDO)
// CRC: enabled
int state = loraSX1262.begin();
if (state == ERR_NONE) {
@ -67,7 +76,7 @@ void setup() {
// bandwidth: 500.0 kHz
// spreading factor: 6
// coding rate: 5
// sync word: 0x3444 (public network)
// sync word: 0x34 (public network)
// output power: 2 dBm
// current limit: 50 mA
// preamble length: 20 symbols

View file

@ -19,7 +19,7 @@
// SX1262 has the following connections:
// NSS pin: 10
// DIO1 pin: 2
// DIO2 pin: 3
// NRST pin: 3
// BUSY pin: 9
SX1262 lora = new Module(10, 2, 3, 9);
@ -36,10 +36,12 @@ void setup() {
// bandwidth: 125.0 kHz
// spreading factor: 9
// coding rate: 7
// sync word: 0x1424 (private network)
// sync word: 0x12 (private network)
// output power: 14 dBm
// current limit: 60 mA
// preamble length: 8 symbols
// TCXO voltage: 1.6 V (set to 0 to not use TCXO)
// regulator: DC-DC (set to true to use LDO)
// CRC: enabled
int state = lora.begin();
if (state == ERR_NONE) {
@ -49,29 +51,6 @@ void setup() {
Serial.println(state);
while (true);
}
// NOTE: Some SX126x modules use TCXO
// (Temprature-Compensated Crystal Oscillator).
// To be able to use these modules, TCXO
// 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);
}
*/
}
void loop() {

View file

@ -20,7 +20,7 @@
// SX1262 has the following connections:
// NSS pin: 10
// DIO1 pin: 2
// DIO2 pin: 3
// NRST pin: 3
// BUSY pin: 9
SX1262 lora = new Module(10, 2, 3, 9);
@ -36,10 +36,12 @@ void setup() {
// bandwidth: 125.0 kHz
// spreading factor: 9
// coding rate: 7
// sync word: 0x1424 (private network)
// sync word: 0x12 (private network)
// output power: 14 dBm
// current limit: 60 mA
// preamble length: 8 symbols
// TCXO voltage: 1.6 V (set to 0 to not use TCXO)
// regulator: DC-DC (set to true to use LDO)
// CRC: enabled
int state = lora.begin();
if (state == ERR_NONE) {

View file

@ -19,8 +19,9 @@
// SX1278 has the following connections:
// NSS pin: 10
// DIO0 pin: 2
// RESET pin: 9
// DIO1 pin: 3
SX1278 lora = new Module(10, 2, 3);
SX1278 lora = new Module(10, 2, 9, 3);
// or using RadioShield
// https://github.com/jgromes/RadioShield

View file

@ -19,8 +19,9 @@
// SX1278 has the following connections:
// NSS pin: 10
// DIO0 pin: 2
// RESET pin: 9
// DIO1 pin: 3
SX1278 fsk = new Module(10, 2, 3);
SX1278 fsk = new Module(10, 2, 9, 3);
// or using RadioShield
// https://github.com/jgromes/RadioShield

View file

@ -23,8 +23,9 @@
// SX1278 has the following connections:
// NSS pin: 10
// DIO0 pin: 2
// RESET pin: 9
// DIO1 pin: 3
SX1278 lora = new Module(10, 2, 3);
SX1278 lora = new Module(10, 2, 9, 3);
// or using RadioShield
// https://github.com/jgromes/RadioShield

View file

@ -24,8 +24,9 @@
// SX1278 has the following connections:
// NSS pin: 10
// DIO0 pin: 2
// RESET pin: 9
// DIO1 pin: 3
SX1278 lora = new Module(10, 2, 3);
SX1278 lora = new Module(10, 2, 9, 3);
// or using RadioShield
// https://github.com/jgromes/RadioShield

View file

@ -22,14 +22,21 @@
// 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);
// DIO0 pin: 2
// RESET pin: 9
// DIO1 pin: 3
SX1278 loraSX1278 = new Module(10, 2, 9, 3);
// SX1272 has different connections:
// NSS pin: 9
// DIO0 pin: 4
// RESET pin: 5
// DIO1 pin: 6
SX1272 loraSX1272 = new Module(9, 4, 5, 6);
// or using RadioShield
// https://github.com/jgromes/RadioShield
SX1272 loraSX1272 = RadioShield.ModuleB;
//SX1276 loraSX1276 = RadioShield.ModuleB;
void setup() {
Serial.begin(9600);

View file

@ -19,8 +19,9 @@
// SX1278 has the following connections:
// NSS pin: 10
// DIO0 pin: 2
// RESET pin: 9
// DIO1 pin: 3
SX1278 lora = new Module(10, 2, 3);
SX1278 lora = new Module(10, 2, 9, 3);
// or using RadioShield
// https://github.com/jgromes/RadioShield

View file

@ -20,8 +20,9 @@
// SX1278 has the following connections:
// NSS pin: 10
// DIO0 pin: 2
// RESET pin: 9
// DIO1 pin: 3
SX1278 lora = new Module(10, 2, 3);
SX1278 lora = new Module(10, 2, 9, 3);
// or using RadioShield
// https://github.com/jgromes/RadioShield

View file

@ -18,7 +18,7 @@
// TX pin: 9
// RX pin: 8
// RESET pin: 3
XBee bee = new Module(9, 8);
XBee bee = new Module(9, 8, 3);
// or using RadioShield
// https://github.com/jgromes/RadioShield

View file

@ -18,7 +18,7 @@
// TX pin: 9
// RX pin: 8
// RESET pin: 3
XBee bee = new Module(9, 8);
XBee bee = new Module(9, 8, 3);
// or using RadioShield
// https://github.com/jgromes/RadioShield

View file

@ -20,7 +20,7 @@
// TX pin: 9
// RX pin: 8
// RESET pin: 3
XBeeSerial bee = new Module(9, 8);
XBeeSerial bee = new Module(9, 8, 3);
// or using RadioShield
// https://github.com/jgromes/RadioShield

View file

@ -17,9 +17,9 @@
#include <RadioLib.h>
// nRF24 has the following connections:
// NSS pin: 10
// CE pin: 2
// IRQ pin: 3
// CS pin: 10
// IRQ pin: 2
// CE pin: 3
nRF24 nrf = new Module(10, 2, 3);
// or using RadioShield

View file

@ -17,9 +17,9 @@
#include <RadioLib.h>
// nRF24 has the following connections:
// NSS pin: 10
// CE pin: 2
// IRQ pin: 3
// CS pin: 10
// IRQ pin: 2
// CE pin: 3
nRF24 nrf = new Module(10, 2, 3);
// or using RadioShield

View file

@ -39,6 +39,8 @@ HTTPClient KEYWORD1
RTTYClient KEYWORD1
MorseClient KEYWORD1
PagerClient KEYWORD1
AX25Client KEYWORD1
AX25Frame KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
@ -62,6 +64,8 @@ receiveDirect KEYWORD2
packetMode KEYWORD2
setDio0Action KEYWORD2
setDio1Action KEYWORD2
clearDio0Action KEYWORD2
clearDio1Action KEYWORD2
startTransmit KEYWORD2
startReceive KEYWORD2
readData KEYWORD2
@ -107,15 +111,23 @@ setAmbientTemperature KEYWORD2
# CC1101-specific
getLQI KEYWORD2
setGdo0Action KEYWORD2
setGdo1Action KEYWORD2
setGdo2Action KEYWORD2
clearGdo0Action KEYWORD2
clearGdo2Action KEYWORD2
# SX126x-specific
setDio2Action KEYWORD2
setTCXO KEYWORD2
setDio2AsRfSwitch KEYWORD2
getTimeOnAir KEYWORD2
implicitHeader KEYWORD2
explicitHeader KEYWORD2
setSyncBits KEYWORD2
setWhitening KEYWORD2
startReceiveDutyCycle KEYWORD2
startReceiveDutyCycleAuto KEYWORD2
setRegulatorLDO KEYWORD2
setRegulatorDCDC KEYWORD2
getCurrentLimit KEYWORD2
# ESP8266
join KEYWORD2
@ -133,6 +145,7 @@ setTransmitPipe KEYWORD2
setReceivePipe KEYWORD2
disablePipe KEYWORD2
getStatus KEYWORD2
setAutoAck KEYWORD2
# HTTP
get KEYWORD2
@ -165,10 +178,19 @@ getNumBytes KEYWORD2
sendSMS KEYWORD2
shutdown KEYWORD2
# AX.25
setRepeaters KEYWORD2
setRecvSequence KEYWORD2
setSendSequence KEYWORD2
sendFrame KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
NC LITERAL1
RADIOLIB_VERSION LITERAL1
ERR_NONE LITERAL1
ERR_UNKNOWN LITERAL1
@ -246,3 +268,9 @@ ERR_INVALID_MODULATION_PARAMETERS LITERAL1
ERR_SPI_CMD_TIMEOUT LITERAL1
ERR_SPI_CMD_INVALID LITERAL1
ERR_SPI_CMD_FAILED LITERAL1
ERR_INVALID_SLEEP_PERIOD LITERAL1
ERR_INVALID_RX_PERIOD LITERAL1
ERR_INVALID_CALLSIGN LITERAL1
ERR_INVALID_NUM_REPEATERS LITERAL1
ERR_INVALID_REPEATER_CALLSIGN LITERAL1

View file

@ -1,5 +1,5 @@
name=RadioLib
version=1.8.0
version=3.3.0
author=Jan Gromes <gromes.jan@gmail.com>
maintainer=Jan Gromes <gromes.jan@gmail.com>
sentence=Universal wireless communication library for Arduino

View file

@ -1,11 +1,11 @@
#include "Module.h"
Module::Module(int rx, int tx, HardwareSerial* useSer) {
_cs = -1;
Module::Module(int16_t rx, int16_t tx, HardwareSerial* useSer, int16_t rst) {
_cs = NC;
_rx = rx;
_tx = tx;
_int0 = -1;
_int1 = -1;
_irq = NC;
_rst = rst;
#ifdef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
ModuleSerial = useSer;
@ -15,22 +15,32 @@ Module::Module(int rx, int tx, HardwareSerial* useSer) {
#endif
}
Module::Module(int cs, int int0, int int1, SPIClass& spi, SPISettings spiSettings) {
Module::Module(int16_t cs, int16_t irq, int16_t rst, SPIClass& spi, SPISettings spiSettings) {
_cs = cs;
_rx = -1;
_tx = -1;
_int0 = int0;
_int1 = int1;
_rx = NC;
_tx = NC;
_irq = irq;
_rst = rst;
_spi = &spi;
_spiSettings = spiSettings;
}
Module::Module(int cs, int int0, int int1, int rx, int tx, SPIClass& spi, SPISettings spiSettings, HardwareSerial* useSer) {
Module::Module(int16_t cs, int16_t irq, int16_t rst, int16_t gpio, SPIClass& spi, SPISettings spiSettings) {
_cs = cs;
_rx = gpio;
_tx = NC;
_irq = irq;
_rst = rst;
_spi = &spi;
_spiSettings = spiSettings;
}
Module::Module(int16_t cs, int16_t irq, int16_t rst, int16_t rx, int16_t tx, SPIClass& spi, SPISettings spiSettings, HardwareSerial* useSer) {
_cs = cs;
_rx = rx;
_tx = tx;
_int0 = int0;
_int1 = int1;
_irq = irq;
_rst = rst;
_spi = &spi;
_spiSettings = spiSettings;
@ -42,22 +52,12 @@ Module::Module(int cs, int int0, int int1, int rx, int tx, SPIClass& spi, SPISet
#endif
}
Module::Module(int cs, int int0, int int1, int int2, SPIClass& spi, SPISettings spiSettings) {
_cs = cs;
_rx = int2;
_tx = -1;
_int0 = int0;
_int1 = int1;
_spi = &spi;
_spiSettings = spiSettings;
}
void Module::init(uint8_t interface, uint8_t gpio) {
void Module::init(uint8_t interface) {
// select interface
switch(interface) {
case RADIOLIB_USE_SPI:
pinMode(_cs, OUTPUT);
digitalWrite(_cs, HIGH);
Module::pinMode(_cs, OUTPUT);
Module::digitalWrite(_cs, HIGH);
_spi->begin();
break;
case RADIOLIB_USE_UART:
@ -70,27 +70,17 @@ void Module::init(uint8_t interface, uint8_t gpio) {
case RADIOLIB_USE_I2C:
break;
}
// select GPIO
switch(gpio) {
case RADIOLIB_INT_NONE:
break;
case RADIOLIB_INT_0:
pinMode(_int0, INPUT);
break;
case RADIOLIB_INT_1:
pinMode(_int1, INPUT);
break;
case RADIOLIB_INT_BOTH:
pinMode(_int0, INPUT);
pinMode(_int1, INPUT);
break;
}
}
void Module::term() {
// stop SPI
_spi->end();
// stop hardware interfaces
if(_spi != nullptr) {
_spi->end();
}
if(ModuleSerial != nullptr) {
ModuleSerial->end();
}
}
void Module::ATemptyBuffer() {
@ -199,7 +189,7 @@ void Module::SPIreadRegisterBurst(uint8_t reg, uint8_t numBytes, uint8_t* inByte
}
uint8_t Module::SPIreadRegister(uint8_t reg) {
uint8_t resp;
uint8_t resp = 0;
SPItransfer(SPIreadCommand, reg, NULL, &resp, 1);
return(resp);
}
@ -217,14 +207,20 @@ void Module::SPItransfer(uint8_t cmd, uint8_t reg, uint8_t* dataOut, uint8_t* da
_spi->beginTransaction(_spiSettings);
// pull CS low
digitalWrite(_cs, LOW);
Module::digitalWrite(_cs, LOW);
// send SPI register address with access command
_spi->transfer(reg | cmd);
RADIOLIB_VERBOSE_PRINT(reg | cmd, HEX);
RADIOLIB_VERBOSE_PRINT('\t');
RADIOLIB_VERBOSE_PRINT(reg | cmd, BIN);
RADIOLIB_VERBOSE_PRINT('\t');
#ifdef RADIOLIB_VERBOSE
if(cmd == SPIwriteCommand) {
RADIOLIB_VERBOSE_PRINT('W');
} else if(cmd == SPIreadCommand) {
RADIOLIB_VERBOSE_PRINT('R');
}
RADIOLIB_VERBOSE_PRINT('\t')
RADIOLIB_VERBOSE_PRINT(reg, HEX);
RADIOLIB_VERBOSE_PRINT('\t');
#endif
// send data or get response
if(cmd == SPIwriteCommand) {
@ -232,23 +228,31 @@ void Module::SPItransfer(uint8_t cmd, uint8_t reg, uint8_t* dataOut, uint8_t* da
_spi->transfer(dataOut[n]);
RADIOLIB_VERBOSE_PRINT(dataOut[n], HEX);
RADIOLIB_VERBOSE_PRINT('\t');
RADIOLIB_VERBOSE_PRINT(dataOut[n], BIN);
RADIOLIB_VERBOSE_PRINT('\t');
}
} else if (cmd == SPIreadCommand) {
for(size_t n = 0; n < numBytes; n++) {
dataIn[n] = _spi->transfer(0x00);
RADIOLIB_VERBOSE_PRINT(dataIn[n], HEX);
RADIOLIB_VERBOSE_PRINT('\t');
RADIOLIB_VERBOSE_PRINT(dataIn[n], BIN);
RADIOLIB_VERBOSE_PRINT('\t');
}
}
RADIOLIB_VERBOSE_PRINTLN();
// release CS
digitalWrite(_cs, HIGH);
Module::digitalWrite(_cs, HIGH);
// end SPI transaction
_spi->endTransaction();
}
void Module::pinMode(int16_t pin, uint8_t mode) {
if(pin != NC) {
::pinMode(pin, mode);
}
}
void Module::digitalWrite(int16_t pin, uint8_t value) {
if(pin != NC) {
::digitalWrite(pin, value);
}
}

View file

@ -25,12 +25,14 @@ class Module {
\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
\param serial HardwareSerial to be used on platforms that do not support SoftwareSerial. Defaults to Serial1.
\param rst Arduino pin to be used as hardware reset for the module. Defaults to -1 (unused).
*/
#ifdef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
Module(int tx, int rx, HardwareSerial* useSer = &Serial1);
Module(int16_t tx, int16_t rx, HardwareSerial* serial = &Serial1, int16_t rst = -1);
#else
Module(int tx, int rx, HardwareSerial* useSer = nullptr);
Module(int16_t tx, int16_t rx, HardwareSerial* serial = nullptr, int16_t rst = -1);
#endif
/*!
@ -38,41 +40,41 @@ class Module {
\param cs Arduino pin to be used as chip select.
\param int0 Arduino pin to be used as interrupt/GPIO 0.
\param irq Arduino pin to be used as interrupt/GPIO.
\param int1 Arduino pin to be used as interrupt/GPIO 1.
\param rst Arduino pin to be used as hardware reset for the 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.
*/
Module(int cs, int int0, int int1, SPIClass& spi = SPI, SPISettings spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0));
Module(int16_t cs, int16_t irq, int16_t rst, SPIClass& spi = SPI, SPISettings spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0));
/*!
\brief Extended SPI-based module constructor.
\param cs Arduino pin to be used as chip select.
\param int0 Arduino pin to be used as interrupt/GPIO 0.
\param irq Arduino pin to be used as interrupt/GPIO.
\param int1 Arduino pin to be used as interrupt/GPIO 1.
\param rst Arduino pin to be used as hardware reset for the module.
\param int2 Arduino pin to be used as interrupt/GPIO 2.
\param gpio Arduino pin to be used as additional interrupt/GPIO.
\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.
*/
Module(int cs, int int0, int int1, int int2, SPIClass& spi = SPI, SPISettings spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0));
Module(int16_t cs, int16_t irq, int16_t rst, int16_t gpio, SPIClass& spi = SPI, SPISettings spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0));
/*!
\brief Generic module constructor.
\param cs Arduino pin to be used as chip select.
\param int0 Arduino pin to be used as interrupt/GPIO 0.
\param irq Arduino pin to be used as interrupt/GPIO.
\param int1 Arduino pin to be used as interrupt/GPIO 1.
\param rst Arduino pin to be used as hardware reset for the module.
\param tx Arduino pin to be used as Tx pin for SoftwareSerial communication.
@ -85,9 +87,9 @@ class Module {
\param serial HardwareSerial to be used on ESP32 and SAMD. Defaults to 1
*/
#ifdef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
Module(int cs, int int0, int int1, int rx, int tx, SPIClass& spi = SPI, SPISettings spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0), HardwareSerial* useSer = &Serial1);
Module(int16_t cs, int16_t irq, int16_t rst, int16_t rx, int16_t tx, SPIClass& spi = SPI, SPISettings spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0), HardwareSerial* serial = &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);
Module(int16_t cs, int16_t irq, int16_t rst, int16_t rx, int16_t tx, SPIClass& spi = SPI, SPISettings spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0), HardwareSerial* serial = nullptr);
#endif
@ -128,10 +130,8 @@ class Module {
\brief Initialize low-level module control.
\param interface Interface to be used on the module. See \ref shield_config for details.
\param gpio GPIO/interrupt pins to be used on the module. See \ref uart_config for details.
*/
void init(uint8_t interface, uint8_t gpio);
void init(uint8_t interface);
/*!
\brief Terminate low-level module control.
@ -266,35 +266,42 @@ class Module {
\returns Pin number of SPI chip select configured in the constructor.
*/
int getCs() const { return(_cs); }
int16_t getCs() const { return(_cs); }
/*!
\brief Access method to get the pin number of interrupt/GPIO 0.
\brief Access method to get the pin number of interrupt/GPIO.
\returns Pin number of interrupt/GPIO 0 configured in the constructor.
\returns Pin number of interrupt/GPIO configured in the constructor.
*/
int getInt0() const { return(_int0); }
int16_t getIrq() const { return(_irq); }
/*!
\brief Access method to get the pin number of interrupt/GPIO 1.
\brief Access method to get the pin number of hardware reset pin.
\returns Pin number of interrupt/GPIO 1 configured in the constructor.
\returns Pin number of hardware reset pin configured in the constructor.
*/
int getInt1() const { return(_int1); }
int16_t getRst() const { return(_rst); }
/*!
\brief Access method to get the pin number of second interrupt/GPIO.
\returns Pin number of second interrupt/GPIO configured in the constructor.
*/
int16_t getGpio() const { return(_rx); }
/*!
\brief Access method to get the pin number of UART Rx.
\returns Pin number of UART Rx configured in the constructor.
*/
int getRx() const { return(_rx); }
int16_t getRx() const { return(_rx); }
/*!
\brief Access method to get the pin number of UART Rx.
\returns Pin number of UART Rx configured in the constructor.
*/
int getTx() const { return(_tx); }
int16_t getTx() const { return(_tx); }
/*!
\brief Access method to get the SPI interface.
@ -310,14 +317,32 @@ class Module {
*/
SPISettings getSpiSettings() const { return(_spiSettings); }
/*!
\brief Arduino core pinMode override that checks -1 as alias for unused pin.
\param pin Pin to change the mode of.
\param mode Which mode to set.
*/
static void pinMode(int16_t pin, uint8_t mode);
/*!
\brief Arduino core digitalWrite override that checks -1 as alias for unused pin.
\param pin Pin to write to.
\param value Whether to set the pin high or low.
*/
static void digitalWrite(int16_t pin, uint8_t value);
#ifndef RADIOLIB_GODMODE
private:
#endif
int _cs;
int _tx;
int _rx;
int _int0;
int _int1;
int16_t _cs;
int16_t _tx;
int16_t _rx;
int16_t _irq;
int16_t _rst;
SPIClass* _spi;
SPISettings _spiSettings;

View file

@ -18,6 +18,7 @@
- PhysicalLayer protocols
- RTTY (RTTYClient)
- Morse Code (MorseClient)
- AX.25 (AX25Client)
- TransportLayer protocols
- HTTP (HTTPClient)
- MQTT (MQTTClient)
@ -67,6 +68,7 @@
// physical layer protocols
#include "protocols/PhysicalLayer/PhysicalLayer.h"
#include "protocols/AX25/AX25.h"
#include "protocols/Morse/Morse.h"
#include "protocols/RTTY/RTTY.h"
@ -77,6 +79,9 @@
#include "protocols/MQTT/MQTT.h"
#endif
// only create Radio class when using RadioShield
#ifdef RADIOLIB_RADIOSHIELD
// RadioShield pin definitions
#define RADIOSHIELD_CS_A 10
#define RADIOSHIELD_RX_A 9
@ -115,5 +120,6 @@ class Radio {
};
Radio RadioShield;
#endif
#endif

View file

@ -1,11 +1,20 @@
#ifndef _RADIOLIB_TYPES_H
#define _RADIOLIB_TYPES_H
#if ARDUINO >= 100
#include "Arduino.h"
#else
#error "Unsupported Arduino version (< 1.0.0)"
#endif
// version definitions
#define RADIOLIB_VERSION_MAJOR (0x03)
#define RADIOLIB_VERSION_MINOR (0x03)
#define RADIOLIB_VERSION_PATCH (0x00)
#define RADIOLIB_VERSION_EXTRA (0x00)
#define RADIOLIB_VERSION ((RADIOLIB_VERSION_MAJOR << 24) | (RADIOLIB_VERSION_MAJOR << 16) | (RADIOLIB_VERSION_MAJOR << 8) | (RADIOLIB_VERSION_EXTRA))
/*
* Uncomment to enable static-only memory management: no dynamic allocation will be performed.
* Warning: Large static arrays will be created in some methods. It is not advised to send large packets in this mode.
@ -53,13 +62,30 @@
*/
//#define RADIOLIB_GODMODE
/*
* Uncomment to enable pre-defined modules when using RadioShield.
*/
//#define RADIOLIB_RADIOSHIELD
/*
* The following platforms do not support SoftwareSerial library.
*/
#if defined(ESP32) || defined(SAMD_SERIES) || defined(ARDUINO_ARCH_STM32) || defined(__SAM3X8E__)
#if defined(ESP32) || defined(SAMD_SERIES) || defined(ARDUINO_ARCH_STM32) || defined(__SAM3X8E__) || defined(AM_PART_APOLLO3)
#define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
#endif
/*!
\brief Alias for unused pin, if not supplied by the Arduino core.
*/
#if !(defined(NC) || defined(ARDUINO_ARCH_STM32))
#define NC (-1)
#endif
/*!
\brief A simple assert macro, will return on error.
*/
#define RADIOLIB_ASSERT(STATEVAR) { if(STATEVAR != ERR_NONE) { return(STATEVAR); } }
/*!
\defgroup shield_config Shield Configuration
@ -69,37 +95,17 @@
/*!
\brief Use SPI interface.
*/
#define RADIOLIB_USE_SPI 0x00
#define RADIOLIB_USE_SPI 0x00
/*!
\brief Use UART interface.
*/
#define RADIOLIB_USE_UART 0x01
#define RADIOLIB_USE_UART 0x01
/*!
\brief Use I2C interface.
*/
#define RADIOLIB_USE_I2C 0x02
/*!
\brief Do not use any interrupts/GPIOs.
*/
#define RADIOLIB_INT_NONE 0x00
/*!
\brief Use interrupt/GPIO 0.
*/
#define RADIOLIB_INT_0 0x01
/*!
\brief Use interrupt/GPIO 1.
*/
#define RADIOLIB_INT_1 0x02
/*!
\brief Use both interrupts/GPIOs.
*/
#define RADIOLIB_INT_BOTH 0x03
#define RADIOLIB_USE_I2C 0x02
/*!
\}
@ -114,52 +120,52 @@
/*!
\brief Use 1 bit stop.
*/
#define RADIOLIB_UART_STOPBIT_1 0x01
#define RADIOLIB_UART_STOPBIT_1 0x01
/*!
\brief Use 1.5 bit stop.
*/
#define RADIOLIB_UART_STOPBIT_1_5 0x02
#define RADIOLIB_UART_STOPBIT_1_5 0x02
/*!
\brief Use 2 bit stop.
*/
#define RADIOLIB_UART_STOPBIT_2 0x03
#define RADIOLIB_UART_STOPBIT_2 0x03
/*!
\brief No parity.
*/
#define RADIOLIB_UART_PARITY_NONE 0x00
#define RADIOLIB_UART_PARITY_NONE 0x00
/*!
\brief Odd parity.
*/
#define RADIOLIB_UART_PARITY_ODD 0x01
#define RADIOLIB_UART_PARITY_ODD 0x01
/*!
\brief Even parity.
*/
#define RADIOLIB_UART_PARITY_EVEN 0x02
#define RADIOLIB_UART_PARITY_EVEN 0x02
/*!
\brief No flow control.
*/
#define RADIOLIB_UART_FLOW_NONE 0x00
#define RADIOLIB_UART_FLOW_NONE 0x00
/*!
\brief RTS only.
*/
#define RADIOLIB_UART_FLOW_RTS 0x01
#define RADIOLIB_UART_FLOW_RTS 0x01
/*!
\brief CTS only.
*/
#define RADIOLIB_UART_FLOW_CTS 0x02
#define RADIOLIB_UART_FLOW_CTS 0x02
/*!
\brief Both RTS and CTS.
*/
#define RADIOLIB_UART_FLOW_BOTH 0x03
#define RADIOLIB_UART_FLOW_BOTH 0x03
/*!
\}
@ -176,13 +182,13 @@
/*!
\brief No error, method executed successfully.
*/
#define ERR_NONE 0
#define ERR_NONE 0
/*!
\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
@ -190,334 +196,372 @@
\brief Radio chip was not found during initialization. This can be caused by specifying wrong chip type in the constructor
(i.e. calling SX1272 constructor for SX1278 chip) or by a fault in your wiring (incorrect slave select pin).
*/
#define ERR_CHIP_NOT_FOUND -2
#define ERR_CHIP_NOT_FOUND -2
/*!
\brief Failed to allocate memory for temporary buffer. This can be cause by not enough RAM or by passing invalid pointer.
*/
#define ERR_MEMORY_ALLOCATION_FAILED -3
#define ERR_MEMORY_ALLOCATION_FAILED -3
/*!
\brief Packet supplied to transmission method was longer than limit.
*/
#define ERR_PACKET_TOO_LONG -4
#define ERR_PACKET_TOO_LONG -4
/*!
\brief Timed out waiting for transmission finish.
*/
#define ERR_TX_TIMEOUT -5
#define ERR_TX_TIMEOUT -5
/*!
\brief Timed out waiting for incoming transmission.
*/
#define ERR_RX_TIMEOUT -6
#define ERR_RX_TIMEOUT -6
/*!
\brief The calculated and expected CRCs of received packet do not match.
This means that the packet was damaged during transmission and should be sent again.
*/
#define ERR_CRC_MISMATCH -7
#define ERR_CRC_MISMATCH -7
/*!
\brief The supplied bandwidth value is invalid for this module.
*/
#define ERR_INVALID_BANDWIDTH -8
#define ERR_INVALID_BANDWIDTH -8
/*!
\brief The supplied spreading factor value is invalid for this module.
*/
#define ERR_INVALID_SPREADING_FACTOR -9
#define ERR_INVALID_SPREADING_FACTOR -9
/*!
\brief The supplied coding rate value is invalid for this module.
*/
#define ERR_INVALID_CODING_RATE -10
#define ERR_INVALID_CODING_RATE -10
/*!
\brief Internal only.
*/
#define ERR_INVALID_BIT_RANGE -11
#define ERR_INVALID_BIT_RANGE -11
/*!
\brief The supplied frequency value is invalid for this module.
*/
#define ERR_INVALID_FREQUENCY -12
#define ERR_INVALID_FREQUENCY -12
/*!
\brief The supplied output power value is invalid for this module.
*/
#define ERR_INVALID_OUTPUT_POWER -13
#define ERR_INVALID_OUTPUT_POWER -13
/*!
\brief LoRa preamble was detected during channel activity detection.
This means that there is some LoRa device currently transmitting in your channel.
*/
#define PREAMBLE_DETECTED -14
#define PREAMBLE_DETECTED -14
/*!
\brief No LoRa preambles were detected during channel activity detection. Your channel is free.
*/
#define CHANNEL_FREE -15
#define CHANNEL_FREE -15
/*!
\brief Real value in SPI register does not match the expected one. This can be caused by faulty SPI wiring.
*/
#define ERR_SPI_WRITE_FAILED -16
#define ERR_SPI_WRITE_FAILED -16
/*!
\brief The supplied current limit value is invalid.
*/
#define ERR_INVALID_CURRENT_LIMIT -17
#define ERR_INVALID_CURRENT_LIMIT -17
/*!
\brief The supplied preamble length is invalid.
*/
#define ERR_INVALID_PREAMBLE_LENGTH -18
#define ERR_INVALID_PREAMBLE_LENGTH -18
/*!
\brief The supplied gain value is invalid.
*/
#define ERR_INVALID_GAIN -19
#define ERR_INVALID_GAIN -19
/*!
\brief User tried to execute modem-exclusive method on a wrong modem.
For example, this can happen when you try to change LoRa configuration when FSK modem is active.
*/
#define ERR_WRONG_MODEM -20
#define ERR_WRONG_MODEM -20
/*!
\brief The supplied number of RSSI samples is invalid.
*/
#define ERR_INVALID_NUM_SAMPLES -21
#define ERR_INVALID_NUM_SAMPLES -21
/*!
\brief The supplied RSSI offset is invalid.
*/
#define ERR_INVALID_RSSI_OFFSET -22
#define ERR_INVALID_RSSI_OFFSET -22
/*!
\brief The supplied encoding is invalid.
*/
#define ERR_INVALID_ENCODING -23
#define ERR_INVALID_ENCODING -23
// RF69-specific status codes
/*!
\brief The supplied bit rate value is invalid.
*/
#define ERR_INVALID_BIT_RATE -101
#define ERR_INVALID_BIT_RATE -101
/*!
\brief The supplied frequency deviation value is invalid.
*/
#define ERR_INVALID_FREQUENCY_DEVIATION -102
#define ERR_INVALID_FREQUENCY_DEVIATION -102
/*!
\brief The supplied bit rate to bandwidth ratio is invalid. See the module datasheet for more information.
*/
#define ERR_INVALID_BIT_RATE_BW_RATIO -103
#define ERR_INVALID_BIT_RATE_BW_RATIO -103
/*!
\brief The supplied receiver bandwidth value is invalid.
*/
#define ERR_INVALID_RX_BANDWIDTH -104
#define ERR_INVALID_RX_BANDWIDTH -104
/*!
\brief The supplied FSK sync word is invalid.
*/
#define ERR_INVALID_SYNC_WORD -105
#define ERR_INVALID_SYNC_WORD -105
/*!
\brief The supplied FSK data shaping option is invalid.
*/
#define ERR_INVALID_DATA_SHAPING -106
#define ERR_INVALID_DATA_SHAPING -106
/*!
\brief The current modulation is invalid for the requested operation.
*/
#define ERR_INVALID_MODULATION -107
#define ERR_INVALID_MODULATION -107
// ESP8266 status codes
/*!
\brief AT command failed to execute, or timed out.
*/
#define ERR_AT_FAILED -201
#define ERR_AT_FAILED -201
/*!
\brief Supplied URL is malformed or invalid.
*/
#define ERR_URL_MALFORMED -202
#define ERR_URL_MALFORMED -202
/*!
\brief AT command response was malformed.
*/
#define ERR_RESPONSE_MALFORMED_AT -203
#define ERR_RESPONSE_MALFORMED_AT -203
/*!
\brief Data response was malformed.
*/
#define ERR_RESPONSE_MALFORMED -204
#define ERR_RESPONSE_MALFORMED -204
/*!
\brief MQTT broker rejected connection due to version mismatch.
*/
#define ERR_MQTT_CONN_VERSION_REJECTED -205
#define ERR_MQTT_CONN_VERSION_REJECTED -205
/*!
\brief MQTT broker rejected connection due to unknown ID.
*/
#define ERR_MQTT_CONN_ID_REJECTED -206
#define ERR_MQTT_CONN_ID_REJECTED -206
/*!
\brief Failed to establish connection with MQTT broker.
*/
#define ERR_MQTT_CONN_SERVER_UNAVAILABLE -207
#define ERR_MQTT_CONN_SERVER_UNAVAILABLE -207
/*!
\brief Supplied username/password combination is incorrect.
*/
#define ERR_MQTT_CONN_BAD_USERNAME_PASSWORD -208
#define ERR_MQTT_CONN_BAD_USERNAME_PASSWORD -208
/*!
\brief Unauthorized connection to MQTT broker.
*/
#define ERR_MQTT_CONN_NOT_AUTHORIZED -208
#define ERR_MQTT_CONN_NOT_AUTHORIZED -208
/*!
\brief Received packet ID does not match the expected ID.
*/
#define ERR_MQTT_UNEXPECTED_PACKET_ID -209
#define ERR_MQTT_UNEXPECTED_PACKET_ID -209
/*!
\brief No new packet was received since the last check.
*/
#define ERR_MQTT_NO_NEW_PACKET_AVAILABLE -210
#define ERR_MQTT_NO_NEW_PACKET_AVAILABLE -210
/*!
\brief Successfully subscribed to MQTT topic with QoS 0.
*/
#define MQTT_SUBS_SUCCESS_QOS_0 0x00
#define MQTT_SUBS_SUCCESS_QOS_0 0x00
/*!
\brief Successfully subscribed to MQTT topic with QoS 1.
*/
#define MQTT_SUBS_SUCCESS_QOS_1 0x01
#define MQTT_SUBS_SUCCESS_QOS_1 0x01
/*!
\brief Successfully subscribed to MQTT topic with QoS 2.
*/
#define MQTT_SUBS_SUCCESS_QOS_2 0x02
#define MQTT_SUBS_SUCCESS_QOS_2 0x02
/*!
\brief Failed to subscribe to MQTT topic.
*/
#define ERR_MQTT_SUBS_FAILED 0x80
#define ERR_MQTT_SUBS_FAILED 0x80
// XBee status codes
/*!
\brief Failed to enter command mode.
*/
#define ERR_CMD_MODE_FAILED -301
#define ERR_CMD_MODE_FAILED -301
/*!
\brief Received ZigBee frame is malformed.
*/
#define ERR_FRAME_MALFORMED -302
#define ERR_FRAME_MALFORMED -302
/*!
\brief Received ZigBee frame checksum does not match the calculated.
*/
#define ERR_FRAME_INCORRECT_CHECKSUM -303
#define ERR_FRAME_INCORRECT_CHECKSUM -303
/*!
\brief Received ZigBee frame with unexpected ID.
*/
#define ERR_FRAME_UNEXPECTED_ID -304
#define ERR_FRAME_UNEXPECTED_ID -304
/*!
\brief Timed out waiting for response to ZigBee frame.
*/
#define ERR_FRAME_NO_RESPONSE -305
#define ERR_FRAME_NO_RESPONSE -305
// RTTY status codes
/*!
\brief Supplied RTTY frequency shift is invalid for this module.
*/
#define ERR_INVALID_RTTY_SHIFT -401
#define ERR_INVALID_RTTY_SHIFT -401
/*!
\brief Supplied RTTY encoding is invalid.
*/
#define ERR_UNSUPPORTED_ENCODING -402
#define ERR_UNSUPPORTED_ENCODING -402
// nRF24-specific status codes
/*!
\brief Supplied data rate is invalid.
*/
#define ERR_INVALID_DATA_RATE -501
#define ERR_INVALID_DATA_RATE -501
/*!
\brief Supplied address width is invalid.
*/
#define ERR_INVALID_ADDRESS_WIDTH -502
#define ERR_INVALID_ADDRESS_WIDTH -502
/*!
\brief Supplied data pipe number is invalid.
*/
#define ERR_INVALID_PIPE_NUMBER -503
#define ERR_INVALID_PIPE_NUMBER -503
/*!
\brief ACK packet from destination module was not received within 15 retries.
*/
#define ERR_ACK_NOT_RECEIVED -504
#define ERR_ACK_NOT_RECEIVED -504
// CC1101-specific status codes
/*!
\brief Supplied number of broadcast addresses is invalid.
*/
#define ERR_INVALID_NUM_BROAD_ADDRS -601
#define ERR_INVALID_NUM_BROAD_ADDRS -601
// SX126x-specific status codes
/*!
\brief Supplied CRC configuration is invalid.
*/
#define ERR_INVALID_CRC_CONFIGURATION -701
#define ERR_INVALID_CRC_CONFIGURATION -701
/*!
\brief Detected LoRa transmission while scanning channel.
*/
#define LORA_DETECTED -702
#define LORA_DETECTED -702
/*!
\brief Supplied TCXO reference voltage is invalid.
*/
#define ERR_INVALID_TCXO_VOLTAGE -703
#define ERR_INVALID_TCXO_VOLTAGE -703
/*!
\brief Bit rate / bandwidth / frequency deviation ratio is invalid. See SX126x datasheet for details.
*/
#define ERR_INVALID_MODULATION_PARAMETERS -704
#define ERR_INVALID_MODULATION_PARAMETERS -704
/*!
\brief SX126x timed out while waiting for complete SPI command.
*/
#define ERR_SPI_CMD_TIMEOUT -705
#define ERR_SPI_CMD_TIMEOUT -705
/*!
\brief SX126x received invalid SPI command.
*/
#define ERR_SPI_CMD_INVALID -706
#define ERR_SPI_CMD_INVALID -706
/*!
\brief SX126x failed to execute SPI command.
*/
#define ERR_SPI_CMD_FAILED -707
#define ERR_SPI_CMD_FAILED -707
/*!
\brief The supplied sleep period is invalid.
The specified sleep period is shorter than the time necessary to sleep and wake the hardware
including TCXO delay, or longer than the maximum possible
*/
#define ERR_INVALID_SLEEP_PERIOD -708
/*!
\brief The supplied Rx period is invalid.
The specified Rx period is shorter or longer than the hardware can handle.
*/
#define ERR_INVALID_RX_PERIOD -709
// AX.25-specific status codes
/*!
\brief The provided callsign is invalid.
The specified callsign is longer than 6 ASCII characters.
*/
#define ERR_INVALID_CALLSIGN -801
/*!
\brief The provided repeater configuration is invalid.
The specified number of repeaters does not match number of repeater IDs or their callsigns.
*/
#define ERR_INVALID_NUM_REPEATERS -802
/*!
\brief One of the provided repeater callsigns is invalid.
The specified callsign is longer than 6 ASCII characters.
*/
#define ERR_INVALID_REPEATER_CALLSIGN -803
/*!
\}

View file

@ -1,18 +1,20 @@
#include "CC1101.h"
CC1101::CC1101(Module* module) : PhysicalLayer(CC1101_CRYSTAL_FREQ, CC1101_DIV_EXPONENT, CC1101_MAX_PACKET_LENGTH) {
CC1101::CC1101(Module* module) : PhysicalLayer(CC1101_FREQUENCY_STEP_SIZE, CC1101_MAX_PACKET_LENGTH) {
_mod = module;
_packetLengthQueried = false;
_packetLengthConfig = CC1101_LENGTH_CONFIG_VARIABLE;
_modulation = CC1101_MOD_FORMAT_2_FSK;
_syncWordLength = 2;
}
int16_t CC1101::begin(float freq, float br, float rxBw, float freqDev, int8_t power, uint8_t preambleLength) {
int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t preambleLength) {
// set module properties
_mod->SPIreadCommand = CC1101_CMD_READ;
_mod->SPIwriteCommand = CC1101_CMD_WRITE;
_mod->init(RADIOLIB_USE_SPI, RADIOLIB_INT_0);
_mod->init(RADIOLIB_USE_SPI);
Module::pinMode(_mod->getIrq(), INPUT);
// try to find the CC1101 chip
uint8_t i = 0;
@ -40,7 +42,7 @@ int16_t CC1101::begin(float freq, float br, float rxBw, float freqDev, int8_t po
if(!flagFound) {
RADIOLIB_DEBUG_PRINTLN(F("No CC1101 found!"));
SPI.end();
_mod->term();
return(ERR_CHIP_NOT_FOUND);
} else {
RADIOLIB_DEBUG_PRINTLN(F("Found CC1101! (match by CC1101_REG_VERSION == 0x14)"));
@ -48,51 +50,43 @@ int16_t CC1101::begin(float freq, float br, float rxBw, float freqDev, int8_t po
// configure settings not accessible by API
int16_t state = config();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setFrequency(freq);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure bitrate
state = setBitRate(br);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure default RX bandwidth
state = setRxBandwidth(rxBw);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure default frequency deviation
state = setFrequencyDeviation(freqDev);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure default TX output power
state = setOutputPower(power);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set default packet length mode
state = variablePacketLengthMode();
if (state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure default preamble lenght
state = setPreambleLength(preambleLength);
if (state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set default data shaping
state = setDataShaping(0);
RADIOLIB_ASSERT(state);
// set default encoding
state = setEncoding(2);
RADIOLIB_ASSERT(state);
// flush FIFOs
SPIsendCommand(CC1101_CMD_FLUSH_RX);
@ -104,15 +98,17 @@ int16_t CC1101::begin(float freq, float br, float rxBw, float freqDev, int8_t po
int16_t CC1101::transmit(uint8_t* data, size_t len, uint8_t addr) {
// start transmission
int16_t state = startTransmit(data, len, addr);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// wait for transmission start
while(!digitalRead(_mod->getInt0()));
while(!digitalRead(_mod->getIrq())) {
yield();
}
// wait for transmission end
while(digitalRead(_mod->getInt0()));
while(digitalRead(_mod->getIrq())) {
yield();
}
// set mode to standby
standby();
@ -126,15 +122,17 @@ int16_t CC1101::transmit(uint8_t* data, size_t len, uint8_t addr) {
int16_t CC1101::receive(uint8_t* data, size_t len) {
// start reception
int16_t state = startReceive();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// wait for sync word
while(!digitalRead(_mod->getInt0()));
while(!digitalRead(_mod->getIrq())) {
yield();
}
// wait for packet end
while(digitalRead(_mod->getInt0()));
while(digitalRead(_mod->getIrq())) {
yield();
}
// read packet data
return(readData(data, len));
@ -157,9 +155,7 @@ int16_t CC1101::transmitDirect(uint32_t frf) {
// activate direct mode
int16_t state = directMode();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// start transmitting
SPIsendCommand(CC1101_CMD_TX);
@ -169,9 +165,7 @@ int16_t CC1101::transmitDirect(uint32_t frf) {
int16_t CC1101::receiveDirect() {
// activate direct mode
int16_t state = directMode();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// start receiving
SPIsendCommand(CC1101_CMD_RX);
@ -186,11 +180,26 @@ int16_t CC1101::packetMode() {
}
void CC1101::setGdo0Action(void (*func)(void), uint8_t dir) {
attachInterrupt(digitalPinToInterrupt(_mod->getInt0()), func, dir);
attachInterrupt(digitalPinToInterrupt(_mod->getIrq()), func, dir);
}
void CC1101::clearGdo0Action() {
detachInterrupt(digitalPinToInterrupt(_mod->getIrq()));
}
void CC1101::setGdo2Action(void (*func)(void), uint8_t dir) {
attachInterrupt(digitalPinToInterrupt(_mod->getInt1()), func, dir);
if(_mod->getGpio() != NC) {
return;
}
Module::pinMode(_mod->getGpio(), INPUT);
attachInterrupt(digitalPinToInterrupt(_mod->getGpio()), func, dir);
}
void CC1101::clearGdo2Action() {
if(_mod->getGpio() != NC) {
return;
}
detachInterrupt(digitalPinToInterrupt(_mod->getGpio()));
}
int16_t CC1101::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
@ -206,10 +215,8 @@ int16_t CC1101::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
SPIsendCommand(CC1101_CMD_FLUSH_TX);
// set GDO0 mapping
int state = SPIsetRegValue(CC1101_REG_IOCFG0, CC1101_GDOX_SYNC_WORD_SENT_OR_RECEIVED);
if(state != ERR_NONE) {
return(state);
}
int16_t state = SPIsetRegValue(CC1101_REG_IOCFG0, CC1101_GDOX_SYNC_WORD_SENT_OR_RECEIVED);
RADIOLIB_ASSERT(state);
// optionally write packet length
if (_packetLengthConfig == CC1101_LENGTH_CONFIG_VARIABLE) {
@ -240,9 +247,7 @@ int16_t CC1101::startReceive() {
// set GDO0 mapping
int state = SPIsetRegValue(CC1101_REG_IOCFG0, CC1101_GDOX_SYNC_WORD_SENT_OR_RECEIVED);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set mode to receive
SPIsendCommand(CC1101_CMD_RX);
@ -273,9 +278,6 @@ int16_t CC1101::readData(uint8_t* data, size_t len) {
uint8_t val = SPIgetRegValue(CC1101_REG_FIFO);
_rawLQI = val & 0x7F;
// add terminating null
data[length] = 0;
// flush Rx FIFO
SPIsendCommand(CC1101_CMD_FLUSH_RX);
@ -286,8 +288,8 @@ int16_t CC1101::readData(uint8_t* data, size_t len) {
standby();
// check CRC
if((val & 0b10000000) == 0b00000000) {
return(ERR_CRC_MISMATCH);
if (_crcOn && (val & 0b10000000) == 0b00000000) {
return (ERR_CRC_MISMATCH);
}
return(ERR_NONE);
@ -315,7 +317,8 @@ int16_t CC1101::setFrequency(float freq) {
_freq = freq;
}
return(state);
// Update the TX power accordingly to new freq. (PA values depend on chosen freq)
return(setOutputPower(_power));
}
int16_t CC1101::setBitRate(float br) {
@ -351,14 +354,14 @@ int16_t CC1101::setRxBandwidth(float rxBw) {
for(int8_t e = 3; e >= 0; e--) {
for(int8_t m = 3; m >= 0; m --) {
float point = (CC1101_CRYSTAL_FREQ * 1000000.0)/(8 * (m + 4) * ((uint32_t)1 << e));
if(abs((rxBw * 1000.0) - point) <= 0.001) {
if(abs((rxBw * 1000.0) - point) <= 1000) {
// set Rx channel filter bandwidth
return(SPIsetRegValue(CC1101_REG_MDMCFG4, (e << 6) | (m << 4), 7, 4));
}
}
}
return(ERR_UNKNOWN);
return(ERR_INVALID_RX_BANDWIDTH);
}
int16_t CC1101::setFrequencyDeviation(float freqDev) {
@ -445,12 +448,27 @@ int16_t CC1101::setOutputPower(int8_t power) {
return(ERR_INVALID_OUTPUT_POWER);
}
// write raw power setting
return(SPIsetRegValue(CC1101_REG_PATABLE, powerRaw));
// store the value
_power = power;
if(_modulation == CC1101_MOD_FORMAT_ASK_OOK){
// Amplitude modulation:
// PA_TABLE[0] is the power to be used when transmitting a 0 (no power)
// PA_TABLE[1] is the power to be used when transmitting a 1 (full power)
uint8_t paValues[2] = {0x00, powerRaw};
SPIwriteRegisterBurst(CC1101_REG_PATABLE, paValues, 2);
return(ERR_NONE);
} else {
// Freq modulation:
// PA_TABLE[0] is the power to be used when transmitting.
return(SPIsetRegValue(CC1101_REG_PATABLE, powerRaw));
}
}
int16_t CC1101::setSyncWord(uint8_t* syncWord, uint8_t len, uint8_t maxErrBits) {
if((maxErrBits > 1) || (len > 2)) {
int16_t CC1101::setSyncWord(uint8_t* syncWord, uint8_t len, uint8_t maxErrBits, bool requireCarrierSense) {
if((maxErrBits > 1) || (len != 2)) {
return(ERR_INVALID_SYNC_WORD);
}
@ -464,20 +482,19 @@ int16_t CC1101::setSyncWord(uint8_t* syncWord, uint8_t len, uint8_t maxErrBits)
_syncWordLength = len;
// enable sync word filtering
int16_t state = enableSyncWordFiltering(maxErrBits);
if (state != ERR_NONE) {
return(state);
}
int16_t state = enableSyncWordFiltering(maxErrBits, requireCarrierSense);
RADIOLIB_ASSERT(state);
// set sync word register
_mod->SPIwriteRegisterBurst(CC1101_REG_SYNC1, syncWord, len);
state = SPIsetRegValue(CC1101_REG_SYNC1, syncWord[0]);
state |= SPIsetRegValue(CC1101_REG_SYNC0, syncWord[1]);
return(ERR_NONE);
return(state);
}
int16_t CC1101::setSyncWord(uint8_t syncH, uint8_t syncL, uint8_t maxErrBits) {
int16_t CC1101::setSyncWord(uint8_t syncH, uint8_t syncL, uint8_t maxErrBits, bool requireCarrierSense) {
uint8_t syncWord[] = { syncH, syncL };
return(setSyncWord(syncWord, sizeof(syncWord), maxErrBits));
return(setSyncWord(syncWord, sizeof(syncWord), maxErrBits, requireCarrierSense));
}
int16_t CC1101::setPreambleLength(uint8_t preambleLength) {
@ -524,9 +541,7 @@ int16_t CC1101::setNodeAddress(uint8_t nodeAddr, uint8_t numBroadcastAddrs) {
// enable address filtering
int16_t state = SPIsetRegValue(CC1101_REG_PKTCTRL1, numBroadcastAddrs + 0x01, 1, 0);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set node address
return(SPIsetRegValue(CC1101_REG_ADDR, nodeAddr));
@ -535,14 +550,44 @@ int16_t CC1101::setNodeAddress(uint8_t nodeAddr, uint8_t numBroadcastAddrs) {
int16_t CC1101::disableAddressFiltering() {
// disable address filtering
int16_t state = _mod->SPIsetRegValue(CC1101_REG_PKTCTRL1, CC1101_ADR_CHK_NONE, 1, 0);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set node address to default (0x00)
return(SPIsetRegValue(CC1101_REG_ADDR, 0x00));
}
int16_t CC1101::setOOK(bool enableOOK) {
// Change modulation
if(enableOOK) {
int16_t state = SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_MOD_FORMAT_ASK_OOK, 6, 4);
RADIOLIB_ASSERT(state);
// PA_TABLE[0] is (by default) the power value used when transmitting a "0L".
// Set PA_TABLE[1] to be used when transmitting a "1L".
state = SPIsetRegValue(CC1101_REG_FREND0, 1, 2, 0);
RADIOLIB_ASSERT(state);
// update current modulation
_modulation = CC1101_MOD_FORMAT_ASK_OOK;
} else {
int16_t state = SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_MOD_FORMAT_2_FSK, 6, 4);
RADIOLIB_ASSERT(state);
// Reset FREND0 to default value.
state = SPIsetRegValue(CC1101_REG_FREND0, 0, 2, 0);
RADIOLIB_ASSERT(state);
// update current modulation
_modulation = CC1101_MOD_FORMAT_2_FSK;
}
// Update PA_TABLE values according to the new _modulation.
return(setOutputPower(_power));
}
float CC1101::getRSSI() {
float rssi;
if(_rawRSSI >= 128) {
@ -579,39 +624,29 @@ int16_t CC1101::variablePacketLengthMode(uint8_t maxLen) {
return(setPacketMode(CC1101_LENGTH_CONFIG_VARIABLE, maxLen));
}
int16_t CC1101::enableSyncWordFiltering(uint8_t maxErrBits) {
if (maxErrBits > 1) {
return(ERR_INVALID_SYNC_WORD);
int16_t CC1101::enableSyncWordFiltering(uint8_t maxErrBits, bool requireCarrierSense) {
switch (maxErrBits){
case 0:
// in 16 bit sync word, expect all 16 bits.
return (SPIsetRegValue(CC1101_REG_MDMCFG2,
requireCarrierSense ? CC1101_SYNC_MODE_16_16_THR : CC1101_SYNC_MODE_16_16, 2, 0));
case 1:
// in 16 bit sync word, expect at least 15 bits.
return (SPIsetRegValue(CC1101_REG_MDMCFG2,
requireCarrierSense ? CC1101_SYNC_MODE_15_16_THR : CC1101_SYNC_MODE_15_16, 2, 0));
default:
return (ERR_INVALID_SYNC_WORD);
}
if (maxErrBits == 0) {
if (_syncWordLength == 1) {
// in 16 bit sync word, expect all 16 bits
return(SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_SYNC_MODE_16_16, 2, 0));
} else {
// there's no 32 of 32 case, so we resort to 30 of 32 bits required
return(SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_SYNC_MODE_30_32, 2, 0));
}
}
if (maxErrBits == 1) {
if (_syncWordLength == 1) {
// in 16 bit sync word, expect at least 15 bits
return(SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_SYNC_MODE_15_16, 2, 0));
} else {
// in 32 bits sync word (16 + 16), expect 30 of 32 to match
return(SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_SYNC_MODE_30_32, 2, 0));
}
}
return(ERR_UNKNOWN);
}
int16_t CC1101::disableSyncWordFiltering() {
return(SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_SYNC_MODE_NONE, 2, 0));
int16_t CC1101::disableSyncWordFiltering(bool requireCarrierSense) {
return(SPIsetRegValue(CC1101_REG_MDMCFG2,
requireCarrierSense ? CC1101_SYNC_MODE_NONE_THR : CC1101_SYNC_MODE_NONE, 2, 0));
}
int16_t CC1101::setCrcFiltering(bool crcOn) {
_crcOn = crcOn;
if (crcOn == true) {
return(SPIsetRegValue(CC1101_REG_PKTCTRL0, CC1101_CRC_ON, 2, 2));
} else {
@ -629,18 +664,14 @@ int16_t CC1101::setPromiscuousMode(bool promiscuous) {
if (promiscuous == true) {
// disable preamble and sync word filtering and insertion
state = disableSyncWordFiltering();
if (state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// disable CRC filtering
state = setCrcFiltering(false);
} else {
// enable preamble and sync word filtering and insertion
state = enableSyncWordFiltering();
if (state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// enable CRC filtering
state = setCrcFiltering(true);
@ -649,12 +680,57 @@ int16_t CC1101::setPromiscuousMode(bool promiscuous) {
return(state);
}
int16_t CC1101::setDataShaping(float sh) {
// set mode to standby
int16_t state = standby();
RADIOLIB_ASSERT(state);
// set data shaping
sh *= 10.0;
if(abs(sh - 0.0) <= 0.001) {
state = _mod->SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_MOD_FORMAT_2_FSK, 6, 4);
} else if(abs(sh - 5.0) <= 0.001) {
state = _mod->SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_MOD_FORMAT_GFSK, 6, 4);
} else {
return(ERR_INVALID_DATA_SHAPING);
}
return(state);
}
int16_t CC1101::setEncoding(uint8_t encoding) {
// set mode to standby
int16_t state = standby();
RADIOLIB_ASSERT(state);
// set encoding
switch(encoding) {
case 0:
state = _mod->SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_MANCHESTER_EN_OFF, 3, 3);
RADIOLIB_ASSERT(state);
return(_mod->SPIsetRegValue(CC1101_REG_PKTCTRL0, CC1101_WHITE_DATA_OFF, 6, 6));
case 1:
state = _mod->SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_MANCHESTER_EN_ON, 3, 3);
RADIOLIB_ASSERT(state);
return(_mod->SPIsetRegValue(CC1101_REG_PKTCTRL0, CC1101_WHITE_DATA_OFF, 6, 6));
case 2:
state = _mod->SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_MANCHESTER_EN_OFF, 3, 3);
RADIOLIB_ASSERT(state);
return(_mod->SPIsetRegValue(CC1101_REG_PKTCTRL0, CC1101_WHITE_DATA_ON, 6, 6));
default:
return(ERR_INVALID_ENCODING);
}
}
int16_t CC1101::config() {
// Reset the radio. Registers may be dirty from previous usage.
SPIsendCommand(CC1101_CMD_RESET);
// Wait a ridiculous amount of time to be sure radio is ready.
delay(150);
// enable automatic frequency synthesizer calibration
int16_t state = SPIsetRegValue(CC1101_REG_MCSM0, CC1101_FS_AUTOCAL_IDLE_TO_RXTX, 5, 4);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set packet mode
state = packetMode();
@ -707,19 +783,16 @@ int16_t CC1101::setPacketMode(uint8_t mode, uint8_t len) {
return(ERR_PACKET_TOO_LONG);
}
// set to fixed packet length
int16_t state = _mod->SPIsetRegValue(CC1101_REG_PKTCTRL0, mode, 7, 7);
if (state != ERR_NONE) {
return(state);
}
// set PKTCTRL0.LENGTH_CONFIG
int16_t state = _mod->SPIsetRegValue(CC1101_REG_PKTCTRL0, mode, 1, 0);
RADIOLIB_ASSERT(state);
// set length to register
state = _mod->SPIsetRegValue(CC1101_REG_PKTLEN, len);
if (state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// update the cached value
_packetLength = len;
_packetLengthConfig = mode;
return(state);
}
@ -769,9 +842,9 @@ void CC1101::SPIwriteRegisterBurst(uint8_t reg, uint8_t* data, size_t len) {
}
void CC1101::SPIsendCommand(uint8_t cmd) {
digitalWrite(_mod->getCs(), LOW);
Module::digitalWrite(_mod->getCs(), LOW);
SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0));
SPI.transfer(cmd);
SPI.endTransaction();
digitalWrite(_mod->getCs(), HIGH);
Module::digitalWrite(_mod->getCs(), HIGH);
}

View file

@ -7,9 +7,10 @@
#include "../../protocols/PhysicalLayer/PhysicalLayer.h"
// CC1101 physical layer properties
#define CC1101_FREQUENCY_STEP_SIZE 396.7285156
#define CC1101_MAX_PACKET_LENGTH 63
#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
@ -524,17 +525,17 @@ class CC1101: public PhysicalLayer {
\param br Bit rate to be used in kbps. Defaults to 4.8 kbps.
\param rxBw Receiver bandwidth in kHz. Defaults to 325.0 kHz.
\param freqDev Frequency deviation from carrier frequency in kHz Defaults to 48.0 kHz.
\param rxBw Receiver bandwidth in kHz. Defaults to 325.0 kHz.
\param power Output power in dBm. Defaults to 0 dBm.
\param preambleLength Preamble Length in bytes. Defaults to 4 bytes.
\returns \ref status_codes
*/
int16_t begin(float freq = 868.0, float br = 4.8, float rxBw = 325.0, float freqDev = 48.0, int8_t power = 0, uint8_t preambleLength = 4);
int16_t begin(float freq = 868.0, float br = 4.8, float freqDev = 48.0, float rxBw = 325.0, int8_t power = 0, uint8_t preambleLength = 4);
/*!
\brief Blocking binary transmit method.
@ -601,6 +602,11 @@ class CC1101: public PhysicalLayer {
*/
void setGdo0Action(void (*func)(void), uint8_t dir = FALLING);
/*!
\brief Clears interrupt service routine to call when GDO0 activates.
*/
void clearGdo0Action();
/*!
\brief Sets interrupt service routine to call when GDO2 activates.
@ -610,6 +616,11 @@ class CC1101: public PhysicalLayer {
*/
void setGdo2Action(void (*func)(void), uint8_t dir = FALLING);
/*!
\brief Clears interrupt service routine to call when GDO0 activates.
*/
void clearGdo2Action();
/*!
\brief Interrupt-driven binary transmit method.
Overloads for string-based transmissions are implemented in PhysicalLayer.
@ -698,9 +709,11 @@ class CC1101: public PhysicalLayer {
\param maxErrBits Maximum allowed number of bit errors in received sync word. Defaults to 0.
\param requireCarrierSense Require carrier sense above threshold in addition to sync word.
\returns \ref status_codes
*/
int16_t setSyncWord(uint8_t syncH, uint8_t syncL, uint8_t maxErrBits = 0);
int16_t setSyncWord(uint8_t syncH, uint8_t syncL, uint8_t maxErrBits = 0, bool requireCarrierSense = false);
/*!
\brief Sets 1 or 2 bytes of sync word.
@ -711,9 +724,11 @@ class CC1101: public PhysicalLayer {
\param maxErrBits Maximum allowed number of bit errors in received sync word. Defaults to 0.
\param requireCarrierSense Require carrier sense above threshold in addition to sync word.
\returns \ref status_codes
*/
int16_t setSyncWord(uint8_t* syncWord, uint8_t len, uint8_t maxErrBits = 0);
int16_t setSyncWord(uint8_t* syncWord, uint8_t len, uint8_t maxErrBits = 0, bool requireCarrierSense = false);
/*!
\brief Sets preamble length.
@ -742,6 +757,15 @@ class CC1101: public PhysicalLayer {
*/
int16_t disableAddressFiltering();
/*!
\brief Enables/disables OOK modulation instead of FSK.
\param enableOOK Enable (true) or disable (false) OOK.
\returns \ref status_codes
*/
int16_t setOOK(bool enableOOK);
/*!
\brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet.
@ -788,16 +812,20 @@ class CC1101: public PhysicalLayer {
\param numBits Sync word length in bits.
\param requireCarrierSense Require carrier sense above threshold in addition to sync word.
\returns \ref status_codes
*/
int16_t enableSyncWordFiltering(uint8_t maxErrBits = 0);
int16_t enableSyncWordFiltering(uint8_t maxErrBits = 0, bool requireCarrierSense = false);
/*!
\brief Disable preamble and sync word filtering and generation.
\param requireCarrierSense Require carrier sense above threshold.
\returns \ref status_codes
*/
int16_t disableSyncWordFiltering();
int16_t disableSyncWordFiltering(bool requireCarrierSense = false);
/*!
\brief Enable CRC filtering and generation.
@ -817,6 +845,25 @@ class CC1101: public PhysicalLayer {
*/
int16_t setPromiscuousMode(bool promiscuous = true);
/*!
\brief Sets Gaussian filter bandwidth-time product that will be used for data shaping.
Allowed value is 0.5. Set to 0 to disable data shaping.
\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 transmission encoding.
\param encoding Encoding to be used. Set to 0 for NRZ, 1 for Manchester and 2 for whitening.
\returns \ref status_codes
*/
int16_t setEncoding(uint8_t encoding);
#ifndef RADIOLIB_GODMODE
private:
#endif
@ -825,14 +872,17 @@ class CC1101: public PhysicalLayer {
float _freq;
uint8_t _rawRSSI;
uint8_t _rawLQI;
uint8_t _modulation;
size_t _packetLength;
bool _packetLengthQueried;
uint8_t _packetLengthConfig;
bool _promiscuous;
bool _crcOn = true;
uint8_t _syncWordLength;
int8_t _power;
int16_t config();
int16_t directMode();

View file

@ -9,7 +9,7 @@ int16_t ESP8266::begin(long speed) {
// set module properties
_mod->AtLineFeed = "\r\n";
_mod->baudrate = speed;
_mod->init(RADIOLIB_USE_UART, RADIOLIB_INT_NONE);
_mod->init(RADIOLIB_USE_UART);
// empty UART buffer (garbage data)
_mod->ATemptyBuffer();

View file

@ -1,11 +1,11 @@
#include "HC05.h"
HC05::HC05(Module* mod) : ISerial(mod) {
}
void HC05::begin(long speed) {
// set module properties
_mod->baudrate = speed;
_mod->init(RADIOLIB_USE_UART, RADIOLIB_INT_NONE);
_mod->init(RADIOLIB_USE_UART);
}

View file

@ -1,12 +1,12 @@
#include "JDY08.h"
JDY08::JDY08(Module* mod) : ISerial(mod) {
}
void JDY08::begin(long speed) {
// set module properties
_mod->AtLineFeed = "";
_mod->baudrate = speed;
_mod->init(RADIOLIB_USE_UART, RADIOLIB_INT_NONE);
_mod->init(RADIOLIB_USE_UART);
}

View file

@ -1,6 +1,6 @@
#include "RF69.h"
RF69::RF69(Module* module) : PhysicalLayer(RF69_CRYSTAL_FREQ, RF69_DIV_EXPONENT, RF69_MAX_PACKET_LENGTH) {
RF69::RF69(Module* module) : PhysicalLayer(RF69_FREQUENCY_STEP_SIZE, RF69_MAX_PACKET_LENGTH) {
_mod = module;
_tempOffset = 0;
@ -12,14 +12,19 @@ RF69::RF69(Module* module) : PhysicalLayer(RF69_CRYSTAL_FREQ, RF69_DIV_EXPONENT,
_syncWordLength = 2;
}
int16_t RF69::begin(float freq, float br, float rxBw, float freqDev, int8_t power) {
int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t power) {
// set module properties
_mod->init(RADIOLIB_USE_SPI, RADIOLIB_INT_0);
_mod->init(RADIOLIB_USE_SPI);
Module::pinMode(_mod->getIrq(), INPUT);
// try to find the RF69 chip
uint8_t i = 0;
bool flagFound = false;
while((i < 10) && !flagFound) {
// reset the module
reset();
// check version register
uint8_t version = _mod->SPIreadRegister(RF69_REG_VERSION);
if(version == 0x24) {
flagFound = true;
@ -42,7 +47,7 @@ int16_t RF69::begin(float freq, float br, float rxBw, float freqDev, int8_t powe
if(!flagFound) {
RADIOLIB_DEBUG_PRINTLN(F("No RF69 found!"));
SPI.end();
_mod->term();
return(ERR_CHIP_NOT_FOUND);
} else {
RADIOLIB_DEBUG_PRINTLN(F("Found RF69! (match by RF69_REG_VERSION == 0x24)"));
@ -50,66 +55,77 @@ int16_t RF69::begin(float freq, float br, float rxBw, float freqDev, int8_t powe
// configure settings not accessible by API
int16_t state = config();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setFrequency(freq);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure bitrate
_rxBw = 125.0;
state = setBitRate(br);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure default RX bandwidth
state = setRxBandwidth(rxBw);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure default frequency deviation
state = setFrequencyDeviation(freqDev);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure default TX output power
state = setOutputPower(power);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set default packet length mode
state = variablePacketLengthMode();
if (state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// default sync word values 0x2D01 is the same as the default in LowPowerLab RFM69 library
uint8_t syncWord[] = {0x2D, 0x01};
state = setSyncWord(syncWord, sizeof(syncWord));
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set default data shaping
state = setDataShaping(0);
RADIOLIB_ASSERT(state);
// set default encoding
state = setEncoding(0);
RADIOLIB_ASSERT(state);
return(ERR_NONE);
}
void RF69::reset() {
Module::pinMode(_mod->getRst(), OUTPUT);
Module::digitalWrite(_mod->getRst(), HIGH);
delayMicroseconds(100);
Module::digitalWrite(_mod->getRst(), LOW);
delay(10);
}
int16_t RF69::transmit(uint8_t* data, size_t len, uint8_t addr) {
// 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
int16_t state = startTransmit(data, len, addr);
if(state != ERR_NONE) {
return(state);
RADIOLIB_ASSERT(state);
// wait for transmission end or timeout
uint32_t start = micros();
while(!digitalRead(_mod->getIrq())) {
if(micros() - start > timeout) {
standby();
clearIRQFlags();
return(ERR_TX_TIMEOUT);
}
}
// wait for transmission end
while(!digitalRead(_mod->getInt0()));
// set mode to standby
standby();
// clear interrupt flags
clearIRQFlags();
@ -118,15 +134,18 @@ int16_t RF69::transmit(uint8_t* data, size_t len, uint8_t addr) {
}
int16_t RF69::receive(uint8_t* data, size_t len) {
// calculate timeout (500 ms + 400 full 64-byte packets at current bit rate)
uint32_t timeout = 500000 + (1.0/(_br*1000.0))*(RF69_MAX_PACKET_LENGTH*400.0);
// start reception
int16_t state = startReceive(true);
if(state != ERR_NONE) {
return(state);
}
int16_t state = startReceive();
RADIOLIB_ASSERT(state);
// wait for packet reception or timeout
while(!digitalRead(_mod->getInt0())) {
if(digitalRead(_mod->getInt1())) {
uint32_t start = micros();
while(!digitalRead(_mod->getIrq())) {
if(micros() - start > timeout) {
standby();
clearIRQFlags();
return(ERR_RX_TIMEOUT);
}
@ -158,9 +177,7 @@ int16_t RF69::transmitDirect(uint32_t frf) {
// activate direct mode
int16_t state = directMode();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// start transmitting
return(setMode(RF69_TX));
@ -169,9 +186,7 @@ int16_t RF69::transmitDirect(uint32_t frf) {
int16_t RF69::receiveDirect() {
// activate direct mode
int16_t state = directMode();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// start receiving
return(setMode(RF69_RX));
@ -180,16 +195,14 @@ int16_t RF69::receiveDirect() {
int16_t RF69::directMode() {
// set mode to standby
int16_t state = setMode(RF69_STANDBY);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set DIO mapping
state = _mod->SPIsetRegValue(RF69_REG_DIO_MAPPING_1, RF69_DIO1_CONT_DCLK | RF69_DIO2_CONT_DATA, 5, 2);
RADIOLIB_ASSERT(state);
// set continuous mode
state |= _mod->SPIsetRegValue(RF69_REG_DATA_MODUL, RF69_CONTINUOUS_MODE_WITH_SYNC, 6, 5);
return(state);
return(_mod->SPIsetRegValue(RF69_REG_DATA_MODUL, RF69_CONTINUOUS_MODE_WITH_SYNC, 6, 5));
}
int16_t RF69::packetMode() {
@ -208,23 +221,15 @@ int16_t RF69::disableAES() {
return(_mod->SPIsetRegValue(RF69_REG_PACKET_CONFIG_2, RF69_AES_OFF, 0, 0));
}
int16_t RF69::startReceive(bool timeout) {
int16_t RF69::startReceive() {
// set mode to standby
int16_t state = setMode(RF69_STANDBY);
// 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);
}
state = _mod->SPIsetRegValue(RF69_REG_DIO_MAPPING_1, RF69_DIO0_PACK_PAYLOAD_READY, 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);
RADIOLIB_ASSERT(state);
// clear interrupt flags
clearIRQFlags();
@ -238,11 +243,26 @@ int16_t RF69::startReceive(bool timeout) {
}
void RF69::setDio0Action(void (*func)(void)) {
attachInterrupt(digitalPinToInterrupt(_mod->getInt0()), func, RISING);
attachInterrupt(digitalPinToInterrupt(_mod->getIrq()), func, RISING);
}
void RF69::clearDio0Action() {
detachInterrupt(digitalPinToInterrupt(_mod->getIrq()));
}
void RF69::setDio1Action(void (*func)(void)) {
attachInterrupt(digitalPinToInterrupt(_mod->getInt1()), func, RISING);
if(_mod->getGpio() != NC) {
return;
}
Module::pinMode(_mod->getGpio(), INPUT);
attachInterrupt(digitalPinToInterrupt(_mod->getGpio()), func, RISING);
}
void RF69::clearDio1Action() {
if(_mod->getGpio() != NC) {
return;
}
detachInterrupt(digitalPinToInterrupt(_mod->getGpio()));
}
int16_t RF69::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
@ -253,12 +273,11 @@ int16_t RF69::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
// set mode to standby
int16_t state = setMode(RF69_STANDBY);
RADIOLIB_ASSERT(state);
// set DIO pin mapping
state |= _mod->SPIsetRegValue(RF69_REG_DIO_MAPPING_1, RF69_DIO0_PACK_PACKET_SENT, 7, 6);
if(state != ERR_NONE) {
return(state);
}
state = _mod->SPIsetRegValue(RF69_REG_DIO_MAPPING_1, RF69_DIO0_PACK_PACKET_SENT, 7, 6);
RADIOLIB_ASSERT(state);
// clear interrupt flags
clearIRQFlags();
@ -291,10 +310,7 @@ int16_t RF69::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
int16_t RF69::readData(uint8_t* data, size_t len) {
// set mdoe to standby
int16_t state = standby();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// get packet length
size_t length = len;
if(len == RF69_MAX_PACKET_LENGTH) {
@ -310,9 +326,6 @@ int16_t RF69::readData(uint8_t* data, size_t len) {
// read packet data
_mod->SPIreadRegisterBurst(RF69_REG_FIFO, length, data);
// add terminating null
data[length] = 0;
// update RSSI
lastPacketRSSI = -1.0 * (_mod->SPIgetRegValue(RF69_REG_RSSI_VALUE)/2.0);
@ -520,9 +533,7 @@ int16_t RF69::setSyncWord(uint8_t* syncWord, size_t len, uint8_t maxErrBits) {
_syncWordLength = len;
int16_t state = enableSyncWordFiltering(maxErrBits);
if (state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set sync word register
_mod->SPIwriteRegisterBurst(RF69_REG_SYNC_VALUE_1, syncWord, len);
@ -532,9 +543,7 @@ int16_t RF69::setSyncWord(uint8_t* syncWord, size_t len, uint8_t maxErrBits) {
int16_t RF69::setNodeAddress(uint8_t nodeAddr) {
// enable address filtering (node only)
int16_t state = _mod->SPIsetRegValue(RF69_REG_PACKET_CONFIG_1, RF69_ADDRESS_FILTERING_NODE, 2, 1);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set node address
return(_mod->SPIsetRegValue(RF69_REG_NODE_ADRS, nodeAddr));
@ -543,9 +552,7 @@ int16_t RF69::setNodeAddress(uint8_t nodeAddr) {
int16_t RF69::setBroadcastAddress(uint8_t broadAddr) {
// enable address filtering (node + broadcast)
int16_t state = _mod->SPIsetRegValue(RF69_REG_PACKET_CONFIG_1, RF69_ADDRESS_FILTERING_NODE_BROADCAST, 2, 1);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set broadcast address
return(_mod->SPIsetRegValue(RF69_REG_BROADCAST_ADRS, broadAddr));
@ -554,15 +561,11 @@ int16_t RF69::setBroadcastAddress(uint8_t broadAddr) {
int16_t RF69::disableAddressFiltering() {
// disable address filtering
int16_t state = _mod->SPIsetRegValue(RF69_REG_PACKET_CONFIG_1, RF69_ADDRESS_FILTERING_OFF, 2, 1);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set node address to default (0x00)
state = _mod->SPIsetRegValue(RF69_REG_NODE_ADRS, 0x00);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set broadcast address to default (0x00)
return(_mod->SPIsetRegValue(RF69_REG_BROADCAST_ADRS, 0x00));
@ -612,27 +615,17 @@ int16_t RF69::variablePacketLengthMode(uint8_t maxLen) {
int16_t RF69::enableSyncWordFiltering(uint8_t maxErrBits) {
// enable sync word recognition
int16_t state = _mod->SPIsetRegValue(RF69_REG_SYNC_CONFIG, RF69_SYNC_ON | RF69_FIFO_FILL_CONDITION_SYNC | (_syncWordLength - 1) << 3 | maxErrBits, 7, 0);
if(state != ERR_NONE) {
return(state);
}
return(state);
return(_mod->SPIsetRegValue(RF69_REG_SYNC_CONFIG, RF69_SYNC_ON | RF69_FIFO_FILL_CONDITION_SYNC | (_syncWordLength - 1) << 3 | maxErrBits, 7, 0));
}
int16_t RF69::disableSyncWordFiltering() {
// disable preamble detection and generation
int16_t state = _mod->SPIsetRegValue(RF69_REG_PREAMBLE_LSB, 0, 7, 0);
state |= _mod->SPIsetRegValue(RF69_REG_PREAMBLE_MSB, 0, 7, 0);
if (state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// disable sync word detection and generation
state = _mod->SPIsetRegValue(RF69_REG_SYNC_CONFIG, RF69_SYNC_OFF | RF69_FIFO_FILL_CONDITION, 7, 6);
if (state != ERR_NONE) {
return(state);
}
return(state);
}
@ -655,18 +648,14 @@ int16_t RF69::setPromiscuousMode(bool promiscuous) {
if (promiscuous == true) {
// disable preamble and sync word filtering and insertion
state = disableSyncWordFiltering();
if (state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// disable CRC filtering
state = setCrcFiltering(false);
} else {
// enable preamble and sync word filtering and insertion
state = enableSyncWordFiltering();
if (state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// enable CRC filtering
state = setCrcFiltering(true);
@ -675,81 +664,97 @@ int16_t RF69::setPromiscuousMode(bool promiscuous) {
return(state);
}
int16_t RF69::setDataShaping(float sh) {
// set mode to standby
int16_t state = standby();
RADIOLIB_ASSERT(state);
// set data shaping
sh *= 10.0;
if(abs(sh - 0.0) <= 0.001) {
state = _mod->SPIsetRegValue(RF69_REG_DATA_MODUL, RF69_NO_SHAPING, 1, 0);
} else if(abs(sh - 3.0) <= 0.001) {
state = _mod->SPIsetRegValue(RF69_REG_DATA_MODUL, RF69_FSK_GAUSSIAN_0_3, 1, 0);
} else if(abs(sh - 5.0) <= 0.001) {
state = _mod->SPIsetRegValue(RF69_REG_DATA_MODUL, RF69_FSK_GAUSSIAN_0_5, 1, 0);
} else if(abs(sh - 10.0) <= 0.001) {
state = _mod->SPIsetRegValue(RF69_REG_DATA_MODUL, RF69_FSK_GAUSSIAN_1_0, 1, 0);
} else {
return(ERR_INVALID_DATA_SHAPING);
}
return(state);
}
int16_t RF69::setEncoding(uint8_t encoding) {
// set mode to standby
int16_t state = standby();
RADIOLIB_ASSERT(state);
// set encoding
switch(encoding) {
case 0:
return(_mod->SPIsetRegValue(RF69_REG_PACKET_CONFIG_1, RF69_DC_FREE_NONE, 6, 5));
case 1:
return(_mod->SPIsetRegValue(RF69_REG_PACKET_CONFIG_1, RF69_DC_FREE_MANCHESTER, 6, 5));
case 2:
return(_mod->SPIsetRegValue(RF69_REG_PACKET_CONFIG_1, RF69_DC_FREE_WHITENING, 6, 5));
default:
return(ERR_INVALID_ENCODING);
}
}
int16_t RF69::config() {
int16_t state = ERR_NONE;
// set mode to STANDBY
state = setMode(RF69_STANDBY);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set operation modes
state = _mod->SPIsetRegValue(RF69_REG_OP_MODE, RF69_SEQUENCER_ON | RF69_LISTEN_OFF, 7, 6);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// enable over-current protection
state = _mod->SPIsetRegValue(RF69_REG_OCP, RF69_OCP_ON, 4, 4);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set data mode, modulation type and shaping
state = _mod->SPIsetRegValue(RF69_REG_DATA_MODUL, RF69_PACKET_MODE | RF69_FSK, 6, 3);
state |= _mod->SPIsetRegValue(RF69_REG_DATA_MODUL, RF69_FSK_GAUSSIAN_0_3, 1, 0);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set RSSI threshold
state = _mod->SPIsetRegValue(RF69_REG_RSSI_THRESH, RF69_RSSI_THRESHOLD, 7, 0);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// reset FIFO flag
_mod->SPIwriteRegister(RF69_REG_IRQ_FLAGS_2, RF69_IRQ_FIFO_OVERRUN);
// disable ClkOut on DIO5
state = _mod->SPIsetRegValue(RF69_REG_DIO_MAPPING_2, RF69_CLK_OUT_OFF, 2, 0);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set packet configuration and disable encryption
state = _mod->SPIsetRegValue(RF69_REG_PACKET_CONFIG_1, RF69_PACKET_FORMAT_VARIABLE | RF69_DC_FREE_NONE | RF69_CRC_ON | RF69_CRC_AUTOCLEAR_ON | RF69_ADDRESS_FILTERING_OFF, 7, 1);
state |= _mod->SPIsetRegValue(RF69_REG_PACKET_CONFIG_2, RF69_INTER_PACKET_RX_DELAY, 7, 4);
state |= _mod->SPIsetRegValue(RF69_REG_PACKET_CONFIG_2, RF69_AUTO_RX_RESTART_ON | RF69_AES_OFF, 1, 0);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set payload length
state = _mod->SPIsetRegValue(RF69_REG_PAYLOAD_LENGTH, RF69_PAYLOAD_LENGTH, 7, 0);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set FIFO threshold
state = _mod->SPIsetRegValue(RF69_REG_FIFO_THRESH, RF69_TX_START_CONDITION_FIFO_NOT_EMPTY | RF69_FIFO_THRESHOLD, 7, 0);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set Rx timeouts
state = _mod->SPIsetRegValue(RF69_REG_RX_TIMEOUT_1, RF69_TIMEOUT_RX_START, 7, 0);
state = _mod->SPIsetRegValue(RF69_REG_RX_TIMEOUT_2, RF69_TIMEOUT_RSSI_THRESH, 7, 0);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// enable improved fading margin
state = _mod->SPIsetRegValue(RF69_REG_TEST_DAGC, RF69_CONTINUOUS_DAGC_LOW_BETA_OFF, 7, 0);
if(state != ERR_NONE) {
return(state);
}
return(ERR_NONE);
}
@ -762,15 +767,11 @@ int16_t RF69::setPacketMode(uint8_t mode, uint8_t len) {
// set to fixed packet length
int16_t state = _mod->SPIsetRegValue(RF69_REG_PACKET_CONFIG_1, mode, 7, 7);
if (state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set length to register
state = _mod->SPIsetRegValue(RF69_REG_PAYLOAD_LENGTH, len);
if (state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// update the cached value
_packetLengthConfig = mode;

View file

@ -7,9 +7,10 @@
#include "../../protocols/PhysicalLayer/PhysicalLayer.h"
// RF69 physical layer properties
#define RF69_FREQUENCY_STEP_SIZE 61.03515625
#define RF69_MAX_PACKET_LENGTH 64
#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
@ -454,15 +455,20 @@ class RF69: public PhysicalLayer {
\param br Bit rate to be used in kbps. Defaults to 48.0 kbps.
\param rxBw Receiver bandwidth in kHz. Defaults to 125.0 kHz.
\param freqDev Frequency deviation from carrier frequency in kHz Defaults to 50.0 kHz.
\param rxBw Receiver bandwidth in kHz. Defaults to 125.0 kHz.
\param power Output power in dBm. Defaults to 13 dBm.
\returns \ref status_codes
*/
int16_t begin(float freq = 434.0, float br = 48.0, float rxBw = 125.0, float freqDev = 50.0, int8_t power = 13);
int16_t begin(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 125.0, int8_t power = 13);
/*!
\brief Reset method. Will reset the chip to the default state using RST pin.
*/
void reset();
/*!
\brief Blocking binary transmit method.
@ -557,6 +563,11 @@ class RF69: public PhysicalLayer {
*/
void setDio0Action(void (*func)(void));
/*!
\brief Clears interrupt service routine to call when DIO0 activates.
*/
void clearDio0Action();
/*!
\brief Sets interrupt service routine to call when DIO1 activates.
@ -564,6 +575,11 @@ class RF69: public PhysicalLayer {
*/
void setDio1Action(void (*func)(void));
/*!
\brief Clears interrupt service routine to call when DIO1 activates.
*/
void clearDio1Action();
/*!
\brief Interrupt-driven binary transmit method.
Overloads for string-based transmissions are implemented in PhysicalLayer.
@ -581,11 +597,9 @@ 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(bool timeout = false);
int16_t startReceive();
/*!
\brief Reads data received after calling startReceive method.
@ -758,6 +772,25 @@ class RF69: public PhysicalLayer {
*/
int16_t setPromiscuousMode(bool promiscuous = true);
/*!
\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.
\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 transmission encoding.
\param encoding Encoding to be used. Set to 0 for NRZ, 1 for Manchester and 2 for whitening.
\returns \ref status_codes
*/
int16_t setEncoding(uint8_t encoding);
#ifndef RADIOLIB_GODMODE
protected:
#endif

View file

@ -7,47 +7,30 @@ RFM95::RFM95(Module* mod) : SX1278(mod) {
int16_t RFM95::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint8_t currentLimit, uint16_t preambleLength, uint8_t gain) {
// execute common part
int16_t state = SX127x::begin(RFM95_CHIP_VERSION, syncWord, currentLimit, preambleLength);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure settings not accessible by API
state = config();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setFrequency(freq);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setBandwidth(bw);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setSpreadingFactor(sf);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setCodingRate(cr);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setOutputPower(power);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setGain(gain);
if(state != ERR_NONE) {
return(state);
}
return(state);
}
@ -56,7 +39,7 @@ int16_t RFM95::setFrequency(float freq) {
if((freq < 868.0) || (freq > 915.0)) {
return(ERR_INVALID_FREQUENCY);
}
// set frequency
return(SX127x::setFrequencyRaw(freq));
}

View file

@ -7,47 +7,30 @@ RFM96::RFM96(Module* mod) : SX1278(mod) {
int16_t RFM96::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint8_t currentLimit, uint16_t preambleLength, uint8_t gain) {
// execute common part
int16_t state = SX127x::begin(RFM9X_CHIP_VERSION, syncWord, currentLimit, preambleLength);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure settings not accessible by API
state = config();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setFrequency(freq);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setBandwidth(bw);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setSpreadingFactor(sf);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setCodingRate(cr);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setOutputPower(power);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setGain(gain);
if(state != ERR_NONE) {
return(state);
}
return(state);
}
@ -56,7 +39,7 @@ int16_t RFM96::setFrequency(float freq) {
if((freq < 433.0) || (freq > 470.0)) {
return(ERR_INVALID_FREQUENCY);
}
// set frequency
return(SX127x::setFrequencyRaw(freq));
}

View file

@ -11,7 +11,7 @@ int16_t RFM97::setSpreadingFactor(uint8_t sf) {
}
uint8_t newSpreadingFactor;
// check allowed spreading factor values
switch(sf) {
case 6:
@ -29,7 +29,7 @@ int16_t RFM97::setSpreadingFactor(uint8_t sf) {
default:
return(ERR_INVALID_SPREADING_FACTOR);
}
// set spreading factor and if successful, save the new setting
int16_t state = SX1278::setSpreadingFactorRaw(newSpreadingFactor);
if(state == ERR_NONE) {

View file

@ -6,7 +6,9 @@ SX1231::SX1231(Module* mod) : RF69(mod) {
int16_t SX1231::begin(float freq, float br, float rxBw, float freqDev, int8_t power) {
// set module properties
_mod->init(RADIOLIB_USE_SPI, RADIOLIB_INT_BOTH);
_mod->init(RADIOLIB_USE_SPI);
Module::pinMode(_mod->getIrq(), INPUT);
Module::pinMode(_mod->getRst(), OUTPUT);
// try to find the SX1231 chip
uint8_t i = 0;
@ -35,7 +37,7 @@ int16_t SX1231::begin(float freq, float br, float rxBw, float freqDev, int8_t po
if(!flagFound) {
RADIOLIB_DEBUG_PRINTLN(F("No SX1231 found!"));
SPI.end();
_mod->term();
return(ERR_CHIP_NOT_FOUND);
} else {
RADIOLIB_DEBUG_PRINTLN(F("Found SX1231!"));
@ -43,47 +45,33 @@ int16_t SX1231::begin(float freq, float br, float rxBw, float freqDev, int8_t po
// configure settings not accessible by API
int16_t state = config();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setFrequency(freq);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure bitrate
_rxBw = 125.0;
state = setBitRate(br);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure default RX bandwidth
state = setRxBandwidth(rxBw);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure default frequency deviation
state = setFrequencyDeviation(freqDev);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure default TX output power
state = setOutputPower(power);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// default sync word values 0x2D01 is the same as the default in LowPowerLab RFM69 library
uint8_t syncWord[] = {0x2D, 0x01};
state = setSyncWord(syncWord, 2);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set default packet length mode
state = variablePacketLengthMode();
@ -95,15 +83,11 @@ int16_t SX1231::begin(float freq, float br, float rxBw, float freqDev, int8_t po
if(_chipRevision == SX1231_CHIP_REVISION_2_A) {
// modify default OOK threshold value
state = _mod->SPIsetRegValue(SX1231_REG_TEST_OOK, SX1231_OOK_DELTA_THRESHOLD);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// enable OCP with 95 mA limit
state = _mod->SPIsetRegValue(RF69_REG_OCP, RF69_OCP_ON | RF69_OCP_TRIM, 4, 0);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
}
return(ERR_NONE);

View file

@ -1,11 +1,10 @@
#include "SX1261.h"
SX1261::SX1261(Module* mod)
: SX1262(mod) {
SX1261::SX1261(Module* mod): SX1262(mod) {
}
int16_t SX1261::setOutputPower(int8_t power) {
int16_t SX1261::setOutputPower(int8_t power) {
// check allowed power range
if (!((power >= -17) && (power <= 14))) {
return(ERR_INVALID_OUTPUT_POWER);
@ -14,37 +13,17 @@ int16_t SX1261::setOutputPower(int8_t 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);
}
RADIOLIB_ASSERT(state);
state = setOptimalLowPowerPaConfig(&power);
if (state != ERR_NONE) {
return(state);
}
// set PA config
state = SX126x::setPaConfig(0x04, SX126X_PA_CONFIG_SX1261, 0x00);
RADIOLIB_ASSERT(state);
// set output power
// TODO power ramp time configuration
state = SX126x::setTxParams(power);
if (state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// restore OCP configuration
return writeRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1);
}
int16_t SX1261::setOptimalLowPowerPaConfig(int8_t* inOutPower)
{
int16_t state;
if (*inOutPower > 10) {
state = SX126x::setPaConfig(0x04, SX126X_PA_CONFIG_SX1261, 0x00);
}
else {
state = SX126x::setPaConfig(0x01, SX126X_PA_CONFIG_SX1261, 0x00);
// changing the PaConfig means output power is now scaled so we get 3 dB less than requested.
// see datasheet table 13-21 and comments in setOptimalHiPowerPaConfig.
*inOutPower -= 3;
}
return state;
return(writeRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1));
}

View file

@ -35,7 +35,7 @@ class SX1261 : public SX1262 {
#ifndef RADIOLIB_GODMODE
private:
#endif
int16_t setOptimalLowPowerPaConfig(int8_t* inOutPower);
};

View file

@ -4,54 +4,36 @@ 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) {
int16_t SX1262::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, float currentLimit, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) {
// execute common part
int16_t state = SX126x::begin(bw, sf, cr, syncWord, currentLimit, preambleLength);
if(state != ERR_NONE) {
return(state);
}
int16_t state = SX126x::begin(bw, sf, cr, syncWord, currentLimit, preambleLength, tcxoVoltage, useRegulatorLDO);
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setFrequency(freq);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setOutputPower(power);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = SX126x::fixPaClamping();
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) {
int16_t SX1262::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, float currentLimit, uint16_t preambleLength, float dataShaping, float tcxoVoltage, bool useRegulatorLDO) {
// execute common part
int16_t state = SX126x::beginFSK(br, freqDev, rxBw, currentLimit, preambleLength, dataShaping);
if(state != ERR_NONE) {
return(state);
}
int16_t state = SX126x::beginFSK(br, freqDev, rxBw, currentLimit, preambleLength, dataShaping, tcxoVoltage, useRegulatorLDO);
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setFrequency(freq);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setOutputPower(power);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = SX126x::fixPaClamping();
if (state != ERR_NONE) {
return state;
}
return(state);
}
@ -84,9 +66,7 @@ int16_t SX1262::setFrequency(float freq, bool calibrate) {
data[1] = SX126X_CAL_IMG_430_MHZ_2;
}
state = SX126x::calibrateImage(data);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
}
// set frequency
@ -102,25 +82,17 @@ int16_t SX1262::setOutputPower(int8_t 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);
}
RADIOLIB_ASSERT(state);
// this function sets the optimal PA settings
// and adjusts power based on the PA settings chosen
// so that output power matches requested power.
state = SX126x::setOptimalHiPowerPaConfig(&power);
if (state != ERR_NONE) {
return(state);
}
// set PA config
state = SX126x::setPaConfig(0x04, SX126X_PA_CONFIG_SX1262);
RADIOLIB_ASSERT(state);
// set output power
// TODO power ramp time configuration
state = SX126x::setTxParams(power);
if (state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// restore OCP configuration
return writeRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1);
return(writeRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1));
}

View file

@ -5,6 +5,9 @@
#include "../../Module.h"
#include "SX126x.h"
//SX126X_CMD_SET_PA_CONFIG
#define SX126X_PA_CONFIG_SX1262 0x00
/*!
\class SX1262
@ -32,7 +35,7 @@ class SX1262: public SX126x {
\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 syncWord 2-byte LoRa sync word. Defaults to SX126X_SYNC_WORD_PRIVATE (0x12).
\param power Output power in dBm. Defaults to 14 dBm.
@ -40,9 +43,11 @@ class SX1262: public SX126x {
\param preambleLength LoRa preamble length in symbols.Defaults to 8 symbols.
\param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip.
\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);
int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX126X_SYNC_WORD_PRIVATE, int8_t power = 14, float currentLimit = 60.0, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false);
/*!
\brief Initialization method for FSK modem.
@ -63,9 +68,11 @@ class SX1262: public SX126x {
\param dataShaping Time-bandwidth product of the Gaussian filter to be used for shaping. Defaults to 0.5.
\param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip.
\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);
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, float tcxoVoltage = 1.6, bool useRegulatorLDO = false);
// configuration methods

View file

@ -4,53 +4,35 @@ 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) {
int16_t SX1268::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, float currentLimit, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) {
// execute common part
int16_t state = SX126x::begin(bw, sf, cr, syncWord, currentLimit, preambleLength);
if(state != ERR_NONE) {
return(state);
}
int16_t state = SX126x::begin(bw, sf, cr, syncWord, currentLimit, preambleLength, tcxoVoltage, useRegulatorLDO);
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setFrequency(freq);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setOutputPower(power);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = SX126x::fixPaClamping();
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) {
int16_t SX1268::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, float currentLimit, uint16_t preambleLength, float dataShaping, float tcxoVoltage, bool useRegulatorLDO) {
// execute common part
int16_t state = SX126x::beginFSK(br, freqDev, rxBw, currentLimit, preambleLength, dataShaping);
if(state != ERR_NONE) {
return(state);
}
int16_t state = SX126x::beginFSK(br, freqDev, rxBw, currentLimit, preambleLength, dataShaping, tcxoVoltage, useRegulatorLDO);
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setFrequency(freq);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setOutputPower(power);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = SX126x::fixPaClamping();
if (state != ERR_NONE) {
return state;
}
return(state);
}
@ -77,9 +59,7 @@ int16_t SX1268::setFrequency(float freq, bool calibrate) {
data[1] = SX126X_CAL_IMG_430_MHZ_2;
}
state = SX126x::calibrateImage(data);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
}
// set frequency
@ -95,23 +75,17 @@ int16_t SX1268::setOutputPower(int8_t 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);
}
RADIOLIB_ASSERT(state);
// enable optimal PA - this changes the value of power.
state = SX126x::setOptimalHiPowerPaConfig(&power);
if (state != ERR_NONE) {
return(state);
}
// set PA config
state = SX126x::setPaConfig(0x04, SX126X_PA_CONFIG_SX1268);
RADIOLIB_ASSERT(state);
// set output power
// TODO power ramp time configuration
state = SX126x::setTxParams(power);
if (state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// restore OCP configuration
return writeRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1);
return(writeRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1));
}

View file

@ -35,17 +35,19 @@ class SX1268: public SX126x {
\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 syncWord 2-byte LoRa sync word. Defaults to SX126X_SYNC_WORD_PRIVATE (0x12).
\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.
\param preambleLength LoRa preamble length in symbols. Defaults to 8 symbols.
\param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip.
\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);
int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX126X_SYNC_WORD_PRIVATE, int8_t power = 14, float currentLimit = 60.0, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false);
/*!
\brief Initialization method for FSK modem.
@ -66,14 +68,16 @@ class SX1268: public SX126x {
\param dataShaping Time-bandwidth product of the Gaussian filter to be used for shaping. Defaults to 0.5.
\param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip.
\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);
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, float tcxoVoltage = 1.6, bool useRegulatorLDO = false);
// configuration methods
/*!
\brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz.
\brief Sets carrier frequency. Allowed values are in range from 410.0 to 810.0 MHz.
\param freq Carrier frequency to be set in MHz.
@ -84,7 +88,7 @@ class SX1268: public SX126x {
int16_t setFrequency(float freq, bool calibrate = true);
/*!
\brief Sets output power. Allowed values are in range from -17 to 22 dBm.
\brief Sets output power. Allowed values are in range from -9 to 22 dBm.
\param power Output power to be set in dBm.

File diff suppressed because it is too large Load diff

View file

@ -7,9 +7,10 @@
#include "../../protocols/PhysicalLayer/PhysicalLayer.h"
// SX126X physical layer properties
#define SX126X_FREQUENCY_STEP_SIZE 0.9536743164
#define SX126X_MAX_PACKET_LENGTH 255
#define SX126X_CRYSTAL_FREQ 32.0
#define SX126X_DIV_EXPONENT 25
#define SX126X_MAX_PACKET_LENGTH 255
// SX126X SPI commands
// operational modes commands
@ -325,8 +326,8 @@
// SX126X SPI register variables
//SX126X_REG_LORA_SYNC_WORD_MSB + LSB
#define SX126X_SYNC_WORD_PUBLIC 0x3444
#define SX126X_SYNC_WORD_PRIVATE 0x1424
#define SX126X_SYNC_WORD_PUBLIC 0x34 // actually 0x3444 NOTE: The low nibbles in each byte (0x_4_4) are masked out since apparently, they're reserved.
#define SX126X_SYNC_WORD_PRIVATE 0x12 // actually 0x1424 You couldn't make this up if you tried.
/*!
@ -361,15 +362,19 @@ class SX126x: public PhysicalLayer {
\param cr LoRa coding rate denominator. Allowed values range from 5 to 8.
\param syncWord 2-byte LoRa sync word.
\param syncWord 1-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.
\param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip.
\param useRegulatorLDO use the LDO instead of DC-DC converter (default false). This is necessary for some modules such as the LAMBDA from RF solutions.
\returns \ref status_codes
*/
int16_t begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, float currentLimit, uint16_t preambleLength);
int16_t begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, float currentLimit, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO = false);
/*!
\brief Initialization method for FSK modem.
@ -386,9 +391,23 @@ class SX126x: public PhysicalLayer {
\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.
\param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip.
\param useRegulatorLDO use the LDO instead of DC-DC converter (default false). This is necessary for some modules such as the LAMBDA from RF solutions.
\returns \ref status_codes
*/
int16_t beginFSK(float br, float freqDev, float rxBw, float currentLimit, uint16_t preambleLength, float dataShaping);
int16_t beginFSK(float br, float freqDev, float rxBw, float currentLimit, uint16_t preambleLength, float dataShaping, float tcxoVoltage, bool useRegulatorLDO = false);
/*!
\brief Reset method. Will reset the chip to the default state using RST pin.
\param verify Whether correct module startup should be verified. When set to true, RadioLib will attempt to verify the module has started correctly
by repeatedly issuing setStandby command. Enabled by default.
\returns \ref status_codes
*/
int16_t reset(bool verify = true);
/*!
\brief Blocking binary transmit method.
@ -443,9 +462,11 @@ class SX126x: public PhysicalLayer {
/*!
\brief Sets the module to sleep mode.
\param retainConfig Set to true to retain configuration of the currently active modem ("warm start") or to false to discard current configuration ("cold start"). Defaults to true.
\returns \ref status_codes
*/
int16_t sleep();
int16_t sleep(bool retainConfig = true);
/*!
\brief Sets the module to standby mode (overload for PhysicalLayer compatibility, uses 13 MHz RC oscillator).
@ -473,11 +494,9 @@ class SX126x: public PhysicalLayer {
void setDio1Action(void (*func)(void));
/*!
\brief Sets interrupt service routine to call when DIO2 activates.
\param func ISR to call.
\brief Clears interrupt service routine to call when DIO1 activates.
*/
void setDio2Action(void (*func)(void));
void clearDio1Action();
/*!
\brief Interrupt-driven binary transmit method.
@ -502,6 +521,31 @@ class SX126x: public PhysicalLayer {
*/
int16_t startReceive(uint32_t timeout = SX126X_RX_TIMEOUT_INF);
/*!
\brief Interrupt-driven receive method where the device mostly sleeps and periodically wakes to listen.
Note that this function assumes the unit will take 500us + TCXO_delay to change state. See datasheet section 13.1.7, version 1.2.
\param rxPeriod The duration the receiver will be in Rx mode, in microseconds.
\param sleepPeriod The duration the receiver will not be in Rx mode, in microseconds.
\returns \ref status_codes
*/
int16_t startReceiveDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod);
/*!
\brief Calls \ref startReceiveDutyCycle with rxPeriod and sleepPeriod set so the unit shouldn't miss any messages.
\param senderPreambleLength Expected preamble length of the messages to receive.
If set to zero, the currently configured preamble length will be used. Defaults to zero.
\param minSymbols Parameters will be chosen to ensure that the unit will catch at least this many symbols of any preamble of the specified length. Defaults to 8.
According to Semtech, receiver requires 8 symbols to reliably latch a preamble. This makes this method redundant when transmitter preamble length is less than 17 (2*minSymbols + 1).
\returns \ref status_codes
*/
int16_t startReceiveDutyCycleAuto(uint16_t senderPreambleLength = 0, uint16_t minSymbols = 8);
/*!
\brief Reads data received after calling startReceive method.
@ -547,9 +591,11 @@ class SX126x: public PhysicalLayer {
\param syncWord LoRa sync word to be set.
\param controlBits Undocumented control bits, required for compatibility purposes.
\returns \ref status_codes
*/
int16_t setSyncWord(uint16_t syncWord);
int16_t setSyncWord(uint8_t syncWord, uint8_t controlBits = 0x44);
/*!
\brief Sets current protection limit. Can be set in 0.25 mA steps.
@ -560,6 +606,13 @@ class SX126x: public PhysicalLayer {
*/
int16_t setCurrentLimit(float currentLimit);
/*!
\brief Reads current protection limit.
\returns Currently configured overcurrent protection limit in mA.
*/
float getCurrentLimit();
/*!
\brief Sets preamble length for LoRa or FSK modem. Allowed values range from 1 to 65535.
@ -751,6 +804,45 @@ class SX126x: public PhysicalLayer {
*/
uint32_t getTimeOnAir(size_t len);
/*!
\brief Set implicit header mode for future reception/transmission.
\returns \ref status_codes
*/
int16_t implicitHeader(size_t len);
/*!
\brief Set explicit header mode for future reception/transmission.
\param len Payload length in bytes.
\returns \ref status_codes
*/
int16_t explicitHeader();
/*!
\brief Set regulator mode to LDO.
\returns \ref status_codes
*/
int16_t setRegulatorLDO();
/*!
\brief Set regulator mode to DC-DC.
\returns \ref status_codes
*/
int16_t setRegulatorDCDC();
/*!
\brief Sets transmission encoding. Available in FSK mode only. Serves only as alias for PhysicalLayer compatibility.
\param encoding Encoding to be used. Set to 0 for NRZ, and 2 for whitening.
\returns \ref status_codes
*/
int16_t setEncoding(uint8_t encoding);
#ifndef RADIOLIB_GODMODE
protected:
#endif
@ -772,17 +864,19 @@ class SX126x: public PhysicalLayer {
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);
int16_t setModulationParamsFSK(uint32_t br, uint8_t pulseShape, uint8_t rxBw, uint32_t freqDev);
int16_t setPacketParams(uint16_t preambleLength, uint8_t crcType, uint8_t payloadLength = 0xFF, uint8_t headerType = SX126X_LORA_HEADER_EXPLICIT, uint8_t invertIQ = SX126X_LORA_IQ_STANDARD);
int16_t setPacketParams(uint16_t preambleLength, uint8_t crcType, uint8_t payloadLength, uint8_t headerType, uint8_t invertIQ = SX126X_LORA_IQ_STANDARD);
int16_t setPacketParamsFSK(uint16_t preambleLength, uint8_t crcType, uint8_t syncWordLength, uint8_t addrComp, uint8_t whitening, uint8_t packetType = SX126X_GFSK_PACKET_VARIABLE, uint8_t payloadLength = 0xFF, uint8_t preambleDetectorLength = SX126X_GFSK_PREAMBLE_DETECT_16);
int16_t setBufferBaseAddress(uint8_t txBaseAddress = 0x00, uint8_t rxBaseAddress = 0x00);
int16_t setRegulatorMode(uint8_t mode);
uint8_t getStatus();
uint32_t getPacketStatus();
uint16_t getDeviceErrors();
int16_t clearDeviceErrors();
int16_t startReceiveCommon();
int16_t setFrequencyRaw(float freq);
int16_t setOptimalHiPowerPaConfig(int8_t* inOutPower);
int16_t setPacketMode(uint8_t mode, uint8_t len);
int16_t setHeaderType(uint8_t headerType, size_t len = 0xFF);
// fixes to errata
int16_t fixSensitivity();
@ -795,7 +889,7 @@ class SX126x: public PhysicalLayer {
#endif
Module* _mod;
uint8_t _bw, _sf, _cr, _ldro, _crcType;
uint8_t _bw, _sf, _cr, _ldro, _crcType, _headerType;
uint16_t _preambleLength;
float _bwKhz;
@ -806,6 +900,10 @@ class SX126x: public PhysicalLayer {
float _dataRate;
uint32_t _tcxoDelay;
size_t _implicitLen;
int16_t config(uint8_t modem);
// common low-level SPI interface

View file

@ -7,53 +7,34 @@ SX1272::SX1272(Module* mod) : SX127x(mod) {
int16_t SX1272::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint8_t currentLimit, uint16_t preambleLength, uint8_t gain) {
// execute common part
int16_t state = SX127x::begin(SX1272_CHIP_VERSION, syncWord, currentLimit, preambleLength);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure settings not accessible by API
state = config();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// mitigation of receiver spurious response
// see SX1272/73 Errata, section 2.2 for details
state = _mod->SPIsetRegValue(0x31, 0b10000000, 7, 7);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setFrequency(freq);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setBandwidth(bw);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setSpreadingFactor(sf);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setCodingRate(cr);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setOutputPower(power);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setGain(gain);
if(state != ERR_NONE) {
return(state);
}
return(state);
}
@ -61,26 +42,17 @@ int16_t SX1272::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync
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, preambleLength, enableOOK);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure settings not accessible by API
state = configFSK();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setFrequency(freq);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setOutputPower(power);
if(state != ERR_NONE) {
return(state);
}
return(state);
}
@ -326,13 +298,13 @@ int16_t SX1272::setDataShapingOOK(uint8_t sh) {
// set data shaping
switch(sh) {
case 0:
state |= _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1272_NO_SHAPING, 4, 3);
state |= _mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX1272_NO_SHAPING, 4, 3);
break;
case 1:
state |= _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1272_OOK_FILTER_BR, 4, 3);
state |= _mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX1272_OOK_FILTER_BR, 4, 3);
break;
case 2:
state |= _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1272_OOK_FILTER_2BR, 4, 3);
state |= _mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX1272_OOK_FILTER_2BR, 4, 3);
break;
default:
state = ERR_INVALID_DATA_SHAPING;
@ -429,9 +401,7 @@ int16_t SX1272::setCodingRateRaw(uint8_t newCodingRate) {
int16_t SX1272::configFSK() {
// configure common registers
int16_t state = SX127x::configFSK();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set fast PLL hop
state = _mod->SPIsetRegValue(SX1272_REG_PLL_HOP, SX127X_FAST_HOP_ON, 7, 7);

View file

@ -1,66 +1,47 @@
#include "SX1273.h"
SX1273::SX1273(Module* mod) : SX1272(mod) {
}
int16_t SX1273::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint8_t currentLimit, uint16_t preambleLength, uint8_t gain) {
// execute common part
int16_t state = SX127x::begin(SX1272_CHIP_VERSION, syncWord, currentLimit, preambleLength);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure settings not accessible by API
state = config();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// mitigation of receiver spurious response
// see SX1272/73 Errata, section 2.2 for details
state = _mod->SPIsetRegValue(0x31, 0b10000000, 7, 7);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setFrequency(freq);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setBandwidth(bw);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setSpreadingFactor(sf);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setCodingRate(cr);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setOutputPower(power);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setGain(gain);
if(state != ERR_NONE) {
return(state);
}
return(state);
}
int16_t SX1273::setSpreadingFactor(uint8_t sf) {
uint8_t newSpreadingFactor;
// check allowed spreading factor values
switch(sf) {
case 6:
@ -78,12 +59,12 @@ int16_t SX1273::setSpreadingFactor(uint8_t sf) {
default:
return(ERR_INVALID_SPREADING_FACTOR);
}
// set spreading factor and if successful, save the new setting
int16_t state = setSpreadingFactorRaw(newSpreadingFactor);
if(state == ERR_NONE) {
SX127x::_sf = sf;
}
return(state);
}

View file

@ -1,53 +1,36 @@
#include "SX1276.h"
SX1276::SX1276(Module* mod) : SX1278(mod) {
}
int16_t SX1276::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint8_t currentLimit, uint16_t preambleLength, uint8_t gain) {
// execute common part
int16_t state = SX127x::begin(SX1278_CHIP_VERSION, syncWord, currentLimit, preambleLength);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure settings not accessible by API
state = config();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setFrequency(freq);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setBandwidth(bw);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setSpreadingFactor(sf);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setCodingRate(cr);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setOutputPower(power);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setGain(gain);
if(state != ERR_NONE) {
return(state);
}
return(state);
}
@ -56,7 +39,7 @@ int16_t SX1276::setFrequency(float freq) {
if((freq < 137.0) || (freq > 1020.0)) {
return(ERR_INVALID_FREQUENCY);
}
// SX1276/77/78 Errata fixes
if(getActiveModem() == SX127X_LORA) {
// sensitivity optimization for 500kHz bandwidth
@ -70,7 +53,7 @@ int16_t SX1276::setFrequency(float freq) {
_mod->SPIwriteRegister(0x3a, 0x7F);
}
}
// mitigation of receiver spurious response
// see SX1276/77/78 Errata, section 2.3 for details
if(abs(_bw - 7.8) <= 0.001) {
@ -119,7 +102,7 @@ int16_t SX1276::setFrequency(float freq) {
_mod->SPIsetRegValue(0x31, 0b1000000, 7, 7);
}
}
// set frequency
return(SX127x::setFrequencyRaw(freq));
}

View file

@ -1,53 +1,36 @@
#include "SX1277.h"
SX1277::SX1277(Module* mod) : SX1278(mod) {
}
int16_t SX1277::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint8_t currentLimit, uint16_t preambleLength, uint8_t gain) {
// execute common part
int16_t state = SX127x::begin(SX1278_CHIP_VERSION, syncWord, currentLimit, preambleLength);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure settings not accessible by API
state = config();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setFrequency(freq);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setBandwidth(bw);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setSpreadingFactor(sf);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setCodingRate(cr);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setOutputPower(power);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setGain(gain);
if(state != ERR_NONE) {
return(state);
}
return(state);
}
@ -56,7 +39,7 @@ int16_t SX1277::setFrequency(float freq) {
if((freq < 137.0) || (freq > 1020.0)) {
return(ERR_INVALID_FREQUENCY);
}
// SX1276/77/78 Errata fixes
if(getActiveModem() == SX127X_LORA) {
// sensitivity optimization for 500kHz bandwidth
@ -70,7 +53,7 @@ int16_t SX1277::setFrequency(float freq) {
_mod->SPIwriteRegister(0x3a, 0x7F);
}
}
// mitigation of receiver spurious response
// see SX1276/77/78 Errata, section 2.3 for details
if(abs(_bw - 7.8) <= 0.001) {
@ -119,14 +102,14 @@ int16_t SX1277::setFrequency(float freq) {
_mod->SPIsetRegValue(0x31, 0b1000000, 7, 7);
}
}
// set frequency and if successful, save the new setting
return(SX127x::setFrequencyRaw(freq));
}
int16_t SX1277::setSpreadingFactor(uint8_t sf) {
uint8_t newSpreadingFactor;
// check allowed spreading factor values
switch(sf) {
case 6:
@ -144,12 +127,12 @@ int16_t SX1277::setSpreadingFactor(uint8_t sf) {
default:
return(ERR_INVALID_SPREADING_FACTOR);
}
// set spreading factor and if successful, save the new setting
int16_t state = SX1278::setSpreadingFactorRaw(newSpreadingFactor);
if(state == ERR_NONE) {
SX127x::_sf = sf;
}
return(state);
}

View file

@ -7,46 +7,29 @@ SX1278::SX1278(Module* mod) : SX127x(mod) {
int16_t SX1278::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint8_t currentLimit, uint16_t preambleLength, uint8_t gain) {
// execute common part
int16_t state = SX127x::begin(SX1278_CHIP_VERSION, syncWord, currentLimit, preambleLength);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure settings not accessible by API
state = config();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setFrequency(freq);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setBandwidth(bw);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setSpreadingFactor(sf);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setCodingRate(cr);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setOutputPower(power);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setGain(gain);
if(state != ERR_NONE) {
return(state);
}
return(state);
}
@ -54,26 +37,17 @@ int16_t SX1278::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync
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, preambleLength, enableOOK);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure settings not accessible by API
state = configFSK();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setFrequency(freq);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setOutputPower(power);
if(state != ERR_NONE) {
return(state);
}
return(state);
}
@ -505,9 +479,7 @@ int16_t SX1278::setCodingRateRaw(uint8_t newCodingRate) {
int16_t SX1278::configFSK() {
// configure common registers
int16_t state = SX127x::configFSK();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set fast PLL hop
state = _mod->SPIsetRegValue(SX1278_REG_PLL_HOP, SX127X_FAST_HOP_ON, 7, 7);

View file

@ -1,53 +1,36 @@
#include "SX1279.h"
SX1279::SX1279(Module* mod) : SX1278(mod) {
}
int16_t SX1279::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint8_t currentLimit, uint16_t preambleLength, uint8_t gain) {
// execute common part
int16_t state = SX127x::begin(SX1278_CHIP_VERSION, syncWord, currentLimit, preambleLength);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure settings not accessible by API
state = config();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setFrequency(freq);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setBandwidth(bw);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setSpreadingFactor(sf);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setCodingRate(cr);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setOutputPower(power);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
state = setGain(gain);
if(state != ERR_NONE) {
return(state);
}
return(state);
}
@ -56,7 +39,7 @@ int16_t SX1279::setFrequency(float freq) {
if((freq < 137.0) || (freq > 960.0)) {
return(ERR_INVALID_FREQUENCY);
}
// set frequency
return(SX127x::setFrequencyRaw(freq));
}

View file

@ -1,13 +1,15 @@
#include "SX127x.h"
SX127x::SX127x(Module* mod) : PhysicalLayer(SX127X_CRYSTAL_FREQ, SX127X_DIV_EXPONENT, SX127X_MAX_PACKET_LENGTH) {
SX127x::SX127x(Module* mod) : PhysicalLayer(SX127X_FREQUENCY_STEP_SIZE, SX127X_MAX_PACKET_LENGTH) {
_mod = mod;
_packetLengthQueried = false;
}
int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint8_t currentLimit, uint16_t preambleLength) {
// set module properties
_mod->init(RADIOLIB_USE_SPI, RADIOLIB_INT_BOTH);
_mod->init(RADIOLIB_USE_SPI);
Module::pinMode(_mod->getIrq(), INPUT);
Module::pinMode(_mod->getGpio(), INPUT);
// try to find the SX127x chip
if(!SX127x::findChip(chipVersion)) {
@ -18,33 +20,28 @@ int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint8_t currentLimi
RADIOLIB_DEBUG_PRINTLN(F("Found SX127x!"));
}
// set mode to standby
int16_t state = standby();
RADIOLIB_ASSERT(state);
// check active modem
int16_t state;
if(getActiveModem() != SX127X_LORA) {
// set LoRa mode
state = setActiveModem(SX127X_LORA);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
}
// set LoRa sync word
state = SX127x::setSyncWord(syncWord);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set over current protection
state = SX127x::setCurrentLimit(currentLimit);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set preamble length
state = SX127x::setPreambleLength(preambleLength);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// initalize internal variables
_dataRate = 0.0;
@ -54,7 +51,11 @@ int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint8_t currentLimi
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(RADIOLIB_USE_SPI, RADIOLIB_INT_BOTH);
_mod->init(RADIOLIB_USE_SPI);
Module::pinMode(_mod->getIrq(), INPUT);
// reset the module
reset();
// try to find the SX127x chip
if(!SX127x::findChip(chipVersion)) {
@ -70,81 +71,64 @@ int16_t SX127x::beginFSK(uint8_t chipVersion, float br, float freqDev, float rxB
if(getActiveModem() != SX127X_FSK_OOK) {
// set FSK mode
state = setActiveModem(SX127X_FSK_OOK);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
}
// set bit rate
state = SX127x::setBitRate(br);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set frequency deviation
state = SX127x::setFrequencyDeviation(freqDev);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set receiver bandwidth
state = SX127x::setRxBandwidth(rxBw);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set over current protection
state = SX127x::setCurrentLimit(currentLimit);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set preamble length
state = SX127x::setPreambleLength(preambleLength);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(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);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// disable address filtering
state = disableAddressFiltering();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// enable/disable OOK
state = setOOK(enableOOK);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set default RSSI measurement config
state = setRSSIConfig(2);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set default encoding
state = setEncoding(0);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set default packet length mode
state = variablePacketLengthMode();
if (state != ERR_NONE) {
return(state);
}
return(state);
}
void SX127x::reset() {
Module::pinMode(_mod->getRst(), OUTPUT);
Module::digitalWrite(_mod->getRst(), LOW);
delayMicroseconds(100);
Module::digitalWrite(_mod->getRst(), HIGH);
delay(5);
}
int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) {
// set mode to standby
int16_t state = setMode(SX127X_STANDBY);
@ -166,13 +150,11 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) {
// start transmission
state = startTransmit(data, len, addr);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// wait for packet transmission or timeout
start = micros();
while(!digitalRead(_mod->getInt0())) {
while(!digitalRead(_mod->getIrq())) {
if(micros() - start > timeout) {
clearIRQFlags();
return(ERR_TX_TIMEOUT);
@ -185,13 +167,11 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) {
// start transmission
state = startTransmit(data, len, addr);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// wait for transmission end or timeout
start = micros();
while(!digitalRead(_mod->getInt0())) {
while(!digitalRead(_mod->getIrq())) {
if(micros() - start > timeout) {
clearIRQFlags();
standby();
@ -221,13 +201,11 @@ int16_t SX127x::receive(uint8_t* data, size_t len) {
if(modem == SX127X_LORA) {
// set mode to receive
state = startReceive(len, SX127X_RXSINGLE);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// wait for packet reception or timeout (100 LoRa symbols)
while(!digitalRead(_mod->getInt0())) {
if(digitalRead(_mod->getInt1())) {
while(!digitalRead(_mod->getIrq())) {
if(digitalRead(_mod->getGpio())) {
clearIRQFlags();
return(ERR_RX_TIMEOUT);
}
@ -239,13 +217,11 @@ int16_t SX127x::receive(uint8_t* data, size_t len) {
// set mode to receive
state = startReceive(len, SX127X_RX);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// wait for packet reception or timeout
uint32_t start = micros();
while(!digitalRead(_mod->getInt0())) {
while(!digitalRead(_mod->getIrq())) {
if(micros() - start > timeout) {
clearIRQFlags();
return(ERR_RX_TIMEOUT);
@ -267,22 +243,22 @@ int16_t SX127x::scanChannel() {
// set mode to standby
int16_t state = setMode(SX127X_STANDBY);
RADIOLIB_ASSERT(state);
// set DIO pin mapping
state |= _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_CAD_DONE | SX127X_DIO1_CAD_DETECTED, 7, 4);
state = _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_CAD_DONE | SX127X_DIO1_CAD_DETECTED, 7, 4);
RADIOLIB_ASSERT(state);
// clear interrupt flags
clearIRQFlags();
// set mode to CAD
state |= setMode(SX127X_CAD);
if(state != ERR_NONE) {
return(state);
}
state = setMode(SX127X_CAD);
RADIOLIB_ASSERT(state);
// wait for channel activity detected or timeout
while(!digitalRead(_mod->getInt0())) {
if(digitalRead(_mod->getInt1())) {
while(!digitalRead(_mod->getIrq())) {
if(digitalRead(_mod->getGpio())) {
clearIRQFlags();
return(PREAMBLE_DETECTED);
}
@ -321,9 +297,7 @@ int16_t SX127x::transmitDirect(uint32_t FRF) {
// activate direct mode
int16_t state = directMode();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// start transmitting
return(setMode(SX127X_TX));
@ -337,9 +311,7 @@ int16_t SX127x::receiveDirect() {
// activate direct mode
int16_t state = directMode();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// start receiving
return(setMode(SX127X_RX));
@ -348,16 +320,14 @@ int16_t SX127x::receiveDirect() {
int16_t SX127x::directMode() {
// set mode to standby
int16_t state = setMode(SX127X_STANDBY);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set DIO mapping
state = _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO1_CONT_DCLK | SX127X_DIO2_CONT_DATA, 5, 2);
RADIOLIB_ASSERT(state);
// set continuous mode
state |= _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_2, SX127X_DATA_MODE_CONTINUOUS, 6, 6);
return(state);
return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_2, SX127X_DATA_MODE_CONTINUOUS, 6, 6));
}
int16_t SX127x::packetMode() {
@ -389,9 +359,7 @@ int16_t SX127x::startReceive(uint8_t len, uint8_t mode) {
// set FIFO pointers
state |= _mod->SPIsetRegValue(SX127X_REG_FIFO_RX_BASE_ADDR, SX127X_FIFO_RX_BASE_ADDR_MAX);
state |= _mod->SPIsetRegValue(SX127X_REG_FIFO_ADDR_PTR, SX127X_FIFO_RX_BASE_ADDR_MAX);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
} else if(modem == SX127X_FSK_OOK) {
// set DIO pin mapping
@ -411,11 +379,25 @@ int16_t SX127x::startReceive(uint8_t len, uint8_t mode) {
}
void SX127x::setDio0Action(void (*func)(void)) {
attachInterrupt(digitalPinToInterrupt(_mod->getInt0()), func, RISING);
attachInterrupt(digitalPinToInterrupt(_mod->getIrq()), func, RISING);
}
void SX127x::clearDio0Action() {
detachInterrupt(digitalPinToInterrupt(_mod->getIrq()));
}
void SX127x::setDio1Action(void (*func)(void)) {
attachInterrupt(digitalPinToInterrupt(_mod->getInt1()), func, RISING);
if(_mod->getGpio() != NC) {
return;
}
attachInterrupt(digitalPinToInterrupt(_mod->getGpio()), func, RISING);
}
void SX127x::clearDio1Action() {
if(_mod->getGpio() != NC) {
return;
}
detachInterrupt(digitalPinToInterrupt(_mod->getGpio()));
}
int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
@ -447,9 +429,7 @@ int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
// start transmission
state |= setMode(SX127X_TX);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
return(ERR_NONE);
@ -479,9 +459,7 @@ int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
// start transmission
state |= setMode(SX127X_TX);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
return(ERR_NONE);
}
@ -579,9 +557,7 @@ int16_t SX127x::setCurrentLimit(uint8_t currentLimit) {
int16_t SX127x::setPreambleLength(uint16_t preambleLength) {
// set mode to standby
int16_t state = setMode(SX127X_STANDBY);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// check active modem
uint8_t modem = getActiveModem();
@ -693,9 +669,7 @@ int16_t SX127x::setBitRate(float br) {
// set mode to STANDBY
int16_t state = setMode(SX127X_STANDBY);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set bit rate
uint16_t bitRate = (SX127X_CRYSTAL_FREQ * 1000.0) / br;
@ -722,9 +696,7 @@ int16_t SX127x::setFrequencyDeviation(float freqDev) {
// set mode to STANDBY
int16_t state = setMode(SX127X_STANDBY);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set allowed frequency deviation
uint32_t base = 1;
@ -747,9 +719,7 @@ int16_t SX127x::setRxBandwidth(float rxBw) {
// set mode to STANDBY
int16_t state = setMode(SX127X_STANDBY);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// calculate exponent and mantissa values
for(uint8_t e = 7; e >= 1; e--) {
@ -758,9 +728,7 @@ int16_t SX127x::setRxBandwidth(float rxBw) {
if(abs(rxBw - ((point / 1000.0) + 0.05)) <= 0.5) {
// set Rx bandwidth during AFC
state = _mod->SPIsetRegValue(SX127X_REG_AFC_BW, (m << 3) | e, 4, 0);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set Rx bandwidth
state = _mod->SPIsetRegValue(SX127X_REG_RX_BW, (m << 3) | e, 4, 0);
@ -796,9 +764,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 - 1, 2, 0);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set sync word
_mod->SPIwriteRegisterBurst(SX127X_REG_SYNC_VALUE_1, syncWord, len);
@ -813,9 +779,7 @@ int16_t SX127x::setNodeAddress(uint8_t nodeAddr) {
// enable address filtering (node only)
int16_t state = _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_ADDRESS_FILTERING_NODE, 2, 1);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set node address
return(_mod->SPIsetRegValue(SX127X_REG_NODE_ADRS, nodeAddr));
@ -829,9 +793,7 @@ int16_t SX127x::setBroadcastAddress(uint8_t broadAddr) {
// enable address filtering (node + broadcast)
int16_t state = _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_ADDRESS_FILTERING_NODE_BROADCAST, 2, 1);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set broadcast address
return(_mod->SPIsetRegValue(SX127X_REG_BROADCAST_ADRS, broadAddr));
@ -845,15 +807,11 @@ int16_t SX127x::disableAddressFiltering() {
// disable address filtering
int16_t state = _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_ADDRESS_FILTERING_OFF, 2, 1);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set node address to default (0x00)
state = _mod->SPIsetRegValue(SX127X_REG_NODE_ADRS, 0x00);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set broadcast address to default (0x00)
return(_mod->SPIsetRegValue(SX127X_REG_BROADCAST_ADRS, 0x00));
@ -933,9 +891,7 @@ int16_t SX127x::setRSSIConfig(uint8_t smoothingSamples, int8_t offset) {
// set mode to standby
int16_t state = standby();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// check provided values
if(!(smoothingSamples <= 7)) {
@ -980,9 +936,7 @@ int16_t SX127x::config() {
int16_t SX127x::configFSK() {
// set RSSI threshold
int16_t state = _mod->SPIsetRegValue(SX127X_REG_RSSI_THRESH, SX127X_RSSI_THRESHOLD);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// reset FIFO flag
_mod->SPIwriteRegister(SX127X_REG_IRQ_FLAGS_2, SX127X_FLAG_FIFO_OVERRUN);
@ -990,38 +944,27 @@ int16_t SX127x::configFSK() {
// set packet configuration
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);
}
RADIOLIB_ASSERT(state);
// set preamble polarity
state =_mod->SPIsetRegValue(SX127X_REG_SYNC_CONFIG, SX127X_PREAMBLE_POLARITY_55, 5, 5);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(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);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// disable Rx timeouts
state = _mod->SPIsetRegValue(SX127X_REG_RX_TIMEOUT_1, SX127X_TIMEOUT_RX_RSSI_OFF);
state |= _mod->SPIsetRegValue(SX127X_REG_RX_TIMEOUT_2, SX127X_TIMEOUT_RX_PREAMBLE_OFF);
state |= _mod->SPIsetRegValue(SX127X_REG_RX_TIMEOUT_3, SX127X_TIMEOUT_SIGNAL_SYNC_OFF);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// enable preamble detector and set preamble length
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) {
return(state);
}
return(state);
}
@ -1039,15 +982,11 @@ int16_t SX127x::setPacketMode(uint8_t mode, uint8_t len) {
// set to fixed packet length
int16_t state = _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, mode, 7, 7);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set length to register
state = _mod->SPIsetRegValue(SX127X_REG_PAYLOAD_LENGTH_FSK, len);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// update cached value
_packetLengthConfig = mode;
@ -1058,6 +997,10 @@ bool SX127x::findChip(uint8_t ver) {
uint8_t i = 0;
bool flagFound = false;
while((i < 10) && !flagFound) {
// reset the module
reset();
// check version register
uint8_t version = _mod->SPIreadRegister(SX127X_REG_VERSION);
if(version == ver) {
flagFound = true;

View file

@ -7,10 +7,11 @@
#include "../../protocols/PhysicalLayer/PhysicalLayer.h"
// SX127x physical layer properties
#define SX127X_CRYSTAL_FREQ 32.0
#define SX127X_DIV_EXPONENT 19
#define SX127X_FREQUENCY_STEP_SIZE 61.03515625
#define SX127X_MAX_PACKET_LENGTH 255
#define SX127X_MAX_PACKET_LENGTH_FSK 64
#define SX127X_CRYSTAL_FREQ 32.0
#define SX127X_DIV_EXPONENT 19
// SX127x series common LoRa registers
#define SX127X_REG_FIFO 0x00
@ -563,6 +564,11 @@ class SX127x: public PhysicalLayer {
*/
int16_t begin(uint8_t chipVersion, uint8_t syncWord, uint8_t currentLimit, uint16_t preambleLength);
/*!
\brief Reset method. Will reset the chip to the default state using RST pin.
*/
void reset();
/*!
\brief Initialization method for FSK modem. Will be called with appropriate parameters when calling FSK initialization method from derived class.
@ -667,6 +673,11 @@ class SX127x: public PhysicalLayer {
*/
void setDio0Action(void (*func)(void));
/*!
\brief Clears interrupt service routine to call when DIO0 activates.
*/
void clearDio0Action();
/*!
\brief Set interrupt service routine function to call when DIO1 activates.
@ -674,6 +685,11 @@ class SX127x: public PhysicalLayer {
*/
void setDio1Action(void (*func)(void));
/*!
\brief Clears interrupt service routine to call when DIO1 activates.
*/
void clearDio1Action();
/*!
\brief Interrupt-driven binary transmit method. Will start transmitting arbitrary binary data up to 255 bytes long using %LoRa or up to 63 bytes using FSK modem.

View file

@ -10,7 +10,7 @@ XBee::XBee(Module* mod) {
int16_t XBee::begin(long speed) {
// set module properties
_mod->baudrate = speed;
_mod->init(RADIOLIB_USE_UART, RADIOLIB_INT_1);
_mod->init(RADIOLIB_USE_UART);
// reset module
reset();
@ -52,11 +52,10 @@ int16_t XBee::begin(long speed) {
}
void XBee::reset() {
pinMode(_mod->getInt1(), OUTPUT);
digitalWrite(_mod->getInt1(), LOW);
pinMode(_mod->getRst(), OUTPUT);
digitalWrite(_mod->getRst(), LOW);
delayMicroseconds(200);
digitalWrite(_mod->getInt1(), HIGH);
pinMode(_mod->getInt1(), INPUT);
digitalWrite(_mod->getRst(), HIGH);
}
int16_t XBee::transmit(uint8_t* dest, const char* payload, uint8_t radius) {
@ -173,9 +172,7 @@ int16_t XBee::setPanId(uint8_t* panId) {
// get response code
int16_t state = readApiFrame(frameID, 4);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// confirm changes
return(confirmChanges());
@ -189,7 +186,10 @@ int16_t XBeeSerial::begin(long speed) {
// set module properties
_mod->AtLineFeed = "\r";
_mod->baudrate = speed;
_mod->init(RADIOLIB_USE_UART, RADIOLIB_INT_NONE);
_mod->init(RADIOLIB_USE_UART);
// reset module
reset();
// empty UART buffer (garbage data)
_mod->ATemptyBuffer();
@ -216,11 +216,11 @@ int16_t XBeeSerial::begin(long speed) {
}
void XBeeSerial::reset() {
pinMode(_mod->getInt1(), OUTPUT);
digitalWrite(_mod->getInt1(), LOW);
pinMode(_mod->getRst(), OUTPUT);
digitalWrite(_mod->getRst(), LOW);
delayMicroseconds(200);
digitalWrite(_mod->getInt1(), HIGH);
pinMode(_mod->getInt1(), INPUT);
digitalWrite(_mod->getRst(), HIGH);
pinMode(_mod->getRst(), INPUT);
}
int16_t XBeeSerial::setDestinationAddress(const char* destinationAddressHigh, const char* destinationAddressLow) {
@ -340,9 +340,7 @@ int16_t XBee::confirmChanges() {
// get response code
int16_t state = readApiFrame(frameID, 4);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// apply changes
frameID = _frameID++;
@ -350,9 +348,6 @@ int16_t XBee::confirmChanges() {
// get response code
state = readApiFrame(frameID, 4);
if(state != ERR_NONE) {
return(state);
}
return(state);
}

View file

@ -1,6 +1,6 @@
#include "nRF24.h"
nRF24::nRF24(Module* mod) : PhysicalLayer(NRF24_CRYSTAL_FREQ, NRF24_DIV_EXPONENT, NRF24_MAX_PACKET_LENGTH) {
nRF24::nRF24(Module* mod) : PhysicalLayer(NRF24_FREQUENCY_STEP_SIZE, NRF24_MAX_PACKET_LENGTH) {
_mod = mod;
}
@ -8,18 +8,18 @@ int16_t nRF24::begin(int16_t freq, int16_t dataRate, int8_t power, uint8_t addrW
// set module properties
_mod->SPIreadCommand = NRF24_CMD_READ;
_mod->SPIwriteCommand = NRF24_CMD_WRITE;
_mod->init(RADIOLIB_USE_SPI, RADIOLIB_INT_BOTH);
_mod->init(RADIOLIB_USE_SPI);
// override pin mode on INT0 (connected to nRF24 CE pin)
pinMode(_mod->getInt0(), OUTPUT);
digitalWrite(_mod->getInt0(), LOW);
// set pin mode on RST (connected to nRF24 CE pin)
Module::pinMode(_mod->getRst(), OUTPUT);
Module::digitalWrite(_mod->getRst(), LOW);
// wait for minimum power-on reset duration
delay(100);
// check SPI connection
int16_t val = _mod->SPIgetRegValue(NRF24_REG_SETUP_AW);
if(!((val >= 1) && (val <= 3))) {
if(!((val >= 0) && (val <= 3))) {
RADIOLIB_DEBUG_PRINTLN(F("No nRF24 found!"));
_mod->term();
return(ERR_CHIP_NOT_FOUND);
@ -27,39 +27,25 @@ int16_t nRF24::begin(int16_t freq, int16_t dataRate, int8_t power, uint8_t addrW
// configure settings inaccessible by public API
int16_t state = config();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set mode to standby
state = standby();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set frequency
state = setFrequency(freq);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set data rate
state = setDataRate(dataRate);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set output power
state = setOutputPower(power);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set address width
state = setAddressWidth(addrWidth);
if(state != ERR_NONE) {
return(state);
}
return(state);
}
@ -72,7 +58,7 @@ int16_t nRF24::standby() {
// make sure carrier output is disabled
_mod->SPIsetRegValue(NRF24_REG_RF_SETUP, NRF24_CONT_WAVE_OFF, 7, 7);
_mod->SPIsetRegValue(NRF24_REG_RF_SETUP, NRF24_PLL_LOCK_OFF, 4, 4);
digitalWrite(_mod->getInt0(), LOW);
digitalWrite(_mod->getRst(), LOW);
// use standby-1 mode
return(_mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_POWER_UP, 1, 1));
@ -81,13 +67,11 @@ int16_t nRF24::standby() {
int16_t nRF24::transmit(uint8_t* data, size_t len, uint8_t addr) {
// start transmission
int16_t state = startTransmit(data, len, addr);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// wait until transmission is finished
uint32_t start = micros();
while(digitalRead(_mod->getInt1())) {
while(digitalRead(_mod->getIrq())) {
// check maximum number of retransmits
if(getStatus(NRF24_MAX_RT)) {
standby();
@ -112,13 +96,11 @@ int16_t nRF24::transmit(uint8_t* data, size_t len, uint8_t addr) {
int16_t nRF24::receive(uint8_t* data, size_t len) {
// start reception
int16_t state = startReceive();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// wait for Rx_DataReady or timeout
uint32_t start = micros();
while(digitalRead(_mod->getInt1())) {
while(digitalRead(_mod->getIrq())) {
// check timeout: 15 retries * 4ms (max Tx time as per datasheet)
if(micros() - start >= 60000) {
standby();
@ -142,7 +124,7 @@ int16_t nRF24::transmitDirect(uint32_t frf) {
int16_t state = _mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_PTX, 0, 0);
state |= _mod->SPIsetRegValue(NRF24_REG_RF_SETUP, NRF24_CONT_WAVE_ON, 7, 7);
state |= _mod->SPIsetRegValue(NRF24_REG_RF_SETUP, NRF24_PLL_LOCK_ON, 4, 4);
digitalWrite(_mod->getInt0(), HIGH);
digitalWrite(_mod->getRst(), HIGH);
return(state);
}
@ -153,7 +135,7 @@ int16_t nRF24::receiveDirect() {
}
void nRF24::setIrqAction(void (*func)(void)) {
attachInterrupt(digitalPinToInterrupt(_mod->getInt1()), func, FALLING);
attachInterrupt(digitalPinToInterrupt(_mod->getIrq()), func, FALLING);
}
int16_t nRF24::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
@ -167,9 +149,7 @@ int16_t nRF24::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
// set mode to standby
int16_t state = standby();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// enable primary Tx mode
state = _mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_PTX, 0, 0);
@ -179,9 +159,7 @@ int16_t nRF24::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
// enable Tx_DataSent interrupt
state |= _mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_MASK_TX_DS_IRQ_ON, 5, 5);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// flush Tx FIFO
SPItransfer(NRF24_CMD_FLUSH_TX);
@ -193,9 +171,9 @@ int16_t nRF24::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
SPIwriteTxPayload(data, len);
// CE high to start transmitting
digitalWrite(_mod->getInt0(), HIGH);
digitalWrite(_mod->getRst(), HIGH);
delayMicroseconds(10);
digitalWrite(_mod->getInt0(), LOW);
digitalWrite(_mod->getRst(), LOW);
return(state);
}
@ -203,28 +181,22 @@ int16_t nRF24::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
int16_t nRF24::startReceive() {
// set mode to standby
int16_t state = standby();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// enable primary Rx mode
state = _mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_PRX, 0, 0);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// enable Rx_DataReady interrupt
clearIRQ();
state |= _mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_MASK_RX_DR_IRQ_ON, 6, 6);
if(state != ERR_NONE) {
return(state);
}
state = _mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_MASK_RX_DR_IRQ_ON, 6, 6);
RADIOLIB_ASSERT(state);
// flush Rx FIFO
SPItransfer(NRF24_CMD_FLUSH_RX);
// CE high to start receiving
digitalWrite(_mod->getInt0(), HIGH);
digitalWrite(_mod->getRst(), HIGH);
// wait to enter Rx state
delayMicroseconds(130);
@ -235,9 +207,7 @@ int16_t nRF24::startReceive() {
int16_t nRF24::readData(uint8_t* data, size_t len) {
// set mode to standby
int16_t state = standby();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// get packet length
size_t length = len;
@ -248,9 +218,6 @@ int16_t nRF24::readData(uint8_t* data, size_t len) {
// read packet data
SPIreadRxPayload(data, length);
// add terminating null
data[length] = 0;
// clear interrupt
clearIRQ();
@ -265,9 +232,7 @@ int16_t nRF24::setFrequency(int16_t freq) {
// set mode to standby
int16_t state = standby();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set frequency
uint8_t freqRaw = freq - 2400;
@ -278,9 +243,7 @@ int16_t nRF24::setFrequency(int16_t freq) {
int16_t nRF24::setDataRate(int16_t dataRate) {
// set mode to standby
int16_t state = standby();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set data rate
if(dataRate == 250) {
@ -302,9 +265,7 @@ int16_t nRF24::setDataRate(int16_t dataRate) {
int16_t nRF24::setOutputPower(int8_t power) {
// set mode to standby
int16_t state = standby();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// check allowed values
uint8_t powerRaw = 0;
@ -333,12 +294,15 @@ int16_t nRF24::setOutputPower(int8_t power) {
int16_t nRF24::setAddressWidth(uint8_t addrWidth) {
// set mode to standby
int16_t state = standby();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set address width
switch(addrWidth) {
case 2:
// Even if marked as 'Illegal' on the datasheet this will work:
// http://travisgoodspeed.blogspot.com/2011/02/promiscuity-is-nrf24l01s-duty.html
state = _mod->SPIsetRegValue(NRF24_REG_SETUP_AW, NRF24_ADDRESS_2_BYTES, 1, 0);
break;
case 3:
state = _mod->SPIsetRegValue(NRF24_REG_SETUP_AW, NRF24_ADDRESS_3_BYTES, 1, 0);
break;
@ -361,9 +325,7 @@ int16_t nRF24::setAddressWidth(uint8_t addrWidth) {
int16_t nRF24::setTransmitPipe(uint8_t* addr) {
// set mode to standby
int16_t state = standby();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set transmit address
_mod->SPIwriteRegisterBurst(NRF24_REG_TX_ADDR, addr, _addrWidth);
@ -377,9 +339,7 @@ int16_t nRF24::setTransmitPipe(uint8_t* addr) {
int16_t nRF24::setReceivePipe(uint8_t pipeNum, uint8_t* addr) {
// set mode to standby
int16_t state = standby();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// write full pipe 0 - 1 address and enable the pipe
switch(pipeNum) {
@ -401,9 +361,7 @@ int16_t nRF24::setReceivePipe(uint8_t pipeNum, uint8_t* addr) {
int16_t nRF24::setReceivePipe(uint8_t pipeNum, uint8_t addrByte) {
// set mode to standby
int16_t state = standby();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// write unique pipe 2 - 5 address and enable the pipe
switch(pipeNum) {
@ -433,9 +391,7 @@ int16_t nRF24::setReceivePipe(uint8_t pipeNum, uint8_t addrByte) {
int16_t nRF24::disablePipe(uint8_t pipeNum) {
// set mode to standby
int16_t state = standby();
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
switch(pipeNum) {
case 0:
@ -481,6 +437,53 @@ size_t nRF24::getPacketLength(bool update) {
return((size_t)length);
}
int16_t nRF24::setCrcFiltering(bool crcOn) {
return _mod->SPIsetRegValue(NRF24_REG_CONFIG, crcOn ? NRF24_CRC_ON : NRF24_CRC_OFF, 3, 3);
}
int16_t nRF24::setAutoAck(bool autoAckOn){
return _mod->SPIsetRegValue(NRF24_REG_EN_AA, autoAckOn ? NRF24_AA_ALL_ON : NRF24_AA_ALL_OFF, 5, 0);
}
int16_t nRF24::setAutoAck(uint8_t pipeNum, bool autoAckOn){
switch(pipeNum) {
case 0:
return _mod->SPIsetRegValue(NRF24_REG_EN_AA, autoAckOn ? NRF24_AA_P0_ON : NRF24_AA_P0_OFF, 0, 0);
break;
case 1:
return _mod->SPIsetRegValue(NRF24_REG_EN_AA, autoAckOn ? NRF24_AA_P1_ON : NRF24_AA_P1_OFF, 1, 1);
break;
case 2:
return _mod->SPIsetRegValue(NRF24_REG_EN_AA, autoAckOn ? NRF24_AA_P2_ON : NRF24_AA_P2_OFF, 2, 2);
break;
case 3:
return _mod->SPIsetRegValue(NRF24_REG_EN_AA, autoAckOn ? NRF24_AA_P3_ON : NRF24_AA_P3_OFF, 3, 3);
break;
case 4:
return _mod->SPIsetRegValue(NRF24_REG_EN_AA, autoAckOn ? NRF24_AA_P4_ON : NRF24_AA_P4_OFF, 4, 4);
break;
case 5:
return _mod->SPIsetRegValue(NRF24_REG_EN_AA, autoAckOn ? NRF24_AA_P5_ON : NRF24_AA_P5_OFF, 5, 5);
break;
default:
return (ERR_INVALID_PIPE_NUMBER);
}
}
int16_t nRF24::setDataShaping(float sh) {
// nRF24 is unable to set data shaping
// this method is implemented only for PhysicalLayer compatibility
(void)sh;
return(ERR_NONE);
}
int16_t nRF24::setEncoding(uint8_t encoding) {
// nRF24 is unable to set encoding
// this method is implemented only for PhysicalLayer compatibility
(void)encoding;
return(ERR_NONE);
}
void nRF24::clearIRQ() {
// clear status bits
_mod->SPIsetRegValue(NRF24_REG_STATUS, NRF24_RX_DR | NRF24_TX_DS | NRF24_MAX_RT, 6, 4);
@ -492,27 +495,18 @@ void nRF24::clearIRQ() {
int16_t nRF24::config() {
// enable 16-bit CRC
int16_t state = _mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_CRC_ON | NRF24_CRC_16, 3, 2);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// set 15 retries and delay 1500 (5*250) us
_mod->SPIsetRegValue(NRF24_REG_SETUP_RETR, (5 << 4) | 5);
if(state != ERR_NONE) {
return(state);
}
// set features: dynamic payload on, payload with ACK packets off, dynamic ACK off
state = _mod->SPIsetRegValue(NRF24_REG_FEATURE, NRF24_DPL_ON | NRF24_ACK_PAY_OFF | NRF24_DYN_ACK_OFF, 2, 0);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// enable dynamic payloads
state = _mod->SPIsetRegValue(NRF24_REG_DYNPD, NRF24_DPL_ALL_ON, 5, 0);
if(state != ERR_NONE) {
return(state);
}
RADIOLIB_ASSERT(state);
// reset IRQ
clearIRQ();

View file

@ -6,9 +6,8 @@
#include "../../protocols/PhysicalLayer/PhysicalLayer.h"
// nRF24 physical layer properties (dummy only)
#define NRF24_CRYSTAL_FREQ 1.0
#define NRF24_DIV_EXPONENT 0
// nRF24 physical layer properties
#define NRF24_FREQUENCY_STEP_SIZE 1000000.0
#define NRF24_MAX_PACKET_LENGTH 32
// nRF24 SPI commands
@ -69,6 +68,8 @@
#define NRF24_PRX 0b00000001 // 0 0 enable primary Rx
// NRF24_REG_EN_AA
#define NRF24_AA_ALL_OFF 0b00000000 // 5 0 auto-ACK on all pipes: disabled
#define NRF24_AA_ALL_ON 0b00111111 // 5 0 enabled (default)
#define NRF24_AA_P5_OFF 0b00000000 // 5 5 auto-ACK on pipe 5: disabled
#define NRF24_AA_P5_ON 0b00100000 // 5 5 enabled (default)
#define NRF24_AA_P4_OFF 0b00000000 // 4 4 auto-ACK on pipe 4: disabled
@ -97,7 +98,8 @@
#define NRF24_P0_ON 0b00000001 // 0 0 enabled (default)
// NRF24_REG_SETUP_AW
#define NRF24_ADDRESS_3_BYTES 0b00000001 // 1 0 address width: 3 bytes
#define NRF24_ADDRESS_2_BYTES 0b00000000 // 1 0 address width: 2 bytes
#define NRF24_ADDRESS_3_BYTES 0b00000001 // 1 0 3 bytes
#define NRF24_ADDRESS_4_BYTES 0b00000010 // 1 0 4 bytes
#define NRF24_ADDRESS_5_BYTES 0b00000011 // 1 0 5 bytes (default)
@ -408,6 +410,54 @@ class nRF24: public PhysicalLayer {
*/
size_t getPacketLength(bool update = true);
/*!
\brief Enable CRC filtering and generation.
\param crcOn Set or unset CRC check.
\returns \ref status_codes
*/
int16_t setCrcFiltering(bool crcOn = true);
/*!
\brief Enable or disable auto-acknowlede packets on all pipes
\param autoAckOn Enable (true) or disable (false) auto-acks.
\returns \ref status_codes
*/
int16_t setAutoAck(bool autoAckOn = true);
/*!
\brief Enable or disable auto-acknowlede packets on given pipe.
\param pipeNum Number of pipe to which enable / disable auto-acks.
\param autoAckOn Enable (true) or disable (false) auto-acks.
\returns \ref status_codes
*/
int16_t setAutoAck(uint8_t pipeNum, bool autoAckOn = true);
/*!
\brief Dummy data shaping configuration method, to ensure PhysicalLayer compatibility.
\param sh Ignored.
\returns \ref status_codes
*/
int16_t setDataShaping(float sh);
/*!
\brief Dummy encoding configuration method, to ensure PhysicalLayer compatibility.
\param sh Ignored.
\returns \ref status_codes
*/
int16_t setEncoding(uint8_t encoding);
#ifndef RADIOLIB_GODMODE
private:
#endif

382
src/protocols/AX25/AX25.cpp Normal file
View file

@ -0,0 +1,382 @@
#include "AX25.h"
AX25Frame::AX25Frame(const char* destCallsign, uint8_t destSSID, const char* srcCallsign, uint8_t srcSSID, uint8_t control)
: AX25Frame(destCallsign, destSSID, srcCallsign, srcSSID, control, 0, NULL, 0) {
}
AX25Frame::AX25Frame(const char* destCallsign, uint8_t destSSID, const char* srcCallsign, uint8_t srcSSID, uint8_t control, uint8_t protocolID, const char* info)
: AX25Frame(destCallsign, destSSID, srcCallsign, srcSSID, control, protocolID, (uint8_t*)info, strlen(info)) {
}
AX25Frame::AX25Frame(const char* destCallsign, uint8_t destSSID, const char* srcCallsign, uint8_t srcSSID, uint8_t control, uint8_t protocolID, uint8_t* info, uint16_t infoLen) {
// destination callsign/SSID
memcpy(this->destCallsign, destCallsign, strlen(destCallsign));
this->destCallsign[strlen(destCallsign)] = '\0';
this->destSSID = destSSID;
// source callsign/SSID
memcpy(this->srcCallsign, srcCallsign, strlen(srcCallsign));
this->srcCallsign[strlen(srcCallsign)] = '\0';
this->srcSSID = srcSSID;
// set repeaters
this->numRepeaters = 0;
#ifndef RADIOLIB_STATIC_ONLY
this->repeaterCallsigns = NULL;
this->repeaterSSIDs = NULL;
#endif
// control field
this->control = control;
// sequence numbers
this->rcvSeqNumber = 0;
this->sendSeqNumber = 0;
// PID field
this->protocolID = protocolID;
// info field
this->infoLen = infoLen;
if(infoLen > 0) {
#ifndef RADIOLIB_STATIC_ONLY
this->info = new uint8_t[infoLen];
#endif
memcpy(this->info, info, infoLen);
}
}
AX25Frame::~AX25Frame() {
#ifndef RADIOLIB_STATIC_ONLY
// deallocate info field
if(infoLen > 0) {
delete[] this->info;
}
// deallocate repeaters
if(this->numRepeaters > 0) {
for(uint8_t i = 0; i < this->numRepeaters; i++) {
delete[] this->repeaterCallsigns[i];
}
delete[] this->repeaterCallsigns;
delete[] this->repeaterSSIDs;
}
#endif
}
int16_t AX25Frame::setRepeaters(char** repeaterCallsigns, uint8_t* repeaterSSIDs, uint8_t numRepeaters) {
// check number of repeaters
if((numRepeaters < 1) || (numRepeaters > 8)) {
return(ERR_INVALID_NUM_REPEATERS);
}
// check repeater configuration
if(!(((repeaterCallsigns == NULL) && (repeaterSSIDs == NULL) && (numRepeaters == 0)) ||
((repeaterCallsigns != NULL) && (repeaterSSIDs != NULL) && (numRepeaters != 0)))) {
return(ERR_INVALID_NUM_REPEATERS);
}
for(uint16_t i = 0; i < numRepeaters; i++) {
if(strlen(repeaterCallsigns[i]) > AX25_MAX_CALLSIGN_LEN) {
return(ERR_INVALID_REPEATER_CALLSIGN);
}
}
// create buffers
#ifndef RADIOLIB_STATIC_ONLY
this->repeaterCallsigns = new char*[numRepeaters];
for(uint8_t i = 0; i < numRepeaters; i++) {
this->repeaterCallsigns[i] = new char[strlen(repeaterCallsigns[i])];
}
this->repeaterSSIDs = new uint8_t[numRepeaters];
#endif
// copy data
this->numRepeaters = numRepeaters;
for(uint8_t i = 0; i < numRepeaters; i++) {
memcpy(this->repeaterCallsigns[i], repeaterCallsigns[i], strlen(repeaterCallsigns[i]));
}
memcpy(this->repeaterSSIDs, repeaterSSIDs, numRepeaters);
return(ERR_NONE);
}
void AX25Frame::setRecvSequence(uint8_t seqNumber) {
this->rcvSeqNumber = seqNumber;
}
void AX25Frame::setSendSequence(uint8_t seqNumber) {
this->sendSeqNumber = seqNumber;
}
AX25Client::AX25Client(PhysicalLayer* phy) {
_phy = phy;
}
int16_t AX25Client::begin(const char* srcCallsign, uint8_t srcSSID, uint8_t preambleLen) {
// set source SSID
_srcSSID = srcSSID;
// check source callsign length (6 characters max)
if(strlen(srcCallsign) > AX25_MAX_CALLSIGN_LEN) {
return(ERR_INVALID_CALLSIGN);
}
// copy callsign
memcpy(_srcCallsign, srcCallsign, strlen(srcCallsign));
_srcCallsign[strlen(srcCallsign)] = '\0';
// save preamble length
_preambleLen = preambleLen;
// disable physical layer data shaping and set encoding to NRZ
int16_t state = _phy->setDataShaping(0.0);
RADIOLIB_ASSERT(state);
state = _phy->setEncoding(0);
return(state);
}
int16_t AX25Client::transmit(const char* str, const char* destCallsign, uint8_t destSSID) {
// create control field
uint8_t controlField = AX25_CONTROL_U_UNNUMBERED_INFORMATION | AX25_CONTROL_POLL_FINAL_DISABLED | AX25_CONTROL_UNNUMBERED_FRAME;
// build the frame
AX25Frame frame(destCallsign, destSSID, _srcCallsign, _srcSSID, controlField, AX25_PID_NO_LAYER_3, (uint8_t*)str, strlen(str));
// send Unnumbered Information frame
return(sendFrame(&frame));
}
int16_t AX25Client::sendFrame(AX25Frame* frame) {
// check destination callsign length (6 characters max)
if(strlen(frame->destCallsign) > AX25_MAX_CALLSIGN_LEN) {
return(ERR_INVALID_CALLSIGN);
}
// check repeater configuration
#ifndef RADIOLIB_STATIC_ONLY
if(!(((frame->repeaterCallsigns == NULL) && (frame->repeaterSSIDs == NULL) && (frame->numRepeaters == 0)) ||
((frame->repeaterCallsigns != NULL) && (frame->repeaterSSIDs != NULL) && (frame->numRepeaters != 0)))) {
return(ERR_INVALID_NUM_REPEATERS);
}
for(uint16_t i = 0; i < frame->numRepeaters; i++) {
if(strlen(frame->repeaterCallsigns[i]) > AX25_MAX_CALLSIGN_LEN) {
return(ERR_INVALID_REPEATER_CALLSIGN);
}
}
#endif
// calculate frame length without FCS (destination address, source address, repeater addresses, control, PID, info)
size_t frameBuffLen = ((2 + frame->numRepeaters)*(AX25_MAX_CALLSIGN_LEN + 1)) + 1 + 1 + frame->infoLen;
// create frame buffer without preamble, start or stop flags
#ifndef RADIOLIB_STATIC_ONLY
uint8_t* frameBuff = new uint8_t[frameBuffLen + 2];
#else
uint8_t frameBuff[RADIOLIB_STATIC_ARRAY_SIZE];
#endif
uint8_t* frameBuffPtr = frameBuff;
// set destination callsign - all address field bytes are shifted by one bit to make room for HDLC address extension bit
memset(frameBuffPtr, ' ' << 1, AX25_MAX_CALLSIGN_LEN);
for(uint8_t i = 0; i < strlen(frame->destCallsign); i++) {
*(frameBuffPtr + i) = frame->destCallsign[i] << 1;
}
frameBuffPtr += AX25_MAX_CALLSIGN_LEN;
// set destination SSID
*(frameBuffPtr++) = AX25_SSID_COMMAND_DEST | AX25_SSID_RESERVED_BITS | (frame->destSSID & 0x0F) << 1 | AX25_SSID_HDLC_EXTENSION_CONTINUE;
// set source callsign - all address field bytes are shifted by one bit to make room for HDLC address extension bit
memset(frameBuffPtr, ' ' << 1, AX25_MAX_CALLSIGN_LEN);
for(uint8_t i = 0; i < strlen(frame->srcCallsign); i++) {
*(frameBuffPtr + i) = frame->srcCallsign[i] << 1;
}
frameBuffPtr += AX25_MAX_CALLSIGN_LEN;
// set source SSID
*(frameBuffPtr++) = AX25_SSID_COMMAND_SOURCE | AX25_SSID_RESERVED_BITS | (frame->srcSSID & 0x0F) << 1 | AX25_SSID_HDLC_EXTENSION_END;
// set repeater callsigns
for(uint16_t i = 0; i < frame->numRepeaters; i++) {
memset(frameBuffPtr, ' ' << 1, AX25_MAX_CALLSIGN_LEN);
for(uint8_t j = 0; j < strlen(frame->repeaterCallsigns[i]); j++) {
*(frameBuffPtr + j) = frame->repeaterCallsigns[i][j] << 1;
}
frameBuffPtr += AX25_MAX_CALLSIGN_LEN;
*(frameBuffPtr++) = AX25_SSID_HAS_NOT_BEEN_REPEATED | AX25_SSID_RESERVED_BITS | (frame->repeaterSSIDs[i] & 0x0F) << 1 | AX25_SSID_HDLC_EXTENSION_CONTINUE;
}
// set HDLC extension end bit
*frameBuffPtr |= AX25_SSID_HDLC_EXTENSION_END;
// set sequence numbers of the frames that have it
uint8_t controlField = frame->control;
if((frame->control & 0x01) == 0) {
// information frame, set both sequence numbers
controlField |= frame->rcvSeqNumber << 5;
controlField |= frame->sendSeqNumber << 1;
} else if((frame->control & 0x02) == 0) {
// supervisory frame, set only receive sequence number
controlField |= frame->rcvSeqNumber << 5;
}
// set control field
*(frameBuffPtr++) = controlField;
// set PID field of the frames that have it
if(frame->protocolID != 0x00) {
*(frameBuffPtr++) = frame->protocolID;
}
// set info field of the frames that have it
if(frame->infoLen > 0) {
memcpy(frameBuffPtr, frame->info, frame->infoLen);
frameBuffPtr += frame->infoLen;
}
// flip bit order
for(size_t i = 0; i < frameBuffLen; i++) {
frameBuff[i] = flipBits(frameBuff[i]);
}
// calculate FCS
uint16_t fcs = getFrameCheckSequence(frameBuff, frameBuffLen);
*(frameBuffPtr++) = (uint8_t)((fcs >> 8) & 0xFF);
*(frameBuffPtr++) = (uint8_t)(fcs & 0xFF);
// prepare buffer for the final frame (stuffed, with added preamble + flags and NRZI-encoded)
#ifndef RADIOLIB_STATIC_ONLY
// worst-case scenario: sequence of 1s, will have 120% of the original length, stuffed frame also includes both flags
uint8_t* stuffedFrameBuff = new uint8_t[_preambleLen + 1 + (6*frameBuffLen)/5 + 2];
#else
uint8_t stuffedFrameBuff[RADIOLIB_STATIC_ARRAY_SIZE];
#endif
// stuff bits (skip preamble and both flags)
uint16_t stuffedFrameBuffLenBits = 8*(_preambleLen + 1);
uint8_t count = 0;
for(uint16_t i = 0; i < frameBuffLen + 2; i++) {
for(int8_t shift = 7; shift >= 0; shift--) {
uint16_t stuffedFrameBuffPos = stuffedFrameBuffLenBits + 7 - 2*(stuffedFrameBuffLenBits%8);
if((frameBuff[i] >> shift) & 0x01) {
// copy 1 and increment counter
SET_BIT_IN_ARRAY(stuffedFrameBuff, stuffedFrameBuffPos);
stuffedFrameBuffLenBits++;
count++;
// check 5 consecutive 1s
if(count == 5) {
// get the new position in stuffed frame
stuffedFrameBuffPos = stuffedFrameBuffLenBits + 7 - 2*(stuffedFrameBuffLenBits%8);
// insert 0 and reset counter
CLEAR_BIT_IN_ARRAY(stuffedFrameBuff, stuffedFrameBuffPos);
stuffedFrameBuffLenBits++;
count = 0;
}
} else {
// copy 0 and reset counter
CLEAR_BIT_IN_ARRAY(stuffedFrameBuff, stuffedFrameBuffPos);
stuffedFrameBuffLenBits++;
count = 0;
}
}
}
// deallocate memory
#ifndef RADIOLIB_STATIC_ONLY
delete[] frameBuff;
#endif
// set preamble bytes and start flag field
for(uint16_t i = 0; i < _preambleLen + 1; i++) {
stuffedFrameBuff[i] = AX25_FLAG;
}
// get stuffed frame length in bytes
size_t stuffedFrameBuffLen = stuffedFrameBuffLenBits/8 + 1;
uint8_t trailingLen = stuffedFrameBuffLenBits % 8;
// set end flag field (may be split into two bytes due to misalignment caused by extra stuffing bits)
if(trailingLen != 0) {
stuffedFrameBuffLen++;
stuffedFrameBuff[stuffedFrameBuffLen - 2] = AX25_FLAG >> trailingLen;
stuffedFrameBuff[stuffedFrameBuffLen - 1] = AX25_FLAG << (8 - trailingLen);
} else {
stuffedFrameBuff[stuffedFrameBuffLen - 1] = AX25_FLAG;
}
// convert to NRZI
for(size_t i = _preambleLen + 1; i < stuffedFrameBuffLen*8; i++) {
size_t currBitPos = i + 7 - 2*(i%8);
size_t prevBitPos = (i - 1) + 7 - 2*((i - 1)%8);
if(TEST_BIT_IN_ARRAY(stuffedFrameBuff, currBitPos)) {
// bit is 1, no change, copy previous bit
if(TEST_BIT_IN_ARRAY(stuffedFrameBuff, prevBitPos)) {
SET_BIT_IN_ARRAY(stuffedFrameBuff, currBitPos);
} else {
CLEAR_BIT_IN_ARRAY(stuffedFrameBuff, currBitPos);
}
} else {
// bit is 0, transition, copy inversion of the previous bit
if(TEST_BIT_IN_ARRAY(stuffedFrameBuff, prevBitPos)) {
CLEAR_BIT_IN_ARRAY(stuffedFrameBuff, currBitPos);
} else {
SET_BIT_IN_ARRAY(stuffedFrameBuff, currBitPos);
}
}
}
// transmit
int16_t state = _phy->transmit(stuffedFrameBuff, stuffedFrameBuffLen);
// deallocate memory
#ifndef RADIOLIB_STATIC_ONLY
delete[] stuffedFrameBuff;
#endif
return(state);
}
/*
CCITT CRC implementation based on https://github.com/kicksat/ax25
Licensed under Creative Commons Attribution-ShareAlike 4.0 International
https://creativecommons.org/licenses/by-sa/4.0/
*/
uint16_t AX25Client::getFrameCheckSequence(uint8_t* buff, size_t len) {
uint8_t outBit = 0;
uint16_t mask = 0x0000;
uint16_t shiftReg = CRC_CCITT_INIT;
for(size_t i = 0; i < len; i++) {
for(uint8_t b = 0x80; b > 0x00; b /= 2) {
outBit = (shiftReg & 0x01) ? 0x01 : 0x00;
shiftReg >>= 1;
mask = XOR((buff[i] & b), outBit) ? CRC_CCITT_POLY_REVERSED : 0x0000;
shiftReg ^= mask;
}
}
return(flipBits16(~shiftReg));
}
uint8_t AX25Client::flipBits(uint8_t b) {
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
return b;
}
uint16_t AX25Client::flipBits16(uint16_t i) {
i = (i & 0xFF00) >> 8 | (i & 0x00FF) << 8;
i = (i & 0xF0F0) >> 4 | (i & 0x0F0F) << 4;
i = (i & 0xCCCC) >> 2 | (i & 0x3333) << 2;
i = (i & 0xAAAA) >> 1 | (i & 0x5555) << 1;
return i;
}

314
src/protocols/AX25/AX25.h Normal file
View file

@ -0,0 +1,314 @@
#ifndef _RADIOLIB_AX25_H
#define _RADIOLIB_AX25_H
#include "../../TypeDef.h"
#include "../PhysicalLayer/PhysicalLayer.h"
// macros to access bits in byte array, from http://www.mathcs.emory.edu/~cheung/Courses/255/Syllabus/1-C-intro/bit-array.html
#define SET_BIT_IN_ARRAY(A, k) ( A[(k/8)] |= (1 << (k%8)) )
#define CLEAR_BIT_IN_ARRAY(A, k) ( A[(k/8)] &= ~(1 << (k%8)) )
#define TEST_BIT_IN_ARRAY(A, k) ( A[(k/8)] & (1 << (k%8)) )
#define GET_BIT_IN_ARRAY(A, k) ( (A[(k/8)] & (1 << (k%8))) ? 1 : 0 )
// CRC-CCITT calculation macros
#define XOR(A, B) ( ((A) || (B)) && !((A) && (B)) )
#define CRC_CCITT_POLY 0x1021 // generator polynomial
#define CRC_CCITT_POLY_REVERSED 0x8408 // CRC_CCITT_POLY in reversed bit order
#define CRC_CCITT_INIT 0xFFFF // initial value
// maximum callsign length in bytes
#define AX25_MAX_CALLSIGN_LEN 6
// flag field MSB LSB DESCRIPTION
#define AX25_FLAG 0b01111110 // 7 0 AX.25 frame start/end flag
// address field
#define AX25_SSID_COMMAND_DEST 0b10000000 // 7 7 frame type: command (set in destination SSID)
#define AX25_SSID_COMMAND_SOURCE 0b00000000 // 7 7 command (set in source SSID)
#define AX25_SSID_RESPONSE_DEST 0b00000000 // 7 7 response (set in destination SSID)
#define AX25_SSID_RESPONSE_SOURCE 0b10000000 // 7 7 response (set in source SSID)
#define AX25_SSID_HAS_NOT_BEEN_REPEATED 0b00000000 // 7 7 not repeated yet (set in repeater SSID)
#define AX25_SSID_HAS_BEEN_REPEATED 0b10000000 // 7 7 repeated (set in repeater SSID)
#define AX25_SSID_RESERVED_BITS 0b01100000 // 6 5 reserved bits in SSID
#define AX25_SSID_HDLC_EXTENSION_CONTINUE 0b00000000 // 0 0 HDLC extension bit: next octet contains more address information
#define AX25_SSID_HDLC_EXTENSION_END 0b00000001 // 0 0 address field end
// control field
#define AX25_CONTROL_U_SET_ASYNC_BAL_MODE 0b01101100 // 7 2 U frame type: set asynchronous balanced mode (connect request)
#define AX25_CONTROL_U_SET_ASYNC_BAL_MODE_EXT 0b00101100 // 7 2 set asynchronous balanced mode extended (connect request with module 128)
#define AX25_CONTROL_U_DISCONNECT 0b01000000 // 7 2 disconnect request
#define AX25_CONTROL_U_DISCONNECT_MODE 0b00001100 // 7 2 disconnect mode (system busy or disconnected)
#define AX25_CONTROL_U_UNNUMBERED_ACK 0b01100000 // 7 2 unnumbered acknowledge
#define AX25_CONTROL_U_FRAME_REJECT 0b10000100 // 7 2 frame reject
#define AX25_CONTROL_U_UNNUMBERED_INFORMATION 0b00000000 // 7 2 unnumbered information
#define AX25_CONTROL_U_EXHANGE_IDENTIFICATION 0b10101100 // 7 2 exchange ID
#define AX25_CONTROL_U_TEST 0b11100000 // 7 2 test
#define AX25_CONTROL_POLL_FINAL_ENABLED 0b00010000 // 4 4 control field poll/final bit: enabled
#define AX25_CONTROL_POLL_FINAL_DISABLED 0b00000000 // 4 4 disabled
#define AX25_CONTROL_S_RECEIVE_READY 0b00000000 // 3 2 S frame type: receive ready (system ready to receive)
#define AX25_CONTROL_S_RECEIVE_NOT_READY 0b00000100 // 3 2 receive not ready (TNC buffer full)
#define AX25_CONTROL_S_REJECT 0b00001000 // 3 2 reject (out of sequence or duplicate)
#define AX25_CONTROL_S_SELECTIVE_REJECT 0b00001100 // 3 2 selective reject (single frame repeat request)
#define AX25_CONTROL_INFORMATION_FRAME 0b00000000 // 0 0 frame type: information (I frame)
#define AX25_CONTROL_SUPERVISORY_FRAME 0b00000001 // 1 0 supervisory (S frame)
#define AX25_CONTROL_UNNUMBERED_FRAME 0b00000011 // 1 0 unnumbered (U frame)
// protocol identifier field
#define AX25_PID_ISO_8208 0x01
#define AX25_PID_TCP_IP_COMPRESSED 0x06
#define AX25_PID_TCP_IP_UNCOMPRESSED 0x07
#define AX25_PID_SEGMENTATION_FRAGMENT 0x08
#define AX25_PID_TEXNET_DATAGRAM_PROTOCOL 0xC3
#define AX25_PID_LINK_QUALITY_PROTOCOL 0xC4
#define AX25_PID_APPLETALK 0xCA
#define AX25_PID_APPLETALK_ARP 0xCB
#define AX25_PID_ARPA_INTERNET_PROTOCOL 0xCC
#define AX25_PID_ARPA_ADDRESS_RESOLUTION 0xCD
#define AX25_PID_FLEXNET 0xCE
#define AX25_PID_NET_ROM 0xCF
#define AX25_PID_NO_LAYER_3 0xF0
#define AX25_PID_ESCAPE_CHARACTER 0xFF
/*!
\class AX25Frame
\brief Abstraction of AX.25 frame format.
*/
class AX25Frame {
public:
/*!
\brief Callsign of the destination station.
*/
char destCallsign[AX25_MAX_CALLSIGN_LEN + 1];
/*!
\brief SSID of the destination station.
*/
uint8_t destSSID;
/*!
\brief Callsign of the source station.
*/
char srcCallsign[AX25_MAX_CALLSIGN_LEN + 1];
/*!
\brief SSID of the source station.
*/
uint8_t srcSSID;
/*!
\brief Number of repeaters to be used.
*/
uint8_t numRepeaters;
/*!
\brief The control field.
*/
uint8_t control;
/*!
\brief The protocol identifier (PID) field.
*/
uint8_t protocolID;
/*!
\brief Number of bytes in the information field.
*/
uint16_t infoLen;
/*!
\brief Receive sequence number.
*/
uint8_t rcvSeqNumber;
/*!
\brief Send sequence number.
*/
uint16_t sendSeqNumber;
#ifndef RADIOLIB_STATIC_ONLY
/*!
\brief The info field.
*/
uint8_t* info;
/*!
\brief Array of repeater callsigns.
*/
char** repeaterCallsigns;
/*!
\brief Array of repeater SSIDs.
*/
uint8_t* repeaterSSIDs;
#else
/*!
\brief The info field.
*/
uint8_t info[RADIOLIB_STATIC_ARRAY_SIZE];
/*!
\brief Array of repeater callsigns.
*/
char repeaterCallsigns[8][AX25_MAX_CALLSIGN_LEN + 1];
/*!
\brief Array of repeater SSIDs.
*/
uint8_t repeaterSSIDs[8];
#endif
/*!
\brief Overloaded constructor, for frames without info field.
\param destCallsign Callsign of the destination station.
\param destSSID SSID of the destination station.
\param srcCallsign Callsign of the source station.
\param srcSSID SSID of the source station.
\param control The control field.
*/
AX25Frame(const char* destCallsign, uint8_t destSSID, const char* srcCallsign, uint8_t srcSSID, uint8_t control);
/*!
\brief Overloaded constructor, for frames with C-string info field.
\param destCallsign Callsign of the destination station.
\param destSSID SSID of the destination station.
\param srcCallsign Callsign of the source station.
\param srcSSID SSID of the source station.
\param control The control field.
\param protocolID The protocol identifier (PID) field. Set to zero if the frame doesn't have this field.
\param info Information field, in the form of null-terminated C-string.
*/
AX25Frame(const char* destCallsign, uint8_t destSSID, const char* srcCallsign, uint8_t srcSSID, uint8_t control, uint8_t protocolID, const char* info);
/*!
\brief Default constructor.
\param destCallsign Callsign of the destination station.
\param destSSID SSID of the destination station.
\param srcCallsign Callsign of the source station.
\param srcSSID SSID of the source station.
\param control The control field.
\param protocolID The protocol identifier (PID) field. Set to zero if the frame doesn't have this field.
\param info Information field, in the form of arbitrary binary buffer.
\param infoLen Number of bytes in the information field.
*/
AX25Frame(const char* destCallsign, uint8_t destSSID, const char* srcCallsign, uint8_t srcSSID, uint8_t control, uint8_t protocolID, uint8_t* info, uint16_t infoLen);
/*!
\brief Default destructor.
*/
~AX25Frame();
/*!
\brief Method to set the repeater callsigns and SSIDs.
\param repeaterCallsigns Array of repeater callsigns in the form of null-terminated C-strings.
\param repeaterSSIDs Array of repeater SSIDs.
\param numRepeaters Number of repeaters, maximum is 8.
\returns \ref status_codes
*/
int16_t setRepeaters(char** repeaterCallsigns, uint8_t* repeaterSSIDs, uint8_t numRepeaters);
/*!
\brief Method to set receive sequence number.
\param seqNumber Sequence number to set, 0 to 7.
*/
void setRecvSequence(uint8_t seqNumber);
/*!
\brief Method to set send sequence number.
\param seqNumber Sequence number to set, 0 to 7.
*/
void setSendSequence(uint8_t seqNumber);
};
/*!
\class AX25Client
\brief Client for AX25 communication.
*/
class AX25Client {
public:
/*!
\brief Default constructor.
\param phy Pointer to the wireless module providing PhysicalLayer communication.
*/
AX25Client(PhysicalLayer* phy);
// basic methods
/*!
\brief Initialization method.
\param srcCallsign Callsign of the source station.
\param srcSSID 4-bit SSID of the source station (in case there are more stations with the same callsign). Defaults to 0.
\param preambleLen Number of "preamble" bytes (AX25_FLAG) sent ahead of the actual AX.25 frame. Does not include the first AX25_FLAG byte, which is considered part of the frame. Defaults to 8.
\returns \ref status_codes
*/
int16_t begin(const char* srcCallsign, uint8_t srcSSID = 0x00, uint8_t preambleLen = 8);
/*!
\brief Transmit unnumbered information (UI) frame.
\param str Data to be sent.
\param destCallsign Callsign of the destination station.
\param destSSID 4-bit SSID of the destination station (in case there are more stations with the same callsign). Defaults to 0.
\returns \ref status_codes
*/
int16_t transmit(const char* str, const char* destCallsign, uint8_t destSSID = 0x00);
/*!
\brief Transmit arbitrary AX.25 frame.
\param frame Frame to be sent.
\returns \ref status_codes
*/
int16_t sendFrame(AX25Frame* frame);
#ifndef RADIOLIB_GODMODE
private:
#endif
PhysicalLayer* _phy;
char _srcCallsign[AX25_MAX_CALLSIGN_LEN + 1];
uint8_t _srcSSID;
uint16_t _preambleLen;
uint16_t getFrameCheckSequence(uint8_t* buff, size_t len);
uint8_t flipBits(uint8_t b);
uint16_t flipBits16(uint16_t i);
};
#endif

View file

@ -1,80 +1,12 @@
#include "Morse.h"
// structure to save data about character Morse code
/*!
\cond RADIOLIB_DOXYGEN_HIDDEN
*/
struct Morse_t {
char c; // ASCII character
char m[7]; // Morse code representation
};
/*!
\endcond
*/
// array of all Morse code characters
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) {
_phy = phy;
}
int16_t MorseClient::begin(float base, uint8_t speed) {
// calculate 24-bit frequency
_base = (base * (uint32_t(1) << _phy->getDivExponent())) / _phy->getCrystalFreq();
_base = (base * 1000000.0) / _phy->getFreqStep();
// calculate dot length (assumes PARIS as typical word)
_dotLength = 1200 / speed;
@ -86,7 +18,7 @@ int16_t MorseClient::begin(float base, uint8_t speed) {
}
size_t MorseClient::startSignal() {
return(MorseClient::write(0x01));
return(MorseClient::write('_'));
}
size_t MorseClient::write(const char* str) {
@ -106,52 +38,55 @@ size_t MorseClient::write(uint8_t* buff, size_t len) {
}
size_t MorseClient::write(uint8_t b) {
// find the correct Morse code in array
Morse_t mc;
bool found = false;
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 unprintable ASCII characters and boundaries
if((b < ' ') || (b == 0x60) || (b > 'z')) {
return(0);
}
// check if the requested code was found in the array
if(found) {
RADIOLIB_DEBUG_PRINT(mc.c);
RADIOLIB_DEBUG_PRINT('\t');
RADIOLIB_DEBUG_PRINTLN(mc.m);
// iterate over Morse code representation and output appropriate tones
for(uint8_t i = 0; i < strlen(mc.m); i++) {
switch(mc.m[i]) {
case '.':
_phy->transmitDirect(_base);
delay(_dotLength);
break;
case '-':
_phy->transmitDirect(_base);
delay(_dotLength * 3);
break;
case '_':
// do nothing (word space)
break;
}
// symbol space
_phy->standby();
delay(_dotLength);
}
// letter space
RADIOLIB_DEBUG_PRINTLN();
delay(_dotLength * 3);
// inter-word pause (space)
if(b == ' ') {
RADIOLIB_DEBUG_PRINTLN(F("space"));
_phy->standby();
delay(4 * _dotLength);
return(1);
}
return(0);
// get morse code from lookup table
uint8_t code = pgm_read_byte(&MorseTable[(uint8_t)(toupper(b) - 32)]);
// check unsupported characters
if(code == MORSE_UNSUPORTED) {
return(0);
}
// iterate through codeword until guard bit is reached
while(code > MORSE_GUARDBIT) {
// send dot or dash
if (code & MORSE_DASH) {
RADIOLIB_DEBUG_PRINT('-');
_phy->transmitDirect(_base);
delay(3 * _dotLength);
} else {
RADIOLIB_DEBUG_PRINT('.');
_phy->transmitDirect(_base);
delay(_dotLength);
}
// symbol space
_phy->standby();
delay(_dotLength);
// move onto the next bit
code >>= 1;
}
// letter space
_phy->standby();
delay(2 * _dotLength);
RADIOLIB_DEBUG_PRINTLN();
return(1);
}
size_t MorseClient::print(__FlashStringHelper* fstr) {
@ -219,7 +154,7 @@ size_t MorseClient::print(double n, int digits) {
}
size_t MorseClient::println(void) {
return(MorseClient::write(0x02));
return(MorseClient::write('^'));
}
size_t MorseClient::println(__FlashStringHelper* fstr) {

View file

@ -4,7 +4,81 @@
#include "../../TypeDef.h"
#include "../PhysicalLayer/PhysicalLayer.h"
#define MORSE_LENGTH 52
#define MORSE_DOT 0b0
#define MORSE_DASH 0b1
#define MORSE_GUARDBIT 0b1
#define MORSE_UNSUPORTED 0xFF
// Morse character table: - using codes defined in ITU-R M.1677-1
// - Morse code representation is saved LSb first, using additional bit as guard
// - position in array corresponds ASCII code minus MORSE_ASCII_OFFSET
// - ASCII characters marked MORSE_UNSUPORTED do not have ITU-R M.1677-1 equivalent
static const uint8_t MorseTable[] PROGMEM = {
0b00, // space
0b110101, // ! (unsupported)
0b1010010, // "
MORSE_UNSUPORTED, // # (unsupported)
MORSE_UNSUPORTED, // $ (unsupported)
MORSE_UNSUPORTED, // % (unsupported)
MORSE_UNSUPORTED, // & (unsupported)
0b1011110, // '
0b101101, // (
0b1101101, // )
MORSE_UNSUPORTED, // * (unsupported)
0b101010, // +
0b1110011, // ,
0b1100001, // -
0b1101010, // .
0b101001, // /
0b111111, // 0
0b111110, // 1
0b111100, // 2
0b111000, // 3
0b110000, // 4
0b100000, // 5
0b100001, // 6
0b100011, // 7
0b100111, // 8
0b101111, // 9
0b1000111, // :
MORSE_UNSUPORTED, // ; (unsupported)
MORSE_UNSUPORTED, // < (unsupported)
0b110001, // =
MORSE_UNSUPORTED, // > (unsupported)
0b1001100, // ?
0b1010110, // @
0b110, // A
0b10001, // B
0b10101, // C
0b1001, // D
0b10, // E
0b10100, // F
0b1011, // G
0b10000, // H
0b100, // I
0b11110, // J
0b1101, // K
0b10010, // L
0b111, // M
0b101, // N
0b1111, // O
0b10110, // P
0b11011, // Q
0b1010, // R
0b1000, // S
0b11, // T
0b1100, // U
0b11000, // V
0b1110, // W
0b11001, // X
0b11101, // Y
0b10011, // Z
MORSE_UNSUPORTED, // [ (unsupported)
MORSE_UNSUPORTED, // \ (unsupported)
MORSE_UNSUPORTED, // ] (unsupported)
0b1101000, // ^ (unsupported, used as alias for end of work)
0b110101 // _ (unsupported, used as alias for starting signal)
};
/*!
\class MorseClient

View file

@ -1,8 +1,7 @@
#include "PhysicalLayer.h"
PhysicalLayer::PhysicalLayer(float crysFreq, uint8_t divExp, size_t maxPacketLength) {
_crystalFreq = crysFreq;
_divExponent = divExp;
PhysicalLayer::PhysicalLayer(float freqStep, size_t maxPacketLength) {
_freqStep = freqStep;
_maxPacketLength = maxPacketLength;
}
@ -141,10 +140,6 @@ int16_t PhysicalLayer::receive(String& str, size_t len) {
return(state);
}
float PhysicalLayer::getCrystalFreq() {
return(_crystalFreq);
}
uint8_t PhysicalLayer::getDivExponent() {
return(_divExponent);
float PhysicalLayer::getFreqStep() {
return(_freqStep);
}

View file

@ -18,13 +18,11 @@ class PhysicalLayer {
/*!
\brief Default constructor.
\param crysFreq Frequency of crystal oscillator inside the module in MHz.
\param divExp Exponent of module frequency divider.
\param freqStep Frequency step of the synthesizer in Hz.
\param maxPacketLength Maximum length of packet that can be received by the module-
*/
PhysicalLayer(float crysFreq, uint8_t divExp, size_t maxPacketLength);
PhysicalLayer(float freqStep, size_t maxPacketLength);
// basic methods
@ -193,18 +191,29 @@ class PhysicalLayer {
virtual int16_t setFrequencyDeviation(float freqDev) = 0;
/*!
\brief Gets the module crystal oscillator frequency that was set in constructor.
\brief Sets GFSK data shaping. Only available in FSK mode. Must be implemented in module class.
\returns Crystal oscillator frequency in MHz.
\param sh Shaping to be set. Set to zero to disable data shaping.
\returns \ref status_codes
*/
float getCrystalFreq();
virtual int16_t setDataShaping(float sh) = 0;
/*!
\brief Gets the module frequency divider exponent that was set in constructor.
\brief Sets FSK data encoding. Only available in FSK mode. Must be implemented in module class.
\returns Frequency divider exponent.
\param enc Encoding to be used. Set to zero to for no encoding (NRZ).
\returns \ref status_codes
*/
uint8_t getDivExponent();
virtual int16_t setEncoding(uint8_t encoding) = 0;
/*!
\brief Gets the module frequency step size that was set in constructor.
\returns Synthesizer frequency step size in Hz.
*/
float getFreqStep();
/*!
\brief Query modem for the packet length of received payload.
@ -218,8 +227,7 @@ class PhysicalLayer {
#ifndef RADIOLIB_GODMODE
private:
#endif
float _crystalFreq;
uint8_t _divExponent;
float _freqStep;
size_t _maxPacketLength;
};

View file

@ -131,7 +131,7 @@ int16_t RTTYClient::begin(float base, uint32_t shift, uint16_t rate, uint8_t enc
_bitDuration = (uint32_t)1000000/rate;
// calculate module carrier frequency resolution
uint32_t step = round((_phy->getCrystalFreq() * 1000000) / (uint32_t(1) << _phy->getDivExponent()));
uint32_t step = round(_phy->getFreqStep());
// check minimum shift value
if(shift < step / 2) {
@ -146,7 +146,7 @@ int16_t RTTYClient::begin(float base, uint32_t shift, uint16_t rate, uint8_t enc
}
// calculate 24-bit frequency
_base = (base * (uint32_t(1) << _phy->getDivExponent())) / _phy->getCrystalFreq();
_base = (base * 1000000.0) / _phy->getFreqStep();
// set module frequency deviation to 0
int16_t state = _phy->setFrequencyDeviation(0);