[CC1101] Implemented packet reception
This commit is contained in:
parent
269cafb8f3
commit
44e4a16b8b
3 changed files with 212 additions and 33 deletions
70
examples/CC1101_Receive/CC1101_Receive.ino
Normal file
70
examples/CC1101_Receive/CC1101_Receive.ino
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
RadioLib CC1101 Receive Example
|
||||
|
||||
This example receives packets using CC1101 FSK radio module.
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// CC1101 is in slot A on the shield
|
||||
CC1101 cc = RadioShield.ModuleA;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
||||
// initialize CC1101 with default settings
|
||||
Serial.print(F("[CC1101] Initializing ... "));
|
||||
// carrier frequency: 868.0 MHz
|
||||
// bit rate: 4.8 kbps
|
||||
// Rx bandwidth: 325.0 kHz
|
||||
// frequency deviation: 48.0 kHz
|
||||
// sync word: 0xD391
|
||||
int state = cc.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("[CC1101] Waiting for incoming transmission ... "));
|
||||
|
||||
// you can receive data as an Arduino String
|
||||
String str;
|
||||
int state = cc.receive(str);
|
||||
|
||||
// you can also receive data as byte array
|
||||
/*
|
||||
byte byteArr[8];
|
||||
int state = cc.receive(byteArr, 8);
|
||||
*/
|
||||
|
||||
if (state == ERR_NONE) {
|
||||
// packet was successfully received
|
||||
Serial.println(F("success!"));
|
||||
|
||||
// print the data of the packet
|
||||
Serial.print(F("[CC1101] Data:\t\t"));
|
||||
Serial.println(str);
|
||||
|
||||
// print RSSI (Received Signal Strength Indicator)
|
||||
// of the last received packet
|
||||
Serial.print("[CC1101] RSSI:\t\t");
|
||||
Serial.print(cc.getRSSI());
|
||||
Serial.println(" dBm");
|
||||
|
||||
// print LQI (Link Quality Indicator)
|
||||
// of the last received packet, lower is better
|
||||
Serial.print("[CC1101] LQI:\t\t");
|
||||
Serial.println(cc.getLQI());
|
||||
|
||||
} else if (state == ERR_CRC_MISMATCH) {
|
||||
// packet was received, but is malformed
|
||||
Serial.println(F("CRC error!"));
|
||||
|
||||
}
|
||||
}
|
|
@ -69,6 +69,10 @@ int16_t CC1101::begin(float freq, float br, float rxBw, float freqDev) {
|
|||
return(state);
|
||||
}
|
||||
|
||||
// flush FIFOs
|
||||
SPIsendCommand(CC1101_CMD_FLUSH_RX);
|
||||
SPIsendCommand(CC1101_CMD_FLUSH_TX);
|
||||
|
||||
return(state);
|
||||
}
|
||||
|
||||
|
@ -82,7 +86,7 @@ int16_t CC1101::transmit(const char* str, uint8_t addr) {
|
|||
|
||||
int16_t CC1101::transmit(uint8_t* data, size_t len, uint8_t addr) {
|
||||
// check packet length
|
||||
if(len > 255) {
|
||||
if(len > 63) {
|
||||
return(ERR_PACKET_TOO_LONG);
|
||||
}
|
||||
|
||||
|
@ -90,13 +94,13 @@ int16_t CC1101::transmit(uint8_t* data, size_t len, uint8_t addr) {
|
|||
standby();
|
||||
|
||||
// set GDO0 mapping
|
||||
_mod->SPIsetRegValue(CC1101_REG_IOCFG0, CC1101_GDOX_SYNC_WORD_SENT_OR_RECEIVED);
|
||||
SPIsetRegValue(CC1101_REG_IOCFG0, CC1101_GDOX_SYNC_WORD_SENT_OR_RECEIVED);
|
||||
|
||||
// write packet length
|
||||
_mod->SPIwriteRegister(CC1101_REG_FIFO, len);
|
||||
SPIwriteRegister(CC1101_REG_FIFO, len);
|
||||
|
||||
// write packet to FIFO
|
||||
_mod->SPIwriteRegisterBurst(CC1101_REG_FIFO | CC1101_CMD_BURST, data, len);
|
||||
SPIwriteRegisterBurst(CC1101_REG_FIFO, data, len);
|
||||
|
||||
// set mode to transmit
|
||||
SPIsendCommand(CC1101_CMD_TX);
|
||||
|
@ -131,10 +135,58 @@ int16_t CC1101::receive(String& str, size_t len) {
|
|||
}
|
||||
|
||||
int16_t CC1101::receive(uint8_t* data, size_t len) {
|
||||
// TODO
|
||||
// set mode to standby
|
||||
standby();
|
||||
|
||||
// set GDO0 and GDO2 mapping
|
||||
// flush Rx FIFO
|
||||
SPIsendCommand(CC1101_CMD_FLUSH_RX);
|
||||
|
||||
// set GDO0 mapping
|
||||
SPIsetRegValue(CC1101_REG_IOCFG0, CC1101_GDOX_SYNC_WORD_SENT_OR_RECEIVED);
|
||||
|
||||
// set mode to receive
|
||||
SPIsendCommand(CC1101_CMD_RX);
|
||||
|
||||
// wait for sync word
|
||||
while(!digitalRead(_mod->getInt0()));
|
||||
|
||||
// wait for packet end
|
||||
while(digitalRead(_mod->getInt0()));
|
||||
|
||||
// get packet length
|
||||
size_t length = SPIreadRegister(CC1101_REG_RXBYTES) - 2;
|
||||
|
||||
// read packet data
|
||||
if(len == 0) {
|
||||
// argument len equal to zero indicates String call, which means dynamically allocated data array
|
||||
// dispose of the original and create a new one
|
||||
delete[] data;
|
||||
data = new uint8_t[length + 1];
|
||||
}
|
||||
SPIreadRegisterBurst(CC1101_REG_FIFO, length, data);
|
||||
|
||||
// read RSSI byte
|
||||
_rawRSSI = SPIgetRegValue(CC1101_REG_FIFO);
|
||||
|
||||
// read LQI and CRC byte
|
||||
uint8_t val = SPIgetRegValue(CC1101_REG_FIFO);
|
||||
_rawLQI = val & 0x7F;
|
||||
|
||||
// add terminating null
|
||||
if(len == 0) {
|
||||
data[length] = 0;
|
||||
}
|
||||
|
||||
// flush Rx FIFO
|
||||
SPIsendCommand(CC1101_CMD_FLUSH_RX);
|
||||
|
||||
// set mode to standby
|
||||
standby();
|
||||
|
||||
// check CRC
|
||||
if((val & 0b10000000) == 0b00000000) {
|
||||
return(ERR_CRC_MISMATCH);
|
||||
}
|
||||
|
||||
return(ERR_NONE);
|
||||
}
|
||||
|
@ -147,9 +199,9 @@ int16_t CC1101::standby() {
|
|||
int16_t CC1101::transmitDirect(uint32_t FRF) {
|
||||
// user requested to start transmitting immediately (required for RTTY)
|
||||
if(FRF != 0) {
|
||||
_mod->SPIwriteRegister(CC1101_REG_FREQ2, (FRF & 0xFF0000) >> 16);
|
||||
_mod->SPIwriteRegister(CC1101_REG_FREQ1, (FRF & 0x00FF00) >> 8);
|
||||
_mod->SPIwriteRegister(CC1101_REG_FREQ0, FRF & 0x0000FF);
|
||||
SPIwriteRegister(CC1101_REG_FREQ2, (FRF & 0xFF0000) >> 16);
|
||||
SPIwriteRegister(CC1101_REG_FREQ1, (FRF & 0x00FF00) >> 8);
|
||||
SPIwriteRegister(CC1101_REG_FREQ0, FRF & 0x0000FF);
|
||||
|
||||
SPIsendCommand(CC1101_CMD_TX);
|
||||
}
|
||||
|
@ -191,9 +243,9 @@ int16_t CC1101::setFrequency(float freq) {
|
|||
//set carrier frequency
|
||||
uint32_t base = 1;
|
||||
uint32_t FRF = (freq * (base << 16)) / 26.0;
|
||||
int16_t state = _mod->SPIsetRegValue(CC1101_REG_FREQ2, (FRF & 0xFF0000) >> 16, 7, 0);
|
||||
state |= _mod->SPIsetRegValue(CC1101_REG_FREQ1, (FRF & 0x00FF00) >> 8, 7, 0);
|
||||
state |= _mod->SPIsetRegValue(CC1101_REG_FREQ0, FRF & 0x0000FF, 7, 0);
|
||||
int16_t state = SPIsetRegValue(CC1101_REG_FREQ2, (FRF & 0xFF0000) >> 16, 7, 0);
|
||||
state |= SPIsetRegValue(CC1101_REG_FREQ1, (FRF & 0x00FF00) >> 8, 7, 0);
|
||||
state |= SPIsetRegValue(CC1101_REG_FREQ0, FRF & 0x0000FF, 7, 0);
|
||||
|
||||
return(state);
|
||||
}
|
||||
|
@ -213,8 +265,8 @@ int16_t CC1101::setBitRate(float br) {
|
|||
getExpMant(br * 1000.0, 256, 28, 14, e, m);
|
||||
|
||||
// set bit rate value
|
||||
int16_t state = _mod->SPIsetRegValue(CC1101_REG_MDMCFG4, e, 3, 0);
|
||||
state |= _mod->SPIsetRegValue(CC1101_REG_MDMCFG3, m);
|
||||
int16_t state = SPIsetRegValue(CC1101_REG_MDMCFG4, e, 3, 0);
|
||||
state |= SPIsetRegValue(CC1101_REG_MDMCFG3, m);
|
||||
return(state);
|
||||
}
|
||||
|
||||
|
@ -233,7 +285,7 @@ int16_t CC1101::setRxBandwidth(float rxBw) {
|
|||
float point = (CC1101_CRYSTAL_FREQ * 1000000.0)/(8 * (m + 4) * ((uint32_t)1 << e));
|
||||
if(abs((rxBw * 1000.0) - point) <= 0.001) {
|
||||
// set Rx channel filter bandwidth
|
||||
return(_mod->SPIsetRegValue(CC1101_REG_MDMCFG4, (e << 6) | (m << 4), 7, 4));
|
||||
return(SPIsetRegValue(CC1101_REG_MDMCFG4, (e << 6) | (m << 4), 7, 4));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -244,8 +296,8 @@ int16_t CC1101::setRxBandwidth(float rxBw) {
|
|||
int16_t CC1101::setFrequencyDeviation(float freqDev) {
|
||||
// set frequency deviation to lowest available setting (required for RTTY)
|
||||
if(freqDev == 0.0) {
|
||||
int16_t state = _mod->SPIsetRegValue(CC1101_REG_DEVIATN, 0, 6, 4);
|
||||
state |= _mod->SPIsetRegValue(CC1101_REG_DEVIATN, 0, 2, 0);
|
||||
int16_t state = SPIsetRegValue(CC1101_REG_DEVIATN, 0, 6, 4);
|
||||
state |= SPIsetRegValue(CC1101_REG_DEVIATN, 0, 2, 0);
|
||||
return(state);
|
||||
}
|
||||
|
||||
|
@ -263,27 +315,50 @@ int16_t CC1101::setFrequencyDeviation(float freqDev) {
|
|||
getExpMant(freqDev * 1000.0, 8, 17, 7, e, m);
|
||||
|
||||
// set frequency deviation value
|
||||
int16_t state = _mod->SPIsetRegValue(CC1101_REG_DEVIATN, (e << 4), 6, 4);
|
||||
state |= _mod->SPIsetRegValue(CC1101_REG_DEVIATN, m, 2, 0);
|
||||
int16_t state = SPIsetRegValue(CC1101_REG_DEVIATN, (e << 4), 6, 4);
|
||||
state |= SPIsetRegValue(CC1101_REG_DEVIATN, m, 2, 0);
|
||||
return(state);
|
||||
}
|
||||
|
||||
int16_t CC1101::setSyncWord(uint8_t syncH, uint8_t syncL) {
|
||||
// set sync word
|
||||
int16_t state = _mod->SPIsetRegValue(CC1101_REG_SYNC1, syncH);
|
||||
state |= _mod->SPIsetRegValue(CC1101_REG_SYNC0, syncL);
|
||||
int16_t state = SPIsetRegValue(CC1101_REG_SYNC1, syncH);
|
||||
state |= SPIsetRegValue(CC1101_REG_SYNC0, syncL);
|
||||
return(state);
|
||||
}
|
||||
|
||||
float CC1101::getRSSI() {
|
||||
float rssi;
|
||||
if(_rawRSSI >= 128) {
|
||||
rssi = (((float)_rawRSSI - 256.0)/2.0) - 74.0;
|
||||
} else {
|
||||
rssi = (((float)_rawRSSI)/2.0) - 74.0;
|
||||
}
|
||||
return(rssi);
|
||||
}
|
||||
|
||||
uint8_t CC1101::getLQI() {
|
||||
return(_rawLQI);
|
||||
}
|
||||
|
||||
int16_t CC1101::config() {
|
||||
// enable automatic frequency synthesizer calibration
|
||||
int16_t state = _mod->SPIsetRegValue(CC1101_REG_MCSM0, CC1101_FS_AUTOCAL_IDLE_TO_RXTX, 5, 4);
|
||||
int16_t state = SPIsetRegValue(CC1101_REG_MCSM0, CC1101_FS_AUTOCAL_IDLE_TO_RXTX, 5, 4);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
// set output power
|
||||
_mod->SPIwriteRegister(CC1101_REG_PATABLE, 0x60);
|
||||
// set packet mode
|
||||
// TODO: address filtering
|
||||
state = SPIsetRegValue(CC1101_REG_PKTCTRL1, CC1101_CRC_AUTOFLUSH_OFF | CC1101_APPEND_STATUS_ON | CC1101_ADR_CHK_NONE, 3, 0);
|
||||
state |= SPIsetRegValue(CC1101_REG_PKTCTRL0, CC1101_WHITE_DATA_OFF | CC1101_PKT_FORMAT_NORMAL, 6, 4);
|
||||
state |= SPIsetRegValue(CC1101_REG_PKTCTRL0, CC1101_CRC_ON | CC1101_LENGTH_CONFIG_VARIABLE, 2, 0);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
// TODO: configurable power output
|
||||
SPIwriteRegister(CC1101_REG_PATABLE, 0x60);
|
||||
|
||||
return(state);
|
||||
}
|
||||
|
@ -293,11 +368,11 @@ int16_t CC1101::directMode() {
|
|||
SPIsendCommand(CC1101_CMD_IDLE);
|
||||
|
||||
// set GDO0 and GDO2 mapping
|
||||
int16_t state = _mod->SPIsetRegValue(CC1101_REG_IOCFG0, CC1101_GDOX_SERIAL_CLOCK , 5, 0);
|
||||
state |= _mod->SPIsetRegValue(CC1101_REG_IOCFG2, CC1101_GDOX_SERIAL_DATA_SYNC , 5, 0);
|
||||
int16_t state = SPIsetRegValue(CC1101_REG_IOCFG0, CC1101_GDOX_SERIAL_CLOCK , 5, 0);
|
||||
state |= SPIsetRegValue(CC1101_REG_IOCFG2, CC1101_GDOX_SERIAL_DATA_SYNC , 5, 0);
|
||||
|
||||
// set continuous mode
|
||||
state |= _mod->SPIsetRegValue(CC1101_REG_PKTCTRL0, CC1101_PKT_FORMAT_SYNCHRONOUS, 5, 4);
|
||||
state |= SPIsetRegValue(CC1101_REG_PKTCTRL0, CC1101_PKT_FORMAT_SYNCHRONOUS, 5, 4);
|
||||
return(state);
|
||||
}
|
||||
|
||||
|
@ -327,9 +402,7 @@ void CC1101::getExpMant(float target, uint16_t mantOffset, uint8_t divExp, uint8
|
|||
}
|
||||
}
|
||||
|
||||
void CC1101::SPIwriteRegisterBurst(uint8_t reg, uint8_t* data, size_t len) {
|
||||
_mod->SPIwriteRegisterBurst(reg | CC1101_CMD_BURST, data, len);
|
||||
}
|
||||
|
||||
|
||||
int16_t CC1101::SPIgetRegValue(uint8_t reg, uint8_t msb, uint8_t lsb) {
|
||||
// status registers require special command
|
||||
|
@ -340,6 +413,19 @@ int16_t CC1101::SPIgetRegValue(uint8_t reg, uint8_t msb, uint8_t lsb) {
|
|||
return(_mod->SPIgetRegValue(reg, msb, lsb));
|
||||
}
|
||||
|
||||
int16_t CC1101::SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb, uint8_t lsb, uint8_t checkInterval) {
|
||||
// status registers require special command
|
||||
if(reg > CC1101_REG_TEST0) {
|
||||
reg |= CC1101_CMD_ACCESS_STATUS_REG;
|
||||
}
|
||||
|
||||
return(_mod->SPIsetRegValue(reg, value, msb, lsb, checkInterval));
|
||||
}
|
||||
|
||||
void CC1101::SPIreadRegisterBurst(uint8_t reg, uint8_t numBytes, uint8_t* inBytes) {
|
||||
_mod->SPIreadRegisterBurst(reg | CC1101_CMD_BURST, numBytes, inBytes);
|
||||
}
|
||||
|
||||
uint8_t CC1101::SPIreadRegister(uint8_t reg) {
|
||||
// status registers require special command
|
||||
if(reg > CC1101_REG_TEST0) {
|
||||
|
@ -349,6 +435,19 @@ uint8_t CC1101::SPIreadRegister(uint8_t reg) {
|
|||
return(_mod->SPIreadRegister(reg));
|
||||
}
|
||||
|
||||
void CC1101::SPIwriteRegister(uint8_t reg, uint8_t data) {
|
||||
// status registers require special command
|
||||
if(reg > CC1101_REG_TEST0) {
|
||||
reg |= CC1101_CMD_ACCESS_STATUS_REG;
|
||||
}
|
||||
|
||||
return(_mod->SPIwriteRegister(reg, data));
|
||||
}
|
||||
|
||||
void CC1101::SPIwriteRegisterBurst(uint8_t reg, uint8_t* data, size_t len) {
|
||||
_mod->SPIwriteRegisterBurst(reg | CC1101_CMD_BURST, data, len);
|
||||
}
|
||||
|
||||
void CC1101::SPIsendCommand(uint8_t cmd) {
|
||||
digitalWrite(_mod->getCs(), LOW);
|
||||
SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0));
|
||||
|
|
|
@ -271,7 +271,8 @@
|
|||
#define CC1101_RX_TIMEOUT_RSSI_ON 0b00010000 // 4 4 enabled
|
||||
#define CC1101_RX_TIMEOUT_QUAL_OFF 0b00000000 // 3 3 check for sync word on Rx timeout
|
||||
#define CC1101_RX_TIMEOUT_QUAL_ON 0b00001000 // 3 3 check for PQI set on Rx timeout
|
||||
#define CC1101_RX_TIMEOUT 0b00000111 // 2 0 Rx timeout coefficient value
|
||||
#define CC1101_RX_TIMEOUT_OFF 0b00000111 // 2 0 Rx timeout: disabled (default)
|
||||
#define CC1101_RX_TIMEOUT_MAX 0b00000000 // 2 0 max value (actual value depends on WOR_RES, EVENT0 and f(XOSC))
|
||||
|
||||
// CC1101_REG_MCSM1
|
||||
#define CC1101_CCA_MODE_ALWAYS 0b00000000 // 5 4 clear channel indication: always
|
||||
|
@ -485,6 +486,7 @@
|
|||
|
||||
// CC1101_REG_PKTSTATUS
|
||||
#define CC1101_CRC_OK 0b10000000 // 7 7 CRC check passed
|
||||
#define CC1101_CRC_ERROR 0b00000000 // 7 7 CRC check failed
|
||||
#define CC1101_CS 0b01000000 // 6 6 carrier sense
|
||||
#define CC1101_PQT_REACHED 0b00100000 // 5 5 preamble quality reached
|
||||
#define CC1101_CCA 0b00010000 // 4 4 channel clear
|
||||
|
@ -498,7 +500,7 @@ class CC1101: public PhysicalLayer {
|
|||
CC1101(Module* module);
|
||||
|
||||
// basic methods
|
||||
int16_t begin(float freq = 868.0, float br = 115.2, float rxBw = 325.0, float freqDev = 48.0);
|
||||
int16_t begin(float freq = 868.0, float br = 4.8, float rxBw = 325.0, float freqDev = 48.0);
|
||||
int16_t transmit(String& str, uint8_t addr = 0);
|
||||
int16_t transmit(const char* str, uint8_t addr = 0);
|
||||
int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0);
|
||||
|
@ -514,18 +516,26 @@ class CC1101: public PhysicalLayer {
|
|||
int16_t setRxBandwidth(float rxBw);
|
||||
int16_t setFrequencyDeviation(float freqDev);
|
||||
int16_t setSyncWord(uint8_t syncH, uint8_t syncL);
|
||||
float getRSSI();
|
||||
uint8_t getLQI();
|
||||
|
||||
private:
|
||||
Module* _mod;
|
||||
|
||||
uint8_t _rawRSSI;
|
||||
uint8_t _rawLQI;
|
||||
|
||||
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);
|
||||
|
||||
// SPI read overrides to set bit for burst write and status registers access
|
||||
void SPIwriteRegisterBurst(uint8_t reg, uint8_t* data, size_t len);
|
||||
int16_t SPIgetRegValue(uint8_t reg, uint8_t msb = 7, uint8_t lsb = 0);
|
||||
int16_t SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb = 7, uint8_t lsb = 0, uint8_t checkInterval = 2);
|
||||
void SPIreadRegisterBurst(uint8_t reg, uint8_t numBytes, uint8_t* inBytes);
|
||||
uint8_t SPIreadRegister(uint8_t reg);
|
||||
void SPIwriteRegisterBurst(uint8_t reg, uint8_t* data, size_t len);
|
||||
void SPIwriteRegister(uint8_t reg, uint8_t data);
|
||||
|
||||
void SPIsendCommand(uint8_t cmd);
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue