Merge branch 'master' into development

This commit is contained in:
jgromes 2019-11-22 14:48:29 +01:00
commit 43eefd4703
75 changed files with 2229 additions and 826 deletions

View file

@ -5,9 +5,10 @@ env:
# see https://github.com/arduino/Arduino/blob/master/build/shared/manpage.adoc#options
# and https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5-3rd-party-Hardware-specification#boardstxt
- BOARD="esp32:esp32:esp32"
- BOARD="STM32:stm32:GenF1:pnum=BLUEPILL_F103C6"
- BOARD="STM32:stm32:GenF3:pnum=BLACKPILL_F303CC"
- BOARD="esp8266:esp8266:generic:xtal=80,ResetMethod=ck,CrystalFreq=26,FlashFreq=40,FlashMode=qio,eesz=512K"
- BOARD="arduino:samd:arduino_zero_native"
- BOARD="arduino:sam:arduino_due_x"
- BOARD="arduino:avr:uno"
- BOARD="arduino:avr:leonardo"
- BOARD="arduino:avr:mega:cpu=atmega2560"
@ -28,7 +29,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://dl.espressif.com/dl/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" --save-prefs 2>&1
- if [[ "$BOARD" =~ "esp8266:esp8266:" ]]; then
arduino --install-boards esp8266:esp8266;
export SKIP_PAT='(HTTP|MQTT).*ino';
@ -38,6 +39,8 @@ before_install:
arduino --install-boards STM32:stm32;
elif [[ "$BOARD" =~ "arduino:samd:" ]]; then
arduino --install-boards arduino:samd;
elif [[ "$BOARD" =~ "arduino:sam:" ]]; then
arduino --install-boards arduino:sam;
fi
# create directory to save the library and create symbolic link

View file

