Merge branch 'master' of github.com:rfquack/RadioLib
* 'master' of github.com:rfquack/RadioLib: (135 commits) [CC1101] Added bitrate caching. [nRF24] Removed ambiguity, PR #119 [nRF24] Minor fixes [nRF24] Added "isCarrierDetected()" Bump version to 3.3.1 [SX127x] Set OOK parameter before setting the bitrate to avoid reading undefined variable [Module] Fixed incorrect arguments [Module] Fixed interface termination [SX1231] Removed old call to SPI end [RF69] Removed old call to SPI end [CC1101] Removed old call to SPI end [CC1101] Removed redundant null terminator [nRF24] Removed redundant null terminator [RF69] Removed redundant null terminator [CC1101] Requested changes PR #114 [CC1101] Fixed interrupt direction. Tested: CC1101_Receive, CC1101_Receive_Interrupt, CC1101_Transmit, CC1101_Transmit_Interrupt [CC1101] Receive up to 255 bytes [CC1101] Transmit up to 255 bytes [CC1101] Added carrier sense as sync word qualifier [CC1101] Update cached len value. ...
This commit is contained in:
commit
e7a7d5fef5
87 changed files with 2758 additions and 1697 deletions
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
|
@ -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)).
|
||||
|
|
|
@ -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
|
||||
|
|
16
README.md
16
README.md
|
@ -29,19 +29,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:
|
||||
* __AVR__ - tested on Uno, Mega and Leonardo
|
||||
* __ESP8266__ - tested NodeMCU and Wemos D1
|
||||
* __ESP32__ - tested on ESP-WROOM-32
|
||||
* __STM32__ - tested on Nucleo L452RE-P
|
||||
* __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.
|
||||
* _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.
|
||||
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
|
||||
|
|
167
examples/AX25/AX25_Frames/AX25_Frames.ino
Normal file
167
examples/AX25/AX25_Frames/AX25_Frames.ino
Normal 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);
|
||||
}
|
88
examples/AX25/AX25_Transmit/AX25_Transmit.ino
Normal file
88
examples/AX25/AX25_Transmit/AX25_Transmit.ino
Normal 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);
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -19,16 +19,18 @@
|
|||
#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:
|
||||
// NSS pin: 9
|
||||
// CS pin: 9
|
||||
// GDO0 pin: 4
|
||||
// GDO2 pin: 5
|
||||
CC1101 cc2 = new Module(9, 4, 5);
|
||||
// RST pin: unused
|
||||
// GDO2 pin: 5 (optional)
|
||||
CC1101 cc2 = new Module(9, 4, NC, 53);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
|
@ -41,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) {
|
||||
|
@ -57,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 {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -19,15 +19,15 @@
|
|||
#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:
|
||||
// NSS pin: 9
|
||||
// CS pin: 9
|
||||
// DIO0 pin: 4
|
||||
// DIO1 pin: 5
|
||||
// RESET pin: 5
|
||||
RF69 rf2 = new Module(9, 4, 5);
|
||||
|
||||
// or using RadioShield
|
||||
|
@ -41,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();
|
||||
|
@ -58,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 {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -18,8 +18,9 @@
|
|||
// SX1262 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO1 pin: 2
|
||||
// NRST pin: 3
|
||||
// BUSY pin: 9
|
||||
SX1262 lora = new Module(10, 2, 9);
|
||||
SX1262 lora = new Module(10, 2, 3, 9);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
|
@ -34,11 +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) {
|
||||
|
|
|
@ -19,8 +19,9 @@
|
|||
// SX1262 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO1 pin: 2
|
||||
// NRST pin: 3
|
||||
// BUSY pin: 9
|
||||
SX1262 fsk = new Module(10, 2, 9);
|
||||
SX1262 fsk = new Module(10, 2, 3, 9);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
|
@ -40,6 +41,7 @@ void setup() {
|
|||
// 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();
|
||||
|
|
|
@ -23,9 +23,9 @@
|
|||
// 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, 9);
|
||||
SX1262 lora = new Module(10, 2, 3, 9);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
|
@ -40,11 +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) {
|
||||
|
|
|
@ -24,8 +24,9 @@
|
|||
// SX1262 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO1 pin: 2
|
||||
// NRST pin: 3
|
||||
// BUSY pin: 9
|
||||
SX1262 lora = new Module(10, 2, 9);
|
||||
SX1262 lora = new Module(10, 2, 3, 9);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
|
@ -40,11 +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) {
|
||||
|
|
|
@ -27,14 +27,16 @@
|
|||
// SX1262 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO1 pin: 2
|
||||
// NRST pin: 3
|
||||
// BUSY pin: 9
|
||||
SX1262 loraSX1262 = new Module(10, 2, 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, 6);
|
||||
SX1268 loraSX1268 = new Module(8, 4, 5, 6);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
|
@ -49,11 +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) {
|
||||
|
@ -73,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
|
||||
|
|
|
@ -19,8 +19,9 @@
|
|||
// SX1262 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO1 pin: 2
|
||||
// NRST pin: 3
|
||||
// BUSY pin: 9
|
||||
SX1262 lora = new Module(10, 2, 9);
|
||||
SX1262 lora = new Module(10, 2, 3, 9);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
|
@ -35,11 +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) {
|
||||
|
|
|
@ -20,8 +20,9 @@
|
|||
// SX1262 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO1 pin: 2
|
||||
// NRST pin: 3
|
||||
// BUSY pin: 9
|
||||
SX1262 lora = new Module(10, 2, 9);
|
||||
SX1262 lora = new Module(10, 2, 3, 9);
|
||||
|
||||
// save transmission state between loops
|
||||
int transmissionState = ERR_NONE;
|
||||
|
@ -35,11 +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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -23,14 +23,16 @@
|
|||
// SX1278 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO0 pin: 2
|
||||
// RESET pin: 9
|
||||
// DIO1 pin: 3
|
||||
SX1278 loraSX1278 = new Module(10, 2, 3);
|
||||
SX1278 loraSX1278 = new Module(10, 2, 9, 3);
|
||||
|
||||
// SX1272 has different connections:
|
||||
// NSS pin: 9
|
||||
// DIO0 pin: 4
|
||||
// DIO1 pin: 5
|
||||
SX1272 loraSX1272 = new Module(9, 4, 5);
|
||||
// RESET pin: 5
|
||||
// DIO1 pin: 6
|
||||
SX1272 loraSX1272 = new Module(9, 4, 5, 6);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
26
keywords.txt
26
keywords.txt
|
@ -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,16 +111,23 @@ setAmbientTemperature KEYWORD2
|
|||
# CC1101-specific
|
||||
getLQI KEYWORD2
|
||||
setGdo0Action KEYWORD2
|
||||
setGdo1Action KEYWORD2
|
||||
setGdo2Action KEYWORD2
|
||||
clearGdo0Action KEYWORD2
|
||||
clearGdo2Action KEYWORD2
|
||||
|
||||
# SX126x-specific
|
||||
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
|
||||
|
@ -167,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
|
||||
|
||||
|
@ -250,3 +270,7 @@ 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name=RadioLib
|
||||
version=2.0.1
|
||||
version=3.3.1
|
||||
author=Jan Gromes <gromes.jan@gmail.com>
|
||||
maintainer=Jan Gromes <gromes.jan@gmail.com>
|
||||
sentence=Universal wireless communication library for Arduino
|
||||
|
|
110
src/Module.cpp
110
src/Module.cpp
|
@ -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:
|
||||
setPin(_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:
|
||||
setPin(_int0, INPUT);
|
||||
break;
|
||||
case RADIOLIB_INT_1:
|
||||
setPin(_int1, INPUT);
|
||||
break;
|
||||
case RADIOLIB_INT_BOTH:
|
||||
setPin(_int0, INPUT);
|
||||
setPin(_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() {
|
||||
|
@ -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,29 +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::setPin(int16_t pin, uint8_t mode) {
|
||||
if(pin != -1) {
|
||||
pinMode(pin, mode);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
89
src/Module.h
89
src/Module.h
|
@ -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,21 +317,37 @@ 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;
|
||||
|
||||
uint32_t _ATtimeout = 15000;
|
||||
|
||||
void setPin(int16_t pin, uint8_t mode);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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 (0x01)
|
||||
#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.
|
||||
|
@ -61,10 +70,22 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
|
@ -86,26 +107,6 @@
|
|||
*/
|
||||
#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
|
||||
|
||||
/*!
|
||||
\}
|
||||
*/
|
||||
|
@ -539,6 +540,29 @@
|
|||
*/
|
||||
#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
|
||||
|
||||
/*!
|
||||
\}
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
|
@ -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,16 +122,13 @@ 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 rx queue to exceed threshold.
|
||||
while (!digitalRead(_mod->getIrq())) {
|
||||
yield();
|
||||
}
|
||||
|
||||
// wait for sync word
|
||||
while(!digitalRead(_mod->getInt0()));
|
||||
|
||||
// wait for packet end
|
||||
while(digitalRead(_mod->getInt0()));
|
||||
|
||||
// read packet data
|
||||
return(readData(data, len));
|
||||
}
|
||||
|
@ -157,9 +150,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 +160,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 +175,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,29 +210,56 @@ 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);
|
||||
|
||||
// data put on FIFO.
|
||||
uint8_t dataSent = 0;
|
||||
|
||||
// optionally write packet length
|
||||
if (_packetLengthConfig == CC1101_LENGTH_CONFIG_VARIABLE) {
|
||||
|
||||
// enforce variable len limit.
|
||||
if (len > 254) {
|
||||
return (ERR_PACKET_TOO_LONG);
|
||||
}
|
||||
|
||||
SPIwriteRegister(CC1101_REG_FIFO, len);
|
||||
dataSent += 1;
|
||||
}
|
||||
|
||||
// check address filtering
|
||||
uint8_t filter = SPIgetRegValue(CC1101_REG_PKTCTRL1, 1, 0);
|
||||
if(filter != CC1101_ADR_CHK_NONE) {
|
||||
SPIwriteRegister(CC1101_REG_FIFO, addr);
|
||||
dataSent += 1;
|
||||
}
|
||||
|
||||
// write packet to FIFO
|
||||
SPIwriteRegisterBurst(CC1101_REG_FIFO, data, len);
|
||||
// fill the FIFO.
|
||||
uint8_t initialWrite = min((uint8_t)len, (uint8_t)(CC1101_FIFO_SIZE - dataSent));
|
||||
SPIwriteRegisterBurst(CC1101_REG_FIFO, data, initialWrite);
|
||||
dataSent += initialWrite;
|
||||
|
||||
// set mode to transmit
|
||||
SPIsendCommand(CC1101_CMD_TX);
|
||||
|
||||
return(state);
|
||||
// keep feeding the FIFO until the packet is over.
|
||||
while (dataSent < len) {
|
||||
// get number of bytes in FIFO.
|
||||
uint8_t bytesInFIFO = SPIgetRegValue(CC1101_REG_TXBYTES, 6, 0);
|
||||
|
||||
// if there's room then put other data.
|
||||
if (bytesInFIFO < CC1101_FIFO_SIZE) {
|
||||
uint8_t bytesToWrite = min((uint8_t)(CC1101_FIFO_SIZE - bytesInFIFO), (uint8_t)(len - dataSent));
|
||||
SPIwriteRegisterBurst(CC1101_REG_FIFO, &data[dataSent], bytesToWrite);
|
||||
dataSent += bytesToWrite;
|
||||
} else {
|
||||
// wait for radio to send some data.
|
||||
delay(1);
|
||||
}
|
||||
}
|
||||
|
||||
return (state);
|
||||
}
|
||||
|
||||
int16_t CC1101::startReceive() {
|
||||
|
@ -238,11 +269,10 @@ int16_t CC1101::startReceive() {
|
|||
// flush Rx FIFO
|
||||
SPIsendCommand(CC1101_CMD_FLUSH_RX);
|
||||
|
||||
// set GDO0 mapping
|
||||
int state = SPIsetRegValue(CC1101_REG_IOCFG0, CC1101_GDOX_SYNC_WORD_SENT_OR_RECEIVED);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
// set GDO0 mapping: Asserted when RX FIFO > 4 bytes.
|
||||
int16_t state = SPIsetRegValue(CC1101_REG_IOCFG0, CC1101_GDOX_RX_FIFO_FULL_OR_PKT_END);
|
||||
state |= SPIsetRegValue(CC1101_REG_FIFOTHR, CC1101_FIFO_THR_TX_61_RX_4, 3, 0);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set mode to receive
|
||||
SPIsendCommand(CC1101_CMD_RX);
|
||||
|
@ -253,8 +283,8 @@ int16_t CC1101::startReceive() {
|
|||
int16_t CC1101::readData(uint8_t* data, size_t len) {
|
||||
// get packet length
|
||||
size_t length = len;
|
||||
if(len == CC1101_MAX_PACKET_LENGTH) {
|
||||
length = getPacketLength();
|
||||
if (len == CC1101_MAX_PACKET_LENGTH) {
|
||||
length = getPacketLength(true);
|
||||
}
|
||||
|
||||
// check address filtering
|
||||
|
@ -263,31 +293,66 @@ int16_t CC1101::readData(uint8_t* data, size_t len) {
|
|||
SPIreadRegister(CC1101_REG_FIFO);
|
||||
}
|
||||
|
||||
// read packet data
|
||||
SPIreadRegisterBurst(CC1101_REG_FIFO, length, data);
|
||||
uint8_t bytesInFIFO = SPIgetRegValue(CC1101_REG_RXBYTES, 6, 0);
|
||||
uint16_t readBytes = 0;
|
||||
uint32_t lastPop = millis();
|
||||
|
||||
// read RSSI byte
|
||||
_rawRSSI = SPIgetRegValue(CC1101_REG_FIFO);
|
||||
// keep reading from FIFO until we get all the packet.
|
||||
while (readBytes < length) {
|
||||
if (bytesInFIFO == 0) {
|
||||
if (millis() - lastPop > 5) {
|
||||
// readData was required to read a packet longer than the one received.
|
||||
RADIOLIB_DEBUG_PRINTLN(F("No data for more than 5mS. Stop here."));
|
||||
break;
|
||||
} else {
|
||||
delay(1);
|
||||
bytesInFIFO = SPIgetRegValue(CC1101_REG_RXBYTES, 6, 0);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// read the minimum between "remaining length" and bytesInFifo
|
||||
uint8_t bytesToRead = min((uint8_t)(length - readBytes), bytesInFIFO);
|
||||
SPIreadRegisterBurst(CC1101_REG_FIFO, bytesToRead, &(data[readBytes]));
|
||||
readBytes += bytesToRead;
|
||||
lastPop = millis();
|
||||
|
||||
// Get how many bytes are left in FIFO.
|
||||
bytesInFIFO = SPIgetRegValue(CC1101_REG_RXBYTES, 6, 0);
|
||||
}
|
||||
|
||||
// add terminating null
|
||||
data[readBytes] = 0;
|
||||
|
||||
// check if status bytes are enabled (default: CC1101_APPEND_STATUS_ON)
|
||||
bool isAppendStatus = SPIgetRegValue(CC1101_REG_PKTCTRL1, 2, 2) == CC1101_APPEND_STATUS_ON;
|
||||
|
||||
// If status byte is enabled at least 2 bytes (2 status bytes + any following packet) will remain in FIFO.
|
||||
if (bytesInFIFO >= 2 && isAppendStatus) {
|
||||
// read RSSI byte
|
||||
_rawRSSI = SPIgetRegValue(CC1101_REG_FIFO);
|
||||
|
||||
// read LQI and CRC byte
|
||||
uint8_t val = SPIgetRegValue(CC1101_REG_FIFO);
|
||||
_rawLQI = val & 0x7F;
|
||||
|
||||
// add terminating null
|
||||
data[length] = 0;
|
||||
|
||||
// flush Rx FIFO
|
||||
SPIsendCommand(CC1101_CMD_FLUSH_RX);
|
||||
// check CRC
|
||||
if (_crcOn && (val & 0b10000000) == 0b00000000) {
|
||||
return (ERR_CRC_MISMATCH);
|
||||
}
|
||||
}
|
||||
|
||||
// clear internal flag so getPacketLength can return the new packet length
|
||||
_packetLengthQueried = false;
|
||||
|
||||
// set mode to standby
|
||||
standby();
|
||||
// Flush then standby according to RXOFF_MODE (default: CC1101_RXOFF_IDLE)
|
||||
if (SPIgetRegValue(CC1101_REG_MCSM1, 3, 2) == CC1101_RXOFF_IDLE) {
|
||||
|
||||
// check CRC
|
||||
if (_crcOn && (val & 0b10000000) == 0b00000000) {
|
||||
return (ERR_CRC_MISMATCH);
|
||||
// flush Rx FIFO
|
||||
SPIsendCommand(CC1101_CMD_FLUSH_RX);
|
||||
|
||||
// set mode to standby
|
||||
standby();
|
||||
}
|
||||
|
||||
return(ERR_NONE);
|
||||
|
@ -316,7 +381,7 @@ int16_t CC1101::setFrequency(float freq) {
|
|||
}
|
||||
|
||||
// Update the TX power accordingly to new freq. (PA values depend on chosen freq)
|
||||
return setOutputPower(_power);
|
||||
return(setOutputPower(_power));
|
||||
}
|
||||
|
||||
int16_t CC1101::setBitRate(float br) {
|
||||
|
@ -336,7 +401,12 @@ int16_t CC1101::setBitRate(float br) {
|
|||
// set bit rate value
|
||||
int16_t state = SPIsetRegValue(CC1101_REG_MDMCFG4, e, 3, 0);
|
||||
state |= SPIsetRegValue(CC1101_REG_MDMCFG3, m);
|
||||
return(state);
|
||||
|
||||
if (state == ERR_NONE) {
|
||||
_br = br;
|
||||
}
|
||||
|
||||
return (state);
|
||||
}
|
||||
|
||||
int16_t CC1101::setRxBandwidth(float rxBw) {
|
||||
|
@ -352,14 +422,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) {
|
||||
|
@ -390,9 +460,6 @@ int16_t CC1101::setFrequencyDeviation(float freqDev) {
|
|||
}
|
||||
|
||||
int16_t CC1101::setOutputPower(int8_t power) {
|
||||
// Store the value.
|
||||
_power = power;
|
||||
|
||||
// round to the known frequency settings
|
||||
uint8_t f;
|
||||
if(_freq < 374.0) {
|
||||
|
@ -449,11 +516,26 @@ 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) {
|
||||
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);
|
||||
}
|
||||
|
@ -468,21 +550,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
|
||||
state = SPIsetRegValue(CC1101_REG_SYNC1, syncWord[0]);
|
||||
state |= SPIsetRegValue(CC1101_REG_SYNC0, syncWord[1]);
|
||||
|
||||
return (state);
|
||||
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) {
|
||||
|
@ -529,9 +609,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));
|
||||
|
@ -540,14 +618,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) {
|
||||
|
@ -584,21 +692,24 @@ int16_t CC1101::variablePacketLengthMode(uint8_t maxLen) {
|
|||
return(setPacketMode(CC1101_LENGTH_CONFIG_VARIABLE, maxLen));
|
||||
}
|
||||
|
||||
int16_t CC1101::enableSyncWordFiltering(uint8_t maxErrBits) {
|
||||
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, CC1101_SYNC_MODE_16_16, 2, 0));
|
||||
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, CC1101_SYNC_MODE_15_16, 2, 0));
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -621,18 +732,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);
|
||||
|
@ -641,6 +748,47 @@ 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);
|
||||
|
@ -650,9 +798,7 @@ int16_t CC1101::config() {
|
|||
|
||||
// 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,17 +853,14 @@ int16_t CC1101::setPacketMode(uint8_t mode, uint8_t len) {
|
|||
|
||||
// set PKTCTRL0.LENGTH_CONFIG
|
||||
int16_t state = _mod->SPIsetRegValue(CC1101_REG_PKTCTRL0, mode, 1, 0);
|
||||
if (state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
@ -767,9 +910,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);
|
||||
}
|
||||
|
|
|
@ -7,9 +7,11 @@
|
|||
#include "../../protocols/PhysicalLayer/PhysicalLayer.h"
|
||||
|
||||
// CC1101 physical layer properties
|
||||
#define CC1101_FREQUENCY_STEP_SIZE 396.7285156
|
||||
#define CC1101_MAX_PACKET_LENGTH 255
|
||||
#define CC1101_CRYSTAL_FREQ 26.0
|
||||
#define CC1101_DIV_EXPONENT 16
|
||||
#define CC1101_MAX_PACKET_LENGTH 63
|
||||
#define CC1101_FIFO_SIZE 64
|
||||
|
||||
// CC1101 SPI commands
|
||||
#define CC1101_CMD_READ 0b10000000
|
||||
|
@ -167,7 +169,7 @@
|
|||
#define CC1101_RX_ATTEN_6_DB 0b00010000 // 5 4 6 dB
|
||||
#define CC1101_RX_ATTEN_12_DB 0b00100000 // 5 4 12 dB
|
||||
#define CC1101_RX_ATTEN_18_DB 0b00110000 // 5 4 18 dB
|
||||
#define CC1101_FIFO_THR 0b00000111 // 5 4 Rx FIFO threshold [bytes] = CC1101_FIFO_THR * 4; Tx FIFO threshold [bytes] = 65 - (CC1101_FIFO_THR * 4)
|
||||
#define CC1101_FIFO_THR_TX_61_RX_4 0b00000000 // 3 0 TX fifo threshold: 61, RX fifo threshold: 4
|
||||
|
||||
// CC1101_REG_SYNC1
|
||||
#define CC1101_SYNC_WORD_MSB 0xD3 // 7 0 sync word MSB
|
||||
|
@ -524,17 +526,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.
|
||||
|
@ -597,9 +599,14 @@ class CC1101: public PhysicalLayer {
|
|||
|
||||
\param func ISR to call.
|
||||
|
||||
\param dir Signal change direction. Defaults to FALLING.
|
||||
\param dir Signal change direction. Defaults to RISING.
|
||||
*/
|
||||
void setGdo0Action(void (*func)(void), uint8_t dir = FALLING);
|
||||
void setGdo0Action(void (*func)(void), uint8_t dir = RISING);
|
||||
|
||||
/*!
|
||||
\brief Clears interrupt service routine to call when GDO0 activates.
|
||||
*/
|
||||
void clearGdo0Action();
|
||||
|
||||
/*!
|
||||
\brief Sets interrupt service routine to call when GDO2 activates.
|
||||
|
@ -610,6 +617,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 +710,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 +725,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 +758,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 +813,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,14 +846,35 @@ 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
|
||||
Module* _mod;
|
||||
|
||||
float _freq;
|
||||
float _br;
|
||||
uint8_t _rawRSSI;
|
||||
uint8_t _rawLQI;
|
||||
uint8_t _modulation;
|
||||
|
||||
size_t _packetLength;
|
||||
bool _packetLengthQueried;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ class SX1261 : public SX1262 {
|
|||
#ifndef RADIOLIB_GODMODE
|
||||
private:
|
||||
#endif
|
||||
int16_t setOptimalLowPowerPaConfig(int8_t* inOutPower);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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, float tcxoVoltage) {
|
||||
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, tcxoVoltage);
|
||||
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, float tcxoVoltage) {
|
||||
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, tcxoVoltage);
|
||||
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));
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
@ -44,7 +47,7 @@ class SX1262: public SX126x {
|
|||
|
||||
\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, float tcxoVoltage = 1.6);
|
||||
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.
|
||||
|
@ -69,7 +72,7 @@ class SX1262: public SX126x {
|
|||
|
||||
\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, float tcxoVoltage = 1.6);
|
||||
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
|
||||
|
||||
|
|
|
@ -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, float tcxoVoltage) {
|
||||
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, tcxoVoltage);
|
||||
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, float tcxoVoltage) {
|
||||
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, tcxoVoltage);
|
||||
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));
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ 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.
|
||||
|
||||
|
@ -47,7 +47,7 @@ class SX1268: public SX126x {
|
|||
|
||||
\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, float tcxoVoltage = 1.6);
|
||||
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.
|
||||
|
@ -72,7 +72,7 @@ class SX1268: public SX126x {
|
|||
|
||||
\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, float tcxoVoltage = 1.6);
|
||||
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
|
||||
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
#include "SX126x.h"
|
||||
|
||||
SX126x::SX126x(Module* mod) : PhysicalLayer(SX126X_CRYSTAL_FREQ, SX126X_DIV_EXPONENT, SX126X_MAX_PACKET_LENGTH) {
|
||||
SX126x::SX126x(Module* mod) : PhysicalLayer(SX126X_FREQUENCY_STEP_SIZE, SX126X_MAX_PACKET_LENGTH) {
|
||||
_mod = mod;
|
||||
}
|
||||
|
||||
int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, float currentLimit, uint16_t preambleLength, float tcxoVoltage) {
|
||||
int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, float currentLimit, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) {
|
||||
// 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);
|
||||
|
||||
// BW in kHz and SF are required in order to calculate LDRO for setModulationParams
|
||||
_bwKhz = bw;
|
||||
|
@ -19,67 +21,63 @@ int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, float
|
|||
_crcType = SX126X_LORA_CRC_ON;
|
||||
_preambleLength = preambleLength;
|
||||
_tcxoDelay = 0;
|
||||
_headerType = SX126X_LORA_HEADER_EXPLICIT;
|
||||
_implicitLen = 0xFF;
|
||||
|
||||
// reset the module and verify startup
|
||||
int16_t state = reset();
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set mode to standby
|
||||
int16_t state = standby();
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
state = standby();
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// configure settings not accessible by API
|
||||
state = config(SX126X_PACKET_TYPE_LORA);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set TCXO control, if requested
|
||||
if(tcxoVoltage > 0.0) {
|
||||
state = setTCXO(tcxoVoltage);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
}
|
||||
|
||||
// configure publicly accessible settings
|
||||
state = setSpreadingFactor(sf);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
state = setBandwidth(bw);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
state = setCodingRate(cr);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
state = setSyncWord(syncWord);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
state = setCurrentLimit(currentLimit);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
state = setPreambleLength(preambleLength);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set publicly accessible settings that are not a part of begin method
|
||||
state = setDio2AsRfSwitch(false);
|
||||
state = setDio2AsRfSwitch(true);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
if (useRegulatorLDO) {
|
||||
state = setRegulatorLDO();
|
||||
} else {
|
||||
state = setRegulatorDCDC();
|
||||
}
|
||||
|
||||
return(state);
|
||||
}
|
||||
|
||||
int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, float currentLimit, uint16_t preambleLength, float dataShaping, float tcxoVoltage) {
|
||||
int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, float currentLimit, uint16_t preambleLength, float dataShaping, float tcxoVoltage, bool useRegulatorLDO) {
|
||||
// set module properties
|
||||
_mod->init(RADIOLIB_USE_SPI, RADIOLIB_INT_BOTH);
|
||||
_mod->init(RADIOLIB_USE_SPI);
|
||||
Module::pinMode(_mod->getIrq(), INPUT);
|
||||
|
||||
// initialize configuration variables (will be overwritten during public settings configuration)
|
||||
_br = 21333; // 48.0 kbps
|
||||
|
@ -91,80 +89,103 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, float currentLimit
|
|||
_preambleLengthFSK = preambleLength;
|
||||
_addrComp = SX126X_GFSK_ADDRESS_FILT_OFF;
|
||||
|
||||
// reset the module and verify startup
|
||||
int16_t state = reset();
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set mode to standby
|
||||
int16_t state = standby();
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
state = standby();
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// configure settings not accessible by API
|
||||
state = config(SX126X_PACKET_TYPE_GFSK);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set TCXO control, if requested
|
||||
if(tcxoVoltage > 0.0) {
|
||||
state = setTCXO(tcxoVoltage);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
}
|
||||
|
||||
// configure publicly accessible settings
|
||||
state = setBitRate(br);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
state = setFrequencyDeviation(freqDev);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
state = setRxBandwidth(rxBw);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
state = setCurrentLimit(currentLimit);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
state = setDataShaping(dataShaping);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
state = setPreambleLength(preambleLength);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set publicly accessible settings that are not a part of begin method
|
||||
uint8_t sync[] = {0x2D, 0x01};
|
||||
state = setSyncWord(sync, 2);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
state = setWhitening(true, 0x0100);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
state = variablePacketLengthMode(SX126X_MAX_PACKET_LENGTH);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
state = setDio2AsRfSwitch(false);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
if (useRegulatorLDO) {
|
||||
state = setRegulatorLDO();
|
||||
} else {
|
||||
state = setRegulatorDCDC();
|
||||
}
|
||||
|
||||
return(state);
|
||||
}
|
||||
|
||||
int16_t SX126x::reset(bool verify) {
|
||||
// run the reset sequence
|
||||
Module::pinMode(_mod->getRst(), OUTPUT);
|
||||
Module::digitalWrite(_mod->getRst(), LOW);
|
||||
delayMicroseconds(150);
|
||||
Module::digitalWrite(_mod->getRst(), HIGH);
|
||||
|
||||
// return immediately when verification is disabled
|
||||
if(!verify) {
|
||||
return(ERR_NONE);
|
||||
}
|
||||
|
||||
// set mode to standby - SX126x often refuses first few commands after reset
|
||||
uint32_t start = millis();
|
||||
while(true) {
|
||||
// try to set mode to standby
|
||||
int16_t state = standby();
|
||||
if(state == ERR_NONE) {
|
||||
// standby command successful
|
||||
return(ERR_NONE);
|
||||
}
|
||||
|
||||
// standby command failed, check timeout and try again
|
||||
if(millis() - start >= 3000) {
|
||||
// timed out, possibly incorrect wiring
|
||||
return(state);
|
||||
}
|
||||
|
||||
// wait a bit to not spam the module
|
||||
delay(10);
|
||||
}
|
||||
}
|
||||
|
||||
int16_t SX126x::transmit(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);
|
||||
|
||||
// check packet length
|
||||
if(len > SX126X_MAX_PACKET_LENGTH) {
|
||||
|
@ -193,15 +214,14 @@ int16_t SX126x::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
|
||||
uint32_t start = micros();
|
||||
while(!digitalRead(_mod->getInt0())) {
|
||||
while(!digitalRead(_mod->getIrq())) {
|
||||
if(micros() - start > timeout) {
|
||||
clearIrqStatus();
|
||||
standby();
|
||||
return(ERR_TX_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
@ -212,9 +232,7 @@ int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) {
|
|||
|
||||
// clear interrupt flags
|
||||
state = clearIrqStatus();
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set mode to standby to disable transmitter
|
||||
state = standby();
|
||||
|
@ -225,9 +243,7 @@ int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) {
|
|||
int16_t SX126x::receive(uint8_t* data, size_t len) {
|
||||
// set mode to standby
|
||||
int16_t state = standby();
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
uint32_t timeout = 0;
|
||||
|
||||
|
@ -237,7 +253,6 @@ int16_t SX126x::receive(uint8_t* data, size_t len) {
|
|||
// calculate timeout (100 LoRa symbols, the default for SX127x series)
|
||||
float symbolLength = (float)(uint32_t(1) << _sf) / (float)_bwKhz;
|
||||
timeout = (uint32_t)(symbolLength * 100.0 * 1000.0);
|
||||
|
||||
} else if(modem == SX126X_PACKET_TYPE_GFSK) {
|
||||
// calculate timeout (500 % of expected time-one-air)
|
||||
size_t maxLen = len;
|
||||
|
@ -258,24 +273,23 @@ int16_t SX126x::receive(uint8_t* data, size_t len) {
|
|||
// start reception
|
||||
uint32_t timeoutValue = (uint32_t)((float)timeout / 15.625);
|
||||
state = startReceive(timeoutValue);
|
||||
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) {
|
||||
fixImplicitTimeout();
|
||||
clearIrqStatus();
|
||||
standby();
|
||||
return(ERR_RX_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
// timeout fix is recommended after any reception with active timeout
|
||||
state = fixImplicitTimeout();
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
// fix timeout in implicit LoRa mode
|
||||
if(((_headerType == SX126X_LORA_HEADER_IMPLICIT) && (getPacketType() == SX126X_PACKET_TYPE_LORA))) {
|
||||
state = fixImplicitTimeout();
|
||||
RADIOLIB_ASSERT(state);
|
||||
}
|
||||
|
||||
// read the received data
|
||||
|
@ -288,9 +302,7 @@ int16_t SX126x::transmitDirect(uint32_t frf) {
|
|||
if(frf != 0) {
|
||||
state = setRfFrequency(frf);
|
||||
}
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// start transmitting
|
||||
uint8_t data[] = {SX126X_CMD_NOP};
|
||||
|
@ -310,30 +322,24 @@ int16_t SX126x::scanChannel() {
|
|||
|
||||
// set mode to standby
|
||||
int16_t state = standby();
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set DIO pin mapping
|
||||
state = setDioIrqParams(SX126X_IRQ_CAD_DETECTED | SX126X_IRQ_CAD_DONE, SX126X_IRQ_CAD_DETECTED | SX126X_IRQ_CAD_DONE);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// clear interrupt flags
|
||||
state = clearIrqStatus();
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set mode to CAD
|
||||
state = setCad();
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// wait for channel activity detected or timeout
|
||||
while(!digitalRead(_mod->getInt0()));
|
||||
while(!digitalRead(_mod->getIrq())) {
|
||||
yield();
|
||||
}
|
||||
|
||||
// check CAD result
|
||||
uint16_t cadResult = getIrqStatus();
|
||||
|
@ -350,9 +356,12 @@ int16_t SX126x::scanChannel() {
|
|||
return(ERR_UNKNOWN);
|
||||
}
|
||||
|
||||
int16_t SX126x::sleep() {
|
||||
uint8_t data[] = {SX126X_SLEEP_START_COLD | SX126X_SLEEP_RTC_OFF};
|
||||
int16_t state = SPIwriteCommand(SX126X_CMD_SET_SLEEP, data, 1, false);
|
||||
int16_t SX126x::sleep(bool retainConfig) {
|
||||
uint8_t sleepMode = SX126X_SLEEP_START_WARM | SX126X_SLEEP_RTC_OFF;
|
||||
if(!retainConfig) {
|
||||
sleepMode = SX126X_SLEEP_START_COLD | SX126X_SLEEP_RTC_OFF;
|
||||
}
|
||||
int16_t state = SPIwriteCommand(SX126X_CMD_SET_SLEEP, &sleepMode, 1, false);
|
||||
|
||||
// wait for SX126x to safely enter sleep mode
|
||||
delayMicroseconds(500);
|
||||
|
@ -370,7 +379,11 @@ int16_t SX126x::standby(uint8_t mode) {
|
|||
}
|
||||
|
||||
void SX126x::setDio1Action(void (*func)(void)) {
|
||||
attachInterrupt(digitalPinToInterrupt(_mod->getInt0()), func, RISING);
|
||||
attachInterrupt(digitalPinToInterrupt(_mod->getIrq()), func, RISING);
|
||||
}
|
||||
|
||||
void SX126x::clearDio1Action() {
|
||||
detachInterrupt(digitalPinToInterrupt(_mod->getIrq()));
|
||||
}
|
||||
|
||||
int16_t SX126x::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
|
||||
|
@ -391,63 +404,49 @@ int16_t SX126x::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
|
|||
int16_t state = ERR_NONE;
|
||||
uint8_t modem = getPacketType();
|
||||
if(modem == SX126X_PACKET_TYPE_LORA) {
|
||||
state = setPacketParams(_preambleLength, _crcType, len);
|
||||
state = setPacketParams(_preambleLength, _crcType, len, _headerType);
|
||||
} else if(modem == SX126X_PACKET_TYPE_GFSK) {
|
||||
state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType, len);
|
||||
} else {
|
||||
return(ERR_UNKNOWN);
|
||||
}
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set DIO mapping
|
||||
state = setDioIrqParams(SX126X_IRQ_TX_DONE | SX126X_IRQ_TIMEOUT, SX126X_IRQ_TX_DONE);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set buffer pointers
|
||||
state = setBufferBaseAddress();
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// write packet to buffer
|
||||
state = writeBuffer(data, len);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// clear interrupt flags
|
||||
state = clearIrqStatus();
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// fix sensitivity
|
||||
state = fixSensitivity();
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// start transmission
|
||||
state = setTx(SX126X_TX_TIMEOUT_NONE);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// wait for BUSY to go low (= PA ramp up done)
|
||||
while(digitalRead(_mod->getInt1()));
|
||||
while(digitalRead(_mod->getGpio())) {
|
||||
yield();
|
||||
}
|
||||
|
||||
return(state);
|
||||
}
|
||||
|
||||
int16_t SX126x::startReceive(uint32_t timeout) {
|
||||
int16_t state = startReceiveCommon();
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set mode to receive
|
||||
state = setRx(timeout);
|
||||
|
@ -475,9 +474,7 @@ int16_t SX126x::startReceiveDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod) {
|
|||
}
|
||||
|
||||
int16_t state = startReceiveCommon();
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
uint8_t data[6] = {(uint8_t)((rxPeriodRaw >> 16) & 0xFF), (uint8_t)((rxPeriodRaw >> 8) & 0xFF), (uint8_t)(rxPeriodRaw & 0xFF),
|
||||
(uint8_t)((sleepPeriodRaw >> 16) & 0xFF), (uint8_t)((sleepPeriodRaw >> 8) & 0xFF), (uint8_t)(sleepPeriodRaw & 0xFF)};
|
||||
|
@ -527,34 +524,35 @@ int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_
|
|||
int16_t SX126x::startReceiveCommon() {
|
||||
// set DIO mapping
|
||||
int16_t state = setDioIrqParams(SX126X_IRQ_RX_DONE | SX126X_IRQ_TIMEOUT | SX126X_IRQ_CRC_ERR | SX126X_IRQ_HEADER_ERR, SX126X_IRQ_RX_DONE);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set buffer pointers
|
||||
state = setBufferBaseAddress();
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// clear interrupt flags
|
||||
state = clearIrqStatus();
|
||||
|
||||
// set implicit mode and expected len if applicable
|
||||
if(_headerType == SX126X_LORA_HEADER_IMPLICIT && getPacketType() == SX126X_PACKET_TYPE_LORA) {
|
||||
state = setPacketParams(_preambleLength, _crcType, _implicitLen, _headerType);
|
||||
RADIOLIB_ASSERT(state);
|
||||
}
|
||||
|
||||
return(state);
|
||||
}
|
||||
|
||||
int16_t SX126x::readData(uint8_t* data, size_t len) {
|
||||
// set mode to standby
|
||||
int16_t state = standby();
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// check integrity CRC
|
||||
uint16_t irq = getIrqStatus();
|
||||
int16_t crcState = ERR_NONE;
|
||||
if((irq & SX126X_IRQ_CRC_ERR) || (irq & SX126X_IRQ_HEADER_ERR)) {
|
||||
clearIrqStatus();
|
||||
return(ERR_CRC_MISMATCH);
|
||||
crcState = ERR_CRC_MISMATCH;
|
||||
}
|
||||
|
||||
// get packet length
|
||||
|
@ -565,13 +563,14 @@ int16_t SX126x::readData(uint8_t* data, size_t len) {
|
|||
|
||||
// read packet data
|
||||
state = readBuffer(data, length);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// clear interrupt flags
|
||||
state = clearIrqStatus();
|
||||
|
||||
// check if CRC failed - this is done after reading data to give user the option to keep them
|
||||
RADIOLIB_ASSERT(crcState);
|
||||
|
||||
return(state);
|
||||
}
|
||||
|
||||
|
@ -660,18 +659,23 @@ int16_t SX126x::setCodingRate(uint8_t cr) {
|
|||
return(setModulationParams(_sf, _bw, _cr));
|
||||
}
|
||||
|
||||
int16_t SX126x::setSyncWord(uint16_t syncWord) {
|
||||
int16_t SX126x::setSyncWord(uint8_t syncWord, uint8_t controlBits) {
|
||||
// check active modem
|
||||
if(getPacketType() != SX126X_PACKET_TYPE_LORA) {
|
||||
return(ERR_WRONG_MODEM);
|
||||
}
|
||||
|
||||
// update register
|
||||
uint8_t data[2] = {(uint8_t)((syncWord >> 8) & 0xFF), (uint8_t)(syncWord & 0xFF)};
|
||||
uint8_t data[2] = {(uint8_t)((syncWord & 0xF0) | ((controlBits & 0xF0) >> 4)), (uint8_t)(((syncWord & 0x0F) << 4) | (controlBits & 0x0F))};
|
||||
return(writeRegister(SX126X_REG_LORA_SYNC_WORD_MSB, data, 2));
|
||||
}
|
||||
|
||||
int16_t SX126x::setCurrentLimit(float currentLimit) {
|
||||
// check allowed range
|
||||
if(!((currentLimit >= 0) && (currentLimit <= 140))) {
|
||||
return(ERR_INVALID_CURRENT_LIMIT);
|
||||
}
|
||||
|
||||
// calculate raw value
|
||||
uint8_t rawLimit = (uint8_t)(currentLimit / 2.5);
|
||||
|
||||
|
@ -679,11 +683,20 @@ int16_t SX126x::setCurrentLimit(float currentLimit) {
|
|||
return(writeRegister(SX126X_REG_OCP_CONFIGURATION, &rawLimit, 1));
|
||||
}
|
||||
|
||||
float SX126x::getCurrentLimit() {
|
||||
// get the raw value
|
||||
uint8_t ocp = 0;
|
||||
readRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1);
|
||||
|
||||
// return the actual value
|
||||
return((float)ocp * 2.5);
|
||||
}
|
||||
|
||||
int16_t SX126x::setPreambleLength(uint16_t preambleLength) {
|
||||
uint8_t modem = getPacketType();
|
||||
if(modem == SX126X_PACKET_TYPE_LORA) {
|
||||
_preambleLength = preambleLength;
|
||||
return(setPacketParams(_preambleLength, _crcType));
|
||||
return(setPacketParams(_preambleLength, _crcType, _implicitLen, _headerType));
|
||||
} else if(modem == SX126X_PACKET_TYPE_GFSK) {
|
||||
_preambleLengthFSK = preambleLength;
|
||||
return(setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType));
|
||||
|
@ -842,9 +855,7 @@ int16_t SX126x::setSyncWord(uint8_t* syncWord, uint8_t len) {
|
|||
|
||||
// write sync word
|
||||
int16_t state = writeRegister(SX126X_REG_SYNC_WORD_0, syncWord, len);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// update packet parameters
|
||||
_syncWordLength = len * 8;
|
||||
|
@ -871,9 +882,7 @@ int16_t SX126x::setSyncBits(uint8_t *syncWord, uint8_t bitsLen) {
|
|||
|
||||
// write sync word
|
||||
int16_t state = writeRegister(SX126X_REG_SYNC_WORD_0, syncWord, bytesLen);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// update packet parameters
|
||||
_syncWordLength = bitsLen;
|
||||
|
@ -891,9 +900,7 @@ int16_t SX126x::setNodeAddress(uint8_t nodeAddr) {
|
|||
// enable address filtering (node only)
|
||||
_addrComp = SX126X_GFSK_ADDRESS_FILT_NODE;
|
||||
int16_t state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set node address
|
||||
state = writeRegister(SX126X_REG_NODE_ADDRESS, &nodeAddr, 1);
|
||||
|
@ -910,9 +917,7 @@ int16_t SX126x::setBroadcastAddress(uint8_t broadAddr) {
|
|||
// enable address filtering (node and broadcast)
|
||||
_addrComp = SX126X_GFSK_ADDRESS_FILT_NODE_BROADCAST;
|
||||
int16_t state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set broadcast address
|
||||
state = writeRegister(SX126X_REG_BROADCAST_ADDRESS, &broadAddr, 1);
|
||||
|
@ -960,16 +965,12 @@ int16_t SX126x::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool
|
|||
}
|
||||
|
||||
int16_t state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// write initial CRC value
|
||||
uint8_t data[2] = {(uint8_t)((initial >> 8) & 0xFF), (uint8_t)(initial & 0xFF)};
|
||||
state = writeRegister(SX126X_REG_CRC_INITIAL_MSB, data, 2);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// write CRC polynomial value
|
||||
data[0] = (uint8_t)((polynomial >> 8) & 0xFF);
|
||||
|
@ -988,7 +989,7 @@ int16_t SX126x::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool
|
|||
_crcType = SX126X_LORA_CRC_OFF;
|
||||
}
|
||||
|
||||
return(setPacketParams(_preambleLength, _crcType));
|
||||
return(setPacketParams(_preambleLength, _crcType, _implicitLen, _headerType));
|
||||
}
|
||||
|
||||
return(ERR_UNKNOWN);
|
||||
|
@ -1006,9 +1007,7 @@ int16_t SX126x::setWhitening(bool enabled, uint16_t initial) {
|
|||
_whitening = SX126X_GFSK_WHITENING_OFF;
|
||||
|
||||
state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
} else {
|
||||
// enable whitening
|
||||
_whitening = SX126X_GFSK_WHITENING_ON;
|
||||
|
@ -1019,21 +1018,15 @@ int16_t SX126x::setWhitening(bool enabled, uint16_t initial) {
|
|||
// first read the actual value and mask 7 MSB which we can not change
|
||||
// if different value is written in 7 MSB, the Rx won't even work (tested on HW)
|
||||
state = readRegister(SX126X_REG_WHITENING_INITIAL_MSB, data, 1);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
data[0] = (data[0] & 0xFE) | (uint8_t)((initial >> 8) & 0x01);
|
||||
data[1] = (uint8_t)(initial & 0xFF);
|
||||
state = writeRegister(SX126X_REG_WHITENING_INITIAL_MSB, data, 2);
|
||||
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
}
|
||||
return(state);
|
||||
}
|
||||
|
@ -1058,7 +1051,11 @@ float SX126x::getSNR() {
|
|||
// get last packet SNR from packet status
|
||||
uint32_t packetStatus = getPacketStatus();
|
||||
uint8_t snrPkt = (packetStatus >> 8) & 0xFF;
|
||||
return(snrPkt/4.0);
|
||||
if(snrPkt < 128) {
|
||||
return(snrPkt/4.0);
|
||||
} else {
|
||||
return((snrPkt - 256)/4.0);
|
||||
}
|
||||
}
|
||||
|
||||
size_t SX126x::getPacketLength(bool update) {
|
||||
|
@ -1092,7 +1089,7 @@ uint32_t SX126x::getTimeOnAir(size_t len) {
|
|||
sfDivisor = 4*(_sf - 2);
|
||||
}
|
||||
const int8_t bitsPerCrc = 16;
|
||||
const int8_t N_symbol_header = 20;
|
||||
const int8_t N_symbol_header = _headerType == SX126X_LORA_HEADER_EXPLICIT ? 20 : 0;
|
||||
|
||||
// numerator of equation in section 6.1.4 of SX1268 datasheet v1.1 (might not actually be bitcount, but it has len * 8)
|
||||
int16_t bitCount = (int16_t) 8 * len + _crcType * bitsPerCrc - 4 * _sf + sfCoeff2 + N_symbol_header;
|
||||
|
@ -1111,6 +1108,26 @@ uint32_t SX126x::getTimeOnAir(size_t len) {
|
|||
}
|
||||
}
|
||||
|
||||
int16_t SX126x::implicitHeader(size_t len) {
|
||||
return(setHeaderType(SX126X_LORA_HEADER_IMPLICIT, len));
|
||||
}
|
||||
|
||||
int16_t SX126x::explicitHeader() {
|
||||
return(setHeaderType(SX126X_LORA_HEADER_EXPLICIT));
|
||||
}
|
||||
|
||||
int16_t SX126x::setRegulatorLDO() {
|
||||
return(setRegulatorMode(SX126X_REGULATOR_LDO));
|
||||
}
|
||||
|
||||
int16_t SX126x::setRegulatorDCDC() {
|
||||
return(setRegulatorMode(SX126X_REGULATOR_DC_DC));
|
||||
}
|
||||
|
||||
int16_t SX126x::setEncoding(uint8_t encoding) {
|
||||
return(setWhitening(encoding));
|
||||
}
|
||||
|
||||
int16_t SX126x::setTCXO(float voltage, uint32_t delay) {
|
||||
// set mode to standby
|
||||
standby();
|
||||
|
@ -1246,30 +1263,6 @@ int16_t SX126x::setTxParams(uint8_t power, uint8_t rampTime) {
|
|||
return(SPIwriteCommand(SX126X_CMD_SET_TX_PARAMS, data, 2));
|
||||
}
|
||||
|
||||
int16_t SX126x::setOptimalHiPowerPaConfig(int8_t * inOutPower) {
|
||||
// set PA config for optimal consumption as described in section 13-21 of SX1268 datasheet v1.1
|
||||
// the final column of Table 13-21 suggests that the value passed in SetTxParams
|
||||
// is actually scaled depending on the parameters of setPaConfig
|
||||
int16_t state;
|
||||
if (*inOutPower >= 21) {
|
||||
state = SX126x::setPaConfig(0x04, SX126X_PA_CONFIG_SX1262_8, SX126X_PA_CONFIG_HP_MAX/*0x07*/);
|
||||
}
|
||||
else if (*inOutPower >= 18) {
|
||||
state = SX126x::setPaConfig(0x03, SX126X_PA_CONFIG_SX1262_8, 0x05);
|
||||
// datasheet instructs request 22 dBm for 20 dBm actual output power
|
||||
*inOutPower += 2;
|
||||
} else if (*inOutPower >= 15) {
|
||||
state = SX126x::setPaConfig(0x02, SX126X_PA_CONFIG_SX1262_8, 0x03);
|
||||
// datasheet instructs request 22 dBm for 17 dBm actual output power
|
||||
*inOutPower += 5;
|
||||
} else {
|
||||
state = SX126x::setPaConfig(0x02, SX126X_PA_CONFIG_SX1262_8, 0x02);
|
||||
// datasheet instructs request 22 dBm for 14 dBm actual output power.
|
||||
*inOutPower += 8;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
int16_t SX126x::setPacketMode(uint8_t mode, uint8_t len) {
|
||||
// check active modem
|
||||
if(getPacketType() != SX126X_PACKET_TYPE_GFSK) {
|
||||
|
@ -1278,15 +1271,30 @@ int16_t SX126x::setPacketMode(uint8_t mode, uint8_t len) {
|
|||
|
||||
// set requested packet mode
|
||||
int16_t state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, mode, len);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// update cached value
|
||||
_packetType = mode;
|
||||
return(state);
|
||||
}
|
||||
|
||||
int16_t SX126x::setHeaderType(uint8_t headerType, size_t len) {
|
||||
// check active modem
|
||||
if(getPacketType() != SX126X_PACKET_TYPE_LORA) {
|
||||
return(ERR_WRONG_MODEM);
|
||||
}
|
||||
|
||||
// set requested packet mode
|
||||
int16_t state = setPacketParams(_preambleLength, _crcType, len, headerType);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// update cached value
|
||||
_headerType = headerType;
|
||||
_implicitLen = len;
|
||||
|
||||
return(state);
|
||||
}
|
||||
|
||||
int16_t SX126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro) {
|
||||
// calculate symbol length and enable low data rate optimization, if needed
|
||||
if(ldro == 0xFF) {
|
||||
|
@ -1315,7 +1323,8 @@ int16_t SX126x::setModulationParamsFSK(uint32_t br, uint8_t pulseShape, uint8_t
|
|||
}
|
||||
|
||||
int16_t SX126x::setPacketParams(uint16_t preambleLength, uint8_t crcType, uint8_t payloadLength, uint8_t headerType, uint8_t invertIQ) {
|
||||
fixInvertedIQ(invertIQ);
|
||||
int16_t state = fixInvertedIQ(invertIQ);
|
||||
RADIOLIB_ASSERT(state);
|
||||
uint8_t data[6] = {(uint8_t)((preambleLength >> 8) & 0xFF), (uint8_t)(preambleLength & 0xFF), headerType, payloadLength, crcType, invertIQ};
|
||||
return(SPIwriteCommand(SX126X_CMD_SET_PACKET_PARAMS, data, 6));
|
||||
}
|
||||
|
@ -1332,6 +1341,11 @@ int16_t SX126x::setBufferBaseAddress(uint8_t txBaseAddress, uint8_t rxBaseAddres
|
|||
return(SPIwriteCommand(SX126X_CMD_SET_BUFFER_BASE_ADDRESS, data, 2));
|
||||
}
|
||||
|
||||
int16_t SX126x::setRegulatorMode(uint8_t mode) {
|
||||
uint8_t data[1] = {mode};
|
||||
return(SPIwriteCommand(SX126X_CMD_SET_REGULATOR_MODE, data, 1));
|
||||
}
|
||||
|
||||
uint8_t SX126x::getStatus() {
|
||||
uint8_t data = 0;
|
||||
SPIreadCommand(SX126X_CMD_GET_STATUS, &data, 1);
|
||||
|
@ -1369,9 +1383,7 @@ int16_t SX126x::fixSensitivity() {
|
|||
// read current sensitivity configuration
|
||||
uint8_t sensitivityConfig = 0;
|
||||
int16_t state = readRegister(SX126X_REG_SENSITIVITY_CONFIG, &sensitivityConfig, 1);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// fix the value for LoRa with 500 kHz bandwidth
|
||||
if((getPacketType() == SX126X_PACKET_TYPE_LORA) && (abs(_bwKhz - 500.0) <= 0.001)) {
|
||||
|
@ -1389,9 +1401,7 @@ int16_t SX126x::fixPaClamping() {
|
|||
// read current clamping configuration
|
||||
uint8_t clampConfig = 0;
|
||||
int16_t state = readRegister(SX126X_REG_TX_CLAMP_CONFIG, &clampConfig, 1);
|
||||
if (state != ERR_NONE) {
|
||||
return state;
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// update with the new value
|
||||
clampConfig |= 0x1E;
|
||||
|
@ -1402,19 +1412,20 @@ int16_t SX126x::fixImplicitTimeout() {
|
|||
// fixes timeout in implicit header mode
|
||||
// see SX1262/SX1268 datasheet, chapter 15 Known Limitations, section 15.3 for details
|
||||
|
||||
//check if we're in implicit LoRa mode
|
||||
if(!((_headerType == SX126X_LORA_HEADER_IMPLICIT) && (getPacketType() == SX126X_PACKET_TYPE_LORA))) {
|
||||
return(ERR_WRONG_MODEM);
|
||||
}
|
||||
|
||||
// stop RTC counter
|
||||
uint8_t rtcStop = 0x00;
|
||||
int16_t state = writeRegister(SX126X_REG_RTC_STOP, &rtcStop, 1);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// read currently active event
|
||||
uint8_t rtcEvent = 0;
|
||||
state = readRegister(SX126X_REG_RTC_EVENT, &rtcEvent, 1);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// clear events
|
||||
rtcEvent |= 0x02;
|
||||
|
@ -1428,9 +1439,7 @@ int16_t SX126x::fixInvertedIQ(uint8_t iqConfig) {
|
|||
// read current IQ configuration
|
||||
uint8_t iqConfigCurrent = 0;
|
||||
int16_t state = readRegister(SX126X_REG_IQ_CONFIG, &iqConfigCurrent, 1);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set correct IQ configuration
|
||||
if(iqConfig == SX126X_LORA_IQ_STANDARD) {
|
||||
|
@ -1444,33 +1453,20 @@ int16_t SX126x::fixInvertedIQ(uint8_t iqConfig) {
|
|||
}
|
||||
|
||||
int16_t SX126x::config(uint8_t modem) {
|
||||
// set regulator mode
|
||||
uint8_t data[7];
|
||||
data[0] = SX126X_REGULATOR_DC_DC;
|
||||
int16_t state = SPIwriteCommand(SX126X_CMD_SET_REGULATOR_MODE, data, 1);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
// reset buffer base address
|
||||
state = setBufferBaseAddress();
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
int16_t state = setBufferBaseAddress();
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set modem
|
||||
uint8_t data[7];
|
||||
data[0] = modem;
|
||||
state = SPIwriteCommand(SX126X_CMD_SET_PACKET_TYPE, data, 1);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set Rx/Tx fallback mode to STDBY_RC
|
||||
data[0] = SX126X_RX_TX_FALLBACK_MODE_STDBY_RC;
|
||||
state = SPIwriteCommand(SX126X_CMD_SET_RX_TX_FALLBACK_MODE, data, 1);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set CAD parameters
|
||||
data[0] = SX126X_CAD_ON_8_SYMB;
|
||||
|
@ -1481,27 +1477,23 @@ int16_t SX126x::config(uint8_t modem) {
|
|||
data[5] = 0x00;
|
||||
data[6] = 0x00;
|
||||
state = SPIwriteCommand(SX126X_CMD_SET_CAD_PARAMS, data, 7);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// clear IRQ
|
||||
state = clearIrqStatus();
|
||||
state |= setDioIrqParams(SX126X_IRQ_NONE, SX126X_IRQ_NONE);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// calibrate all blocks
|
||||
data[0] = SX126X_CALIBRATE_ALL;
|
||||
state = SPIwriteCommand(SX126X_CMD_CALIBRATE, data, 1);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// wait for calibration completion
|
||||
delay(5);
|
||||
while(digitalRead(_mod->getInt1()));
|
||||
while(digitalRead(_mod->getGpio())) {
|
||||
yield();
|
||||
}
|
||||
|
||||
return(ERR_NONE);
|
||||
}
|
||||
|
@ -1535,9 +1527,8 @@ int16_t SX126x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* d
|
|||
digitalWrite(_mod->getCs(), LOW);
|
||||
|
||||
// ensure BUSY is low (state meachine ready)
|
||||
RADIOLIB_VERBOSE_PRINTLN(F("Wait for BUSY ... "));
|
||||
uint32_t start = millis();
|
||||
while(digitalRead(_mod->getInt1())) {
|
||||
while(digitalRead(_mod->getGpio())) {
|
||||
if(millis() - start >= timeout) {
|
||||
return(ERR_SPI_CMD_TIMEOUT);
|
||||
}
|
||||
|
@ -1604,11 +1595,11 @@ int16_t SX126x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* d
|
|||
if(waitForBusy) {
|
||||
delayMicroseconds(1);
|
||||
start = millis();
|
||||
while(digitalRead(_mod->getInt1())) {
|
||||
if(millis() - start >= timeout) {
|
||||
status = SX126X_STATUS_CMD_TIMEOUT;
|
||||
break;
|
||||
}
|
||||
while(digitalRead(_mod->getGpio())) {
|
||||
if(millis() - start >= timeout) {
|
||||
status = SX126X_STATUS_CMD_TIMEOUT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1650,6 +1641,13 @@ int16_t SX126x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* d
|
|||
RADIOLIB_VERBOSE_PRINTLN();
|
||||
}
|
||||
RADIOLIB_VERBOSE_PRINTLN();
|
||||
#else
|
||||
// some faster platforms require a short delay here
|
||||
// not sure why, but it seems that long enough SPI transaction
|
||||
// (e.g. setPacketParams for GFSK) will fail without it
|
||||
#if defined(ARDUINO_ARCH_STM32)
|
||||
delay(1);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// parse status
|
||||
|
|
|
@ -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,7 +362,7 @@ 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.
|
||||
|
||||
|
@ -369,9 +370,11 @@ class SX126x: public PhysicalLayer {
|
|||
|
||||
\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, float tcxoVoltage);
|
||||
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.
|
||||
|
@ -390,9 +393,21 @@ class SX126x: public PhysicalLayer {
|
|||
|
||||
\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, float tcxoVoltage);
|
||||
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.
|
||||
|
@ -447,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).
|
||||
|
@ -476,6 +493,11 @@ class SX126x: 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.
|
||||
|
@ -569,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.
|
||||
|
@ -582,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.
|
||||
|
||||
|
@ -772,6 +803,46 @@ class SX126x: public PhysicalLayer {
|
|||
\returns Expected time-on-air in microseconds.
|
||||
*/
|
||||
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
|
||||
|
@ -793,9 +864,10 @@ 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();
|
||||
|
@ -803,8 +875,8 @@ class SX126x: public PhysicalLayer {
|
|||
|
||||
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();
|
||||
|
@ -817,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;
|
||||
|
||||
|
@ -830,6 +902,8 @@ class SX126x: public PhysicalLayer {
|
|||
|
||||
uint32_t _tcxoDelay;
|
||||
|
||||
size_t _implicitLen;
|
||||
|
||||
int16_t config(uint8_t modem);
|
||||
|
||||
// common low-level SPI interface
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
// set bit rate
|
||||
state = SX127x::setBitRate(br);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
// set frequency deviation
|
||||
state = SX127x::setFrequencyDeviation(freqDev);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
// set receiver bandwidth
|
||||
state = SX127x::setRxBandwidth(rxBw);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
// set over current protection
|
||||
state = SX127x::setCurrentLimit(currentLimit);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
// set preamble length
|
||||
state = SX127x::setPreambleLength(preambleLength);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
// default sync word value 0x2D01 is the same as the default in LowPowerLab RFM69 library
|
||||
uint8_t syncWord[] = {0x2D, 0x01};
|
||||
state = setSyncWord(syncWord, 2);
|
||||
if(state != ERR_NONE) {
|
||||
return(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 bit rate
|
||||
state = SX127x::setBitRate(br);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set frequency deviation
|
||||
state = SX127x::setFrequencyDeviation(freqDev);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set receiver bandwidth
|
||||
state = SX127x::setRxBandwidth(rxBw);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set over current protection
|
||||
state = SX127x::setCurrentLimit(currentLimit);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set preamble length
|
||||
state = SX127x::setPreambleLength(preambleLength);
|
||||
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);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// disable address filtering
|
||||
state = disableAddressFiltering();
|
||||
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;
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,11 +8,11 @@ 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);
|
||||
|
@ -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();
|
||||
|
||||
|
@ -263,24 +230,15 @@ int16_t nRF24::setFrequency(int16_t freq) {
|
|||
return(ERR_INVALID_FREQUENCY);
|
||||
}
|
||||
|
||||
// set mode to standby
|
||||
int16_t state = standby();
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
// set frequency
|
||||
uint8_t freqRaw = freq - 2400;
|
||||
state = _mod->SPIsetRegValue(NRF24_REG_RF_CH, freqRaw, 6, 0);
|
||||
return(state);
|
||||
return _mod->SPIsetRegValue(NRF24_REG_RF_CH, freqRaw, 6, 0);
|
||||
}
|
||||
|
||||
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 +260,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,9 +289,7 @@ 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) {
|
||||
|
@ -366,15 +320,14 @@ 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);
|
||||
|
||||
// set Rx pipe 0 address (for ACK)
|
||||
_mod->SPIwriteRegisterBurst(NRF24_REG_RX_ADDR_P0, addr, _addrWidth);
|
||||
state |= _mod->SPIsetRegValue(NRF24_REG_EN_RXADDR, NRF24_P0_ON, 0, 0);
|
||||
|
||||
return(state);
|
||||
}
|
||||
|
@ -382,9 +335,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) {
|
||||
|
@ -406,9 +357,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) {
|
||||
|
@ -438,9 +387,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:
|
||||
|
@ -472,6 +419,10 @@ int16_t nRF24::getStatus(uint8_t mask) {
|
|||
return(_mod->SPIgetRegValue(NRF24_REG_STATUS) & mask);
|
||||
}
|
||||
|
||||
bool nRF24::isCarrierDetected() {
|
||||
return(_mod->SPIgetRegValue(NRF24_REG_RPD, 0,0)) == 1;
|
||||
}
|
||||
|
||||
int16_t nRF24::setFrequencyDeviation(float freqDev) {
|
||||
// nRF24 is unable to set frequency deviation
|
||||
// this method is implemented only for PhysicalLayer compatibility
|
||||
|
@ -487,6 +438,13 @@ size_t nRF24::getPacketLength(bool update) {
|
|||
}
|
||||
|
||||
int16_t nRF24::setCrcFiltering(bool crcOn) {
|
||||
// Auto Ack needs to be disabled in order to disable CRC.
|
||||
if (!crcOn) {
|
||||
int16_t status = setAutoAck(false);
|
||||
RADIOLIB_ASSERT(status)
|
||||
}
|
||||
|
||||
// Disable CRC
|
||||
return _mod->SPIsetRegValue(NRF24_REG_CONFIG, crcOn ? NRF24_CRC_ON : NRF24_CRC_OFF, 3, 3);
|
||||
}
|
||||
|
||||
|
@ -519,6 +477,20 @@ int16_t nRF24::setAutoAck(uint8_t pipeNum, bool autoAckOn){
|
|||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -530,27 +502,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();
|
||||
|
|
|
@ -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
|
||||
|
@ -128,7 +127,7 @@
|
|||
// NRF24_REG_STATUS
|
||||
#define NRF24_RX_DR 0b01000000 // 6 6 Rx data ready
|
||||
#define NRF24_TX_DS 0b00100000 // 5 5 Tx data sent
|
||||
#define NRF24_MAX_RT 0b00010000 // 4 4 maximum number of rentransmits reached (must be cleared to continue)
|
||||
#define NRF24_MAX_RT 0b00010000 // 4 4 maximum number of retransmits reached (must be cleared to continue)
|
||||
#define NRF24_RX_FIFO_EMPTY 0b00001110 // 3 1 Rx FIFO is empty
|
||||
#define NRF24_RX_P_NO 0b00000000 // 3 1 number of data pipe that received data
|
||||
#define NRF24_TX_FIFO_FULL 0b00000001 // 0 0 Tx FIFO is full
|
||||
|
@ -393,6 +392,13 @@ class nRF24: public PhysicalLayer {
|
|||
*/
|
||||
int16_t getStatus(uint8_t mask = 0xFF);
|
||||
|
||||
/*!
|
||||
\brief Checks if carrier was detected during last RX
|
||||
|
||||
\returns Whatever the carrier was above threshold.
|
||||
*/
|
||||
bool isCarrierDetected();
|
||||
|
||||
/*!
|
||||
\brief Dummy configuration method, to ensure PhysicalLayer compatibility.
|
||||
|
||||
|
@ -438,7 +444,25 @@ class nRF24: public PhysicalLayer {
|
|||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setAutoAck(uint8_t pipeNum, bool autoAckOn = true);
|
||||
int16_t setAutoAck(uint8_t pipeNum, bool autoAckOn);
|
||||
|
||||
/*!
|
||||
\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:
|
||||
|
|
382
src/protocols/AX25/AX25.cpp
Normal file
382
src/protocols/AX25/AX25.cpp
Normal 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
314
src/protocols/AX25/AX25.h
Normal 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
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue