Tasmota/lib/cc1101/cc1101.cpp

549 lines
14 KiB
C++
Raw Normal View History

2020-02-20 19:50:46 +00:00
#include <SPI.h>
/**
* Copyright (c) 2011 panStamp <contact@panstamp.com>
*
* This file is part of the panStamp project.
*
* panStamp is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* any later version.
*
* panStamp is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with panStamp; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*
* Author: Daniel Berenguer
* Creation date: 03/03/2011
*/
extern "C" {
#include "cc1101.h"
}
#define PORT_GDO0 5
#define byte uint8_t
/**
* Macros
*/
// Select (SPI) CC1101
#define cc1101_Select() spi.begin()
// Deselect (SPI) CC1101
#define cc1101_Deselect() spi.end()
// Wait until SPI MISO line goes low
#define wait_Miso() delay(10)
//while(digitalRead(PORT_SPI_MISO))
// Get GDO0 pin state
#define getGDO0state() digitalRead(PORT_GDO0)
// Wait until GDO0 line goes high
#define wait_GDO0_high() while(!getGDO0state()) {delay(1);}
// Wait until GDO0 line goes low
#define wait_GDO0_low() while(getGDO0state()) {delay(1);}
/**
* PATABLE
*/
const byte paTable[8] = {0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
/**
* CC1101
*
* Class constructor
*/
CC1101::CC1101(void)
{
carrierFreq = CFREQ_868;
channel = CC1101_DEFVAL_CHANNR;
syncWord[0] = CC1101_DEFVAL_SYNC1;
syncWord[1] = CC1101_DEFVAL_SYNC0;
devAddress = CC1101_DEFVAL_ADDR;
paTableByte = PA_LowPower; // Priority = Low power
}
/**
* wakeUp
*
* Wake up CC1101 from Power Down state
*/
void CC1101::wakeUp(void)
{
cc1101_Select(); // Select CC1101
wait_Miso(); // Wait until MISO goes low
cc1101_Deselect(); // Deselect CC1101
}
/**
* writeReg
*
* Write single register into the CC1101 IC via SPI
*
* 'regAddr' Register address
* 'value' Value to be writen
*/
void CC1101::writeReg(byte regAddr, byte value)
{
cc1101_Select(); // Select CC1101
wait_Miso(); // Wait until MISO goes low
spi.transfer(regAddr); // Send register address
spi.transfer(value); // Send value
cc1101_Deselect(); // Deselect CC1101
}
/**
* writeBurstReg
*
* Write multiple registers into the CC1101 IC via SPI
*
* 'regAddr' Register address
* 'buffer' Data to be writen
* 'len' Data length
*/
void CC1101::writeBurstReg(byte regAddr, byte* buffer, byte len)
{
byte addr, i;
addr = regAddr | WRITE_BURST; // Enable burst transfer
cc1101_Select(); // Select CC1101
wait_Miso(); // Wait until MISO goes low
spi.transfer(addr); // Send register address
for(i=0 ; i<len ; i++)
spi.transfer(buffer[i]); // Send value
cc1101_Deselect(); // Deselect CC1101
}
/**
* cmdStrobe
*
* Send command strobe to the CC1101 IC via SPI
*
* 'cmd' Command strobe
*/
void CC1101::cmdStrobe(byte cmd)
{
cc1101_Select(); // Select CC1101
wait_Miso(); // Wait until MISO goes low
spi.transfer(cmd); // Send strobe command
cc1101_Deselect(); // Deselect CC1101
}
/**
* readReg
*
* Read CC1101 register via SPI
*
* 'regAddr' Register address
* 'regType' Type of register: CC1101_CONFIG_REGISTER or CC1101_STATUS_REGISTER
*
* Return:
* Data byte returned by the CC1101 IC
*/
byte CC1101::readReg(byte regAddr, byte regType)
{
byte addr, val;
addr = regAddr | regType;
cc1101_Select(); // Select CC1101
wait_Miso(); // Wait until MISO goes low
spi.transfer(addr); // Send register address
val = spi.transfer(0x00); // Read result
cc1101_Deselect(); // Deselect CC1101
return val;
}
/**
* readBurstReg
*
* Read burst data from CC1101 via SPI
*
* 'buffer' Buffer where to copy the result to
* 'regAddr' Register address
* 'len' Data length
*/
void CC1101::readBurstReg(byte * buffer, byte regAddr, byte len)
{
byte addr, i;
addr = regAddr | READ_BURST;
cc1101_Select(); // Select CC1101
wait_Miso(); // Wait until MISO goes low
spi.transfer(addr); // Send register address
for(i=0 ; i<len ; i++)
buffer[i] = spi.transfer(0x00); // Read result byte by byte
cc1101_Deselect(); // Deselect CC1101
}
/**
* reset
*
* Reset CC1101
*/
void CC1101::reset(void)
{
cc1101_Deselect(); // Deselect CC1101
delayMicroseconds(5);
cc1101_Select(); // Select CC1101
delayMicroseconds(10);
cc1101_Deselect(); // Deselect CC1101
delayMicroseconds(41);
cc1101_Select(); // Select CC1101
wait_Miso(); // Wait until MISO goes low
spi.transfer(CC1101_SRES); // Send reset command strobe
wait_Miso(); // Wait until MISO goes low
cc1101_Deselect(); // Deselect CC1101
setCCregs(); // Reconfigure CC1101
}
/**
* setCCregs
*
* Configure CC1101 registers
*/
void CC1101::setCCregs(void)
{
writeReg(CC1101_IOCFG2, CC1101_DEFVAL_IOCFG2);
writeReg(CC1101_IOCFG1, CC1101_DEFVAL_IOCFG1);
writeReg(CC1101_IOCFG0, CC1101_DEFVAL_IOCFG0);
writeReg(CC1101_FIFOTHR, CC1101_DEFVAL_FIFOTHR);
writeReg(CC1101_PKTLEN, CC1101_DEFVAL_PKTLEN);
writeReg(CC1101_PKTCTRL1, CC1101_DEFVAL_PKTCTRL1);
writeReg(CC1101_PKTCTRL0, CC1101_DEFVAL_PKTCTRL0);
// Set default synchronization word
setSyncWord(syncWord);
// Set default device address
setDevAddress(devAddress);
// Set default frequency channel
setChannel(channel);
writeReg(CC1101_FSCTRL1, CC1101_DEFVAL_FSCTRL1);
writeReg(CC1101_FSCTRL0, CC1101_DEFVAL_FSCTRL0);
// Set default carrier frequency = 868 MHz
setCarrierFreq(carrierFreq);
writeReg(CC1101_MDMCFG4, CC1101_DEFVAL_MDMCFG4);
writeReg(CC1101_MDMCFG3, CC1101_DEFVAL_MDMCFG3);
writeReg(CC1101_MDMCFG2, CC1101_DEFVAL_MDMCFG2);
writeReg(CC1101_MDMCFG1, CC1101_DEFVAL_MDMCFG1);
writeReg(CC1101_MDMCFG0, CC1101_DEFVAL_MDMCFG0);
writeReg(CC1101_DEVIATN, CC1101_DEFVAL_DEVIATN);
writeReg(CC1101_MCSM2, CC1101_DEFVAL_MCSM2);
writeReg(CC1101_MCSM1, CC1101_DEFVAL_MCSM1);
writeReg(CC1101_MCSM0, CC1101_DEFVAL_MCSM0);
writeReg(CC1101_FOCCFG, CC1101_DEFVAL_FOCCFG);
writeReg(CC1101_BSCFG, CC1101_DEFVAL_BSCFG);
writeReg(CC1101_AGCCTRL2, CC1101_DEFVAL_AGCCTRL2);
writeReg(CC1101_AGCCTRL1, CC1101_DEFVAL_AGCCTRL1);
writeReg(CC1101_AGCCTRL0, CC1101_DEFVAL_AGCCTRL0);
writeReg(CC1101_WOREVT1, CC1101_DEFVAL_WOREVT1);
writeReg(CC1101_WOREVT0, CC1101_DEFVAL_WOREVT0);
writeReg(CC1101_WORCTRL, CC1101_DEFVAL_WORCTRL);
writeReg(CC1101_FREND1, CC1101_DEFVAL_FREND1);
writeReg(CC1101_FREND0, CC1101_DEFVAL_FREND0);
writeReg(CC1101_FSCAL3, CC1101_DEFVAL_FSCAL3);
writeReg(CC1101_FSCAL2, CC1101_DEFVAL_FSCAL2);
writeReg(CC1101_FSCAL1, CC1101_DEFVAL_FSCAL1);
writeReg(CC1101_FSCAL0, CC1101_DEFVAL_FSCAL0);
writeReg(CC1101_RCCTRL1, CC1101_DEFVAL_RCCTRL1);
writeReg(CC1101_RCCTRL0, CC1101_DEFVAL_RCCTRL0);
writeReg(CC1101_FSTEST, CC1101_DEFVAL_FSTEST);
writeReg(CC1101_PTEST, CC1101_DEFVAL_PTEST);
writeReg(CC1101_AGCTEST, CC1101_DEFVAL_AGCTEST);
writeReg(CC1101_TEST2, CC1101_DEFVAL_TEST2);
writeReg(CC1101_TEST1, CC1101_DEFVAL_TEST1);
writeReg(CC1101_TEST0, CC1101_DEFVAL_TEST0);
// Send empty packet
CCPACKET packet;
packet.length = 0;
sendData(packet);
}
/**
* init
*
* Initialize CC1101 radio
*
* @param freq Carrier frequency
*/
void CC1101::init(uint8_t freq)
{
carrierFreq = freq;
spi.begin(); // Initialize SPI interface
pinMode(PORT_GDO0, INPUT); // Config GDO0 as input
reset(); // Reset CC1101
// Configure PATABLE
//writeBurstReg(CC1101_PATABLE, (byte*)paTable, 8);
writeReg(CC1101_PATABLE, paTableByte);
}
/**
* setSyncWord
*
* Set synchronization word
*
* 'syncH' Synchronization word - High byte
* 'syncL' Synchronization word - Low byte
*/
void CC1101::setSyncWord(uint8_t syncH, uint8_t syncL)
{
writeReg(CC1101_SYNC1, syncH);
writeReg(CC1101_SYNC0, syncL);
syncWord[0] = syncH;
syncWord[1] = syncL;
}
/**
* setSyncWord (overriding method)
*
* Set synchronization word
*
* 'syncH' Synchronization word - pointer to 2-byte array
*/
void CC1101::setSyncWord(byte *sync)
{
CC1101::setSyncWord(sync[0], sync[1]);
}
/**
* setDevAddress
*
* Set device address
*
* @param addr Device address
*/
void CC1101::setDevAddress(byte addr)
{
writeReg(CC1101_ADDR, addr);
devAddress = addr;
}
/**
* setChannel
*
* Set frequency channel
*
* 'chnl' Frequency channel
*/
void CC1101::setChannel(byte chnl)
{
writeReg(CC1101_CHANNR, chnl);
channel = chnl;
}
/**
* setCarrierFreq
*
* Set carrier frequency
*
* 'freq' New carrier frequency
*/
void CC1101::setCarrierFreq(byte freq)
{
switch(freq)
{
case CFREQ_915:
writeReg(CC1101_FREQ2, CC1101_DEFVAL_FREQ2_915);
writeReg(CC1101_FREQ1, CC1101_DEFVAL_FREQ1_915);
writeReg(CC1101_FREQ0, CC1101_DEFVAL_FREQ0_915);
break;
case CFREQ_433:
writeReg(CC1101_FREQ2, CC1101_DEFVAL_FREQ2_433);
writeReg(CC1101_FREQ1, CC1101_DEFVAL_FREQ1_433);
writeReg(CC1101_FREQ0, CC1101_DEFVAL_FREQ0_433);
break;
case CFREQ_918:
writeReg(CC1101_FREQ2, CC1101_DEFVAL_FREQ2_918);
writeReg(CC1101_FREQ1, CC1101_DEFVAL_FREQ1_918);
writeReg(CC1101_FREQ0, CC1101_DEFVAL_FREQ0_918);
break;
default:
writeReg(CC1101_FREQ2, CC1101_DEFVAL_FREQ2_868);
writeReg(CC1101_FREQ1, CC1101_DEFVAL_FREQ1_868);
writeReg(CC1101_FREQ0, CC1101_DEFVAL_FREQ0_868);
break;
}
carrierFreq = freq;
}
/**
* setPowerDownState
*
* Put CC1101 into power-down state
*/
void CC1101::setPowerDownState()
{
// Comming from RX state, we need to enter the IDLE state first
cmdStrobe(CC1101_SIDLE);
// Enter Power-down state
cmdStrobe(CC1101_SPWD);
}
/**
* sendData
*
* Send data packet via RF
*
* 'packet' Packet to be transmitted. First byte is the destination address
*
* Return:
* True if the transmission succeeds
* False otherwise
*/
bool CC1101::sendData(CCPACKET packet)
{
byte marcState;
bool res = false;
// Declare to be in Tx state. This will avoid receiving packets whilst
// transmitting
rfState = RFSTATE_TX;
// Enter RX state
setRxState();
// Check that the RX state has been entered
while (((marcState = readStatusReg(CC1101_MARCSTATE)) & 0x1F) != 0x0D)
{
if (marcState == 0x11) // RX_OVERFLOW
flushRxFifo(); // flush receive queue
}
delayMicroseconds(500);
if (packet.length > 0)
{
// Set data length at the first position of the TX FIFO
writeReg(CC1101_TXFIFO, packet.length);
// Write data into the TX FIFO
writeBurstReg(CC1101_TXFIFO, packet.data, packet.length);
// CCA enabled: will enter TX state only if the channel is clear
setTxState();
}
// Check that TX state is being entered (state = RXTX_SETTLING)
marcState = readStatusReg(CC1101_MARCSTATE) & 0x1F;
if((marcState != 0x13) && (marcState != 0x14) && (marcState != 0x15))
{
setIdleState(); // Enter IDLE state
flushTxFifo(); // Flush Tx FIFO
setRxState(); // Back to RX state
// Declare to be in Rx state
rfState = RFSTATE_RX;
return false;
}
// Wait for the sync word to be transmitted
wait_GDO0_high();
// Wait until the end of the packet transmission
wait_GDO0_low();
// Check that the TX FIFO is empty
if((readStatusReg(CC1101_TXBYTES) & 0x7F) == 0)
res = true;
setIdleState(); // Enter IDLE state
flushTxFifo(); // Flush Tx FIFO
// Enter back into RX state
setRxState();
// Declare to be in Rx state
rfState = RFSTATE_RX;
return res;
}
/**
* receiveData
*
* Read data packet from RX FIFO
*
* 'packet' Container for the packet received
*
* Return:
* Amount of bytes received
*/
byte CC1101::receiveData(CCPACKET * packet)
{
byte val;
byte rxBytes = readStatusReg(CC1101_RXBYTES);
// Any byte waiting to be read and no overflow?
if (rxBytes & 0x7F)
{
// Read data length
packet->length = readConfigReg(CC1101_RXFIFO);
// If packet is too long
if (packet->length > CCPACKET_DATA_LEN)
packet->length = 0; // Discard packet
else
{
// Read data packet
readBurstReg(packet->data, CC1101_RXFIFO, packet->length);
// Read RSSI
packet->rssi = readConfigReg(CC1101_RXFIFO);
// Read LQI and CRC_OK
val = readConfigReg(CC1101_RXFIFO);
packet->lqi = val & 0x7F;
packet->crc_ok = bitRead(val, 7);
}
}
else
packet->length = 0;
setIdleState(); // Enter IDLE state
flushRxFifo(); // Flush Rx FIFO
//cmdStrobe(CC1101_SCAL);
// Back to RX state
setRxState();
return packet->length;
}
/**
* setRxState
*
* Enter Rx state
*/
void CC1101::setRxState(void)
{
cmdStrobe(CC1101_SRX);
rfState = RFSTATE_RX;
}
/**
* setTxState
*
* Enter Tx state
*/
void CC1101::setTxState(void)
{
cmdStrobe(CC1101_STX);
rfState = RFSTATE_TX;
}