@ -15,6 +15,8 @@ To report bugs or suggest new features, use the provided issue templates. Use th
Issues with generic titles (e.g. "not working", "lora", etc.) will be **CLOSED** until the title is fixed, since the title is supposed to categorize the issue. The same applies for issues with very little information and extensive grammatical or formatting errors that make it difficult to find out what is the actual issue.
4. **Issues deserve some attention too.**
Issues that are left for 2 weeks without response by the original author when asked for further information will be closed due to inactivity. This is to keep track of important issues, the author is encouraged to reopen the issue at a later date.
5. **LoRaLib is a separate project.**
RadioLib was created as an extension of LoRaLib for radios other than SX127x. However, LoRaLib project is still active and RadioLib is reusing its code. **Because of that, please open issues/PRs related to SX127x in [LoRaLib](https://github.com/jgromes/LoRaLib)**.
## Code style guidelines
@ -22,6 +24,7 @@ I like pretty code! Or at least, I like *consistent* code style. When creating p
1. **Bracket style**
This library uses the following style of bracket indentation (1TBS, or "javascript" style):
```c++
if (foo) {
bar();
@ -35,6 +38,7 @@ Use 2 space characters for tabs.
3. **Single-line comments**
Comments can be very useful - and they can become the bane of readability. Every single-line comment should start at new line, have one space between comment delimiter `//` and the start of the comment itself. The comment should also start with a lower-case letter.
```c++
// this function does something
foo("bar");
@ -45,6 +49,7 @@ foo(12345);
4. **Split code into blocks**
It is very easy to write code that machine can read. It is much harder to write one that humans can read. That's why it's a great idea to split code into blocks - even if the block is just a single line!
```c++
// build a temporary buffer (first block)
uint8_t* data = new uint8_t[len + 1];
@ -63,4 +68,4 @@ data[len] = 0;
If you're adding a new method, make sure to add appropriate Doxygen comments, so that the documentation is always complete.
6. **Keywords**
This is an Arduino library, so it needs to comply with the Arduino library specification. To add a new keyword to the Arduino IDE syntax highlighting, add it to the keywords.txt file. **Use true tabs in keywords.txt! No spaces there!"
This is an Arduino library, so it needs to comply with the Arduino library specification. To add a new keyword to the Arduino IDE syntax highlighting, add it to the keywords.txt file. **Use true tabs in keywords.txt! No spaces there!**

View file

@ -32,8 +32,9 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github
* __Arduino AVR boards__ - tested on Uno, Mega and Leonardo
* __ESP8266 boards__ - NodeMCU, Wemos D1, etc.
* __ESP32 boards__ - tested on ESP-WROOM-32
* __STM32 boards__ - tested on BluePill F103C6
* __STM32 boards__ - tested on Nucleo L452RE-P
* __SAMD boards__ - Arduino Zero
* __SAM boards__ - Arduino Due
### In development:
* __SIM800C__ GSM module

View file

@ -70,6 +70,7 @@ void setup() {
// cc.sleep()
// cc.transmit();
// cc.receive();
// cc.readData();
}
// flag to indicate that a packet was received
@ -142,6 +143,9 @@ void loop() {
}
// put module back to listen mode
cc.startReceive();
// we're ready to receive more packets,
// enable interrupt service routine
enableInterrupt = true;

View file

@ -64,6 +64,7 @@ void setup() {
// rf.sleep()
// rf.transmit();
// rf.receive();
// rf.readData();
}
// flag to indicate that a packet was received
@ -125,6 +126,9 @@ void loop() {
}
// put module back to listen mode
rf.startReceive();
// we're ready to receive more packets,
// enable interrupt service routine
enableInterrupt = true;

View file

@ -53,6 +53,28 @@ void setup() {
Serial.println(state);
while (true);
}
// NOTE: Some SX126x modules use TCXO
// (Temprature-Compensated Crystal Oscillator).
// To be able to use these modules, TCXO
// control must be enabled by calling
// setTCXO() and specifying the reference
// voltage.
/*
Serial.print(F("[SX1262] Setting TCXO reference ... "));
// enable TCXO
// reference voltage: 1.6 V
// timeout: 5000 us
state = lora.setTCXO(1.6);
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
*/
}
void loop() {
@ -89,7 +111,7 @@ void loop() {
// of the last received packet
Serial.print(F("[SX1262] SNR:\t\t"));
Serial.print(lora.getSNR());
Serial.println(F(" dBm"));
Serial.println(F(" dB"));
} else if (state == ERR_RX_TIMEOUT) {
// timeout occurred while waiting for a packet

View file

@ -77,6 +77,7 @@ void setup() {
// lora.sleep()
// lora.transmit();
// lora.receive();
// lora.readData();
// lora.scanChannel();
}
@ -136,7 +137,7 @@ void loop() {
// print SNR (Signal-to-Noise Ratio)
Serial.print(F("[SX1262] SNR:\t\t"));
Serial.print(lora.getSNR());
Serial.println(F(" dBm"));
Serial.println(F(" dB"));
} else if (state == ERR_CRC_MISMATCH) {
// packet was received, but is malformed
@ -149,6 +150,9 @@ void loop() {
}
// put module back to listen mode
lora.startReceive();
// we're ready to receive more packets,
// enable interrupt service routine
enableInterrupt = true;

View file

@ -88,7 +88,7 @@ void loop() {
// of the last received packet
Serial.print(F("[SX1278] SNR:\t\t\t"));
Serial.print(lora.getSNR());
Serial.println(F(" dBm"));
Serial.println(F(" dB"));
// print frequency error
// of the last received packet

View file

@ -76,6 +76,7 @@ void setup() {
// lora.sleep()
// lora.transmit();
// lora.receive();
// lora.readData();
// lora.scanChannel();
}
@ -135,7 +136,7 @@ void loop() {
// print SNR (Signal-to-Noise Ratio)
Serial.print(F("[SX1278] SNR:\t\t"));
Serial.print(lora.getSNR());
Serial.println(F(" dBm"));
Serial.println(F(" dB"));
// print frequency error
Serial.print(F("[SX1278] Frequency error:\t"));
@ -153,6 +154,9 @@ void loop() {
}
// put module back to listen mode
lora.startReceive();
// we're ready to receive more packets,
// enable interrupt service routine
enableInterrupt = true;

View file

@ -1,6 +1,6 @@
/*
/*
RadioLib Module Template header file
Before opening pull request, please make sure that:
1. All files MUST be compiled without errors using default Arduino IDE settings.
2. All files SHOULD be compiled without warnings with compiler warnings set to "All".
@ -8,7 +8,7 @@
4. Writing style SHOULD be consistent.
5. Comments SHOULD be in place for the most important chunks of code and SHOULD be free of typos.
6. To indent, 2 spaces MUST be used.
If at any point you are unsure about the required style, please refer to the rest of the modules.
*/
@ -21,33 +21,33 @@
*/
#include "Module.h"
/*
/*
Only use the following include if the module implements methods for OSI transport layer control.
This concerns only modules similar to e.g. ESP8266.
This concerns only modules similar to e.g. ESP8266.
In this case, your class MUST implement all virtual methods of TransportLayer class.
You also MUST provide crystal oscillator frequency and frequency configuration divisor step resolution
to the TransportLayer constructor.
*/
//#include "../protocols/TransportLayer.h"
/*
/*
Only use the following include if the module implements methods for OSI physical layer control.
This concerns only modules similar to SX127x/RF69/CC1101 etc.
In this case, your class MUST implement all virtual methods of PhysicalLayer class.
In this case, your class MUST implement all virtual methods of PhysicalLayer class.
*/
//#include "../protocols/PhysicalLayer.h"
/*
/*
Register map
Definition of SPI/I2C register map SHOULD be placed here. The register map SHOULD have two parts:
1 - Address map: only defines register names and addresses. Register names MUST match names in
official documentation (datasheets etc.).
2 - Variable map: defines variables inside register. This functions as a bit range map for a specific register.
Bit range (MSB and LSB) as well as short description for each variable MUST be provided in a comment.
See RF69 and SX127x header files for examples of register maps.
*/
// <module_name> register map | spaces up to this point
@ -59,9 +59,9 @@
/*
Module class definition
The module class MAY inherit from the following classes:
1 - ISerial: Interface for Arduino Serial class, intended as a thin wrapper for modules that directly take
Serial input (e.g. HC-05).
2 - TransportLayer: In case the module implements methods for OSI transport layer control (e.g. ESP8266).
@ -75,29 +75,31 @@ class <module_name> {
*/
// constructor
<module_name>(Module* module);
/*
The class MUST implement at least one basic method called "begin".
The "begin" method MUST initialize the module and return the status as int16_t type.
*/
// basic methods
int16_t begin();
/*
The class MAY implement additional methods.
All implemented methods SHOULD return the status as int16_t type.
*/
#ifndef RADIOLIB_GODMODE
private:
#endif
/*
The class MUST contain private member "Module* _mod"
*/
Module* _mod;
/*
The class MAY contain additional private variables and/or methods.
Private member variables MUST have a name prefixed with "_" (underscore, ASCII 0x5F)
Usually, these are variables for saving module configuration, or methods that do not have to be exposed to the end user.
*/
};

View file

@ -88,6 +88,14 @@ setDataShaping KEYWORD2
setOOK KEYWORD2
setDataShapingOOK KEYWORD2
setCRC KEYWORD2
variablePacketLengthMode KEYWORD2
fixedPacketLengthMode KEYWORD2
setCrcFiltering KEYWORD2
enableSyncWordFiltering KEYWORD2
disableSyncWordFiltering KEYWORD2
setPromiscuous KEYWORD2
setRSSIConfig KEYWORD2
setEncoding KEYWORD2
# RF69-specific
setAESKey KEYWORD2
@ -107,6 +115,7 @@ setTCXO KEYWORD2
setDio2AsRfSwitch KEYWORD2
getTimeOnAir KEYWORD2
setSyncBits KEYWORD2
setWhitening KEYWORD2
# ESP8266
join KEYWORD2
@ -182,6 +191,9 @@ ERR_INVALID_CURRENT_LIMIT LITERAL1
ERR_INVALID_PREAMBLE_LENGTH LITERAL1
ERR_INVALID_GAIN LITERAL1
ERR_WRONG_MODEM LITERAL1
ERR_INVALID_NUM_SAMPLES LITERAL1
ERR_INVALID_RSSI_OFFSET LITERAL1
ERR_INVALID_ENCODING LITERAL1
ERR_INVALID_BIT_RATE LITERAL1
ERR_INVALID_FREQUENCY_DEVIATION LITERAL1

View file

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

View file

@ -9,7 +9,7 @@ void ISerial::begin(long speed) {
}
bool ISerial::listen() {
#if defined ( ESP32 ) || defined (SAMD_SERIES) || defined (ARDUINO_ARCH_STM32)
#ifdef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
return true;
#else
return(_mod->ModuleSerial->listen());
@ -21,7 +21,7 @@ void ISerial::end() {
}
bool ISerial::isListening() {
#if defined( ESP32 ) || defined ( SAMD_SERIES ) || defined (ARDUINO_ARCH_STM32)
#ifdef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
return true;
#else
return(_mod->ModuleSerial->isListening());
@ -29,7 +29,7 @@ bool ISerial::isListening() {
}
bool ISerial::stopListening() {
#if defined( ESP32 ) || defined ( SAMD_SERIES ) || defined (ARDUINO_ARCH_STM32)
#ifdef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
return true;
#else
return(_mod->ModuleSerial->stopListening());
@ -37,7 +37,7 @@ bool ISerial::stopListening() {
}
bool ISerial::overflow() {
#if defined( ESP32 ) || defined ( SAMD_SERIES ) || defined (ARDUINO_ARCH_STM32)
#ifdef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
return false;
#else
return(_mod->ModuleSerial->overflow());

View file

@ -54,7 +54,9 @@ class ISerial {
size_t println(const Printable&);
size_t println(void);
#ifndef RADIOLIB_GODMODE
protected:
#endif
Module* _mod;
};

View file

@ -7,10 +7,11 @@ Module::Module(int rx, int tx, HardwareSerial* useSer) {
_int0 = -1;
_int1 = -1;
#if defined(ESP32) || defined(SAMD_SERIES) || defined (ARDUINO_ARCH_STM32)
ModuleSerial = useSer;
#ifdef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
ModuleSerial = useSer;
#else
ModuleSerial = new SoftwareSerial(_rx, _tx);
(void)useSer;
#endif
}
@ -33,10 +34,11 @@ Module::Module(int cs, int int0, int int1, int rx, int tx, SPIClass& spi, SPISet
_spi = &spi;
_spiSettings = spiSettings;
#if defined(ESP32) || defined(SAMD_SERIES) || defined (ARDUINO_ARCH_STM32)
#ifdef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
ModuleSerial = useSer;
#else
ModuleSerial = new SoftwareSerial(_rx, _tx);
(void)useSer;
#endif
}
@ -53,33 +55,33 @@ Module::Module(int cs, int int0, int int1, int int2, SPIClass& spi, SPISettings
void Module::init(uint8_t interface, uint8_t gpio) {
// select interface
switch(interface) {
case USE_SPI:
case RADIOLIB_USE_SPI:
pinMode(_cs, OUTPUT);
digitalWrite(_cs, HIGH);
_spi->begin();
break;
case USE_UART:
case RADIOLIB_USE_UART:
#if defined(ESP32)
ModuleSerial->begin(baudrate, SERIAL_8N1, _rx, _tx);
#else
ModuleSerial->begin(baudrate);
#endif
break;
case USE_I2C:
case RADIOLIB_USE_I2C:
break;
}
// select GPIO
switch(gpio) {
case INT_NONE:
case RADIOLIB_INT_NONE:
break;
case INT_0:
case RADIOLIB_INT_0:
pinMode(_int0, INPUT);
break;
case INT_1:
case RADIOLIB_INT_1:
pinMode(_int1, INPUT);
break;
case INT_BOTH:
case RADIOLIB_INT_BOTH:
pinMode(_int0, INPUT);
pinMode(_int1, INPUT);
break;
@ -120,20 +122,20 @@ bool Module::ATgetResponse() {
while (millis() - start < _ATtimeout) {
while(ModuleSerial->available() > 0) {
char c = ModuleSerial->read();
DEBUG_PRINT(c);
RADIOLIB_VERBOSE_PRINT(c);
data += c;
}
if(data.indexOf("OK") != -1) {
DEBUG_PRINTLN();
RADIOLIB_VERBOSE_PRINTLN();
return(true);
} else if (data.indexOf("ERROR") != -1) {
DEBUG_PRINTLN();
RADIOLIB_VERBOSE_PRINTLN();
return(false);
}
}
DEBUG_PRINTLN();
RADIOLIB_VERBOSE_PRINTLN();
return(false);
}
@ -170,24 +172,24 @@ int16_t Module::SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb, uint8_t
}
// check failed, print debug info
DEBUG_PRINTLN();
DEBUG_PRINT(F("address:\t0x"));
DEBUG_PRINTLN(reg, HEX);
DEBUG_PRINT(F("bits:\t\t"));
DEBUG_PRINT(msb);
DEBUG_PRINT(' ');
DEBUG_PRINTLN(lsb);
DEBUG_PRINT(F("value:\t\t0b"));
DEBUG_PRINTLN(value, BIN);
DEBUG_PRINT(F("current:\t0b"));
DEBUG_PRINTLN(currentValue, BIN);
DEBUG_PRINT(F("mask:\t\t0b"));
DEBUG_PRINTLN(mask, BIN);
DEBUG_PRINT(F("new:\t\t0b"));
DEBUG_PRINTLN(newValue, BIN);
DEBUG_PRINT(F("read:\t\t0b"));
DEBUG_PRINTLN(readValue, BIN);
DEBUG_PRINTLN();
RADIOLIB_DEBUG_PRINTLN();
RADIOLIB_DEBUG_PRINT(F("address:\t0x"));
RADIOLIB_DEBUG_PRINTLN(reg, HEX);
RADIOLIB_DEBUG_PRINT(F("bits:\t\t"));
RADIOLIB_DEBUG_PRINT(msb);
RADIOLIB_DEBUG_PRINT(' ');
RADIOLIB_DEBUG_PRINTLN(lsb);
RADIOLIB_DEBUG_PRINT(F("value:\t\t0b"));
RADIOLIB_DEBUG_PRINTLN(value, BIN);
RADIOLIB_DEBUG_PRINT(F("current:\t0b"));
RADIOLIB_DEBUG_PRINTLN(currentValue, BIN);
RADIOLIB_DEBUG_PRINT(F("mask:\t\t0b"));
RADIOLIB_DEBUG_PRINTLN(mask, BIN);
RADIOLIB_DEBUG_PRINT(F("new:\t\t0b"));
RADIOLIB_DEBUG_PRINTLN(newValue, BIN);
RADIOLIB_DEBUG_PRINT(F("read:\t\t0b"));
RADIOLIB_DEBUG_PRINTLN(readValue, BIN);
RADIOLIB_DEBUG_PRINTLN();
return(ERR_SPI_WRITE_FAILED);
}
@ -219,30 +221,30 @@ void Module::SPItransfer(uint8_t cmd, uint8_t reg, uint8_t* dataOut, uint8_t* da
// send SPI register address with access command
_spi->transfer(reg | cmd);
DEBUG_PRINT(reg | cmd, HEX);
DEBUG_PRINT('\t');
DEBUG_PRINT(reg | cmd, BIN);
DEBUG_PRINT('\t');
RADIOLIB_VERBOSE_PRINT(reg | cmd, HEX);
RADIOLIB_VERBOSE_PRINT('\t');
RADIOLIB_VERBOSE_PRINT(reg | cmd, BIN);
RADIOLIB_VERBOSE_PRINT('\t');
// send data or get response
if(cmd == SPIwriteCommand) {
for(size_t n = 0; n < numBytes; n++) {
_spi->transfer(dataOut[n]);
DEBUG_PRINT(dataOut[n], HEX);
DEBUG_PRINT('\t');
DEBUG_PRINT(dataOut[n], BIN);
DEBUG_PRINT('\t');
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);
DEBUG_PRINT(dataIn[n], HEX);
DEBUG_PRINT('\t');
DEBUG_PRINT(dataIn[n], BIN);
DEBUG_PRINT('\t');
RADIOLIB_VERBOSE_PRINT(dataIn[n], HEX);
RADIOLIB_VERBOSE_PRINT('\t');
RADIOLIB_VERBOSE_PRINT(dataIn[n], BIN);
RADIOLIB_VERBOSE_PRINT('\t');
}
}
DEBUG_PRINTLN();
RADIOLIB_VERBOSE_PRINTLN();
// release CS
digitalWrite(_cs, HIGH);

View file

@ -1,15 +1,14 @@
#ifndef _RADIOLIB_MODULE_H
#define _RADIOLIB_MODULE_H
#include "TypeDef.h"
#include <SPI.h>
//#include <Wire.h>
#if defined(ESP32) || defined(SAMD_SERIES) || defined (ARDUINO_ARCH_STM32)
#else
#ifndef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
#include <SoftwareSerial.h>
#endif
#include "TypeDef.h"
/*!
\class Module
@ -28,7 +27,7 @@ class Module {
\param serial HardwareSerial to be used on ESP32 and SAMD. Defaults to 1
*/
#if defined(ESP32) || defined(SAMD_SERIES) || defined (ARDUINO_ARCH_STM32)
#ifdef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
Module(int tx, int rx, HardwareSerial* useSer = &Serial1);
#else
Module(int tx, int rx, HardwareSerial* useSer = nullptr);
@ -85,7 +84,7 @@ class Module {
\param serial HardwareSerial to be used on ESP32 and SAMD. Defaults to 1
*/
#if defined(ESP32) || defined(SAMD_SERIES) || defined (ARDUINO_ARCH_STM32)
#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);
#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);
@ -97,7 +96,7 @@ class Module {
/*!
\brief Internal SoftwareSerial instance.
*/
#if defined(ESP32) || defined(SAMD_SERIES) || defined (ARDUINO_ARCH_STM32)
#ifdef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
HardwareSerial* ModuleSerial;
#else
SoftwareSerial* ModuleSerial;
@ -311,7 +310,9 @@ class Module {
*/
SPISettings getSpiSettings() const { return(_spiSettings); }
#ifndef RADIOLIB_GODMODE
private:
#endif
int _cs;
int _tx;
int _rx;

View file

@ -1,8 +0,0 @@
#include "RadioLib.h"
Radio::Radio() {
ModuleA = new Module(RADIOSHIELD_CS_A, RADIOSHIELD_INT_0, RADIOSHIELD_INT_1, RADIOSHIELD_RX_A, RADIOSHIELD_TX_A);
ModuleB = new Module(RADIOSHIELD_CS_B, RADIOSHIELD_INT_0, RADIOSHIELD_INT_1, RADIOSHIELD_RX_B, RADIOSHIELD_TX_B);
}
Radio RadioShield;

View file

@ -38,42 +38,43 @@
#include "TypeDef.h"
#include "Module.h"
#include "modules/CC1101.h"
#ifndef ESP8266
#include "modules/ESP8266.h"
#ifdef RADIOLIB_GODMODE
#warning "God mode active, I hope it was intentional. Buckle up, lads."
#endif
#include "modules/HC05.h"
#include "modules/JDY08.h"
#include "modules/nRF24.h"
#include "modules/RF69.h"
#include "modules/RFM95.h"
#include "modules/RFM96.h"
#include "modules/RFM97.h"
#include "modules/SIM800.h"
#include "modules/SX1231.h"
#include "modules/SX1261.h"
#include "modules/SX1262.h"
#include "modules/SX1268.h"
#include "modules/SX1272.h"
#include "modules/SX1273.h"
#include "modules/SX1276.h"
#include "modules/SX1277.h"
#include "modules/SX1278.h"
#include "modules/SX1279.h"
#include "modules/XBee.h"
#include "modules/CC1101/CC1101.h"
#ifndef ESP8266
#include "modules/ESP8266/ESP8266.h"
#endif
#include "modules/HC05/HC05.h"
#include "modules/JDY08/JDY08.h"
#include "modules/nRF24/nRF24.h"
#include "modules/RF69/RF69.h"
#include "modules/RFM9x/RFM95.h"
#include "modules/RFM9x/RFM96.h"
#include "modules/RFM9x/RFM97.h"
#include "modules/SX1231/SX1231.h"
#include "modules/SX126x/SX1261.h"
#include "modules/SX126x/SX1262.h"
#include "modules/SX126x/SX1268.h"
#include "modules/SX127x/SX1272.h"
#include "modules/SX127x/SX1273.h"
#include "modules/SX127x/SX1276.h"
#include "modules/SX127x/SX1277.h"
#include "modules/SX127x/SX1278.h"
#include "modules/SX127x/SX1279.h"
#include "modules/XBee/XBee.h"
// physical layer protocols
#include "protocols/PhysicalLayer.h"
#include "protocols/Morse.h"
#include "protocols/RTTY.h"
#include "protocols/Pager.h"
#include "protocols/PSK.h"
#include "protocols/PhysicalLayer/PhysicalLayer.h"
#include "protocols/Morse/Morse.h"
#include "protocols/RTTY/RTTY.h"
// transport layer protocols
#ifndef ESP8266
#include "protocols/TransportLayer.h"
#include "protocols/HTTP.h"
#include "protocols/MQTT.h"
#include "protocols/TransportLayer/TransportLayer.h"
#include "protocols/HTTP/HTTP.h"
#include "protocols/MQTT/MQTT.h"
#endif
// RadioShield pin definitions
@ -96,18 +97,23 @@
class Radio {
public:
/*!
\brief Default constructor. Only used to set ModuleA and ModuleB configuration.
*/
Radio();
Module* ModuleA;
Module* ModuleB;
/*!
\brief Default constructor. Only used to set ModuleA and ModuleB configuration.
*/
Radio() {
ModuleA = new Module(RADIOSHIELD_CS_A, RADIOSHIELD_INT_0, RADIOSHIELD_INT_1, RADIOSHIELD_RX_A, RADIOSHIELD_TX_A, SPI, SPISettings(2000000, MSBFIRST, SPI_MODE0), nullptr);
ModuleB = new Module(RADIOSHIELD_CS_B, RADIOSHIELD_INT_0, RADIOSHIELD_INT_1, RADIOSHIELD_RX_B, RADIOSHIELD_TX_B, SPI, SPISettings(2000000, MSBFIRST, SPI_MODE0), nullptr);
}
#ifndef RADIOLIB_GODMODE
private:
#endif
};
extern Radio RadioShield;
Radio RadioShield;
#endif

View file

@ -1,20 +1,63 @@
#ifndef _RADIOLIB_TYPES_H
#define _RADIOLIB_TYPES_H
#if ARDUINO >= 100
#include "Arduino.h"
#else
#error "Unsupported Arduino version (< 1.0.0)"
#endif
/*
* 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.
*/
//#define RADIOLIB_STATIC_ONLY
// set the size of static arrays to use
#define RADIOLIB_STATIC_ARRAY_SIZE 256
/*
* Uncomment to enable debug output.
* Warning: Debug output will slow down the whole system significantly.
* Also, it will result in larger compiled binary.
* Levels: debug - only main info
* verbose - full transcript of all SPI/UART communication
*/
//#define RADIOLIB_DEBUG
//#define RADIOLIB_VERBOSE
// set which Serial port should be used for debug output
#define RADIOLIB_DEBUG_PORT Serial
#ifdef RADIOLIB_DEBUG
#define DEBUG_PRINT(...) { Serial.print(__VA_ARGS__); }
#define DEBUG_PRINTLN(...) { Serial.println(__VA_ARGS__); }
#define RADIOLIB_DEBUG_PRINT(...) { RADIOLIB_DEBUG_PORT.print(__VA_ARGS__); }
#define RADIOLIB_DEBUG_PRINTLN(...) { RADIOLIB_DEBUG_PORT.println(__VA_ARGS__); }
#else
#define DEBUG_PRINT(...) {}
#define DEBUG_PRINTLN(...) {}
#define RADIOLIB_DEBUG_PRINT(...) {}
#define RADIOLIB_DEBUG_PRINTLN(...) {}
#endif
#ifdef RADIOLIB_VERBOSE
#define RADIOLIB_VERBOSE_PRINT(...) { RADIOLIB_DEBUG_PORT.print(__VA_ARGS__); }
#define RADIOLIB_VERBOSE_PRINTLN(...) { RADIOLIB_DEBUG_PORT.println(__VA_ARGS__); }
#else
#define RADIOLIB_VERBOSE_PRINT(...) {}
#define RADIOLIB_VERBOSE_PRINTLN(...) {}
#endif
/*
* Uncomment to enable god mode - all methods and member variables in all classes will be made public, thus making them accessible from Arduino code.
* Warning: Come on, it's called GOD mode - obviously only use this if you know what you're doing.
* Failure to heed the above warning may result in bricked module.
*/
//#define RADIOLIB_GODMODE
/*
* The following platforms do not support SoftwareSerial library.
*/
#if defined(ESP32) || defined(SAMD_SERIES) || defined(ARDUINO_ARCH_STM32) || defined(__SAM3X8E__)
#define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
#endif
/*!
@ -26,37 +69,37 @@
/*!
\brief Use SPI interface.
*/
#define USE_SPI 0x00
#define RADIOLIB_USE_SPI 0x00
/*!
\brief Use UART interface.
*/
#define USE_UART 0x01
#define RADIOLIB_USE_UART 0x01
/*!
\brief Use I2C interface.
*/
#define USE_I2C 0x02
#define RADIOLIB_USE_I2C 0x02
/*!
\brief Do not use any interrupts/GPIOs.
*/
#define INT_NONE 0x00
#define RADIOLIB_INT_NONE 0x00
/*!
\brief Use interrupt/GPIO 0.
*/
#define INT_0 0x01
#define RADIOLIB_INT_0 0x01
/*!
\brief Use interrupt/GPIO 1.
*/
#define INT_1 0x02
#define RADIOLIB_INT_1 0x02
/*!
\brief Use both interrupts/GPIOs.
*/
#define INT_BOTH 0x03
#define RADIOLIB_INT_BOTH 0x03
/*!
\}
@ -242,6 +285,21 @@
*/
#define ERR_WRONG_MODEM -20
/*!
\brief The supplied number of RSSI samples is invalid.
*/
#define ERR_INVALID_NUM_SAMPLES -21
/*!
\brief The supplied RSSI offset is invalid.
*/
#define ERR_INVALID_RSSI_OFFSET -22
/*!
\brief The supplied encoding is invalid.
*/
#define ERR_INVALID_ENCODING -23
// RF69-specific status codes
/*!

View file

@ -3,13 +3,16 @@
CC1101::CC1101(Module* module) : PhysicalLayer(CC1101_CRYSTAL_FREQ, CC1101_DIV_EXPONENT, CC1101_MAX_PACKET_LENGTH) {
_mod = module;
_packetLengthQueried = false;
_packetLengthConfig = CC1101_LENGTH_CONFIG_VARIABLE;
_syncWordLength = 2;
}
int16_t CC1101::begin(float freq, float br, float rxBw, float freqDev, int8_t power) {
int16_t CC1101::begin(float freq, float br, float rxBw, float freqDev, int8_t power, uint8_t preambleLength) {
// set module properties
_mod->SPIreadCommand = CC1101_CMD_READ;
_mod->SPIwriteCommand = CC1101_CMD_WRITE;
_mod->init(USE_SPI, INT_0);
_mod->init(RADIOLIB_USE_SPI, RADIOLIB_INT_0);
// try to find the CC1101 chip
uint8_t i = 0;
@ -20,15 +23,15 @@ int16_t CC1101::begin(float freq, float br, float rxBw, float freqDev, int8_t po
flagFound = true;
} else {
#ifdef RADIOLIB_DEBUG
Serial.print(F("CC1101 not found! ("));
Serial.print(i + 1);
Serial.print(F(" of 10 tries) CC1101_REG_VERSION == "));
RADIOLIB_DEBUG_PRINT(F("CC1101 not found! ("));
RADIOLIB_DEBUG_PRINT(i + 1);
RADIOLIB_DEBUG_PRINT(F(" of 10 tries) CC1101_REG_VERSION == "));
char buffHex[7];
sprintf(buffHex, "0x%04X", version);
Serial.print(buffHex);
Serial.print(F(", expected 0x0014"));
Serial.println();
RADIOLIB_DEBUG_PRINT(buffHex);
RADIOLIB_DEBUG_PRINT(F(", expected 0x0014"));
RADIOLIB_DEBUG_PRINTLN();
#endif
delay(1000);
i++;
@ -36,11 +39,11 @@ int16_t CC1101::begin(float freq, float br, float rxBw, float freqDev, int8_t po
}
if(!flagFound) {
DEBUG_PRINTLN(F("No CC1101 found!"));
RADIOLIB_DEBUG_PRINTLN(F("No CC1101 found!"));
SPI.end();
return(ERR_CHIP_NOT_FOUND);
} else {
DEBUG_PRINTLN(F("Found CC1101! (match by CC1101_REG_VERSION == 0x14)"));
RADIOLIB_DEBUG_PRINTLN(F("Found CC1101! (match by CC1101_REG_VERSION == 0x14)"));
}
// configure settings not accessible by API
@ -55,26 +58,42 @@ int16_t CC1101::begin(float freq, float br, float rxBw, float freqDev, int8_t po
return(state);
}
// configure bitrate
state = setBitRate(br);
if(state != ERR_NONE) {
return(state);
}
// configure default RX bandwidth
state = setRxBandwidth(rxBw);
if(state != ERR_NONE) {
return(state);
}
// configure default frequency deviation
state = setFrequencyDeviation(freqDev);
if(state != ERR_NONE) {
return(state);
}
// configure default TX output power
state = setOutputPower(power);
if(state != ERR_NONE) {
return(state);
}
// set default packet length mode
state = variablePacketLengthMode();
if (state != ERR_NONE) {
return(state);
}
// configure default preamble lenght
state = setPreambleLength(preambleLength);
if (state != ERR_NONE) {
return(state);
}
// flush FIFOs
SPIsendCommand(CC1101_CMD_FLUSH_RX);
SPIsendCommand(CC1101_CMD_FLUSH_TX);
@ -162,7 +181,7 @@ int16_t CC1101::receiveDirect() {
int16_t CC1101::packetMode() {
int16_t state = SPIsetRegValue(CC1101_REG_PKTCTRL1, CC1101_CRC_AUTOFLUSH_OFF | CC1101_APPEND_STATUS_ON | CC1101_ADR_CHK_NONE, 3, 0);
state |= SPIsetRegValue(CC1101_REG_PKTCTRL0, CC1101_WHITE_DATA_OFF | CC1101_PKT_FORMAT_NORMAL, 6, 4);
state |= SPIsetRegValue(CC1101_REG_PKTCTRL0, CC1101_CRC_ON | CC1101_LENGTH_CONFIG_VARIABLE, 2, 0);
state |= SPIsetRegValue(CC1101_REG_PKTCTRL0, CC1101_CRC_ON | _packetLengthConfig, 2, 0);
return(state);
}
@ -192,8 +211,10 @@ int16_t CC1101::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
return(state);
}
// write packet length
SPIwriteRegister(CC1101_REG_FIFO, len);
// optionally write packet length
if (_packetLengthConfig == CC1101_LENGTH_CONFIG_VARIABLE) {
SPIwriteRegister(CC1101_REG_FIFO, len);
}
// check address filtering
uint8_t filter = SPIgetRegValue(CC1101_REG_PKTCTRL1, 1, 0);
@ -428,13 +449,74 @@ int16_t CC1101::setOutputPower(int8_t power) {
return(SPIsetRegValue(CC1101_REG_PATABLE, powerRaw));
}
int16_t CC1101::setSyncWord(uint8_t syncH, uint8_t syncL) {
// set sync word
int16_t state = SPIsetRegValue(CC1101_REG_SYNC1, syncH);
state |= SPIsetRegValue(CC1101_REG_SYNC0, syncL);
return(state);
int16_t CC1101::setSyncWord(uint8_t* syncWord, uint8_t len, uint8_t maxErrBits) {
if((maxErrBits > 1) || (len > 2)) {
return(ERR_INVALID_SYNC_WORD);
}
// sync word must not contain value 0x00
for(uint8_t i = 0; i < len; i++) {
if(syncWord[i] == 0x00) {
return(ERR_INVALID_SYNC_WORD);
}
}
_syncWordLength = len;
// enable sync word filtering
int16_t state = enableSyncWordFiltering(maxErrBits);
if (state != ERR_NONE) {
return(state);
}
// set sync word register
_mod->SPIwriteRegisterBurst(CC1101_REG_SYNC1, syncWord, len);
return(ERR_NONE);
}
int16_t CC1101::setSyncWord(uint8_t syncH, uint8_t syncL, uint8_t maxErrBits) {
uint8_t syncWord[] = { syncH, syncL };
return(setSyncWord(syncWord, sizeof(syncWord), maxErrBits));
}
int16_t CC1101::setPreambleLength(uint8_t preambleLength) {
// check allowed values
uint8_t value;
switch(preambleLength){
case 2:
value = CC1101_NUM_PREAMBLE_2;
break;
case 3:
value = CC1101_NUM_PREAMBLE_3;
break;
case 4:
value = CC1101_NUM_PREAMBLE_4;
break;
case 6:
value = CC1101_NUM_PREAMBLE_6;
break;
case 8:
value = CC1101_NUM_PREAMBLE_8;
break;
case 12:
value = CC1101_NUM_PREAMBLE_12;
break;
case 16:
value = CC1101_NUM_PREAMBLE_16;
break;
case 24:
value = CC1101_NUM_PREAMBLE_24;
break;
default:
return(ERR_INVALID_PREAMBLE_LENGTH);
}
return SPIsetRegValue(CC1101_REG_MDMCFG1, value, 6, 4);
}
int16_t CC1101::setNodeAddress(uint8_t nodeAddr, uint8_t numBroadcastAddrs) {
if(!(numBroadcastAddrs > 0) && (numBroadcastAddrs <= 2)) {
return(ERR_INVALID_NUM_BROAD_ADDRS);
@ -477,13 +559,96 @@ uint8_t CC1101::getLQI() {
size_t CC1101::getPacketLength(bool update) {
if(!_packetLengthQueried && update) {
_packetLength = _mod->SPIreadRegister(CC1101_REG_FIFO);
if (_packetLengthConfig == CC1101_LENGTH_CONFIG_VARIABLE) {
_packetLength = _mod->SPIreadRegister(CC1101_REG_FIFO);
} else {
_packetLength = _mod->SPIreadRegister(CC1101_REG_PKTLEN);
}
_packetLengthQueried = true;
}
return(_packetLength);
}
int16_t CC1101::fixedPacketLengthMode(uint8_t len) {
return(setPacketMode(CC1101_LENGTH_CONFIG_FIXED, len));
}
int16_t CC1101::variablePacketLengthMode(uint8_t maxLen) {
return(setPacketMode(CC1101_LENGTH_CONFIG_VARIABLE, maxLen));
}
int16_t CC1101::enableSyncWordFiltering(uint8_t maxErrBits) {
if (maxErrBits > 1) {
return(ERR_INVALID_SYNC_WORD);
}
if (maxErrBits == 0) {
if (_syncWordLength == 1) {
// in 16 bit sync word, expect all 16 bits
return(SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_SYNC_MODE_16_16, 2, 0));
} else {
// there's no 32 of 32 case, so we resort to 30 of 32 bits required
return(SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_SYNC_MODE_30_32, 2, 0));
}
}
if (maxErrBits == 1) {
if (_syncWordLength == 1) {
// in 16 bit sync word, expect at least 15 bits
return(SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_SYNC_MODE_15_16, 2, 0));
} else {
// in 32 bits sync word (16 + 16), expect 30 of 32 to match
return(SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_SYNC_MODE_30_32, 2, 0));
}
}
return(ERR_UNKNOWN);
}
int16_t CC1101::disableSyncWordFiltering() {
return(SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_SYNC_MODE_NONE, 2, 0));
}
int16_t CC1101::setCrcFiltering(bool crcOn) {
if (crcOn == true) {
return(SPIsetRegValue(CC1101_REG_PKTCTRL0, CC1101_CRC_ON, 2, 2));
} else {
return(SPIsetRegValue(CC1101_REG_PKTCTRL0, CC1101_CRC_OFF, 2, 2));
}
}
int16_t CC1101::setPromiscuousMode(bool promiscuous) {
int16_t state = ERR_NONE;
if (_promiscuous == promiscuous) {
return(state);
}
if (promiscuous == true) {
// disable preamble and sync word filtering and insertion
state = disableSyncWordFiltering();
if (state != ERR_NONE) {
return(state);
}
// disable CRC filtering
state = setCrcFiltering(false);
} else {
// enable preamble and sync word filtering and insertion
state = enableSyncWordFiltering();
if (state != ERR_NONE) {
return(state);
}
// enable CRC filtering
state = setCrcFiltering(true);
}
return(state);
}
int16_t CC1101::config() {
// enable automatic frequency synthesizer calibration
int16_t state = SPIsetRegValue(CC1101_REG_MCSM0, CC1101_FS_AUTOCAL_IDLE_TO_RXTX, 5, 4);
@ -536,6 +701,29 @@ void CC1101::getExpMant(float target, uint16_t mantOffset, uint8_t divExp, uint8
}
}
int16_t CC1101::setPacketMode(uint8_t mode, uint8_t len) {
// check length
if (len > CC1101_MAX_PACKET_LENGTH) {
return(ERR_PACKET_TOO_LONG);
}
// set to fixed packet length
int16_t state = _mod->SPIsetRegValue(CC1101_REG_PKTCTRL0, mode, 7, 7);
if (state != ERR_NONE) {
return(state);
}
// set length to register
state = _mod->SPIsetRegValue(CC1101_REG_PKTLEN, len);
if (state != ERR_NONE) {
return(state);
}
// update the cached value
_packetLengthConfig = mode;
return(state);
}
int16_t CC1101::SPIgetRegValue(uint8_t reg, uint8_t msb, uint8_t lsb) {
// status registers require special command
if(reg > CC1101_REG_TEST0) {

View file

@ -1,10 +1,10 @@
#ifndef _RADIOLIB_CC1101_H
#define _RADIOLIB_CC1101_H
#include "TypeDef.h"
#include "Module.h"
#include "../../TypeDef.h"
#include "../../Module.h"
#include "../protocols/PhysicalLayer.h"
#include "../../protocols/PhysicalLayer/PhysicalLayer.h"
// CC1101 physical layer properties
#define CC1101_CRYSTAL_FREQ 26.0
@ -237,7 +237,7 @@
#define CC1101_MOD_FORMAT_MFSK 0b01110000 // 6 4 MFSK - only for data rates above 26 kBaud
#define CC1101_MANCHESTER_EN_OFF 0b00000000 // 3 3 Manchester encoding: disabled (default)
#define CC1101_MANCHESTER_EN_ON 0b00001000 // 3 3 enabled
#define CC1101_SYNC_MODE_NONE 0b00000000 // 2 0 synchronization: no preamble sync
#define CC1101_SYNC_MODE_NONE 0b00000000 // 2 0 synchronization: no preamble/sync
#define CC1101_SYNC_MODE_15_16 0b00000001 // 2 0 15/16 sync word bits
#define CC1101_SYNC_MODE_16_16 0b00000010 // 2 0 16/16 sync word bits (default)
#define CC1101_SYNC_MODE_30_32 0b00000011 // 2 0 30/32 sync word bits
@ -530,9 +530,11 @@ class CC1101: public PhysicalLayer {
\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);
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);
/*!
\brief Blocking binary transmit method.
@ -694,9 +696,33 @@ class CC1101: public PhysicalLayer {
\param syncL LSB of the sync word.
\param maxErrBits Maximum allowed number of bit errors in received sync word. Defaults to 0.
\returns \ref status_codes
*/
int16_t setSyncWord(uint8_t syncH, uint8_t syncL);
int16_t setSyncWord(uint8_t syncH, uint8_t syncL, uint8_t maxErrBits = 0);
/*!
\brief Sets 1 or 2 bytes of sync word.
\param syncWord Pointer to the array of sync word bytes.
\param len Sync word length in bytes.
\param maxErrBits Maximum allowed number of bit errors in received sync word. Defaults to 0.
\returns \ref status_codes
*/
int16_t setSyncWord(uint8_t* syncWord, uint8_t len, uint8_t maxErrBits = 0);
/*!
\brief Sets preamble length.
\param preambleLength Preamble length to be set (in bytes), allowed values: 2, 3, 4, 6, 8, 12, 16, 24
\returns \ref status_codes
*/
int16_t setPreambleLength(uint8_t preambleLength);
/*!
\brief Sets node and broadcast addresses. Calling this method will also enable address filtering.
@ -739,7 +765,61 @@ class CC1101: public PhysicalLayer {
*/
size_t getPacketLength(bool update = true);
/*!
\brief Set modem in fixed packet length mode.
\param len Packet length.
\returns \ref status_codes
*/
int16_t fixedPacketLengthMode(uint8_t len = CC1101_MAX_PACKET_LENGTH);
/*!
\brief Set modem in variable packet length mode.
\param len Maximum packet length.
\returns \ref status_codes
*/
int16_t variablePacketLengthMode(uint8_t maxLen = CC1101_MAX_PACKET_LENGTH);
/*!
\brief Enable sync word filtering and generation.
\param numBits Sync word length in bits.
\returns \ref status_codes
*/
int16_t enableSyncWordFiltering(uint8_t maxErrBits = 0);
/*!
\brief Disable preamble and sync word filtering and generation.
\returns \ref status_codes
*/
int16_t disableSyncWordFiltering();
/*!
\brief Enable CRC filtering and generation.
\param crcOn Set or unset promiscuous mode.
\returns \ref status_codes
*/
int16_t setCrcFiltering(bool crcOn = true);
/*!
\brief Set modem in "sniff" mode: no packet filtering (e.g., no preamble, sync word, address, CRC).
\param promiscuous Set or unset promiscuous mode.
\returns \ref status_codes
*/
int16_t setPromiscuousMode(bool promiscuous = true);
#ifndef RADIOLIB_GODMODE
private:
#endif
Module* _mod;
float _freq;
@ -748,10 +828,16 @@ class CC1101: public PhysicalLayer {
size_t _packetLength;
bool _packetLengthQueried;
uint8_t _packetLengthConfig;
bool _promiscuous;
uint8_t _syncWordLength;
int16_t config();
int16_t directMode();
void getExpMant(float target, uint16_t mantOffset, uint8_t divExp, uint8_t expMax, uint8_t& exp, uint8_t& mant);
int16_t setPacketMode(uint8_t mode, uint8_t len);
// SPI read overrides to set bit for burst write and status registers access
int16_t SPIgetRegValue(uint8_t reg, uint8_t msb = 7, uint8_t lsb = 0);

View file

@ -9,7 +9,7 @@ int16_t ESP8266::begin(long speed) {
// set module properties
_mod->AtLineFeed = "\r\n";
_mod->baudrate = speed;
_mod->init(USE_UART, INT_NONE);
_mod->init(RADIOLIB_USE_UART, RADIOLIB_INT_NONE);
// empty UART buffer (garbage data)
_mod->ATemptyBuffer();
@ -52,8 +52,12 @@ int16_t ESP8266::join(const char* ssid, const char* password) {
// build AT command
const char* atStr = "AT+CWJAP_CUR=\"";
uint8_t cmdLen = strlen(atStr) + strlen(ssid) + strlen(password) + 4;
char* cmd = new char[cmdLen + 1];
#ifdef RADIOLIB_STATIC_ONLY
char cmd[RADIOLIB_STATIC_ARRAY_SIZE];
#else
uint8_t cmdLen = strlen(atStr) + strlen(ssid) + strlen(password) + 4;
char* cmd = new char[cmdLen + 1];
#endif
strcpy(cmd, atStr);
strcat(cmd, ssid);
strcat(cmd, "\",\"");
@ -62,7 +66,9 @@ int16_t ESP8266::join(const char* ssid, const char* password) {
// send command
bool res = _mod->ATsendCommand(cmd);
delete[] cmd;
#ifndef RADIOLIB_STATIC_ONLY
delete[] cmd;
#endif
if(!res) {
return(ERR_AT_FAILED);
}
@ -87,7 +93,11 @@ int16_t ESP8266::openTransportConnection(const char* host, const char* protocol,
if((strcmp(protocol, "TCP") == 0) && (tcpKeepAlive > 0)) {
cmdLen += strlen(tcpKeepAliveStr) + 1;
}
char* cmd = new char[cmdLen + 1];
#ifdef RADIOLIB_STATIC_ONLY
char cmd[RADIOLIB_STATIC_ARRAY_SIZE];
#else
char* cmd = new char[cmdLen + 1];
#endif
strcpy(cmd, atStr);
strcat(cmd, protocol);
strcat(cmd, "\",\"");
@ -101,7 +111,9 @@ int16_t ESP8266::openTransportConnection(const char* host, const char* protocol,
// send command
bool res = _mod->ATsendCommand(cmd);
delete[] cmd;
#ifndef RADIOLIB_STATIC_ONLY
delete[] cmd;
#endif
if(!res) {
return(ERR_AT_FAILED);
}
@ -122,13 +134,19 @@ int16_t ESP8266::send(const char* data) {
char lenStr[8];
itoa(strlen(data), lenStr, 10);
const char* atStr = "AT+CIPSEND=";
char* cmd = new char[strlen(atStr) + strlen(lenStr) + 1];
#ifdef RADIOLIB_STATIC_ONLY
char cmd[RADIOLIB_STATIC_ARRAY_SIZE];
#else
char* cmd = new char[strlen(atStr) + strlen(lenStr) + 1];
#endif
strcpy(cmd, atStr);
strcat(cmd, lenStr);
// send command
bool res = _mod->ATsendCommand(cmd);
delete[] cmd;
#ifndef RADIOLIB_STATIC_ONLY
delete[] cmd;
#endif
if(!res) {
return(ERR_AT_FAILED);
}
@ -146,13 +164,19 @@ int16_t ESP8266::send(uint8_t* data, uint32_t len) {
char lenStr[8];
itoa(len, lenStr, 10);
const char atStr[] = "AT+CIPSEND=";
char* cmd = new char[strlen(atStr) + strlen(lenStr) + 1];
#ifdef RADIOLIB_STATIC_ONLY
char cmd[RADIOLIB_STATIC_ARRAY_SIZE];
#else
char* cmd = new char[strlen(atStr) + strlen(lenStr) + 1];
#endif
strcpy(cmd, atStr);
strcat(cmd, lenStr);
// send command
bool res = _mod->ATsendCommand(cmd);
delete[] cmd;
#ifndef RADIOLIB_STATIC_ONLY
delete[] cmd;
#endif
if(!res) {
return(ERR_AT_FAILED);
}
@ -173,7 +197,7 @@ size_t ESP8266::receive(uint8_t* data, size_t len, uint32_t timeout) {
while((millis() - start < timeout) && (i < len)) {
while(_mod->ModuleSerial->available() > 0) {
uint8_t b = _mod->ModuleSerial->read();
DEBUG_PRINT(b);
RADIOLIB_DEBUG_PRINT(b);
data[i] = b;
i++;
}

View file

@ -1,9 +1,9 @@
#if !defined(_RADIOLIB_ESP8266_H) && !defined(ESP8266)
#define _RADIOLIB_ESP8266_H
#include "Module.h"
#include "../../Module.h"
#include "../protocols/TransportLayer.h"
#include "../../protocols/TransportLayer/TransportLayer.h"
/*!
\class ESP8266
@ -54,7 +54,9 @@ class ESP8266: public TransportLayer {
size_t receive(uint8_t* data, size_t len, uint32_t timeout = 10000);
size_t getNumBytes(uint32_t timeout = 10000, size_t minBytes = 10);
#ifndef RADIOLIB_GODMODE
private:
#endif
Module* _mod;
};

View file

@ -7,5 +7,5 @@ HC05::HC05(Module* mod) : ISerial(mod) {
void HC05::begin(long speed) {
// set module properties
_mod->baudrate = speed;
_mod->init(USE_UART, INT_NONE);
_mod->init(RADIOLIB_USE_UART, RADIOLIB_INT_NONE);
}

View file

@ -1,7 +1,7 @@
#ifndef _RADIOLIB_HC05_H
#define _RADIOLIB_HC05_H
#include "ISerial.h"
#include "../../ISerial.h"
/*!
\class HC05

View file

@ -8,5 +8,5 @@ void JDY08::begin(long speed) {
// set module properties
_mod->AtLineFeed = "";
_mod->baudrate = speed;
_mod->init(USE_UART, INT_NONE);
_mod->init(RADIOLIB_USE_UART, RADIOLIB_INT_NONE);
}

View file

@ -1,7 +1,7 @@
#ifndef _RADIOLIB_JDY08_H
#define _RADIOLIB_JDY08_H
#include "ISerial.h"
#include "../../ISerial.h"
/*!
\class JDY08

View file

@ -3,12 +3,18 @@
RF69::RF69(Module* module) : PhysicalLayer(RF69_CRYSTAL_FREQ, RF69_DIV_EXPONENT, RF69_MAX_PACKET_LENGTH) {
_mod = module;
_tempOffset = 0;
_packetLengthQueried = false;
_packetLengthConfig = RF69_PACKET_FORMAT_VARIABLE;
_promiscuous = false;
_syncWordLength = 2;
}
int16_t RF69::begin(float freq, float br, float rxBw, float freqDev, int8_t power) {
// set module properties
_mod->init(USE_SPI, INT_0);
_mod->init(RADIOLIB_USE_SPI, RADIOLIB_INT_0);
// try to find the RF69 chip
uint8_t i = 0;
@ -19,15 +25,15 @@ int16_t RF69::begin(float freq, float br, float rxBw, float freqDev, int8_t powe
flagFound = true;
} else {
#ifdef RADIOLIB_DEBUG
Serial.print(F("RF69 not found! ("));
Serial.print(i + 1);
Serial.print(F(" of 10 tries) RF69_REG_VERSION == "));
RADIOLIB_DEBUG_PRINT(F("RF69 not found! ("));
RADIOLIB_DEBUG_PRINT(i + 1);
RADIOLIB_DEBUG_PRINT(F(" of 10 tries) RF69_REG_VERSION == "));
char buffHex[7];
sprintf(buffHex, "0x%04X", version);
Serial.print(buffHex);
Serial.print(F(", expected 0x0024"));
Serial.println();
RADIOLIB_DEBUG_PRINT(buffHex);
RADIOLIB_DEBUG_PRINT(F(", expected 0x0024"));
RADIOLIB_DEBUG_PRINTLN();
#endif
delay(1000);
i++;
@ -35,11 +41,11 @@ int16_t RF69::begin(float freq, float br, float rxBw, float freqDev, int8_t powe
}
if(!flagFound) {
DEBUG_PRINTLN(F("No RF69 found!"));
RADIOLIB_DEBUG_PRINTLN(F("No RF69 found!"));
SPI.end();
return(ERR_CHIP_NOT_FOUND);
} else {
DEBUG_PRINTLN(F("Found RF69! (match by RF69_REG_VERSION == 0x24)"));
RADIOLIB_DEBUG_PRINTLN(F("Found RF69! (match by RF69_REG_VERSION == 0x24)"));
}
// configure settings not accessible by API
@ -54,30 +60,40 @@ int16_t RF69::begin(float freq, float br, float rxBw, float freqDev, int8_t powe
return(state);
}
// configure bitrate
_rxBw = 125.0;
state = setBitRate(br);
if(state != ERR_NONE) {
return(state);
}
// configure default RX bandwidth
state = setRxBandwidth(rxBw);
if(state != ERR_NONE) {
return(state);
}
// configure default frequency deviation
state = setFrequencyDeviation(freqDev);
if(state != ERR_NONE) {
return(state);
}
// configure default TX output power
state = setOutputPower(power);
if(state != ERR_NONE) {
return(state);
}
// set default packet length mode
state = variablePacketLengthMode();
if (state != ERR_NONE) {
return(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);
state = setSyncWord(syncWord, sizeof(syncWord));
if(state != ERR_NONE) {
return(state);
}
@ -250,6 +266,11 @@ int16_t RF69::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
// set packet length
_mod->SPIwriteRegister(RF69_REG_FIFO, len);
// optionally write packet length
if (_packetLengthConfig == RF69_PACKET_FORMAT_VARIABLE) {
_mod->SPIwriteRegister(RF69_REG_FIFO, len);
}
// check address filtering
uint8_t filter = _mod->SPIgetRegValue(RF69_REG_PACKET_CONFIG_1, 2, 1);
if((filter == RF69_ADDRESS_FILTERING_NODE) || (filter == RF69_ADDRESS_FILTERING_NODE_BROADCAST)) {
@ -268,6 +289,12 @@ 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);
}
// get packet length
size_t length = len;
if(len == RF69_MAX_PACKET_LENGTH) {
@ -490,13 +517,14 @@ int16_t RF69::setSyncWord(uint8_t* syncWord, size_t len, uint8_t maxErrBits) {
}
}
// enable sync word recognition
int16_t state = _mod->SPIsetRegValue(RF69_REG_SYNC_CONFIG, RF69_SYNC_ON | RF69_FIFO_FILL_CONDITION_SYNC | (len - 1) << 3 | maxErrBits, 7, 0);
if(state != ERR_NONE) {
_syncWordLength = len;
int16_t state = enableSyncWordFiltering(maxErrBits);
if (state != ERR_NONE) {
return(state);
}
// set sync word
// set sync word register
_mod->SPIwriteRegisterBurst(RF69_REG_SYNC_VALUE_1, syncWord, len);
return(ERR_NONE);
}
@ -563,13 +591,90 @@ int16_t RF69::getTemperature() {
size_t RF69::getPacketLength(bool update) {
if(!_packetLengthQueried && update) {
_packetLength = _mod->SPIreadRegister(RF69_REG_FIFO);
if (_packetLengthConfig == RF69_PACKET_FORMAT_VARIABLE) {
_packetLength = _mod->SPIreadRegister(RF69_REG_FIFO);
} else {
_packetLength = _mod->SPIreadRegister(RF69_REG_PAYLOAD_LENGTH);
}
_packetLengthQueried = true;
}
return(_packetLength);
}
int16_t RF69::fixedPacketLengthMode(uint8_t len) {
return(setPacketMode(RF69_PACKET_FORMAT_FIXED, len));
}
int16_t RF69::variablePacketLengthMode(uint8_t maxLen) {
return(setPacketMode(RF69_PACKET_FORMAT_VARIABLE, 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);
}
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);
}
// 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);
}
int16_t RF69::setCrcFiltering(bool crcOn) {
if (crcOn == true) {
return(_mod->SPIsetRegValue(RF69_REG_PACKET_CONFIG_1, RF69_CRC_ON, 4, 4));
} else {
return(_mod->SPIsetRegValue(RF69_REG_PACKET_CONFIG_1, RF69_CRC_OFF, 4, 4));
}
}
int16_t RF69::setPromiscuousMode(bool promiscuous) {
int16_t state = ERR_NONE;
if (_promiscuous == promiscuous) {
return(state);
}
if (promiscuous == true) {
// disable preamble and sync word filtering and insertion
state = disableSyncWordFiltering();
if (state != ERR_NONE) {
return(state);
}
// disable CRC filtering
state = setCrcFiltering(false);
} else {
// enable preamble and sync word filtering and insertion
state = enableSyncWordFiltering();
if (state != ERR_NONE) {
return(state);
}
// enable CRC filtering
state = setCrcFiltering(true);
}
return(state);
}
int16_t RF69::config() {
int16_t state = ERR_NONE;
@ -649,6 +754,29 @@ int16_t RF69::config() {
return(ERR_NONE);
}
int16_t RF69::setPacketMode(uint8_t mode, uint8_t len) {
// check length
if (len > RF69_MAX_PACKET_LENGTH) {
return(ERR_PACKET_TOO_LONG);
}
// set to fixed packet length
int16_t state = _mod->SPIsetRegValue(RF69_REG_PACKET_CONFIG_1, mode, 7, 7);
if (state != ERR_NONE) {
return(state);
}
// set length to register
state = _mod->SPIsetRegValue(RF69_REG_PAYLOAD_LENGTH, len);
if (state != ERR_NONE) {
return(state);
}
// update the cached value
_packetLengthConfig = mode;
return(state);
}
int16_t RF69::setMode(uint8_t mode) {
return(_mod->SPIsetRegValue(RF69_REG_OP_MODE, mode, 4, 2));
}

View file

@ -1,10 +1,10 @@
#ifndef _RADIOLIB_RF69_H
#define _RADIOLIB_RF69_H
#include "TypeDef.h"
#include "Module.h"
#include "../../TypeDef.h"
#include "../../Module.h"
#include "../protocols/PhysicalLayer.h"
#include "../../protocols/PhysicalLayer/PhysicalLayer.h"
// RF69 physical layer properties
#define RF69_CRYSTAL_FREQ 32.0
@ -646,7 +646,7 @@ class RF69: public PhysicalLayer {
int16_t setOutputPower(int8_t power);
/*!
\brief Sets sync word. Up to 8 bytes can be set as snyc word.
\brief Sets sync word. Up to 8 bytes can be set as sync word.
\param syncWord Pointer to the array of sync word bytes.
@ -697,7 +697,7 @@ class RF69: public PhysicalLayer {
*/
int16_t getTemperature();
/*!
/*!
\brief Query modem for the packet length of received payload.
\param update Update received packet length. Will return cached value when set to false.
@ -706,7 +706,61 @@ class RF69: public PhysicalLayer {
*/
size_t getPacketLength(bool update = true);
/*!
\brief Set modem in fixed packet length mode.
\param len Packet length.
\returns \ref status_codes
*/
int16_t fixedPacketLengthMode(uint8_t len = RF69_MAX_PACKET_LENGTH);
/*!
\brief Set modem in variable packet length mode.
\param len Maximum packet length.
\returns \ref status_codes
*/
int16_t variablePacketLengthMode(uint8_t maxLen = RF69_MAX_PACKET_LENGTH);
/*!
\brief Enable sync word filtering and generation.
\param numBits Sync word length in bits.
\returns \ref status_codes
*/
int16_t enableSyncWordFiltering(uint8_t maxErrBits = 0);
/*!
\brief Disable preamble and sync word filtering and generation.
\returns \ref status_codes
*/
int16_t disableSyncWordFiltering();
/*!
\brief Enable CRC filtering and generation.
\param crcOn Set or unset promiscuous mode.
\returns \ref status_codes
*/
int16_t setCrcFiltering(bool crcOn = true);
/*!
\brief Set modem in "sniff" mode: no packet filtering (e.g., no preamble, sync word, address, CRC).
\param promiscuous Set or unset promiscuous mode.
\returns \ref status_codes
*/
int16_t setPromiscuousMode(bool promiscuous = true);
#ifndef RADIOLIB_GODMODE
protected:
#endif
Module* _mod;
float _br;
@ -715,11 +769,19 @@ class RF69: public PhysicalLayer {
size_t _packetLength;
bool _packetLengthQueried;
uint8_t _packetLengthConfig;
bool _promiscuous;
uint8_t _syncWordLength;
int16_t config();
int16_t directMode();
int16_t setPacketMode(uint8_t mode, uint8_t len);
#ifndef RADIOLIB_GODMODE
private:
#endif
int16_t setMode(uint8_t mode);
void clearIRQFlags();
};

View file

@ -1,10 +1,10 @@
#ifndef _RADIOLIB_RFM95_H
#define _RADIOLIB_RFM95_H
#include "TypeDef.h"
#include "Module.h"
#include "SX127x.h"
#include "SX1278.h"
#include "../../TypeDef.h"
#include "../../Module.h"
#include "../SX127x/SX127x.h"
#include "../SX127x/SX1278.h"
// SX127X_REG_VERSION
#define RFM95_CHIP_VERSION 0x11
@ -16,59 +16,61 @@
*/
class RFM95: public SX1278 {
public:
// constructor
/*!
\brief Default constructor. Called from Arduino sketch when creating new LoRa instance.
\param mod Instance of Module that will be used to communicate with the %LoRa chip.
*/
RFM95(Module* mod);
// basic methods
/*!
\brief %LoRa modem initialization method. Must be called at least once from Arduino sketch to initialize the module.
\param freq Carrier frequency in MHz. Allowed values range from 868.0 MHz to 915.0 MHz.
\param bw %LoRa link bandwidth in kHz. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz.
\param sf %LoRa link spreading factor. Allowed values range from 6 to 12.
\param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8.
\param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks.
\param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm.
\param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA.
\param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA.
Set to 0 to disable OCP (not recommended).
\param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number.
\param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number.
Allowed values range from 6 to 65535.
\param gain Gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain.
Set to 0 to enable automatic gain control (recommended).
\returns \ref status_codes
*/
int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 17, uint8_t currentLimit = 100, uint16_t preambleLength = 8, uint8_t gain = 0);
// configuration methods
/*!
\brief Sets carrier frequency. Allowed values range from 868.0 MHz to 915.0 MHz.
\param freq Carrier frequency to be set in MHz.
\returns \ref status_codes
*/
int16_t setFrequency(float freq);
#ifndef RADIOLIB_GODMODE
private:
#endif
};
#endif

View file

@ -1,10 +1,10 @@
#ifndef _RADIOLIB_RFM96_H
#define _RADIOLIB_RFM96_H
#include "TypeDef.h"
#include "Module.h"
#include "SX127x.h"
#include "SX1278.h"
#include "../../TypeDef.h"
#include "../../Module.h"
#include "../SX127x/SX127x.h"
#include "../SX127x/SX1278.h"
// SX127X_REG_VERSION
#define RFM9X_CHIP_VERSION 0x12 // according to datasheet, this should be 0x11, but all modules seem to have 0x12
@ -16,59 +16,61 @@
*/
class RFM96: public SX1278 {
public:
// constructor
/*!
\brief Default constructor. Called from Arduino sketch when creating new LoRa instance.
\param mod Instance of Module that will be used to communicate with the %LoRa chip.
*/
RFM96(Module* mod);
// basic methods
/*!
\brief %LoRa modem initialization method. Must be called at least once from Arduino sketch to initialize the module.
\param freq Carrier frequency in MHz. Allowed values range from 433.0 MHz to 470.0 MHz.
\param bw %LoRa link bandwidth in kHz. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz.
\param sf %LoRa link spreading factor. Allowed values range from 6 to 12.
\param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8.
\param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks.
\param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm.
\param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA.
\param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA.
Set to 0 to disable OCP (not recommended).
\param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number.
\param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number.
Allowed values range from 6 to 65535.
\param gain Gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain.
Set to 0 to enable automatic gain control (recommended).
\returns \ref status_codes
*/
int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 17, uint8_t currentLimit = 100, uint16_t preambleLength = 8, uint8_t gain = 0);
// configuration methods
/*!
\brief Sets carrier frequency. Allowed values range from 433.0 MHz to 470.0 MHz.
\param freq Carrier frequency to be set in MHz.
\returns \ref status_codes
*/
int16_t setFrequency(float freq);
#ifndef RADIOLIB_GODMODE
private:
#endif
};
/*!

View file

@ -1,10 +1,10 @@
#ifndef _RADIOLIB_RFM97_H
#define _RADIOLIB_RFM97_H
#include "TypeDef.h"
#include "Module.h"
#include "SX127x.h"
#include "SX1278.h"
#include "../../TypeDef.h"
#include "../../Module.h"
#include "../SX127x/SX127x.h"
#include "../SX127x/SX1278.h"
#include "RFM95.h"
/*!
@ -14,28 +14,31 @@
*/
class RFM97: public RFM95 {
public:
// constructor
/*!
\brief Default constructor. Called from Arduino sketch when creating new LoRa instance.
\param mod Instance of Module that will be used to communicate with the %LoRa chip.
*/
RFM97(Module* mod);
// configuration methods
/*!
\brief Sets %LoRa link spreading factor. Allowed values range from 6 to 9. Only available in %LoRa mode.
\param sf %LoRa link spreading factor to be set.
\returns \ref status_codes
*/
int16_t setSpreadingFactor(uint8_t sf);
#ifndef RADIOLIB_GODMODE
private:
#endif
};
#endif

View file

@ -6,8 +6,8 @@ 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(USE_SPI, INT_BOTH);
_mod->init(RADIOLIB_USE_SPI, RADIOLIB_INT_BOTH);
// try to find the SX1231 chip
uint8_t i = 0;
bool flagFound = false;
@ -18,69 +18,79 @@ int16_t SX1231::begin(float freq, float br, float rxBw, float freqDev, int8_t po
_chipRevision = version;
} else {
#ifdef RADIOLIB_DEBUG
Serial.print(F("SX127x not found! ("));
Serial.print(i + 1);
Serial.print(F(" of 10 tries) SX127X_REG_VERSION == "));
RADIOLIB_DEBUG_PRINT(F("SX127x not found! ("));
RADIOLIB_DEBUG_PRINT(i + 1);
RADIOLIB_DEBUG_PRINT(F(" of 10 tries) SX127X_REG_VERSION == "));
char buffHex[7];
sprintf(buffHex, "0x%04X", version);
Serial.print(buffHex);
Serial.print(F(", expected 0x0021 / 0x0022 / 0x0023"));
Serial.println();
RADIOLIB_DEBUG_PRINT(buffHex);
RADIOLIB_DEBUG_PRINT(F(", expected 0x0021 / 0x0022 / 0x0023"));
RADIOLIB_DEBUG_PRINTLN();
#endif
delay(1000);
i++;
}
}
if(!flagFound) {
DEBUG_PRINTLN(F("No SX1231 found!"));
RADIOLIB_DEBUG_PRINTLN(F("No SX1231 found!"));
SPI.end();
return(ERR_CHIP_NOT_FOUND);
} else {
DEBUG_PRINTLN(F("Found SX1231!"));
RADIOLIB_DEBUG_PRINTLN(F("Found SX1231!"));
}
// configure settings not accessible by API
int16_t state = config();
if(state != ERR_NONE) {
return(state);
}
// configure publicly accessible settings
state = setFrequency(freq);
if(state != ERR_NONE) {
return(state);
}
// configure bitrate
_rxBw = 125.0;
state = setBitRate(br);
if(state != ERR_NONE) {
return(state);
}
// configure default RX bandwidth
state = setRxBandwidth(rxBw);
if(state != ERR_NONE) {
return(state);
}
// configure default frequency deviation
state = setFrequencyDeviation(freqDev);
if(state != ERR_NONE) {
return(state);
}
// configure default TX output power
state = setOutputPower(power);
if(state != ERR_NONE) {
return(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);
}
// set default packet length mode
state = variablePacketLengthMode();
if (state != ERR_NONE) {
return(state);
}
// SX1231 V2a only
if(_chipRevision == SX1231_CHIP_REVISION_2_A) {
// modify default OOK threshold value
@ -88,13 +98,13 @@ int16_t SX1231::begin(float freq, float br, float rxBw, float freqDev, int8_t po
if(state != ERR_NONE) {
return(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);
}
}
return(ERR_NONE);
}

View file

@ -1,9 +1,9 @@
#ifndef _RADIOLIB_SX1231_H
#define _RADIOLIB_SX1231_H
#include "TypeDef.h"
#include "Module.h"
#include "RF69.h"
#include "../../TypeDef.h"
#include "../../Module.h"
#include "../RF69/RF69.h"
#define SX1231_CHIP_REVISION_2_A 0x21
#define SX1231_CHIP_REVISION_2_B 0x22
@ -46,7 +46,9 @@ class SX1231: public RF69 {
*/
int16_t begin(float freq = 434.0, float br = 48.0, float rxBw = 125.0, float freqDev = 50.0, int8_t power = 13);
#ifndef RADIOLIB_GODMODE
private:
#endif
uint8_t _chipRevision;
};

View file

@ -1,16 +0,0 @@
#ifndef _RADIOLIB_SX1261_H
#define _RADIOLIB_SX1261_H
#include "TypeDef.h"
#include "Module.h"
#include "SX126x.h"
#include "SX1262.h"
//SX126X_CMD_SET_PA_CONFIG
#define SX126X_PA_CONFIG_SX1261 0x01
#define SX126X_PA_CONFIG_SX1262 0x00
// TODO: implement SX1261 class
using SX1261 = SX1262;
#endif

View file

@ -0,0 +1,50 @@
#include "SX1261.h"
SX1261::SX1261(Module* mod)
: SX1262(mod) {
}
int16_t SX1261::setOutputPower(int8_t power) {
// check allowed power range
if (!((power >= -17) && (power <= 14))) {
return(ERR_INVALID_OUTPUT_POWER);
}
// get current OCP configuration
uint8_t ocp = 0;
int16_t state = readRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1);
if (state != ERR_NONE) {
return(state);
}
state = setOptimalLowPowerPaConfig(&power);
if (state != ERR_NONE) {
return(state);
}
// set output power
// TODO power ramp time configuration
state = SX126x::setTxParams(power);
if (state != ERR_NONE) {
return(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;
}

View file

@ -0,0 +1,42 @@
#ifndef _RADIOLIB_SX1261_H
#define _RADIOLIB_SX1261_H
#include "../../TypeDef.h"
#include "../../Module.h"
#include "SX126x.h"
#include "SX1262.h"
//SX126X_CMD_SET_PA_CONFIG
#define SX126X_PA_CONFIG_SX1261 0x01
/*!
\class SX1261
\brief Derived class for %SX1261 modules.
*/
class SX1261 : public SX1262 {
public:
/*!
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio.
*/
SX1261(Module* mod);
/*!
\brief Sets output power. Allowed values are in range from -17 to 14 dBm.
\param power Output power to be set in dBm.
\returns \ref status_codes
*/
int16_t setOutputPower(int8_t power);
#ifndef RADIOLIB_GODMODE
private:
#endif
int16_t setOptimalLowPowerPaConfig(int8_t* inOutPower);
};
#endif

View file

@ -22,6 +22,11 @@ int16_t SX1262::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint16_t syn
return(state);
}
state = SX126x::fixPaClamping();
if (state != ERR_NONE) {
return state;
}
return(state);
}
@ -43,6 +48,11 @@ int16_t SX1262::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t
return(state);
}
state = SX126x::fixPaClamping();
if (state != ERR_NONE) {
return state;
}
return(state);
}
@ -85,28 +95,32 @@ int16_t SX1262::setFrequency(float freq, bool calibrate) {
int16_t SX1262::setOutputPower(int8_t power) {
// check allowed power range
if(!((power >= -17) && (power <= 22))) {
if (!((power >= -17) && (power <= 22))) {
return(ERR_INVALID_OUTPUT_POWER);
}
// get current OCP configuration
uint8_t ocp = 0;
int16_t state = readRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1);
if(state != ERR_NONE) {
if (state != ERR_NONE) {
return(state);
}
// enable high power PA for output power higher than 14 dBm
if(power > 13) {
SX126x::setPaConfig(0x04, SX126X_PA_CONFIG_SX1262);
} else {
SX126x::setPaConfig(0x04, SX126X_PA_CONFIG_SX1261);
// 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 output power
// TODO power ramp time configuration
SX126x::setTxParams(power);
state = SX126x::setTxParams(power);
if (state != ERR_NONE) {
return(state);
}
// restore OCP configuration
return(writeRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1));
return writeRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1);
}

View file

@ -1,14 +1,10 @@
#ifndef _RADIOLIB_SX1262_H
#define _RADIOLIB_SX1262_H
#include "TypeDef.h"
#include "Module.h"
#include "../../TypeDef.h"
#include "../../Module.h"
#include "SX126x.h"
//SX126X_CMD_SET_PA_CONFIG
#define SX126X_PA_CONFIG_SX1261 0x01
#define SX126X_PA_CONFIG_SX1262 0x00
/*!
\class SX1262
@ -93,8 +89,9 @@ class SX1262: public SX126x {
*/
int16_t setOutputPower(int8_t power);
#ifndef RADIOLIB_GODMODE
private:
#endif
};

View file

@ -22,6 +22,11 @@ int16_t SX1268::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint16_t syn
return(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) {
@ -42,6 +47,11 @@ int16_t SX1268::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t
return(state);
}
state = SX126x::fixPaClamping();
if (state != ERR_NONE) {
return state;
}
return(state);
}
@ -89,13 +99,19 @@ int16_t SX1268::setOutputPower(int8_t power) {
return(state);
}
// enable high power PA
SX126x::setPaConfig(0x04, SX126X_PA_CONFIG_SX1268);
// enable optimal PA - this changes the value of power.
state = SX126x::setOptimalHiPowerPaConfig(&power);
if (state != ERR_NONE) {
return(state);
}
// set output power
// TODO power ramp time configuration
SX126x::setTxParams(power);
state = SX126x::setTxParams(power);
if (state != ERR_NONE) {
return(state);
}
// restore OCP configuration
return(writeRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1));
return writeRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1);
}

View file

@ -1,8 +1,8 @@
#ifndef _RADIOLIB_SX1268_H
#define _RADIOLIB_SX1268_H
#include "TypeDef.h"
#include "Module.h"
#include "../../TypeDef.h"
#include "../../Module.h"
#include "SX126x.h"
//SX126X_CMD_SET_PA_CONFIG
@ -91,6 +91,11 @@ class SX1268: public SX126x {
\returns \ref status_codes
*/
int16_t setOutputPower(int8_t power);
#ifndef RADIOLIB_GODMODE
private:
#endif
};
#endif

View file

@ -6,7 +6,7 @@ SX126x::SX126x(Module* mod) : PhysicalLayer(SX126X_CRYSTAL_FREQ, SX126X_DIV_EXPO
int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, float currentLimit, uint16_t preambleLength) {
// set module properties
_mod->init(USE_SPI, INT_BOTH);
_mod->init(RADIOLIB_USE_SPI, RADIOLIB_INT_BOTH);
pinMode(_mod->getRx(), INPUT);
// BW in kHz and SF are required in order to calculate LDRO for setModulationParams
@ -71,7 +71,7 @@ int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, float
int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, float currentLimit, uint16_t preambleLength, float dataShaping) {
// set module properties
_mod->init(USE_SPI, INT_BOTH);
_mod->init(RADIOLIB_USE_SPI, RADIOLIB_INT_BOTH);
pinMode(_mod->getRx(), INPUT);
// initialize configuration variables (will be overwritten during public settings configuration)
@ -134,6 +134,11 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, float currentLimit
return(state);
}
state = setWhitening(true, 0x0100);
if(state != ERR_NONE) {
return(state);
}
state = setDio2AsRfSwitch(false);
return(state);
@ -167,9 +172,9 @@ int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) {
return(ERR_UNKNOWN);
}
DEBUG_PRINT(F("Timeout in "));
DEBUG_PRINT(timeout);
DEBUG_PRINTLN(F(" us"));
RADIOLIB_DEBUG_PRINT(F("Timeout in "));
RADIOLIB_DEBUG_PRINT(timeout);
RADIOLIB_DEBUG_PRINTLN(F(" us"));
// start transmission
state = startTransmit(data, len, addr);
@ -231,9 +236,9 @@ int16_t SX126x::receive(uint8_t* data, size_t len) {
return(ERR_UNKNOWN);
}
DEBUG_PRINT(F("Timeout in "));
DEBUG_PRINT(timeout);
DEBUG_PRINTLN(F(" us"));
RADIOLIB_DEBUG_PRINT(F("Timeout in "));
RADIOLIB_DEBUG_PRINT(timeout);
RADIOLIB_DEBUG_PRINTLN(F(" us"));
// start reception
uint32_t timeoutValue = (uint32_t)((float)timeout / 15.625);
@ -246,11 +251,18 @@ int16_t SX126x::receive(uint8_t* data, size_t len) {
uint32_t start = micros();
while(!digitalRead(_mod->getInt0())) {
if(micros() - start > timeout) {
fixImplicitTimeout();
clearIrqStatus();
return(ERR_RX_TIMEOUT);
}
}
// timeout fix is recommended after any reception with active timeout
state = fixImplicitTimeout();
if(state != ERR_NONE) {
return(state);
}
// read the received data
return(readData(data, len));
}
@ -359,13 +371,18 @@ int16_t SX126x::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
return(ERR_PACKET_TOO_LONG);
}
// maximum packet length is decreased by 1 when address filtering is active
if((_addrComp != SX126X_GFSK_ADDRESS_FILT_OFF) && (len > SX126X_MAX_PACKET_LENGTH - 1)) {
return(ERR_PACKET_TOO_LONG);
}
// set packet Length
int16_t state = ERR_NONE;
uint8_t modem = getPacketType();
if(modem == SX126X_PACKET_TYPE_LORA) {
state = setPacketParams(_preambleLength, _crcType, len);
} else if(modem == SX126X_PACKET_TYPE_GFSK) {
state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, len);
state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType, len);
} else {
return(ERR_UNKNOWN);
}
@ -397,6 +414,12 @@ int16_t SX126x::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
return(state);
}
// fix sensitivity
state = fixSensitivity();
if(state != ERR_NONE) {
return(state);
}
// start transmission
state = setTx(SX126X_TX_TIMEOUT_NONE);
if(state != ERR_NONE) {
@ -435,6 +458,12 @@ int16_t SX126x::startReceive(uint32_t timeout) {
}
int16_t SX126x::readData(uint8_t* data, size_t len) {
// set mode to standby
int16_t state = standby();
if(state != ERR_NONE) {
return(state);
}
// check integrity CRC
uint16_t irq = getIrqStatus();
if((irq & SX126X_IRQ_CRC_ERR) || (irq & SX126X_IRQ_HEADER_ERR)) {
@ -449,7 +478,7 @@ int16_t SX126x::readData(uint8_t* data, size_t len) {
}
// read packet data
int16_t state = readBuffer(data, length);
state = readBuffer(data, length);
if(state != ERR_NONE) {
return(state);
}
@ -554,7 +583,7 @@ int16_t SX126x::setPreambleLength(uint16_t preambleLength) {
return(setPacketParams(_preambleLength, _crcType));
} else if(modem == SX126X_PACKET_TYPE_GFSK) {
_preambleLengthFSK = preambleLength;
return(setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp));
return(setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType));
}
return(ERR_UNKNOWN);
@ -716,7 +745,7 @@ int16_t SX126x::setSyncWord(uint8_t* syncWord, uint8_t len) {
// update packet parameters
_syncWordLength = len * 8;
state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp);
state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType);
return(state);
}
@ -745,7 +774,7 @@ int16_t SX126x::setSyncBits(uint8_t *syncWord, uint8_t bitsLen) {
// update packet parameters
_syncWordLength = bitsLen;
state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp);
state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType);
return(state);
}
@ -758,7 +787,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);
int16_t state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType);
if(state != ERR_NONE) {
return(state);
}
@ -777,7 +806,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);
int16_t state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType);
if(state != ERR_NONE) {
return(state);
}
@ -796,7 +825,7 @@ int16_t SX126x::disableAddressFiltering() {
// disable address filtering
_addrComp = SX126X_GFSK_ADDRESS_FILT_OFF;
return(setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp));
return(setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening));
}
int16_t SX126x::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool inverted) {
@ -827,7 +856,7 @@ int16_t SX126x::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool
return(ERR_INVALID_CRC_CONFIGURATION);
}
int16_t state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp);
int16_t state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType);
if(state != ERR_NONE) {
return(state);
}
@ -862,6 +891,50 @@ int16_t SX126x::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool
return(ERR_UNKNOWN);
}
int16_t SX126x::setWhitening(bool enabled, uint16_t initial) {
// check active modem
if(getPacketType() != SX126X_PACKET_TYPE_GFSK) {
return(ERR_WRONG_MODEM);
}
int16_t state = ERR_NONE;
if(enabled != true) {
// disable whitening
_whitening = SX126X_GFSK_WHITENING_OFF;
state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType);
if(state != ERR_NONE) {
return(state);
}
} else {
// enable whitening
_whitening = SX126X_GFSK_WHITENING_ON;
// write initial whitening value
// as per note on pg. 65 of datasheet v1.2: "The user should not change the value of the 7 MSB's of this register"
uint8_t data[2];
// 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);
}
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);
}
state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType);
if(state != ERR_NONE) {
return(state);
}
}
return(state);
}
float SX126x::getDataRate() {
return(_dataRate);
}
@ -892,6 +965,14 @@ size_t SX126x::getPacketLength(bool update) {
return((size_t)rxBufStatus[0]);
}
int16_t SX126x::fixedPacketLengthMode(uint8_t len) {
return(setPacketMode(SX126X_GFSK_PACKET_FIXED, len));
}
int16_t SX126x::variablePacketLengthMode(uint8_t maxLen) {
return(setPacketMode(SX126X_GFSK_PACKET_VARIABLE, maxLen));
}
uint32_t SX126x::getTimeOnAir(size_t len) {
if(getPacketType() == SX126X_PACKET_TYPE_LORA) {
float symbolLength = (float)((uint32_t)(1) << _sf) / (float)_bwKhz;
@ -913,10 +994,15 @@ uint32_t SX126x::getTimeOnAir(size_t len) {
}
}
int16_t SX126x::setTCXO(float voltage, uint32_t timeout) {
int16_t SX126x::setTCXO(float voltage, uint32_t delay) {
// set mode to standby
standby();
// check SX126X_XOSC_START_ERR flag and clear it
if(getDeviceErrors() & SX126X_XOSC_START_ERR) {
clearDeviceErrors();
}
// check alowed voltage values
uint8_t data[4];
if(abs(voltage - 1.6) <= 0.001) {
@ -939,11 +1025,11 @@ int16_t SX126x::setTCXO(float voltage, uint32_t timeout) {
return(ERR_INVALID_TCXO_VOLTAGE);
}
// calculate timeout
uint32_t timeoutValue = (float)timeout / 15.625;
data[1] = (uint8_t)((timeoutValue >> 16) & 0xFF);
data[2] = (uint8_t)((timeoutValue >> 8) & 0xFF);
data[3] = (uint8_t)(timeoutValue & 0xFF);
// calculate delay
uint32_t delayValue = (float)delay / 15.625;
data[1] = (uint8_t)((delayValue >> 16) & 0xFF);
data[2] = (uint8_t)((delayValue >> 8) & 0xFF);
data[3] = (uint8_t)(delayValue & 0xFF);
// enable TCXO control on DIO3
SPIwriteCommand(SX126X_CMD_SET_DIO3_AS_TCXO_CTRL, data, 4);
@ -981,12 +1067,8 @@ int16_t SX126x::setPaConfig(uint8_t paDutyCycle, uint8_t deviceSel, uint8_t hpMa
}
int16_t SX126x::writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) {
uint8_t* dat = new uint8_t[2 + numBytes];
dat[0] = (uint8_t)((addr >> 8) & 0xFF);
dat[1] = (uint8_t)(addr & 0xFF);
memcpy(dat + 2, data, numBytes);
int16_t state = SPIwriteCommand(SX126X_CMD_WRITE_REGISTER, dat, 2 + numBytes);
delete[] dat;
uint8_t cmd[] = { SX126X_CMD_WRITE_REGISTER, (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) };
int16_t state = SPIwriteCommand(cmd, 3, data, numBytes);
return(state);
}
@ -996,22 +1078,15 @@ int16_t SX126x::readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) {
}
int16_t SX126x::writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) {
uint8_t* dat = new uint8_t[1 + numBytes];
dat[0] = offset;
memcpy(dat + 1, data, numBytes);
int16_t state = SPIwriteCommand(SX126X_CMD_WRITE_BUFFER, dat, 1 + numBytes);
delete[] dat;
uint8_t cmd[] = { SX126X_CMD_WRITE_BUFFER, offset };
int16_t state = SPIwriteCommand(cmd, 2, data, numBytes);
return(state);
}
int16_t SX126x::readBuffer(uint8_t* data, uint8_t numBytes) {
// offset will be always set to 0 (one extra NOP is sent)
uint8_t* dat = new uint8_t[1 + numBytes];
dat[0] = SX126X_CMD_NOP;
memcpy(dat + 1, data, numBytes);
int16_t state = SPIreadCommand(SX126X_CMD_READ_BUFFER, dat, 1 + numBytes);
memcpy(data, dat + 1, numBytes);
delete[] dat;
uint8_t cmd[] = { SX126X_CMD_READ_BUFFER, SX126X_CMD_NOP };
int16_t state = SPIreadCommand(cmd, 2, data, numBytes);
return(state);
}
@ -1054,13 +1129,54 @@ 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) {
return(ERR_WRONG_MODEM);
}
// set requested packet mode
int16_t state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, mode, len);
if(state != ERR_NONE) {
return(state);
}
// update cached value
_packetType = mode;
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) {
float symbolLength = (float)(uint32_t(1) << _sf) / (float)_bwKhz;
DEBUG_PRINT("Symbol length: ");
DEBUG_PRINT(symbolLength);
DEBUG_PRINTLN(" ms");
RADIOLIB_DEBUG_PRINT("Symbol length: ");
RADIOLIB_DEBUG_PRINT(symbolLength);
RADIOLIB_DEBUG_PRINTLN(" ms");
if(symbolLength >= 16.0) {
_ldro = SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON;
} else {
@ -1082,11 +1198,12 @@ 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);
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));
}
int16_t SX126x::setPacketParamsFSK(uint16_t preambleLength, uint8_t crcType, uint8_t syncWordLength, uint8_t addrComp, uint8_t payloadLength, uint8_t packetType, uint8_t preambleDetectorLength, uint8_t whitening) {
int16_t SX126x::setPacketParamsFSK(uint16_t preambleLength, uint8_t crcType, uint8_t syncWordLength, uint8_t addrComp, uint8_t whitening, uint8_t packetType, uint8_t payloadLength, uint8_t preambleDetectorLength) {
uint8_t data[9] = {(uint8_t)((preambleLength >> 8) & 0xFF), (uint8_t)(preambleLength & 0xFF),
preambleDetectorLength, syncWordLength, addrComp,
packetType, payloadLength, crcType, whitening};
@ -1118,8 +1235,8 @@ uint16_t SX126x::getDeviceErrors() {
}
int16_t SX126x::clearDeviceErrors() {
uint8_t data[1] = {SX126X_CMD_NOP};
return(SPIwriteCommand(SX126X_CMD_CLEAR_DEVICE_ERRORS, data, 1));
uint8_t data[2] = {SX126X_CMD_NOP, SX126X_CMD_NOP};
return(SPIwriteCommand(SX126X_CMD_CLEAR_DEVICE_ERRORS, data, 2));
}
int16_t SX126x::setFrequencyRaw(float freq) {
@ -1129,9 +1246,90 @@ int16_t SX126x::setFrequencyRaw(float freq) {
return(ERR_NONE);
}
int16_t SX126x::fixSensitivity() {
// fix receiver sensitivity for 500 kHz LoRa
// see SX1262/SX1268 datasheet, chapter 15 Known Limitations, section 15.1 for details
// read current sensitivity configuration
uint8_t sensitivityConfig = 0;
int16_t state = readRegister(SX126X_REG_SENSITIVITY_CONFIG, &sensitivityConfig, 1);
if(state != ERR_NONE) {
return(state);
}
// fix the value for LoRa with 500 kHz bandwidth
if((getPacketType() == SX126X_PACKET_TYPE_LORA) && (abs(_bwKhz - 500.0) <= 0.001)) {
sensitivityConfig &= 0xFB;
} else {
sensitivityConfig |= 0x04;
}
return(writeRegister(SX126X_REG_SENSITIVITY_CONFIG, &sensitivityConfig, 1));
}
int16_t SX126x::fixPaClamping() {
// fixes overly eager PA clamping
// see SX1262/SX1268 datasheet, chapter 15 Known Limitations, section 15.2 for details
// 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;
}
// update with the new value
clampConfig |= 0x1E;
return(writeRegister(SX126X_REG_TX_CLAMP_CONFIG, &clampConfig, 1));
}
int16_t SX126x::fixImplicitTimeout() {
// fixes timeout in implicit header mode
// see SX1262/SX1268 datasheet, chapter 15 Known Limitations, section 15.3 for details
// stop RTC counter
uint8_t rtcStop = 0x00;
int16_t state = writeRegister(SX126X_REG_RTC_STOP, &rtcStop, 1);
if(state != ERR_NONE) {
return(state);
}
// read currently active event
uint8_t rtcEvent = 0;
state = readRegister(SX126X_REG_RTC_EVENT, &rtcEvent, 1);
if(state != ERR_NONE) {
return(state);
}
// clear events
rtcEvent |= 0x02;
return(writeRegister(SX126X_REG_RTC_EVENT, &rtcEvent, 1));
}
int16_t SX126x::fixInvertedIQ(uint8_t iqConfig) {
// fixes IQ configuration for inverted IQ
// see SX1262/SX1268 datasheet, chapter 15 Known Limitations, section 15.4 for details
// read current IQ configuration
uint8_t iqConfigCurrent = 0;
int16_t state = readRegister(SX126X_REG_IQ_CONFIG, &iqConfigCurrent, 1);
if(state != ERR_NONE) {
return(state);
}
// set correct IQ configuration
if(iqConfig == SX126X_LORA_IQ_STANDARD) {
iqConfigCurrent &= 0xFB;
} else {
iqConfigCurrent |= 0x04;
}
// update with the new value
return(writeRegister(SX126X_REG_IQ_CONFIG, &iqConfigCurrent, 1));
}
int16_t SX126x::config(uint8_t modem) {
// set regulator mode
uint8_t* data = new uint8_t[1];
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) {
@ -1159,8 +1357,6 @@ int16_t SX126x::config(uint8_t modem) {
}
// set CAD parameters
delete[] data;
data = new uint8_t[7];
data[0] = SX126X_CAD_ON_8_SYMB;
data[1] = _sf + 13;
data[2] = 10;
@ -1181,8 +1377,6 @@ int16_t SX126x::config(uint8_t modem) {
}
// calibrate all blocks
delete[] data;
data = new uint8_t[1];
data[0] = SX126X_CALIBRATE_ALL;
state = SPIwriteCommand(SX126X_CMD_CALIBRATE, data, 1);
if(state != ERR_NONE) {
@ -1193,19 +1387,23 @@ int16_t SX126x::config(uint8_t modem) {
delayMicroseconds(1);
while(digitalRead(_mod->getRx()));
delete[] data;
return(ERR_NONE);
}
int16_t SX126x::SPIwriteCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy) {
return(SX126x::SPItransfer(cmd, cmdLen, true, data, NULL, numBytes, waitForBusy));
}
int16_t SX126x::SPIwriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy) {
uint8_t cmdBuffer[] = {cmd};
return(SX126x::SPItransfer(cmdBuffer, 1, true, data, NULL, numBytes, waitForBusy));
return(SX126x::SPItransfer(&cmd, 1, true, data, NULL, numBytes, waitForBusy));
}
int16_t SX126x::SPIreadCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy) {
return(SX126x::SPItransfer(cmd, cmdLen, false, NULL, data, numBytes, waitForBusy));
}
int16_t SX126x::SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy) {
uint8_t cmdBuffer[] = {cmd};
return(SX126x::SPItransfer(cmdBuffer, 1, false, NULL, data, numBytes, waitForBusy));
return(SX126x::SPItransfer(&cmd, 1, false, NULL, data, numBytes, waitForBusy));
}
int16_t SX126x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForBusy, uint32_t timeout) {
@ -1213,7 +1411,15 @@ int16_t SX126x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* d
SPIClass* spi = _mod->getSpi();
SPISettings spiSettings = _mod->getSpiSettings();
#ifdef RADIOLIB_VERBOSE
uint8_t debugBuff[256];
#endif
// pull NSS low
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->getRx())) {
if(millis() - start >= timeout) {
@ -1222,14 +1428,11 @@ int16_t SX126x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* d
}
// start transfer
digitalWrite(_mod->getCs(), LOW);
spi->beginTransaction(spiSettings);
// send command byte(s)
for(uint8_t n = 0; n < cmdLen; n++) {
spi->transfer(cmd[n]);
DEBUG_PRINT(cmd[n], HEX);
DEBUG_PRINT('\t');
}
// variable to save error during SPI transfer
@ -1240,41 +1443,41 @@ int16_t SX126x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* d
for(uint8_t n = 0; n < numBytes; n++) {
// send byte
uint8_t in = spi->transfer(dataOut[n]);
DEBUG_PRINT(dataOut[n], HEX);
DEBUG_PRINT('\t');
DEBUG_PRINT(in, HEX);
DEBUG_PRINT('\t');
#ifdef RADIOLIB_VERBOSE
debugBuff[n] = in;
#endif
// check status
if(((in & 0b00001110) == SX126X_STATUS_CMD_TIMEOUT) ||
((in & 0b00001110) == SX126X_STATUS_CMD_INVALID) ||
((in & 0b00001110) == SX126X_STATUS_CMD_FAILED)) {
status = in;
status = in & 0b00001110;
break;
} else if(in == 0x00 || in == 0xFF) {
status = SX126X_STATUS_SPI_FAILED;
break;
}
}
DEBUG_PRINTLN();
} else {
// skip the first byte for read-type commands (status-only)
uint8_t in = spi->transfer(SX126X_CMD_NOP);
DEBUG_PRINT(SX126X_CMD_NOP, HEX);
DEBUG_PRINT('\t');
DEBUG_PRINT(in, HEX);
DEBUG_PRINT('\t')
#ifdef RADIOLIB_VERBOSE
debugBuff[0] = in;
#endif
// check status
if(((in & 0b00001110) == SX126X_STATUS_CMD_TIMEOUT) ||
((in & 0b00001110) == SX126X_STATUS_CMD_INVALID) ||
((in & 0b00001110) == SX126X_STATUS_CMD_FAILED)) {
status = in;
status = in & 0b00001110;
} else if(in == 0x00 || in == 0xFF) {
status = SX126X_STATUS_SPI_FAILED;
} else {
for(uint8_t n = 0; n < numBytes; n++) {
dataIn[n] = spi->transfer(SX126X_CMD_NOP);
}
}
for(uint8_t n = 0; n < numBytes; n++) {
dataIn[n] = spi->transfer(SX126X_CMD_NOP);
DEBUG_PRINT(SX126X_CMD_NOP, HEX);
DEBUG_PRINT('\t');
DEBUG_PRINT(dataIn[n], HEX);
DEBUG_PRINT('\t');
}
DEBUG_PRINTLN();
}
// stop transfer
@ -1287,11 +1490,52 @@ int16_t SX126x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* d
start = millis();
while(digitalRead(_mod->getRx())) {
if(millis() - start >= timeout) {
return(ERR_SPI_CMD_TIMEOUT);
status = SX126X_STATUS_CMD_TIMEOUT;
break;
}
}
}
// print debug output
#ifdef RADIOLIB_VERBOSE
// print command byte(s)
RADIOLIB_VERBOSE_PRINT("CMD\t");
for(uint8_t n = 0; n < cmdLen; n++) {
RADIOLIB_VERBOSE_PRINT(cmd[n], HEX);
RADIOLIB_VERBOSE_PRINT('\t');
}
RADIOLIB_VERBOSE_PRINTLN();
// print data bytes
RADIOLIB_VERBOSE_PRINT("DAT");
if(write) {
RADIOLIB_VERBOSE_PRINT("W\t");
for(uint8_t n = 0; n < numBytes; n++) {
RADIOLIB_VERBOSE_PRINT(dataOut[n], HEX);
RADIOLIB_VERBOSE_PRINT('\t');
RADIOLIB_VERBOSE_PRINT(debugBuff[n], HEX);
RADIOLIB_VERBOSE_PRINT('\t');
}
RADIOLIB_VERBOSE_PRINTLN();
} else {
RADIOLIB_VERBOSE_PRINT("R\t");
// skip the first byte for read-type commands (status-only)
RADIOLIB_VERBOSE_PRINT(SX126X_CMD_NOP, HEX);
RADIOLIB_VERBOSE_PRINT('\t');
RADIOLIB_VERBOSE_PRINT(debugBuff[0], HEX);
RADIOLIB_VERBOSE_PRINT('\t')
for(uint8_t n = 0; n < numBytes; n++) {
RADIOLIB_VERBOSE_PRINT(SX126X_CMD_NOP, HEX);
RADIOLIB_VERBOSE_PRINT('\t');
RADIOLIB_VERBOSE_PRINT(dataIn[n], HEX);
RADIOLIB_VERBOSE_PRINT('\t');
}
RADIOLIB_VERBOSE_PRINTLN();
}
RADIOLIB_VERBOSE_PRINTLN();
#endif
// parse status
switch(status) {
case SX126X_STATUS_CMD_TIMEOUT:
@ -1300,6 +1544,8 @@ int16_t SX126x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* d
return(ERR_SPI_CMD_INVALID);
case SX126X_STATUS_CMD_FAILED:
return(ERR_SPI_CMD_FAILED);
case SX126X_STATUS_SPI_FAILED:
return(ERR_CHIP_NOT_FOUND);
default:
return(ERR_NONE);
}

