mBed RFM12B module library

Dependents:   _EXAMPLE_RFM12B

Fork of RF12B by Sukkin Pang

RFM12B Library

The main purpose of this library was to implement the RFM12B module in order to be able to establish communication with the Moteino (arduino clone that uses the RFM12B).

In order to achieve my goal I was highly inspired by RF12B library from pangsk https://mbed.org/users/pangsk/ and by RFM12B arduino library made by Felix Rusu (http://lowpowerlab.com/blog/2012/12/28/rfm12b-arduino-library/)

Who/What is Moteino? (http://lowpowerlab.com/moteino/)

RF12B.cpp

Committer:
pangsk
Date:
2012-03-13
Revision:
5:12d8175359f2
Parent:
3:e926e54424cb

File content as of revision 5:12d8175359f2:

/* 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);


RF12B::RF12B(PinName _SDI,
             PinName _SDO,
             PinName _SCK,
             PinName _NCS,
             PinName _NIRQ):spi(_SDI, _SDO, _SCK),
        NCS(_NCS), NIRQ(_NIRQ), NIRQ_in(_NIRQ) {

    /* 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 | group); // SYNC=2DXX&#65307; 
    
    writeCmd(0xC483); // @PWR,NO RSTRIC,!st,!fi,OE,EN 
    writeCmd(0x9850); // !mp,90kHz,MAX OUT 
    writeCmd(0xCC77); // OB1&#65292;OB0, LPX,&#65281;ddy&#65292;DDIT&#65292;BW0 
    writeCmd(0xE000); // NOT USE 
    writeCmd(0xC800); // NOT USE 
    writeCmd(0xC049); // 1.66MHz,3.1V 

    rxstate = TXIDLE;
       
 
}

/* 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::get_hdr(void)
{
    return rf12_hdr;

}


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;
}