[Si443x] Added support for Si443x/RFM2x

This commit is contained in:
jgromes 2020-03-30 17:38:04 +02:00
parent 2910351740
commit 83b713b776
18 changed files with 2384 additions and 4 deletions

View file

@ -18,7 +18,9 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github
* __JDY08__ BLE module
* __nRF24L01__ 2.4 GHz module
* __RF69__ FSK/OOK radio module
* __RFM2x__ series FSK modules (RFM22, RM23)
* __RFM9x__ series LoRa modules (RFM95, RM96, RFM97, RFM98)
* __Si443x__ series FSK modules (Si4430, Si4431, Si4432)
* __SX127x__ series LoRa modules (SX1272, SX1273, SX1276, SX1277, SX1278, SX1279)
* __SX126x__ series LoRa modules (SX1261, SX1262, SX1268)
* __SX1231__ FSK/OOK radio module
@ -27,9 +29,9 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github
### Supported protocols:
* __MQTT__ for modules: ESP8266
* __HTTP__ for modules: ESP8266
* __RTTY__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101 and nRF24L01
* __Morse Code__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101 and nRF24L01
* __AX.25__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231 and CC1101
* __RTTY__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x and Si443x
* __Morse Code__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x and Si443x
* __AX.25__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, RFM2x and Si443x
### Supported platforms:
* __Arduino AVR__ - tested with hardware on Uno, Mega and Leonardo
@ -44,7 +46,7 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github
* _Apollo3_ - SparkFun Artemis Redboard etc.
* _Arduino nRF52_ - Arduino Nano 33 BLE
The list above is by no means exhaustive. Most of RadioLib code is independent of the used platform, so as long as your board is running some Arduino-compatible core, RadioLib should work. Compilation of all examples is tested for all platoforms in __bold__ on each git push. Platforms in _italic_ are not tested on each push, but do compile and should be working.
The list above is by no means exhaustive. Most of RadioLib code is independent of the used platform, so as long as your board is running some Arduino-compatible core, RadioLib should work. Compilation of all examples is tested for all platforms in __bold__ on each git push. Platforms in _italic_ are not tested on each push, but do compile and should be working.
### In development:
* __SIM800C__ GSM module

View file

@ -0,0 +1,87 @@
/*
RadioLib Si443x Receive Example
This example receives packets using Si443x FSK radio module.
To successfully receive data, the following settings have to be the same
on both transmitter and receiver:
- carrier frequency
- bit rate
- frequency deviation
- sync word
Other modules from Si443x/RFM2x family can also be used.
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// Si4432 has the following connections:
// nSEL pin: 10
// nIRQ pin: 2
// SDN pin: 9
Si4432 fsk = new Module(10, 2, 9);
// or using RadioShield
// https://github.com/jgromes/RadioShield
//Si4432 fsk = RadioShield.ModuleA;
void setup() {
Serial.begin(9600);
// initialize Si4432 with default settings
Serial.print(F("[Si4432] Initializing ... "));
// carrier frequency: 434.0 MHz
// bit rate: 48.0 kbps
// frequency deviation: 50.0 kHz
// Rx bandwidth: 225.1 kHz
// output power: 11 dBm
// sync word: 0x2D 0x01
int state = fsk.begin();
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
}
void loop() {
Serial.print(F("[Si4432] Waiting for incoming transmission ... "));
// you can receive data as an Arduino String
String str;
int state = fsk.receive(str);
// you can also receive data as byte array
/*
byte byteArr[8];
int state = rf.receive(byteArr, 8);
*/
if (state == ERR_NONE) {
// packet was successfully received
Serial.println(F("success!"));
// print the data of the packet
Serial.print(F("[Si4432] Data:\t\t"));
Serial.println(str);
} else if (state == ERR_RX_TIMEOUT) {
// timeout occurred while waiting for a packet
Serial.println(F("timeout!"));
} else if (state == ERR_CRC_MISMATCH) {
// packet was received, but is malformed
Serial.println(F("CRC error!"));
} else {
// some other error occurred
Serial.print(F("failed, code "));
Serial.println(state);
}
}

View file

@ -0,0 +1,139 @@
/*
RadioLib Si443x Receive with Interrupts Example
This example listens for FSK transmissions and tries to
receive them. Once a packet is received, an interrupt is
triggered.
Other modules from Si443x/RFM2x family can also be used.
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// Si4432 has the following connections:
// nSEL pin: 10
// nIRQ pin: 2
// SDN pin: 9
Si4432 fsk = new Module(10, 2, 9);
// or using RadioShield
// https://github.com/jgromes/RadioShield
//Si4432 fsk = RadioShield.ModuleA;
void setup() {
Serial.begin(9600);
// initialize Si4432 with default settings
Serial.print(F("[Si4432] Initializing ... "));
// carrier frequency: 434.0 MHz
// bit rate: 48.0 kbps
// frequency deviation: 50.0 kHz
// Rx bandwidth: 225.1 kHz
// output power: 11 dBm
// sync word: 0x2D 0x01
int state = fsk.begin();
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
// set the function that will be called
// when new packet is received
fsk.setIrqAction(setFlag);
// start listening for packets
Serial.print(F("[Si4432] Starting to listen ... "));
state = fsk.startReceive();
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
// if needed, 'listen' mode can be disabled by calling
// any of the following methods:
//
// fsk.standby()
// fsk.sleep()
// fsk.transmit();
// fsk.receive();
// fsk.readData();
}
// flag to indicate that a packet was received
volatile bool receivedFlag = false;
// disable interrupt when it's not needed
volatile bool enableInterrupt = true;
// this function is called when a complete packet
// is received by the module
// IMPORTANT: this function MUST be 'void' type
// and MUST NOT have any arguments!
void setFlag(void) {
// check if the interrupt is enabled
if(!enableInterrupt) {
return;
}
// we got a packet, set the flag
receivedFlag = true;
}
void loop() {
// check if the flag is set
if(receivedFlag) {
// disable the interrupt service routine while
// processing the data
enableInterrupt = false;
// reset flag
receivedFlag = false;
// you can read received data as an Arduino String
String str;
int state = fsk.readData(str);
// you can also read received data as byte array
/*
byte byteArr[8];
int state = fsk.readData(byteArr, 8);
*/
if (state == ERR_NONE) {
// packet was successfully received
Serial.println(F("[Si4432] Received packet!"));
// print data of the packet
Serial.print(F("[Si4432] Data:\t\t\t"));
Serial.println(str);
} else if (state == ERR_CRC_MISMATCH) {
// packet was received, but is malformed
Serial.println(F("CRC error!"));
} else {
// some other error occurred
Serial.print(F("failed, code "));
Serial.println(state);
}
// put module back to listen mode
fsk.startReceive();
// we're ready to receive more packets,
// enable interrupt service routine
enableInterrupt = true;
}
}

View file

@ -0,0 +1,126 @@
/*
RadioLib Si443x Settings Example
This example shows how to change all the properties of RF69 radio.
RadioLib currently supports the following settings:
- pins (SPI slave select, nIRQ, shutdown)
- carrier frequency
- bit rate
- receiver bandwidth
- frequency deviation
- output power during transmission
- sync word
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// Si4432 has the following connections:
// nSEL pin: 10
// nIRQ pin: 2
// SDN pin: 9
Si4432 fsk1 = new Module(10, 2, 9);
// Si4432 has the following connections:
// nSEL pin: 8
// nIRQ pin: 3
// SDN pin: 7
Si4432 fsk2 = new Module(8, 3, 7);
// or using RadioShield
// https://github.com/jgromes/RadioShield
//Si4432 fsk3 = RadioShield.ModuleB;
void setup() {
Serial.begin(9600);
// initialize Si4432 with default settings
Serial.print(F("[Si4432] Initializing ... "));
// carrier frequency: 434.0 MHz
// bit rate: 48.0 kbps
// frequency deviation: 50.0 kHz
// Rx bandwidth: 225.1 kHz
// output power: 11 dBm
// sync word: 0x2D 0x01
int state = fsk1.begin();
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
// initialize Si4432 with non-default settings
Serial.print(F("[Si4432] Initializing ... "));
// carrier frequency: 868.0 MHz
// bit rate: 200.0 kbps
// frequency deviation: 60.0 kHz
// Rx bandwidth: 335.5 kHz
// output power: 17 dBm
// sync word: 0x2D 0x01
state = fsk2.begin(868.0, 200.0, 60.0, 335.5, 17);
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
// you can also change the settings at runtime
// and check if the configuration was changed successfully
// set carrier frequency to 433.5 MHz
if (fsk1.setFrequency(433.5) == ERR_INVALID_FREQUENCY) {
Serial.println(F("[Si4432] Selected frequency is invalid for this module!"));
while (true);
}
// set bit rate to 100.0 kbps
state = fsk1.setBitRate(100.0);
if (state == ERR_INVALID_BIT_RATE) {
Serial.println(F("[Si4432] Selected bit rate is invalid for this module!"));
while (true);
} else if (state == ERR_INVALID_BIT_RATE_BW_RATIO) {
Serial.println(F("[Si4432] Selected bit rate to bandwidth ratio is invalid!"));
Serial.println(F("[Si4432] Increase receiver bandwidth to set this bit rate."));
while (true);
}
// set receiver bandwidth to 284.8 kHz
state = fsk1.setRxBandwidth(284.8);
if (state == ERR_INVALID_RX_BANDWIDTH) {
Serial.println(F("[Si4432] Selected receiver bandwidth is invalid for this module!"));
while (true);
}
// set frequency deviation to 10.0 kHz
if (fsk1.setFrequencyDeviation(10.0) == ERR_INVALID_FREQUENCY_DEVIATION) {
Serial.println(F("[Si4432] Selected frequency deviation is invalid for this module!"));
while (true);
}
// set output power to 2 dBm
if (fsk1.setOutputPower(2) == ERR_INVALID_OUTPUT_POWER) {
Serial.println(F("[Si4432] Selected output power is invalid for this module!"));
while (true);
}
// up to 4 bytes can be set as sync word
// set sync word to 0x01234567
uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67};
if (fsk1.setSyncWord(syncWord, 4) == ERR_INVALID_SYNC_WORD) {
Serial.println(F("[Si4432] Selected sync word is invalid for this module!"));
while (true);
}
Serial.println(F("[Si4432] All settings changed successfully!"));
}
void loop() {
// nothing here
}

View file

@ -0,0 +1,87 @@
/*
RadioLib Si443x Transmit Example
This example transmits packets using Si4432 FSK radio module.
Each packet contains up to 64 bytes of data, in the form of:
- Arduino String
- null-terminated char array (C-string)
- arbitrary binary data (byte array)
Other modules from Si443x/RFM2x family can also be used.
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// Si4432 has the following connections:
// nSEL pin: 10
// nIRQ pin: 2
// SDN pin: 9
Si4432 fsk = new Module(10, 2, 9);
// or using RadioShield
// https://github.com/jgromes/RadioShield
//Si4432 fsk = RadioShield.ModuleA;
void setup() {
Serial.begin(9600);
// initialize Si4432 with default settings
Serial.print(F("[Si4432] Initializing ... "));
// carrier frequency: 434.0 MHz
// bit rate: 48.0 kbps
// frequency deviation: 50.0 kHz
// Rx bandwidth: 225.1 kHz
// output power: 11 dBm
// sync word: 0x2D 0x01
int state = fsk.begin();
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
}
void loop() {
Serial.print(F("[Si4432] Transmitting packet ... "));
// you can transmit C-string or Arduino string up to
// 64 characters long
// NOTE: transmit() is a blocking method!
// See example Si443x_Transmit_Interrupt for details
// on non-blocking transmission method.
int state = fsk.transmit("Hello World!");
// you can also transmit byte array up to 64 bytes long
/*
byte byteArr[] = {0x01, 0x23, 0x45, 0x56, 0x78, 0xAB, 0xCD, 0xEF};
int state = fsk.transmit(byteArr, 8);
*/
if (state == ERR_NONE) {
// the packet was successfully transmitted
Serial.println(F(" success!"));
} else if (state == ERR_PACKET_TOO_LONG) {
// the supplied packet was longer than 256 bytes
Serial.println(F(" too long!"));
} else if (state == ERR_TX_TIMEOUT) {
// timeout occured while transmitting packet
Serial.println(F(" timeout!"));
} else {
// some other error occurred
Serial.print(F("failed, code "));
Serial.println(state);
}
// wait for a second before transmitting again
delay(1000);
}

View file

