Library for HopeRF RFM22 / RFM22B transceiver module ported to mbed. Original Software from Mike McCauley (mikem@open.com.au) . See http://www.open.com.au/mikem/arduino/RF22/

Dependents:   RF22_MAX_test_Send Geofence_receiver Geofence_sender Geofence_sender ... more

More Info about RFM22-modules like connecting and a demo-program see RF22-Notebook

Files at this revision

API Documentation at this revision

Comitter:
charly
Date:
Tue Feb 14 19:39:36 2012 +0000
Child:
1:813d4f57d630
Commit message:
Initial Port - Quick and Dirty !!!

Changed in this revision

RF22.cpp Show annotated file Show diff for this revision Revisions of this file
RF22.h Show annotated file Show diff for this revision Revisions of this file
RF22Datagram.cpp Show annotated file Show diff for this revision Revisions of this file
RF22Datagram.h Show annotated file Show diff for this revision Revisions of this file
RF22Mesh.cpp Show annotated file Show diff for this revision Revisions of this file
RF22Mesh.h Show annotated file Show diff for this revision Revisions of this file
RF22ReliableDatagram.cpp Show annotated file Show diff for this revision Revisions of this file
RF22ReliableDatagram.h Show annotated file Show diff for this revision Revisions of this file
RF22Router.cpp Show annotated file Show diff for this revision Revisions of this file
RF22Router.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RF22.cpp	Tue Feb 14 19:39:36 2012 +0000
@@ -0,0 +1,739 @@
+// RF22.cpp
+//
+// Copyright (C) 2011 Mike McCauley
+// $Id: RF22.cpp,v 1.13 2011/10/09 21:22:24 mikem Exp mikem $
+// ported to mbed by Karl Zweimueller
+
+
+#include "mbed.h"
+#include "RF22.h"
+//#include <SPI.h>
+
+
+// Interrupt vectors for the 2 Arduino interrupt pins
+// Each interrupt can be handled by a different instance of RF22, allowing you to have
+// 2 RF22s per Arduino
+//RF22* RF22::_RF22ForInterrupt[2] = {0, 0};
+
+// These are indexed by the values of ModemConfigChoice
+// Canned modem configurations generated with 
+// 'http://www.hoperf.com/upfile/RF22B 23B 31B 42B 43B Register Settings_RevB1-v5.xls'
+// Stored in flash (program) memory to save SRAM
+/*PROGMEM */ static const RF22::ModemConfig MODEM_CONFIG_TABLE[] =
+{
+    { 0x2b, 0x03, 0xf4, 0x20, 0x41, 0x89, 0x00, 0x36, 0x40, 0x0a, 0x1d, 0x80, 0x60, 0x10, 0x62, 0x2c, 0x00, 0x08 }, // Unmodulated carrier
+    { 0x2b, 0x03, 0xf4, 0x20, 0x41, 0x89, 0x00, 0x36, 0x40, 0x0a, 0x1d, 0x80, 0x60, 0x10, 0x62, 0x2c, 0x33, 0x08 }, // FSK, PN9 random modulation, 2, 5
+
+    //  1c,   1f,   20,   21,   22,   23,   24,   25,   2c,   2d,   2e,   58,   69,   6e,   6f,   70,   71,   72
+    // FSK, No Manchester, Max Rb err <1%, Xtal Tol 20ppm
+    { 0x2b, 0x03, 0xf4, 0x20, 0x41, 0x89, 0x00, 0x36, 0x40, 0x0a, 0x1d, 0x80, 0x60, 0x10, 0x62, 0x2c, 0x22, 0x08 }, // 2, 5
+    { 0x1b, 0x03, 0x41, 0x60, 0x27, 0x52, 0x00, 0x07, 0x40, 0x0a, 0x1e, 0x80, 0x60, 0x13, 0xa9, 0x2c, 0x22, 0x3a }, // 2.4, 36
+    { 0x1d, 0x03, 0xa1, 0x20, 0x4e, 0xa5, 0x00, 0x13, 0x40, 0x0a, 0x1e, 0x80, 0x60, 0x27, 0x52, 0x2c, 0x22, 0x48 }, // 4.8, 45
+    { 0x1e, 0x03, 0xd0, 0x00, 0x9d, 0x49, 0x00, 0x45, 0x40, 0x0a, 0x20, 0x80, 0x60, 0x4e, 0xa5, 0x2c, 0x22, 0x48 }, // 9.6, 45
+    { 0x2b, 0x03, 0x34, 0x02, 0x75, 0x25, 0x07, 0xff, 0x40, 0x0a, 0x1b, 0x80, 0x60, 0x9d, 0x49, 0x2c, 0x22, 0x0f }, // 19.2, 9.6
+    { 0x02, 0x03, 0x68, 0x01, 0x3a, 0x93, 0x04, 0xd5, 0x40, 0x0a, 0x1e, 0x80, 0x60, 0x09, 0xd5, 0x0c, 0x22, 0x1f }, // 38.4, 19.6
+    { 0x06, 0x03, 0x45, 0x01, 0xd7, 0xdc, 0x07, 0x6e, 0x40, 0x0a, 0x2d, 0x80, 0x60, 0x0e, 0xbf, 0x0c, 0x22, 0x2e }, // 57.6. 28.8
+    { 0x8a, 0x03, 0x60, 0x01, 0x55, 0x55, 0x02, 0xad, 0x40, 0x0a, 0x50, 0x80, 0x60, 0x20, 0x00, 0x0c, 0x22, 0xc8 }, // 125, 125
+
+    // GFSK, No Manchester, Max Rb err <1%, Xtal Tol 20ppm
+    // These differ from FSK only in register 71, for the modulation type
+    { 0x2b, 0x03, 0xf4, 0x20, 0x41, 0x89, 0x00, 0x36, 0x40, 0x0a, 0x1d, 0x80, 0x60, 0x10, 0x62, 0x2c, 0x23, 0x08 }, // 2, 5
+    { 0x1b, 0x03, 0x41, 0x60, 0x27, 0x52, 0x00, 0x07, 0x40, 0x0a, 0x1e, 0x80, 0x60, 0x13, 0xa9, 0x2c, 0x23, 0x3a }, // 2.4, 36
+    { 0x1d, 0x03, 0xa1, 0x20, 0x4e, 0xa5, 0x00, 0x13, 0x40, 0x0a, 0x1e, 0x80, 0x60, 0x27, 0x52, 0x2c, 0x23, 0x48 }, // 4.8, 45
+    { 0x1e, 0x03, 0xd0, 0x00, 0x9d, 0x49, 0x00, 0x45, 0x40, 0x0a, 0x20, 0x80, 0x60, 0x4e, 0xa5, 0x2c, 0x23, 0x48 }, // 9.6, 45
+    { 0x2b, 0x03, 0x34, 0x02, 0x75, 0x25, 0x07, 0xff, 0x40, 0x0a, 0x1b, 0x80, 0x60, 0x9d, 0x49, 0x2c, 0x23, 0x0f }, // 19.2, 9.6
+    { 0x02, 0x03, 0x68, 0x01, 0x3a, 0x93, 0x04, 0xd5, 0x40, 0x0a, 0x1e, 0x80, 0x60, 0x09, 0xd5, 0x0c, 0x23, 0x1f }, // 38.4, 19.6
+    { 0x06, 0x03, 0x45, 0x01, 0xd7, 0xdc, 0x07, 0x6e, 0x40, 0x0a, 0x2d, 0x80, 0x60, 0x0e, 0xbf, 0x0c, 0x23, 0x2e }, // 57.6. 28.8
+    { 0x8a, 0x03, 0x60, 0x01, 0x55, 0x55, 0x02, 0xad, 0x40, 0x0a, 0x50, 0x80, 0x60, 0x20, 0x00, 0x0c, 0x23, 0xc8 }, // 125, 125
+
+    // OOK, No Manchester, Max Rb err <1%, Xtal Tol 20ppm
+    { 0x51, 0x03, 0x68, 0x00, 0x3a, 0x93, 0x01, 0x3d, 0x2c, 0x11, 0x28, 0x80, 0x60, 0x09, 0xd5, 0x2c, 0x21, 0x08 }, // 1.2, 75
+    { 0xc8, 0x03, 0x39, 0x20, 0x68, 0xdc, 0x00, 0x6b, 0x2a, 0x08, 0x2a, 0x80, 0x60, 0x13, 0xa9, 0x2c, 0x21, 0x08 }, // 2.4, 335
+    { 0xc8, 0x03, 0x9c, 0x00, 0xd1, 0xb7, 0x00, 0xd4, 0x29, 0x04, 0x29, 0x80, 0x60, 0x27, 0x52, 0x2c, 0x21, 0x08 }, // 4.8, 335
+    { 0xb8, 0x03, 0x9c, 0x00, 0xd1, 0xb7, 0x00, 0xd4, 0x28, 0x82, 0x29, 0x80, 0x60, 0x4e, 0xa5, 0x2c, 0x21, 0x08 }, // 9.6, 335
+    { 0xa8, 0x03, 0x9c, 0x00, 0xd1, 0xb7, 0x00, 0xd4, 0x28, 0x41, 0x29, 0x80, 0x60, 0x9d, 0x49, 0x2c, 0x21, 0x08 }, // 19.2, 335
+    { 0x98, 0x03, 0x9c, 0x00, 0xd1, 0xb7, 0x00, 0xd4, 0x28, 0x20, 0x29, 0x80, 0x60, 0x09, 0xd5, 0x0c, 0x21, 0x08 }, // 38.4, 335
+    { 0x98, 0x03, 0x96, 0x00, 0xda, 0x74, 0x00, 0xdc, 0x28, 0x1f, 0x29, 0x80, 0x60, 0x0a, 0x3d, 0x0c, 0x21, 0x08 }, // 40, 335
+
+};
+
+RF22::RF22(PinName slaveSelectPin, PinName mosi, PinName miso, PinName sclk, PinName interrupt)
+          : _slaveSelectPin(slaveSelectPin),  _spi(mosi, miso, sclk), _interrupt(interrupt), led1(LED1), led2(LED2), led3(LED3), led4(LED4)
+{
+
+
+    _idleMode = RF22_XTON; // Default idle state is READY mode
+    _mode = RF22_MODE_IDLE; // We start up in idle mode
+    _rxGood = 0;
+    _rxBad = 0;
+    _txGood = 0;
+    
+    
+}
+
+boolean RF22::init()
+{
+    // Wait for RF22 POR (up to 16msec)
+    //delay(16);
+    wait_ms(16);
+
+    // Initialise the slave select pin
+    //pinMode(_slaveSelectPin, OUTPUT);
+    //digitalWrite(_slaveSelectPin, HIGH);
+    _slaveSelectPin = 1;
+    
+    wait_ms(100);
+  
+    // start the SPI library:
+    // Note the RF22 wants mode 0, MSB first and default to 1 Mbps
+    /*SPI.begin();
+    SPI.setDataMode(SPI_MODE0);
+    SPI.setBitOrder(MSBFIRST);
+    SPI.setClockDivider(SPI_CLOCK_DIV16);  // (16 Mhz / 16) = 1 MHz
+    */
+
+    // Setup the spi for 8 bit data : 1RW-bit 7 adressbit and  8 databit
+    // second edge capture, with a 10MHz clock rate
+    _spi.format(8,0);
+    _spi.frequency(10000000);
+
+    // Software reset the device
+    reset();
+
+    // Get the device type and check it
+    // This also tests whether we are really connected to a device
+    _deviceType = spiRead(RF22_REG_00_DEVICE_TYPE);
+    if (   _deviceType != RF22_DEVICE_TYPE_RX_TRX
+        && _deviceType != RF22_DEVICE_TYPE_TX)
+    return false;
+
+    // Set up interrupt handler
+//    if (_interrupt == 0)
+//    {
+    //_RF22ForInterrupt[0] = this;
+    //attachInterrupt(0, RF22::isr0, LOW);  
+    _interrupt.fall(this, &RF22::isr0);
+/*    }
+    else if (_interrupt == 1)
+    {
+    _RF22ForInterrupt[1] = this;
+    attachInterrupt(1, RF22::isr1, LOW);  
+    }
+    else
+    return false;
+*/ 
+    clearTxBuf();
+    clearRxBuf();
+  
+    // Most of these are the POR default
+    spiWrite(RF22_REG_7D_TX_FIFO_CONTROL2, RF22_TXFFAEM_THRESHOLD);
+    spiWrite(RF22_REG_7E_RX_FIFO_CONTROL,  RF22_RXFFAFULL_THRESHOLD);
+    spiWrite(RF22_REG_30_DATA_ACCESS_CONTROL, RF22_ENPACRX | RF22_ENPACTX | RF22_ENCRC | RF22_CRC_CRC_16_IBM);
+    // Configure the message headers
+    // Here we set up the standard packet format for use by the RF22 library
+    // 8 nibbles preamble
+    // 2 SYNC words 2d, d4
+    // Header length 4 (to, from, id, flags)
+    // 1 octet of data length (0 to 255)
+    // 0 to 255 octets data
+    // 2 CRC octets as CRC16(IBM), computed on the header, length and data
+    // On reception the to address is check for validity against RF22_REG_3F_CHECK_HEADER3
+    // or the broadcast address of 0xff
+    // If no changes are made after this, the transmitted
+    // to address will be 0xff, the from address will be 0xff
+    // and all such messages will be accepted. This permits the out-of the box
+    // RF22 config to act as an unaddresed, unreliable datagram service
+    spiWrite(RF22_REG_32_HEADER_CONTROL1, RF22_BCEN_HEADER3 | RF22_HDCH_HEADER3);
+    spiWrite(RF22_REG_33_HEADER_CONTROL2, RF22_HDLEN_4 | RF22_SYNCLEN_2);
+    setPreambleLength(8);
+    uint8_t syncwords[] = { 0x2d, 0xd4 };
+    setSyncWords(syncwords, sizeof(syncwords));
+    setPromiscuous(false); 
+    // Check the TO header against RF22_DEFAULT_NODE_ADDRESS
+    spiWrite(RF22_REG_3F_CHECK_HEADER3, RF22_DEFAULT_NODE_ADDRESS);
+    // Set the default transmit header values
+    setHeaderTo(RF22_DEFAULT_NODE_ADDRESS);
+    setHeaderFrom(RF22_DEFAULT_NODE_ADDRESS);
+    setHeaderId(0);
+    setHeaderFlags(0);
+
+    // Ensure the antenna can be switched automatically according to transmit and receive
+    // This assumes GPIO0(out) is connected to TX_ANT(in) to enable tx antenna during transmit
+    // This assumes GPIO1(out) is connected to RX_ANT(in) to enable rx antenna during receive
+    spiWrite (RF22_REG_0B_GPIO_CONFIGURATION0, 0x12) ; // TX state
+    spiWrite (RF22_REG_0C_GPIO_CONFIGURATION1, 0x15) ; // RX state
+
+    // Enable interrupts
+    spiWrite(RF22_REG_05_INTERRUPT_ENABLE1, RF22_ENTXFFAEM | RF22_ENRXFFAFULL | RF22_ENPKSENT | RF22_ENPKVALID | RF22_ENCRCERROR | RF22_ENFFERR);
+    spiWrite(RF22_REG_06_INTERRUPT_ENABLE2, RF22_ENPREAVAL);
+
+    // Set some defaults. An innocuous ISM frequency
+    setFrequency(868.0);
+//    setFrequency(434.0);
+//    setFrequency(900.0);
+    // Some slow, reliable default speed and modulation
+    setModemConfig(FSK_Rb2_4Fd36);
+//    setModemConfig(FSK_Rb125Fd125);
+    // Minimum power
+    setTxPower(RF22_TXPOW_8DBM);
+//    setTxPower(RF22_TXPOW_17DBM);
+
+    return true;
+}
+
+// C++ level interrupt handler for this instance
+void RF22::handleInterrupt()
+{
+    uint8_t _lastInterruptFlags[2];
+    
+led1 = !led1;
+    
+    // Read the interrupt flags which clears the interrupt
+    spiBurstRead(RF22_REG_03_INTERRUPT_STATUS1, _lastInterruptFlags, 2);
+
+#if 0
+    pc.print("interrupt ");
+    Serial.print(_lastInterruptFlags[0], HEX);
+    Serial.print(" ");
+    Serial.println(_lastInterruptFlags[1], HEX);
+    if (_lastInterruptFlags[0] == 0 && _lastInterruptFlags[1] == 0)
+    Serial.println("FUNNY: no interrupt!");
+#endif
+
+/*
+    // TESTING: fake an RF22_IFFERROR
+    static int counter = 0;
+    if (_lastInterruptFlags[0] & RF22_IPKSENT && counter++ == 10)
+    {
+    _lastInterruptFlags[0] = RF22_IFFERROR;
+    counter = 0;
+    }
+*/
+
+    if (_lastInterruptFlags[0] & RF22_IFFERROR)
+    {
+//    Serial.println("IFFERROR");  
+    resetFifos(); // Clears the interrupt
+    if (_mode == RF22_MODE_TX)
+        restartTransmit();
+    else if (_mode == RF22_MODE_RX)
+        clearRxBuf();
+    }
+    // Caution, any delay here may cause a FF underflow or overflow
+    if (_lastInterruptFlags[0] & RF22_ITXFFAEM)
+    {
+    // See if more data has to be loaded into the Tx FIFO 
+    sendNextFragment();
+//    Serial.println("TXFFAEM");  
+    }
+    if (_lastInterruptFlags[0] & RF22_IRXFFAFULL)
+    {
+    // Caution, any delay here may cause a FF overflow
+    // Read some data from the Rx FIFO
+    readNextFragment();
+//    Serial.println("IRXFFAFULL"); 
+    }
+    if (_lastInterruptFlags[0] & RF22_IEXT)
+    {
+    // This is not enabled by the base code, but users may want to enable it
+    handleExternalInterrupt();
+//    Serial.println("IEXT"); 
+    }
+    if (_lastInterruptFlags[1] & RF22_IWUT)
+    {
+    // This is not enabled by the base code, but users may want to enable it
+    handleWakeupTimerInterrupt();
+//    Serial.println("IWUT"); 
+    }
+    if (_lastInterruptFlags[0] & RF22_IPKSENT)
+    {
+//    Serial.println("PKSENT");   
+    _txGood++; 
+    led4 = !led4;
+    // Transmission does not automatically clear the tx buffer.
+    // Could retransmit if we wanted
+    _txPacketSent = true;
+    // RF22 transitions automatically to Idle
+    _mode = RF22_MODE_IDLE;
+    }
+    if (_lastInterruptFlags[0] & RF22_IPKVALID)
+    {
+//    Serial.println("IPKVALID");    
+    uint8_t len = spiRead(RF22_REG_4B_RECEIVED_PACKET_LENGTH);
+    // May have already read one or more fragments
+    // Get any remaining unread octets, based on the expected length
+    len -= _bufLen;
+    spiBurstRead(RF22_REG_7F_FIFO_ACCESS, _buf + _bufLen, len);
+    _rxGood++;
+    led3 = !led3;
+    _bufLen += len;
+    _mode = RF22_MODE_IDLE;
+    _rxBufValid = true;
+    }
+    if (_lastInterruptFlags[0] & RF22_ICRCERROR)
+    {
+//    Serial.println("ICRCERR");  
+    _rxBad++;
+    led2 = !led2;
+    clearRxBuf();
+    resetRxFifo();
+    _mode = RF22_MODE_IDLE;
+    setModeRx(); // Keep trying
+    }
+    if (_lastInterruptFlags[1] & RF22_ENPREAVAL)
+    {
+//    Serial.println("ENPREAVAL");  
+    _lastRssi = spiRead(RF22_REG_26_RSSI);
+    clearRxBuf();
+    }
+}
+
+// These are low level functions that call the interrupt handler for the correct
+// instance of RF22.
+// 2 interrupts allows us to have 2 different devices
+void RF22::isr0()
+{
+    //if (_RF22ForInterrupt[0])
+    //_RF22ForInterrupt[0]->handleInterrupt();
+    handleInterrupt();
+}
+/*
+void RF22::isr1()
+{
+    if (_RF22ForInterrupt[1])
+    _RF22ForInterrupt[1]->handleInterrupt();
+}
+*/
+void RF22::reset()
+{
+    spiWrite(RF22_REG_07_OPERATING_MODE1, RF22_SWRES);
+    // Wait for it to settle
+    //delay(1); // SWReset time is nominally 100usec
+    wait_ms(1);
+}
+
+uint8_t RF22::spiRead(uint8_t reg)
+{
+    //digitalWrite(_slaveSelectPin, LOW);
+    _slaveSelectPin=0;
+    //_spi.write(reg & ~RF22_SPI_WRITE_MASK); // Send the address with the write mask off
+    _spi.write(reg & ~RF22_SPI_WRITE_MASK); // Send the address with the write mask off
+    uint8_t val = _spi.write(0); // The written value is ignored, reg value is read
+    //digitalWrite(_slaveSelectPin, HIGH);
+    _slaveSelectPin = 1;
+    return val;
+}
+
+void RF22::spiWrite(uint8_t reg, uint8_t val)
+{
+    //digitalWrite(_slaveSelectPin, LOW);
+    _slaveSelectPin = 0;
+    _spi.write(reg | RF22_SPI_WRITE_MASK); // Send the address with the write mask on
+    _spi.write(val); // New value follows
+    //digitalWrite(_slaveSelectPin, HIGH);
+    _slaveSelectPin = 1;
+}
+
+void RF22::spiBurstRead(uint8_t reg, uint8_t* dest, uint8_t len)
+{
+    //digitalWrite(_slaveSelectPin, LOW);
+    _slaveSelectPin = 0;
+    _spi.write(reg & ~RF22_SPI_WRITE_MASK); // Send the start address with the write mask off
+    while (len--)
+    *dest++ = _spi.write(0);
+    //digitalWrite(_slaveSelectPin, HIGH);
+    _slaveSelectPin = 1;
+}
+
+void RF22::spiBurstWrite(uint8_t reg, uint8_t* src, uint8_t len)
+{
+    //digitalWrite(_slaveSelectPin, LOW);
+    _slaveSelectPin = 0;
+    _spi.write(reg | RF22_SPI_WRITE_MASK); // Send the start address with the write mask on
+    while (len--)
+    _spi.write(*src++);
+    //digitalWrite(_slaveSelectPin, HIGH);
+    _slaveSelectPin = 1;
+}
+
+uint8_t RF22::statusRead()
+{
+    return spiRead(RF22_REG_02_DEVICE_STATUS);
+}
+
+uint8_t RF22::adcRead(uint8_t adcsel,
+                      uint8_t adcref ,
+                      uint8_t adcgain, 
+                      uint8_t adcoffs)
+{
+    uint8_t configuration = adcsel | adcref | (adcgain & RF22_ADCGAIN);
+    spiWrite(RF22_REG_0F_ADC_CONFIGURATION, configuration | RF22_ADCSTART);
+    spiWrite(RF22_REG_10_ADC_SENSOR_AMP_OFFSET, adcoffs);
+
+    // Conversion time is nominally 305usec
+    // Wait for the DONE bit
+    while (!(spiRead(RF22_REG_0F_ADC_CONFIGURATION) & RF22_ADCDONE))
+    ;
+    // Return the value  
+    return spiRead(RF22_REG_11_ADC_VALUE);
+}
+
+uint8_t RF22::temperatureRead(uint8_t tsrange, uint8_t tvoffs)
+{
+    spiWrite(RF22_REG_12_TEMPERATURE_SENSOR_CALIBRATION, tsrange | RF22_ENTSOFFS);
+    spiWrite(RF22_REG_13_TEMPERATURE_VALUE_OFFSET, tvoffs);
+    return adcRead(RF22_ADCSEL_INTERNAL_TEMPERATURE_SENSOR | RF22_ADCREF_BANDGAP_VOLTAGE); 
+}
+
+uint16_t RF22::wutRead()
+{
+    uint8_t buf[2];
+    spiBurstRead(RF22_REG_17_WAKEUP_TIMER_VALUE1, buf, 2);
+    return ((uint16_t)buf[0] << 8) | buf[1]; // Dont rely on byte order
+}
+
+// RFM-22 doc appears to be wrong: WUT for wtm = 10000, r, = 0, d = 0 is about 1 sec
+void RF22::setWutPeriod(uint16_t wtm, uint8_t wtr, uint8_t wtd)
+{
+    uint8_t period[3];
+
+    period[0] = ((wtr & 0xf) << 2) | (wtd & 0x3);
+    period[1] = wtm >> 8;
+    period[2] = wtm & 0xff;
+    spiBurstWrite(RF22_REG_14_WAKEUP_TIMER_PERIOD1, period, sizeof(period));
+}
+
+// Returns true if centre + (fhch * fhs) is within limits
+// Caution, different versions of the RF22 suport different max freq
+// so YMMV
+boolean RF22::setFrequency(float centre)
+{
+    uint8_t fbsel = RF22_SBSEL;
+    if (centre < 240.0 || centre > 960.0) // 930.0 for early silicon
+    return false;
+    if (centre >= 480.0)
+    {
+    centre /= 2;
+    fbsel |= RF22_HBSEL;
+    }
+    centre /= 10.0;
+    float integerPart = floor(centre);
+    float fractionalPart = centre - integerPart;
+
+    uint8_t fb = (uint8_t)integerPart - 24; // Range 0 to 23
+    fbsel |= fb;
+    uint16_t fc = fractionalPart * 64000;
+    spiWrite(RF22_REG_73_FREQUENCY_OFFSET1, 0);  // REVISIT
+    spiWrite(RF22_REG_74_FREQUENCY_OFFSET2, 0);
+    spiWrite(RF22_REG_75_FREQUENCY_BAND_SELECT, fbsel);
+    spiWrite(RF22_REG_76_NOMINAL_CARRIER_FREQUENCY1, fc >> 8);
+    spiWrite(RF22_REG_77_NOMINAL_CARRIER_FREQUENCY0, fc & 0xff);
+    return !(statusRead() & RF22_FREQERR);
+}
+
+// Step size in 10kHz increments
+// Returns true if centre + (fhch * fhs) is within limits
+boolean RF22::setFHStepSize(uint8_t fhs)
+{
+    spiWrite(RF22_REG_7A_FREQUENCY_HOPPING_STEP_SIZE, fhs);
+    return !(statusRead() & RF22_FREQERR);
+}
+
+// Adds fhch * fhs to centre frequency
+// Returns true if centre + (fhch * fhs) is within limits
+boolean RF22::setFHChannel(uint8_t fhch)
+{
+    spiWrite(RF22_REG_79_FREQUENCY_HOPPING_CHANNEL_SELECT, fhch);
+    return !(statusRead() & RF22_FREQERR);
+}
+
+uint8_t RF22::rssiRead()
+{
+    return spiRead(RF22_REG_26_RSSI);
+}
+
+uint8_t RF22::ezmacStatusRead()
+{
+    return spiRead(RF22_REG_31_EZMAC_STATUS);
+}
+
+void RF22::setMode(uint8_t mode)
+{
+    spiWrite(RF22_REG_07_OPERATING_MODE1, mode);
+}
+
+void RF22::setModeIdle()
+{
+    if (_mode != RF22_MODE_IDLE)
+    {
+    setMode(_idleMode);
+    _mode = RF22_MODE_IDLE;
+    }
+}
+
+void RF22::setModeRx()
+{
+    if (_mode != RF22_MODE_RX)
+    {
+    setMode(_idleMode | RF22_RXON);
+    _mode = RF22_MODE_RX;
+    }
+}
+
+void RF22::setModeTx()
+{
+    if (_mode != RF22_MODE_TX)
+    {
+    setMode(_idleMode | RF22_TXON);
+    _mode = RF22_MODE_TX;
+    }
+}
+
+void RF22::setTxPower(uint8_t power)
+{
+    spiWrite(RF22_REG_6D_TX_POWER, power);
+}
+
+// Sets registers from a canned modem configuration structure
+void RF22::setModemRegisters(ModemConfig* config)
+{
+    spiWrite(RF22_REG_1C_IF_FILTER_BANDWIDTH,                    config->reg_1c);
+    spiWrite(RF22_REG_1F_CLOCK_RECOVERY_GEARSHIFT_OVERRIDE,      config->reg_1f);
+    spiBurstWrite(RF22_REG_20_CLOCK_RECOVERY_OVERSAMPLING_RATE, &config->reg_20, 6);
+    spiBurstWrite(RF22_REG_2C_OOK_COUNTER_VALUE_1,              &config->reg_2c, 3);
+    spiWrite(RF22_REG_58_CHARGE_PUMP_CURRENT_TRIMMING,           config->reg_58);
+    spiWrite(RF22_REG_69_AGC_OVERRIDE1,                          config->reg_69);
+    spiBurstWrite(RF22_REG_6E_TX_DATA_RATE1,                    &config->reg_6e, 5);
+}
+
+// Set one of the canned FSK Modem configs
+// Returns true if its a valid choice
+boolean RF22::setModemConfig(ModemConfigChoice index)
+{
+    if (index > (sizeof(MODEM_CONFIG_TABLE) / sizeof(ModemConfig)))
+        return false;
+
+    RF22::ModemConfig cfg;
+    memcpy(&cfg, &MODEM_CONFIG_TABLE[index], sizeof(RF22::ModemConfig));
+    setModemRegisters(&cfg);
+
+    return true;
+}
+
+// REVISIT: top bit is in Header Control 2 0x33
+void RF22::setPreambleLength(uint8_t nibbles)
+{
+    spiWrite(RF22_REG_34_PREAMBLE_LENGTH, nibbles);
+}
+
+// Caution doesnt set sync word len in Header Control 2 0x33
+void RF22::setSyncWords(uint8_t* syncWords, uint8_t len)
+{
+    spiBurstWrite(RF22_REG_36_SYNC_WORD3, syncWords, len);
+}
+
+void RF22::clearRxBuf()
+{
+    _bufLen = 0;
+    _rxBufValid = false;
+}
+
+boolean RF22::available()
+{
+    setModeRx();
+    return _rxBufValid;
+}
+
+// Blocks until a valid message is received
+void RF22::waitAvailable()
+{
+    while (!available())
+    ;
+}
+
+// Blocks until a valid message is received or timeout expires
+// Return true if there is a message available
+bool RF22::waitAvailableTimeout(uint16_t timeout)
+{
+    Timer t;
+    t.start();
+    unsigned long endtime = t.read_ms() + timeout;
+    while (t.read_ms() < endtime)
+    if (available())
+        return true;
+    return false;
+}
+
+void RF22::waitPacketSent()
+{
+    while (!_txPacketSent)
+    ;
+}
+
+boolean RF22::recv(uint8_t* buf, uint8_t* len)
+{
+    if (!available())
+    return false;
+    if (*len > _bufLen)
+    *len = _bufLen;
+    memcpy(buf, _buf, *len);
+    clearRxBuf();
+    return true;
+}
+
+void RF22::clearTxBuf()
+{
+    _bufLen = 0;
+    _txBufSentIndex = 0;
+    _txPacketSent = false;
+}
+
+void RF22::startTransmit()
+{
+    sendNextFragment(); // Actually the first fragment
+    spiWrite(RF22_REG_3E_PACKET_LENGTH, _bufLen); // Total length that will be sent
+    setModeTx(); // Start the transmitter, turns off the receiver
+}
+
+// Restart the trasnmission of a packet that had a problem
+void RF22::restartTransmit()
+{
+    _mode = RF22_MODE_IDLE;
+    _txBufSentIndex = 0;
+    _txPacketSent = false;
+//        Serial.println("Restart");
+    startTransmit();
+}
+
+boolean RF22::send(uint8_t* data, uint8_t len)
+{
+    setModeIdle();
+    fillTxBuf(data, len);
+    startTransmit();
+    return true;
+}
+
+boolean RF22::fillTxBuf(uint8_t* data, uint8_t len)
+{
+    clearTxBuf();
+    return appendTxBuf(data, len);
+}
+
+boolean RF22::appendTxBuf(uint8_t* data, uint8_t len)
+{
+    if (((uint16_t)_bufLen + len) > RF22_MAX_MESSAGE_LEN)
+    return false;
+    memcpy(_buf + _bufLen, data, len);
+    _bufLen += len;
+    return true;
+}
+
+// Assumption: there is currently <= RF22_TXFFAEM_THRESHOLD bytes in the Tx FIFO
+void RF22::sendNextFragment()
+{
+    if (_txBufSentIndex < _bufLen)
+    {
+    // Some left to send
+    uint8_t len = _bufLen - _txBufSentIndex;
+    // But dont send too much
+    if (len > (RF22_FIFO_SIZE - RF22_TXFFAEM_THRESHOLD - 1))
+        len = (RF22_FIFO_SIZE - RF22_TXFFAEM_THRESHOLD - 1);
+    spiBurstWrite(RF22_REG_7F_FIFO_ACCESS, _buf + _txBufSentIndex, len);
+    _txBufSentIndex += len;
+    }
+}
+
+// Assumption: there are at least RF22_RXFFAFULL_THRESHOLD in the RX FIFO
+// That means it should only be called after a RXAFULL interrupt
+void RF22::readNextFragment()
+{
+    if (((uint16_t)_bufLen + RF22_RXFFAFULL_THRESHOLD) > RF22_MAX_MESSAGE_LEN)
+    {
+    // Hmmm receiver overflow. Should never occur
+    return;
+    }
+    // Read the RF22_RXFFAFULL_THRESHOLD octets that should be there
+    spiBurstRead(RF22_REG_7F_FIFO_ACCESS, _buf + _bufLen, RF22_RXFFAFULL_THRESHOLD);
+    _bufLen += RF22_RXFFAFULL_THRESHOLD;
+}
+
+// Clear the FIFOs
+void RF22::resetFifos()
+{
+    spiWrite(RF22_REG_08_OPERATING_MODE2, RF22_FFCLRRX | RF22_FFCLRTX);
+    spiWrite(RF22_REG_08_OPERATING_MODE2, 0);
+}
+
+// Clear the Rx FIFO
+void RF22::resetRxFifo()
+{
+    spiWrite(RF22_REG_08_OPERATING_MODE2, RF22_FFCLRRX);
+    spiWrite(RF22_REG_08_OPERATING_MODE2, 0);
+}
+
+// CLear the TX FIFO
+void RF22::resetTxFifo()
+{
+    spiWrite(RF22_REG_08_OPERATING_MODE2, RF22_FFCLRTX);
+    spiWrite(RF22_REG_08_OPERATING_MODE2, 0);
+}
+
+// Default implmentation does nothing. Override if you wish
+void RF22::handleExternalInterrupt()
+{
+}
+
+// Default implmentation does nothing. Override if you wish
+void RF22::handleWakeupTimerInterrupt()
+{
+}
+
+void RF22::setHeaderTo(uint8_t to)
+{
+    spiWrite(RF22_REG_3A_TRANSMIT_HEADER3, to);
+}
+
+void RF22::setHeaderFrom(uint8_t from)
+{
+    spiWrite(RF22_REG_3B_TRANSMIT_HEADER2, from);
+}
+
+void RF22::setHeaderId(uint8_t id)
+{
+    spiWrite(RF22_REG_3C_TRANSMIT_HEADER1, id);
+}
+
+void RF22::setHeaderFlags(uint8_t flags)
+{
+    spiWrite(RF22_REG_3D_TRANSMIT_HEADER0, flags);
+}
+
+uint8_t RF22::headerTo()
+{
+    return spiRead(RF22_REG_47_RECEIVED_HEADER3);
+}
+
+uint8_t RF22::headerFrom()
+{
+    return spiRead(RF22_REG_48_RECEIVED_HEADER2);
+}
+
+uint8_t RF22::headerId()
+{
+    return spiRead(RF22_REG_49_RECEIVED_HEADER1);
+}
+
+uint8_t RF22::headerFlags()
+{
+    return spiRead(RF22_REG_4A_RECEIVED_HEADER0);
+}
+
+uint8_t RF22::lastRssi()
+{
+    return _lastRssi;
+}
+
+void RF22::setPromiscuous(boolean promiscuous)
+{
+    spiWrite(RF22_REG_43_HEADER_ENABLE3, promiscuous ? 0x00 : 0xff);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RF22.h	Tue Feb 14 19:39:36 2012 +0000
@@ -0,0 +1,1024 @@
+// RF22.h
+// Author: Mike McCauley (mikem@open.com.au)
+// Copyright (C) 2011 Mike McCauley
+// $Id: RF22.h,v 1.19 2011/10/09 21:22:24 mikem Exp mikem $
+// ported to mbed by Karl Zweimueller
+//
+/// \mainpage RF22 library for Arduino
+///
+/// This is the Arduino RF22 library.
+/// It provides an object-oriented interface for sending and receiving data messages with Hope-RF
+/// RF22B based radio modules, and compatible chips and modules, including the RFM22B transceiver module such as 
+/// this one: http://www.sparkfun.com/products/10153
+///
+/// RF22 also supports some of the features of ZigBee and XBee, 
+/// (such as mesh routing and automatic route discovery), 
+/// but with a much less complicated system and less expensive radios.
+///
+/// The Hope-RF (http://www.hoperf.com) RFM22B (http://www.hoperf.com/rf_fsk/fsk/RFM22B.htm) 
+/// is a low-cost ISM transceiver module. It supports FSK, GFSK, OOK over a wide 
+/// range of frequencies and programmable data rates.
+///
+/// This library provides functions for sending and receiving messages of up to 255 octets on any 
+/// frequency supported by the RF22B, in a range of predefined data rates and frequency deviations. 
+/// Frequency can be set with 312Hz precision to any frequency from 240.0MHz to 960.0MHz.
+///
+/// Up to 2 RF22B modules can be connected to an Arduino, permitting the construction of translators
+/// and frequency changers, etc.
+///
+/// This library provides classes for 
+/// - RF22: unaddressed, unreliable messages
+/// - RF22Datagram: addressed, unreliable messages
+/// - RF22ReliableDatagram: addressed, reliable, retransmitted, acknowledged messages.
+/// - RF22Router: multi hop delivery from source node to destination node via 0 or more intermediate nodes
+/// - RF22Mesh: multi hop delivery with automatic route discovery and rediscovery.
+///
+/// The following modulation types are suppported with a range of modem configurations for 
+/// common data rates and frequency deviations:
+/// - GFSK Gaussian Frequency Shift Keying
+/// - FSK Frequency Shift Keying
+/// - OOK On-Off Keying
+///
+/// Support for other RF22B features such as on-chip temperature measurement, analog-digital 
+/// converter, transmitter power control etc is also provided.
+///
+/// The latest version of this documentation can be downloaded from 
+/// http://www.open.com.au/mikem/arduino/RF22
+///
+/// Example Arduino programs are included to show the main modes of use.
+///
+/// The version of the package that this documentation refers to can be downloaded 
+/// from http://www.open.com.au/mikem/arduino/RF22/RF22-1.10.zip
+/// You can find the latest version at http://www.open.com.au/mikem/arduino/RF22
+///
+/// Tested on Arduino Diecimila and Mega with arduino-0021 
+/// on OpenSuSE 11.1 and avr-libc-1.6.1-1.15,
+/// cross-avr-binutils-2.19-9.1, cross-avr-gcc-4.1.3_20080612-26.5.
+/// With HopeRF RFM22 modules that appear to have RF22B chips on board:
+///    - Device Type Code = 0x08 (RX/TRX)
+///    - Version Code = 0x06
+/// It is known not to work on Diecimila. Dont bother trying.
+///
+/// \par Packet Format
+///
+/// All messages sent and received by this RF22 library must conform to this packet format:
+///
+/// - 8 nibbles (4 octets) PREAMBLE
+/// - 2 octets SYNC 0x2d, 0xd4
+/// - 4 octets HEADER: (TO, FROM, ID, FLAGS)
+/// - 1 octet LENGTH (0 to 255), number of octets in DATA
+/// - 0 to 255 octets DATA
+/// - 2 octets CRC computed with CRC16(IBM), computed on HEADER, LENGTH and DATA
+///
+/// For technical reasons, the message format is not compatible with the 
+/// 'HopeRF Radio Transceiver Message Library for Arduino' http://www.open.com.au/mikem/arduino/HopeRF from the same author. Nor is it compatible with 
+/// 'Virtual Wire' http://www.open.com.au/mikem/arduino/VirtualWire.pdf also from the same author.
+///
+/// \par Connecting RFM-22 to Arduino
+/// The physical connection between the RF22B and the Arduino require 3.3V, the 3 x SPI pins (SCK, SDI, SDO), 
+/// a Slave Select pin and an interrupt pin.
+/// Note also that on the RFF22B, it is required to control the TX_ANT and X_ANT pins of the RFM22 in order to enable the
+/// antenna connection. The RF22 library is configured so that GPIO0 and GPIO1 outputs can control TX_ANT and RX_ANT input pins
+/// automatically. You must connect GPIO0 to TX_ANT and GPIO1 to RX_ANT for this automatic antenna switching to occur.
+///
+/// Connect the RFM-22 to most Arduino's like this (Caution, Arduino Mega has different pins for SPI, 
+/// see below):
+/// \code
+///                 Arduino      RFM-22B
+///                 GND----------GND-\ (ground in)
+///                              SDN-/ (shutdown in)
+///                 3V3----------VCC   (3.3V in)
+/// interrupt 0 pin D2-----------NIRQ  (interrupt request out)
+///          SS pin D10----------NSEL  (chip select in)
+///         SCK pin D13----------SCK   (SPI clock in)
+///        MOSI pin D11----------SDI   (SPI Data in)
+///        MISO pin D12----------SDO   (SPI data out)
+///                           /--GPIO0 (GPIO0 out to control transmitter antenna TX_ANT
+///                           \--TX_ANT (TX antenna control in)
+///                           /--GPIO1 (GPIO1 out to control receiver antenna RX_ANT
+///                           \--RX_ANT (RX antenna control in)
+/// \endcode
+/// For an Arduino Mega:
+/// \code
+///                 Mega         RFM-22B
+///                 GND----------GND-\ (ground in)
+///                              SDN-/ (shutdown in)
+///                 3V3----------VCC   (3.3V in)
+/// interrupt 0 pin D2-----------NIRQ  (interrupt request out)
+///          SS pin D10----------NSEL  (chip select in)
+///         SCK pin D52----------SCK   (SPI clock in)
+///        MOSI pin D51----------SDI   (SPI Data in)
+///        MISO pin D50----------SDO   (SPI data out)
+///                           /--GPIO0 (GPIO0 out to control transmitter antenna TX_ANT
+///                           \--TX_ANT (TX antenna control in)
+///                           /--GPIO1 (GPIO1 out to control receiver antenna RX_ANT
+///                           \--RX_ANT (RX antenna control in)
+/// \endcode
+/// and you can then use the default constructor RF22(). 
+/// You can override the default settings for the SS pin and the interrupt 
+/// in the RF22 constructor if you wish to connect the slave select SS to other than pin D10 
+/// or the interrupt request to other than pin D2.
+/// It is possible to have 2 radios conected to one arduino, provided each radio has its own 
+/// SS and interrupt line (SCK, SDI and SDO are common to both radios)
+///
+/// \par Example programs
+///
+/// The following example programs are provided:
+/// - rf22_client, rf22_server: Simple client/server pair using RF22 class
+/// - rf22_datagram_client, rf22_datagram_server: Simple client/server pair using RF22Datagram class
+/// - rf22_reliable_datagram_client, rf22_reliable_datagram_server:
+///   Simple client/server pair using RF22ReliableDatagram class
+/// - rf22_router_client, rf22_router_server1, rf22_router_server2, rf22_router_server3: 
+///   Simple RF22Router network. Requires Arduino Mega.
+/// - rf22_mesh_client, rf22_mesh_server1, rf22_mesh_server2, rf22_mesh_server3: 
+///   Simple RF22Mesh network. Requires Arduino Mega.
+/// - rf22_test: Some test code used during development, shows how to call some support functions
+/// - rf22_snoop: Dumps in ASCII the contents of all RF22 messages received
+/// - rf22_specan: Simple spectrum analyser using the RSSI measurements of the RF22
+///   (see <a href="specan1.png">Sample output</a> showing a plot from 395.0MHz to 396.0MHz of a 
+///   signal generator at 395.5MHz amplitude modulated at 100% 1kHz)
+///
+/// \par Memory
+///
+/// The RF22 library requires non-trivial amounts of memory. The sample programs above all compile to 
+/// about 9 to 14kbytes each, which will fit in the flash proram memory of most Arduinos. However, 
+/// the RAM requirements are more critical. Most sample programs above will run on Duemilanova, 
+/// but not on Diecimila. Even on Duemilanova, the RAM requirements are very close to the 
+/// available memory of 2kbytes. Therefore, you should be vary sparing with RAM use in programs that use 
+/// the RF22 library on Duemilanova.
+///
+/// The sample RF22Router and RF22Mesh programs compile to about 14kbytes, 
+/// and require more RAM than the others. 
+/// They will not run on Duemilanova or Diecimila, but will run on Arduino Mega.
+///
+/// It is often hard to accurately identify when you are hitting RAM limits on Arduino. 
+/// The symptoms can include:
+/// - Mysterious crashes and restarts
+/// - Changes in behaviour when seemingly unrelated changes are made (such as adding print() statements)
+/// - Hanging
+/// - Output from Serial.print() not appearing
+/// 
+/// With an Arduino Mega, with 8 kbytes of SRAM, there is much more RAM headroom for 
+/// your own elaborate programs. 
+/// This library is reported not to work with Arduino Pro Mini and Arduino UNO, but these have not been tested here.
+///
+/// \par Installation
+///
+/// Install in the usual way: unzip the distribution zip file to the libraries
+/// sub-folder of your sketchbook. 
+///
+/// This software is Copyright (C) 2011 Mike McCauley. Use is subject to license
+/// conditions. The main licensing options available are GPL V2 or Commercial:
+/// 
+/// \par Open Source Licensing GPL V2
+///
+/// This is the appropriate option if you want to share the source code of your
+/// application with everyone you distribute it to, and you also want to give them
+/// the right to share who uses it. If you wish to use this software under Open
+/// Source Licensing, you must contribute all your source code to the open source
+/// community in accordance with the GPL Version 2 when your application is
+/// distributed. See http://www.gnu.org/copyleft/gpl.html
+/// 
+/// \par Commercial Licensing
+///
+/// This is the appropriate option if you are creating proprietary applications
+/// and you are not prepared to distribute and share the source code of your
+/// application. Contact info@open.com.au for details.
+///
+/// \par Revision History
+///
+/// \version 1.0 Initial release
+///
+/// \version 1.1 Added rf22_snoop and rf22_specan examples
+///
+/// \version 1.2 Changed default modulation to FSK_Rb2_4Fd36
+///              Some internal reorganisation.
+///              Added RF22Router and RF22Mesh classes plus sample programs to support multi-hop and 
+///              automatic route discovery.
+/// \version 1.3 Removed some unnecessary debug messages. Added virtual doArp and isPhysicalAddress
+///              functions to RF22Mesh to support other physical address interpretation schemes (IPV4/IPV6?)
+/// \version 1.4 RF22Router and RF22Mesh were inadvertently left out of the distro.
+/// \version 1.5 Improvements contributed by Peter Mousley: Modem config table is now in flash rather than SRAM, 
+///              saving 400 bytes of SRAM. Allow a user-defined buffer size. Thanks Peter.
+/// \version 1.6 Fixed some minor typos on doc and clarified that this code is for the RF22B. Fixed errors in the 
+///              definition of the power output constants which were incorrectly set to the values for the RF22.
+///              Reported by Fred Slamen. If you were using a previous version of RF22, you probably were not getting the output
+///              power you thought.
+/// \version 1.7 Added code to initialise GPIO0 and GPIO1 so they can automatically control the TX_ANT and RX_ANT
+///              antenna switching inputs. You must connect GPIO0 to TX_ANT and GPIO1 to RX_ANT for this automatic 
+///              antenna switching to occur. Updated doc to reflect this new connection requirement
+/// \version 1.8 Changed the name of RF22_ENLBD in RF22_REG_06_INTERRUPT_ENABLE2 to RF22_ENLBDI because it collided
+///              with a define of the same name in RF22_REG_07_OPERATING_MODE. RF22_REG_05_INTERRUPT_ENABLE1 enable mask
+///              incorrectly used RF22_IFFERROR instead of RF22_ENFFERR. Reported by Steffan Woltjer.
+/// \version 1.9 Fixed typos in RF22_REG_21_CLOCk*. Reported by Steffan Woltjer.
+/// \version 1.10 Fixed a problem where a IFFERR during transmission could cause an infinite loop and a hang. 
+///              Reported by Raymond Gilbert.
+///
+///
+/// \author  Mike McCauley (mikem@open.com.au)
+
+#ifndef RF22_h
+#define RF22_h
+#include "mbed.h"
+
+#define boolean bool
+
+//#include <wiring.h>
+// These defs cause trouble on some versions of Arduino
+#undef round
+#undef double
+
+// This is the bit in the SPI address that marks it as a write
+#define RF22_SPI_WRITE_MASK 0x80
+
+// This is the maximum message length that can be supported by this library. Limited by
+// the message length octet in the header. Yes, 255 is correct even though the FIFO size in the RF22 is only
+// 64 octets. We use interrupts to refil the Tx FIFO during transmission and to empty the
+// Rx FIF during reception
+// Can be pre-defined to a smaller size (to save SRAM) prior to including this header
+#ifndef RF22_MAX_MESSAGE_LEN
+#define RF22_MAX_MESSAGE_LEN 255
+#endif
+
+// Max number of octets the RF22 Rx and Tx FIFOs can hold
+#define RF22_FIFO_SIZE 64
+
+// Keep track of the mode the RF22 is in
+#define RF22_MODE_IDLE         0
+#define RF22_MODE_RX           1
+#define RF22_MODE_TX           2
+
+// These values we set for FIFO thresholds are actually the same as the POR values
+#define RF22_TXFFAEM_THRESHOLD 4
+#define RF22_RXFFAFULL_THRESHOLD 55
+
+// This is the default node address,
+#define RF22_DEFAULT_NODE_ADDRESS 0
+
+// This address in the TO addreess signifies a broadcast
+#define RF22_BROADCAST_ADDRESS 0xff
+
+// Number of registers to be passed to setModemConfig()
+#define RF22_NUM_MODEM_CONFIG_REGS 18
+
+// Register names
+#define RF22_REG_00_DEVICE_TYPE                         0x00
+#define RF22_REG_01_VERSION_CODE                        0x01
+#define RF22_REG_02_DEVICE_STATUS                       0x02
+#define RF22_REG_03_INTERRUPT_STATUS1                   0x03
+#define RF22_REG_04_INTERRUPT_STATUS2                   0x04
+#define RF22_REG_05_INTERRUPT_ENABLE1                   0x05
+#define RF22_REG_06_INTERRUPT_ENABLE2                   0x06
+#define RF22_REG_07_OPERATING_MODE1                     0x07
+#define RF22_REG_08_OPERATING_MODE2                     0x08
+#define RF22_REG_09_OSCILLATOR_LOAD_CAPACITANCE         0x09
+#define RF22_REG_0A_UC_OUTPUT_CLOCK                     0x0a
+#define RF22_REG_0B_GPIO_CONFIGURATION0                 0x0b
+#define RF22_REG_0C_GPIO_CONFIGURATION1                 0x0c
+#define RF22_REG_0D_GPIO_CONFIGURATION2                 0x0d
+#define RF22_REG_0E_IO_PORT_CONFIGURATION               0x0e
+#define RF22_REG_0F_ADC_CONFIGURATION                   0x0f
+#define RF22_REG_10_ADC_SENSOR_AMP_OFFSET               0x10
+#define RF22_REG_11_ADC_VALUE                           0x11
+#define RF22_REG_12_TEMPERATURE_SENSOR_CALIBRATION      0x12
+#define RF22_REG_13_TEMPERATURE_VALUE_OFFSET            0x13
+#define RF22_REG_14_WAKEUP_TIMER_PERIOD1                0x14
+#define RF22_REG_15_WAKEUP_TIMER_PERIOD2                0x15
+#define RF22_REG_16_WAKEUP_TIMER_PERIOD3                0x16
+#define RF22_REG_17_WAKEUP_TIMER_VALUE1                 0x17
+#define RF22_REG_18_WAKEUP_TIMER_VALUE2                 0x18
+#define RF22_REG_19_LDC_MODE_DURATION                   0x19
+#define RF22_REG_1A_LOW_BATTERY_DETECTOR_THRESHOLD      0x1a
+#define RF22_REG_1B_BATTERY_VOLTAGE_LEVEL               0x1b
+#define RF22_REG_1C_IF_FILTER_BANDWIDTH                 0x1c
+#define RF22_REG_1D_AFC_LOOP_GEARSHIFT_OVERRIDE         0x1d
+#define RF22_REG_1E_AFC_TIMING_CONTROL                  0x1e
+#define RF22_REG_1F_CLOCK_RECOVERY_GEARSHIFT_OVERRIDE   0x1f
+#define RF22_REG_20_CLOCK_RECOVERY_OVERSAMPLING_RATE    0x20
+#define RF22_REG_21_CLOCK_RECOVERY_OFFSET2              0x21
+#define RF22_REG_22_CLOCK_RECOVERY_OFFSET1              0x22
+#define RF22_REG_23_CLOCK_RECOVERY_OFFSET0              0x23
+#define RF22_REG_24_CLOCK_RECOVERY_TIMING_LOOP_GAIN1    0x24
+#define RF22_REG_25_CLOCK_RECOVERY_TIMING_LOOP_GAIN0    0x25
+#define RF22_REG_26_RSSI                                0x26
+#define RF22_REG_27_RSSI_THRESHOLD                      0x27
+#define RF22_REG_28_ANTENNA_DIVERSITY1                  0x28
+#define RF22_REG_29_ANTENNA_DIVERSITY2                  0x29
+#define RF22_REG_2A_AFC_LIMITER                         0x2a
+#define RF22_REG_2B_AFC_CORRECTION_READ                 0x2b
+#define RF22_REG_2C_OOK_COUNTER_VALUE_1                 0x2c
+#define RF22_REG_2D_OOK_COUNTER_VALUE_2                 0x2d
+#define RF22_REG_2E_SLICER_PEAK_HOLD                    0x2e
+#define RF22_REG_30_DATA_ACCESS_CONTROL                 0x30
+#define RF22_REG_31_EZMAC_STATUS                        0x31
+#define RF22_REG_32_HEADER_CONTROL1                     0x32
+#define RF22_REG_33_HEADER_CONTROL2                     0x33
+#define RF22_REG_34_PREAMBLE_LENGTH                     0x34
+#define RF22_REG_35_PREAMBLE_DETECTION_CONTROL1         0x35
+#define RF22_REG_36_SYNC_WORD3                          0x36
+#define RF22_REG_37_SYNC_WORD2                          0x37
+#define RF22_REG_38_SYNC_WORD1                          0x38
+#define RF22_REG_39_SYNC_WORD0                          0x39
+#define RF22_REG_3A_TRANSMIT_HEADER3                    0x3a
+#define RF22_REG_3B_TRANSMIT_HEADER2                    0x3b
+#define RF22_REG_3C_TRANSMIT_HEADER1                    0x3c
+#define RF22_REG_3D_TRANSMIT_HEADER0                    0x3d
+#define RF22_REG_3E_PACKET_LENGTH                       0x3e
+#define RF22_REG_3F_CHECK_HEADER3                       0x3f
+#define RF22_REG_40_CHECK_HEADER2                       0x40
+#define RF22_REG_41_CHECK_HEADER1                       0x41
+#define RF22_REG_42_CHECK_HEADER0                       0x42
+#define RF22_REG_43_HEADER_ENABLE3                      0x43
+#define RF22_REG_44_HEADER_ENABLE2                      0x44
+#define RF22_REG_45_HEADER_ENABLE1                      0x45
+#define RF22_REG_46_HEADER_ENABLE0                      0x46
+#define RF22_REG_47_RECEIVED_HEADER3                    0x47
+#define RF22_REG_48_RECEIVED_HEADER2                    0x48
+#define RF22_REG_49_RECEIVED_HEADER1                    0x49
+#define RF22_REG_4A_RECEIVED_HEADER0                    0x4a
+#define RF22_REG_4B_RECEIVED_PACKET_LENGTH              0x4b
+#define RF22_REG_50_ANALOG_TEST_BUS_SELECT              0x50
+#define RF22_REG_51_DIGITAL_TEST_BUS_SELECT             0x51
+#define RF22_REG_52_TX_RAMP_CONTROL                     0x52
+#define RF22_REG_53_PLL_TUNE_TIME                       0x53
+#define RF22_REG_55_CALIBRATION_CONTROL                 0x55
+#define RF22_REG_56_MODEM_TEST                          0x56
+#define RF22_REG_57_CHARGE_PUMP_TEST                    0x57
+#define RF22_REG_58_CHARGE_PUMP_CURRENT_TRIMMING        0x58
+#define RF22_REG_59_DIVIDER_CURRENT_TRIMMING            0x59
+#define RF22_REG_5A_VCO_CURRENT_TRIMMING                0x5a
+#define RF22_REG_5B_VCO_CALIBRATION                     0x5b
+#define RF22_REG_5C_SYNTHESIZER_TEST                    0x5c
+#define RF22_REG_5D_BLOCK_ENABLE_OVERRIDE1              0x5d
+#define RF22_REG_5E_BLOCK_ENABLE_OVERRIDE2              0x5e
+#define RF22_REG_5F_BLOCK_ENABLE_OVERRIDE3              0x5f
+#define RF22_REG_60_CHANNEL_FILTER_COEFFICIENT_ADDRESS  0x60
+#define RF22_REG_61_CHANNEL_FILTER_COEFFICIENT_VALUE    0x61
+#define RF22_REG_62_CRYSTAL_OSCILLATOR_POR_CONTROL      0x62
+#define RF22_REG_63_RC_OSCILLATOR_COARSE_CALIBRATION    0x63
+#define RF22_REG_64_RC_OSCILLATOR_FINE_CALIBRATION      0x64
+#define RF22_REG_65_LDO_CONTROL_OVERRIDE                0x65
+#define RF22_REG_66_LDO_LEVEL_SETTINGS                  0x66
+#define RF22_REG_67_DELTA_SIGMA_ADC_TUNING1             0x67
+#define RF22_REG_68_DELTA_SIGMA_ADC_TUNING2             0x68
+#define RF22_REG_69_AGC_OVERRIDE1                       0x69
+#define RF22_REG_6A_AGC_OVERRIDE2                       0x6a
+#define RF22_REG_6B_GFSK_FIR_FILTER_COEFFICIENT_ADDRESS 0x6b
+#define RF22_REG_6C_GFSK_FIR_FILTER_COEFFICIENT_VALUE   0x6c
+#define RF22_REG_6D_TX_POWER                            0x6d
+#define RF22_REG_6E_TX_DATA_RATE1                       0x6e
+#define RF22_REG_6F_TX_DATA_RATE0                       0x6f
+#define RF22_REG_70_MODULATION_CONTROL1                 0x70
+#define RF22_REG_71_MODULATION_CONTROL2                 0x71
+#define RF22_REG_72_FREQUENCY_DEVIATION                 0x72
+#define RF22_REG_73_FREQUENCY_OFFSET1                   0x73
+#define RF22_REG_74_FREQUENCY_OFFSET2                   0x74
+#define RF22_REG_75_FREQUENCY_BAND_SELECT               0x75
+#define RF22_REG_76_NOMINAL_CARRIER_FREQUENCY1          0x76
+#define RF22_REG_77_NOMINAL_CARRIER_FREQUENCY0          0x77
+#define RF22_REG_79_FREQUENCY_HOPPING_CHANNEL_SELECT    0x79
+#define RF22_REG_7A_FREQUENCY_HOPPING_STEP_SIZE         0x7a
+#define RF22_REG_7C_TX_FIFO_CONTROL1                    0x7c
+#define RF22_REG_7D_TX_FIFO_CONTROL2                    0x7d
+#define RF22_REG_7E_RX_FIFO_CONTROL                     0x7e
+#define RF22_REG_7F_FIFO_ACCESS                         0x7f
+
+// These register masks etc are named wherever possible
+// corresponding to the bit and field names in the RF-22 Manual
+// RF22_REG_00_DEVICE_TYPE                      0x00
+#define RF22_DEVICE_TYPE_RX_TRX                 0x08
+#define RF22_DEVICE_TYPE_TX                     0x07
+
+// RF22_REG_02_DEVICE_STATUS                    0x02
+#define RF22_FFOVL                              0x80
+#define RF22_FFUNFL                             0x40
+#define RF22_RXFFEM                             0x20
+#define RF22_HEADERR                            0x10
+#define RF22_FREQERR                            0x08
+#define RF22_LOCKDET                            0x04
+#define RF22_CPS                                0x03
+#define RF22_CPS_IDLE                           0x00
+#define RF22_CPS_RX                             0x01
+#define RF22_CPS_TX                             0x10
+
+// RF22_REG_03_INTERRUPT_STATUS1                0x03
+#define RF22_IFFERROR                           0x80
+#define RF22_ITXFFAFULL                         0x40
+#define RF22_ITXFFAEM                           0x20
+#define RF22_IRXFFAFULL                         0x10
+#define RF22_IEXT                               0x08
+#define RF22_IPKSENT                            0x04
+#define RF22_IPKVALID                           0x02
+#define RF22_ICRCERROR                          0x01
+
+// RF22_REG_04_INTERRUPT_STATUS2                0x04
+#define RF22_ISWDET                             0x80
+#define RF22_IPREAVAL                           0x40
+#define RF22_IPREAINVAL                         0x20
+#define RF22_IRSSI                              0x10
+#define RF22_IWUT                               0x08
+#define RF22_ILBD                               0x04
+#define RF22_ICHIPRDY                           0x02
+#define RF22_IPOR                               0x01
+
+// RF22_REG_05_INTERRUPT_ENABLE1                0x05
+#define RF22_ENFFERR                            0x80
+#define RF22_ENTXFFAFULL                        0x40
+#define RF22_ENTXFFAEM                          0x20
+#define RF22_ENRXFFAFULL                        0x10
+#define RF22_ENEXT                              0x08
+#define RF22_ENPKSENT                           0x04
+#define RF22_ENPKVALID                          0x02
+#define RF22_ENCRCERROR                         0x01
+
+// RF22_REG_06_INTERRUPT_ENABLE2                0x06
+#define RF22_ENSWDET                            0x80
+#define RF22_ENPREAVAL                          0x40
+#define RF22_ENPREAINVAL                        0x20
+#define RF22_ENRSSI                             0x10
+#define RF22_ENWUT                              0x08
+#define RF22_ENLBDI                             0x04
+#define RF22_ENCHIPRDY                          0x02
+#define RF22_ENPOR                              0x01
+
+// RF22_REG_07_OPERATING_MODE                   0x07
+#define RF22_SWRES                              0x80
+#define RF22_ENLBD                              0x40
+#define RF22_ENWT                               0x20
+#define RF22_X32KSEL                            0x10
+#define RF22_TXON                               0x08
+#define RF22_RXON                               0x04
+#define RF22_PLLON                              0x02
+#define RF22_XTON                               0x01
+
+// RF22_REG_08_OPERATING_MODE2                  0x08
+#define RF22_ANTDIV                             0xc0
+#define RF22_RXMPK                              0x10
+#define RF22_AUTOTX                             0x08
+#define RF22_ENLDM                              0x04
+#define RF22_FFCLRRX                            0x02
+#define RF22_FFCLRTX                            0x01
+
+// RF22_REG_0F_ADC_CONFIGURATION                0x0f
+#define RF22_ADCSTART                           0x80
+#define RF22_ADCDONE                            0x80
+#define RF22_ADCSEL                             0x70
+#define RF22_ADCSEL_INTERNAL_TEMPERATURE_SENSOR 0x00
+#define RF22_ADCSEL_GPIO0_SINGLE_ENDED          0x10
+#define RF22_ADCSEL_GPIO1_SINGLE_ENDED          0x20
+#define RF22_ADCSEL_GPIO2_SINGLE_ENDED          0x30
+#define RF22_ADCSEL_GPIO0_GPIO1_DIFFERENTIAL    0x40
+#define RF22_ADCSEL_GPIO1_GPIO2_DIFFERENTIAL    0x50
+#define RF22_ADCSEL_GPIO0_GPIO2_DIFFERENTIAL    0x60
+#define RF22_ADCSEL_GND                         0x70
+#define RF22_ADCREF                             0x0c
+#define RF22_ADCREF_BANDGAP_VOLTAGE             0x00
+#define RF22_ADCREF_VDD_ON_3                    0x08
+#define RF22_ADCREF_VDD_ON_2                    0x0c
+#define RF22_ADCGAIN                            0x03
+
+// RF22_REG_10_ADC_SENSOR_AMP_OFFSET            0x10
+#define RF22_ADCOFFS                            0x0f
+
+// RF22_REG_12_TEMPERATURE_SENSOR_CALIBRATION   0x12
+#define RF22_TSRANGE                            0xc0
+#define RF22_TSRANGE_M64_64C                    0x00
+#define RF22_TSRANGE_M64_192C                   0x40
+#define RF22_TSRANGE_0_128C                     0x80
+#define RF22_TSRANGE_M40_216F                   0xc0
+#define RF22_ENTSOFFS                           0x20
+#define RF22_ENTSTRIM                           0x10
+#define RF22_TSTRIM                             0x0f
+
+// RF22_REG_14_WAKEUP_TIMER_PERIOD1             0x14
+#define RF22_WTR                                0x3c
+#define RF22_WTD                                0x03
+
+//  RF22_REG_1D_AFC_LOOP_GEARSHIFT_OVERRIDE     0x1d
+#define RF22_AFC_EN                             0x40
+
+// Reg  RF22_REG_1E_AFC_TIMING_CONTROL          0x1e
+#define RF22_AFC_TC                             0x0a
+
+// Reg RF22_REG_2A_AFC_LIMITER                  0x2a
+#define RF22_AFC_LIMIT                          0x50
+
+// RF22_REG_30_DATA_ACCESS_CONTROL              0x30
+#define RF22_ENPACRX                            0x80
+#define RF22_LSBFRST                            0x40
+#define RF22_CRCDONLY                           0x20
+#define RF22_ENPACTX                            0x08
+#define RF22_ENCRC                              0x04
+#define RF22_CRC                                0x03
+#define RF22_CRC_CCITT                          0x00
+#define RF22_CRC_CRC_16_IBM                     0x01
+#define RF22_CRC_IEC_16                         0x02
+#define RF22_CRC_BIACHEVA                       0x03
+
+// RF22_REG_32_HEADER_CONTROL1                  0x32
+#define RF22_BCEN                               0xf0
+#define RF22_BCEN_NONE                          0x00
+#define RF22_BCEN_HEADER0                       0x10
+#define RF22_BCEN_HEADER1                       0x20
+#define RF22_BCEN_HEADER2                       0x40
+#define RF22_BCEN_HEADER3                       0x80
+#define RF22_HDCH                               0x0f
+#define RF22_HDCH_NONE                          0x00
+#define RF22_HDCH_HEADER0                       0x01
+#define RF22_HDCH_HEADER1                       0x02
+#define RF22_HDCH_HEADER2                       0x04
+#define RF22_HDCH_HEADER3                       0x08
+
+// RF22_REG_33_HEADER_CONTROL2                  0x33
+#define RF22_HDLEN                              0x70
+#define RF22_HDLEN_0                            0x00
+#define RF22_HDLEN_1                            0x10
+#define RF22_HDLEN_2                            0x20
+#define RF22_HDLEN_3                            0x30
+#define RF22_HDLEN_4                            0x40
+#define RF22_FIXPKLEN                           0x08
+#define RF22_SYNCLEN                            0x06
+#define RF22_SYNCLEN_1                          0x00
+#define RF22_SYNCLEN_2                          0x02
+#define RF22_SYNCLEN_3                          0x04
+#define RF22_SYNCLEN_4                          0x06
+#define RF22_PREALEN8                           0x01
+
+// RF22_REG_6D_TX_POWER                         0x6d
+#define RF22_TXPOW                              0x07
+#define RF22_TXPOW_4X31                         0x08 // Not used in RFM22B
+#define RF22_TXPOW_1DBM                         0x00
+#define RF22_TXPOW_2DBM                         0x01
+#define RF22_TXPOW_5DBM                         0x02
+#define RF22_TXPOW_8DBM                         0x03
+#define RF22_TXPOW_11DBM                        0x04
+#define RF22_TXPOW_14DBM                        0x05
+#define RF22_TXPOW_17DBM                        0x06
+#define RF22_TXPOW_20DBM                        0x07
+// IN RFM23B
+#define RF22_TXPOW_LNA_SW                       0x08
+
+// RF22_REG_71_MODULATION_CONTROL2              0x71
+#define RF22_TRCLK                              0xc0
+#define RF22_TRCLK_NONE                         0x00
+#define RF22_TRCLK_GPIO                         0x40
+#define RF22_TRCLK_SDO                          0x80
+#define RF22_TRCLK_NIRQ                         0xc0
+#define RF22_DTMOD                              0x30
+#define RF22_DTMOD_DIRECT_GPIO                  0x00
+#define RF22_DTMOD_DIRECT_SDI                   0x10
+#define RF22_DTMOD_FIFO                         0x20
+#define RF22_DTMOD_PN9                          0x30
+#define RF22_ENINV                              0x08
+#define RF22_FD8                                0x04
+#define RF22_MODTYP                             0x30
+#define RF22_MODTYP_UNMODULATED                 0x00
+#define RF22_MODTYP_OOK                         0x01
+#define RF22_MODTYP_FSK                         0x02
+#define RF22_MODTYP_GFSK                        0x03
+
+// RF22_REG_75_FREQUENCY_BAND_SELECT            0x75
+#define RF22_SBSEL                              0x40
+#define RF22_HBSEL                              0x20
+#define RF22_FB                                 0x1f
+
+/////////////////////////////////////////////////////////////////////
+/// \class RF22 RF22.h <RF22.h>
+/// \brief Send and receive unaddressed, unreliable datagrams.
+///
+/// This base class provides basic functions for sending and receiving unaddressed, 
+/// unreliable datagrams of arbitrary length to 255 octets per packet.
+///
+/// Subclasses may use this class to implement reliable, addressed datagrams and streams, 
+/// mesh routers, repeaters, translators etc.
+///
+/// On transmission, the TO and FROM addresses default to 0x00, unless changed by a subclass. 
+/// On reception the TO addressed is checked against the node address (defaults to 0x00) or the
+/// broadcast address (which is 0xff). The ID and FLAGS are set to 0, and not checked by this class.
+/// This permits use of the this base RF22 class as an 
+/// unaddresed, unreliable datagram service. Subclasses are expected to change this behaviour to 
+/// add node address, ids, retransmission etc
+///
+/// Naturally, for any 2 radios to communicate that must be configured to use the same frequence and 
+/// modulation scheme.
+class RF22
+{
+public:
+
+    /// \brief Defines register values for a set of modem configuration registers
+    ///
+    /// Defines register values for a set of modem configuration registers
+    /// that can be passed to setModemConfig()
+    /// if none of the choices in ModemConfigChoice suit your need
+    /// setModemConfig() writes the register values to the appropriate RF22 registers
+    /// to set the desired modulation type, data rate and deviation/bandwidth.
+    /// Suitable values for these registers can be computed using the register calculator at
+    /// "http://www.hoperf.com/upfile/RF22B 23B 31B 42B 43B Register Settings_RevB1-v5.xls"
+    typedef struct
+    {
+    uint8_t    reg_1c;   ///< Value for register RF22_REG_1C_IF_FILTER_BANDWIDTH
+    uint8_t    reg_1f;   ///< Value for register RF22_REG_1F_CLOCK_RECOVERY_GEARSHIFT_OVERRIDE
+    uint8_t    reg_20;   ///< Value for register RF22_REG_20_CLOCK_RECOVERY_OVERSAMPLING_RATE
+    uint8_t    reg_21;   ///< Value for register RF22_REG_21_CLOCK_RECOVERY_OFFSET2 
+    uint8_t    reg_22;   ///< Value for register RF22_REG_22_CLOCK_RECOVERY_OFFSET1 
+    uint8_t    reg_23;   ///< Value for register RF22_REG_23_CLOCK_RECOVERY_OFFSET0
+    uint8_t    reg_24;   ///< Value for register RF22_REG_24_CLOCK_RECOVERY_TIMING_LOOP_GAIN1
+    uint8_t    reg_25;   ///< Value for register RF22_REG_25_CLOCK_RECOVERY_TIMING_LOOP_GAIN0 
+    uint8_t    reg_2c;   ///< Value for register RF22_REG_2C_OOK_COUNTER_VALUE_1 
+    uint8_t    reg_2d;   ///< Value for register RF22_REG_2D_OOK_COUNTER_VALUE_2
+    uint8_t    reg_2e;   ///< Value for register RF22_REG_2E_SLICER_PEAK_HOLD 
+    uint8_t    reg_58;   ///< Value for register RF22_REG_58_CHARGE_PUMP_CURRENT_TRIMMING
+    uint8_t    reg_69;   ///< Value for register RF22_REG_69_AGC_OVERRIDE1 
+    uint8_t    reg_6e;   ///< Value for register RF22_REG_6E_TX_DATA_RATE1
+    uint8_t    reg_6f;   ///< Value for register RF22_REG_6F_TX_DATA_RATE0 
+    uint8_t    reg_70;   ///< Value for register RF22_REG_70_MODULATION_CONTROL1
+    uint8_t    reg_71;   ///< Value for register RF22_REG_71_MODULATION_CONTROL2
+    uint8_t    reg_72;   ///< Value for register RF22_REG_72_FREQUENCY_DEVIATION
+    } ModemConfig;
+  
+    /// Choices for setModemConfig() for a selected subset of common modulation types,
+    /// and data rates. If you need another configuration, use the register calculator at
+    /// "http://www.hoperf.com/upfile/RF22B 23B 31B 42B 43B Register Settings_RevB1-v5.xls"
+    /// and call setModemRegisters() with your desired settings
+    /// These are indexes into _modemConfig
+    typedef enum
+    {
+    UnmodulatedCarrier = 0, ///< Unmodulated carrier for testing
+    FSK_PN9_Rb2Fd5,      ///< FSK, No Manchester, Rb = 2kbs, Fd = 5kHz, PN9 random modulation for testing
+
+    FSK_Rb2Fd5,         ///< FSK, No Manchester, Rb = 2kbs,    Fd = 5kHz
+    FSK_Rb2_4Fd36,       ///< FSK, No Manchester, Rb = 2.4kbs,  Fd = 36kHz
+    FSK_Rb4_8Fd45,       ///< FSK, No Manchester, Rb = 4.8kbs,  Fd = 45kHz
+    FSK_Rb9_6Fd45,       ///< FSK, No Manchester, Rb = 9.6kbs,  Fd = 45kHz
+    FSK_Rb19_2Fd9_6,     ///< FSK, No Manchester, Rb = 19.2kbs, Fd = 9.6kHz
+    FSK_Rb38_4Fd19_6,    ///< FSK, No Manchester, Rb = 38.4kbs, Fd = 19.6kHz
+    FSK_Rb57_6Fd28_8,    ///< FSK, No Manchester, Rb = 57.6kbs, Fd = 28.8kHz
+    FSK_Rb125Fd125,      ///< FSK, No Manchester, Rb = 125kbs,  Fd = 125kHz
+
+    GFSK_Rb2Fd5,         ///< GFSK, No Manchester, Rb = 2kbs,    Fd = 5kHz
+    GFSK_Rb2_4Fd36,      ///< GFSK, No Manchester, Rb = 2.4kbs,  Fd = 36kHz
+    GFSK_Rb4_8Fd45,      ///< GFSK, No Manchester, Rb = 4.8kbs,  Fd = 45kHz
+    GFSK_Rb9_6Fd45,      ///< GFSK, No Manchester, Rb = 9.6kbs,  Fd = 45kHz
+    GFSK_Rb19_2Fd9_6,    ///< GFSK, No Manchester, Rb = 19.2kbs, Fd = 9.6kHz
+    GFSK_Rb38_4Fd19_6,   ///< GFSK, No Manchester, Rb = 38.4kbs, Fd = 19.6kHz
+    GFSK_Rb57_6Fd28_8,   ///< GFSK, No Manchester, Rb = 57.6kbs, Fd = 28.8kHz
+    GFSK_Rb125Fd125,     ///< GFSK, No Manchester, Rb = 125kbs,  Fd = 125kHz
+
+    OOK_Rb1_2Bw75,       ///< OOK, No Manchester, Rb = 1.2kbs,  Rx Bandwidth = 75kHz
+    OOK_Rb2_4Bw335,      ///< OOK, No Manchester, Rb = 2.4kbs,  Rx Bandwidth = 335kHz
+    OOK_Rb4_8Bw335,      ///< OOK, No Manchester, Rb = 4.8kbs,  Rx Bandwidth = 335kHz
+    OOK_Rb9_6Bw335,      ///< OOK, No Manchester, Rb = 9.6kbs,  Rx Bandwidth = 335kHz
+    OOK_Rb19_2Bw335,     ///< OOK, No Manchester, Rb = 19.2kbs, Rx Bandwidth = 335kHz
+    OOK_Rb38_4Bw335,     ///< OOK, No Manchester, Rb = 38.4kbs, Rx Bandwidth = 335kHz
+    OOK_Rb40Bw335        ///< OOK, No Manchester, Rb = 40kbs,   Rx Bandwidth = 335kHz
+    } ModemConfigChoice;
+
+    /// Constructor. You can have multiple instances, but each instance must have its own
+    /// interrupt and slave select pin. After constructing, you must call init() to initialise the intnerface
+    /// and the radio module
+    /// \param[in] slaveSelectPin the Arduino pin number of the output to use to select the RF22 before
+    /// accessing it
+    /// \param[in] interrupt The interrupt number to use. Default is interrupt 0 (Arduino input pin 2)
+    RF22(PinName slaveSelectPin , PinName mosi, PinName miso, PinName sclk, PinName interrupt );
+  
+    /// Initialises this instance and the radio module connected to it.
+    /// The following steps are taken:
+    /// - Initialise the slave select pin and the SPI interface library
+    /// - Software reset the RF22 module
+    /// - Checks the connected RF22 module is either a RF22_DEVICE_TYPE_RX_TRX or a RF22_DEVICE_TYPE_TX
+    /// - Attaches an interrupt handler
+    /// - Configures the RF22 module
+    /// - Sets the frequncy to 434.0 MHz
+    /// - Sets the modem data rate to FSK_Rb2_4Fd36
+    /// \return  true if everything was successful
+    boolean        init();
+
+    /// Issues a software reset to the 
+    /// RF22 module. Blocks for 1ms to ensure the reset is complete.
+    void           reset();
+
+    /// Reads a single register from the RF22
+    /// \param[in] reg Register number, one of RF22_REG_*
+    /// \return The value of the register
+    uint8_t        spiRead(uint8_t reg);
+
+    /// Writes a single byte to the RF22
+    /// \param[in] reg Register number, one of RF22_REG_*
+    /// \param[in] val The value to write
+    void           spiWrite(uint8_t reg, uint8_t val);
+
+    /// Reads a number of consecutive registers from the RF22 using burst read mode
+    /// \param[in] reg Register number of the first register, one of RF22_REG_*
+    /// \param[in] dest Array to write the register values to. Must be at least len bytes
+    /// \param[in] len Number of bytes to read
+    void           spiBurstRead(uint8_t reg, uint8_t* dest, uint8_t len);
+
+    /// Write a number of consecutive registers using burst write mode
+    /// \param[in] reg Register number of the first register, one of RF22_REG_*
+    /// \param[in] src Array of new register values to write. Must be at least len bytes
+    /// \param[in] len Number of bytes to write
+    void           spiBurstWrite(uint8_t reg, uint8_t* src, uint8_t len);
+
+    /// Reads and returns the device status register RF22_REG_02_DEVICE_STATUS
+    /// \return The value of the device status register
+    uint8_t        statusRead();
+  
+    /// Reads a value from the on-chip analog-digital converter
+    /// \param[in] adcsel Selects the ADC input to measure. One of RF22_ADCSEL_*. Defaults to the 
+    /// internal temperature sensor
+    /// \param[in] adcref Specifies the refernce voltage to use. One of RF22_ADCREF_*. 
+    /// Defaults to the internal bandgap voltage.
+    /// \param[in] adcgain Amplifier gain selection. 
+    /// \param[in] adcoffs Amplifier offseet (0 to 15).
+    /// \return The analog value. 0 to 255.
+    uint8_t        adcRead(uint8_t adcsel = RF22_ADCSEL_INTERNAL_TEMPERATURE_SENSOR,
+               uint8_t adcref = RF22_ADCREF_BANDGAP_VOLTAGE,
+               uint8_t adcgain = 0, 
+               uint8_t adcoffs = 0);
+
+    /// Reads the on-chip temperature sensoer
+    /// \param[in] tsrange Specifies the temperature range to use. One of RF22_TSRANGE_*
+    /// \param[in] tvoffs Specifies the temperature value offset. This is actually signed value 
+    /// added to the measured temperature value
+    /// \return The measured temperature.
+    uint8_t        temperatureRead(uint8_t tsrange = RF22_TSRANGE_M64_64C, uint8_t tvoffs = 0);   
+
+    /// Reads the wakeup timer value in registers RF22_REG_17_WAKEUP_TIMER_VALUE1 
+    /// and RF22_REG_18_WAKEUP_TIMER_VALUE2
+    /// \return The wakeup timer value 
+    uint16_t       wutRead();
+
+    /// Sets the wakeup timer period registers RF22_REG_14_WAKEUP_TIMER_PERIOD1,
+    /// RF22_REG_15_WAKEUP_TIMER_PERIOD2 and RF22_REG_16_WAKEUP_TIMER_PERIOD3
+    /// \param[in] wtm Wakeup timer mantissa value
+    /// \param[in] wtr Wakeup timer exponent R value
+    /// \param[in] wtd Wakeup timer exponent D value
+    void           setWutPeriod(uint16_t wtm, uint8_t wtr = 0, uint8_t wtd = 0);
+
+    /// Sets the transmitter and receiver centre frequency
+    /// \param[in] centre Frequency in MHz. 240.0 to 960.0. Caution, some versions of RF22 and derivatives 
+    /// implemented more restricted frequency ranges.
+    /// \return true if the selected frquency centre + (fhch * fhs) is within range
+    boolean        setFrequency(float centre);
+
+    /// Sets the frequency hopping step size.
+    /// \param[in] fhs Frequency Hopping step size in 10kHz increments
+    /// \return true if centre + (fhch * fhs) is within limits
+    boolean        setFHStepSize(uint8_t fhs);
+
+    /// Sets the frequncy hopping channel. Adds fhch * fhs to centre frequency
+    /// \param[in] fhch The channel number
+    /// \return true if the selected frquency centre + (fhch * fhs) is within range
+    boolean        setFHChannel(uint8_t fhch);
+
+    /// Reads and returns the current RSSI value from register RF22_REG_26_RSSI
+    /// \return The current RSSI value 
+    uint8_t        rssiRead();
+
+    /// Reads and returns the current EZMAC value from register RF22_REG_31_EZMAC_STATUS
+    /// \return The current EZMAC value
+    uint8_t        ezmacStatusRead();
+
+    /// Sets the parameters for the RF22 Idle mode in register RF22_REG_07_OPERATING_MODE. 
+    /// Idle mode is the mode the RF22 wil be in when not transmitting or receiving. The default idle mode 
+    /// is RF22_XTON ie READY mode. 
+    /// \param[in] mode MAsk of mode bits, using RF22_SWRES, RF22_ENLBD, RF22_ENWT, 
+    /// RF22_X32KSEL, RF22_PLLON, RF22_XTON.
+    void           setMode(uint8_t mode);
+
+    /// If current mode is Rx or Tx changes it to Idle. If the transmitter or receiver is running, 
+    /// disables them.
+    void           setModeIdle();
+
+    /// If current mode is Tx or Idle, changes it to Rx. 
+    /// Starts the receiver in the RF22.
+    void           setModeRx();
+
+    /// If current mode is Rx or Idle, changes it to Rx. 
+    /// Starts the transmitter in the RF22.
+    void           setModeTx();
+
+    /// Sets the transmitter power output level in register RF22_REG_6D_TX_POWER.
+    /// Be a good neighbour and set the lowest power level you need.
+    /// After init(), the power wil be set to RF22_TXPOW_8DBM.
+    /// Caution: In some countries you may only select RF22_TXPOW_17DBM if you
+    /// are also using frequency hopping.
+    /// \param[in] power Transmitter power level, one of RF22_TXPOW_*
+    void           setTxPower(uint8_t power);
+
+    /// Sets all the registered required to configure the data modem in the RF22, including the data rate, 
+    /// bandwidths etc. You cas use this to configure the modem with custom configuraitons if none of the 
+    /// canned configurations in ModemConfigChoice suit you.
+    /// \param[in] config A ModemConfig structure containing values for the modem configuration registers.
+    void           setModemRegisters(ModemConfig* config);
+
+    /// Select one of the predefined modem configurations. If you need a modem configuration not provided 
+    /// here, use setModemRegisters() with your own ModemConfig.
+    /// \param[in] index The configuration choice.
+    /// \return true if index is a valid choice.
+    boolean        setModemConfig(ModemConfigChoice index);
+
+    /// Starts the receiver and checks whether a received message is available.
+    /// This can be called multiple times in a timeout loop
+    /// \return true if a complete, valid message has been received and is able to be retrieved by
+    /// recv()
+    boolean        available();
+
+    /// Starts the receiver and blocks until a valid received 
+    /// message is available.
+    void           waitAvailable();
+
+    /// Starts the receiver and blocks until a received message is available or a timeout
+    /// \param[in] timeout Maximum time to wait in milliseconds.
+    /// \return true if a message is available
+    bool           waitAvailableTimeout(uint16_t timeout);
+
+    /// Turns the receiver on if it not already on.
+    /// If there is a valid message available, copy it to buf and return true
+    /// else return false.
+    /// If a message is copied, *len is set to the length (Caution, 0 length messages are permitted).
+    /// You should be sure to call this function frequently enough to not miss any messages
+    /// It is recommended that you call it in your main loop.
+    /// \param[in] buf Location to copy the received message
+    /// \param[in,out] len Pointer to available space in buf. Set to the actual number of octets copied.
+    /// \return true if a valid message was copied to buf
+    boolean        recv(uint8_t* buf, uint8_t* len);
+
+    /// Loads a message into the transmitter and starts the transmitter. Note that a message length
+    /// of 0 is permitted, in which case data may be NULL.
+    /// \param[in] data Array of data to be sent
+    /// \param[in] len Number of bytes of data to send.
+    /// \return true
+    boolean        send(uint8_t* data, uint8_t len);
+
+    /// Blocks until the current message 
+    /// (if any) has been completely sent
+    void           waitPacketSent();
+  
+    /// Tells the receiver to accept messages with any TO address, not just messages
+    /// addressed to this node or the broadcast address
+    /// \param[in] promiscuous true if you wish to receive messages with any TO address
+    void           setPromiscuous(boolean promiscuous);
+
+    /// Returns the TO header of the last received message
+    /// \return The TO header
+    uint8_t        headerTo();
+
+    /// Returns the FROM header of the last received message
+    /// \return The FROM header
+    /// \return
+    uint8_t        headerFrom();
+
+    /// Returns the ID header of the last received message
+    /// \return The ID header
+    /// \return
+    uint8_t        headerId();
+
+    /// Returns the FLAGS header of the last received message
+    /// \return The FLAGS header
+    /// \return
+    uint8_t        headerFlags();
+
+    /// Returns the RSSI (Receiver Signal Strength Indicator)
+    /// of the last received message. This measurement is taken when 
+    /// the preamble has been received. It is a (non-linear) measure of the received signal strength.
+    /// \return The RSSI
+    uint8_t        lastRssi();
+
+protected:
+    /// Sets the message preamble length in RF22_REG_34_PREAMBLE_LENGTH
+    /// \param[in] nibbles Preamble length in nibbles of 4 bits each.  
+    void           setPreambleLength(uint8_t nibbles);
+
+    /// Sets the sync words for transmit and receive in registers RF22_REG_36_SYNC_WORD3 
+    /// to RF22_REG_39_SYNC_WORD0
+    /// \param[in] syncWords Array of sync words
+    /// \param[in] len Number of sync words to set
+    void           setSyncWords(uint8_t* syncWords, uint8_t len);
+
+    /// This is a low level function to handle the interrupts for one instance of RF22.
+    /// Called automatically by isr0() and isr1()
+    /// Should not need to be called.
+    void           handleInterrupt();
+
+    /// Clears the receiver buffer.
+    /// Internal use only
+    void           clearRxBuf();
+
+    /// Clears the transmitter buffer
+    /// Internal use only
+    void           clearTxBuf();
+
+    /// Fills the transmitter buffer with the data of a mesage to be sent
+    /// \param[in] data Array of data bytes to be sent (0 to 255)
+    /// \param[in] len Number of data bytes in data
+    /// \return true
+    boolean           fillTxBuf(uint8_t* data, uint8_t len);
+
+    /// Appends the transmitter buffer with the data of a mesage to be sent
+    /// \param[in] data Array of data bytes to be sent (0 to 255)
+    /// \param[in] len Number of data bytes in data
+    /// \return false if the resulting message would exceed RF22_MAX_MESSAGE_LEN, else true
+    boolean           appendTxBuf(uint8_t* data, uint8_t len);
+
+    /// Internal function to load the next fragment of 
+    /// the current message into the transmitter FIFO
+    /// Internal use only
+    void           sendNextFragment();
+
+    ///  function to copy the next fragment from 
+    /// the receiver FIF) into the receiver buffer
+    void           readNextFragment();
+
+    /// Clears the RF22 Rx and Tx FIFOs
+    /// Internal use only
+    void           resetFifos();
+
+    /// Clears the RF22 Rx FIFO
+    /// Internal use only
+    void           resetRxFifo();
+
+    /// Clears the RF22 Tx FIFO
+    /// Internal use only
+    void           resetTxFifo();
+
+    /// This function will be called by handleInterrupt() if an RF22 external interrupt occurs. 
+    /// This can only happen if external interrupts are enabled in the RF22 
+    /// (which they are not by default). 
+    /// Subclasses may override this function to get control when  an RF22 external interrupt occurs. 
+    virtual void   handleExternalInterrupt();
+
+    /// This function will be called by handleInterrupt() if an RF22 wakeup timer interrupt occurs. 
+    /// This can only happen if wakeup timer interrupts are enabled in the RF22 
+    /// (which they are not by default). 
+    /// Subclasses may override this function to get control when  an RF22 wakeup timer interrupt occurs. 
+    virtual void   handleWakeupTimerInterrupt();
+
+    /// Sets the TO header to be sent in all subsequent messages
+    /// \param[in] to The new TO header value
+    void           setHeaderTo(uint8_t to);
+
+    /// Sets the FROM header to be sent in all subsequent messages
+    /// \param[in] from The new FROM header value
+    void           setHeaderFrom(uint8_t from);
+
+    /// Sets the ID header to be sent in all subsequent messages
+    /// \param[in] id The new ID header value
+    void           setHeaderId(uint8_t id);
+
+    /// Sets the FLAGS header to be sent in all subsequent messages
+    /// \param[in] flags The new FLAGS header value
+    void           setHeaderFlags(uint8_t flags);
+
+    /// Start the transmission of the contents 
+    /// of the Tx buffer
+    void           startTransmit();
+
+    /// ReStart the transmission of the contents 
+    /// of the Tx buffer after a atransmission failure
+    void           restartTransmit();
+
+//private:
+    /// Low level interrupt service routine for RF22 connected to interrupt 0
+    //static void         isr0();
+    void         isr0();
+
+    /// Low level interrupt service routine for RF22 connected to interrupt 1
+    //static void         isr1();
+private:
+    /// Array of instances connected to interrupts 0 and 1
+    //static RF22*        _RF22ForInterrupt[];
+    
+   
+    uint8_t             _mode; // One of RF22_MODE_*
+
+    uint8_t             _idleMode;
+    DigitalOut          _slaveSelectPin;
+    SPI                 _spi;
+    InterruptIn         _interrupt;
+    uint8_t             _deviceType;
+    
+    DigitalOut           led1;
+    DigitalOut           led2;
+    DigitalOut           led3;
+    DigitalOut           led4;
+
+    // These volatile members may get changed in the interrupt service routine
+    uint8_t             _buf[RF22_MAX_MESSAGE_LEN];
+    volatile uint8_t    _bufLen;
+
+    volatile boolean    _rxBufValid;
+
+    volatile boolean    _txPacketSent;
+    volatile uint8_t    _txBufSentIndex;
+  
+    volatile uint16_t   _rxBad;
+    volatile uint16_t   _rxGood;
+    volatile uint16_t   _txGood;
+
+    volatile uint8_t    _lastRssi;
+    
+};
+
+
+#endif 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RF22Datagram.cpp	Tue Feb 14 19:39:36 2012 +0000
@@ -0,0 +1,51 @@
+// RF22Datagram.cpp
+//
+// Copyright (C) 2011 Mike McCauley
+// $Id: RF22Datagram.cpp,v 1.2 2011/02/09 22:26:09 mikem Exp $
+// ported to mbed by Karl Zweimueller
+
+#include <RF22Datagram.h>
+//#include <SPI.h>
+
+RF22Datagram::RF22Datagram(uint8_t thisAddress, PinName slaveSelectPin , PinName mosi, PinName miso, PinName sclk, PinName interrupt ) 
+    : RF22(slaveSelectPin , mosi, miso, sclk, interrupt )
+{
+    _thisAddress = thisAddress;
+}
+
+////////////////////////////////////////////////////////////////////
+// Public methods
+boolean RF22Datagram::init()
+{
+    boolean ret = this->RF22::init();
+    if (ret)
+    setThisAddress(_thisAddress);
+    return ret;
+}
+
+void RF22Datagram::setThisAddress(uint8_t thisAddress)
+{
+    _thisAddress = thisAddress;
+    // Check the TO header against RF22_DEFAULT_NODE_ADDRESS
+    spiWrite(RF22_REG_3F_CHECK_HEADER3, _thisAddress);
+    // Use this address in the transmitted FROM header
+    setHeaderFrom(_thisAddress);
+}
+
+boolean RF22Datagram::sendto(uint8_t* buf, uint8_t len, uint8_t address)
+{
+    setHeaderTo(address);
+    return send(buf, len);
+}
+
+boolean RF22Datagram::recvfrom(uint8_t* buf, uint8_t* len, uint8_t* from, uint8_t* to, uint8_t* id, uint8_t* flags)
+{
+    if (from)  *from =  headerFrom();
+    if (to)    *to =    headerTo();
+    if (id)    *id =    headerId();
+    if (flags) *flags = headerFlags();
+    return recv(buf, len);
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RF22Datagram.h	Tue Feb 14 19:39:36 2012 +0000
@@ -0,0 +1,77 @@
+// RF22Datagram.h
+// Author: Mike McCauley (mikem@open.com.au)
+// Copyright (C) 2011 Mike McCauley
+// $Id: RF22Datagram.h,v 1.3 2011/02/15 01:18:03 mikem Exp $
+// ported to mbed by Karl Zweimueller
+
+#ifndef RF22Datagram_h
+#define RF22Datagram_h
+
+#include <RF22.h>
+
+/////////////////////////////////////////////////////////////////////
+/// \class RF22Datagram RF22Datagram.h <RF22Datagram.h>
+/// \brief RF22 subclass for addressed, unreliable messages
+///
+/// Extends RF22 to define addressed, unreliable datagrams.
+/// Every node has an 8 bit address (defaults to 0).
+/// Addresses (DEST and SRC) are 8 bit integers with an address of RF22_BROADCAST_ADDRESS (0xff) 
+/// reserved for broadcast.
+///
+/// Part of the Arduino RF22 library for operating with HopeRF RF22 compatible transceivers 
+/// (see http://www.hoperf.com).
+class RF22Datagram : public RF22
+{
+public:
+    /// Constructor. 
+    /// \param[in] thisAddress The address to assign to this node. Defaults to 0
+    /// \param[in] slaveSelectPin the Arduino pin number of the output to use to select the RF22 before
+    /// accessing it
+    /// \param[in] interrupt The interrupt number to use. Default is interrupt 0 (Arduino input pin 2)
+    RF22Datagram(uint8_t thisAddress ,PinName slaveSelectPin , PinName mosi, PinName miso, PinName sclk, PinName interrupt );
+    
+    /// Initialises this instance and the radio module connected to it.
+    /// Overrides the init() function in RF22
+    boolean init();
+
+    /// Sets the address of this node. Defaults to 0. 
+    /// This will be used to set the FROM address of all messages sent by this node.
+    /// If all the nodes leave the address unset (ie 0),
+    /// In a conventional multinode system, all nodes will have a unique address 
+    /// (which you could store in EEPROM).
+    /// \param[in] thisAddress The address of this node
+    void setThisAddress(uint8_t thisAddress);
+
+    /// Sends a message to the node(s) with the given address
+    /// RF22_BROADCAST_ADDRESS is a valid address which will cause the message
+    /// to be accepted by all RF22Datagram nodes within range.
+    /// \param[in] buf Pointer to the binary message to send
+    /// \param[in] len Number of octets to send
+    /// \param[in] address The address to send the message to.
+    /// \return true if the message was transmitted.
+    boolean sendto(uint8_t* buf, uint8_t len, uint8_t address);
+
+    /// Turns the receiver on if it not already on.
+    /// If there is a valid message available for this node, copy it to buf and return true
+    /// The SRC address is placed in *from if present and not NULL.
+    /// The DEST address is placed in *to if present and not NULL.
+    /// If a message is copied, *len is set to the length.
+    /// You should be sure to call this function frequently enough to not miss any messages
+    /// It is recommended that you call it in your main loop.
+    /// \param[in] buf Location to copy the received message
+    /// \param[in,out] len Pointer to available space in buf. Set to the actual number of octets copied.
+    /// \param[in] from If present and not NULL, the referenced uint8_t will be set to the FROM address
+    /// \param[in] to If present and not NULL, the referenced uint8_t will be set to the TO address
+    /// \param[in] id If present and not NULL, the referenced uint8_t will be set to the ID
+    /// \param[in] flags If present and not NULL, the referenced uint8_t will be set to the FLAGS
+    /// (not just those addressed to this node).
+    /// \return true if a valid message was copied to buf
+    boolean recvfrom(uint8_t* buf, uint8_t* len, uint8_t* from = NULL, uint8_t* to = NULL, uint8_t* id = NULL, uint8_t* flags = NULL);
+
+protected:
+    /// The address of this node. Defaults to 0.
+    uint8_t _thisAddress;
+
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RF22Mesh.cpp	Tue Feb 14 19:39:36 2012 +0000
@@ -0,0 +1,241 @@
+// RF22Mesh.cpp
+//
+// Define addressed datagram
+// 
+// Part of the Arduino RF22 library for operating with HopeRF RF22 compatible transceivers 
+// (see http://www.hoperf.com)
+// RF22Datagram will be received only by the addressed node or all nodes within range if the 
+// to address is RF22_BROADCAST_ADDRESS
+//
+// Author: Mike McCauley (mikem@open.com.au)
+// Copyright (C) 2011 Mike McCauley
+// $Id: RF22Mesh.cpp,v 1.4 2011/02/15 04:51:59 mikem Exp $
+// ported to mbed by Karl Zweimueller
+
+#include <mbed.h>
+#include <RF22Mesh.h>
+//#include <SPI.h>
+
+
+uint8_t RF22Mesh::_tmpMessage[RF22_ROUTER_MAX_MESSAGE_LEN];
+
+////////////////////////////////////////////////////////////////////
+// Constructors
+RF22Mesh::RF22Mesh(uint8_t thisAddress ,PinName slaveSelectPin , PinName mosi, PinName miso, PinName sclk, PinName interrupt ) 
+    : RF22Router(thisAddress, slaveSelectPin, mosi,  miso, sclk, interrupt )
+{
+}
+
+////////////////////////////////////////////////////////////////////
+// Public methods
+
+////////////////////////////////////////////////////////////////////
+// Discovers a route to the destination (if necessary), sends and 
+// waits for delivery to the next hop (but not for delivery to the final destination)
+uint8_t RF22Mesh::sendtoWait(uint8_t* buf, uint8_t len, uint8_t address)
+{
+    if (len > RF22_MESH_MAX_MESSAGE_LEN)
+    return RF22_ROUTER_ERROR_INVALID_LENGTH;
+
+    RoutingTableEntry* route = getRouteTo(address);
+    if (!route && !doArp(address))
+    return RF22_ROUTER_ERROR_NO_ROUTE;
+
+    // Now have a route. Contruct an applicaiotn layer message and dend it via that route
+    MeshApplicationMessage* a = (MeshApplicationMessage*)&_tmpMessage;
+    a->header.msgType = RF22_MESH_MESSAGE_TYPE_APPLICATION;
+    memcpy(a->data, buf, len);
+    return RF22Router::sendtoWait(_tmpMessage, sizeof(RF22Mesh::MeshMessageHeader) + len, address);
+}
+
+////////////////////////////////////////////////////////////////////
+boolean RF22Mesh::doArp(uint8_t address)
+{
+    // Need to discover a route
+    // Broadcast a route discovery message with nothing in it
+    MeshRouteDiscoveryMessage* p = (MeshRouteDiscoveryMessage*)&_tmpMessage;
+    p->header.msgType = RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_REQUEST;
+    p->destlen = 1; 
+    p->dest = address; // Who we are looking for
+    uint8_t error = RF22Router::sendtoWait((uint8_t*)p, sizeof(RF22Mesh::MeshMessageHeader) + 2, RF22_BROADCAST_ADDRESS);
+    if (error !=  RF22_ROUTER_ERROR_NONE)
+    return false;
+    
+    // Wait for a reply, which will be unicast back to us
+    // It will contain the complete route to the destination
+    uint8_t messageLen = sizeof(_tmpMessage);
+    // FIXME: timeout should be configurable
+    Timer t;
+    t.start();
+    unsigned long endtime = t.read_ms() + 4000;
+    while (t.read_ms() < endtime)
+    {
+    if (RF22Router::recvfromAck(_tmpMessage, &messageLen))
+    {
+        if (   messageLen > 1
+        && p->header.msgType == RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE)
+        {
+        MeshRouteDiscoveryMessage* d = (MeshRouteDiscoveryMessage*)p;
+        // Got a reply, now add the next hop to the dest to the routing table
+        // The first hop taken is the first octet
+        addRouteTo(address, headerFrom());
+        return true;
+        }
+    }
+    }
+    return false;
+}
+
+////////////////////////////////////////////////////////////////////
+// Called by RF22Router::recvfromAck whenever a message goes past
+void RF22Mesh::peekAtMessage(RoutedMessage* message, uint8_t messageLen)
+{
+    MeshMessageHeader* m = (MeshMessageHeader*)message->data;
+    if (   messageLen > 1 
+    && m->msgType == RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE)
+    {
+    // This is a unicast RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE messages 
+    // being routed back to the originator here. Want to scrape some routing data out of the response
+    // We can find the routes to all the nodes between here and the responding node
+    MeshRouteDiscoveryMessage* d = (MeshRouteDiscoveryMessage*)message->data;
+    addRouteTo(d->dest, headerFrom());
+    uint8_t numRoutes = messageLen - sizeof(RoutedMessageHeader) - sizeof(MeshMessageHeader) - 2;
+    uint8_t i;
+    // Find us in the list of nodes that were traversed to get to the responding node
+    for (i = 0; i < numRoutes; i++)
+        if (d->route[i] == _thisAddress)
+        break;
+    i++;
+    while (i++ < numRoutes)
+        addRouteTo(d->route[i], headerFrom());
+    }
+    else if (   messageLen > 1 
+         && m->msgType == RF22_MESH_MESSAGE_TYPE_ROUTE_FAILURE)
+    {
+    MeshRouteFailureMessage* d = (MeshRouteFailureMessage*)message->data;
+    deleteRouteTo(d->dest);
+    }
+}
+
+////////////////////////////////////////////////////////////////////
+// This is called when a message is to be delivered to the next hop
+uint8_t RF22Mesh::route(RoutedMessage* message, uint8_t messageLen)
+{
+    uint8_t from = headerFrom(); // Might get clobbered during call to superclass route()
+    uint8_t ret = RF22Router::route(message, messageLen);
+    if (   ret == RF22_ROUTER_ERROR_NO_ROUTE
+    || ret == RF22_ROUTER_ERROR_UNABLE_TO_DELIVER)
+    {
+    // Cant deliver to the next hop. Delete the route
+    deleteRouteTo(message->header.dest);
+    if (message->header.source != _thisAddress)
+    {
+        // This is being proxied, so tell the originator about it
+        MeshRouteFailureMessage* p = (MeshRouteFailureMessage*)&_tmpMessage;
+        p->header.msgType = RF22_MESH_MESSAGE_TYPE_ROUTE_FAILURE;
+        p->dest = message->header.dest; // Who you were trying to deliver to
+        // Make sure there is a route back towards whoever sent the original message
+        addRouteTo(message->header.source, from);
+        ret = RF22Router::sendtoWait((uint8_t*)p, sizeof(RF22Mesh::MeshMessageHeader) + 1, message->header.source);
+    }
+    }
+    return ret;
+}
+
+////////////////////////////////////////////////////////////////////
+// Subclasses may want to override
+boolean RF22Mesh::isPhysicalAddress(uint8_t* address, uint8_t addresslen)
+{
+    // Can only handle physical addresses 1 octet long, which is the physical node address
+    return addresslen == 1 && address[0] == _thisAddress;
+}
+
+////////////////////////////////////////////////////////////////////
+boolean RF22Mesh::recvfromAck(uint8_t* buf, uint8_t* len, uint8_t* source, uint8_t* dest, uint8_t* id, uint8_t* flags)
+{     
+    uint8_t tmpMessageLen = sizeof(_tmpMessage);
+    uint8_t _source;
+    uint8_t _dest;
+    uint8_t _id;
+    uint8_t _flags;
+    if (RF22Router::recvfromAck(_tmpMessage, &tmpMessageLen, &_source, &_dest, &_id, &_flags))
+    {
+    MeshMessageHeader* p = (MeshMessageHeader*)&_tmpMessage;
+
+    if (   tmpMessageLen >= 1 
+        && p->msgType == RF22_MESH_MESSAGE_TYPE_APPLICATION)
+    {
+        MeshApplicationMessage* a = (MeshApplicationMessage*)p;
+        // Handle application layer messages, presumably for our caller
+        if (source) *source = _source;
+        if (dest)   *dest   = _dest;
+        if (id)     *id     = _id;
+        if (flags)  *flags  = _flags;
+        uint8_t msgLen = tmpMessageLen - sizeof(MeshMessageHeader);
+        if (*len > msgLen)
+        *len = msgLen;
+        memcpy(buf, a->data, *len);
+        
+        return true;
+    }
+    else if (   _dest == RF22_BROADCAST_ADDRESS 
+         && tmpMessageLen > 1 
+         && p->msgType == RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_REQUEST)
+    {
+        MeshRouteDiscoveryMessage* d = (MeshRouteDiscoveryMessage*)p;
+        // Handle Route discovery requests
+        // Message is an array of node addresses the route request has already passed through
+        // If it originally came from us, ignore it
+        if (_source == _thisAddress)
+        return false;
+        
+        uint8_t numRoutes = tmpMessageLen - sizeof(MeshMessageHeader) - 2;
+        uint8_t i;
+        // Are we already mentioned?
+        for (i = 0; i < numRoutes; i++)
+        if (d->route[i] == _thisAddress)
+            return false; // Already been through us. Discard
+        
+        // Hasnt been past us yet, record routes back to the earlier nodes
+        addRouteTo(_source, headerFrom()); // The originator
+        for (i = 0; i < numRoutes; i++)
+        addRouteTo(d->route[i], headerFrom());
+        if (isPhysicalAddress(&d->dest, d->destlen))
+        {
+        // This route discovery is for us. Unicast the whole route back to the originator
+        // as a RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE
+        // We are certain to have a route there, becuase we just got it
+        d->header.msgType = RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE;
+        RF22Router::sendtoWait((uint8_t*)d, tmpMessageLen, _source);
+        }
+        else if (i < _max_hops)
+        {
+        // Its for someone else, rebroadcast it, after adding ourselves to the list
+        d->route[numRoutes] = _thisAddress;
+        tmpMessageLen++;
+        // Have to impersonate the source
+        // REVISIT: if this fails what can we do?
+        RF22Router::sendtoWait(_tmpMessage, tmpMessageLen, RF22_BROADCAST_ADDRESS, _source);
+        }
+    }
+    }
+    return false;
+}
+
+////////////////////////////////////////////////////////////////////
+boolean RF22Mesh::recvfromAckTimeout(uint8_t* buf, uint8_t* len, uint16_t timeout, uint8_t* from, uint8_t* to, uint8_t* id, uint8_t* flags)
+{  
+    Timer t;
+    
+    t.start();
+    unsigned long endtime = t.read_ms() + timeout;
+    while (t.read_ms() < endtime)
+    {
+    if (recvfromAck(buf, len, from, to, id, flags))
+        return true;
+    }
+    return false;
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RF22Mesh.h	Tue Feb 14 19:39:36 2012 +0000
@@ -0,0 +1,238 @@
+// RF22Mesh.h
+//
+// Author: Mike McCauley (mikem@open.com.au)
+// Copyright (C) 2011 Mike McCauley
+// $Id: RF22Mesh.h,v 1.3 2011/02/15 04:51:59 mikem Exp $
+// ported to mbed by Karl Zweimueller
+
+#ifndef RF22Mesh_h
+#define RF22Mesh_h
+
+#include <RF22Router.h>
+
+// Types of RF22Mesh message, used to set msgType in the RF22MeshHeader
+#define RF22_MESH_MESSAGE_TYPE_APPLICATION                    0
+#define RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_REQUEST        1
+#define RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE       2
+#define RF22_MESH_MESSAGE_TYPE_ROUTE_FAILURE                  3
+
+/////////////////////////////////////////////////////////////////////
+/// \class RF22Mesh RF22Mesh.h <RF22Mesh.h>
+/// \brief RF22 subclass for sending addressed, optionally acknowledged datagrams
+/// multi-hop routed across a network, with automatic route discovery
+///
+/// Extends RF22Router to add automatic route discovery within a mesh of adjacent nodes, 
+/// and route signalling.
+///
+/// Unlike RF22Router, RF22Mesh can be used in networks where the network topology is fluid, or unknown, 
+/// or if nodes can mode around or go in or out of service. When a node wants to send a 
+/// message to another node, it will automcatically discover a route to the destaintion node and use it. 
+/// If the route becomes unavailable, a new route will be discovered.
+///
+/// \par Route Discovery
+///
+/// When a RF22Mesh mesh node is initialised, it doe not know any routes to any other nodes 
+/// (see RF22Router for details on route and the routing table).
+/// When you attempt to send a message with sendtoWait, will first check to see if there is a route to the 
+/// destinastion node in the routing tabl;e. If not, it wil initialite 'Route Discovery'.
+/// When a node needs to discover a route to another node, it broadcasts MeshRouteDiscoveryMessage 
+/// with a message type of RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_REQUEST. 
+/// Any node that receives such a request checks to see if it is a request for a route to itself
+/// (in which case it makes a unicast reply to the originating node with a 
+/// MeshRouteDiscoveryMessage 
+/// with a message type of RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE) 
+/// otherwise it rebroadcasts the request, after adding itself to the list of nodes visited so 
+/// far by the request.
+///
+/// If a node receives a RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_REQUEST that already has itself 
+/// listed in the visited nodes, it knows it has already seen and rebroadcast this request, 
+/// and threfore ignores it. This prevents broadcast storms.
+/// When a node receives a RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_REQUEST it can use the list of 
+/// nodes aready visited to deduce routes back towards the originating (requesting node). 
+/// This also means that when the destination node of the request is reached, it (and all 
+/// the previous nodes the request visited) will have a route back to the originating node. 
+/// This means the unicast RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE 
+/// reply will be routed successfully back to the original route requester.
+///
+/// The RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE sent back by the destination node contains 
+/// the full list of nodes that were visited on the way to the destination.
+/// Therefore, intermediate nodes that route the reply back towards the originating node can use the 
+/// node list in the reply to deduce routes to all the nodes between it and the destination node.
+///
+/// Therefore, RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_REQUEST and 
+/// RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE together ensure the original requester and all 
+/// the intermediate nodes know how to route to the source and destination nodes and every node along the path.
+///
+/// Note that there is a race condition here that can effect routing on multipath routes. For example, 
+/// if the route to the destination can traverse several paths, last reply from the destination 
+/// will be the one used.
+///
+/// \par Route Failure
+///
+/// RF22Router (and therefore RF22Mesh) use reliable hop-to-hop delivery of messages using 
+/// hop-to-hop acknowledgements, but not end-to-end acknowledgements. When sendtoWait() returns, 
+/// you know that the message has been delivered to the next hop, but not if it is (or even if it can be) 
+/// delivered to the destination node. If during the course of hop-to-hop routing of a message, 
+/// one of the intermediate RF22Mesh nodes finds it cannot deliver to the next hop 
+/// (say due to a lost route or no acknwledgement from the next hop), it replies to the 
+/// originator with a unicast MeshRouteFailureMessage RF22_MESH_MESSAGE_TYPE_ROUTE_FAILURE message. 
+/// Intermediate nodes (on the way beack to the originator)
+/// and the originating node use this message to delete the route to the destination 
+/// node of the original message. This means that if a route to a destination becomes unusable 
+/// (either because an intermediate node is off the air, or has moved out of range) a new route 
+/// will be established the next time a message is to be sent.
+///
+/// \par Message Format
+///
+/// RF22Mesh uses a number of message formats layered on top of RF22Router:
+/// - MeshApplicationMessage (message type RF22_MESH_MESSAGE_TYPE_APPLICATION). 
+///   Carries an application layer message for the caller of RF22Mesh
+/// - MeshRouteDiscoveryMessage (message types RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_REQUEST 
+///   and RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE). Carries Route Discovery messages 
+///   (broadcast) and replies (unicast).
+/// - MeshRouteFailureMessage (message type RF22_MESH_MESSAGE_TYPE_ROUTE_FAILURE) Informs nodes of 
+///   route failures.
+///
+/// Part of the Arduino RF22 library for operating with HopeRF RF22 compatible transceivers 
+/// (see http://www.hoperf.com)
+class RF22Mesh : public RF22Router
+{
+public:
+
+    /// The maximum length permitted for the application payload data in a RF22Mesh message
+    #define RF22_MESH_MAX_MESSAGE_LEN (RF22_ROUTER_MAX_MESSAGE_LEN - sizeof(RF22Mesh::MeshMessageHeader))
+
+    /// Structure of the basic RF22Mesh header.
+    typedef struct
+    {
+    uint8_t             msgType;  ///< Type of RF22Mesh message, one of RF22_MESH_MESSAGE_TYPE_*
+    } MeshMessageHeader;
+
+    /// Signals an application layer message for the caller of RF22Mesh
+    typedef struct
+    {
+    MeshMessageHeader   header; ///< msgType = RF22_MESH_MESSAGE_TYPE_APPLICATION 
+    uint8_t             data[RF22_MESH_MAX_MESSAGE_LEN]; ///< Applicaiotn layer payload data
+    } MeshApplicationMessage;
+
+    /// Signals a route discovery request or reply
+    /// At present only supports physical dest addresses of length 1 octet
+    typedef struct
+    {
+    MeshMessageHeader   header; ///< msgType = RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_*
+    uint8_t             destlen; ///< Reserved. Must be 1.
+    uint8_t             dest;   ///< The address of the destination node whose route is being sought
+    uint8_t             route[RF22_MESH_MAX_MESSAGE_LEN - 1]; ///< List of node addresses visited so far. Length is implcit
+    } MeshRouteDiscoveryMessage;
+
+    /// Signals a route failure
+    typedef struct
+    {
+    MeshMessageHeader   header; ///< msgType = RF22_MESH_MESSAGE_TYPE_ROUTE_FAILURE
+    uint8_t             dest; ///< The address of the destination towards which the route failed
+    } MeshRouteFailureMessage;
+
+    /// Constructor. 
+    /// \param[in] thisAddress The address to assign to this node. Defaults to 0
+    /// \param[in] slaveSelectPin the Arduino pin number of the output to use to select the RF22 before
+    /// accessing it
+    /// \param[in] interrupt The interrupt number to use. Default is interrupt 0 (Arduino input pin 2)
+    RF22Mesh(uint8_t thisAddress ,PinName slaveSelectPin , PinName mosi, PinName miso, PinName sclk, PinName interrupt );
+
+    /// Sends a message to the destination node. Initialises the RF22Router message header 
+    /// (the SOURCE address is set to the address of this node, HOPS to 0) and calls 
+    /// route() which looks up in the routing table the next hop to deliver to.
+    /// If no route is known, initiates route discovery and waits for a reply.
+    /// Then sends the message to the next hop
+    /// Then waits for an acknowledgement from the next hop 
+    /// (but not from the destination node (if that is different).
+    /// \param [in] buf The application message data
+    /// \param [in] len Number of octets in the application message data. 0 is permitted
+    /// \param [in] dest The destination node address
+    /// \return The result code:
+    ///         - RF22_ROUTER_ERROR_NONE Message was routed and deliverd to the next hop 
+    ///           (not necessarily to the final dest address)
+    ///         - RF22_ROUTER_ERROR_NO_ROUTE There was no route for dest in the local routing table
+    ///         - RF22_ROUTER_ERROR_UNABLE_TO_DELIVER Noyt able to deliver to the next hop 
+    ///           (usually because it dod not acknowledge due to being off the air or out of range
+    uint8_t sendtoWait(uint8_t* buf, uint8_t len, uint8_t dest);
+
+    /// Starts the receiver if it is not running already.
+    /// If there is a valid application layer message available for this node (or RF22_BROADCAST_ADDRESS), 
+    /// send an acknowledgement to the last hop
+    /// address (blocking until this is complete), then copy the application message payload data
+    /// to buf and return true
+    /// else return false. 
+    /// If a message is copied, *len is set to the length..
+    /// If from is not NULL, the originator SOURCE address is placed in *source.
+    /// If to is not NULL, the DEST address is placed in *dest. This might be this nodes address or 
+    /// RF22_BROADCAST_ADDRESS. 
+    /// This is the preferred function for getting messages addressed to this node.
+    /// If the message is not a broadcast, acknowledge to the sender before returning.
+    /// \param[in] buf Location to copy the received message
+    /// \param[in,out] len Available space in buf. Set to the actual number of octets copied.
+    /// \param[in] source If present and not NULL, the referenced uint8_t will be set to the SOURCE address
+    /// \param[in] dest If present and not NULL, the referenced uint8_t will be set to the DEST address
+    /// \param[in] id If present and not NULL, the referenced uint8_t will be set to the ID
+    /// \param[in] flags If present and not NULL, the referenced uint8_t will be set to the FLAGS
+    /// (not just those addressed to this node).
+    /// \return true if a valid message was recvived for this node and copied to buf
+    boolean recvfromAck(uint8_t* buf, uint8_t* len, uint8_t* source = NULL, uint8_t* dest = NULL, uint8_t* id = NULL, uint8_t* flags = NULL);
+
+    /// Starts the receiver if it is not running already.
+    /// Similar to recvfromAck(), this will block until either a valid application layer 
+    /// message available for this node
+    /// or the timeout expires. 
+    /// \param[in] buf Location to copy the received message
+    /// \param[in,out] len Available space in buf. Set to the actual number of octets copied.
+    /// \param[in] timeout Maximum time to wait in milliseconds
+    /// \param[in] source If present and not NULL, the referenced uint8_t will be set to the SOURCE address
+    /// \param[in] dest If present and not NULL, the referenced uint8_t will be set to the DEST address
+    /// \param[in] id If present and not NULL, the referenced uint8_t will be set to the ID
+    /// \param[in] flags If present and not NULL, the referenced uint8_t will be set to the FLAGS
+    /// (not just those addressed to this node).
+    /// \return true if a valid message was copied to buf
+    boolean recvfromAckTimeout(uint8_t* buf, uint8_t* len,  uint16_t timeout, uint8_t* source = NULL, uint8_t* dest = NULL, uint8_t* id = NULL, uint8_t* flags = NULL);
+
+protected:
+
+    /// Internal function that inspects messages being received and adjusts the routing table if necessary.
+    /// Called by recvfromAck() immediately after it gets the message from RF22ReliableDatagram
+    /// \param [in] message Pointer to the RF22Router message that was received.
+    /// \param [in] messageLen Length of message in octets
+    virtual void peekAtMessage(RoutedMessage* message, uint8_t messageLen);
+
+    /// Internal function that inspects messages being received and adjusts the routing table if necessary.
+    /// This is virtual, which lets subclasses override or intercept the route() function.
+    /// Called by sendtoWait after the message header has been filled in.
+    /// \param [in] message Pointer to the RF22Router message to be sent.
+    /// \param [in] messageLen Length of message in octets
+    virtual uint8_t route(RoutedMessage* message, uint8_t messageLen);
+
+    /// Try to resolve a route for the given address. Blocks while discovering the route
+    /// which may take up to 4000 msec.
+    /// Virtual so subclasses can override.
+    /// \param [in] address The physical addres to resolve
+    /// \return true if the address was resolved and added to the local routing table
+    virtual boolean doArp(uint8_t address);
+
+    /// Tests if the given address of length addresslen is indentical to the
+    /// physical addres of this node.
+    /// RF22Mesh always ikmplements p[hysical addresses as the 1 octet address of the node
+    /// given by _thisAddress
+    /// Called by recvfromAck() to test whether a RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_REQUEST
+    /// is for this node.
+    /// Subclasses may want to override to implemnt mode complicated or longer physical addresses
+    /// \param [in] address Address of the pyysical addres being tested
+    /// \param [in] addresslen Lengthof the address in bytes
+    /// \return true if the physical address of this node is identical to address
+    virtual boolean isPhysicalAddress(uint8_t* address, uint8_t addresslen);
+
+private:
+    /// Temporary mesage buffer
+    static uint8_t _tmpMessage[RF22_ROUTER_MAX_MESSAGE_LEN];
+
+};
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RF22ReliableDatagram.cpp	Tue Feb 14 19:39:36 2012 +0000
@@ -0,0 +1,171 @@
+// RF22ReliableDatagram.cpp
+//
+// Define addressed datagram
+// 
+// Part of the Arduino RF22 library for operating with HopeRF RF22 compatible transceivers 
+// (see http://www.hoperf.com)
+// RF22Datagram will be received only by the addressed node or all nodes within range if the 
+// to address is RF22_BROADCAST_ADDRESS
+//
+// Author: Mike McCauley (mikem@open.com.au)
+// Copyright (C) 2011 Mike McCauley
+// $Id: RF22ReliableDatagram.cpp,v 1.8 2011/02/15 01:18:03 mikem Exp $
+// ported to mbed by Karl Zweimueller
+
+#include <RF22ReliableDatagram.h>
+//#include <SPI.h>
+
+
+////////////////////////////////////////////////////////////////////
+// Constructors
+RF22ReliableDatagram::RF22ReliableDatagram(uint8_t thisAddress ,PinName slaveSelectPin , PinName mosi, PinName miso, PinName sclk, PinName interrupt ) 
+    : RF22Datagram(thisAddress ,slaveSelectPin , mosi, miso, sclk, interrupt )
+{
+    _retransmissions = 0;
+    _lastSequenceNumber = 0;
+    _timeout = 200;
+    _retries = 3;
+}
+
+////////////////////////////////////////////////////////////////////
+// Public methods
+void RF22ReliableDatagram::setTimeout(uint16_t timeout)
+{
+    _timeout = timeout;
+}
+
+////////////////////////////////////////////////////////////////////
+void RF22ReliableDatagram::setRetries(uint8_t retries)
+{
+    _retries = retries;
+}
+
+////////////////////////////////////////////////////////////////////
+boolean RF22ReliableDatagram::sendtoWait(uint8_t* buf, uint8_t len, uint8_t address)
+{
+    // Assemble the message
+    uint8_t thisSequenceNumber = ++_lastSequenceNumber;
+
+    Timer t;
+    
+    uint8_t retries = 0;
+    while (retries++ <= _retries)
+    {
+    setHeaderId(thisSequenceNumber);
+    setHeaderFlags(0);
+    sendto(buf, len, address);
+    waitPacketSent();
+
+    // Never wait for ACKS to broadcasts:
+    if (address == RF22_BROADCAST_ADDRESS)
+        return true;
+
+    if (retries > 1)
+        _retransmissions++;
+    t.start();
+    unsigned long thisSendTime = t.read_ms(); // Timeout does not include original transmit time
+
+
+    // Compute a new timeout, random between _timeout and _timeout*2
+    // This is to prevent collissions on every retransmit
+    // if 2 nodes try to transmit at the same time
+    uint16_t timeout = _timeout + (_timeout * rand());
+    while (t.read_ms() < (thisSendTime + timeout))
+    {
+        if (available())
+        {
+        clearRxBuf(); // Not using recv, so clear it ourselves
+        uint8_t from = headerFrom();
+        uint8_t to = headerTo();
+        uint8_t id = headerId();
+        uint8_t flags = headerFlags();
+        // Now have a message: is it our ACK?
+        if (   from == address 
+            && to == _thisAddress 
+            && (flags & RF22_FLAGS_ACK) 
+            && (id == thisSequenceNumber))
+        {
+            // Its the ACK we are waiting for
+            return true;
+        }
+        else if (   !(flags & RF22_FLAGS_ACK)
+             && (id == _seenIds[from]))
+        {
+            // This is a request we have already received. ACK it again
+            acknowledge(id, from);
+        }
+        // Else discard it
+        }
+        // Not the one we are waiting for, maybe keep waiting until timeout exhausted
+    }
+    // Timeout exhausted, maybe retry
+    }
+    return false;
+}
+
+////////////////////////////////////////////////////////////////////
+boolean RF22ReliableDatagram::recvfromAck(uint8_t* buf, uint8_t* len, uint8_t* from, uint8_t* to, uint8_t* id, uint8_t* flags)
+{  
+    uint8_t _from;
+    uint8_t _to;
+    uint8_t _id;
+    uint8_t _flags;
+    // Get the message before its clobbered by the ACK (shared rx anfd tx buffer in RF22
+    if (available() && recvfrom(buf, len, &_from, &_to, &_id, &_flags))
+    {
+    // Never ACK an ACK
+    if (!(_flags & RF22_FLAGS_ACK))
+    {
+        // Its a normal message for this node, not an ACK
+        if (_to != RF22_BROADCAST_ADDRESS)
+        {
+        // Its not a broadcast, so ACK it
+        // Acknowledge message with ACK set in flags and ID set to received ID
+        acknowledge(_id, _from);
+        }
+        // If we have not seen this message before, then we are interested in it
+        if (_id != _seenIds[_from])
+        {
+        if (from)  *from =  _from;
+        if (to)    *to =    _to;
+        if (id)    *id =    _id;
+        if (flags) *flags = _flags;
+        _seenIds[_from] = _id;
+        return true;
+        }
+        // Else just re-ack it and wait for a new one
+    }
+    }
+    // No message for us available
+    return false;
+}
+
+boolean RF22ReliableDatagram::recvfromAckTimeout(uint8_t* buf, uint8_t* len, uint16_t timeout, uint8_t* from, uint8_t* to, uint8_t* id, uint8_t* flags)
+{  
+    Timer t;
+    unsigned long endtime = t.read_ms() + timeout;
+    while (t.read_ms() < endtime)
+    if (recvfromAck(buf, len, from, to, id, flags))
+        return true;
+    return false;
+}
+
+uint16_t RF22ReliableDatagram::retransmissions()
+{
+    return _retransmissions;
+}
+
+void RF22ReliableDatagram::acknowledge(uint8_t id, uint8_t from)
+{
+    setHeaderId(id);
+    setHeaderFlags(RF22_FLAGS_ACK);
+    // We would prefer to send a zero length ACK,
+    // but if an RF22 receives a 0 length message with a CRC error, it will never receive
+    // a 0 length message again, until its reset, which makes everything hang :-(
+    // So we send an ACK of 1 octet
+    // REVISIT: should we send the RSSI for the information of the sender?
+    uint8_t ack = '!';
+    sendto(&ack, sizeof(ack), from); 
+    waitPacketSent();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RF22ReliableDatagram.h	Tue Feb 14 19:39:36 2012 +0000
@@ -0,0 +1,151 @@
+// RF22ReliableDatagram.h
+//
+// Author: Mike McCauley (mikem@open.com.au)
+// Copyright (C) 2011 Mike McCauley
+// $Id: RF22ReliableDatagram.h,v 1.6 2011/02/15 01:18:03 mikem Exp $
+// ported to mbed by Karl Zweimueller
+
+#ifndef RF22ReliableDatagram_h
+#define RF22ReliableDatagram_h
+
+#include <RF22Datagram.h>
+
+// The acknowledgement bit in the FLAGS
+#define RF22_FLAGS_ACK 0x80
+
+/////////////////////////////////////////////////////////////////////
+/// \class RF22ReliableDatagram RF22ReliableDatagram.h <RF22ReliableDatagram.h>
+/// \brief RF22 subclass for sending addressed, acknowledged, retransmitted datagrams.
+///
+/// Extends RF22Datagram to define addressed, reliable datagrams with acknowledgement and retransmission.
+/// Based on RF22Datagram, adds flags and sequence numbers. RF22ReliableDatagram is reliable in the sense
+/// that messages are acknowledged, and unacknowledged messages are retransmitted until acknowledged or the
+/// retries are exhausted.
+/// When addressed messages are sent (by sendtoWait()), it will wait for an ack, and retransmit
+/// after timeout until an ack is received or retries are exhausted.
+/// When addressed messages are collected by the application (by recvfromAck()), 
+/// an acknowledgement is automatically sent.
+///
+/// The retransmit timeout is randomly varied between timeout and timeout*2 to prevent collisions on all
+/// retries when  2 nodes happen to start sending at the same time .
+///
+/// Each new message sent by sendtoWait() has its ID incremented.
+///
+/// An ack consists of a message with:
+/// - TO set to the from address of the original message
+/// - FROM set to this node address
+/// - ID set to the ID of the original message
+/// - FLAGS with the RF22_FLAGS_ACK bit set
+///
+/// Part of the Arduino RF22 library for operating with HopeRF RF22 compatible transceivers 
+/// (see http://www.hoperf.com)
+class RF22ReliableDatagram : public RF22Datagram
+{
+public:
+    /// Constructor. 
+    /// \param[in] thisAddress The address to assign to this node. Defaults to 0
+    /// \param[in] slaveSelectPin the Arduino pin number of the output to use to select the RF22 before
+    /// accessing it
+    /// \param[in] interrupt The interrupt number to use. Default is interrupt 0 (Arduino input pin 2)
+    RF22ReliableDatagram(uint8_t thisAddress ,PinName slaveSelectPin , PinName mosi, PinName miso, PinName sclk, PinName interrupt );
+
+    /// Sets the minimum retransmit timeout. If sendtoWait is waiting for an ack 
+    /// longer than this time (in milliseconds), 
+    /// it will retransmit the message. Defaults to 200ms. The timeout is measured from the end of
+    /// transmission of the message. It must be at least longer than the the transmit 
+    /// time of the acknowledgement (6 octets) plus the latency/poll time of the receiver. 
+    /// The actual timeout is randomly varied between timeout and timeout*2.
+    /// \param[in] timeout The new timeout period in milliseconds
+    void setTimeout(uint16_t timeout);
+
+    /// Sets the max number of retries. Defaults to 3. If set to 0, the message will only be sent once.
+    /// sendtoWait will give up and return false if there is no ack received after all transmissions time out.
+    /// param[in] retries The maximum number a retries.
+    void setRetries(uint8_t retries);
+
+    /// Send the message and waits for an ack. Returns true if an acknowledgement is received.
+    /// Synchronous: any message other than the desired ACK received while waiting is discarded.
+    /// Blocks until an ACK is received or all retries are exhausted (ie up to retries*timeout milliseconds).
+    /// \param[in] address The address to send the message to.
+    /// \param[in] buf Pointer to the binary message to send
+    /// \param[in] len Number of octets to send
+    /// \return true if the message was transmitted and an acknowledgement was received.
+    boolean sendtoWait(uint8_t* buf, uint8_t len, uint8_t address);
+
+    /// If there is a valid message available for this node, send an acknowledgement to the SRC
+    /// address (blocking until this is complete), then copy the message to buf and return true
+    /// else return false. 
+    /// If a message is copied, *len is set to the length..
+    /// If from is not NULL, the SRC address is placed in *from.
+    /// If to is not NULL, the DEST address is placed in *to.
+    /// This is the preferred function for getting messages addressed to this node.
+    /// If the message is not a broadcast, acknowledge to the sender before returning.
+    /// You should be sure to call this function frequently enough to not miss any messages
+    /// It is recommended that you call it in your main loop.
+    /// \param[in] buf Location to copy the received message
+    /// \param[in,out] len Available space in buf. Set to the actual number of octets copied.
+    /// \param[in] from If present and not NULL, the referenced uint8_t will be set to the SRC address
+    /// \param[in] to If present and not NULL, the referenced uint8_t will be set to the DEST address
+    /// \param[in] id If present and not NULL, the referenced uint8_t will be set to the ID
+    /// \param[in] flags If present and not NULL, the referenced uint8_t will be set to the FLAGS
+    /// (not just those addressed to this node).
+    /// \return true if a valid message was copied to buf
+    boolean recvfromAck(uint8_t* buf, uint8_t* len, uint8_t* from = NULL, uint8_t* to = NULL, uint8_t* id = NULL, uint8_t* flags = NULL);
+
+    /// Similar to recvfromAck(), this will block until either a valid message available for this node
+    /// or the timeout expires. Starts the receiver automatically.
+    /// You should be sure to call this function frequently enough to not miss any messages
+    /// It is recommended that you call it in your main loop.
+    /// \param[in] buf Location to copy the received message
+    /// \param[in,out] len Available space in buf. Set to the actual number of octets copied.
+    /// \param[in] timeout Maximum time to wait in milliseconds
+    /// \param[in] from If present and not NULL, the referenced uint8_t will be set to the SRC address
+    /// \param[in] to If present and not NULL, the referenced uint8_t will be set to the DEST address
+    /// \param[in] id If present and not NULL, the referenced uint8_t will be set to the ID
+    /// \param[in] flags If present and not NULL, the referenced uint8_t will be set to the FLAGS
+    /// (not just those addressed to this node).
+    /// \return true if a valid message was copied to buf
+    boolean recvfromAckTimeout(uint8_t* buf, uint8_t* len,  uint16_t timeout, uint8_t* from = NULL, uint8_t* to = NULL, uint8_t* id = NULL, uint8_t* flags = NULL);
+
+    /// Returns the number of retransmissions 
+    /// we have had to send
+    /// \return The number of retransmissions since initialisation.
+    uint16_t retransmissions();
+
+protected:
+    /// Send an ACK for the message id to the given from address
+    /// Blocks until the ACK has been sent
+    void acknowledge(uint8_t id, uint8_t from);
+
+    /// Checks whether the message currently in the Rx buffer is a new message, not previously received
+    /// based on the from address and the sequence.  If it is new, it is acknowledged and returns true
+    /// \return true if there is a message received and it is a new message
+    boolean haveNewMessage();
+
+private:
+    /// Count of retransmissions we have had to send
+    uint16_t _retransmissions;
+
+    /// The last sequence number to be used
+    /// Defaults to 0
+    uint8_t _lastSequenceNumber;
+
+    // Retransmit timeout (milliseconds)
+    /// Defaults to 200
+    uint16_t _timeout;
+
+    // Retries (0 means one try only)
+    /// Defaults to 3
+    uint8_t _retries;
+
+    /// Array of the last seen sequence number indexed by node address that sent it
+    /// It is used for duplicate detection. Duplicated messages are re-acknowledged when received 
+    /// (this is generally due to lost ACKs, causing the sender to retransmit, even though we have already
+    /// received that message)
+    uint8_t _seenIds[256];
+
+
+};
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RF22Router.cpp	Tue Feb 14 19:39:36 2012 +0000
@@ -0,0 +1,308 @@
+// RF22Router.cpp
+//
+// Define addressed datagram
+// 
+// Part of the Arduino RF22 library for operating with HopeRF RF22 compatible transceivers 
+// (see http://www.hoperf.com)
+// RF22Datagram will be received only by the addressed node or all nodes within range if the 
+// to address is RF22_BROADCAST_ADDRESS
+//
+// Author: Mike McCauley (mikem@open.com.au)
+// Copyright (C) 2011 Mike McCauley
+// $Id: RF22Router.cpp,v 1.6 2011/02/15 01:18:03 mikem Exp $
+// ported to mbed by Karl Zweimueller
+
+#include <mbed.h>
+#include <RF22Router.h>
+//#include <SPI.h>
+
+
+RF22Router::RoutedMessage RF22Router::_tmpMessage;
+
+////////////////////////////////////////////////////////////////////
+// Constructors
+RF22Router::RF22Router(uint8_t thisAddress ,PinName slaveSelectPin , PinName mosi, PinName miso, PinName sclk, PinName interrupt ) 
+    : RF22ReliableDatagram(thisAddress, slaveSelectPin, mosi,  miso, sclk, interrupt )
+{
+    _max_hops = RF22_DEFAULT_MAX_HOPS;
+    clearRoutingTable();
+}
+
+////////////////////////////////////////////////////////////////////
+// Public methods
+boolean RF22Router::init()
+{
+    boolean ret = RF22ReliableDatagram::init();
+    if (ret)
+    _max_hops = RF22_DEFAULT_MAX_HOPS;
+    return ret;
+}
+
+////////////////////////////////////////////////////////////////////
+void RF22Router::setMaxHops(uint8_t max_hops)
+{
+    _max_hops = max_hops;
+}
+
+////////////////////////////////////////////////////////////////////
+void RF22Router::addRouteTo(uint8_t dest, uint8_t next_hop, uint8_t state)
+{
+    uint8_t i;
+
+    // First look for an existing entry we can update
+    for (i = 0; i < RF22_ROUTING_TABLE_SIZE; i++)
+    {
+    if (_routes[i].dest == dest)
+    {
+        _routes[i].dest = dest;
+        _routes[i].next_hop = next_hop;
+        _routes[i].state = state;
+        return;
+    }
+    }
+
+    // Look for an invalid entry we can use
+    for (i = 0; i < RF22_ROUTING_TABLE_SIZE; i++)
+    {
+    if (_routes[i].state == Invalid)
+    {
+        _routes[i].dest = dest;
+        _routes[i].next_hop = next_hop;
+        _routes[i].state = state;
+        return;
+    }
+    }
+
+    // Need to make room for a new one
+    retireOldestRoute();
+    // Should be an invalid slot now
+    for (i = 0; i < RF22_ROUTING_TABLE_SIZE; i++)
+    {
+    if (_routes[i].state == Invalid)
+    {
+        _routes[i].dest = dest;
+        _routes[i].next_hop = next_hop;
+        _routes[i].state = state;
+    }
+    }
+}
+
+////////////////////////////////////////////////////////////////////
+RF22Router::RoutingTableEntry* RF22Router::getRouteTo(uint8_t dest)
+{
+    uint8_t i;
+    for (i = 0; i < RF22_ROUTING_TABLE_SIZE; i++)
+    if (_routes[i].dest == dest && _routes[i].state != Invalid)
+        return &_routes[i];
+    return NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+void RF22Router::deleteRoute(uint8_t index)
+{
+    // Delete a route by copying following routes on top of it
+    memcpy(&_routes[index], &_routes[index+1], 
+       sizeof(RoutingTableEntry) * (RF22_ROUTING_TABLE_SIZE - index - 1));
+    _routes[RF22_ROUTING_TABLE_SIZE - 1].state = Invalid;
+}
+
+#ifdef RF22_HAVE_SERIAL
+////////////////////////////////////////////////////////////////////
+void RF22Router::printRoutingTable()
+{
+    uint8_t i;
+    for (i = 0; i < RF22_ROUTING_TABLE_SIZE; i++)
+    {
+    Serial.print(i, DEC);
+    Serial.print(" Dest: ");
+    Serial.print(_routes[i].dest, DEC);
+    Serial.print(" Next Hop: ");
+    Serial.print(_routes[i].next_hop, DEC);
+    Serial.print(" State: ");
+    Serial.println(_routes[i].state, DEC);
+    }
+}
+#endif
+
+////////////////////////////////////////////////////////////////////
+boolean RF22Router::deleteRouteTo(uint8_t dest)
+{
+    uint8_t i;
+    for (i = 0; i < RF22_ROUTING_TABLE_SIZE; i++)
+    {
+    if (_routes[i].dest == dest)
+    {
+        deleteRoute(i);
+        return true;
+    }
+    }
+    return false;
+}
+
+////////////////////////////////////////////////////////////////////
+void RF22Router::retireOldestRoute()
+{
+    // We just obliterate the first in the table and clear the last
+    deleteRoute(0);
+}
+
+////////////////////////////////////////////////////////////////////
+void RF22Router::clearRoutingTable()
+{
+    uint8_t i;
+    for (i = 0; i < RF22_ROUTING_TABLE_SIZE; i++)
+    _routes[i].state = Invalid;
+}
+
+
+uint8_t RF22Router::sendtoWait(uint8_t* buf, uint8_t len, uint8_t dest)
+{
+    return sendtoWait(buf, len, dest, _thisAddress);
+}
+
+////////////////////////////////////////////////////////////////////
+// Waits for delivery to the next hop (but not for delivery to the final destination)
+uint8_t RF22Router::sendtoWait(uint8_t* buf, uint8_t len, uint8_t dest, uint8_t source)
+{
+    if (((uint16_t)len + sizeof(RoutedMessageHeader)) > RF22_MAX_MESSAGE_LEN)
+    return RF22_ROUTER_ERROR_INVALID_LENGTH;
+
+    // Construct a RF22 RouterMessage message
+    _tmpMessage.header.source = source;
+    _tmpMessage.header.dest = dest;
+    _tmpMessage.header.hops = 0;
+    _tmpMessage.header.id = _lastE2ESequenceNumber++;
+    _tmpMessage.header.flags = 0;
+    memcpy(_tmpMessage.data, buf, len);
+
+    return route(&_tmpMessage, sizeof(RoutedMessageHeader)+len);
+}
+
+////////////////////////////////////////////////////////////////////
+uint8_t RF22Router::route(RoutedMessage* message, uint8_t messageLen)
+{
+    // Reliably deliver it if possible. See if we have a route:
+    uint8_t next_hop = RF22_BROADCAST_ADDRESS;
+    if (message->header.dest != RF22_BROADCAST_ADDRESS)
+    {
+    RoutingTableEntry* route = getRouteTo(message->header.dest);
+    if (!route)
+        return RF22_ROUTER_ERROR_NO_ROUTE;
+    next_hop = route->next_hop;
+    }
+
+    if (!RF22ReliableDatagram::sendtoWait((uint8_t*)message, messageLen, next_hop))
+    return RF22_ROUTER_ERROR_UNABLE_TO_DELIVER;
+
+    return RF22_ROUTER_ERROR_NONE;
+}
+
+////////////////////////////////////////////////////////////////////
+// Subclasses may want to override this to peek at messages going past
+void RF22Router::peekAtMessage(RoutedMessage* message, uint8_t messageLen)
+{
+    // Default does nothing
+}
+
+////////////////////////////////////////////////////////////////////
+boolean RF22Router::recvfromAck(uint8_t* buf, uint8_t* len, uint8_t* source, uint8_t* dest, uint8_t* id, uint8_t* flags)
+{  
+    uint8_t tmpMessageLen = sizeof(_tmpMessage);
+    uint8_t _from;
+    uint8_t _to;
+    uint8_t _id;
+    uint8_t _flags;
+    if (RF22ReliableDatagram::recvfromAck((uint8_t*)&_tmpMessage, &tmpMessageLen, &_from, &_to, &_id, &_flags))
+    {
+    // Here we simulate networks with limited visibility between nodes
+    // so we can test routing
+#ifdef RF22_TEST_NETWORK
+    if (
+#if RF22_TEST_NETWORK==1
+    // This looks like 1-2-3-4
+           (_thisAddress == 1 && _from == 2)
+        || (_thisAddress == 2 && (_from == 1 || _from == 3))
+        || (_thisAddress == 3 && (_from == 2 || _from == 4))
+        || (_thisAddress == 4 && _from == 3)
+        
+#elif RF22_TEST_NETWORK==2
+           // This looks like 1-2-4
+           //                 | | |
+           //                 --3--
+           (_thisAddress == 1 && (_from == 2 || _from == 3))
+        ||  _thisAddress == 2
+        ||  _thisAddress == 3
+        || (_thisAddress == 4 && (_from == 2 || _from == 3))
+
+#elif RF22_TEST_NETWORK==3
+           // This looks like 1-2-4
+           //                 |   |
+           //                 --3--
+           (_thisAddress == 1 && (_from == 2 || _from == 3))
+        || (_thisAddress == 2 && (_from == 1 || _from == 4))
+        || (_thisAddress == 3 && (_from == 1 || _from == 4))
+        || (_thisAddress == 4 && (_from == 2 || _from == 3))
+
+#elif RF22_TEST_NETWORK==4
+           // This looks like 1-2-3
+           //                   |
+           //                   4
+           (_thisAddress == 1 && _from == 2)
+        ||  _thisAddress == 2
+        || (_thisAddress == 3 && _from == 2)
+        || (_thisAddress == 4 && _from == 2)
+
+#endif
+)
+    {
+        // OK
+    }
+    else
+    {
+        return false; // Pretend we got nothing
+    }
+#endif
+
+    peekAtMessage(&_tmpMessage, tmpMessageLen);
+    // See if its for us or has to be routed
+    if (_tmpMessage.header.dest == _thisAddress || _tmpMessage.header.dest == RF22_BROADCAST_ADDRESS)
+    {
+        // Deliver it here
+        if (source) *source  = _tmpMessage.header.source;
+        if (dest)   *dest    = _tmpMessage.header.dest;
+        if (id)     *id      = _tmpMessage.header.id;
+        if (flags)  *flags   = _tmpMessage.header.flags;
+        uint8_t msgLen = tmpMessageLen - sizeof(RoutedMessageHeader);
+        if (*len > msgLen)
+        *len = msgLen;
+        memcpy(buf, _tmpMessage.data, *len);
+        return true; // Its for you!
+    }
+    else if (   _tmpMessage.header.dest != RF22_BROADCAST_ADDRESS
+         && _tmpMessage.header.hops++ < _max_hops)
+    {
+        // Maybe it has to be routed to the next hop
+        // REVISIT: if it fails due to no route or unable to deliver to the next hop, 
+        // tell the originator. BUT HOW?
+        route(&_tmpMessage, tmpMessageLen);
+    }
+    // Discard it and maybe wait for another
+    }
+    return false;
+}
+
+////////////////////////////////////////////////////////////////////
+boolean RF22Router::recvfromAckTimeout(uint8_t* buf, uint8_t* len, uint16_t timeout, uint8_t* source, uint8_t* dest, uint8_t* id, uint8_t* flags)
+{   
+    Timer t;
+    
+    t.start();
+    unsigned long endtime = t.read_ms() + timeout;
+    while (t.read_ms() < endtime)
+    {
+    if (recvfromAck(buf, len, source, dest, id, flags))
+        return true;
+    }
+    return false;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RF22Router.h	Tue Feb 14 19:39:36 2012 +0000
@@ -0,0 +1,326 @@
+// RF22Router.h
+//
+// Author: Mike McCauley (mikem@open.com.au)
+// Copyright (C) 2011 Mike McCauley
+// $Id: RF22Router.h,v 1.7 2011/02/15 01:18:03 mikem Exp $
+// ported to mbed by Karl Zweimueller
+
+#ifndef RF22Router_h
+#define RF22Router_h
+
+#include <RF22ReliableDatagram.h>
+
+// Default max number of hops we will route
+#define RF22_DEFAULT_MAX_HOPS 30
+
+// The default size of the routing table we keep
+#define RF22_ROUTING_TABLE_SIZE 10
+
+// Error codes
+#define RF22_ROUTER_ERROR_NONE              0
+#define RF22_ROUTER_ERROR_INVALID_LENGTH    1
+#define RF22_ROUTER_ERROR_NO_ROUTE          2
+#define RF22_ROUTER_ERROR_TIMEOUT           3
+#define RF22_ROUTER_ERROR_NO_REPLY          4
+#define RF22_ROUTER_ERROR_UNABLE_TO_DELIVER 5
+
+// This size of RF22_ROUTER_MAX_MESSAGE_LEN is OK for Arduino Mega, but too big for
+// Duemilanova. Size of 50 works with the sample router programs on Duemilanova.
+#define RF22_ROUTER_MAX_MESSAGE_LEN (RF22_MAX_MESSAGE_LEN - sizeof(RF22Router::RoutedMessageHeader))
+//#define RF22_ROUTER_MAX_MESSAGE_LEN 50
+
+// These allow us to define a simulated network topology for testing purposes
+// See RF22Router.cpp for details
+//#define RF22_TEST_NETWORK 1
+//#define RF22_TEST_NETWORK 2
+//#define RF22_TEST_NETWORK 3
+//#define RF22_TEST_NETWORK 4
+
+/////////////////////////////////////////////////////////////////////
+/// \class RF22Router RF22Router.h <RF22Router.h>
+/// \brief RF22 subclass for sending addressed, optionally acknowledged datagrams
+/// multi-hop routed across a network.
+///
+/// Extends RF22ReliableDatagram to define addressed messages
+/// That are reliably transmitted and routed across a network. Each message is transmitted reliably 
+/// between each hop in order to get from the source node to the destination node.
+///
+/// With RF22Router, routes are hard wired. This means that each node must have programmed 
+/// in it how to reach each of the other nodes it will be trying to communicate with. 
+/// This means you must specify the next-hop node address for each of the destination nodes, 
+/// using the addRouteTo() function. 
+///
+/// When sendtoWait() is called with a new message to deliver, and the destination address,
+/// RF22Router looks up the next hop node for the destination node. It then uses 
+/// RF22ReliableDatagram to (reliably) deliver the message to the next hop 
+/// (which is expected also to be running an RF22Router). If that next-hop node is not
+/// the final destination, it will also look up the next hop for the destination node and 
+/// (reliably) deliver the message to the next hop. By this method, messages can be delivered 
+/// across a network of nodes, even if each node cannot hear all of the others in the network.
+/// Each time a message is received for another node and retransmitted to the next hop, 
+/// the HOPS filed in teh header is incremented. If a message is received for routing to another node 
+/// which has exceed the routers max_hops, the message wioll be dropped and ignored. 
+/// This helps prevent infinite routing loops.
+///
+/// RF22Router supports messages with a dest of RF22_BROADCAST_ADDRESS. Such messages are not routed, 
+/// and are broadcast (once) to all nodes within range.
+///
+/// The recvfromAck() function is responsible not just for receiving and delivering 
+/// messages addressed to this node (or RF22_BROADCAST_ADDRESS), but 
+/// it is also responsible for routing other message to their next hop. This means that it is important to 
+/// call recvfromAck() or recvfromAckTimeout() frequently in your main loop. recvfromAck() will return 
+/// false if it receives a message but it is not for this node.
+///
+/// RF22Router does not provide reliable end-to-end delivery, but uses reliable hop-to-hop delivery. 
+/// If a message is unable to be delivered to an end node during to a delivery failure between 2 hops, 
+/// the source node will not be told about it.
+///
+/// Note: This class is most useful for networks of nodes that are essentially static 
+/// (i.e. the nodes dont move around), and for which the 
+/// routing never changes. If that is not the case for your proposed network, see RF22Mesh instead.
+///
+/// \par The Routing Table
+///
+/// The routing table is a local table in RF22Router that holds the information about the next hop node 
+/// address for each destination address you may want to send a message to. It is your responsibility 
+/// to make sure every node in an RF22Router network has been configured with a unique address and the 
+/// routing information so that messages are correctly routed across the network from source node to 
+/// destination node. This is usually done once in setup() by calling addRouteTo(). 
+/// The hardwired routing will in general be different on each node, and will depend on the physical 
+/// topololgy of the network.
+/// You can also use addRouteTo() to change a route and 
+/// deleteRouteTo() to delete a route at run time. Youcan also clear the entire routing table
+///
+/// The Routing Table has limited capacity for entries (defined by RF22_ROUTING_TABLE_SIZE, which is 10)
+/// if more than RF22_ROUTING_TABLE_SIZE are added, the oldest (first) one will be removed by calling 
+/// retireOldestRoute()
+///
+/// \par Message Format
+///
+/// RF22Router add to the lower level RF22ReliableDatagram (and even lower level RF22) class mesage formats. 
+/// In those lower level classes, the hop-to-hop message headers are in the RF22 message headers, 
+/// and are handled automcatically by tyhe RF22 hardware.
+/// RF22Router and its subclasses add an end-to-end addressing header in the payload of the RF22 message, 
+/// and before the RF22Router application data.
+/// - 1 octet DEST, the destination node address (ie the address of the final 
+///   destination node for this message)
+/// - 1 octet SOURCE, the source node address (ie the address of the originating node that first sent 
+///   the message).
+/// - 1 octet HOPS, the number of hops this message has traversed so far.
+/// - 1 octet ID, an incrementing message ID for end-to-end message tracking for use by subclasses. 
+///   Not used by RF22Router.
+/// - 1 octet FLAGS, a bitmask for use by subclasses. Not used by RF22Router.
+/// - 0 or more octets DATA, the application payload data. The length of this data is implicit 
+///   in the length of the entire message.
+///
+/// You should be careful to note that there are ID and FLAGS fields in the low level per-hop 
+/// message header too. These are used only for hop-to-hop, and in general will be different to 
+/// the ones at the RF22Router level.
+///
+/// \par Testing
+///
+/// Bench testing of such networks is notoriously difficult, especially simulating limited radio 
+/// connectivity between some nodes.
+/// To assist testing (both during RF22 development and for your own networks) 
+/// RF22Router.cpp has the ability to 
+/// simulate a number of different small network topologies. Each simulated network supports 4 nodes with 
+/// addresses 1 to 4. It operates by pretending to not hear RF22 messages from certain other nodes.
+/// You can enable testing with a \#define TEST_NETWORK in RF22Router.h
+/// The sample programs rf22_mesh_* rely on this feature.
+///
+/// Part of the Arduino RF22 library for operating with HopeRF RF22 compatible transceivers 
+/// (see http://www.hoperf.com)
+class RF22Router : public RF22ReliableDatagram
+{
+public:
+
+    /// Defines the structure of the RF22Router message header, used to keep track of end-to-end delivery
+    /// parameters
+    typedef struct
+    {
+    uint8_t    dest;       ///< Destination node address
+    uint8_t    source;     ///< Originator node address
+    uint8_t    hops;       ///< Hops traversed so far
+    uint8_t    id;         ///< Originator sequence number
+    uint8_t    flags;      ///< Originator flags
+    // Data follows, Length is implicit in the overall message length
+    } RoutedMessageHeader;
+
+    /// Defines the structure of a RF22Router message
+    typedef struct
+    {
+    RoutedMessageHeader header;    ///< end-to-end delivery header
+    uint8_t             data[RF22_ROUTER_MAX_MESSAGE_LEN]; ///< Applicaiton payload data
+    } RoutedMessage;
+
+    /// Values for the possible states for routes
+    typedef enum
+    {
+    Invalid = 0,           ///< No valid route is known
+    Discovering,           ///< Discovering a route (not currently used)
+    Valid                  ///< Route is valid
+    } RouteState;
+
+    /// Defines an entry in the routing table
+    typedef struct
+    {
+    uint8_t      dest;      ///< Destination node address
+    uint8_t      next_hop;  ///< Send via this next hop address
+    uint8_t      state;     ///< State of this route, one of RouteState
+    } RoutingTableEntry;
+
+    /// Constructor. 
+    /// \param[in] thisAddress The address to assign to this node. Defaults to 0
+    /// \param[in] slaveSelectPin the Arduino pin number of the output to use to select the RF22 before
+    /// accessing it
+    /// \param[in] interrupt The interrupt number to use. Default is interrupt 0 (Arduino input pin 2)
+    //RF22Router(uint8_t thisAddress = 0, uint8_t slaveSelectPin = 10, uint8_t interrupt = 0);
+    RF22Router(uint8_t thisAddress ,PinName slaveSelectPin , PinName mosi, PinName miso, PinName sclk, PinName interrupt );
+    /// Initialises this instance and the radio module connected to it.
+    /// Overrides the init() function in RF22.
+    /// Sets max_hops to the default of RF22_DEFAULT_MAX_HOPS (30)
+    boolean init();
+
+    /// Sets the max_hops to the given value
+    /// This controls the maximum number of hops allowed between source and destination nodes
+    /// Messages that are not delivered by the time their HOPS field exceeds max_hops on a 
+    /// routing node will be dropped and ignored.
+    /// \param [in] max_hops The new value for max_hops
+    void setMaxHops(uint8_t max_hops);
+
+    /// Adds a route to the local routing table, or updates it if already present.
+    /// If there is not enough room the oldest (first) route will be deleted by calling retireOldestRoute().
+    /// \param [in] dest The destination node address. RF22_BROADCAST_ADDRESS is permitted.
+    /// \param [in] next_hop The address of the next hop to send messages destined for dest
+    /// \param [in] state The satte of the route. Defaults to Valid
+    void addRouteTo(uint8_t dest, uint8_t next_hop, uint8_t state = Valid);
+
+    /// Finds and returns a RoutingTableEntry for the given destination node
+    /// \param [in] dest The desired destination node address.
+    /// \return pointer to a RoutingTableEntry for dest
+    RoutingTableEntry* getRouteTo(uint8_t dest);
+
+    /// Deletes from the local routing table any route for the destination node.
+    /// \param [in] dest The destination node address
+    /// \return true if the route was present
+    boolean deleteRouteTo(uint8_t dest);
+
+    /// Deletes the oldest (first) route from the 
+    /// local routing table
+    void retireOldestRoute();
+
+    /// Clears all entries from the 
+    /// local routing table
+    void clearRoutingTable();
+
+#ifdef RF22_HAVE_SERIAL
+    /// If RF22_HAVE_SERIAL is defined, this will print out the contents of the local 
+    /// routing table using Serial
+    void printRoutingTable();
+#endif
+
+    /// Sends a message to the destination node. Initialises the RF22Router message header 
+    /// (the SOURCE address is set to the address of this node, HOPS to 0) and calls 
+    /// route() which looks up in the routing table the next hop to deliver to and sends the 
+    /// message to the next hop. Waits for an acknowledgement from the next hop 
+    /// (but not from the destination node (if that is different).
+    /// \param [in] buf The application message data
+    /// \param [in] len Number of octets in the application message data. 0 is permitted
+    /// \param [in] dest The destination node address
+    /// \return The result code:
+    ///         - RF22_ROUTER_ERROR_NONE Message was routed and deliverd to the next hop 
+    ///           (not necessarily to the final dest address)
+    ///         - RF22_ROUTER_ERROR_NO_ROUTE There was no route for dest in the local routing table
+    ///         - RF22_ROUTER_ERROR_UNABLE_TO_DELIVER Noyt able to deliver to the next hop 
+    ///           (usually because it dod not acknowledge due to being off the air or out of range
+    uint8_t sendtoWait(uint8_t* buf, uint8_t len, uint8_t dest);
+
+    /// Similar to sendtoWait() above, but spoofs the source address.
+    /// For internal use only during routing
+    /// \param [in] buf The application message data
+    /// \param [in] len Number of octets in the application message data. 0 is permitted
+    /// \param [in] dest The destination node address
+    /// \param [in] source The (fake) originatong node address.
+    /// \return The result code:
+    ///         - RF22_ROUTER_ERROR_NONE Message was routed and deliverd to the next hop 
+    ///           (not necessarily to the final dest address)
+    ///         - RF22_ROUTER_ERROR_NO_ROUTE There was no route for dest in the local routing table
+    ///         - RF22_ROUTER_ERROR_UNABLE_TO_DELIVER Noyt able to deliver to the next hop 
+    ///           (usually because it dod not acknowledge due to being off the air or out of range
+    uint8_t sendtoWait(uint8_t* buf, uint8_t len, uint8_t dest, uint8_t source);
+
+    /// Starts the receiver if it is not running already.
+    /// If there is a valid message available for this node (or RF22_BROADCAST_ADDRESS), 
+    /// send an acknowledgement to the last hop
+    /// address (blocking until this is complete), then copy the application message payload data
+    /// to buf and return true
+    /// else return false. 
+    /// If a message is copied, *len is set to the length..
+    /// If from is not NULL, the originator SOURCE address is placed in *source.
+    /// If to is not NULL, the DEST address is placed in *dest. This might be this nodes address or 
+    /// RF22_BROADCAST_ADDRESS. 
+    /// This is the preferred function for getting messages addressed to this node.
+    /// If the message is not a broadcast, acknowledge to the sender before returning.
+    /// \param[in] buf Location to copy the received message
+    /// \param[in,out] len Available space in buf. Set to the actual number of octets copied.
+    /// \param[in] source If present and not NULL, the referenced uint8_t will be set to the SOURCE address
+    /// \param[in] dest If present and not NULL, the referenced uint8_t will be set to the DEST address
+    /// \param[in] id If present and not NULL, the referenced uint8_t will be set to the ID
+    /// \param[in] flags If present and not NULL, the referenced uint8_t will be set to the FLAGS
+    /// (not just those addressed to this node).
+    /// \return true if a valid message was recvived for this node copied to buf
+    boolean recvfromAck(uint8_t* buf, uint8_t* len, uint8_t* source = NULL, uint8_t* dest = NULL, uint8_t* id = NULL, uint8_t* flags = NULL);
+
+    /// Starts the receiver if it is not running already.
+    /// Similar to recvfromAck(), this will block until either a valid message available for this node
+    /// or the timeout expires. 
+    /// \param[in] buf Location to copy the received message
+    /// \param[in,out] len Available space in buf. Set to the actual number of octets copied.
+    /// \param[in] timeout Maximum time to wait in milliseconds
+    /// \param[in] source If present and not NULL, the referenced uint8_t will be set to the SOURCE address
+    /// \param[in] dest If present and not NULL, the referenced uint8_t will be set to the DEST address
+    /// \param[in] id If present and not NULL, the referenced uint8_t will be set to the ID
+    /// \param[in] flags If present and not NULL, the referenced uint8_t will be set to the FLAGS
+    /// (not just those addressed to this node).
+    /// \return true if a valid message was copied to buf
+    boolean recvfromAckTimeout(uint8_t* buf, uint8_t* len,  uint16_t timeout, uint8_t* source = NULL, uint8_t* dest = NULL, uint8_t* id = NULL, uint8_t* flags = NULL);
+
+protected:
+
+    /// Lets sublasses peek at messages going 
+    /// past before routing or local delivery.
+    /// Called by recvfromAck() immediately after it gets the message from RF22ReliableDatagram
+    /// \param [in] message Pointer to the RF22Router message that was received.
+    /// \param [in] messageLen Length of message in octets
+    virtual void peekAtMessage(RoutedMessage* message, uint8_t messageLen);
+
+    /// Finds the next-hop route and sends the message via RF22ReliableDatagram::sendtoWait().
+    /// This is virtual, which lets subclasses override or intercept the route() function.
+    /// Called by sendtoWait after the message header has been filled in.
+    /// \param [in] message Pointer to the RF22Router message to be sent.
+    /// \param [in] messageLen Length of message in octets
+    virtual uint8_t route(RoutedMessage* message, uint8_t messageLen);
+
+    /// Deletes a specific rout entry from therouting table
+    /// \param [in] index The 0 based index of the routing table entry to delete
+    void deleteRoute(uint8_t index);
+
+    /// The last end-to-end sequence number to be used
+    /// Defaults to 0
+    uint8_t _lastE2ESequenceNumber;
+
+    /// The maximum number of hops permitted in routed messages.
+    /// If a routed message would exceed this number of hops it is dropped and ignored.
+    uint8_t              _max_hops;
+
+private:
+
+    /// Temporary mesage buffer
+    static RoutedMessage _tmpMessage;
+
+    /// Local routing table
+    RoutingTableEntry    _routes[RF22_ROUTING_TABLE_SIZE];
+};
+
+#endif
+