Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Andrea Guglielmini 2019-11-18 17:03:11 +01:00
commit 53893a6fe1
13 changed files with 472 additions and 79 deletions

View file

@ -90,6 +90,10 @@ setDataShapingOOK KEYWORD2
setCRC KEYWORD2
variablePacketLengthMode KEYWORD2
fixedPacketLengthMode KEYWORD2
setCrcFiltering KEYWORD2
enableSyncWordFiltering KEYWORD2
disableSyncWordFiltering KEYWORD2
setPromiscuous KEYWORD2
# RF69-specific
setAESKey KEYWORD2

View file

@ -4,6 +4,8 @@ CC1101::CC1101(Module* module) : PhysicalLayer(CC1101_CRYSTAL_FREQ, CC1101_DIV_E
_mod = module;
_packetLengthQueried = false;
_packetLengthConfig = CC1101_LENGTH_CONFIG_VARIABLE;
_syncWordLength = CC1101_DEFAULT_SYNC_WORD_LENGTH;
}
int16_t CC1101::begin(float freq, float br, float rxBw, float freqDev, int8_t power) {
@ -441,11 +443,35 @@ 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 > CC1101_MAX_SYNC_WORD_LENGTH)) {
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) {
@ -584,6 +610,76 @@ int16_t CC1101::variablePacketLengthMode(uint8_t maxLen) {
return(state);
}
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);

View file

@ -10,6 +10,9 @@
#define CC1101_CRYSTAL_FREQ 26.0
#define CC1101_DIV_EXPONENT 16
#define CC1101_MAX_PACKET_LENGTH 63
#define CC1101_MAX_SYNC_WORD_LENGTH 2
#define CC1101_DEFAULT_SYNC_WORD_LENGTH 2
#define CC1101_DEFAULT_SYNC_WORD { 0xD3, 0x91 }
// CC1101 SPI commands
#define CC1101_CMD_READ 0b10000000
@ -237,7 +240,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
@ -694,9 +697,24 @@ 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.
@ -766,6 +784,40 @@ class CC1101: public PhysicalLayer {
*/
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);
private:
Module* _mod;
@ -777,6 +829,10 @@ class CC1101: public PhysicalLayer {
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);

View file