@ -0,0 +1,133 @@
/*
RadioLib Si443x Transmit with Interrupts Example
This example transmits packets using Si4432 FSK radio module.
Each packet contains up to 64 bytes of data, in the form of:
- Arduino String
- null-terminated char array (C-string)
- arbitrary binary data (byte array)
Other modules from Si443x/RFM2x family can also be used.
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// Si4432 has the following connections:
// nSEL pin: 10
// nIRQ pin: 2
// SDN pin: 9
Si4432 fsk = new Module(10, 2, 9);
// or using RadioShield
// https://github.com/jgromes/RadioShield
//Si4432 fsk = RadioShield.ModuleA;
// save transmission state between loops
int transmissionState = ERR_NONE;
void setup() {
Serial.begin(9600);
// initialize Si4432 with default settings
Serial.print(F("[Si4432] Initializing ... "));
// carrier frequency: 434.0 MHz
// bit rate: 48.0 kbps
// frequency deviation: 50.0 kHz
// Rx bandwidth: 225.1 kHz
// output power: 11 dBm
// sync word: 0x2D 0x01
int state = fsk.begin();
fsk.setOutputPower(13);
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
// set the function that will be called
// when packet transmission is finished
fsk.setIrqAction(setFlag);
// start transmitting the first packet
Serial.print(F("[Si4432] Sending first packet ... "));
// you can transmit C-string or Arduino string up to
// 64 characters long
transmissionState = fsk.startTransmit("Hello World!");
// you can also transmit byte array up to 64 bytes long
/*
byte byteArr[] = {0x01, 0x23, 0x45, 0x67,
0x89, 0xAB, 0xCD, 0xEF};
state = fsk.startTransmit(byteArr, 8);
*/
}
// flag to indicate that a packet was sent
volatile bool transmittedFlag = false;
// disable interrupt when it's not needed
volatile bool enableInterrupt = true;
// this function is called when a complete packet
// is transmitted by the module
// IMPORTANT: this function MUST be 'void' type
// and MUST NOT have any arguments!
void setFlag(void) {
// check if the interrupt is enabled
if(!enableInterrupt) {
return;
}
// we sent a packet, set the flag
transmittedFlag = true;
}
void loop() {
// check if the previous transmission finished
if(transmittedFlag) {
// disable the interrupt service routine while
// processing the data
enableInterrupt = false;
// reset flag
transmittedFlag = false;
if (transmissionState == ERR_NONE) {
// packet was successfully sent
Serial.println(F("transmission finished!"));
} else {
Serial.print(F("failed, code "));
Serial.println(transmissionState);
}
// wait a second before transmitting again
delay(1000);
// send another one
Serial.print(F("[Si4432] Sending another packet ... "));
// you can transmit C-string or Arduino string up to
// 256 characters long
transmissionState = fsk.startTransmit("Hello World!");
// you can also transmit byte array up to 64 bytes long
/*
byte byteArr[] = {0x01, 0x23, 0x45, 0x67,
0x89, 0xAB, 0xCD, 0xEF};
int state = fsk.startTransmit(byteArr, 8);
*/
// we're ready to send more packets,
// enable interrupt service routine
enableInterrupt = true;
}
}

View file

@ -16,10 +16,15 @@ HC05 KEYWORD1
JDY08 KEYWORD1
nRF24 KEYWORD1
RF69 KEYWORD1
RFM22 KEYWORD1
RFM23 KEYWORD1
RFM95 KEYWORD1
RFM96 KEYWORD1
RFM97 KEYWORD1
RFM98 KEYWORD1
Si4430 KEYWORD1
Si4431 KEYWORD1
Si4432 KEYWORD1
SIM800 KEYWORD1
SX1231 KEYWORD1
SX1261 KEYWORD1
@ -140,6 +145,7 @@ getPacketSource KEYWORD2
getPacketData KEYWORD2
# nRF24
setIrqAction KEYWORD2
setAddressWidth KEYWORD2
setTransmitPipe KEYWORD2
setReceivePipe KEYWORD2

View file

@ -11,6 +11,7 @@
- HC05 Bluetooth module
- JDY08 BLE module
- RF69 FSK module
- Si443x FSK module
- SX126x LoRa/FSK module
- SX127x LoRa/FSK module
- SX1231 FSK module
@ -49,9 +50,14 @@
#include "modules/JDY08/JDY08.h"
#include "modules/nRF24/nRF24.h"
#include "modules/RF69/RF69.h"
#include "modules/RFM2x/RFM22.h"
#include "modules/RFM2x/RFM23.h"
#include "modules/RFM9x/RFM95.h"
#include "modules/RFM9x/RFM96.h"
#include "modules/RFM9x/RFM97.h"
#include "modules/Si443x/Si4430.h"
#include "modules/Si443x/Si4431.h"
#include "modules/Si443x/Si4432.h"
#include "modules/SX1231/SX1231.h"
#include "modules/SX126x/SX1261.h"
#include "modules/SX126x/SX1262.h"

16
src/modules/RFM2x/RFM22.h Normal file
View file

@ -0,0 +1,16 @@
#ifndef _RADIOLIB_RFM22_H
#define _RADIOLIB_RFM22_H
#include "../../TypeDef.h"
#include "../../Module.h"
#include "../Si443x/Si443x.h"
#include "../Si443x/Si4432.h"
/*!
\class RFM22
\brief Only exists as alias for Si4432, since there seems to be no difference between %RFM22 and %Si4432 modules.
*/
using RFM22 = Si4432;
#endif

16
src/modules/RFM2x/RFM23.h Normal file
View file

@ -0,0 +1,16 @@
#ifndef _RADIOLIB_RFM23_H
#define _RADIOLIB_RFM23_H
#include "../../TypeDef.h"
#include "../../Module.h"
#include "../Si443x/Si443x.h"
#include "../Si443x/Si4431.h"
/*!
\class RFM23
\brief Only exists as alias for Si4431, since there seems to be no difference between %RFM23 and %Si4431 modules.
*/
using RFM23 = Si4431;
#endif

View file

@ -0,0 +1,34 @@
#include "Si4430.h"
Si4430::Si4430(Module* mod) : Si4432(mod) {
}
int16_t Si4430::begin(float freq, float br, float freqDev, float rxBw, int8_t power) {
// execute common part
int16_t state = Si443x::begin(br, freqDev, rxBw);
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setFrequency(freq);
RADIOLIB_ASSERT(state);
state = setOutputPower(power);
RADIOLIB_ASSERT(state);
return(state);
}
int16_t Si4430::setFrequency(float freq) {
RADIOLIB_CHECK_RANGE(freq, 900.0, 960.0, ERR_INVALID_FREQUENCY);
// set frequency
return(Si443x::setFrequencyRaw(freq));
}
int16_t Si4430::setOutputPower(int8_t power) {
RADIOLIB_CHECK_RANGE(power, -8, 13, ERR_INVALID_OUTPUT_POWER);
// set output power
return(_mod->SPIsetRegValue(SI443X_REG_TX_POWER, (uint8_t)((power + 8) / 3), 2, 0));
}

View file

@ -0,0 +1,74 @@
#ifndef _RADIOLIB_SI4430_H
#define _RADIOLIB_SI4430_H
#include "../../TypeDef.h"
#include "../../Module.h"
#include "Si4432.h"
/*!
\class Si4430
\brief Derived class for %Si4430 modules.
*/
class Si4430: public Si4432 {
public:
// constructor
/*!
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio chip.
*/
Si4430(Module* mod);
// basic methods
/*!
\brief 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 900.0 MHz to 960.0 MHz.
\param br Bit rate of the FSK transmission in kbps (kilobits per second). Allowed values range from 0.123 to 256.0 kbps.
\param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.625 to 320.0 kbps.
\param rxBw Receiver bandwidth in kHz. Allowed values range from 2.6 to 620.7 kHz.
\param power Transmission output power in dBm. Allowed values range from -8 to 13 dBm in 3 dBm steps.
\returns \ref status_codes
*/
int16_t begin(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 181.1, int8_t power = 10);
// configuration methods
/*!
\brief Sets carrier frequency. Allowed values range from 900.0 MHz to 960.0 MHz.
\param freq Carrier frequency to be set in MHz.
\returns \ref status_codes
*/
int16_t setFrequency(float freq);
/*!
\brief Sets output power. Allowed values range from -8 to 13 dBm in 3 dBm steps.
\param power Output power to be set in dBm.
\returns \ref status_codes
*/
int16_t setOutputPower(int8_t power);
#ifndef RADIOLIB_GODMODE
protected:
#endif
#ifndef RADIOLIB_GODMODE
private:
#endif
};
#endif

View file

@ -0,0 +1,27 @@
#include "Si4431.h"
Si4431::Si4431(Module* mod) : Si4432(mod) {
}
int16_t Si4431::begin(float freq, float br, float freqDev, float rxBw, int8_t power) {
// execute common part
int16_t state = Si443x::begin(br, freqDev, rxBw);
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setFrequency(freq);
RADIOLIB_ASSERT(state);
state = setOutputPower(power);
RADIOLIB_ASSERT(state);
return(state);
}
int16_t Si4431::setOutputPower(int8_t power) {
RADIOLIB_CHECK_RANGE(power, -8, 13, ERR_INVALID_OUTPUT_POWER);
// set output power
return(_mod->SPIsetRegValue(SI443X_REG_TX_POWER, (uint8_t)((power + 8) / 3), 2, 0));
}

View file

@ -0,0 +1,65 @@
#ifndef _RADIOLIB_SI4431_H
#define _RADIOLIB_SI4431_H
#include "../../TypeDef.h"
#include "../../Module.h"
#include "Si4432.h"
/*!
\class Si4431
\brief Derived class for %Si4431 modules.
*/
class Si4431: public Si4432 {
public:
// constructor
/*!
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio chip.
*/
Si4431(Module* mod);
// basic methods
/*!
\brief 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 240.0 MHz to 930.0 MHz.
\param br Bit rate of the FSK transmission in kbps (kilobits per second). Allowed values range from 0.123 to 256.0 kbps.
\param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.625 to 320.0 kbps.
\param rxBw Receiver bandwidth in kHz. Allowed values range from 2.6 to 620.7 kHz.
\param power Transmission output power in dBm. Allowed values range from -8 to 13 dBm in 3 dBm steps.
\returns \ref status_codes
*/
int16_t begin(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 181.1, int8_t power = 10);
// configuration methods
/*!
\brief Sets output power. Allowed values range from -8 to 13 dBm in 3 dBm steps.
\param power Output power to be set in dBm.
\returns \ref status_codes
*/
int16_t setOutputPower(int8_t power);
#ifndef RADIOLIB_GODMODE
protected:
#endif
#ifndef RADIOLIB_GODMODE
private:
#endif
};
#endif

View file

@ -0,0 +1,34 @@
#include "Si4432.h"
Si4432::Si4432(Module* mod) : Si443x(mod) {
}
int16_t Si4432::begin(float freq, float br, float freqDev, float rxBw, int8_t power) {
// execute common part
int16_t state = Si443x::begin(br, freqDev, rxBw);
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setFrequency(freq);
RADIOLIB_ASSERT(state);
state = setOutputPower(power);
RADIOLIB_ASSERT(state);
return(state);
}
int16_t Si4432::setFrequency(float freq) {
RADIOLIB_CHECK_RANGE(freq, 240.0, 930.0, ERR_INVALID_FREQUENCY);
// set frequency
return(Si443x::setFrequencyRaw(freq));
}
int16_t Si4432::setOutputPower(int8_t power) {
RADIOLIB_CHECK_RANGE(power, -1, 20, ERR_INVALID_OUTPUT_POWER);
// set output power
return(_mod->SPIsetRegValue(SI443X_REG_TX_POWER, (uint8_t)((power + 1) / 3), 2, 0));
}

View file

@ -0,0 +1,74 @@
#ifndef _RADIOLIB_SI4432_H
#define _RADIOLIB_SI4432_H
#include "../../TypeDef.h"
#include "../../Module.h"
#include "Si443x.h"
/*!
\class Si4432
\brief Derived class for %Si4432 modules.
*/
class Si4432: public Si443x {
public:
// constructor
/*!
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio chip.
*/
Si4432(Module* mod);
// basic methods
/*!
\brief 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 240.0 MHz to 930.0 MHz.
\param br Bit rate of the FSK transmission in kbps (kilobits per second). Allowed values range from 0.123 to 256.0 kbps.
\param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.625 to 320.0 kbps.
\param rxBw Receiver bandwidth in kHz. Allowed values range from 2.6 to 620.7 kHz.
\param power Transmission output power in dBm. Allowed values range from -1 to 20 dBm in 3 dBm steps.
\returns \ref status_codes
*/
int16_t begin(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 181.1, int8_t power = 11);
// configuration methods
/*!
\brief Sets carrier frequency. Allowed values range from 240.0 MHz to 930.0 MHz.
\param freq Carrier frequency to be set in MHz.
\returns \ref status_codes
*/
int16_t setFrequency(float freq);
/*!
\brief Sets output power. Allowed values range from -1 to 20 dBm in 3 dBm steps.
\param power Output power to be set in dBm.
\returns \ref status_codes
*/
int16_t setOutputPower(int8_t power);
#ifndef RADIOLIB_GODMODE
protected:
#endif
#ifndef RADIOLIB_GODMODE
private:
#endif
};
#endif

View file