View file

@ -1,10 +1,10 @@
#ifndef _RADIOLIB_SX126X_H
#define _RADIOLIB_SX126X_H
#include "TypeDef.h"
#include "Module.h"
#include "../../TypeDef.h"
#include "../../Module.h"
#include "../protocols/PhysicalLayer.h"
#include "../../protocols/PhysicalLayer/PhysicalLayer.h"
// SX126X physical layer properties
#define SX126X_CRYSTAL_FREQ 32.0
@ -93,6 +93,16 @@
#define SX126X_REG_XTA_TRIM 0x0911
#define SX126X_REG_XTB_TRIM 0x0912
// undocumented registers
#define SX126X_REG_SENSITIVITY_CONFIG 0x0889 // SX1268 datasheet v1.1, section 15.1
#define SX126X_REG_TX_CLAMP_CONFIG 0x08D8 // SX1268 datasheet v1.1, section 15.2
#define SX126X_REG_RTC_STOP 0x0920 // SX1268 datasheet v1.1, section 15.3
#define SX126X_REG_RTC_EVENT 0x0944 // SX1268 datasheet v1.1, section 15.3
#define SX126X_REG_IQ_CONFIG 0x0736 // SX1268 datasheet v1.1, section 15.4
#define SX126X_REG_RX_GAIN_RETENTION_0 0x029F // SX1268 datasheet v1.1, section 9.6
#define SX126X_REG_RX_GAIN_RETENTION_1 0x02A0 // SX1268 datasheet v1.1, section 9.6
#define SX126X_REG_RX_GAIN_RETENTION_2 0x02A1 // SX1268 datasheet v1.1, section 9.6
// SX126X SPI command variables
//SX126X_CMD_SET_SLEEP
@ -152,6 +162,7 @@
//SX126X_CMD_SET_PA_CONFIG
#define SX126X_PA_CONFIG_HP_MAX 0x07
#define SX126X_PA_CONFIG_PA_LUT 0x01
#define SX126X_PA_CONFIG_SX1262_8 0x00
//SX126X_CMD_SET_RX_TX_FALLBACK_MODE
#define SX126X_RX_TX_FALLBACK_MODE_FS 0x40 // 7 0 after Rx/Tx go to: FS mode
@ -289,6 +300,7 @@
#define SX126X_STATUS_CMD_INVALID 0b00001000 // 3 1 invalid SPI command
#define SX126X_STATUS_CMD_FAILED 0b00001010 // 3 1 SPI command failed to execute
#define SX126X_STATUS_TX_DONE 0b00001100 // 3 1 packet transmission done
#define SX126X_STATUS_SPI_FAILED 0b11111111 // 7 0 SPI transaction failed
//SX126X_CMD_GET_PACKET_STATUS
#define SX126X_GFSK_RX_STATUS_PREAMBLE_ERR 0b10000000 // 7 7 GFSK Rx status: preamble error
@ -655,6 +667,17 @@ class SX126x: public PhysicalLayer {
*/
int16_t setCRC(uint8_t len, uint16_t initial = 0x1D0F, uint16_t polynomial = 0x1021, bool inverted = true);
/*!
\brief Sets FSK whitening parameters.
\param enabled True = Whitening enabled
\param initial Initial value used for the whitening LFSR in FSK mode.
\returns \ref status_codes
*/
int16_t setWhitening(bool enabled, uint16_t initial = 0x0100);
/*!
\brief Sets TCXO (Temperature Compensated Crystal Oscillator) configuration.
@ -662,7 +685,7 @@ class SX126x: public PhysicalLayer {
\param TCXO timeout in us. Defaults to 5000 us.
*/
int16_t setTCXO(float voltage, uint32_t timeout = 5000);
int16_t setTCXO(float voltage, uint32_t delay = 5000);
/*!
\brief Set DIO2 to function as RF switch (default in Semtech example designs).
@ -701,6 +724,24 @@ class SX126x: public PhysicalLayer {
*/
size_t getPacketLength(bool update = true);
/*!
\brief Set modem in fixed packet length mode. Available in FSK mode only.
\param len Packet length.
\returns \ref status_codes
*/
int16_t fixedPacketLengthMode(uint8_t len = SX126X_MAX_PACKET_LENGTH);
/*!
\brief Set modem in variable packet length mode. Available in FSK mode only.
\param len Maximum packet length.
\returns \ref status_codes
*/
int16_t variablePacketLengthMode(uint8_t maxLen = SX126X_MAX_PACKET_LENGTH);
/*!
\brief Get expected time-on-air for a given size of payload
@ -710,7 +751,9 @@ class SX126x: public PhysicalLayer {
*/
uint32_t getTimeOnAir(size_t len);
#ifndef RADIOLIB_GODMODE
protected:
#endif
// SX1276x SPI command implementations
int16_t setTx(uint32_t timeout = 0);
int16_t setRx(uint32_t timeout);
@ -730,7 +773,7 @@ class SX126x: public PhysicalLayer {
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 setPacketParamsFSK(uint16_t preambleLength, uint8_t crcType, uint8_t syncWordLength, uint8_t addrComp, uint8_t payloadLength = 0xFF, uint8_t packetType = SX126X_GFSK_PACKET_VARIABLE, uint8_t preambleDetectorLength = SX126X_GFSK_PREAMBLE_DETECT_16, uint8_t whitening = SX126X_GFSK_WHITENING_ON);
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);
uint8_t getStatus();
uint32_t getPacketStatus();
@ -738,8 +781,18 @@ class SX126x: public PhysicalLayer {
int16_t clearDeviceErrors();
int16_t setFrequencyRaw(float freq);
int16_t setOptimalHiPowerPaConfig(int8_t* inOutPower);
int16_t setPacketMode(uint8_t mode, uint8_t len);
// fixes to errata
int16_t fixSensitivity();
int16_t fixPaClamping();
int16_t fixImplicitTimeout();
int16_t fixInvertedIQ(uint8_t iqConfig);
#ifndef RADIOLIB_GODMODE
private:
#endif
Module* _mod;
uint8_t _bw, _sf, _cr, _ldro, _crcType;
@ -747,7 +800,7 @@ class SX126x: public PhysicalLayer {
float _bwKhz;
uint32_t _br, _freqDev;
uint8_t _rxBw, _pulseShape, _crcTypeFSK, _syncWordLength, _addrComp;
uint8_t _rxBw, _pulseShape, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType;
uint16_t _preambleLengthFSK;
float _rxBwKhz;
@ -757,7 +810,9 @@ class SX126x: public PhysicalLayer {
// common low-level SPI interface
int16_t SPIwriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy = true);
int16_t SPIwriteCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy = true);
int16_t SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy = true);
int16_t SPIreadCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy = true);
int16_t SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForBusy, uint32_t timeout = 5000);
};

