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

Files at this revision

API Documentation at this revision

Comitter:
hajesusrodrigues
Date:
Thu May 30 22:05:50 2013 +0000
Parent:
5:12d8175359f2
Child:
7:19d9da22271a
Commit message:
Moteino Comunication Protocol Implementation

Changed in this revision

RF12B.cpp Show diff for this revision Revisions of this file
RF12B.h Show diff for this revision Revisions of this file
RFM12B.cpp Show annotated file Show diff for this revision Revisions of this file
RFM12B.h Show annotated file Show diff for this revision Revisions of this file
--- a/RF12B.cpp	Tue Mar 13 10:21:46 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,280 +0,0 @@
-/* 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;
-}
-
-
-
-
-
-
-
-
-
-
--- a/RF12B.h	Tue Mar 13 10:21:46 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,96 +0,0 @@
-#ifndef _RF12B_H
-#define _RF12B_H
-
-#include "mbed.h"
-#define RF12_433MHZ     1
-#define RF12_868MHZ     2
-#define RF12_915MHZ     3
-
-#define rf12_grp        rf12_buf[0]
-#define rf12_hdr        rf12_buf[1]
-#define rf12_len        rf12_buf[2]
-#define rf12_data       (rf12_buf + 3)
-
-#define RF12_HDR_CTL    0x80
-#define RF12_HDR_DST    0x40
-#define RF12_HDR_ACK    0x20
-#define RF12_HDR_MASK   0x1F
-
-#define RF12_MAXDATA    66
-// maximum transmit / receive buffer: 3 header + data + 2 crc bytes
-#define RF_MAX   (RF12_MAXDATA + 5)
-#define PACKET_LEN 16
-
-// shorthand to simplify sending out the proper ACK when requested
-#define RF12_WANTS_ACK ((rf12_hdr & RF12_HDR_ACK) && !(rf12_hdr & RF12_HDR_CTL))
-#define RF12_ACK_REPLY (rf12_hdr & RF12_HDR_DST ? RF12_HDR_CTL : \
-            RF12_HDR_CTL | RF12_HDR_DST | (rf12_hdr & RF12_HDR_MASK))
- 
-// New for mbed 
-#define RF12_WANTS_ACK_MBED ((radiolink.get_hdr() & RF12_HDR_ACK) && !(radiolink.get_hdr() & RF12_HDR_CTL))
-#define RF12_ACK_REPLY_MBED (radiolink.get_hdr() & RF12_HDR_DST ? RF12_HDR_CTL : \
-            RF12_HDR_CTL | RF12_HDR_DST | (radiolink.get_hdr() & RF12_HDR_MASK))
-                       
-            
-//enum rfmode_t{RX, TX};
-
-class RF12B {
-public:
-    /* Constructor */
-    RF12B(PinName SDI,
-          PinName SDO,
-          PinName SCK,
-          PinName NCS,
-          PinName NIRQ);
-   
-     
-    /* Initialises the RF12B module */
-    void init(uint8_t id, uint8_t band, uint8_t g);
-        
- 
-    /* Returns the packet length if data is available in the receive buffer, 0 otherwise*/
-   unsigned int available();
-   void rf12_sendStart (uint8_t hdr, const void* ptr, uint8_t len);
-   void rf12_sendStart2 (uint8_t hdr); 
-   uint8_t  rf12_recvDone (void);
-   void rf12_recvStart (void);
-   uint16_t check_crc(void);
-   uint8_t length(void);
-   uint8_t* get_data(void);
-   uint8_t get_hdr(void);
-   
-protected:
-
-    /* SPI module */
-    SPI spi;
-    
-    /* Other digital pins */
-    DigitalOut NCS;
-    InterruptIn NIRQ;
-    DigitalIn NIRQ_in;
-
-    volatile uint16_t rf12_crc; // running crc value
-    volatile unsigned char rf12_buf[RF_MAX];  // recv/xmit buf, including hdr & crc bytes  
-    volatile  uint8_t nodeid;              // address of this node
-    volatile  uint8_t group;               // network grou
-    volatile uint8_t rxfill;     // number of data bytes in rf12_buf
-    volatile int8_t rxstate;     // current transceiver state
- 
-
-    /* Write a command to the RF Module */
-    unsigned int writeCmd(unsigned int cmd);
-    
-    /* Sends a byte of data across RF */
-    void send(unsigned char data);
-    
-    /* Interrupt routine for data reception */
-    void rxISR();
-    
-
-    uint16_t _crc16_update(uint16_t crc, uint8_t data);
-    
-    uint16_t rf12_xfer (uint16_t cmd);    
-    uint8_t rf12_byte(uint8_t out);
-};
-
-#endif /* _RF12B_H */
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RFM12B.cpp	Thu May 30 22:05:50 2013 +0000
@@ -0,0 +1,372 @@
+/*
+ RFM12B 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
+
+ Modified by Hugo Rodrigues (May 2013)
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ */
+
+#include "RFM12B.h"
+
+RFM12B::RFM12B(PinName _SDI, PinName _SDO, PinName _SCK, PinName _NCS, PinName _NIRQ, PinName _NIRQ_LED) :
+spi(_SDI, _SDO, _SCK), NCS(_NCS), NIRQ(_NIRQ), NIRQ_in(_NIRQ), NIRQ_LED(_NIRQ_LED) {
+
+    useEncryption = false;
+
+    /* SPI frequency, 8 bit word length, 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, &RFM12B::InterruptHandler);
+}
+
+int RFM12B::writeCmd(int cmd) {
+    NCS = 0;
+    int recv = spi.write(cmd >> 8);
+    recv = spi.write(cmd);
+    NCS = 1;
+    return recv;
+}
+
+uint16_t RFM12B::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;
+}
+
+uint8_t RFM12B::byte(uint8_t out) {
+    return spi.write(out);
+}
+
+uint16_t RFM12B::xfer(uint16_t cmd) {
+    NCS = 0;
+    uint16_t reply = byte(cmd >> 8) << 8;
+    reply |= byte(cmd);
+    NCS = 1;
+    return reply;
+}
+
+// Call this once with params:
+// - node ID (0-31)
+// - frequency band (RF12_433MHZ, RF12_868MHZ, RF12_915MHZ)
+// - networkid [optional - default = 170] (0-255 for RF12B, only 212 allowed for RF12)
+// - txPower [optional - default = 0 (max)] (7 is min value)
+// - airKbps [optional - default = 38.31Kbps]
+void RFM12B::Initialize(uint8_t nodeid, uint8_t freqBand, uint8_t groupid, uint8_t txPower, uint8_t airKbps) {
+
+    nodeID = nodeid;
+    networkID = groupid;
+    rf12_grp= groupid;
+
+    writeCmd(0x0000);                   // initial 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 | (freqBand << 4)); // EL (ena TX), EF (ena RX FIFO), 12.0pF
+    writeCmd(0xA640);                   // Frequency is exactly 434/868/915MHz (whatever freqBand is)
+    writeCmd(0xC600 + airKbps);         //Air transmission baud rate: 0x08= ~38.31Kbps
+    writeCmd(0x94A2);                   // VDI,FAST,134kHz,0dBm,-91dBm
+    writeCmd(0xC2AC);                   // AL,!ml,DIG,DQD4
+    if (networkID != 0) {
+        writeCmd(0xCA83);               // FIFO8,2-SYNC,!ff,DR
+        writeCmd(0xCE00 | networkID);   // SYNC=2DXX
+    } else {
+        writeCmd(0xCA8B);               // FIFO8,1-SYNC,!ff,DR
+        writeCmd(0xCE2D);               // SYNC=2D
+    }
+
+    writeCmd(0xC483);                   // @PWR,NO RSTRIC,!st,!fi,OE,EN
+    writeCmd(0x9850 | (txPower > 7 ? 7 : txPower)); // !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;
+}
+
+void RFM12B::InterruptHandler() {
+
+    NIRQ_LED = 1;
+
+    // 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 = xfer(RF_RX_FIFO_READ);
+
+        if (rxfill == 0 && networkID != 0)
+            rf12_buf[rxfill++] = networkID;
+
+        rf12_buf[rxfill++] = in;
+        rf12_crc = crc16_update(rf12_crc, in);
+
+        if (rxfill >= rf12_len+ 6 || rxfill >= RF_MAX)
+            xfer(RF_IDLE_MODE);
+    } else {
+        uint8_t out;
+
+        if (rxstate < 0) {
+            uint8_t pos = 4 + 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 = - (3 + rf12_len);
+                break;
+            case TXCRC1:
+                out = rf12_crc;
+                break;
+            case TXCRC2:
+                out = rf12_crc >> 8;
+                break;
+            case TXDONE:
+                xfer(RF_IDLE_MODE); // fall through
+                out = 0xAA;
+                break;
+            default:
+                out = 0xAA;
+            }
+        }
+        xfer(RF_TXREG_WRITE + out);
+    }
+    NIRQ_LED = 0;
+}
+
+void RFM12B::ReceiveStart(void) {
+    rxfill = rf12_len= 0;
+    rf12_crc = ~0;
+
+    if (networkID != 0)
+        rf12_crc = crc16_update(~0, networkID);
+
+    rxstate = TXRECV;
+    xfer(RF_RECEIVER_ON);
+}
+
+bool RFM12B::ReceiveComplete(void) {
+    if (rxstate == TXRECV && (rxfill >= rf12_len+ 6 || rxfill >= RF_MAX)) {
+        rxstate = TXIDLE;
+
+        if (rf12_len > RF12_MAXDATA) {
+            rf12_crc = 1; // force bad crc if packet length is invalid
+        }
+        if (RF12_DESTID == 0 || RF12_DESTID == nodeID) {
+
+            if (rf12_crc == 0 && useEncryption)
+                Encryption(false);
+            else
+                rf12_seq = -1;
+
+#ifdef DEBUG
+            printf("\nReceived message from [%d]; crc:%x,  len: %d, message: ", RF12_SOURCEID, rf12_crc, rf12_len);
+            for (int i=0; i<rf12_len; i++) {
+                printf("%c", rf12_data[i]);
+            }
+            printf("\n");
+#endif
+
+            return true; // it's a broadcast packet or it's addressed to this node
+        }
+    }
+    if (rxstate == TXIDLE)
+        ReceiveStart();
+
+    return false;
+}
+
+bool RFM12B::CanSend() {
+    // no need to test with interrupts disabled: state TXRECV is only reached
+    // outside of ISR and we don't care if rxfill jumps from 0 to 1 here
+    if (rxstate == TXRECV && rxfill == 0 && (byte(0x00) & (RF_RSSI_BIT >> 8)) == 0) {
+        xfer(RF_IDLE_MODE); // stop receiver
+        rxstate = TXIDLE;
+        return true;
+    }
+    return false;
+}
+
+void RFM12B::SendStart(uint8_t toNodeID, bool requestACK, bool sendACK) {
+
+    rf12_hdr1= toNodeID | (sendACK ? RF12_HDR_ACKCTLMASK : 0);
+    rf12_hdr2= nodeID | (requestACK ? RF12_HDR_ACKCTLMASK : 0);
+
+#ifdef DEBUG
+    printf("SendStart to Node [%d], from Node [%d] \n", toNodeID, nodeID);
+#endif
+
+    if (useEncryption)
+        Encryption(true);
+
+    rf12_crc = ~0;
+    rf12_crc = crc16_update(rf12_crc, rf12_grp);
+    rxstate = TXPRE1;
+
+    xfer(RF_XMITTER_ON); // bytes will be fed via interrupts
+}
+
+void RFM12B::SendStart(uint8_t toNodeID, const void* sendBuf, uint8_t sendLen, bool requestACK, bool sendACK) {
+    
+    rf12_len = sendLen;
+    memcpy((void*) rf12_data, sendBuf, sendLen);
+    
+#ifdef DEBUG
+            printf("\nSending message from [%d]; crc:%x,  len: %d, message: ", nodeID, rf12_crc, rf12_len);
+            for (int i=0; i<rf12_len; i++) {
+                printf("%c", rf12_data[i]);
+            }
+#endif
+    
+
+    SendStart(toNodeID, requestACK, sendACK);
+}
+
+/// Should be called immediately after reception in case sender wants ACK
+void RFM12B::SendACK(const void* sendBuf, uint8_t sendLen) {
+    while (!CanSend())
+        ReceiveComplete();
+    SendStart(RF12_SOURCEID, sendBuf, (sendLen > 0) ? sendLen: strlen((const char*)sendBuf), false, true);
+}
+
+void RFM12B::Send(uint8_t toNodeID, const void* sendBuf, uint8_t sendLen, bool requestACK) {
+    while (!CanSend())
+        ReceiveComplete();
+    SendStart(toNodeID, sendBuf, (sendLen > 0) ? sendLen: strlen((const char*)sendBuf) , requestACK, false);
+}
+
+uint8_t RFM12B::GetSender(void) {
+    return RF12_SOURCEID;
+}
+
+volatile uint8_t * RFM12B::GetData(void) {
+
+    return (uint8_t*) rf12_data;
+}
+
+uint8_t RFM12B::GetDataLen(void) {
+    return rf12_len;
+}
+
+bool RFM12B::ACKRequested() {
+    return RF12_WANTS_ACK;
+}
+
+/// Should be polled immediately after sending a packet with ACK request
+bool RFM12B::ACKReceived(uint8_t fromNodeID) {
+    if (ReceiveComplete())
+        return CRC_Pass() && RF12_DESTID == nodeID && (RF12_SOURCEID == fromNodeID || fromNodeID == 0) && (rf12_hdr1&RF12_HDR_ACKCTLMASK) &&
+                !(rf12_hdr2 & RF12_HDR_ACKCTLMASK);
+    return false;
+}
+
+bool RFM12B::CRC_Pass(void) {
+    return (rf12_crc == 0);
+}
+
+// XXTEA by David Wheeler, adapted from http://en.wikipedia.org/wiki/XXTEA
+#define DELTA 0x9E3779B9
+#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (cryptKey[(uint8_t)((p&3)^e)] ^ z)))
+void RFM12B::Encryption(bool encrypt) {
+
+    uint32_t y, z, sum, *v = (uint32_t*) rf12_data;
+    uint8_t p, e, rounds = 6;
+
+    if (encrypt) {
+        // pad with 1..4-byte sequence number
+        *(uint32_t*) (rf12_data + rf12_len) = ++seqNum;
+        uint8_t pad = 3 - (rf12_len & 3);
+        rf12_len += pad;
+        rf12_data[rf12_len] &= 0x3F;
+        rf12_data[rf12_len] |= pad << 6;
+        ++rf12_len;
+        // actual encoding
+        char n = rf12_len / 4;
+        if (n > 1) {
+            sum = 0;
+            z = v[n-1];
+            do {
+                sum += DELTA;
+                e = (sum >> 2) & 3;
+                for (p=0; p<n-1; p++)
+                    y = v[p+1], z = v[p] += MX;
+                y = v[0];
+                z = v[n-1] += MX;
+            }while (--rounds);
+        }
+    } else if (rf12_crc == 0) {
+        // actual decoding
+        char n = rf12_len / 4;
+        if (n > 1) {
+            sum = rounds*DELTA;
+            y = v[0];
+            do {
+                e = (sum >> 2) & 3;
+                for (p=n-1; p>0; p--)
+                    z = v[p-1], y = v[p] -= MX;
+                z = v[n-1];
+                y = v[0] -= MX;
+            }while ((sum -= DELTA) != 0);
+        }
+        // strip sequence number from the end again
+        if (n > 0) {
+            uint8_t pad = rf12_data[--rf12_len] >> 6;
+            rf12_seq = rf12_data[rf12_len] & 0x3F;
+            while (pad-- > 0)
+                rf12_seq = (rf12_seq << 8) | rf12_data[--rf12_len];
+        }
+    }
+
+}
+
+void RFM12B::SetEncryptionKey(const uint8_t* key) {
+    if (key != 0) {
+        for (uint8_t i = 0; i < sizeof cryptKey; ++i)
+            ((uint8_t*) cryptKey)[i] = key[i];
+
+        useEncryption = true;
+    } else
+        useEncryption = false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RFM12B.h	Thu May 30 22:05:50 2013 +0000
@@ -0,0 +1,152 @@
+/*
+ RFM12B 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
+
+ Modified by Hugo Rodrigues (May 2013)
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ */
+
+#ifndef _RFM12B_H
+#define _RFM12B_H
+
+#include "mbed.h"
+
+/// RF12 Maximum message size in bytes.
+#define RF12_MAXDATA    128
+/// Max transmit/receive buffer: 4 header + data + 2 crc bytes
+#define RF_MAX          (RF12_MAXDATA + 6)
+
+#define RF12_433MHZ     1
+#define RF12_868MHZ     2
+#define RF12_915MHZ     3
+
+#define RF12_HDR_IDMASK      0x7F
+#define RF12_HDR_ACKCTLMASK  0x80
+#define RF12_DESTID   (rf12_hdr1 & RF12_HDR_IDMASK)
+#define RF12_SOURCEID (rf12_hdr2 & RF12_HDR_IDMASK)
+
+// shorthands to simplify sending out the proper ACK when requested
+#define RF12_WANTS_ACK ((rf12_hdr2 & RF12_HDR_ACKCTLMASK) && !(rf12_hdr1 & RF12_HDR_ACKCTLMASK))
+
+/// Shorthand for RF12 group byte in rf12_buf.
+#define rf12_grp        rf12_buf[0]
+/// pointer to 1st header byte in rf12_buf (CTL + DESTINATIONID)
+#define rf12_hdr1        rf12_buf[1]
+/// pointer to 2nd header byte in rf12_buf (ACK + SOURCEID)
+#define rf12_hdr2        rf12_buf[2]
+
+/// Shorthand for RF12 length byte in rf12_buf.
+#define rf12_len        rf12_buf[3]
+/// Shorthand for first RF12 data byte in rf12_buf.
+#define rf12_data       (rf12_buf + 4)
+
+// 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
+
+//#define DEBUG
+
+// transceiver states, these determine what to do with each interrupt
+enum {
+    TXCRC1, TXCRC2, TXTAIL, TXDONE, TXIDLE, TXRECV, TXPRE1, TXPRE2, TXPRE3, TXSYN1, TXSYN2,
+};
+
+class RFM12B {
+
+public:
+    /* Constructor */
+    RFM12B(PinName SDI, PinName SDO, PinName SCK, PinName NCS, PinName NIRQ, PinName NIRQ_LED);
+
+    /* Initialises the RFM12B module */
+    void Initialize(uint8_t nodeid, uint8_t freqBand, uint8_t groupid=0xAA, uint8_t txPower=0, uint8_t airKbps=0x08);
+
+    void ReceiveStart(void);
+    bool ReceiveComplete(void);
+    bool CanSend();
+
+    void SendStart(uint8_t toNodeId, bool requestACK = false, bool sendACK = false);
+    void SendStart(uint8_t toNodeId, const void* sendBuf, uint8_t sendLen, bool requestACK = false,
+            bool sendACK = false);
+    void SendACK(const void* sendBuf = "", uint8_t sendLen = 0);
+    void Send(uint8_t toNodeId, const void* sendBuf, uint8_t sendLen, bool requestACK = false);
+
+    volatile uint8_t * GetData();
+    uint8_t GetDataLen(void);                   // how many bytes were received
+    uint8_t GetSender(void);
+
+    bool ACKRequested();
+    bool ACKReceived(uint8_t fromNodeID = 0);
+
+    void Encryption(bool encrypt);              // does en-/decryption
+    void SetEncryptionKey(const uint8_t* key);  // set encryption key
+
+    bool CRC_Pass(void);
+
+protected:
+    /* SPI module */
+    SPI spi;
+
+    /* Other digital pins */
+    DigitalOut NCS;
+    InterruptIn NIRQ;
+    DigitalIn NIRQ_in;
+    DigitalOut NIRQ_LED;
+
+    volatile uint8_t nodeID;                    // address of this node
+    volatile uint8_t networkID;                 // network group
+
+    volatile uint8_t* Data;
+    volatile uint8_t* DataLen;
+
+    void InterruptHandler();                    // interrupt routine for data reception
+
+    int writeCmd(int cmd);                      // write a command to the RF module
+    uint16_t crc16_update(uint16_t crc, uint8_t data);
+    uint16_t xfer(uint16_t cmd);
+    uint8_t byte(uint8_t out);
+
+private:
+    volatile uint8_t rf12_buf[RF_MAX];          // recv/xmit buf, including hdr & crc bytes
+
+    volatile uint8_t rxfill;                    // number of data bytes in rf12_buf
+    volatile int8_t rxstate;                    // current transceiver state
+    volatile uint16_t rf12_crc;                 // running crc value
+    uint32_t seqNum;                            // encrypted send sequence number
+    uint32_t cryptKey[4];                       // encryption key to use
+    long rf12_seq;                              // seq number of encrypted packet (or -1)
+
+    bool useEncryption;
+};
+
+#endif /* _RFM12B_H */