mirror of
https://github.com/letscontrolit/ESPEasy.git
synced 2026-07-27 19:57:38 +00:00
296 lines
7.2 KiB
C++
296 lines
7.2 KiB
C++
/*
|
|
* Author: Klusjesman, modified bij supersjimmie for Arduino/ESP8266
|
|
*/
|
|
|
|
#include "CC1101.h"
|
|
|
|
// default constructor
|
|
CC1101::CC1101(int8_t CSpin, int8_t MISOpin, SPIClass& spi) : _CSpin(CSpin), _MISOpin(MISOpin), _spi(spi)
|
|
{
|
|
// SPI.begin(); // Done already by ESPEasy
|
|
pinMode(_CSpin, OUTPUT);
|
|
} // CC1101
|
|
|
|
// default destructor
|
|
CC1101::~CC1101()
|
|
{} // ~CC1101
|
|
|
|
/***********************/
|
|
|
|
// SPI helper functions select() and deselect()
|
|
inline void CC1101::select(void) {
|
|
digitalWrite(_CSpin, LOW);
|
|
}
|
|
|
|
inline void CC1101::deselect(void) {
|
|
digitalWrite(_CSpin, HIGH);
|
|
}
|
|
|
|
void CC1101::spi_waitMiso()
|
|
{
|
|
uint32_t maxWait = millis() + ITHO_MAX_WAIT; // Wait for max. x seconds
|
|
|
|
while (digitalRead(_MISOpin) == HIGH && millis() < maxWait) {
|
|
yield();
|
|
}
|
|
}
|
|
|
|
void CC1101::init()
|
|
{
|
|
reset();
|
|
}
|
|
|
|
void CC1101::reset()
|
|
{
|
|
deselect();
|
|
delayMicroseconds(5);
|
|
select();
|
|
delayMicroseconds(10);
|
|
deselect();
|
|
delayMicroseconds(45);
|
|
select();
|
|
|
|
spi_waitMiso();
|
|
_spi.transfer(CC1101_SRES);
|
|
delay(10);
|
|
spi_waitMiso();
|
|
deselect();
|
|
}
|
|
|
|
uint8_t CC1101::writeCommand(uint8_t command)
|
|
{
|
|
uint8_t result;
|
|
|
|
select();
|
|
spi_waitMiso();
|
|
result = _spi.transfer(command);
|
|
deselect();
|
|
|
|
return result;
|
|
}
|
|
|
|
void CC1101::writeRegister(uint8_t address, uint8_t data)
|
|
{
|
|
select();
|
|
spi_waitMiso();
|
|
_spi.transfer(address);
|
|
_spi.transfer(data);
|
|
deselect();
|
|
}
|
|
|
|
uint8_t CC1101::readRegister(uint8_t address)
|
|
{
|
|
uint8_t val;
|
|
|
|
select();
|
|
spi_waitMiso();
|
|
_spi.transfer(address);
|
|
val = _spi.transfer(0);
|
|
deselect();
|
|
|
|
return val;
|
|
}
|
|
|
|
uint8_t CC1101::readRegisterMedian3(uint8_t address)
|
|
{
|
|
uint8_t val, val1, val2, val3;
|
|
|
|
select();
|
|
spi_waitMiso();
|
|
_spi.transfer(address);
|
|
val1 = _spi.transfer(0);
|
|
_spi.transfer(address);
|
|
val2 = _spi.transfer(0);
|
|
_spi.transfer(address);
|
|
val3 = _spi.transfer(0);
|
|
deselect();
|
|
|
|
// reverse sort (largest in val1) because this is te expected order for TX_BUFFER
|
|
if (val3 > val2) { val = val3; val3 = val2; val2 = val; } // Swap(val3,val2)
|
|
|
|
if (val2 > val1) { val = val2; val2 = val1, val1 = val; } // Swap(val2,val1)
|
|
|
|
if (val3 > val2) { val = val3; val3 = val2, val2 = val; } // Swap(val3,val2)
|
|
|
|
return val2;
|
|
}
|
|
|
|
/* Known SPI/26MHz synchronization bug (see CC1101 errata)
|
|
This issue affects the following registers: SPI status byte (fields STATE and FIFO_BYTES_AVAILABLE),
|
|
FREQEST or RSSI while the receiver is active, MARCSTATE at any time other than an IDLE radio state,
|
|
RXBYTES when receiving or TXBYTES when transmitting, and WORTIME1/WORTIME0 at any time.*/
|
|
|
|
// uint8_t CC1101::readRegisterWithSyncProblem(uint8_t address, uint8_t registerType)
|
|
uint8_t /* ICACHE_RAM_ATTR */ CC1101::readRegisterWithSyncProblem(uint8_t address, uint8_t registerType)
|
|
{
|
|
uint8_t value1, value2;
|
|
|
|
value1 = readRegister(address | registerType);
|
|
|
|
// if two consecutive reads gives us the same result then we know we are ok
|
|
do
|
|
{
|
|
value2 = value1;
|
|
value1 = readRegister(address | registerType);
|
|
}
|
|
while (value1 != value2);
|
|
|
|
return value1;
|
|
}
|
|
|
|
// registerType = CC1101_CONFIG_REGISTER or CC1101_STATUS_REGISTER
|
|
uint8_t CC1101::readRegister(uint8_t address, uint8_t registerType)
|
|
{
|
|
switch (address)
|
|
{
|
|
case CC1101_FREQEST:
|
|
case CC1101_MARCSTATE:
|
|
case CC1101_RXBYTES:
|
|
case CC1101_TXBYTES:
|
|
case CC1101_WORTIME1:
|
|
case CC1101_WORTIME0:
|
|
return readRegisterWithSyncProblem(address, registerType);
|
|
|
|
default:
|
|
return readRegister(address | registerType);
|
|
}
|
|
}
|
|
|
|
void CC1101::writeBurstRegister(uint8_t address, uint8_t *data, uint8_t length)
|
|
{
|
|
uint8_t i;
|
|
|
|
select();
|
|
spi_waitMiso();
|
|
_spi.transfer(address | CC1101_WRITE_BURST);
|
|
|
|
for (i = 0; i < length; i++) {
|
|
_spi.transfer(pgm_read_byte(&(data[i])));
|
|
}
|
|
deselect();
|
|
}
|
|
|
|
void CC1101::readBurstRegister(uint8_t *buffer, uint8_t address, uint8_t length)
|
|
{
|
|
uint8_t i;
|
|
|
|
select();
|
|
spi_waitMiso();
|
|
_spi.transfer(address | CC1101_READ_BURST);
|
|
|
|
for (i = 0; i < length; i++) {
|
|
buffer[i] = _spi.transfer(0x00);
|
|
}
|
|
|
|
deselect();
|
|
}
|
|
|
|
// wait for fixed length in rx fifo
|
|
uint8_t CC1101::receiveData(CC1101Packet *packet, uint8_t length)
|
|
{
|
|
uint8_t rxBytes = readRegisterWithSyncProblem(CC1101_RXBYTES, CC1101_STATUS_REGISTER);
|
|
|
|
rxBytes = rxBytes & CC1101_BITS_RX_BYTES_IN_FIFO;
|
|
|
|
// check for rx fifo overflow
|
|
if ((readRegisterWithSyncProblem(CC1101_MARCSTATE, CC1101_STATUS_REGISTER) & CC1101_BITS_MARCSTATE) == CC1101_MARCSTATE_RXFIFO_OVERFLOW)
|
|
{
|
|
writeCommand(CC1101_SIDLE); // idle
|
|
writeCommand(CC1101_SFRX); // flush RX buffer
|
|
writeCommand(CC1101_SRX); // switch to RX state
|
|
}
|
|
else if (rxBytes == length)
|
|
{
|
|
readBurstRegister(packet->data, CC1101_RXFIFO, rxBytes);
|
|
|
|
// continue RX
|
|
writeCommand(CC1101_SIDLE); // idle
|
|
writeCommand(CC1101_SFRX); // flush RX buffer
|
|
writeCommand(CC1101_SRX); // switch to RX state
|
|
|
|
packet->length = rxBytes;
|
|
}
|
|
else
|
|
{
|
|
// empty fifo
|
|
packet->length = 0;
|
|
writeCommand(CC1101_SIDLE); // idle
|
|
writeCommand(CC1101_SFRX); // flush RX buffer
|
|
writeCommand(CC1101_SRX); // switch to RX state
|
|
}
|
|
|
|
return packet->length;
|
|
}
|
|
|
|
// This function is able to send packets bigger then the FIFO size.
|
|
void CC1101::sendData(CC1101Packet *packet)
|
|
{
|
|
uint8_t index = 0;
|
|
uint8_t txStatus, MarcState;
|
|
uint8_t length;
|
|
|
|
writeCommand(CC1101_SIDLE); // idle
|
|
|
|
txStatus = readRegisterWithSyncProblem(CC1101_TXBYTES, CC1101_STATUS_REGISTER);
|
|
|
|
// clear TX fifo if needed
|
|
if (txStatus & CC1101_BITS_TX_FIFO_UNDERFLOW)
|
|
{
|
|
writeCommand(CC1101_SIDLE); // idle
|
|
writeCommand(CC1101_SFTX); // flush TX buffer
|
|
}
|
|
|
|
writeCommand(CC1101_SIDLE); // idle
|
|
|
|
// determine how many bytes to send
|
|
length = (packet->length <= CC1101_DATA_LEN ? packet->length : CC1101_DATA_LEN);
|
|
|
|
writeBurstRegister(CC1101_TXFIFO, packet->data, length);
|
|
|
|
writeCommand(CC1101_SIDLE);
|
|
|
|
// start sending packet
|
|
writeCommand(CC1101_STX);
|
|
|
|
// continue sending when packet is bigger than 64 bytes
|
|
if (packet->length > CC1101_DATA_LEN)
|
|
{
|
|
index += length;
|
|
|
|
// loop until all bytes are transmitted
|
|
while (index < packet->length)
|
|
{
|
|
// check if there is free space in the fifo
|
|
uint32_t maxWait = millis() + ITHO_MAX_WAIT; // Wait for max. x seconds
|
|
|
|
while ((txStatus = (readRegisterMedian3(CC1101_TXBYTES | CC1101_STATUS_REGISTER) & CC1101_BITS_RX_BYTES_IN_FIFO)) >
|
|
(CC1101_DATA_LEN - 2) &&
|
|
millis() < maxWait) {
|
|
}
|
|
|
|
// calculate how many bytes we can send
|
|
length = (CC1101_DATA_LEN - txStatus);
|
|
length = ((packet->length - index) < length ? (packet->length - index) : length);
|
|
|
|
// send some more bytes
|
|
for (int i = 0; i < length; i++) {
|
|
writeRegister(CC1101_TXFIFO, packet->data[index + i]);
|
|
}
|
|
|
|
index += length;
|
|
}
|
|
}
|
|
|
|
// wait until transmission is finished (TXOFF_MODE is expected to be set to 0/IDLE or TXFIFO_UNDERFLOW)
|
|
uint32_t maxWait = millis() + ITHO_MAX_WAIT; // Wait for max. x seconds
|
|
|
|
do
|
|
{
|
|
MarcState = (readRegisterWithSyncProblem(CC1101_MARCSTATE, CC1101_STATUS_REGISTER) & CC1101_BITS_MARCSTATE);
|
|
|
|
// if (MarcState == CC1101_MARCSTATE_TXFIFO_UNDERFLOW) Serial.print(F("TXFIFO_UNDERFLOW occured in sendData() \n"));
|
|
}
|
|
while ((MarcState != CC1101_MARCSTATE_IDLE) && (MarcState != CC1101_MARCSTATE_TXFIFO_UNDERFLOW) &&
|
|
millis() < maxWait);
|
|
}
|