@ -0,0 +1,668 @@
#include "Si443x.h"
Si443x::Si443x(Module* mod) : PhysicalLayer(SI443X_FREQUENCY_STEP_SIZE, SI443X_MAX_PACKET_LENGTH) {
_mod = mod;
_packetLengthQueried = false;
}
int16_t Si443x::begin(float br, float freqDev, float rxBw) {
// set module properties
_mod->init(RADIOLIB_USE_SPI);
Module::pinMode(_mod->getIrq(), INPUT);
Module::pinMode(_mod->getRst(), OUTPUT);
Module::digitalWrite(_mod->getRst(), LOW);
// try to find the Si443x chip
if(!Si443x::findChip()) {
RADIOLIB_DEBUG_PRINTLN(F("No Si443x found!"));
_mod->term();
return(ERR_CHIP_NOT_FOUND);
} else {
RADIOLIB_DEBUG_PRINTLN(F("Found Si443x!"));
}
// clear POR interrupt
clearIRQFlags();
// configure settings not accessible by API
int16_t state = config();
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setBitRate(br);
RADIOLIB_ASSERT(state);
state = setFrequencyDeviation(freqDev);
RADIOLIB_ASSERT(state);
state = setRxBandwidth(rxBw);
RADIOLIB_ASSERT(state);
uint8_t syncWord[] = {0x2D, 0x01};
state = setSyncWord(syncWord, sizeof(syncWord));
RADIOLIB_ASSERT(state);
state = packetMode();
RADIOLIB_ASSERT(state);
state = setDataShaping(0);
RADIOLIB_ASSERT(state);
state = setEncoding(0);
RADIOLIB_ASSERT(state);
return(state);
}
void Si443x::reset() {
Module::pinMode(_mod->getRst(), OUTPUT);
Module::digitalWrite(_mod->getRst(), HIGH);
delay(1);
Module::digitalWrite(_mod->getRst(), LOW);
delay(100);
}
int16_t Si443x::transmit(uint8_t* data, size_t len, uint8_t addr) {
// calculate timeout (5ms + 500 % of expected time-on-air)
uint32_t timeout = 5000000 + (uint32_t)((((float)(len * 8)) / (_br * 1000.0)) * 5000000.0);
// start transmission
int16_t state = startTransmit(data, len, addr);
RADIOLIB_ASSERT(state);
// wait for transmission end or timeout
uint32_t start = micros();
while(digitalRead(_mod->getIrq())) {
if(micros() - start > timeout) {
standby();
clearIRQFlags();
return(ERR_TX_TIMEOUT);
}
}
// set mode to standby
state = standby();
// clear interrupt flags
clearIRQFlags();
return(state);
}
int16_t Si443x::receive(uint8_t* data, size_t len) {
// calculate timeout (500 ms + 400 full 64-byte packets at current bit rate)
uint32_t timeout = 500000 + (1.0/(_br*1000.0))*(SI443X_MAX_PACKET_LENGTH*400.0);
// start reception
int16_t state = startReceive();
RADIOLIB_ASSERT(state);
// wait for packet reception or timeout
uint32_t start = micros();
while(digitalRead(_mod->getIrq())) {
if(micros() - start > timeout) {
standby();
clearIRQFlags();
return(ERR_RX_TIMEOUT);
}
}
// read packet data
return(readData(data, len));
}
int16_t Si443x::sleep() {
// disable wakeup timer interrupt
int16_t state = _mod->SPIsetRegValue(SI443X_REG_INTERRUPT_ENABLE_1, 0x00);
RADIOLIB_ASSERT(state);
state = _mod->SPIsetRegValue(SI443X_REG_INTERRUPT_ENABLE_2, 0x00);
RADIOLIB_ASSERT(state);
// enable wakeup timer to set mode to sleep
_mod->SPIwriteRegister(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_ENABLE_WAKEUP_TIMER);
return(state);
}
int16_t Si443x::standby() {
return(_mod->SPIsetRegValue(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_XTAL_ON, 7, 0, 10));
}
int16_t Si443x::transmitDirect(uint32_t frf) {
// user requested to start transmitting immediately (required for RTTY)
if(frf != 0) {
// convert the 24-bit frequency to the format accepted by the module
// TODO integers only
float newFreq = frf / 6400.0;
// check high/low band
uint8_t bandSelect = SI443X_BAND_SELECT_LOW;
uint8_t freqBand = (newFreq / 10) - 24;
if(newFreq >= 480.0) {
bandSelect = SI443X_BAND_SELECT_HIGH;
freqBand = (newFreq / 20) - 24;
}
// calculate register values
uint16_t freqCarrier = ((newFreq / (10 * ((bandSelect >> 5) + 1))) - freqBand - 24) * (uint32_t)64000;
// update registers
_mod->SPIwriteRegister(SI443X_REG_FREQUENCY_BAND_SELECT, SI443X_SIDE_BAND_SELECT_LOW | bandSelect | freqBand);
_mod->SPIwriteRegister(SI443X_REG_NOM_CARRIER_FREQUENCY_1, (uint8_t)((freqCarrier & 0xFF00) >> 8));
_mod->SPIwriteRegister(SI443X_REG_NOM_CARRIER_FREQUENCY_0, (uint8_t)(freqCarrier & 0xFF));
// start direct transmission
directMode();
_mod->SPIwriteRegister(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_TX_ON);
return(ERR_NONE);
}
// activate direct mode
int16_t state = directMode();
RADIOLIB_ASSERT(state);
// start transmitting
_mod->SPIwriteRegister(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_TX_ON);
return(state);
}
int16_t Si443x::receiveDirect() {
// activate direct mode
int16_t state = directMode();
RADIOLIB_ASSERT(state);
// start receiving
_mod->SPIwriteRegister(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_RX_ON);
return(state);
}
int16_t Si443x::packetMode() {
return(_mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_2, SI443X_TX_DATA_SOURCE_FIFO, 5, 4));
}
void Si443x::setIrqAction(void (*func)(void)) {
attachInterrupt(digitalPinToInterrupt(_mod->getIrq()), func, FALLING);
}
void Si443x::clearIrqAction() {
detachInterrupt(digitalPinToInterrupt(_mod->getIrq()));
}
int16_t Si443x::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
// check packet length
if(len > SI443X_MAX_PACKET_LENGTH) {
return(ERR_PACKET_TOO_LONG);
}
// set mode to standby
int16_t state = standby();
RADIOLIB_ASSERT(state);
// clear Tx FIFO
_mod->SPIsetRegValue(SI443X_REG_OP_FUNC_CONTROL_2, SI443X_TX_FIFO_RESET, 0, 0);
_mod->SPIsetRegValue(SI443X_REG_OP_FUNC_CONTROL_2, SI443X_TX_FIFO_CLEAR, 0, 0);
// set interrupt mapping
state = _mod->SPIsetRegValue(SI443X_REG_INTERRUPT_ENABLE_1, SI443X_PACKET_SENT_ENABLED);
RADIOLIB_ASSERT(state);
// clear interrupt flags
clearIRQFlags();
// set packet length
// TODO variable packet length
_mod->SPIwriteRegister(SI443X_REG_TRANSMIT_PACKET_LENGTH, len);
// TODO use header as address field?
(void)addr;
// write packet to FIFO
_mod->SPIwriteRegisterBurst(SI443X_REG_FIFO_ACCESS, data, len);
// set mode to transmit
_mod->SPIwriteRegister(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_TX_ON);
return(state);
}
int16_t Si443x::startReceive() {
// set mode to standby
int16_t state = standby();
RADIOLIB_ASSERT(state);
// clear Rx FIFO
_mod->SPIsetRegValue(SI443X_REG_OP_FUNC_CONTROL_2, SI443X_RX_FIFO_RESET, 1, 1);
_mod->SPIsetRegValue(SI443X_REG_OP_FUNC_CONTROL_2, SI443X_RX_FIFO_CLEAR, 1, 1);
// set interrupt mapping
state = _mod->SPIsetRegValue(SI443X_REG_INTERRUPT_ENABLE_1, SI443X_VALID_PACKET_RECEIVED_ENABLED, SI443X_CRC_ERROR_ENABLED);
RADIOLIB_ASSERT(state);
state = _mod->SPIsetRegValue(SI443X_REG_INTERRUPT_ENABLE_2, 0x00);
RADIOLIB_ASSERT(state);
// clear interrupt flags
clearIRQFlags();
// set mode to receive
_mod->SPIwriteRegister(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_RX_ON);
return(state);
}
int16_t Si443x::readData(uint8_t* data, size_t len) {
// clear interrupt flags
clearIRQFlags();
// get packet length
size_t length = len;
if(len == SI443X_MAX_PACKET_LENGTH) {
length = getPacketLength();
}
// read packet data
_mod->SPIreadRegisterBurst(SI443X_REG_FIFO_ACCESS, length, data);
// clear internal flag so getPacketLength can return the new packet length
_packetLengthQueried = false;
// set mode to standby
int16_t state = standby();
RADIOLIB_ASSERT(state);
// clear interrupt flags
clearIRQFlags();
return(ERR_NONE);
}
int16_t Si443x::setBitRate(float br) {
RADIOLIB_CHECK_RANGE(br, 0.123, 256.0, ERR_INVALID_BIT_RATE);
// check high data rate
uint8_t dataRateMode = SI443X_LOW_DATA_RATE_MODE;
uint8_t exp = 21;
if(br >= 30.0) {
// bit rate above 30 kbps
dataRateMode = SI443X_HIGH_DATA_RATE_MODE;
exp = 16;
}
// calculate raw data rate value
uint16_t txDr = (br * ((uint32_t)1 << exp)) / 1000.0;
// update registers
int16_t state = _mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_1, dataRateMode, 5, 5);
_mod->SPIwriteRegister(SI443X_REG_TX_DATA_RATE_1, (uint8_t)((txDr & 0xFF00) >> 8));
_mod->SPIwriteRegister(SI443X_REG_TX_DATA_RATE_0, (uint8_t)(txDr & 0xFF));
if(state == ERR_NONE) {
_br = br;
}
RADIOLIB_ASSERT(state);
// update clock recovery
state = updateClockRecovery();
return(state);
}
int16_t Si443x::setFrequencyDeviation(float freqDev) {
// set frequency deviation to lowest available setting (required for RTTY)
if(freqDev == 0.0) {
int16_t state = _mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_2, 0x00, 2, 2);
_mod->SPIwriteRegister(SI443X_REG_FREQUENCY_DEVIATION, 0x00);
if(state == ERR_NONE) {
_freqDev = freqDev;
}
}
RADIOLIB_CHECK_RANGE(freqDev, 0.625, 320.0, ERR_INVALID_FREQUENCY_DEVIATION);
// calculate raw frequency deviation value
uint16_t fdev = (uint16_t)(freqDev / 0.625);
// update registers
int16_t state = _mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_2, (uint8_t)((fdev & 0x0100) >> 6), 2, 2);
_mod->SPIwriteRegister(SI443X_REG_FREQUENCY_DEVIATION, (uint8_t)(fdev & 0xFF));
if(state == ERR_NONE) {
_freqDev = freqDev;
}
return(state);
}
int16_t Si443x::setRxBandwidth(float rxBw) {
RADIOLIB_CHECK_RANGE(rxBw, 2.6, 620.7, ERR_INVALID_RX_BANDWIDTH);
// decide which approximation to use for decimation rate and filter tap calculation
uint8_t bypass = SI443X_BYPASS_DEC_BY_3_OFF;
uint8_t decRate = SI443X_IF_FILTER_DEC_RATE;
uint8_t filterSet = SI443X_IF_FILTER_COEFF_SET;
// this is the "well-behaved" section - can be linearly approximated
if((rxBw >= 2.6) && (rxBw <= 4.5)) {
decRate = 5;
filterSet = ((rxBw - 2.1429)/0.3250 + 0.5);
} else if((rxBw > 4.5) && (rxBw <= 8.8)) {
decRate = 4;
filterSet = ((rxBw - 3.9857)/0.6643 + 0.5);
} else if((rxBw > 8.8) && (rxBw <= 17.5)) {
decRate = 3;
filterSet = ((rxBw - 7.6714)/1.3536 + 0.5);
} else if((rxBw > 17.5) && (rxBw <= 34.7)) {
decRate = 2;
filterSet = ((rxBw - 15.2000)/2.6893 + 0.5);
} else if((rxBw > 34.7) && (rxBw <= 69.2)) {
decRate = 1;
filterSet = ((rxBw - 30.2430)/5.3679 + 0.5);
} else if((rxBw > 69.2) && (rxBw <= 137.9)) {
decRate = 0;
filterSet = ((rxBw - 60.286)/10.7000 + 0.5);
// this is the "Lord help thee who tread 'ere" section - no way to approximate this mess
} else if(rxBw == 142.8) {
bypass = SI443X_BYPASS_DEC_BY_3_ON;
decRate = 1;
filterSet = 4;
} else if(rxBw == 167.8) {
bypass = SI443X_BYPASS_DEC_BY_3_ON;
decRate = 1;
filterSet = 5;
} else if(rxBw == 181.1) {
bypass = SI443X_BYPASS_DEC_BY_3_ON;
decRate = 1;
filterSet = 6;
} else if(rxBw == 191.5) {
bypass = SI443X_BYPASS_DEC_BY_3_ON;
decRate = 0;
filterSet = 15;
} else if(rxBw == 225.1) {
bypass = SI443X_BYPASS_DEC_BY_3_ON;
decRate = 0;
filterSet = 1;
} else if(rxBw == 248.8) {
bypass = SI443X_BYPASS_DEC_BY_3_ON;
decRate = 0;
filterSet = 2;
} else if(rxBw == 269.3) {
bypass = SI443X_BYPASS_DEC_BY_3_ON;
decRate = 0;
filterSet = 3;
} else if(rxBw == 284.8) {
bypass = SI443X_BYPASS_DEC_BY_3_ON;
decRate = 0;
filterSet = 4;
} else if(rxBw == 335.5) {
bypass = SI443X_BYPASS_DEC_BY_3_ON;
decRate = 0;
filterSet = 8;
} else if(rxBw == 391.8) {
bypass = SI443X_BYPASS_DEC_BY_3_ON;
decRate = 0;
filterSet = 9;
} else if(rxBw == 420.2) {
bypass = SI443X_BYPASS_DEC_BY_3_ON;
decRate = 0;
filterSet = 10;
} else if(rxBw == 468.4) {
bypass = SI443X_BYPASS_DEC_BY_3_ON;
decRate = 0;
filterSet = 11;
} else if(rxBw == 518.8) {
bypass = SI443X_BYPASS_DEC_BY_3_ON;
decRate = 0;
filterSet = 12;
} else if(rxBw == 577.0) {
bypass = SI443X_BYPASS_DEC_BY_3_ON;
decRate = 0;
filterSet = 13;
} else if(rxBw == 620.7) {
bypass = SI443X_BYPASS_DEC_BY_3_ON;
decRate = 0;
filterSet = 14;
} else {
return(ERR_INVALID_RX_BANDWIDTH);
}
// shift decimation rate bits
decRate <<= 4;
// update register
int16_t state = _mod->SPIsetRegValue(SI443X_REG_IF_FILTER_BANDWIDTH, bypass | decRate | filterSet);
RADIOLIB_ASSERT(state);
// update clock recovery
state = updateClockRecovery();
return(state);
}
int16_t Si443x::setSyncWord(uint8_t* syncWord, size_t len) {
RADIOLIB_CHECK_RANGE(len, 1, 4, ERR_INVALID_SYNC_WORD);
// set mode to standby
int16_t state = standby();
RADIOLIB_ASSERT(state);
// set sync word length
state = _mod->SPIsetRegValue(SI443X_REG_HEADER_CONTROL_2, (uint8_t)(len - 1) << 1, 2, 1);
RADIOLIB_ASSERT(state);
// set sync word bytes
_mod->SPIwriteRegisterBurst(SI443X_REG_SYNC_WORD_3, syncWord, len);
return(state);
}
size_t Si443x::getPacketLength(bool update) {
// TODO variable length mode
if(!_packetLengthQueried && update) {
_packetLength = _mod->SPIreadRegister(SI443X_REG_RECEIVED_PACKET_LENGTH);
_packetLengthQueried = true;
}
return(_packetLength);
}
int16_t Si443x::setEncoding(uint8_t encoding) {
// set mode to standby
int16_t state = standby();
RADIOLIB_ASSERT(state);
// set encoding
// TODO - add inverted Manchester?
switch(encoding) {
case 0:
return(_mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_1, SI443X_MANCHESTER_INVERTED_OFF | SI443X_MANCHESTER_OFF | SI443X_WHITENING_OFF, 2, 0));
case 1:
return(_mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_1, SI443X_MANCHESTER_INVERTED_OFF | SI443X_MANCHESTER_ON | SI443X_WHITENING_OFF, 2, 0));
case 2:
return(_mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_1, SI443X_MANCHESTER_INVERTED_OFF | SI443X_MANCHESTER_OFF | SI443X_WHITENING_ON, 2, 0));
default:
return(ERR_INVALID_ENCODING);
}
}
int16_t Si443x::setDataShaping(float sh) {
// set mode to standby
int16_t state = standby();
RADIOLIB_ASSERT(state);
if(sh == 0.0) {
// set modulation to FSK
return(_mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_2, SI443X_MODULATION_FSK, 1, 0));
} else {
// set modulation to GFSK
// TODO implement fiter configuration - docs claim this should be possible, but seems undocumented
return(_mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_2, SI443X_MODULATION_GFSK, 1, 0));
}
}
int16_t Si443x::setFrequencyRaw(float newFreq) {
// set mode to standby
int16_t state = standby();
RADIOLIB_ASSERT(state);
// check high/low band
uint8_t bandSelect = SI443X_BAND_SELECT_LOW;
uint8_t freqBand = (newFreq / 10) - 24;
if(newFreq >= 480.0) {
bandSelect = SI443X_BAND_SELECT_HIGH;
freqBand = (newFreq / 20) - 24;
}
// calculate register values
uint16_t freqCarrier = ((newFreq / (10 * ((bandSelect >> 5) + 1))) - freqBand - 24) * (uint32_t)64000;
// update registers
state = _mod->SPIsetRegValue(SI443X_REG_FREQUENCY_BAND_SELECT, bandSelect | freqBand, 5, 0);
state |= _mod->SPIsetRegValue(SI443X_REG_NOM_CARRIER_FREQUENCY_1, (uint8_t)((freqCarrier & 0xFF00) >> 8));
state |= _mod->SPIsetRegValue(SI443X_REG_NOM_CARRIER_FREQUENCY_0, (uint8_t)(freqCarrier & 0xFF));
return(state);
}
bool Si443x::findChip() {
uint8_t i = 0;
bool flagFound = false;
while((i < 10) && !flagFound) {
// reset the module
reset();
// check version register
uint8_t version = _mod->SPIreadRegister(SI443X_REG_DEVICE_VERSION);
if(version == SI443X_DEVICE_VERSION) {
flagFound = true;
} else {
#ifdef RADIOLIB_DEBUG
RADIOLIB_DEBUG_PRINT(F("Si443x not found! ("));
RADIOLIB_DEBUG_PRINT(i + 1);
RADIOLIB_DEBUG_PRINT(F(" of 10 tries) SI443X_REG_DEVICE_VERSION == "));
char buffHex[5];
sprintf(buffHex, "0x%02X", version);
RADIOLIB_DEBUG_PRINT(buffHex);
RADIOLIB_DEBUG_PRINT(F(", expected 0x00"));
RADIOLIB_DEBUG_PRINTLN(SI443X_DEVICE_VERSION, HEX);
#endif
delay(1000);
i++;
}
}
return(flagFound);
}
void Si443x::clearIRQFlags() {
_mod->SPIreadRegister(SI443X_REG_INTERRUPT_STATUS_1);
_mod->SPIreadRegister(SI443X_REG_INTERRUPT_STATUS_2);
}
int16_t Si443x::config() {
// set mode to standby
int16_t state = standby();
RADIOLIB_ASSERT(state);
// disable POR and chip ready interrupts
state = _mod->SPIsetRegValue(SI443X_REG_INTERRUPT_ENABLE_2, 0x00);
RADIOLIB_ASSERT(state);
// disable packet header
state = _mod->SPIsetRegValue(SI443X_REG_HEADER_CONTROL_2, SI443X_SYNC_WORD_TIMEOUT_ON | SI443X_HEADER_LENGTH_HEADER_NONE, 7, 4);
RADIOLIB_ASSERT(state);
// disable packet header checking
state = _mod->SPIsetRegValue(SI443X_REG_HEADER_CONTROL_1, SI443X_BROADCAST_ADDR_CHECK_NONE | SI443X_RECEIVED_HEADER_CHECK_NONE);
RADIOLIB_ASSERT(state);
return(state);
}
int16_t Si443x::updateClockRecovery() {
// get the parameters
uint8_t bypass = _mod->SPIgetRegValue(SI443X_REG_IF_FILTER_BANDWIDTH, 7, 7) >> 7;
uint8_t decRate = _mod->SPIgetRegValue(SI443X_REG_IF_FILTER_BANDWIDTH, 6, 4) >> 4;
uint8_t manch = _mod->SPIgetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_1, 1, 1) >> 1;
// calculate oversampling ratio, NCO offset and clock recovery gain
float rxOsr = ((float)(500 * (1 + 2*bypass))) / (((float)((uint16_t)(1) << decRate)) * _br * ((float)(1 + manch)));
uint32_t ncoOff = (_br * (1 + manch) * ((uint32_t)(1) << (20 + decRate))) / (500 * (1 + 2*bypass));
uint16_t crGain = 2 + (((float)(65536.0 * (1 + manch)) * _br) / (rxOsr * (_freqDev / 0.625)));
// convert oversampling ratio from float to fixed point
uint8_t rxOsr_int = (uint8_t)rxOsr;
uint8_t rxOsr_dec = 0;
float rxOsr_temp = rxOsr;
if(rxOsr_temp - rxOsr_int >= 0.5) {
rxOsr_dec |= 0x04;
rxOsr_temp -= 0.5;
}
if(rxOsr_temp - rxOsr_int >= 0.25) {
rxOsr_dec |= 0x02;
rxOsr_temp -= 0.25;
}
if(rxOsr_temp - rxOsr_int >= 0.125) {
rxOsr_dec |= 0x01;
rxOsr_temp -= 0.125;
}
uint16_t rxOsr_fixed = ((uint16_t)rxOsr_int << 3) | ((uint16_t)rxOsr_dec);
// print that whole mess
RADIOLIB_DEBUG_PRINTLN(bypass, HEX);
RADIOLIB_DEBUG_PRINTLN(decRate, HEX);
RADIOLIB_DEBUG_PRINTLN(manch, HEX);
RADIOLIB_DEBUG_PRINT(rxOsr, 3);
RADIOLIB_DEBUG_PRINT('\t');
RADIOLIB_DEBUG_PRINT(rxOsr_int);
RADIOLIB_DEBUG_PRINT('\t');
RADIOLIB_DEBUG_PRINT(rxOsr_int, HEX);
RADIOLIB_DEBUG_PRINT('\t');
RADIOLIB_DEBUG_PRINT(rxOsr_dec);
RADIOLIB_DEBUG_PRINT('\t');
RADIOLIB_DEBUG_PRINT(rxOsr_dec, HEX);
RADIOLIB_DEBUG_PRINT('\t');
RADIOLIB_DEBUG_PRINT(rxOsr_fixed);
RADIOLIB_DEBUG_PRINT('\t');
RADIOLIB_DEBUG_PRINTLN(rxOsr_fixed, HEX);
RADIOLIB_DEBUG_PRINT(ncoOff);
RADIOLIB_DEBUG_PRINT('\t');
RADIOLIB_DEBUG_PRINTLN(ncoOff, HEX);
RADIOLIB_DEBUG_PRINT(crGain);
RADIOLIB_DEBUG_PRINT('\t');
RADIOLIB_DEBUG_PRINTLN(crGain, HEX);
// update oversampling ratio
int16_t state = _mod->SPIsetRegValue(SI443X_REG_CLOCK_REC_OFFSET_2, (uint8_t)((rxOsr_fixed & 0x0700) >> 3), 7, 5);
RADIOLIB_ASSERT(state);
state = _mod->SPIsetRegValue(SI443X_REG_CLOCK_REC_OVERSAMP_RATIO, (uint8_t)(rxOsr_fixed & 0x00FF));
RADIOLIB_ASSERT(state);
// update NCO offset
state = _mod->SPIsetRegValue(SI443X_REG_CLOCK_REC_OFFSET_2, (uint8_t)((ncoOff & 0x0F0000) >> 16), 3, 0);
RADIOLIB_ASSERT(state);
state = _mod->SPIsetRegValue(SI443X_REG_CLOCK_REC_OFFSET_1, (uint8_t)((ncoOff & 0x00FF00) >> 8));
RADIOLIB_ASSERT(state);
state = _mod->SPIsetRegValue(SI443X_REG_CLOCK_REC_OFFSET_0, (uint8_t)(ncoOff & 0x0000FF));
RADIOLIB_ASSERT(state);
// update clock recovery loop gain
state = _mod->SPIsetRegValue(SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_1, (uint8_t)((crGain & 0x0700) >> 8), 2, 0);
RADIOLIB_ASSERT(state);
state = _mod->SPIsetRegValue(SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_0, (uint8_t)(crGain & 0x00FF));
RADIOLIB_ASSERT(state);
return(state);
}
int16_t Si443x::directMode() {
int16_t state = _mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_2, SI443X_TX_DATA_SOURCE_GPIO, 5, 4);
RADIOLIB_ASSERT(state);
state = _mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_2, SI443X_MODULATION_NONE, 1, 0);
return(state);
}