@ -3,8 +3,13 @@
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 = RF69_DEFAULT_SYNC_WORD_LENGTH;
}
int16_t RF69::begin(float freq, float br, float rxBw, float freqDev, int8_t power) {
@ -87,8 +92,8 @@ int16_t RF69::begin(float freq, float br, float rxBw, float freqDev, int8_t powe
}
// default sync word values 0x2D01 is the same as the default in LowPowerLab RFM69 library
uint8_t syncWord[] = {0x2D, 0x01};
state = setSyncWord(syncWord, 2);
uint8_t syncWord[] = RF69_DEFAULT_SYNC_WORD;
state = setSyncWord(syncWord, sizeof(syncWord));
if(state != ERR_NONE) {
return(state);
}
@ -495,7 +500,7 @@ int16_t RF69::setOutputPower(int8_t power) {
int16_t RF69::setSyncWord(uint8_t* syncWord, size_t len, uint8_t maxErrBits) {
// check constraints
if((maxErrBits > 7) || (len > 8)) {
if((maxErrBits > 7) || (len > RF69_MAX_SYNC_WORD_LENGTH)) {
return(ERR_INVALID_SYNC_WORD);
}
@ -506,13 +511,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);
}
@ -636,6 +642,71 @@ int16_t RF69::variablePacketLengthMode(uint8_t maxLen) {
return(state);
}
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;

View file

@ -10,6 +10,10 @@
#define RF69_CRYSTAL_FREQ 32.0
#define RF69_DIV_EXPONENT 19
#define RF69_MAX_PACKET_LENGTH 64
#define RF69_MAX_PREAMBLE_LENGTH 4
#define RF69_MAX_SYNC_WORD_LENGTH 8
#define RF69_DEFAULT_SYNC_WORD_LENGTH 2
#define RF69_DEFAULT_SYNC_WORD { 0x2D, 0x01 }
// RF69 register map
#define RF69_REG_FIFO 0x00
@ -646,7 +650,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.
@ -724,6 +728,40 @@ class RF69: public PhysicalLayer {
*/
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);
protected:
Module* _mod;
@ -735,6 +773,10 @@ class RF69: public PhysicalLayer {
bool _packetLengthQueried;
uint8_t _packetLengthConfig;
bool _promiscuous;
uint8_t _syncWordLength;
int16_t config();
int16_t directMode();

50
src/modules/SX1261.cpp Normal file
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

@ -8,9 +8,33 @@
//SX126X_CMD_SET_PA_CONFIG
#define SX126X_PA_CONFIG_SX1261 0x01
#define SX126X_PA_CONFIG_SX1262 0x00
// TODO: implement SX1261 class
using SX1261 = SX1262;
/*!
\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);
private:
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

@ -5,10 +5,6 @@
#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
@ -94,8 +90,6 @@ class SX1262: public SX126x {
int16_t setOutputPower(int8_t power);
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

@ -1036,18 +1036,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) {
#ifdef STATIC_ONLY
uint8_t dat[STATIC_ARRAY_SIZE + 2];
#else
uint8_t* dat = new uint8_t[2 + numBytes];
#endif
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);
#ifndef STATIC_ONLY
delete[] dat;
#endif
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);
}
@ -1057,34 +1047,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) {
#ifdef STATIC_ONLY
uint8_t dat[STATIC_ARRAY_SIZE + 1];
#else
uint8_t* dat = new uint8_t[1 + numBytes];
#endif
dat[0] = offset;
memcpy(dat + 1, data, numBytes);
int16_t state = SPIwriteCommand(SX126X_CMD_WRITE_BUFFER, dat, 1 + numBytes);
#ifndef STATIC_ONLY
delete[] dat;
#endif
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)
#ifdef STATIC_ONLY
uint8_t dat[STATIC_ARRAY_SIZE + 1];
#else
uint8_t* dat = new uint8_t[1 + numBytes];
#endif
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);
#ifndef STATIC_ONLY
delete[] dat;
#endif
uint8_t cmd[] = { SX126X_CMD_READ_BUFFER, SX126X_CMD_NOP };
int16_t state = SPIreadCommand(cmd, 2, data, numBytes);
return(state);
}
@ -1127,6 +1098,32 @@ int16_t SX126x::setTxParams(uint8_t power, uint8_t rampTime) {
return(SPIwriteCommand(SX126X_CMD_SET_TX_PARAMS, data, 2));
}
// set PA config for optimal consumption as described in section 13-21 of the datasheet.
int16_t SX126x::setOptimalHiPowerPaConfig(int8_t * inOutPower)
{
// the final column of Table 13-21 suggests that the value passed in SetTxParams
// is actually scaled depending on the parameters of setPaConfig.
// Testing confirms this is approximately right
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::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) {
@ -1202,6 +1199,16 @@ int16_t SX126x::setFrequencyRaw(float freq) {
return(ERR_NONE);
}
int16_t SX126x::fixPaClamping() {
uint8_t clampConfig;
uint16_t state = readRegister(SX126X_REG_TX_CLAMP_CONFIG, &clampConfig, 1);
if (state != ERR_NONE) {
return state;
}
clampConfig |= 0x1E;
return writeRegister(SX126X_REG_TX_CLAMP_CONFIG, &clampConfig, 1);
}
int16_t SX126x::config(uint8_t modem) {
// set regulator mode
uint8_t data[7];
@ -1265,14 +1272,20 @@ int16_t SX126x::config(uint8_t modem) {
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) {
@ -1284,6 +1297,9 @@ int16_t SX126x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* d
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();
@ -1294,7 +1310,6 @@ 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)

View file

@ -92,6 +92,7 @@
#define SX126X_REG_OCP_CONFIGURATION 0x08E7
#define SX126X_REG_XTA_TRIM 0x0911
#define SX126X_REG_XTB_TRIM 0x0912
#define SX126X_REG_TX_CLAMP_CONFIG 0x08D8 //Datasheet 15.2
// SX126X SPI command variables
@ -152,6 +153,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
@ -739,6 +741,7 @@ class SX126x: public PhysicalLayer {
int16_t calibrateImage(uint8_t* data);
uint8_t getPacketType();
int16_t setTxParams(uint8_t power, uint8_t rampTime = SX126X_PA_RAMP_200U);
int16_t setOptimalHiPowerPaConfig(int8_t* inOutPower);
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);
@ -751,6 +754,10 @@ class SX126x: public PhysicalLayer {
int16_t setFrequencyRaw(float freq);
/*!
\brief Fixes overly eager PA clamping on SX1262 / SX1268, as described in section 15.2 of the datasheet
*/
int16_t fixPaClamping();
private:
Module* _mod;
@ -767,9 +774,13 @@ class SX126x: public PhysicalLayer {
int16_t config(uint8_t modem);
// 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

@ -147,7 +147,7 @@ class RTTYClient {
uint8_t _encoding;
uint32_t _base;
uint32_t _shift;
uint16_t _bitDuration;
uint32_t _bitDuration;
uint8_t _dataBits;
uint8_t _stopBits;