View file

@ -125,9 +125,9 @@ int16_t SX1272::setBandwidth(float bw) {
// calculate symbol length and set low data rate optimization, if needed
float symbolLength = (float)(uint32_t(1) << SX127x::_sf) / (float)SX127x::_bw;
DEBUG_PRINT("Symbol length: ");
DEBUG_PRINT(symbolLength);
DEBUG_PRINTLN(" ms");
RADIOLIB_DEBUG_PRINT("Symbol length: ");
RADIOLIB_DEBUG_PRINT(symbolLength);
RADIOLIB_DEBUG_PRINTLN(" ms");
if(symbolLength >= 16.0) {
state = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_LOW_DATA_RATE_OPT_ON, 0, 0);
} else {
@ -179,9 +179,9 @@ int16_t SX1272::setSpreadingFactor(uint8_t sf) {
// calculate symbol length and set low data rate optimization, if needed
float symbolLength = (float)(uint32_t(1) << SX127x::_sf) / (float)SX127x::_bw;
DEBUG_PRINT("Symbol length: ");
DEBUG_PRINT(symbolLength);
DEBUG_PRINTLN(" ms");
RADIOLIB_DEBUG_PRINT("Symbol length: ");
RADIOLIB_DEBUG_PRINT(symbolLength);
RADIOLIB_DEBUG_PRINTLN(" ms");
if(symbolLength >= 16.0) {
state = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_LOW_DATA_RATE_OPT_ON, 0, 0);
} else {
@ -342,22 +342,33 @@ int16_t SX1272::setDataShapingOOK(uint8_t sh) {
return(state);
}
int8_t SX1272::getRSSI() {
// check active modem
if(getActiveModem() != SX127X_LORA) {
return(0);
float SX1272::getRSSI() {
if(getActiveModem() == SX127X_LORA) {
// RSSI calculation uses different constant for low-frequency and high-frequency ports
float lastPacketRSSI = -139 + _mod->SPIgetRegValue(SX127X_REG_PKT_RSSI_VALUE);
// spread-spectrum modulation signal can be received below noise floor
// check last packet SNR and if it's less than 0, add it to reported RSSI to get the correct value
float lastPacketSNR = SX127x::getSNR();
if(lastPacketSNR < 0.0) {
lastPacketRSSI += lastPacketSNR;
}
return(lastPacketRSSI);
} else {
// enable listen mode
startReceive();
// read the value for FSK
float rssi = (float)_mod->SPIgetRegValue(SX127X_REG_RSSI_VALUE_FSK) / -2.0;
// set mode back to standby
standby();
// return the value
return(rssi);
}
int8_t lastPacketRSSI = -139 + _mod->SPIgetRegValue(SX127X_REG_PKT_RSSI_VALUE);
// spread-spectrum modulation signal can be received below noise floor
// check last packet SNR and if it's less than 0, add it to reported RSSI to get the correct value
float lastPacketSNR = SX127x::getSNR();
if(lastPacketSNR < 0.0) {
lastPacketRSSI += lastPacketSNR;
}
return(lastPacketRSSI);
}
int16_t SX1272::setCRC(bool enableCRC) {

View file

@ -1,8 +1,8 @@
#ifndef _RADIOLIB_SX1272_H
#define _RADIOLIB_SX1272_H
#include "TypeDef.h"
#include "Module.h"
#include "../../TypeDef.h"
#include "../../Module.h"
#include "SX127x.h"
// SX1272 specific register map
@ -235,11 +235,11 @@ class SX1272: public SX127x {
int16_t setDataShapingOOK(uint8_t sh);
/*!
\brief Gets recorded signal strength indicator of the latest received packet.
\brief Gets recorded signal strength indicator of the latest received packet for LoRa modem, or current RSSI level for FSK modem.
\returns Last packet recorded signal strength indicator (RSSI).
\returns Last packet RSSI for LoRa modem, or current RSSI level for FSK modem.
*/
int8_t getRSSI();
float getRSSI();
/*!
\brief Enables/disables CRC check of received packets.
@ -250,14 +250,18 @@ class SX1272: public SX127x {
*/
int16_t setCRC(bool enableCRC);
#ifndef RADIOLIB_GODMODE
protected:
#endif
int16_t setBandwidthRaw(uint8_t newBandwidth);
int16_t setSpreadingFactorRaw(uint8_t newSpreadingFactor);
int16_t setCodingRateRaw(uint8_t newCodingRate);
int16_t configFSK();
#ifndef RADIOLIB_GODMODE
private:
#endif
};

View file

@ -1,7 +1,7 @@
#ifndef _RADIOLIB_SX1273_H
#define _RADIOLIB_SX1273_H
#include "TypeDef.h"
#include "../../TypeDef.h"
#include "SX1272.h"
/*!
@ -11,56 +11,61 @@
*/
class SX1273: public SX1272 {
public:
// constructor
/*!
\brief Default constructor. Called from Arduino sketch when creating new LoRa instance.
\param mod Instance of Module that will be used to communicate with the %LoRa chip.
*/
SX1273(Module* mod);
// basic methods
/*!
\brief %LoRa modem initialization method. Must be called at least once from Arduino sketch to initialize the module.
\param freq Carrier frequency in MHz. Allowed values range from 860.0 MHz to 1020.0 MHz.
\param bw %LoRa link bandwidth in kHz. Allowed values are 125, 250 and 500 kHz.
\param sf %LoRa link spreading factor. Allowed values range from 6 to 9.
\param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8.
\param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks.
\param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm.
\param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA.
\param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA.
Set to 0 to disable OCP (not recommended).
\param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number.
\param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number.
Allowed values range from 6 to 65535.
\param gain Gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain.
Set to 0 to enable automatic gain control (recommended).
\returns \ref status_codes
*/
int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 17, uint8_t currentLimit = 100, uint16_t preambleLength = 8, uint8_t gain = 0);
// configuration methods
/*!
\brief Sets %LoRa link spreading factor. Allowed values range from 6 to 9. Only available in %LoRa mode.
\param sf %LoRa link spreading factor to be set.
\returns \ref status_codes
*/
int16_t setSpreadingFactor(uint8_t sf);
#ifndef RADIOLIB_GODMODE
private:
#endif
};
#endif

View file

@ -1,7 +1,7 @@
#ifndef _RADIOLIB_SX1276_H
#define _RADIOLIB_SX1276_H
#include "TypeDef.h"
#include "../../TypeDef.h"
#include "SX1278.h"
/*!
@ -11,56 +11,61 @@
*/
class SX1276: public SX1278 {
public:
// constructor
/*!
\brief Default constructor. Called from Arduino sketch when creating new LoRa instance.
\param mod Instance of Module that will be used to communicate with the %LoRa chip.
*/
SX1276(Module* mod);
// basic methods
/*!
\brief %LoRa modem initialization method. Must be called at least once from Arduino sketch to initialize the module.
\param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 1020.0 MHz.
\param bw %LoRa link bandwidth in kHz. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz.
\param sf %LoRa link spreading factor. Allowed values range from 6 to 12.
\param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8.
\param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks.
\param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm.
\param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA.
\param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA.
Set to 0 to disable OCP (not recommended).
\param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number.
\param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number.
Allowed values range from 6 to 65535.
\param gain Gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain.
Set to 0 to enable automatic gain control (recommended).
\returns \ref status_codes
*/
int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 17, uint8_t currentLimit = 100, uint16_t preambleLength = 8, uint8_t gain = 0);
// configuration methods
/*!
\brief Sets carrier frequency. Allowed values range from 137.0 MHz to 1020.0 MHz.
\param freq Carrier frequency to be set in MHz.
\returns \ref status_codes
*/
int16_t setFrequency(float freq);
#ifndef RADIOLIB_GODMODE
private:
#endif
};
#endif

View file

@ -1,7 +1,7 @@
#ifndef _RADIOLIB_SX1277_H
#define _RADIOLIB_SX1277_H
#include "TypeDef.h"
#include "../../TypeDef.h"
#include "SX1278.h"
/*!
@ -11,65 +11,70 @@
*/
class SX1277: public SX1278 {
public:
// constructor
/*!
\brief Default constructor. Called from Arduino sketch when creating new LoRa instance.
\param mod Instance of Module that will be used to communicate with the %LoRa chip.
*/
SX1277(Module* mod);
// basic methods
/*!
\brief %LoRa modem initialization method. Must be called at least once from Arduino sketch to initialize the module.
\param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 1020.0 MHz.
\param bw %LoRa link bandwidth in kHz. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz.
\param sf %LoRa link spreading factor. Allowed values range from 6 to 9.
\param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8.
\param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks.
\param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm.
\param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA.
\param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA.
Set to 0 to disable OCP (not recommended).
\param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number.
\param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number.
Allowed values range from 6 to 65535.
\param gain Gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain.
Set to 0 to enable automatic gain control (recommended).
\returns \ref status_codes
*/
int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 17, uint8_t currentLimit = 100, uint16_t preambleLength = 8, uint8_t gain = 0);
// configuration methods
/*!
\brief Sets carrier frequency. Allowed values range from 137.0 MHz to 1020.0 MHz.
\param freq Carrier frequency to be set in MHz.
\returns \ref status_codes
*/
int16_t setFrequency(float freq);
/*!
\brief Sets %LoRa link spreading factor. Allowed values range from 6 to 9. Only available in %LoRa mode.
\param sf %LoRa link spreading factor to be set.
\returns \ref status_codes
*/
int16_t setSpreadingFactor(uint8_t sf);
#ifndef RADIOLIB_GODMODE
private:
#endif
};
#endif

View file

@ -195,9 +195,9 @@ int16_t SX1278::setBandwidth(float bw) {
// calculate symbol length and set low data rate optimization, if needed
float symbolLength = (float)(uint32_t(1) << SX127x::_sf) / (float)SX127x::_bw;
DEBUG_PRINT("Symbol length: ");
DEBUG_PRINT(symbolLength);
DEBUG_PRINTLN(" ms");
RADIOLIB_DEBUG_PRINT("Symbol length: ");
RADIOLIB_DEBUG_PRINT(symbolLength);
RADIOLIB_DEBUG_PRINTLN(" ms");
if(symbolLength >= 16.0) {
state = _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_LOW_DATA_RATE_OPT_ON, 3, 3);
} else {
@ -249,9 +249,9 @@ int16_t SX1278::setSpreadingFactor(uint8_t sf) {
// calculate symbol length and set low data rate optimization, if needed
float symbolLength = (float)(uint32_t(1) << SX127x::_sf) / (float)SX127x::_bw;
DEBUG_PRINT("Symbol length: ");
DEBUG_PRINT(symbolLength);
DEBUG_PRINTLN(" ms");
RADIOLIB_DEBUG_PRINT("Symbol length: ");
RADIOLIB_DEBUG_PRINT(symbolLength);
RADIOLIB_DEBUG_PRINTLN(" ms");
if(symbolLength >= 16.0) {
state = _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_LOW_DATA_RATE_OPT_ON, 3, 3);
} else {
@ -411,29 +411,40 @@ int16_t SX1278::setDataShapingOOK(uint8_t sh) {
return(state);
}
int8_t SX1278::getRSSI() {
// check active modem
if(getActiveModem() != SX127X_LORA) {
return(0);
}
float SX1278::getRSSI() {
if(getActiveModem() == SX127X_LORA) {
// for LoRa, get RSSI of the last packet
float lastPacketRSSI;
int8_t lastPacketRSSI;
// RSSI calculation uses different constant for low-frequency and high-frequency ports
if(_freq < 868.0) {
lastPacketRSSI = -164 + _mod->SPIgetRegValue(SX127X_REG_PKT_RSSI_VALUE);
} else {
lastPacketRSSI = -157 + _mod->SPIgetRegValue(SX127X_REG_PKT_RSSI_VALUE);
}
// spread-spectrum modulation signal can be received below noise floor
// check last packet SNR and if it's less than 0, add it to reported RSSI to get the correct value
float lastPacketSNR = SX127x::getSNR();
if(lastPacketSNR < 0.0) {
lastPacketRSSI += lastPacketSNR;
}
return(lastPacketRSSI);
// RSSI calculation uses different constant for low-frequency and high-frequency ports
if(_freq < 868.0) {
lastPacketRSSI = -164 + _mod->SPIgetRegValue(SX127X_REG_PKT_RSSI_VALUE);
} else {
lastPacketRSSI = -157 + _mod->SPIgetRegValue(SX127X_REG_PKT_RSSI_VALUE);
}
// enable listen mode
startReceive();
// spread-spectrum modulation signal can be received below noise floor
// check last packet SNR and if it's less than 0, add it to reported RSSI to get the correct value
float lastPacketSNR = SX127x::getSNR();
if(lastPacketSNR < 0.0) {
lastPacketRSSI += lastPacketSNR;
}
// read the value for FSK
float rssi = (float)_mod->SPIgetRegValue(SX127X_REG_RSSI_VALUE_FSK) / -2.0;
return(lastPacketRSSI);
// set mode back to standby
standby();
// return the value
return(rssi);
}
}
int16_t SX1278::setCRC(bool enableCRC) {

View file

@ -1,8 +1,8 @@
#ifndef _RADIOLIB_SX1278_H
#define _RADIOLIB_SX1278_H
#include "TypeDef.h"
#include "Module.h"
#include "../../TypeDef.h"
#include "../../Module.h"
#include "SX127x.h"
// SX1278 specific register map
@ -244,11 +244,11 @@ class SX1278: public SX127x {
int16_t setDataShapingOOK(uint8_t sh);
/*!
\brief Gets recorded signal strength indicator of the latest received packet.
\brief Gets recorded signal strength indicator of the latest received packet for LoRa modem, or current RSSI level for FSK modem.
\returns Last packet recorded signal strength indicator (RSSI).
\returns Last packet RSSI for LoRa modem, or current RSSI level for FSK modem.
*/
int8_t getRSSI();
float getRSSI();
/*!
\brief Enables/disables CRC check of received packets.
@ -259,14 +259,18 @@ class SX1278: public SX127x {
*/
int16_t setCRC(bool enableCRC);
#ifndef RADIOLIB_GODMODE
protected:
#endif
int16_t setBandwidthRaw(uint8_t newBandwidth);
int16_t setSpreadingFactorRaw(uint8_t newSpreadingFactor);
int16_t setCodingRateRaw(uint8_t newCodingRate);
int16_t configFSK();
#ifndef RADIOLIB_GODMODE
private:
#endif
};

View file

@ -1,7 +1,7 @@
#ifndef _RADIOLIB_SX1279_H
#define _RADIOLIB_SX1279_H
#include "TypeDef.h"
#include "../../TypeDef.h"
#include "SX1278.h"
/*!
@ -11,56 +11,61 @@
*/
class SX1279: public SX1278 {
public:
// constructor
/*!
\brief Default constructor. Called from Arduino sketch when creating new LoRa instance.
\param mod Instance of Module that will be used to communicate with the %LoRa chip.
*/
SX1279(Module* mod);
// basic methods
/*!
\brief %LoRa modem initialization method. Must be called at least once from Arduino sketch to initialize the module.
\param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 960.0 MHz.
\param bw %LoRa link bandwidth in kHz. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz.
\param sf %LoRa link spreading factor. Allowed values range from 6 to 12.
\param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8.
\param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks.
\param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm.
\param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA.
\param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA.
Set to 0 to disable OCP (not recommended).
\param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number.
\param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number.
Allowed values range from 6 to 65535.
\param gain Gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain.
Set to 0 to enable automatic gain control (recommended).
\returns \ref status_codes
*/
int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 17, uint8_t currentLimit = 100, uint16_t preambleLength = 8, uint8_t gain = 0);
// configuration methods
/*!
\brief Sets carrier frequency. Allowed values range from 137.0 MHz to 960.0 MHz.
\param freq Carrier frequency to be set in MHz.
\returns \ref status_codes
*/
int16_t setFrequency(float freq);
#ifndef RADIOLIB_GODMODE
private:
#endif
};
#endif

View file

@ -7,15 +7,15 @@ SX127x::SX127x(Module* mod) : PhysicalLayer(SX127X_CRYSTAL_FREQ, SX127X_DIV_EXPO
int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint8_t currentLimit, uint16_t preambleLength) {
// set module properties
_mod->init(USE_SPI, INT_BOTH);
_mod->init(RADIOLIB_USE_SPI, RADIOLIB_INT_BOTH);
// try to find the SX127x chip
if(!SX127x::findChip(chipVersion)) {
DEBUG_PRINTLN(F("No SX127x found!"));
RADIOLIB_DEBUG_PRINTLN(F("No SX127x found!"));
_mod->term();
return(ERR_CHIP_NOT_FOUND);
} else {
DEBUG_PRINTLN(F("Found SX127x!"));
RADIOLIB_DEBUG_PRINTLN(F("Found SX127x!"));
}
// check active modem
@ -42,6 +42,9 @@ int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint8_t currentLimi
// set preamble length
state = SX127x::setPreambleLength(preambleLength);
if(state != ERR_NONE) {
return(state);
}
// initalize internal variables
_dataRate = 0.0;
@ -51,15 +54,15 @@ 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(USE_SPI, INT_BOTH);
_mod->init(RADIOLIB_USE_SPI, RADIOLIB_INT_BOTH);
// try to find the SX127x chip
if(!SX127x::findChip(chipVersion)) {
DEBUG_PRINTLN(F("No SX127x found!"));
RADIOLIB_DEBUG_PRINTLN(F("No SX127x found!"));
_mod->term();
return(ERR_CHIP_NOT_FOUND);
} else {
DEBUG_PRINTLN(F("Found SX127x!"));
RADIOLIB_DEBUG_PRINTLN(F("Found SX127x!"));
}
// check currently active modem
@ -117,6 +120,27 @@ int16_t SX127x::beginFSK(uint8_t chipVersion, float br, float freqDev, float rxB
// enable/disable OOK
state = setOOK(enableOOK);
if(state != ERR_NONE) {
return(state);
}
// set default RSSI measurement config
state = setRSSIConfig(2);
if(state != ERR_NONE) {
return(state);
}
// set default encoding
state = setEncoding(0);
if(state != ERR_NONE) {
return(state);
}
// set default packet length mode
state = variablePacketLengthMode();
if (state != ERR_NONE) {
return(state);
}
return(state);
}
@ -174,6 +198,8 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) {
return(ERR_TX_TIMEOUT);
}
}
} else {
return(ERR_UNKNOWN);
}
// update data rate
@ -399,7 +425,7 @@ int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
int16_t modem = getActiveModem();
if(modem == SX127X_LORA) {
// check packet length
if(len >= 256) {
if(len >= SX127X_MAX_PACKET_LENGTH) {
return(ERR_PACKET_TOO_LONG);
}
@ -429,7 +455,7 @@ int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
} else if(modem == SX127X_FSK_OOK) {
// check packet length
if(len >= 64) {
if(len >= SX127X_MAX_PACKET_LENGTH_FSK) {
return(ERR_PACKET_TOO_LONG);
}
@ -467,6 +493,9 @@ int16_t SX127x::readData(uint8_t* data, size_t len) {
int16_t modem = getActiveModem();
size_t length = len;
// put module to standby
standby();
if(modem == SX127X_LORA) {
// len set to maximum indicates unknown packet length, read the number of actually received bytes
if(len == SX127X_MAX_PACKET_LENGTH) {
@ -888,6 +917,60 @@ size_t SX127x::getPacketLength(bool update) {
return(_packetLength);
}
int16_t SX127x::fixedPacketLengthMode(uint8_t len) {
return(SX127x::setPacketMode(SX127X_PACKET_FIXED, len));
}
int16_t SX127x::variablePacketLengthMode(uint8_t maxLen) {
return(SX127x::setPacketMode(SX127X_PACKET_VARIABLE, maxLen));
}
int16_t SX127x::setRSSIConfig(uint8_t smoothingSamples, int8_t offset) {
// check active modem
if(getActiveModem() != SX127X_FSK_OOK) {
return(ERR_WRONG_MODEM);
}
// set mode to standby
int16_t state = standby();
if(state != ERR_NONE) {
return(state);
}
// check provided values
if(!(smoothingSamples <= 7)) {
return(ERR_INVALID_NUM_SAMPLES);
}
if(!((offset >= -16) && (offset <= 15))) {
return(ERR_INVALID_RSSI_OFFSET);
}
// set new register values
state = _mod->SPIsetRegValue(SX127X_REG_RSSI_CONFIG, offset, 7, 3);
state |= _mod->SPIsetRegValue(SX127X_REG_RSSI_CONFIG, smoothingSamples, 2, 0);
return(state);
}
int16_t SX127x::setEncoding(uint8_t encoding) {
// check active modem
if(getActiveModem() != SX127X_FSK_OOK) {
return(ERR_WRONG_MODEM);
}
// set encoding
switch(encoding) {
case 0:
return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_DC_FREE_NONE, 6, 5));
case 1:
return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_DC_FREE_MANCHESTER, 6, 5));
case 2:
return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_DC_FREE_WHITENING, 6, 5));
default:
return(ERR_INVALID_ENCODING);
}
}
int16_t SX127x::config() {
// turn off frequency hopping
int16_t state = _mod->SPIsetRegValue(SX127X_REG_HOP_PERIOD, SX127X_HOP_PERIOD_OFF);
@ -943,6 +1026,34 @@ int16_t SX127x::configFSK() {
return(state);
}
int16_t SX127x::setPacketMode(uint8_t mode, uint8_t len) {
// check packet length
if (len > SX127X_MAX_PACKET_LENGTH_FSK) {
return(ERR_PACKET_TOO_LONG);
}
// check active modem
if(getActiveModem() != SX127X_FSK_OOK) {
return(ERR_WRONG_MODEM);
}
// set to fixed packet length
int16_t state = _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, mode, 7, 7);
if(state != ERR_NONE) {
return(state);
}
// set length to register
state = _mod->SPIsetRegValue(SX127X_REG_PAYLOAD_LENGTH_FSK, len);
if(state != ERR_NONE) {
return(state);
}
// update cached value
_packetLengthConfig = mode;
return(state);
}
bool SX127x::findChip(uint8_t ver) {
uint8_t i = 0;
bool flagFound = false;
@ -952,16 +1063,15 @@ bool SX127x::findChip(uint8_t ver) {
flagFound = true;
} else {
#ifdef RADIOLIB_DEBUG
Serial.print(F("SX127x not found! ("));
Serial.print(i + 1);
Serial.print(F(" of 10 tries) SX127X_REG_VERSION == "));
RADIOLIB_DEBUG_PRINT(F("SX127x not found! ("));
RADIOLIB_DEBUG_PRINT(i + 1);
RADIOLIB_DEBUG_PRINT(F(" of 10 tries) SX127X_REG_VERSION == "));
char buffHex[5];
sprintf(buffHex, "0x%02X", version);
Serial.print(buffHex);
Serial.print(F(", expected 0x00"));
Serial.print(ver, HEX);
Serial.println();
RADIOLIB_DEBUG_PRINT(buffHex);
RADIOLIB_DEBUG_PRINT(F(", expected 0x00"));
RADIOLIB_DEBUG_PRINTLN(ver, HEX);
#endif
delay(1000);
i++;
@ -1010,23 +1120,23 @@ void SX127x::clearFIFO(size_t count) {
#ifdef RADIOLIB_DEBUG
void SX127x::regDump() {
Serial.println();
Serial.println(F("ADDR\tVALUE"));
RADIOLIB_DEBUG_PRINTLN();
RADIOLIB_DEBUG_PRINTLN(F("ADDR\tVALUE"));
for(uint16_t addr = 0x01; addr <= 0x70; addr++) {
if(addr <= 0x0F) {
Serial.print(F("0x0"));
RADIOLIB_DEBUG_PRINT(F("0x0"));
} else {
Serial.print(F("0x"));
RADIOLIB_DEBUG_PRINT(F("0x"));
}
Serial.print(addr, HEX);
Serial.print('\t');
RADIOLIB_DEBUG_PRINT(addr, HEX);
RADIOLIB_DEBUG_PRINT('\t');
uint8_t val = _mod->SPIreadRegister(addr);
if(val <= 0x0F) {
Serial.print(F("0x0"));
RADIOLIB_DEBUG_PRINT(F("0x0"));
} else {
Serial.print(F("0x"));
RADIOLIB_DEBUG_PRINT(F("0x"));
}
Serial.println(val, HEX);
RADIOLIB_DEBUG_PRINTLN(val, HEX);
delay(50);
}

View file

@ -1,15 +1,16 @@
#ifndef _RADIOLIB_SX127X_H
#define _RADIOLIB_SX127X_H
#include "TypeDef.h"
#include "Module.h"
#include "../../TypeDef.h"
#include "../../Module.h"
#include "../protocols/PhysicalLayer.h"
#include "../../protocols/PhysicalLayer/PhysicalLayer.h"
// SX127x physical layer properties
#define SX127X_CRYSTAL_FREQ 32.0
#define SX127X_DIV_EXPONENT 19
#define SX127X_MAX_PACKET_LENGTH 256
#define SX127X_MAX_PACKET_LENGTH 255
#define SX127X_MAX_PACKET_LENGTH_FSK 64
// SX127x series common LoRa registers
#define SX127X_REG_FIFO 0x00
@ -842,11 +843,52 @@ class SX127x: public PhysicalLayer {
*/
size_t getPacketLength(bool update = true);
/*!
\brief Set modem in fixed packet length mode. Available in FSK mode only.
\param len Packet length.
\returns \ref status_codes
*/
int16_t fixedPacketLengthMode(uint8_t len = SX127X_MAX_PACKET_LENGTH_FSK);
/*!
\brief Set modem in variable packet length mode. Available in FSK mode only.
\param len Maximum packet length.
\returns \ref status_codes
*/
int16_t variablePacketLengthMode(uint8_t maxLen = SX127X_MAX_PACKET_LENGTH_FSK);
/*!
\brief Sets RSSI measurement configuration in FSK mode.
\param smoothingSamples Number of samples taken to avergae the RSSI result.
numSamples = 2 ^ (1 + smoothingSamples), allowed values are in range 0 (2 samples) - 7 (256 samples)
\param offset Signed RSSI offset that will be automatically compensated. 1 dB per LSB, defaults to 0, allowed values are in range -16 dB to +15 dB.
\returns \ref status_codes
*/
int16_t setRSSIConfig(uint8_t smoothingSamples, int8_t offset = 0);
/*!
\brief Sets transmission encoding. Only available in FSK mode.
\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);
#ifdef RADIOLIB_DEBUG
void regDump();
#endif
#ifndef RADIOLIB_GODMODE
protected:
#endif
Module* _mod;
float _freq;
@ -862,12 +904,15 @@ class SX127x: public PhysicalLayer {
int16_t configFSK();
int16_t getActiveModem();
int16_t directMode();
int16_t setPacketMode(uint8_t mode, uint8_t len);
#ifndef RADIOLIB_GODMODE
private:
#endif
float _dataRate;
size_t _packetLength;
bool _packetLengthQueried; // FSK packet length is the first byte in FIFO, length can only be queried once
uint8_t _packetLengthConfig;
bool findChip(uint8_t ver);
int16_t setMode(uint8_t mode);

View file

@ -5,20 +5,19 @@ XBee::XBee(Module* mod) {
_frameID = 0x01;
_frameLength = 0;
_frameHeaderProcessed = false;
_packetData = new char[0];
}
int16_t XBee::begin(long speed) {
// set module properties
_mod->baudrate = speed;
_mod->init(USE_UART, INT_1);
_mod->init(RADIOLIB_USE_UART, RADIOLIB_INT_1);
// reset module
reset();
// empty UART buffer (garbage data)
_mod->ATemptyBuffer();
// try to find the XBee
bool flagFound = false;
uint8_t i = 0;
@ -26,29 +25,29 @@ int16_t XBee::begin(long speed) {
// hardware reset should return 2 modem status frames - 1st status 0x00, second status 0x06
int16_t state = readApiFrame(0x00, 1, 2000);
readApiFrame(0x00, 1, 2000);
if(state == ERR_NONE) {
flagFound = true;
} else {
DEBUG_PRINT(F("XBee not found! ("));
DEBUG_PRINT(i + 1);
DEBUG_PRINT(F(" of 10 tries) STATE == "));
DEBUG_PRINTLN(state);
DEBUG_PRINTLN(F("Resetting ..."));
RADIOLIB_DEBUG_PRINT(F("XBee not found! ("));
RADIOLIB_DEBUG_PRINT(i + 1);
RADIOLIB_DEBUG_PRINT(F(" of 10 tries) STATE == "));
RADIOLIB_DEBUG_PRINTLN(state);
RADIOLIB_DEBUG_PRINTLN(F("Resetting ..."));
reset();
delay(1000);
_mod->ATemptyBuffer();
i++;
}
}
if(!flagFound) {
DEBUG_PRINTLN(F("No XBee found!"));
RADIOLIB_DEBUG_PRINTLN(F("No XBee found!"));
return(ERR_CMD_MODE_FAILED);
} else {
DEBUG_PRINTLN(F("Found XBee!"));
RADIOLIB_DEBUG_PRINTLN(F("Found XBee!"));
}
return(ERR_NONE);
}
@ -69,18 +68,24 @@ int16_t XBee::transmit(uint8_t* dest, uint8_t* destNetwork, const char* payload,
// build the frame
size_t payloadLen = strlen(payload);
size_t dataLen = 8 + 2 + 1 + 1 + payloadLen;
uint8_t* cmd = new uint8_t[dataLen];
#ifdef RADIOLIB_STATIC_ONLY
uint8_t cmd[RADIOLIB_STATIC_ARRAY_SIZE];
#else
uint8_t* cmd = new uint8_t[dataLen];
#endif
memcpy(cmd, dest, 8);
memcpy(cmd + 8, destNetwork, 2);
cmd[10] = radius;
cmd[11] = 0x01; // options: no retries
memcpy(cmd + 12, payload, payloadLen);
// send frame
uint8_t frameID = _frameID++;
sendApiFrame(XBEE_API_FRAME_ZIGBEE_TRANSMIT_REQUEST, frameID, cmd, dataLen);
delete[] cmd;
#ifndef RADIOLIB_STATIC_ONLY
delete[] cmd;
#endif
// get response code
return(readApiFrame(frameID, 5));
}
@ -90,47 +95,55 @@ size_t XBee::available() {
size_t serialBytes = _mod->ModuleSerial->available();
if(serialBytes < 3) {
return(0);
}
}
uint8_t header[3];
if(!_frameHeaderProcessed) {
// read frame header
for(uint8_t i = 0; i < 3; i++) {
header[i] = _mod->ModuleSerial->read();
}
// check if we received API frame
if(header[0] != XBEE_API_START) {
return(0);
}
// get expected frame length
_frameLength = ((header[1] << 8) | header[2]) + 1;
_frameHeaderProcessed = true;
}
// check if the header is complete
if(serialBytes < _frameLength) {
return(0);
}
uint8_t* frame = new uint8_t[_frameLength]; //24
#ifdef RADIOLIB_STATIC_ONLY
char frame[RADIOLIB_STATIC_ARRAY_SIZE];
#else
uint8_t* frame = new uint8_t[_frameLength];
#endif
for(size_t i = 0; i < _frameLength; i++) {
frame[i] = _mod->ModuleSerial->read();
}
// save packet source and data
size_t payloadLength = _frameLength - 12;
delete[] _packetData;
_packetData = new char[payloadLength];
#ifndef RADIOLIB_STATIC_ONLY
delete[] _packetData;
_packetData = new char[payloadLength];
#endif
memcpy(_packetData, frame + 12, payloadLength - 1);
_packetData[payloadLength - 1] = '\0';
memcpy(_packetSource, frame + 1, 8);
delete[] frame;
#ifndef RADIOLIB_STATIC_ONLY
delete[] frame;
#endif
_frameLength = 0;
_frameHeaderProcessed = false;
// return number of bytes in payload
return(payloadLength);
}
@ -153,48 +166,48 @@ int16_t XBee::setPanId(uint8_t* panId) {
uint8_t cmd[10];
memcpy(cmd, "ID", 2);
memcpy(cmd + 2, panId, 8);
// send frame
uint8_t frameID = _frameID++;
sendApiFrame(XBEE_API_FRAME_AT_COMMAND_QUEUE, frameID, cmd, 10);
// get response code
int16_t state = readApiFrame(frameID, 4);
if(state != ERR_NONE) {
return(state);
}
// confirm changes
return(confirmChanges());
}
XBeeSerial::XBeeSerial(Module* mod) : ISerial(mod) {
}
int16_t XBeeSerial::begin(long speed) {
// set module properties
_mod->AtLineFeed = "\r";
_mod->baudrate = speed;
_mod->init(USE_UART, INT_NONE);
_mod->init(RADIOLIB_USE_UART, RADIOLIB_INT_NONE);
// empty UART buffer (garbage data)
_mod->ATemptyBuffer();
// enter command mode
DEBUG_PRINTLN(F("Entering command mode ..."));
RADIOLIB_DEBUG_PRINTLN(F("Entering command mode ..."));
if(!enterCmdMode()) {
return(ERR_CMD_MODE_FAILED);
}
// test AT setup
DEBUG_PRINTLN(F("Sending test command ..."));
RADIOLIB_DEBUG_PRINTLN(F("Sending test command ..."));
if(!_mod->ATsendCommand("AT")) {
return(ERR_AT_FAILED);
}
// exit command mode
DEBUG_PRINTLN(F("Exiting command mode ..."));
RADIOLIB_DEBUG_PRINTLN(F("Exiting command mode ..."));
if(!_mod->ATsendCommand("ATCN")) {
return(ERR_AT_FAILED);
}
@ -212,93 +225,111 @@ void XBeeSerial::reset() {
int16_t XBeeSerial::setDestinationAddress(const char* destinationAddressHigh, const char* destinationAddressLow) {
// enter command mode
DEBUG_PRINTLN(F("Entering command mode ..."));
RADIOLIB_DEBUG_PRINTLN(F("Entering command mode ..."));
if(!enterCmdMode()) {
return(ERR_CMD_MODE_FAILED);
}
// set higher address bytes
DEBUG_PRINTLN(F("Setting address (high) ..."));
char* addressHigh = new char[strlen(destinationAddressHigh) + 4];
RADIOLIB_DEBUG_PRINTLN(F("Setting address (high) ..."));
#ifdef RADIOLIB_STATIC_ONLY
char addressHigh[13];
#else
char* addressHigh = new char[strlen(destinationAddressHigh) + 4];
#endif
strcpy(addressHigh, "ATDH");
strcat(addressHigh, destinationAddressHigh);
bool res = _mod->ATsendCommand(addressHigh);
delete[] addressHigh;
#ifndef RADIOLIB_STATIC_ONLY
delete[] addressHigh;
#endif
if(!res) {
return(ERR_AT_FAILED);
}
// set lower address bytes
DEBUG_PRINTLN(F("Setting address (low) ..."));
char* addressLow = new char[strlen(destinationAddressLow) + 4];
RADIOLIB_DEBUG_PRINTLN(F("Setting address (low) ..."));
#ifdef RADIOLIB_STATIC_ONLY
char addressLow[13];
#else
char* addressLow = new char[strlen(destinationAddressLow) + 4];
#endif
strcpy(addressLow, "ATDL");
strcat(addressLow, destinationAddressLow);
res = _mod->ATsendCommand(addressLow);
delete[] addressLow;
#ifndef RADIOLIB_STATIC_ONLY
delete[] addressLow;
#endif
if(!res) {
return(ERR_AT_FAILED);
}
// exit command mode
DEBUG_PRINTLN(F("Exiting command mode ..."));
RADIOLIB_DEBUG_PRINTLN(F("Exiting command mode ..."));
if(!_mod->ATsendCommand("ATCN")) {
return(ERR_AT_FAILED);
}
return(ERR_NONE);
}
int16_t XBeeSerial::setPanId(const char* panId) {
// enter command mode
DEBUG_PRINTLN(F("Entering command mode ..."));
RADIOLIB_DEBUG_PRINTLN(F("Entering command mode ..."));
if(!enterCmdMode()) {
return(ERR_CMD_MODE_FAILED);
}
// set PAN ID
DEBUG_PRINTLN(F("Setting PAN ID ..."));
char* cmd = new char[strlen(panId) + 4];
RADIOLIB_DEBUG_PRINTLN(F("Setting PAN ID ..."));
#ifdef RADIOLIB_STATIC_ONLY
char cmd[21];
#else
char* cmd = new char[strlen(panId) + 4];
#endif
strcpy(cmd, "ATID");
strcat(cmd, panId);
bool res = _mod->ATsendCommand(cmd);
delete[] cmd;
#ifndef RADIOLIB_STATIC_ONLY
delete[] cmd;
#endif
if(!res) {
return(ERR_AT_FAILED);
}
// exit command mode
DEBUG_PRINTLN(F("Exiting command mode ..."));
RADIOLIB_DEBUG_PRINTLN(F("Exiting command mode ..."));
if(!_mod->ATsendCommand("ATCN")) {
return(ERR_AT_FAILED);
}
return(ERR_NONE);
}
bool XBeeSerial::enterCmdMode() {
for(uint8_t i = 0; i < 10; i++) {
delay(1000);
_mod->ModuleSerial->write('+');
_mod->ModuleSerial->write('+');
_mod->ModuleSerial->write('+');
delay(1000);
if(_mod->ATgetResponse()) {
return(true);
} else {
DEBUG_PRINT(F("Unable to enter command mode! ("));
DEBUG_PRINT(i + 1);
DEBUG_PRINTLN(F(" of 10 tries)"));
RADIOLIB_DEBUG_PRINT(F("Unable to enter command mode! ("));
RADIOLIB_DEBUG_PRINT(i + 1);
RADIOLIB_DEBUG_PRINTLN(F(" of 10 tries)"));
reset();
_mod->ATsendCommand("ATCN");
}
}
DEBUG_PRINTLN(F("Terminated, check your wiring. Is AT FW uploaded?"));
RADIOLIB_DEBUG_PRINTLN(F("Terminated, check your wiring. Is AT FW uploaded?"));
return(false);
}
@ -306,23 +337,23 @@ int16_t XBee::confirmChanges() {
// save changes to non-volatile memory
uint8_t frameID = _frameID++;
sendApiFrame(XBEE_API_FRAME_AT_COMMAND_QUEUE, frameID, "WR");
// get response code
int16_t state = readApiFrame(frameID, 4);
if(state != ERR_NONE) {
return(state);
}
// apply changes
frameID = _frameID++;
sendApiFrame(XBEE_API_FRAME_AT_COMMAND_QUEUE, frameID, "AC");
// get response code
state = readApiFrame(frameID, 4);
if(state != ERR_NONE) {
return(state);
}
return(state);
}
@ -333,43 +364,49 @@ void XBee::sendApiFrame(uint8_t type, uint8_t id, const char* data) {
void XBee::sendApiFrame(uint8_t type, uint8_t id, uint8_t* data, uint16_t length) {
// build the API frame
size_t frameLength = 1 + 2 + length + 1 + 2;
uint8_t* frame = new uint8_t[frameLength];
#ifdef RADIOLIB_STATIC_ONLY
uint8_t frame[RADIOLIB_STATIC_ARRAY_SIZE];
#else
uint8_t* frame = new uint8_t[frameLength];
#endif
frame[0] = 0x7E; // start delimiter
frame[1] = ((length + 2) & 0xFF00) >> 8; // length MSB
frame[2] = (length + 2) & 0x00FF; // length LSB
frame[3] = type; // frame type
frame[4] = id; // frame ID
memcpy(frame + 5, data, length); // data
// calculate the checksum
uint8_t checksum = 0;
for(uint16_t i = 3; i < frameLength - 1; i++) {
checksum += frame[i];
}
frame[5 + length] = 0xFF - checksum;
// send the frame
for(uint16_t i = 0; i < frameLength; i++) {
_mod->ModuleSerial->write(frame[i]);
}
// deallocate memory
delete[] frame;
#ifndef RADIOLIB_STATIC_ONLY
delete[] frame;
#endif
}
int16_t XBee::readApiFrame(uint8_t frameID, uint8_t codePos, uint16_t timeout) {
// TODO: modemStatus frames may be sent at any time, interfering with frame parsing. Add check to make sure this does not happen.
// get number of bytes in response (must be enough to read the length field
uint16_t numBytes = getNumBytes(timeout/2, 3);
if(numBytes == 0) {
return(ERR_FRAME_NO_RESPONSE);
}
// checksum byte is not included in length field
numBytes++;
// wait until all response bytes are available (5s timeout)
uint32_t start = millis();
while(_mod->ModuleSerial->available() < (int16_t)numBytes) {
@ -377,40 +414,46 @@ int16_t XBee::readApiFrame(uint8_t frameID, uint8_t codePos, uint16_t timeout) {
return(ERR_FRAME_MALFORMED);
}
}
DEBUG_PRINT(F("frame data field length: "));
DEBUG_PRINTLN(numBytes);
RADIOLIB_DEBUG_PRINT(F("frame data field length: "));
RADIOLIB_DEBUG_PRINTLN(numBytes);
// read the response
uint8_t* resp = new uint8_t[numBytes];
#ifdef RADIOLIB_STATIC_ONLY
uint8_t resp[RADIOLIB_STATIC_ARRAY_SIZE];
#else
uint8_t* resp = new uint8_t[numBytes];
#endif
for(uint16_t i = 0; i < numBytes; i++) {
resp[i] = _mod->ModuleSerial->read();
}
// verify checksum
// verify checksum
uint8_t checksum = 0;
for(uint16_t i = 0; i < numBytes; i++) {
DEBUG_PRINT(resp[i], HEX);
DEBUG_PRINT('\t');
RADIOLIB_DEBUG_PRINT(resp[i], HEX);
RADIOLIB_DEBUG_PRINT('\t');
checksum += resp[i];
}
DEBUG_PRINTLN();
RADIOLIB_DEBUG_PRINTLN();
if(checksum != 0xFF) {
DEBUG_PRINTLN(checksum, HEX);
RADIOLIB_DEBUG_PRINTLN(checksum, HEX);
return(ERR_FRAME_INCORRECT_CHECKSUM);
}
// check frame ID
if(resp[1] != frameID) {
DEBUG_PRINT(F("received frame ID: "));
DEBUG_PRINTLN(resp[1]);
DEBUG_PRINT(F("expected frame ID: "));
DEBUG_PRINTLN(frameID);
RADIOLIB_DEBUG_PRINT(F("received frame ID: "));
RADIOLIB_DEBUG_PRINTLN(resp[1]);
RADIOLIB_DEBUG_PRINT(F("expected frame ID: "));
RADIOLIB_DEBUG_PRINTLN(frameID);
return(ERR_FRAME_UNEXPECTED_ID);
}
// codePos does not include start delimiter and frame ID
uint8_t code = resp[codePos];
delete[] resp;
#ifndef RADIOLIB_STATIC_ONLY
delete[] resp;
#endif
return(code);
}
@ -422,21 +465,21 @@ uint16_t XBee::getNumBytes(uint32_t timeout, size_t minBytes) {
return(0);
}
}
// read response
uint8_t resp[3];
uint8_t i = 0;
DEBUG_PRINT(F("reading frame length: "));
RADIOLIB_DEBUG_PRINT(F("reading frame length: "));
while(_mod->ModuleSerial->available() > 0) {
uint8_t b = _mod->ModuleSerial->read();
DEBUG_PRINT(b, HEX);
DEBUG_PRINT('\t');
RADIOLIB_DEBUG_PRINT(b, HEX);
RADIOLIB_DEBUG_PRINT('\t');
resp[i++] = b;
if(i == 3) {
break;
}
}
DEBUG_PRINTLN();
RADIOLIB_DEBUG_PRINTLN();
return((resp[1] << 8) | resp[2]);
}

View file

@ -1,8 +1,8 @@
#ifndef _RADIOLIB_XBEE_H
#define _RADIOLIB_XBEE_H
#include "ISerial.h"
#include "TypeDef.h"
#include "../../ISerial.h"
#include "../../TypeDef.h"
// API reserved characters
#define XBEE_API_START 0x7E
@ -81,7 +81,9 @@ class XBeeSerial: public ISerial {
*/
int16_t setPanId(const char* panID);
#ifndef RADIOLIB_GODMODE
private:
#endif
bool enterCmdMode();
};
@ -170,13 +172,19 @@ class XBee {
*/
int16_t setPanId(uint8_t* panID);
#ifndef RADIOLIB_GODMODE
private:
#endif
Module* _mod;
uint8_t _frameID;
size_t _frameLength;
bool _frameHeaderProcessed;
char* _packetData;
#ifdef RADIOLIB_STATIC_ONLY
char _packetData[RADIOLIB_STATIC_ARRAY_SIZE];
#else
char* _packetData = new char[0];
#endif
uint8_t _packetSource[8];
int16_t confirmChanges();

View file

@ -8,7 +8,7 @@ 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(USE_SPI, INT_BOTH);
_mod->init(RADIOLIB_USE_SPI, RADIOLIB_INT_BOTH);
// override pin mode on INT0 (connected to nRF24 CE pin)
pinMode(_mod->getInt0(), OUTPUT);
@ -20,7 +20,7 @@ int16_t nRF24::begin(int16_t freq, int16_t dataRate, int8_t power, uint8_t addrW
// check SPI connection
int16_t val = _mod->SPIgetRegValue(NRF24_REG_SETUP_AW);
if(!((val >= 1) && (val <= 3))) {
DEBUG_PRINTLN(F("No nRF24 found!"));
RADIOLIB_DEBUG_PRINTLN(F("No nRF24 found!"));
_mod->term();
return(ERR_CHIP_NOT_FOUND);
}
@ -386,6 +386,7 @@ int16_t nRF24::setReceivePipe(uint8_t pipeNum, uint8_t* addr) {
case 0:
_mod->SPIwriteRegisterBurst(NRF24_REG_RX_ADDR_P0, addr, _addrWidth);
state |= _mod->SPIsetRegValue(NRF24_REG_EN_RXADDR, NRF24_P0_ON, 0, 0);
break;
case 1:
_mod->SPIwriteRegisterBurst(NRF24_REG_RX_ADDR_P1, addr, _addrWidth);
state |= _mod->SPIsetRegValue(NRF24_REG_EN_RXADDR, NRF24_P1_ON, 1, 1);

View file

@ -1,10 +1,10 @@
#ifndef _RADIOLIB_NRF24_H
#define _RADIOLIB_NRF24_H
#include "Module.h"
#include "TypeDef.h"
#include "../../Module.h"
#include "../../TypeDef.h"
#include "../protocols/PhysicalLayer.h"
#include "../../protocols/PhysicalLayer/PhysicalLayer.h"
// nRF24 physical layer properties (dummy only)
#define NRF24_CRYSTAL_FREQ 1.0
@ -408,7 +408,9 @@ class nRF24: public PhysicalLayer {
*/
size_t getPacketLength(bool update = true);
#ifndef RADIOLIB_GODMODE
private:
#endif
Module* _mod;
uint8_t _addrWidth;

View file

@ -1,8 +1,8 @@
#ifndef _RADIOLIB_HTTP_H
#define _RADIOLIB_HTTP_H
#include "TypeDef.h"
#include "TransportLayer.h"
#include "../../TypeDef.h"
#include "../TransportLayer/TransportLayer.h"
/*!
@ -58,7 +58,9 @@ class HTTPClient {
*/
int16_t post(const char* url, const char* content, String& response, const char* contentType = "text/plain");
#ifndef RADIOLIB_GODMODE
private:
#endif
TransportLayer* _tl;
uint16_t _port;

View file

@ -18,21 +18,25 @@ int16_t MQTTClient::connect(const char* host, const char* clientId, const char*
remainingLength += (2 + userNameLen);
}
if(passwordLen > 0) {
remainingLength += (2 + passwordLen);
remainingLength += (2 + passwordLen);
}
if((willTopicLen > 0) && (willMessageLen > 0)) {
remainingLength += (2 + willTopicLen) + (2 + willMessageLen);
}
uint8_t encoded[] = {0, 0, 0, 0};
size_t encodedBytes = encodeLength(remainingLength, encoded);
// build the CONNECT packet
uint8_t* packet = new uint8_t[1 + encodedBytes + remainingLength];
#ifdef RADIOLIB_STATIC_ONLY
uint8_t packet[256];
#else
uint8_t* packet = new uint8_t[1 + encodedBytes + remainingLength];
#endif
// fixed header
packet[0] = (MQTT_CONNECT << 4) | 0b0000;
memcpy(packet + 1, encoded, encodedBytes);
// variable header
// protocol name
size_t pos = encodedBytes + 1;
@ -40,42 +44,42 @@ int16_t MQTTClient::connect(const char* host, const char* clientId, const char*
packet[pos++] = 0x04;
memcpy(packet + pos, "MQTT", 4);
pos += 4;
// protocol level
packet[pos++] = 0x04;
// flags
packet[pos++] = 0x04;
// flags
packet[pos++] = 0x00;
if(cleanSession) {
packet[encodedBytes + 8] |= MQTT_CONNECT_CLEAN_SESSION;
}
// keep alive interval in seconds
packet[pos++] = (keepAlive & 0xFF00) >> 8;
packet[pos++] = keepAlive & 0x00FF;
// payload
// clientId
packet[pos++] = (clientIdLen & 0xFF00) >> 8;
packet[pos++] = clientIdLen & 0x00FF;
memcpy(packet + pos, clientId, clientIdLen);
pos += clientIdLen;
// will topic and message
if((willTopicLen > 0) && (willMessageLen > 0)) {
packet[encodedBytes + 8] |= MQTT_CONNECT_WILL_FLAG;
packet[pos++] = (willTopicLen & 0xFF00) >> 8;
packet[pos++] = willTopicLen & 0x00FF;
memcpy(packet + pos, willTopic, willTopicLen);
pos += willTopicLen;
packet[pos++] = (willMessageLen & 0xFF00) >> 8;
packet[pos++] = willMessageLen & 0x00FF;
memcpy(packet + pos, willMessage, willMessageLen);
pos += willMessageLen;
}
// user name
if(userNameLen > 0) {
packet[encodedBytes + 8] |= MQTT_CONNECT_USER_NAME_FLAG;
@ -84,7 +88,7 @@ int16_t MQTTClient::connect(const char* host, const char* clientId, const char*
memcpy(packet + pos, userName, userNameLen);
pos += userNameLen;
}
// password
if(passwordLen > 0) {
packet[encodedBytes + 8] |= MQTT_CONNECT_PASSWORD_FLAG;
@ -93,54 +97,66 @@ int16_t MQTTClient::connect(const char* host, const char* clientId, const char*
memcpy(packet + pos, password, passwordLen);
pos += passwordLen;
}
// create TCP connection
int16_t state = _tl->openTransportConnection(host, "TCP", _port, keepAlive);
if(state != ERR_NONE) {
delete[] packet;
#ifndef RADIOLIB_STATIC_ONLY
delete[] packet;
#endif
return(state);
}
// send MQTT packet
state = _tl->send(packet, 1 + encodedBytes + remainingLength);
delete[] packet;
#ifndef RADIOLIB_STATIC_ONLY
delete[] packet;
#endif
if(state != ERR_NONE) {
return(state);
}
// get the response length (MQTT CONNACK response has to be 4 bytes long)
size_t numBytes = _tl->getNumBytes();
if(numBytes != 4) {
return(ERR_RESPONSE_MALFORMED_AT);
}
// read the response
uint8_t* response = new uint8_t[numBytes];
#ifdef RADIOLIB_STATIC_ONLY
uint8_t response[RADIOLIB_STATIC_ARRAY_SIZE];
#else
uint8_t* response = new uint8_t[numBytes];
#endif
_tl->receive(response, numBytes);
if((response[0] == MQTT_CONNACK << 4) && (response[1] == 2)) {
uint8_t returnCode = response[3];
delete[] response;
#ifndef RADIOLIB_STATIC_ONLY
delete[] response;
#endif
return(returnCode);
}
delete[] response;
#ifndef RADIOLIB_STATIC_ONLY
delete[] response;
#endif
return(ERR_RESPONSE_MALFORMED);
}
int16_t MQTTClient::disconnect() {
// build the DISCONNECT packet
uint8_t packet[2];
// fixed header
packet[0] = (MQTT_DISCONNECT << 4) | 0b0000;
packet[1] = 0x00;
// send MQTT packet
int16_t state = _tl->send(packet, 2);
if(state != ERR_NONE) {
return(state);
}
// close tl connection
return(_tl->closeTransportConnection());
}
@ -156,14 +172,18 @@ int16_t MQTTClient::publish(const char* topic, const char* message) {
uint32_t remainingLength = (2 + topicLen) + messageLen;
uint8_t encoded[] = {0, 0, 0, 0};
size_t encodedBytes = encodeLength(remainingLength, encoded);
// build the PUBLISH packet
uint8_t* packet = new uint8_t[1 + encodedBytes + remainingLength];
#ifdef RADIOLIB_STATIC_ONLY
uint8_t packet[RADIOLIB_STATIC_ARRAY_SIZE];
#else
uint8_t* packet = new uint8_t[1 + encodedBytes + remainingLength];
#endif
// fixed header
packet[0] = (MQTT_PUBLISH << 4) | 0b0000;
memcpy(packet + 1, encoded, encodedBytes);
// variable header
// topic name
size_t pos = encodedBytes + 1;
@ -171,19 +191,21 @@ int16_t MQTTClient::publish(const char* topic, const char* message) {
packet[pos++] = topicLen & 0x00FF;
memcpy(packet + pos, topic, topicLen);
pos += topicLen;
// packet ID
// payload
// message
memcpy(packet + pos, message, messageLen);
pos += messageLen;
// send MQTT packet
int16_t state = _tl->send(packet, 1 + encodedBytes + remainingLength);
delete[] packet;
#ifndef RADIOLIB_STATIC_ONLY
delete[] packet;
#endif
return(state);
//TODO: implement QoS > 0 and PUBACK response checking
}
@ -193,21 +215,25 @@ int16_t MQTTClient::subscribe(const char* topicFilter) {
uint32_t remainingLength = 2 + (2 + topicFilterLen + 1);
uint8_t encoded[] = {0, 0, 0, 0};
size_t encodedBytes = encodeLength(remainingLength, encoded);
// build the SUBSCRIBE packet
uint8_t* packet = new uint8_t[1 + encodedBytes + remainingLength];
#ifdef RADIOLIB_STATIC_ONLY
uint8_t packet[RADIOLIB_STATIC_ARRAY_SIZE];
#else
uint8_t* packet = new uint8_t[1 + encodedBytes + remainingLength];
#endif
// fixed header
packet[0] = (MQTT_SUBSCRIBE << 4) | 0b0010;
memcpy(packet + 1, encoded, encodedBytes);
// variable header
// packet ID
size_t pos = encodedBytes + 1;
uint16_t packetId = _packetId++;
packet[pos++] = (packetId & 0xFF00) >> 8;
packet[pos++] = packetId & 0x00FF;
// payload
// topic filter
packet[pos++] = (topicFilterLen & 0xFF00) >> 8;;
@ -215,35 +241,45 @@ int16_t MQTTClient::subscribe(const char* topicFilter) {
memcpy(packet + pos, topicFilter, topicFilterLen);
pos += topicFilterLen;
packet[pos++] = 0x00; // QoS 0
// send MQTT packet
int16_t state = _tl->send(packet, 1 + encodedBytes + remainingLength);
delete[] packet;
#ifndef RADIOLIB_STATIC_ONLY
delete[] packet;
#endif
if(state != ERR_NONE) {
return(state);
}
// get the response length (MQTT SUBACK response has to be 5 bytes long for single subscription)
size_t numBytes = _tl->getNumBytes();
if(numBytes != 5) {
return(ERR_RESPONSE_MALFORMED_AT);
}
// read the response
uint8_t* response = new uint8_t[numBytes];
#ifdef RADIOLIB_STATIC_ONLY
uint8_t response[RADIOLIB_STATIC_ARRAY_SIZE];
#else
uint8_t* response = new uint8_t[numBytes];
#endif
_tl->receive(response, numBytes);
if((response[0] == MQTT_SUBACK << 4) && (response[1] == 3)) {
// check packet ID
uint16_t receivedId = response[3] | response[2] << 8;
int16_t returnCode = response[4];
delete[] response;
#ifndef RADIOLIB_STATIC_ONLY
delete[] response;
#endif
if(receivedId != packetId) {
return(ERR_MQTT_UNEXPECTED_PACKET_ID);
}
return(returnCode);
}
delete[] response;
#ifndef RADIOLIB_STATIC_ONLY
delete[] response;
#endif
return(ERR_RESPONSE_MALFORMED);
}
@ -253,87 +289,109 @@ int16_t MQTTClient::unsubscribe(const char* topicFilter) {
uint32_t remainingLength = 2 + (2 + topicFilterLen);
uint8_t encoded[] = {0, 0, 0, 0};
size_t encodedBytes = encodeLength(remainingLength, encoded);
// build the UNSUBSCRIBE packet
uint8_t* packet = new uint8_t[1 + encodedBytes + remainingLength];
#ifdef RADIOLIB_STATIC_ONLY
uint8_t packet[RADIOLIB_STATIC_ARRAY_SIZE];
#else
uint8_t* packet = new uint8_t[1 + encodedBytes + remainingLength];
#endif
// fixed header
packet[0] = (MQTT_UNSUBSCRIBE << 4) | 0b0010;
memcpy(packet + 1, encoded, encodedBytes);
// variable header
// packet ID
size_t pos = encodedBytes + 1;
uint16_t packetId = _packetId++;
packet[pos++] = (packetId & 0xFF00) >> 8;
packet[pos++] = packetId & 0x00FF;
// payload
// topic filter
packet[pos++] = (topicFilterLen & 0xFF00) >> 8;;
packet[pos++] = topicFilterLen & 0x00FF;
memcpy(packet + pos, topicFilter, topicFilterLen);
pos += topicFilterLen;
// send MQTT packet
int16_t state = _tl->send(packet, 1 + encodedBytes + remainingLength);
delete[] packet;
#ifndef RADIOLIB_STATIC_ONLY
delete[] packet;
#endif
if(state != ERR_NONE) {
return(state);
}
// get the response length (MQTT UNSUBACK response has to be 4 bytes long)
size_t numBytes = _tl->getNumBytes();
if(numBytes != 4) {
return(ERR_RESPONSE_MALFORMED_AT);
}
// read the response
uint8_t* response = new uint8_t[numBytes];
#ifdef RADIOLIB_STATIC_ONLY
uint8_t response[RADIOLIB_STATIC_ARRAY_SIZE];
#else
uint8_t* response = new uint8_t[numBytes];
#endif
_tl->receive(response, numBytes);
if((response[0] == MQTT_UNSUBACK << 4) && (response[1] == 2)) {
// check packet ID
uint16_t receivedId = response[3] | response[2] << 8;
delete[] response;
#ifndef RADIOLIB_STATIC_ONLY
delete[] response;
#endif
if(receivedId != packetId) {
return(ERR_MQTT_UNEXPECTED_PACKET_ID);
}
return(ERR_NONE);
}
delete[] response;
#ifndef RADIOLIB_STATIC_ONLY
delete[] response;
#endif
return(ERR_RESPONSE_MALFORMED);
}
int16_t MQTTClient::ping() {
// build the PINGREQ packet
uint8_t packet[2];
// fixed header
packet[0] = (MQTT_PINGREQ << 4) | 0b0000;
packet[1] = 0x00;
// send MQTT packet
int16_t state = _tl->send(packet, 2);
if(state != ERR_NONE) {
return(state);
}
// get the response length (MQTT PINGRESP response has to be 2 bytes long)
size_t numBytes = _tl->getNumBytes();
if(numBytes != 2) {
return(ERR_RESPONSE_MALFORMED_AT);
}
// read the response
uint8_t* response = new uint8_t[numBytes];
#ifdef RADIOLIB_STATIC_ONLY
uint8_t response[RADIOLIB_STATIC_ARRAY_SIZE];
#else
uint8_t* response = new uint8_t[numBytes];
#endif
_tl->receive(response, numBytes);
if((response[0] == MQTT_PINGRESP << 4) && (response[1] == 0)) {
delete[] response;
#ifndef RADIOLIB_STATIC_ONLY
delete[] response;
#endif
return(ERR_NONE);
}
delete[] response;
#ifndef RADIOLIB_STATIC_ONLY
delete[] response;
#endif
return(ERR_RESPONSE_MALFORMED);
}
@ -343,42 +401,42 @@ int16_t MQTTClient::check(void (*func)(const char*, const char*)) {
if(state != ERR_NONE) {
return(state);
}
// check new data
size_t numBytes = _tl->getNumBytes();
if(numBytes == 0) {
return(ERR_MQTT_NO_NEW_PACKET_AVAILABLE);
}
// read the PUBLISH packet from server
uint8_t* dataIn = new uint8_t[numBytes];
_tl->receive(dataIn, numBytes);
if(dataIn[0] == MQTT_PUBLISH << 4) {
// TODO: properly decode remaining length
uint8_t remainingLength = dataIn[1];
// get the topic
size_t topicLength = dataIn[3] | dataIn[2] << 8;
char* topic = new char[topicLength + 1];
memcpy(topic, dataIn + 4, topicLength);
topic[topicLength] = 0x00;
// get the message
size_t messageLength = remainingLength - topicLength - 2;
char* message = new char[messageLength + 1];
memcpy(message, dataIn + 4 + topicLength, messageLength);
message[messageLength] = 0x00;
// execute the callback function provided by user
func(topic, message);
delete[] topic;
delete[] message;
delete[] dataIn;
return(ERR_NONE);
}
delete[] dataIn;
return(ERR_MQTT_NO_NEW_PACKET_AVAILABLE);
}

View file

@ -1,8 +1,8 @@
#ifndef _RADIOLIB_MQTT_H
#define _RADIOLIB_MQTT_H
#include "TypeDef.h"
#include "TransportLayer.h"
#include "../../TypeDef.h"
#include "../TransportLayer/TransportLayer.h"
// MQTT packet types
#define MQTT_CONNECT 0x01
@ -127,7 +127,9 @@ class MQTTClient {
*/
int16_t check(void (*func)(const char*, const char*));
#ifndef RADIOLIB_GODMODE
private:
#endif
TransportLayer* _tl;
uint16_t _port;

View file

@ -119,9 +119,9 @@ size_t MorseClient::write(uint8_t b) {
// check if the requested code was found in the array
if(found) {
DEBUG_PRINT(mc.c);
DEBUG_PRINT('\t');
DEBUG_PRINTLN(mc.m);
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++) {
@ -145,7 +145,7 @@ size_t MorseClient::write(uint8_t b) {
}
// letter space
DEBUG_PRINTLN();
RADIOLIB_DEBUG_PRINTLN();
delay(_dotLength * 3);
return(1);

View file

@ -1,8 +1,8 @@
#ifndef _RADIOLIB_MORSE_H
#define _RADIOLIB_MORSE_H
#include "TypeDef.h"
#include "PhysicalLayer.h"
#include "../../TypeDef.h"
#include "../PhysicalLayer/PhysicalLayer.h"
#define MORSE_LENGTH 52
@ -67,7 +67,9 @@ class MorseClient {
size_t println(unsigned long, int = DEC);
size_t println(double, int = 2);
#ifndef RADIOLIB_GODMODE
private:
#endif
PhysicalLayer* _phy;
uint32_t _base;
uint16_t _dotLength;

View file

@ -19,7 +19,11 @@ int16_t PhysicalLayer::transmit(__FlashStringHelper* fstr, uint8_t addr) {
}
// dynamically allocate memory
char* str = new char[len];
#ifdef RADIOLIB_STATIC_ONLY
char str[RADIOLIB_STATIC_ARRAY_SIZE];
#else
char* str = new char[len];
#endif
// copy string from flash
p = reinterpret_cast<PGM_P>(fstr);
@ -29,7 +33,9 @@ int16_t PhysicalLayer::transmit(__FlashStringHelper* fstr, uint8_t addr) {
// transmit string
int16_t state = transmit(str, addr);
delete[] str;
#ifndef RADIOLIB_STATIC_ONLY
delete[] str;
#endif
return(state);
}
@ -62,10 +68,14 @@ int16_t PhysicalLayer::readData(String& str, size_t len) {
}
// build a temporary buffer
uint8_t* data = new uint8_t[length + 1];
if(!data) {
return(ERR_MEMORY_ALLOCATION_FAILED);
}
#ifdef RADIOLIB_STATIC_ONLY
uint8_t data[RADIOLIB_STATIC_ARRAY_SIZE + 1];
#else
uint8_t* data = new uint8_t[length + 1];
if(!data) {
return(ERR_MEMORY_ALLOCATION_FAILED);
}
#endif
// read the received data
state = readData(data, length);
@ -79,7 +89,9 @@ int16_t PhysicalLayer::readData(String& str, size_t len) {
}
// deallocate temporary buffer
delete[] data;
#ifndef RADIOLIB_STATIC_ONLY
delete[] data;
#endif
return(state);
}
@ -96,10 +108,14 @@ int16_t PhysicalLayer::receive(String& str, size_t len) {
}
// build a temporary buffer
uint8_t* data = new uint8_t[length + 1];
if(!data) {
return(ERR_MEMORY_ALLOCATION_FAILED);
}
#ifdef RADIOLIB_STATIC_ONLY
uint8_t data[RADIOLIB_STATIC_ARRAY_SIZE + 1];
#else
uint8_t* data = new uint8_t[length + 1];
if(!data) {
return(ERR_MEMORY_ALLOCATION_FAILED);
}
#endif
// attempt packet reception
state = receive(data, length);
@ -118,7 +134,9 @@ int16_t PhysicalLayer::receive(String& str, size_t len) {
}
// deallocate temporary buffer
delete[] data;
#ifndef RADIOLIB_STATIC_ONLY
delete[] data;
#endif
return(state);
}

View file

@ -1,7 +1,7 @@
#ifndef _RADIOLIB_PHYSICAL_LAYER_H
#define _RADIOLIB_PHYSICAL_LAYER_H
#include "TypeDef.h"
#include "../../TypeDef.h"
/*!
\class PhysicalLayer
@ -87,7 +87,7 @@ class PhysicalLayer {
/*!
\brief Sets module to standby.
\returns \ref status_codes
*/
virtual int16_t standby() = 0;
@ -215,7 +215,9 @@ class PhysicalLayer {
*/
virtual size_t getPacketLength(bool update = true) = 0;
#ifndef RADIOLIB_GODMODE
private:
#endif
float _crystalFreq;
uint8_t _divExponent;
size_t _maxPacketLength;

View file

@ -2,20 +2,20 @@
ITA2String::ITA2String(char c) {
_len = 1;
_str = new char[1];
_str[0] = c;
_ita2Len = 0;
}
ITA2String::ITA2String(const char* str) {
_len = strlen(str);
_str = new char[_len];
strcpy(_str, str);
_ita2Len = 0;
}
ITA2String::~ITA2String() {
delete[] _str;
#ifndef RADIOLIB_STATIC_ONLY
delete[] _str;
#endif
}
size_t ITA2String::length() {
@ -32,7 +32,11 @@ size_t ITA2String::length() {
uint8_t* ITA2String::byteArr() {
// create temporary array 2x the string length (figures may be 3 bytes)
uint8_t* temp = new uint8_t[_len*2 + 1];
#ifdef RADIOLIB_STATIC_ONLY
uint8_t temp[RADIOLIB_STATIC_ARRAY_SIZE*2 + 1];
#else
uint8_t* temp = new uint8_t[_len*2 + 1];
#endif
size_t arrayLen = 0;
bool flagFigure = false;
@ -75,7 +79,9 @@ uint8_t* ITA2String::byteArr() {
uint8_t* arr = new uint8_t[arrayLen];
memcpy(arr, temp, arrayLen);
delete[] temp;
#ifndef RADIOLIB_STATIC_ONLY
delete[] temp;
#endif
return(arr);
}
@ -202,7 +208,11 @@ size_t RTTYClient::print(__FlashStringHelper* fstr) {
}
// dynamically allocate memory
char* str = new char[len];
#ifdef RADIOLIB_STATIC_ONLY
char str[RADIOLIB_STATIC_ARRAY_SIZE];
#else
char* str = new char[len];
#endif
// copy string from flash
p = reinterpret_cast<PGM_P>(fstr);
@ -217,7 +227,9 @@ size_t RTTYClient::print(__FlashStringHelper* fstr) {
} else if((_encoding == ASCII) || (_encoding == ASCII_EXTENDED)) {
n = RTTYClient::write((uint8_t*)str, len);
}
delete[] str;
#ifndef RADIOLIB_STATIC_ONLY
delete[] str;
#endif
return(n);
}

View file

@ -1,8 +1,8 @@
#ifndef _RADIOLIB_RTTY_H
#define _RADIOLIB_RTTY_H
#include "TypeDef.h"
#include "PhysicalLayer.h"
#include "../../TypeDef.h"
#include "../PhysicalLayer/PhysicalLayer.h"
#define ITA2_FIGS 0x1B
#define ITA2_LTRS 0x1F
@ -57,8 +57,14 @@ class ITA2String {
*/
uint8_t* byteArr();
#ifndef RADIOLIB_GODMODE
private:
char* _str;
#endif
#ifdef RADIOLIB_STATIC_ONLY
char _str[RADIOLIB_STATIC_ARRAY_SIZE];
#else
char* _str = new char[1];
#endif
size_t _len;
size_t _ita2Len;
@ -137,13 +143,15 @@ class RTTYClient {
size_t println(unsigned long, int = DEC);
size_t println(double, int = 2);
#ifndef RADIOLIB_GODMODE
private:
#endif
PhysicalLayer* _phy;
uint8_t _encoding;
uint32_t _base;
uint32_t _shift;
uint16_t _bitDuration;
uint32_t _bitDuration;
uint8_t _dataBits;
uint8_t _stopBits;

View file

@ -1,7 +1,7 @@
#ifndef _RADIOLIB_TRANSPORT_LAYER_H
#define _RADIOLIB_TRANSPORT_LAYER_H
#include "TypeDef.h"
#include "../../TypeDef.h"
/*!
\class TransportLayer