786
src/modules/Si443x/Si443x.h Normal file
View file

@ -0,0 +1,786 @@
#ifndef _RADIOLIB_SI443X_H
#define _RADIOLIB_SI443X_H
#include "../../TypeDef.h"
#include "../../Module.h"
#include "../../protocols/PhysicalLayer/PhysicalLayer.h"
// Si443x physical layer properties
#define SI443X_FREQUENCY_STEP_SIZE 156.25
#define SI443X_MAX_PACKET_LENGTH 64
// Si443x series common registers
#define SI443X_REG_DEVICE_TYPE 0x00
#define SI443X_REG_DEVICE_VERSION 0x01
#define SI443X_REG_DEVICE_STATUS 0x02
#define SI443X_REG_INTERRUPT_STATUS_1 0x03
#define SI443X_REG_INTERRUPT_STATUS_2 0x04
#define SI443X_REG_INTERRUPT_ENABLE_1 0x05
#define SI443X_REG_INTERRUPT_ENABLE_2 0x06
#define SI443X_REG_OP_FUNC_CONTROL_1 0x07
#define SI443X_REG_OP_FUNC_CONTROL_2 0x08
#define SI443X_REG_XOSC_LOAD_CAPACITANCE 0x09
#define SI443X_REG_MCU_OUTPUT_CLOCK 0x0A
#define SI443X_REG_GPIO0_CONFIG 0x0B
#define SI443X_REG_GPIO1_CONFIG 0x0C
#define SI443X_REG_GPIO2_CONFIG 0x0D
#define SI443X_REG_IO_PORT_CONFIG 0x0E
#define SI443X_REG_ADC_CONFIG 0x0F
#define SI443X_REG_ADC_SENSOR_AMP_OFFSET 0x10
#define SI443X_REG_ADC_VALUE 0x11
#define SI443X_REG_TEMP_SENSOR_CONTROL 0x12
#define SI443X_REG_TEMP_VALUE_OFFSET 0x13
#define SI443X_REG_WAKEUP_TIMER_PERIOD_1 0x14
#define SI443X_REG_WAKEUP_TIMER_PERIOD_2 0x15
#define SI443X_REG_WAKEUP_TIMER_PERIOD_3 0x16
#define SI443X_REG_WAKEUP_TIMER_VALUE_1 0x17
#define SI443X_REG_WAKEUP_TIMER_VALUE_2 0x18
#define SI443X_REG_LOW_DC_MODE_DURATION 0x19
#define SI443X_REG_LOW_BATT_DET_THRESHOLD 0x1A
#define SI443X_REG_BATT_VOLTAGE_LEVEL 0x1B
#define SI443X_REG_IF_FILTER_BANDWIDTH 0x1C
#define SI443X_REG_AFC_LOOP_GEARSHIFT_OVERRIDE 0x1D
#define SI443X_REG_AFC_TIMING_CONTROL 0x1E
#define SI443X_REG_CLOCK_REC_GEARSHIFT_OVERRIDE 0x1F
#define SI443X_REG_CLOCK_REC_OVERSAMP_RATIO 0x20
#define SI443X_REG_CLOCK_REC_OFFSET_2 0x21
#define SI443X_REG_CLOCK_REC_OFFSET_1 0x22
#define SI443X_REG_CLOCK_REC_OFFSET_0 0x23
#define SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_1 0x24
#define SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_0 0x25
#define SI443X_REG_RSSI 0x26
#define SI443X_REG_RSSI_CLEAR_CHANNEL_THRESHOLD 0x27
#define SI443X_REG_ANTENNA_DIVERSITY_1 0x28
#define SI443X_REG_ANTENNA_DIVERSITY_2 0x29
#define SI443X_REG_AFC_LIMITER 0x2A
#define SI443X_REG_AFC_CORRECTION 0x2B
#define SI443X_REG_OOK_COUNTER_1 0x2C
#define SI443X_REG_OOK_COUNTER_2 0x2D
#define SI443X_REG_SLICER_PEAK_HOLD 0x2E
#define SI443X_REG_DATA_ACCESS_CONTROL 0x30
#define SI443X_REG_EZMAC_STATUS 0x31
#define SI443X_REG_HEADER_CONTROL_1 0x32
#define SI443X_REG_HEADER_CONTROL_2 0x33
#define SI443X_REG_PREAMBLE_LENGTH 0x34
#define SI443X_REG_PREAMBLE_DET_CONTROL 0x35
#define SI443X_REG_SYNC_WORD_3 0x36
#define SI443X_REG_SYNC_WORD_2 0x37
#define SI443X_REG_SYNC_WORD_1 0x38
#define SI443X_REG_SYNC_WORD_0 0x39
#define SI443X_REG_TRANSMIT_HEADER_3 0x3A
#define SI443X_REG_TRANSMIT_HEADER_2 0x3B
#define SI443X_REG_TRANSMIT_HEADER_1 0x3C
#define SI443X_REG_TRANSMIT_HEADER_0 0x3D
#define SI443X_REG_TRANSMIT_PACKET_LENGTH 0x3E
#define SI443X_REG_CHECK_HEADER_3 0x3F
#define SI443X_REG_CHECK_HEADER_2 0x40
#define SI443X_REG_CHECK_HEADER_1 0x41
#define SI443X_REG_CHECK_HEADER_0 0x42
#define SI443X_REG_HEADER_ENABLE_3 0x43
#define SI443X_REG_HEADER_ENABLE_2 0x44
#define SI443X_REG_HEADER_ENABLE_1 0x45
#define SI443X_REG_HEADER_ENABLE_0 0x46
#define SI443X_REG_RECEIVED_HEADER_3 0x47
#define SI443X_REG_RECEIVED_HEADER_2 0x48
#define SI443X_REG_RECEIVED_HEADER_1 0x49
#define SI443X_REG_RECEIVED_HEADER_0 0x4A
#define SI443X_REG_RECEIVED_PACKET_LENGTH 0x4B
#define SI443X_REG_ADC8_CONTROL 0x4F
#define SI443X_REG_CHANNEL_FILTER_COEFF 0x60
#define SI443X_REG_XOSC_CONTROL_TEST 0x62
#define SI443X_REG_AGC_OVERRIDE_1 0x69
#define SI443X_REG_TX_POWER 0x6D
#define SI443X_REG_TX_DATA_RATE_1 0x6E
#define SI443X_REG_TX_DATA_RATE_0 0x6F
#define SI443X_REG_MODULATION_MODE_CONTROL_1 0x70
#define SI443X_REG_MODULATION_MODE_CONTROL_2 0x71
#define SI443X_REG_FREQUENCY_DEVIATION 0x72
#define SI443X_REG_FREQUENCY_OFFSET_1 0x73
#define SI443X_REG_FREQUENCY_OFFSET_2 0x74
#define SI443X_REG_FREQUENCY_BAND_SELECT 0x75
#define SI443X_REG_NOM_CARRIER_FREQUENCY_1 0x76
#define SI443X_REG_NOM_CARRIER_FREQUENCY_0 0x77
#define SI443X_REG_FREQUENCY_HOPPING_CHANNEL_SEL 0x79
#define SI443X_REG_FREQUENCY_HOPPING_STEP_SIZE 0x7A
#define SI443X_REG_TX_FIFO_CONTROL_1 0x7C
#define SI443X_REG_TX_FIFO_CONTROL_2 0x7D
#define SI443X_REG_RX_FIFO_CONTROL 0x7E
#define SI443X_REG_FIFO_ACCESS 0x7F
// SI443X_REG_DEVICE_TYPE MSB LSB DESCRIPTION
#define SI443X_DEVICE_TYPE 0x08 // 4 0 device identification register
// SI443X_REG_DEVICE_VERSION
#define SI443X_DEVICE_VERSION 0x06 // 4 0 chip version register
// SI443X_REG_DEVICE_STATUS
#define SI443X_RX_TX_FIFO_OVERFLOW 0b10000000 // 7 7 Rx/Tx FIFO overflow flag
#define SI443X_RX_TX_FIFO_UNDERFLOW 0b01000000 // 6 6 Rx/Tx FIFO underflow flag
#define SI443X_RX_FIFO_EMPTY 0b00100000 // 5 5 Rx FIFO empty flag
#define SI443X_HEADER_ERROR 0b00010000 // 4 4 header error flag
#define SI443X_FREQUENCY_ERROR 0b00001000 // 3 3 frequency error flag (frequency outside allowed range)
#define SI443X_TX 0b00000010 // 1 0 power state: Tx
#define SI443X_RX 0b00000001 // 1 0 Rx
#define SI443X_IDLE 0b00000000 // 1 0 idle
// SI443X_REG_INTERRUPT_STATUS_1
#define SI443X_FIFO_LEVEL_ERROR_INTERRUPT 0b10000000 // 7 7 Tx/Rx FIFO overflow or underflow
#define SI443X_TX_FIFO_ALMOST_FULL_INTERRUPT 0b01000000 // 6 6 Tx FIFO almost full
#define SI443X_TX_FIFO_ALMOST_EMPTY_INTERRUPT 0b00100000 // 5 5 Tx FIFO almost empty
#define SI443X_RX_FIFO_ALMOST_FULL_INTERRUPT 0b00010000 // 4 4 Rx FIFO almost full
#define SI443X_EXTERNAL_INTERRUPT 0b00001000 // 3 3 external interrupt occurred on GPIOx
#define SI443X_PACKET_SENT_INTERRUPT 0b00000100 // 2 2 packet transmission done
#define SI443X_VALID_PACKET_RECEIVED_INTERRUPT 0b00000010 // 1 1 valid packet has been received
#define SI443X_CRC_ERROR_INTERRUPT 0b00000001 // 0 0 CRC failed
// SI443X_REG_INTERRUPT_STATUS_2
#define SI443X_SYNC_WORD_DETECTED_INTERRUPT 0b10000000 // 7 7 sync word has been detected
#define SI443X_VALID_PREAMBLE_DETECTED_INTERRUPT 0b01000000 // 6 6 valid preamble has been detected
#define SI443X_INVALID_PREAMBLE_DETECTED_INTERRUPT 0b00100000 // 5 5 invalid preamble has been detected
#define SI443X_RSSI_INTERRUPT 0b00010000 // 4 4 RSSI exceeded programmed threshold
#define SI443X_WAKEUP_TIMER_INTERRUPT 0b00001000 // 3 3 wake-up timer expired
#define SI443X_LOW_BATTERY_INTERRUPT 0b00000100 // 2 2 low battery detected
#define SI443X_CHIP_READY_INTERRUPT 0b00000010 // 1 1 chip ready event detected
#define SI443X_POWER_ON_RESET_INTERRUPT 0b00000001 // 0 0 power-on-reset detected
// SI443X_REG_INTERRUPT_ENABLE_1
#define SI443X_FIFO_LEVEL_ERROR_ENABLED 0b10000000 // 7 7 Tx/Rx FIFO overflow or underflow interrupt enabled
#define SI443X_TX_FIFO_ALMOST_FULL_ENABLED 0b01000000 // 6 6 Tx FIFO almost full interrupt enabled
#define SI443X_TX_FIFO_ALMOST_EMPTY_ENABLED 0b00100000 // 5 5 Tx FIFO almost empty interrupt enabled
#define SI443X_RX_FIFO_ALMOST_FULL_ENABLED 0b00010000 // 4 4 Rx FIFO almost full interrupt enabled
#define SI443X_EXTERNAL_ENABLED 0b00001000 // 3 3 external interrupt interrupt enabled
#define SI443X_PACKET_SENT_ENABLED 0b00000100 // 2 2 packet transmission done interrupt enabled
#define SI443X_VALID_PACKET_RECEIVED_ENABLED 0b00000010 // 1 1 valid packet received interrupt enabled
#define SI443X_CRC_ERROR_ENABLED 0b00000001 // 0 0 CRC failed interrupt enabled
// SI443X_REG_INTERRUPT_ENABLE_2
#define SI443X_SYNC_WORD_DETECTED_ENABLED 0b10000000 // 7 7 sync word interrupt enabled
#define SI443X_VALID_PREAMBLE_DETECTED_ENABLED 0b01000000 // 6 6 valid preamble interrupt enabled
#define SI443X_INVALID_PREAMBLE_DETECTED_ENABLED 0b00100000 // 5 5 invalid preamble interrupt enabled
#define SI443X_RSSI_ENABLED 0b00010000 // 4 4 RSSI exceeded programmed threshold interrupt enabled
#define SI443X_WAKEUP_TIMER_ENABLED 0b00001000 // 3 3 wake-up timer interrupt enabled
#define SI443X_LOW_BATTERY_ENABLED 0b00000100 // 2 2 low battery interrupt enabled
#define SI443X_CHIP_READY_ENABLED 0b00000010 // 1 1 chip ready event interrupt enabled
#define SI443X_POWER_ON_RESET_ENABLED 0b00000001 // 0 0 power-on-reset interrupt enabled
// SI443X_REG_OP_FUNC_CONTROL_1
#define SI443X_SOFTWARE_RESET 0b10000000 // 7 7 reset all registers to default values
#define SI443X_ENABLE_LOW_BATTERY_DETECT 0b01000000 // 6 6 enable low battery detection
#define SI443X_ENABLE_WAKEUP_TIMER 0b00100000 // 5 5 enable wakeup timer
#define SI443X_32_KHZ_RC 0b00000000 // 4 4 32.768 kHz source: RC oscillator (default)
#define SI443X_32_KHZ_XOSC 0b00010000 // 4 4 crystal oscillator
#define SI443X_TX_ON 0b00001000 // 3 3 Tx on in manual transmit mode
#define SI443X_RX_ON 0b00000100 // 2 2 Rx on in manual receive mode
#define SI443X_PLL_ON 0b00000010 // 1 1 PLL on (tune mode)
#define SI443X_XTAL_OFF 0b00000000 // 0 0 crystal oscillator: off (standby mode)
#define SI443X_XTAL_ON 0b00000001 // 0 0 on (ready mode)
// SI443X_REG_OP_FUNC_CONTROL_2
#define SI443X_ANT_DIV_TR_HL_IDLE_L 0b00000000 // 7 5 GPIO1/2 states: Tx/Rx GPIO1 H, GPIO2 L; idle low (default)
#define SI443X_ANT_DIV_TR_LH_IDLE_L 0b00100000 // 7 5 Tx/Rx GPIO1 L, GPIO2 H; idle low
#define SI443X_ANT_DIV_TR_HL_IDLE_H 0b01000000 // 7 5 Tx/Rx GPIO1 H, GPIO2 L; idle high
#define SI443X_ANT_DIV_TR_LH_IDLE_H 0b01100000 // 7 5 Tx/Rx GPIO1 L, GPIO2 H; idle high
#define SI443X_ANT_DIV_TR_ALG_IDLE_L 0b10000000 // 7 5 Tx/Rx diversity algorithm; idle low
#define SI443X_ANT_DIV_TR_ALG_IDLE_H 0b10100000 // 7 5 Tx/Rx diversity algorithm; idle high
#define SI443X_ANT_DIV_TR_ALG_BEACON_IDLE_L 0b11000000 // 7 5 Tx/Rx diversity algorithm (beacon); idle low
#define SI443X_ANT_DIV_TR_ALG_BEACON_IDLE_H 0b11100000 // 7 5 Tx/Rx diversity algorithm (beacon); idle high
#define SI443X_RX_MULTIPACKET_OFF 0b00000000 // 4 4 Rx multipacket: disabled (default)
#define SI443X_RX_MULTIPACKET_ON 0b00010000 // 4 4 enabled
#define SI443X_AUTO_TX_OFF 0b00000000 // 3 3 Tx autotransmit on FIFO almost full: disabled (default)
#define SI443X_AUTO_TX_ON 0b00001000 // 3 3 enabled
#define SI443X_LOW_DUTY_CYCLE_OFF 0b00000000 // 2 2 low duty cycle mode: disabled (default)
#define SI443X_LOW_DUTY_CYCLE_ON 0b00000100 // 2 2 enabled
#define SI443X_RX_FIFO_RESET 0b00000010 // 1 1 Rx FIFO reset/clear: reset (call first)
#define SI443X_RX_FIFO_CLEAR 0b00000000 // 1 1 clear (call second)
#define SI443X_TX_FIFO_RESET 0b00000001 // 0 0 Tx FIFO reset/clear: reset (call first)
#define SI443X_TX_FIFO_CLEAR 0b00000000 // 0 0 clear (call second)
// SI443X_REG_XOSC_LOAD_CAPACITANCE
#define SI443X_XTAL_SHIFT 0b00000000 // 7 7 crystal capacitance configuration:
#define SI443X_XTAL_LOAD_CAPACITANCE 0b01111111 // 6 0 C_int = 1.8 pF + 0.085 pF * SI443X_XTAL_LOAD_CAPACITANCE + 3.7 pF * SI443X_XTAL_SHIFT
// SI443X_REG_MCU_OUTPUT_CLOCK
#define SI443X_CLOCK_TAIL_CYCLES_OFF 0b00000000 // 5 4 additional clock cycles: none (default)
#define SI443X_CLOCK_TAIL_CYCLES_128 0b00010000 // 5 4 128
#define SI443X_CLOCK_TAIL_CYCLES_256 0b00100000 // 5 4 256
#define SI443X_CLOCK_TAIL_CYCLES_512 0b00110000 // 5 4 512
#define SI443X_LOW_FREQ_CLOCK_OFF 0b00000000 // 3 3 32.768 kHz clock output: disabled (default)
#define SI443X_LOW_FREQ_CLOCK_ON 0b00001000 // 3 3 enabled
#define SI443X_MCU_CLOCK_30_MHZ 0b00000000 // 2 0 GPIO clock output: 30 MHz
#define SI443X_MCU_CLOCK_15_MHZ 0b00000001 // 2 0 15 MHz
#define SI443X_MCU_CLOCK_10_MHZ 0b00000010 // 2 0 10 MHz
#define SI443X_MCU_CLOCK_4_MHZ 0b00000011 // 2 0 4 MHz
#define SI443X_MCU_CLOCK_3_MHZ 0b00000100 // 2 0 3 MHz
#define SI443X_MCU_CLOCK_2_MHZ 0b00000101 // 2 0 2 MHz
#define SI443X_MCU_CLOCK_1_MHZ 0b00000110 // 2 0 1 MHz (default)
#define SI443X_MCU_CLOCK_32_KHZ 0b00000111 // 2 0 32.768 kHz
// SI443X_REG_GPIO0_CONFIG + SI443X_REG_GPIO1_CONFIG + SI443X_REG_GPIO2_CONFIG
#define SI443X_GPIOX_DRIVE_STRENGTH 0b00000000 // 7 6 GPIOx drive strength (higher number = stronger drive)
#define SI443X_GPIOX_PULLUP_OFF 0b00000000 // 5 5 GPIOx internal 200k pullup: disabled (default)
#define SI443X_GPIOX_PULLUP_ON 0b00100000 // 5 5 enabled
#define SI443X_GPIO0_POWER_ON_RESET_OUT 0b00000000 // 4 0 GPIOx function: power-on-reset output (GPIO0 only, default)
#define SI443X_GPIO1_POWER_ON_RESET_INV_OUT 0b00000000 // 4 0 inverted power-on-reset output (GPIO1 only, default)
#define SI443X_GPIO2_MCU_CLOCK_OUT 0b00000000 // 4 0 MCU clock output (GPIO2 only, default)
#define SI443X_GPIOX_WAKEUP_OUT 0b00000001 // 4 0 wakeup timer expired output
#define SI443X_GPIOX_LOW_BATTERY_OUT 0b00000010 // 4 0 low battery detect output
#define SI443X_GPIOX_DIGITAL_OUT 0b00000011 // 4 0 direct digital output
#define SI443X_GPIOX_EXT_INT_FALLING_IN 0b00000100 // 4 0 external interrupt, falling edge
#define SI443X_GPIOX_EXT_INT_RISING_IN 0b00000101 // 4 0 external interrupt, rising edge
#define SI443X_GPIOX_EXT_INT_CHANGE_IN 0b00000110 // 4 0 external interrupt, state change
#define SI443X_GPIOX_ADC_IN 0b00000111 // 4 0 ADC analog input
#define SI443X_GPIOX_ANALOG_TEST_N_IN 0b00001000 // 4 0 analog test N input
#define SI443X_GPIOX_ANALOG_TEST_P_IN 0b00001001 // 4 0 analog test P input
#define SI443X_GPIOX_DIGITAL_IN 0b00001010 // 4 0 direct digital input
#define SI443X_GPIOX_DIGITAL_TEST_OUT 0b00001011 // 4 0 digital test output
#define SI443X_GPIOX_ANALOG_TEST_N_OUT 0b00001100 // 4 0 analog test N output
#define SI443X_GPIOX_ANALOG_TEST_P_OUT 0b00001101 // 4 0 analog test P output
#define SI443X_GPIOX_REFERENCE_VOLTAGE_OUT 0b00001110 // 4 0 reference voltage output
#define SI443X_GPIOX_TX_RX_DATA_CLK_OUT 0b00001111 // 4 0 Tx/Rx clock output in direct mode
#define SI443X_GPIOX_TX_DATA_IN 0b00010000 // 4 0 Tx data input direct mode
#define SI443X_GPIOX_EXT_RETRANSMIT_REQUEST_IN 0b00010001 // 4 0 external retransmission request input
#define SI443X_GPIOX_TX_STATE_OUT 0b00010010 // 4 0 Tx state output
#define SI443X_GPIOX_TX_FIFO_ALMOST_FULL_OUT 0b00010011 // 4 0 Tx FIFO almost full output
#define SI443X_GPIOX_RX_DATA_OUT 0b00010100 // 4 0 Rx data output
#define SI443X_GPIOX_RX_STATE_OUT 0b00010101 // 4 0 Rx state output
#define SI443X_GPIOX_RX_FIFO_ALMOST_FULL_OUT 0b00010110 // 4 0 Rx FIFO almost full output
#define SI443X_GPIOX_ANT_DIV_1_OUT 0b00010111 // 4 0 antenna diversity output 1
#define SI443X_GPIOX_ANT_DIV_2_OUT 0b00011000 // 4 0 antenna diversity output 2
#define SI443X_GPIOX_VALID_PREAMBLE_OUT 0b00011001 // 4 0 valid preamble detected output
#define SI443X_GPIOX_INVALID_PREAMBLE_OUT 0b00011010 // 4 0 invalid preamble detected output
#define SI443X_GPIOX_SYNC_WORD_DETECTED_OUT 0b00011011 // 4 0 sync word detected output
#define SI443X_GPIOX_CLEAR_CHANNEL_OUT 0b00011100 // 4 0 clear channel assessment output
#define SI443X_GPIOX_VDD 0b00011101 // 4 0 VDD
#define SI443X_GPIOX_GND 0b00011110 // 4 0 GND
// SI443X_REG_IO_PORT_CONFIG
#define SI443X_GPIO2_EXT_INT_STATE_MASK 0b01000000 // 6 6 external interrupt state mask for: GPIO2
#define SI443X_GPIO1_EXT_INT_STATE_MASK 0b00100000 // 5 5 GPIO1
#define SI443X_GPIO0_EXT_INT_STATE_MASK 0b00010000 // 4 4 GPIO0
#define SI443X_IRQ_BY_SDO_OFF 0b00000000 // 3 3 output IRQ state on SDO pin: disabled (default)
#define SI443X_IRQ_BY_SDO_ON 0b00001000 // 3 3 enabled
#define SI443X_GPIO2_DIGITAL_STATE_MASK 0b00000100 // 2 2 digital state mask for: GPIO2
#define SI443X_GPIO1_DIGITAL_STATE_MASK 0b00000010 // 1 1 GPIO1
#define SI443X_GPIO0_DIGITAL_STATE_MASK 0b00000001 // 0 0 GPIO0
// SI443X_REG_ADC_CONFIG
#define SI443X_ADC_START 0b10000000 // 7 7 ADC control: start measurement
#define SI443X_ADC_RUNNING 0b00000000 // 7 7 measurement in progress
#define SI443X_ADC_DONE 0b10000000 // 7 7 done
#define SI443X_ADC_SOURCE_TEMPERATURE 0b00000000 // 6 4 ADC source: internal temperature sensor (default)
#define SI443X_ADC_SOURCE_GPIO0_SINGLE 0b00010000 // 6 4 single-ended on GPIO0
#define SI443X_ADC_SOURCE_GPIO1_SINGLE 0b00100000 // 6 4 single-ended on GPIO1
#define SI443X_ADC_SOURCE_GPIO2_SINGLE 0b00110000 // 6 4 single-ended on GPIO2
#define SI443X_ADC_SOURCE_GPIO01_DIFF 0b01000000 // 6 4 differential on GPIO0 (+) and GPIO1 (-)
#define SI443X_ADC_SOURCE_GPIO12_DIFF 0b01010000 // 6 4 differential on GPIO1 (+) and GPIO2 (-)
#define SI443X_ADC_SOURCE_GPIO02_DIFF 0b01100000 // 6 4 differential on GPIO0 (+) and GPIO2 (-)
#define SI443X_ADC_SOURCE_GND 0b01110000 // 6 4 GND
#define SI443X_ADC_REFERNCE_BAND_GAP 0b00000000 // 3 2 ADC reference: internal bandgap 1.2 V (default)
#define SI443X_ADC_REFERNCE_VDD_3 0b00001000 // 3 2 VDD/3
#define SI443X_ADC_REFERNCE_VDD_2 0b00001100 // 3 2 VDD/2
#define SI443X_ADC_GAIN 0b00000000 // 1 0 ADC amplifier gain
// SI443X_REG_ADC_SENSOR_AMP_OFFSET
#define SI443X_ADC_OFFSET 0b00000000 // 3 0 ADC offset
// SI443X_REG_TEMP_SENSOR_CONTROL
#define SI443X_TEMP_SENSOR_RANGE_64_TO_64_C 0b00000000 // 7 6 temperature sensor range: -64 to 64 deg. C, 0.5 deg. C resolution (default)
#define SI443X_TEMP_SENSOR_RANGE_64_TO_192_C 0b01000000 // 7 6 -64 to 192 deg. C, 1.0 deg. C resolution
#define SI443X_TEMP_SENSOR_RANGE_0_TO_128_C 0b11000000 // 7 6 0 to 128 deg. C, 0.5 deg. C resolution
#define SI443X_TEMP_SENSOR_RANGE_40_TO_216_F 0b10000000 // 7 6 -40 to 216 deg. F, 1.0 deg. F resolution
#define SI443X_TEMP_SENSOR_KELVIN_TO_CELSIUS_OFF 0b00000000 // 5 5 Kelvin to Celsius offset: disabled
#define SI443X_TEMP_SENSOR_KELVIN_TO_CELSIUS_ON 0b00100000 // 5 5 enabled (default)
#define SI443X_TEMP_SENSOR_TRIM_OFF 0b00000000 // 4 4 temperature sensor trim: disabled (default)
#define SI443X_TEMP_SENSOR_TRIM_ON 0b00010000 // 4 4 enabled
#define SI443X_TEMP_SENSOR_TRIM_VALUE 0b00000000 // 3 0 temperature sensor trim value
// SI443X_REG_WAKEUP_TIMER_PERIOD_1
#define SI443X_WAKEUP_TIMER_EXPONENT 0b00000011 // 4 0 wakeup timer value exponent
// SI443X_REG_WAKEUP_TIMER_PERIOD_2 + SI443X_REG_WAKEUP_TIMER_PERIOD_3
#define SI443X_WAKEUP_TIMER_MANTISSA_MSB 0x00 // 7 0 wakeup timer value:
#define SI443X_WAKEUP_TIMER_MANTISSA_LSB 0x01 // 7 0 T = (4 * SI443X_WAKEUP_TIMER_MANTISSA * 2 ^ SI443X_WAKEUP_TIMER_EXPONENT) / 32.768 ms
// SI443X_REG_LOW_DC_MODE_DURATION
#define SI443X_LOW_DC_MODE_DURATION_MANTISSA 0x01 // 7 0 low duty cycle mode duration: T = (4 * SI443X_LOW_DC_MODE_DURATION_MANTISSA * 2 ^ SI443X_WAKEUP_TIMER_EXPONENT) / 32.768 ms
// SI443X_REG_LOW_BATT_DET_THRESHOLD
#define SI443X_LOW_BATT_DET_THRESHOLD 0b00010100 // 4 0 low battery detection threshold: Vth = 1.7 + SI443X_LOW_BATT_DET_THRESHOLD * 0.05 V (defaults to 2.7 V)
// SI443X_REG_IF_FILTER_BANDWIDTH
#define SI443X_BYPASS_DEC_BY_3_OFF 0b00000000 // 7 7 bypass decimate-by-3 stage: disabled (default)
#define SI443X_BYPASS_DEC_BY_3_ON 0b10000000 // 7 7 enabled
#define SI443X_IF_FILTER_DEC_RATE 0b00000000 // 6 4 IF filter decimation rate
#define SI443X_IF_FILTER_COEFF_SET 0b00000001 // 3 0 IF filter coefficient set selection
// SI443X_REG_AFC_LOOP_GEARSHIFT_OVERRIDE
#define SI443X_AFC_WIDEBAND_OFF 0b00000000 // 7 7 AFC wideband: disabled (default)
#define SI443X_AFC_WIDEBAND_ON 0b10000000 // 7 7 enabled
#define SI443X_AFC_OFF 0b00000000 // 6 6 AFC: disabled
#define SI443X_AFC_ON 0b01000000 // 6 6 enabled (default)
#define SI443X_AFC_HIGH_GEAR_SETTING 0b00000000 // 5 3 AFC high gear setting
#define SI443X_SECOND_PHASE_BIAS_0_DB 0b00000100 // 2 2 second phase antenna selection bias: 0 dB (default)
#define SI443X_SECOND_PHASE_BIAS_1_5_DB 0b00000000 // 2 2 1.5 dB
#define SI443X_MOVING_AVERAGE_TAP_8 0b00000010 // 1 1 moving average filter tap length: 8*Tb
#define SI443X_MOVING_AVERAGE_TAP_4 0b00000000 // 1 1 4*Tb after first preamble (default)
#define SI443X_ZERO_PHASE_RESET_5 0b00000000 // 0 0 reset preamble detector after: 5 zero phases (default)
#define SI443X_ZERO_PHASE_RESET_2 0b00000001 // 0 0 3 zero phases
// SI443X_REG_AFC_TIMING_CONTROL
#define SI443X_SW_ANT_TIMER 0b00000000 // 7 6 number of periods to wait for RSSI to stabilize during antenna switching
#define SI443X_SHORT_WAIT 0b00001000 // 5 3 period to wait after AFC correction
#define SI443X_ANTENNA_SWITCH_WAIT 0b00000010 // 2 0 antenna switching wait time
// SI443X_REG_CLOCK_REC_GEARSHIFT_OVERRIDE
#define SI443X_CLOCK_RECOVER_FAST_GEARSHIFT 0b00000000 // 5 3 clock recovery fast gearshift value
#define SI443X_CLOCK_RECOVER_SLOW_GEARSHIFT 0b00000011 // 2 0 clock recovery slow gearshift value
// SI443X_REG_CLOCK_REC_OVERSAMP_RATIO
#define SI443X_CLOCK_REC_OVERSAMP_RATIO_LSB 0b01100100 // 7 0 oversampling rate LSB, defaults to 12.5 clock cycles per bit
// SI443X_REG_CLOCK_REC_OFFSET_2
#define SI443X_CLOCK_REC_OVERSAMP_RATIO_MSB 0b00000000 // 7 5 oversampling rate MSB, defaults to 12.5 clock cycles per bit
#define SI443X_SECOND_PHASE_SKIP_THRESHOLD 0b00000000 // 4 4 skip seconds phase antenna diversity threshold
#define SI443X_NCO_OFFSET_MSB 0b00000001 // 3 0 NCO offset MSB
// SI443X_REG_CLOCK_REC_OFFSET_1
#define SI443X_NCO_OFFSET_MID 0b01000111 // 7 0 NCO offset MID
// SI443X_REG_CLOCK_REC_OFFSET_0
#define SI443X_NCO_OFFSET_LSB 0b10101110 // 7 0 NCO offset LSB
// SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_1
#define SI443X_RX_COMPENSATION_OFF 0b00000000 // 4 4 Rx compensation for high data rate: disabled (default)
#define SI443X_RX_COMPENSATION_ON 0b00010000 // 4 4 enabled
#define SI443X_CLOCK_REC_GAIN_DOUBLE_OFF 0b00000000 // 3 3 clock recovery gain doubling: disabled (default)
#define SI443X_CLOCK_REC_GAIN_DOUBLE_ON 0b00001000 // 3 3 enabled
#define SI443X_CLOCK_REC_LOOP_GAIN_MSB 0b00000010 // 2 0 clock recovery timing loop gain MSB
// SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_0
#define SI443X_CLOCK_REC_LOOP_GAIN_LSB 0b10001111 // 7 0 clock recovery timing loop gain LSB
// SI443X_REG_RSSI_CLEAR_CHANNEL_THRESHOLD
#define SI443X_RSSI_CLEAR_CHANNEL_THRESHOLD 0b00011110 // 7 0 RSSI clear channel interrupt threshold
// SI443X_REG_AFC_LIMITER
#define SI443X_AFC_LIMITER 0x00 // 7 0 AFC limiter value
// SI443X_REG_OOK_COUNTER_1
#define SI443X_OOK_FREEZE_OFF 0b00000000 // 5 5 OOK moving average detector freeze: disabled (default)
#define SI443X_OOK_FREEZE_ON 0b00100000 // 5 5 enabled
#define SI443X_PEAK_DETECTOR_OFF 0b00000000 // 4 4 peak detector: disabled
#define SI443X_PEAK_DETECTOR_ON 0b00010000 // 4 4 enabled (default)
#define SI443X_OOK_MOVING_AVERAGE_OFF 0b00000000 // 3 3 OOK moving average: disabled
#define SI443X_OOK_MOVING_AVERAGE_ON 0b00001000 // 3 3 enabled (default)
#define SI443X_OOK_COUNTER_MSB 0b00000000 // 2 0 OOK counter MSB
// SI443X_REG_OOK_COUNTER_2
#define SI443X_OOK_COUNTER_LSB 0b10111100 // 7 0 OOK counter LSB
// SI443X_REG_SLICER_PEAK_HOLD
#define SI443X_PEAK_DETECTOR_ATTACK 0b00010000 // 6 4 OOK peak detector attach time
#define SI443X_PEAK_DETECTOR_DECAY 0b00001100 // 3 0 OOK peak detector decay time
// SI443X_REG_DATA_ACCESS_CONTROL
#define SI443X_PACKET_RX_HANDLING_OFF 0b00000000 // 7 7 packet Rx handling: disabled
#define SI443X_PACKET_RX_HANDLING_ON 0b10000000 // 7 7 enabled (default)
#define SI443X_LSB_FIRST_OFF 0b00000000 // 6 6 LSB first transmission: disabled (default)
#define SI443X_LSB_FIRST_ON 0b01000000 // 6 6 enabled
#define SI443X_CRC_DATA_ONLY_OFF 0b00000000 // 5 5 CRC calculated only from data fields: disabled (default)
#define SI443X_CRC_DATA_ONLY_ON 0b00100000 // 5 5 enabled
#define SI443X_SKIP_SECOND_PHASE_PREAMBLE_DET_OFF 0b00000000 // 4 4 skip second phase of preamble detection: disabled (default)
#define SI443X_SKIP_SECOND_PHASE_PREAMBLE_DET_ON 0b00010000 // 4 4 enabled
#define SI443X_PACKET_TX_HANDLING_OFF 0b00000000 // 3 3 packet Tx handling: disabled
#define SI443X_PACKET_TX_HANDLING_ON 0b00001000 // 3 3 enabled (default)
#define SI443X_CRC_OFF 0b00000000 // 2 2 CRC: disabled
#define SI443X_CRC_ON 0b00000100 // 2 2 enabled (default)
#define SI443X_CRC_CCITT 0b00000000 // 1 0 CRC type: CCITT
#define SI443X_CRC_IBM_CRC16 0b00000001 // 1 0 IBM CRC-16 (default)
#define SI443X_CRC_IEC16 0b00000010 // 1 0 IEC-16
#define SI443X_CRC_BIACHEVA 0b00000011 // 1 0 Biacheva
// SI443X_REG_EZMAC_STATUS
#define SI443X_CRC_ALL_ONE 0b01000000 // 6 6 last received CRC was all ones
#define SI443X_PACKET_SEARCHING 0b00100000 // 5 5 radio is searching for a valid packet
#define SI443X_PACKET_RECEIVING 0b00010000 // 4 4 radio is currently receiving packet
#define SI443X_VALID_PACKET_RECEIVED 0b00001000 // 3 3 valid packet was received
#define SI443X_CRC_ERROR 0b00000100 // 2 2 CRC check failed
#define SI443X_PACKET_TRANSMITTING 0b00000010 // 1 1 radio is currently transmitting packet
#define SI443X_PACKET_SENT 0b00000001 // 0 0 packet sent
// SI443X_REG_HEADER_CONTROL_1
#define SI443X_BROADCAST_ADDR_CHECK_NONE 0b00000000 // 7 4 broadcast address check: none (default)
#define SI443X_BROADCAST_ADDR_CHECK_BYTE0 0b00010000 // 7 4 on byte 0
#define SI443X_BROADCAST_ADDR_CHECK_BYTE1 0b00100000 // 7 4 on byte 1
#define SI443X_BROADCAST_ADDR_CHECK_BYTE2 0b01000000 // 7 4 on byte 2
#define SI443X_BROADCAST_ADDR_CHECK_BYTE3 0b10000000 // 7 4 on byte 3
#define SI443X_RECEIVED_HEADER_CHECK_NONE 0b00000000 // 3 0 received header check: none
#define SI443X_RECEIVED_HEADER_CHECK_BYTE0 0b00000001 // 3 0 on byte 0
#define SI443X_RECEIVED_HEADER_CHECK_BYTE1 0b00000010 // 3 0 on byte 1
#define SI443X_RECEIVED_HEADER_CHECK_BYTE2 0b00000100 // 3 0 on byte 2 (default)
#define SI443X_RECEIVED_HEADER_CHECK_BYTE3 0b00001000 // 3 0 on byte 3 (default)
// SI443X_REG_HEADER_CONTROL_2
#define SI443X_SYNC_WORD_TIMEOUT_OFF 0b00000000 // 7 7 ignore timeout period when searching for sync word: disabled (default)
#define SI443X_SYNC_WORD_TIMEOUT_ON 0b10000000 // 7 7 enabled
#define SI443X_HEADER_LENGTH_HEADER_NONE 0b00000000 // 6 4 header length: none
#define SI443X_HEADER_LENGTH_HEADER_3 0b00010000 // 6 4 header 3
#define SI443X_HEADER_LENGTH_HEADER_32 0b00100000 // 6 4 header 3 and 2
#define SI443X_HEADER_LENGTH_HEADER_321 0b00110000 // 6 4 header 3, 2 and 1 (default)
#define SI443X_HEADER_LENGTH_HEADER_3210 0b01000000 // 6 4 header 3, 2, 1, and 0
#define SI443X_FIXED_PACKET_LENGTH_OFF 0b00000000 // 3 3 fixed packet length mode: disabled (default)
#define SI443X_FIXED_PACKET_LENGTH_ON 0b00001000 // 3 3 enabled
#define SI443X_SYNC_LENGTH_SYNC_3 0b00000000 // 2 1 sync word length: sync 3
#define SI443X_SYNC_LENGTH_SYNC_32 0b00000010 // 2 1 sync 3 and 2 (default)
#define SI443X_SYNC_LENGTH_SYNC_321 0b00000100 // 2 1 sync 3, 2 and 1
#define SI443X_SYNC_LENGTH_SYNC_3210 0b00000110 // 2 1 sync 3, 2, 1 and 0
#define SI443X_PREAMBLE_LENGTH_MSB 0b00000000 // 0 0 preamble length MSB
// SI443X_REG_PREAMBLE_LENGTH
#define SI443X_PREAMBLE_LENGTH_LSB 0b00001000 // 0 0 preamble length LSB, defaults to 32 bits
// SI443X_REG_PREAMBLE_DET_CONTROL
#define SI443X_PREAMBLE_DET_THRESHOLD 0b00101000 // 7 3 number of 4-bit nibbles in valid preamble, defaults to 20 bits
#define SI443X_RSSI_OFFSET 0b00000010 // 2 0 RSSI calculation offset, defaults to +8 dB
// SI443X_REG_SYNC_WORD_3 - SI443X_REG_SYNC_WORD_0
#define SI443X_SYNC_WORD_3 0x2D // 7 0 sync word: 4th byte (MSB)
#define SI443X_SYNC_WORD_2 0xD4 // 7 0 3rd byte
#define SI443X_SYNC_WORD_1 0x00 // 7 0 2nd byte
#define SI443X_SYNC_WORD_0 0x00 // 7 0 1st byte (LSB)
// SI443X_REG_CHANNEL_FILTER_COEFF
#define SI443X_INVALID_PREAMBLE_THRESHOLD 0b00000000 // 7 4 invalid preamble threshold in nibbles
// SI443X_REG_XOSC_CONTROL_TEST
#define SI443X_STATE_LOW_POWER 0b00000000 // 7 5 chip power state: low power
#define SI443X_STATE_READY 0b00100000 // 7 5 ready
#define SI443X_STATE_TUNE 0b01100000 // 7 5 tune
#define SI443X_STATE_TX 0b01000000 // 7 5 Tx
#define SI443X_STATE_RX 0b11100000 // 7 5 Rx
// SI443X_REG_AGC_OVERRIDE_1
#define SI443X_AGC_GAIN_INCREASE_OFF 0b00000000 // 6 6 AGC gain increase override: disabled (default)
#define SI443X_AGC_GAIN_INCREASE_ON 0b01000000 // 6 6 enabled
#define SI443X_AGC_OFF 0b00000000 // 5 5 AGC loop: disabled
#define SI443X_AGC_ON 0b00100000 // 5 5 enabled (default)
#define SI443X_LNA_GAIN_MIN 0b00000000 // 4 4 LNA gain select: 5 dB (default)
#define SI443X_LNA_GAIN_MAX 0b00010000 // 4 4 25 dB
#define SI443X_PGA_GAIN_OVERRIDE 0b00000000 // 3 0 PGA gain override, gain = SI443X_PGA_GAIN_OVERRIDE * 3 dB
// SI443X_REG_TX_POWER
#define SI443X_LNA_SWITCH_OFF 0b00000000 // 3 3 LNA switch control: disabled
#define SI443X_LNA_SWITCH_ON 0b00001000 // 3 3 enabled (default)
#define SI443X_OUTPUT_POWER 0b00000000 // 2 0 output power in 3 dB steps, 0 is chip min, 7 is chip max
// SI443X_REG_TX_DATA_RATE_1 + SI443X_REG_TX_DATA_RATE_0
#define SI443X_DATA_RATE_MSB 0x0A // 7 0 data rate: DR = 10^6 * (SI443X_DATA_RATE / 2^16) in high data rate mode or
#define SI443X_DATA_RATE_LSB 0x3D // 7 0 DR = 10^6 * (SI443X_DATA_RATE / 2^21) in low data rate mode (defaults to 40 kbps)
// SI443X_REG_MODULATION_MODE_CONTROL_1
#define SI443X_HIGH_DATA_RATE_MODE 0b00000000 // 5 5 data rate: above 30 kbps (default)
#define SI443X_LOW_DATA_RATE_MODE 0b00100000 // 5 5 below 30 kbps
#define SI443X_PACKET_HANDLER_POWER_DOWN_OFF 0b00000000 // 4 4 power off packet handler in low power mode: disabled (default)
#define SI443X_PACKET_HANDLER_POWER_DOWN_ON 0b00010000 // 4 4 enabled
#define SI443X_MANCHESTER_PREAMBLE_POL_LOW 0b00000000 // 3 3 preamble polarity in Manchester mode: low
#define SI443X_MANCHESTER_PREAMBLE_POL_HIGH 0b00001000 // 3 3 high (default)
#define SI443X_MANCHESTER_INVERTED_OFF 0b00000000 // 2 2 inverted Manchester encoding: disabled
#define SI443X_MANCHESTER_INVERTED_ON 0b00000100 // 2 2 enabled (default)
#define SI443X_MANCHESTER_OFF 0b00000000 // 1 1 Manchester encoding: disabled (default)
#define SI443X_MANCHESTER_ON 0b00000010 // 1 1 enabled
#define SI443X_WHITENING_OFF 0b00000000 // 0 0 data whitening: disabled (default)
#define SI443X_WHITENING_ON 0b00000001 // 0 0 enabled
// SI443X_REG_MODULATION_MODE_CONTROL_2
#define SI443X_TX_DATA_CLOCK_NONE 0b00000000 // 7 6 Tx data clock: disabled (default)
#define SI443X_TX_DATA_CLOCK_GPIO 0b01000000 // 7 6 GPIO pin
#define SI443X_TX_DATA_CLOCK_SDI 0b10000000 // 7 6 SDI pin
#define SI443X_TX_DATA_CLOCK_NIRQ 0b11000000 // 7 6 nIRQ pin
#define SI443X_TX_DATA_SOURCE_GPIO 0b00000000 // 5 4 Tx data source in direct mode: GPIO pin (default)
#define SI443X_TX_DATA_SOURCE_SDI 0b00010000 // 5 4 SDI pin
#define SI443X_TX_DATA_SOURCE_FIFO 0b00100000 // 5 4 FIFO
#define SI443X_TX_DATA_SOURCE_PN9 0b00110000 // 5 4 PN9 internal
#define SI443X_TX_RX_INVERTED_OFF 0b00000000 // 3 3 Tx/Rx data inverted: disabled (default)
#define SI443X_TX_RX_INVERTED_ON 0b00001000 // 3 3 enabled
#define SI443X_FREQUENCY_DEVIATION_MSB 0b00000000 // 2 2 frequency deviation MSB
#define SI443X_MODULATION_NONE 0b00000000 // 1 0 modulation type: unmodulated carrier (default)
#define SI443X_MODULATION_OOK 0b00000001 // 1 0 OOK
#define SI443X_MODULATION_FSK 0b00000010 // 1 0 FSK
#define SI443X_MODULATION_GFSK 0b00000011 // 1 0 GFSK
// SI443X_REG_FREQUENCY_DEVIATION
#define SI443X_FREQUENCY_DEVIATION_LSB 0b00100000 // 7 0 frequency deviation LSB, Fd = 625 Hz * SI443X_FREQUENCY_DEVIATION, defaults to 20 kHz
// SI443X_REG_FREQUENCY_OFFSET_1 + SI443X_REG_FREQUENCY_OFFSET_2
#define SI443X_FREQUENCY_OFFSET_MSB 0x00 // 7 0 frequency offset:
#define SI443X_FREQUENCY_OFFSET_LSB 0x00 // 1 0 Foff = 156.25 Hz * (SI443X_BAND_SELECT + 1) * SI443X_FREQUENCY_OFFSET, defaults to 156.25 Hz
// SI443X_REG_FREQUENCY_BAND_SELECT
#define SI443X_SIDE_BAND_SELECT_LOW 0b00000000 // 6 6 Rx LO tuning: below channel frequency (default)
#define SI443X_SIDE_BAND_SELECT_HIGH 0b01000000 // 6 6 above channel frequency
#define SI443X_BAND_SELECT_LOW 0b00000000 // 5 5 band select: low, 240 - 479.9 MHz
#define SI443X_BAND_SELECT_HIGH 0b00100000 // 5 5 high, 480 - 960 MHz (default)
#define SI443X_FREQUENCY_BAND_SELECT 0b00010101 // 4 0 frequency band select
// SI443X_REG_NOM_CARRIER_FREQUENCY_1 + SI443X_REG_NOM_CARRIER_FREQUENCY_0
#define SI443X_NOM_CARRIER_FREQUENCY_MSB 0b10111011 // 7 0 nominal carrier frequency:
#define SI443X_NOM_CARRIER_FREQUENCY_LSB 0b10000000 // 7 0 Fc = (SI443X_BAND_SELECT + 1)*10*(SI443X_FREQUENCY_BAND_SELECT + 24) + (SI443X_NOM_CARRIER_FREQUENCY - SI443X_FREQUENCY_OFFSET)/6400 [MHz]
// SI443X_REG_FREQUENCY_HOPPING_CHANNEL_SEL
#define SI443X_FREQUENCY_HOPPING_CHANNEL 0x00 // 7 0 frequency hopping channel number
// SI443X_REG_FREQUENCY_HOPPING_STEP_SIZE
#define SI443X_FREQUENCY_HOPPING_STEP_SIZE 0x00 // 7 0 frequency hopping step size
// SI443X_REG_TX_FIFO_CONTROL_1
#define SI443X_TX_FIFO_ALMOST_FULL_THRESHOLD 0x37 // 5 0 Tx FIFO almost full threshold
// SI443X_REG_TX_FIFO_CONTROL_2
#define SI443X_TX_FIFO_ALMOST_EMPTY_THRESHOLD 0x04 // 5 0 Tx FIFO almost full threshold
// SI443X_REG_RX_FIFO_CONTROL
#define SI443X_RX_FIFO_ALMOST_FULL_THRESHOLD 0x37 // 5 0 Rx FIFO almost full threshold
/*!
\class Si443x
\brief Base class for Si443x series. All derived classes for Si443x (e.g. Si4431 or Si4432) inherit from this base class.
This class should not be instantiated directly from Arduino sketch, only from its derived classes.
*/
class Si443x: public PhysicalLayer {
public:
// introduce PhysicalLayer overloads
using PhysicalLayer::transmit;
using PhysicalLayer::receive;
using PhysicalLayer::startTransmit;
using PhysicalLayer::readData;
// constructor
/*!
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio.
*/
Si443x(Module* mod);
// basic methods
/*!
\brief Initialization method.
\param br Bit rate of the FSK transmission in kbps (kilobits per second).
\param freqDev Frequency deviation of the FSK transmission in kHz.
\param rxBw Receiver bandwidth in kHz.
\returns \ref status_codes
*/
int16_t begin(float br, float freqDev, float rxBw);
/*!
\brief Reset method. Will reset the chip to the default state using SDN pin.
*/
void reset();
/*!
\brief Binary transmit method. Will transmit arbitrary binary data up to 64 bytes long.
For overloads to transmit Arduino String or C-string, see PhysicalLayer::transmit.
\param data Binary data that will be transmitted.
\param len Length of binary data to transmit (in bytes).
\param addr Node address to transmit the packet to.
\returns \ref status_codes
*/
int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0);
/*!
\brief Binary receive method. Will attempt to receive arbitrary binary data up to 64 bytes long.
For overloads to receive Arduino String, see PhysicalLayer::receive.
\param data Pointer to array to save the received binary data.
\param len Number of bytes that will be received. Must be known in advance for binary transmissions.
\returns \ref status_codes
*/
int16_t receive(uint8_t* data, size_t len);
/*!
\brief Sets the module to sleep to save power. %Module will not be able to transmit or receive any data while in sleep mode.
%Module will wake up automatically when methods like transmit or receive are called.
\returns \ref status_codes
*/
int16_t sleep();
/*!
\brief Sets the module to standby.
\returns \ref status_codes
*/
int16_t standby();
/*!
\brief Enables direct transmission mode. While in direct mode, the module will not be able to transmit or receive packets.
\param FRF 24-bit raw frequency value to start transmitting at. Required for quick frequency shifts in RTTY.
\returns \ref status_codes
*/
int16_t transmitDirect(uint32_t frf = 0);
/*!
\brief Enables direct reception mode. While in direct mode, the module will not be able to transmit or receive packets.
\returns \ref status_codes
*/
int16_t receiveDirect();
/*!
\brief Disables direct mode and enables packet mode, allowing the module to receive packets.
\returns \ref status_codes
*/
int16_t packetMode();
// interrupt methods
/*!
\brief Sets interrupt service routine to call when IRQ activates.
\param func ISR to call.
*/
void setIrqAction(void (*func)(void));
/*!
\brief Clears interrupt service routine to call when IRQ activates.
*/
void clearIrqAction();
/*!
\brief Interrupt-driven binary transmit method. Will start transmitting arbitrary binary data up to 64 bytes long.
\param data Binary data that will be transmitted.
\param len Length of binary data to transmit (in bytes).
\param addr Node address to transmit the packet to.
\returns \ref status_codes
*/
int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0);
/*!
\brief Interrupt-driven receive method. IRQ will be activated when full valid packet is received.
\returns \ref status_codes
*/
int16_t startReceive();
/*!
\brief Reads data that was received after calling startReceive method. This method reads len characters.
\param data Pointer to array to save the received binary data.
\param len Number of bytes that will be received. Must be known in advance for binary transmissions.
\returns \ref status_codes
*/
int16_t readData(uint8_t* data, size_t len);
// configuration methods
/*!
\brief Sets FSK bit rate. Allowed values range from 0.123 to 256.0 kbps.
\param br Bit rate to be set (in kbps).
\returns \ref status_codes
*/
int16_t setBitRate(float br);
/*!
\brief Sets FSK frequency deviation from carrier frequency. Allowed values range from 0.625 to 320.0 kHz.
\param freqDev Frequency deviation to be set (in kHz).
\returns \ref status_codes
*/
int16_t setFrequencyDeviation(float freqDev);
/*!
\brief Sets receiver bandwidth. Allowed values range from 2.6 to 620.7 kHz.
\param rxBw Receiver bandwidth to be set in kHz.
\returns \ref status_codes
*/
int16_t setRxBandwidth(float rxBw);
/*!
\brief Sets sync word. Up to 4 bytes can be set as sync word.
\param syncWord Pointer to the array of sync word bytes.
\param len Sync word length in bytes.
*/
int16_t setSyncWord(uint8_t* syncWord, size_t len);
/*!
\brief Query modem for the packet length of received payload.
\param update Update received packet length. Will return cached value when set to false.
\returns Length of last received packet in bytes.
*/
size_t getPacketLength(bool update = true);
/*!
\brief 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);
/*!
\brief Sets Gaussian filter bandwidth-time product that will be used for data shaping.
Allowed values are 0.3, 0.5 or 1.0. Set to 0 to disable data shaping. Only available in FSK mode with FSK modulation.
\param sh Gaussian shaping bandwidth-time product that will be used for data shaping
\returns \ref status_codes
*/
int16_t setDataShaping(float sh);
#ifndef RADIOLIB_GODMODE
protected:
#endif
Module* _mod;
float _br;
float _freqDev;
size_t _packetLength;
bool _packetLengthQueried;
int16_t setFrequencyRaw(float newFreq);
#ifndef RADIOLIB_GODMODE
private:
#endif
bool findChip();
void clearIRQFlags();
int16_t config();
int16_t updateClockRecovery();
int16_t directMode();
};
#endif