File content as of revision 1:27a1606deace:
/* RF12B Library. Based on work done by JeeLabs.org ported to mbed by SK Pang.
http://jeelabs.net/projects/cafe/wiki/RF12
http://opensource.org/licenses/mit-license.php
Jan 2012 skpang.co.uk
*/
#include "RF12B.h"
// RF12 command codes
#define RF_RECEIVER_ON 0x82DD
#define RF_XMITTER_ON 0x823D
#define RF_IDLE_MODE 0x820D
#define RF_SLEEP_MODE 0x8205
#define RF_WAKEUP_MODE 0x8207
#define RF_TXREG_WRITE 0xB800
#define RF_RX_FIFO_READ 0xB000
#define RF_WAKEUP_TIMER 0xE000
// RF12 status bits
#define RF_LBD_BIT 0x0400
#define RF_RSSI_BIT 0x0100
// bits in the node id configuration byte
#define NODE_BAND 0xC0 // frequency band
#define NODE_ACKANY 0x20 // ack on broadcast packets if set
#define NODE_ID 0x1F // id of this node, as A..Z or 1..31
// transceiver states, these determine what to do with each interrupt
enum {
TXCRC1, TXCRC2, TXTAIL, TXDONE, TXIDLE,
TXRECV,
TXPRE1, TXPRE2, TXPRE3, TXSYN1, TXSYN2,
};
DigitalOut rfled(LED3);
DigitalOut t1(p5);
DigitalOut t2(p6);
RF12B::RF12B(PinName _SDI,
PinName _SDO,
PinName _SCK,
PinName _NCS,
PinName _NIRQ):spi(_SDI, _SDO, _SCK),
NCS(_NCS), NIRQ(_NIRQ), NIRQ_in(_NIRQ), rfled(LED3),t1(p5),t2(p6) {
/* SPI frequency, word lenght, polarity and phase */
spi.format(8,0);
spi.frequency(2000000);
/* Set ~CS high */
NCS = 1;
/* Setup interrupt to happen on falling edge of NIRQ */
NIRQ.fall(this, &RF12B::rxISR);
}
/**********************************************************************
* PRIVATE FUNCTIONS
*********************************************************************/
/* Initialises the RF12B module */
void RF12B::init(uint8_t id, uint8_t band, uint8_t g) {
nodeid = id;
group = g;
rf12_grp = g;
writeCmd(0x0000); // intitial SPI transfer added to avoid power-up problem
writeCmd(RF_SLEEP_MODE); // DC (disable clk pin), enable lbd
// wait until RFM12B is out of power-up reset, this takes several *seconds*
writeCmd(RF_TXREG_WRITE); // in case we're still in OOK mode
while (NIRQ == 0) writeCmd(0x0000);
writeCmd(0x80C7 | (2 << 4)); // EL (ena TX), EF (ena RX FIFO), 12.0pF
writeCmd(0xA640); // 868MHz
writeCmd(0xC606); // approx 49.2 Kbps, i.e. 10000/29/(1+6) Kbps
writeCmd(0x94A2); // VDI,FAST,134kHz,0dBm,-91dBm
writeCmd(0xC2AC); // AL,!ml,DIG,DQD4
writeCmd(0xCA83); // FIFO8,2-SYNC,!ff,DR
writeCmd(0xCE00 | 1); // SYNC=2DXX;
writeCmd(0xC483); // @PWR,NO RSTRIC,!st,!fi,OE,EN
writeCmd(0x9850); // !mp,90kHz,MAX OUT
writeCmd(0xCC77); // OB1,OB0, LPX,!ddy,DDIT,BW0
writeCmd(0xE000); // NOT USE
writeCmd(0xC800); // NOT USE
writeCmd(0xC049); // 1.66MHz,3.1V
rxstate = TXIDLE;
rfled = 0;
}
/* Write a command to the RF Module */
unsigned int RF12B::writeCmd(unsigned int cmd) {
NCS = 0;
unsigned int recv = spi.write(cmd >>8);
recv = spi.write(cmd);
NCS = 1;
return recv;
}
/* Sends a byte of data across RF */
void RF12B::send(unsigned char data) {
while (NIRQ);
writeCmd(0xB800 + data);
}
/* Interrupt routine for data reception and Txing */
void RF12B::rxISR() {
// a transfer of 2x 16 bits @ 2 MHz over SPI takes 2x 8 us inside this ISR
writeCmd(0x0000);
if (rxstate == TXRECV) {
uint8_t in = rf12_xfer(RF_RX_FIFO_READ);
if (rxfill == 0 && group != 0)
rf12_buf[rxfill++] = group;
rf12_buf[rxfill++] = in;
rf12_crc = _crc16_update(rf12_crc, in);
if (rxfill >= rf12_len + 5 || rxfill >= RF_MAX)
rf12_xfer(RF_IDLE_MODE);
} else {
uint8_t out;
if (rxstate < 0) {
uint8_t pos = 3 + rf12_len + rxstate++;
out = rf12_buf[pos];
rf12_crc = _crc16_update(rf12_crc, out);
} else
switch (rxstate++) {
case TXSYN1: out = 0x2D; break;
case TXSYN2: out = rf12_grp; rxstate = - (2 + rf12_len); break;
case TXCRC1: out = rf12_crc; break;
case TXCRC2: out = rf12_crc >> 8; break;
case TXDONE: rf12_xfer(RF_IDLE_MODE); // fall through
default: out = 0xAA;
}
rf12_xfer(RF_TXREG_WRITE + out);
}
}
void RF12B::rf12_sendStart (uint8_t hdr, const void* ptr, uint8_t len)
{
rf12_len = len;
memcpy((void*) rf12_data, ptr, len);
rf12_sendStart2(hdr);
}
void RF12B::rf12_sendStart2 (uint8_t hdr) {
rf12_hdr = hdr & RF12_HDR_DST ? hdr :
(hdr & ~RF12_HDR_MASK) + (nodeid & NODE_ID);
/* if (crypter != 0)
crypter(1);
*/
rf12_crc = ~0;
rf12_crc = _crc16_update(rf12_crc, rf12_grp);
rxstate = TXPRE1;
rf12_xfer(RF_XMITTER_ON); // bytes will be fed via interrupts
}
uint16_t RF12B::rf12_xfer (uint16_t cmd) {
NCS = 0;
uint16_t reply = rf12_byte(cmd >> 8) << 8;
reply |= rf12_byte(cmd);
NCS = 1;
return reply;
}
void RF12B::rf12_recvStart (void) {
rxfill = rf12_len = 0;
rf12_crc = ~0;
if (group != 0)
rf12_crc = _crc16_update(~0, group);
rxstate = TXRECV;
rf12_xfer(RF_RECEIVER_ON);
}
uint16_t RF12B::check_crc(void)
{
return rf12_crc;
}
uint8_t RF12B::length(void)
{
return rf12_len;
}
uint8_t* RF12B::get_data(void)
{
return (uint8_t*)rf12_data;
}
uint8_t RF12B::rf12_recvDone (void) {
if (rxstate == TXRECV && (rxfill >= rf12_len + 5 || rxfill >= RF_MAX)) {
rxstate = TXIDLE;
if (rf12_len > RF12_MAXDATA)
rf12_crc = 1; // force bad crc if packet length is invalid
if (!(rf12_hdr & RF12_HDR_DST) || (nodeid & NODE_ID) == 31 ||
(rf12_hdr & RF12_HDR_MASK) == (nodeid & NODE_ID)) {
/*
for(i=0;i<rf12_len+6;i++)
{
printf("%X ",rf12_buf[i]);
}
printf(" crc:%x",rf12_crc);
*/
/*
if (rf12_crc == 0 && crypter != 0)
crypter(0);
else
rf12_seq = -1;
*/
return 1; // it's a broadcast packet or it's addressed to this node
}
}
if (rxstate == TXIDLE)
rf12_recvStart();
return 0;
}
uint8_t RF12B::rf12_byte(uint8_t out)
{
unsigned char recv = spi.write(out);
return recv;
}
uint16_t RF12B::_crc16_update(uint16_t crc, uint8_t data) {
int i;
crc ^= data;
for (i = 0; i < 8; ++i)
{
if (crc & 1)
crc = (crc >> 1) ^ 0xA001;
else
crc = (crc >> 1);
}
return crc;
}