Revision 0:e16ffa7cb900, committed 2012-07-02
- Comitter:
- SangSTBK
- Date:
- Mon Jul 02 01:29:58 2012 +0000
- Commit message:
- RF
Changed in this revision
diff -r 000000000000 -r e16ffa7cb900 RF22.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/RF22.cpp Mon Jul 02 01:29:58 2012 +0000
@@ -0,0 +1,654 @@
+// 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);
+
+// Set the AFC for receiver to max. 0,1MHz
+// Other AFC-Registers have PowerOnValues which enable AFC
+// RF22_AFC_LIMIT 0x50 =0,1MHz
+ spiWrite(RF22_REG_2A_AFC_LIMITER, RF22_AFC_LIMIT); // POR=0x00 = OFF
+
+ return true;
+}
+
+void RF22::handleInterrupt()
+{
+ led1 = !led1;
+ receive_data = spiRead(0x7f);
+ resetFifos();
+ status_03 = spiRead(0x03);
+
+ spiRead(0x04);
+ spiWrite(RF22_REG_05_INTERRUPT_ENABLE1, RF22_ENTXFFAEM | RF22_ENRXFFAFULL | RF22_ENPKSENT | RF22_ENPKVALID | RF22_ENCRCERROR | RF22_ENFFERR);
+ spiWrite(0x3e, 1);
+ spiWrite(0x07, 5);
+ //pc.printf("ch = %d",ch);
+
+}
+// C++ level interrupt handler for this instance
+
+
+// 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);
+}
diff -r 000000000000 -r e16ffa7cb900 RF22.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/RF22.h Mon Jul 02 01:29:58 2012 +0000
@@ -0,0 +1,1026 @@
+// 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();
+ char status_03;
+ char receive_data ;
+
+ /// 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
diff -r 000000000000 -r e16ffa7cb900 RF22Datagram.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/RF22Datagram.cpp Mon Jul 02 01:29:58 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);
+}
+
+
+
diff -r 000000000000 -r e16ffa7cb900 RF22Datagram.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/RF22Datagram.h Mon Jul 02 01:29:58 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
diff -r 000000000000 -r e16ffa7cb900 RF22Mesh.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/RF22Mesh.cpp Mon Jul 02 01:29:58 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;
+}
+
+
+
diff -r 000000000000 -r e16ffa7cb900 RF22Mesh.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/RF22Mesh.h Mon Jul 02 01:29:58 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
+
diff -r 000000000000 -r e16ffa7cb900 RF22ReliableDatagram.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/RF22ReliableDatagram.cpp Mon Jul 02 01:29:58 2012 +0000
@@ -0,0 +1,153 @@
+// 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() % 100) / 100);
+ 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();
+}
+
diff -r 000000000000 -r e16ffa7cb900 RF22ReliableDatagram.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/RF22ReliableDatagram.h Mon Jul 02 01:29:58 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
+
diff -r 000000000000 -r e16ffa7cb900 RF22Router.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/RF22Router.cpp Mon Jul 02 01:29:58 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;
+}
+
diff -r 000000000000 -r e16ffa7cb900 RF22Router.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/RF22Router.h Mon Jul 02 01:29:58 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
+