David Rimer / RadioHead-148
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers RH_RF24.cpp Source File

RH_RF24.cpp

00001 // RH_RF24.cpp
00002 //
00003 // Copyright (C) 2011 Mike McCauley
00004 // $Id: RH_RF24.cpp,v 1.14 2015/08/13 02:45:47 mikem Exp $
00005 
00006 #include <RH_RF24.h>
00007 // Generated with Silicon Labs WDS software:
00008 #include "radio_config_Si4460.h"
00009 
00010 // Interrupt vectors for the 3 Arduino interrupt pins
00011 // Each interrupt can be handled by a different instance of RH_RF24, allowing you to have
00012 // 2 or more RF24s per Arduino
00013 RH_RF24* RH_RF24::_deviceForInterrupt[RH_RF24_NUM_INTERRUPTS] = {0, 0, 0};
00014 uint8_t RH_RF24::_interruptCount = 0; // Index into _deviceForInterrupt for next device
00015 
00016 // This configuration data is defined in radio_config_Si4460.h 
00017 // which was generated with the Silicon Labs WDS program
00018 PROGMEM const uint8_t RFM26_CONFIGURATION_DATA[] = RADIO_CONFIGURATION_DATA_ARRAY;
00019 
00020 // These configurations were all generated originally by the Silicon LAbs WDS configuration tool.
00021 // The configurations were imported into RH_RF24, the complete properties set dumped to a file with printRegisters, then 
00022 // RH_RF24_property_data/convert.pl was used to generate the entry for this table.
00023 // Contributions of new complete and tested ModemConfigs ready to add to this list will be readily accepted.
00024 // Casual suggestions of new schemes without working examples will probably be passed over
00025 PROGMEM static const RH_RF24::ModemConfig MODEM_CONFIG_TABLE[] =
00026 {
00027     // These were generated with convert.pl from data in RH_RF24_property_data
00028     // FSK_Rb0_5Fd1
00029     { 0x02, 0x00, 0x13, 0x88, 0x01, 0x00, 0x00, 0x46, 0x01, 0x34, 0x11, 0x02, 0x71, 0x00, 0xd1, 0xb7, 0x00, 0x69, 0x02, 0x36, 0x80, 0x01, 0x5a, 0xfc, 0xe2, 0x11, 0x89, 0x89, 0x00, 0x02, 0xff, 0xff, 0x00, 0x2b, 0x02, 0x81, 0x00, 0xad, 0x3a, 0xff, 0xba, 0x0f, 0x51, 0xcf, 0xa9, 0xc9, 0xfc, 0x1b, 0x1e, 0x0f, 0x01, 0xfc, 0xfd, 0x15, 0xff, 0x00, 0x0f, 0xff, 0xba, 0x0f, 0x51, 0xcf, 0xa9, 0xc9, 0xfc, 0x1b, 0x1e, 0x0f, 0x01, 0xfc, 0xfd, 0x15, 0xff, 0x00, 0x0f, 0x3f, 0x2c, 0x0e, 0x04, 0x0c, 0x73, },
00030 
00031     // FSK_Rb5Fd10
00032     { 0x02, 0x00, 0xc3, 0x50, 0x01, 0x00, 0x02, 0xbb, 0x01, 0x30, 0x20, 0x01, 0x77, 0x01, 0x5d, 0x86, 0x00, 0xaf, 0x02, 0x36, 0x80, 0x0f, 0x15, 0x87, 0xe2, 0x11, 0x52, 0x52, 0x00, 0x02, 0xff, 0xff, 0x00, 0x2a, 0x02, 0x83, 0x01, 0x20, 0x40, 0xff, 0xba, 0x0f, 0x51, 0xcf, 0xa9, 0xc9, 0xfc, 0x1b, 0x1e, 0x0f, 0x01, 0xfc, 0xfd, 0x15, 0xff, 0x00, 0x0f, 0xff, 0xba, 0x0f, 0x51, 0xcf, 0xa9, 0xc9, 0xfc, 0x1b, 0x1e, 0x0f, 0x01, 0xfc, 0xfd, 0x15, 0xff, 0x00, 0x0f, 0x3f, 0x2c, 0x0e, 0x04, 0x0c, 0x73, },
00033 
00034     // FSK_Rb50Fd100
00035     { 0x02, 0x07, 0xa1, 0x20, 0x01, 0x00, 0x1b, 0x4f, 0x01, 0x00, 0x10, 0x00, 0xc8, 0x02, 0x8f, 0x5c, 0x01, 0x48, 0x02, 0x36, 0x80, 0x92, 0x0a, 0x46, 0xe2, 0x11, 0x2c, 0x2c, 0x00, 0x02, 0xff, 0xff, 0x00, 0x29, 0x02, 0x83, 0x02, 0x7f, 0x40, 0xff, 0xc4, 0x30, 0x7f, 0xf5, 0xb5, 0xb8, 0xde, 0x05, 0x17, 0x16, 0x0c, 0x03, 0x00, 0x15, 0xff, 0x00, 0x00, 0xff, 0xc4, 0x30, 0x7f, 0xf5, 0xb5, 0xb8, 0xde, 0x05, 0x17, 0x16, 0x0c, 0x03, 0x00, 0x15, 0xff, 0x00, 0x00, 0x3f, 0x2c, 0x0e, 0x04, 0x0c, 0x73, },
00036   
00037     //FSK_Rb150Fd300
00038     { 0x02, 0x16, 0xe3, 0x60, 0x01, 0x00, 0x51, 0xec, 0x01, 0x00, 0x30, 0x00, 0xc8, 0x02, 0x8f, 0x5c, 0x01, 0x48, 0x02, 0x47, 0x83, 0x6a, 0x04, 0xb5, 0xe2, 0x22, 0x16, 0x16, 0x00, 0x02, 0xff, 0xff, 0x00, 0x29, 0x02, 0x83, 0x02, 0x7f, 0x40, 0xff, 0xc4, 0x30, 0x7f, 0xf5, 0xb5, 0xb8, 0xde, 0x05, 0x17, 0x16, 0x0c, 0x03, 0x00, 0x15, 0xff, 0x00, 0x00, 0xff, 0xc4, 0x30, 0x7f, 0xf5, 0xb5, 0xb8, 0xde, 0x05, 0x17, 0x16, 0x0c, 0x03, 0x00, 0x15, 0xff, 0x00, 0x00, 0x3f, 0x39, 0x04, 0x05, 0x04, 0x01, },
00039 
00040     // GFSK_Rb0_5Fd1
00041     { 0x03, 0x00, 0x4e, 0x20, 0x05, 0x00, 0x00, 0x46, 0x01, 0x34, 0x11, 0x02, 0x71, 0x00, 0xd1, 0xb7, 0x00, 0x69, 0x02, 0x36, 0x80, 0x01, 0x5a, 0xfc, 0xe2, 0x11, 0x89, 0x89, 0x00, 0x1a, 0xff, 0xff, 0x00, 0x2b, 0x02, 0x81, 0x00, 0x68, 0x3a, 0xff, 0xba, 0x0f, 0x51, 0xcf, 0xa9, 0xc9, 0xfc, 0x1b, 0x1e, 0x0f, 0x01, 0xfc, 0xfd, 0x15, 0xff, 0x00, 0x0f, 0xff, 0xba, 0x0f, 0x51, 0xcf, 0xa9, 0xc9, 0xfc, 0x1b, 0x1e, 0x0f, 0x01, 0xfc, 0xfd, 0x15, 0xff, 0x00, 0x0f, 0x3f, 0x2c, 0x0e, 0x04, 0x0c, 0x73, },
00042 
00043     // GFSK_Rb5Fd10
00044     { 0x03, 0x03, 0x0d, 0x40, 0x05, 0x00, 0x02, 0xbb, 0x01, 0x30, 0x20, 0x01, 0x77, 0x01, 0x5d, 0x86, 0x00, 0xaf, 0x02, 0x36, 0x80, 0x0f, 0x15, 0x87, 0xe2, 0x11, 0x52, 0x52, 0x00, 0x1a, 0xff, 0xff, 0x00, 0x2a, 0x02, 0x83, 0x00, 0xad, 0x40, 0xff, 0xba, 0x0f, 0x51, 0xcf, 0xa9, 0xc9, 0xfc, 0x1b, 0x1e, 0x0f, 0x01, 0xfc, 0xfd, 0x15, 0xff, 0x00, 0x0f, 0xff, 0xba, 0x0f, 0x51, 0xcf, 0xa9, 0xc9, 0xfc, 0x1b, 0x1e, 0x0f, 0x01, 0xfc, 0xfd, 0x15, 0xff, 0x00, 0x0f, 0x3f, 0x2c, 0x0e, 0x04, 0x0c, 0x73, },
00045 
00046     // GFSK_Rb50Fd100
00047     { 0x03, 0x0f, 0x42, 0x40, 0x09, 0x00, 0x1b, 0x4f, 0x01, 0x00, 0x10, 0x00, 0xc8, 0x02, 0x8f, 0x5c, 0x01, 0x48, 0x02, 0x36, 0x80, 0x92, 0x0a, 0x46, 0xe2, 0x11, 0x2c, 0x2c, 0x00, 0x1a, 0xff, 0xff, 0x00, 0x29, 0x02, 0x83, 0x01, 0x7f, 0x40, 0xff, 0xc4, 0x30, 0x7f, 0xf5, 0xb5, 0xb8, 0xde, 0x05, 0x17, 0x16, 0x0c, 0x03, 0x00, 0x15, 0xff, 0x00, 0x00, 0xff, 0xc4, 0x30, 0x7f, 0xf5, 0xb5, 0xb8, 0xde, 0x05, 0x17, 0x16, 0x0c, 0x03, 0x00, 0x15, 0xff, 0x00, 0x00, 0x3f, 0x2c, 0x0e, 0x04, 0x0c, 0x73, },
00048 
00049     // GFSK_Rb150Fd300
00050     { 0x03, 0x2d, 0xc6, 0xc0, 0x09, 0x00, 0x51, 0xec, 0x01, 0x00, 0x30, 0x00, 0xc8, 0x02, 0x8f, 0x5c, 0x01, 0x48, 0x02, 0x47, 0x83, 0x6a, 0x04, 0xb5, 0xe2, 0x22, 0x16, 0x16, 0x00, 0x1a, 0xff, 0xff, 0x00, 0x29, 0x02, 0x83, 0x01, 0x7f, 0x40, 0xff, 0xc4, 0x30, 0x7f, 0xf5, 0xb5, 0xb8, 0xde, 0x05, 0x17, 0x16, 0x0c, 0x03, 0x00, 0x15, 0xff, 0x00, 0x00, 0xff, 0xc4, 0x30, 0x7f, 0xf5, 0xb5, 0xb8, 0xde, 0x05, 0x17, 0x16, 0x0c, 0x03, 0x00, 0x15, 0xff, 0x00, 0x00, 0x3f, 0x39, 0x04, 0x05, 0x04, 0x01, },
00051 
00052     // OOK_Rb5Bw30
00053     { 0x01, 0x00, 0xc3, 0x50, 0x01, 0x00, 0x00, 0x00, 0x00, 0x34, 0x10, 0x00, 0x3f, 0x08, 0x31, 0x27, 0x04, 0x10, 0x02, 0x12, 0x00, 0x2c, 0x03, 0xf9, 0x62, 0x11, 0x0e, 0x0e, 0x00, 0x02, 0xff, 0xff, 0x00, 0x27, 0x00, 0x00, 0x07, 0xff, 0x40, 0xcc, 0xa1, 0x30, 0xa0, 0x21, 0xd1, 0xb9, 0xc9, 0xea, 0x05, 0x12, 0x11, 0x0a, 0x04, 0x15, 0xfc, 0x03, 0x00, 0xcc, 0xa1, 0x30, 0xa0, 0x21, 0xd1, 0xb9, 0xc9, 0xea, 0x05, 0x12, 0x11, 0x0a, 0x04, 0x15, 0xfc, 0x03, 0x00, 0x3f, 0x2c, 0x0e, 0x04, 0x0c, 0x73, },
00054 
00055     // OOK_Rb10Bw40
00056     { 0x01, 0x01, 0x86, 0xa0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x32, 0x20, 0x00, 0x5e, 0x05, 0x76, 0x1a, 0x02, 0xb9, 0x02, 0x12, 0x00, 0x57, 0x02, 0xb0, 0x62, 0x11, 0x15, 0x15, 0x00, 0x02, 0xff, 0xff, 0x00, 0x28, 0x00, 0x00, 0x07, 0xff, 0x40, 0xa2, 0x81, 0x26, 0xaf, 0x3f, 0xee, 0xc8, 0xc7, 0xdb, 0xf2, 0x02, 0x08, 0x07, 0x03, 0x15, 0xfc, 0x0f, 0x00, 0xa2, 0x81, 0x26, 0xaf, 0x3f, 0xee, 0xc8, 0xc7, 0xdb, 0xf2, 0x02, 0x08, 0x07, 0x03, 0x15, 0xfc, 0x0f, 0x00, 0x3f, 0x2c, 0x0e, 0x04, 0x0c, 0x73, },
00057 
00058 };
00059 
00060 RH_RF24::RH_RF24(PINS slaveSelectPin, PINS interruptPin, PINS sdnPin, RHGenericSPI& spi)
00061     :
00062     RHSPIDriver(slaveSelectPin, spi),
00063     _interruptPin(interruptPin),
00064     _sdnPin(sdnPin)
00065 {
00066     _idleMode = RH_RF24_DEVICE_STATE_READY;
00067     _myInterruptIndex = 0xff; // Not allocated yet
00068 }
00069 
00070 void RH_RF24::setIdleMode(uint8_t idleMode)
00071 {
00072     _idleMode = idleMode;
00073 }
00074 
00075 bool RH_RF24::init()
00076 {
00077     if (!RHSPIDriver::init())
00078     return false;
00079 
00080 #if (RH_PLATFORM != RH_PLATFORM_MBED)
00081     // Determine the interrupt number that corresponds to the interruptPin
00082     int interruptNumber = digitalPinToInterrupt(_interruptPin);
00083     if (interruptNumber == NOT_AN_INTERRUPT)
00084     return false;
00085 #endif
00086 
00087     // Initialise the radio
00088     power_on_reset();
00089     cmd_clear_all_interrupts();
00090     // Here we use a configuration generated by the Silicon Las Wireless Development Suite
00091     // in radio_config_Si4460.h
00092     // WE override a few things later that we ned to be sure of.
00093     configure(RFM26_CONFIGURATION_DATA);
00094 
00095     // Get the device type and check it
00096     // This also tests whether we are really connected to a device
00097     uint8_t buf[8];
00098     if (!command(RH_RF24_CMD_PART_INFO, 0, 0, buf, sizeof(buf)))
00099     return false; // SPI error? Not connected?
00100     _deviceType = (buf[1] << 8) | buf[2];
00101     // Check PART to be either 0x4460, 0x4461, 0x4463, 0x4464
00102     if (_deviceType != 0x4460 &&
00103     _deviceType != 0x4461 &&
00104     _deviceType != 0x4463 &&
00105     _deviceType != 0x4464)
00106     return false; // Unknown radio type, or not connected
00107 
00108 #if (RH_PLATFORM != RH_PLATFORM_MBED)
00109     // Add by Adrien van den Bossche <vandenbo@univ-tlse2.fr> for Teensy
00110     // ARM M4 requires the below. else pin interrupt doesn't work properly.
00111     // On all other platforms, its innocuous, belt and braces
00112     pinMode(_interruptPin, INPUT); 
00113 #endif
00114 
00115     // Set up interrupt handler
00116     // Since there are a limited number of interrupt glue functions isr*() available,
00117     // we can only support a limited number of devices simultaneously
00118     // ON some devices, notably most Arduinos, the interrupt pin passed in is actuallt the 
00119     // interrupt number. You have to figure out the interruptnumber-to-interruptpin mapping
00120     // yourself based on knwledge of what Arduino board you are running on.
00121     if (_myInterruptIndex == 0xff)
00122     {
00123     // First run, no interrupt allocated yet
00124     if (_interruptCount <= RH_RF24_NUM_INTERRUPTS)
00125         _myInterruptIndex = _interruptCount++;
00126     else
00127         return false; // Too many devices, not enough interrupt vectors
00128     }
00129     _deviceForInterrupt[_myInterruptIndex] = this;
00130     
00131 #if (RH_PLATFORM == RH_PLATFORM_MBED)
00132     if (_myInterruptIndex == 0)
00133         _interruptPin.fall(&isr0);
00134     else if (_myInterruptIndex == 1)
00135         _interruptPin.fall(&isr1);
00136     else if (_myInterruptIndex == 2)
00137         _interruptPin.fall(&isr2);
00138     else
00139     return false; // Too many devices, not enough interrupt vectors
00140 #else
00141     if (_myInterruptIndex == 0)
00142     attachInterrupt(interruptNumber, isr0, FALLING);
00143     else if (_myInterruptIndex == 1)
00144     attachInterrupt(interruptNumber, isr1, FALLING);
00145     else if (_myInterruptIndex == 2)
00146     attachInterrupt(interruptNumber, isr2, FALLING);
00147     else
00148     return false; // Too many devices, not enough interrupt vectors
00149 #endif
00150     // Ensure we get the interrupts we need, irrespective of whats in the radio_config
00151     uint8_t int_ctl[] = {RH_RF24_MODEM_INT_STATUS_EN | RH_RF24_PH_INT_STATUS_EN, 0xff, 0xff, 0x00 };
00152     set_properties(RH_RF24_PROPERTY_INT_CTL_ENABLE, int_ctl, sizeof(int_ctl));
00153 
00154     // RSSI Latching should be configured in MODEM_RSSI_CONTROL in radio_config
00155 
00156     // PKT_TX_THRESHOLD and PKT_RX_THRESHOLD should be set to about 0x30 in radio_config
00157 
00158     // Configure important RH_RF24 registers
00159     // Here we set up the standard packet format for use by the RH_RF24 library:
00160     // We will use FIFO Mode, with automatic packet generation
00161     // We have 2 fields:
00162     // Field 1 contains only the (variable) length of field 2, with CRC
00163     // Field 2 contains the variable length payload and the CRC
00164     // Hmmm, having no CRC on field 1 and CRC on field 2 causes CRC errors when resetting after an odd
00165     // number of packets! Anyway its prob a good thing at the cost of some airtime.
00166     // Hmmm, enabling WHITEN stops it working!
00167     uint8_t pkt_config1[] = { 0x00 };
00168     set_properties(RH_RF24_PROPERTY_PKT_CONFIG1, pkt_config1, sizeof(pkt_config1));
00169 
00170     uint8_t pkt_len[] = { 0x02, 0x01, 0x00 };
00171     set_properties(RH_RF24_PROPERTY_PKT_LEN, pkt_len, sizeof(pkt_len));
00172 
00173     uint8_t pkt_field1[] = { 0x00, 0x01, 0x00, RH_RF24_FIELD_CONFIG_CRC_START | RH_RF24_FIELD_CONFIG_SEND_CRC | RH_RF24_FIELD_CONFIG_CHECK_CRC | RH_RF24_FIELD_CONFIG_CRC_ENABLE };
00174     set_properties(RH_RF24_PROPERTY_PKT_FIELD_1_LENGTH_12_8, pkt_field1, sizeof(pkt_field1));
00175 
00176     uint8_t pkt_field2[] = { 0x00, sizeof(_buf), 0x00, RH_RF24_FIELD_CONFIG_CRC_START | RH_RF24_FIELD_CONFIG_SEND_CRC | RH_RF24_FIELD_CONFIG_CHECK_CRC | RH_RF24_FIELD_CONFIG_CRC_ENABLE };
00177     set_properties(RH_RF24_PROPERTY_PKT_FIELD_2_LENGTH_12_8, pkt_field2, sizeof(pkt_field2));
00178 
00179     // Clear all other fields so they are never used, irrespective of the radio_config
00180     uint8_t pkt_fieldn[] = { 0x00, 0x00, 0x00, 0x00 };
00181     set_properties(RH_RF24_PROPERTY_PKT_FIELD_3_LENGTH_12_8, pkt_fieldn, sizeof(pkt_fieldn));
00182     set_properties(RH_RF24_PROPERTY_PKT_FIELD_4_LENGTH_12_8, pkt_fieldn, sizeof(pkt_fieldn));
00183     set_properties(RH_RF24_PROPERTY_PKT_FIELD_5_LENGTH_12_8, pkt_fieldn, sizeof(pkt_fieldn));
00184 
00185     // The following can be changed later by the user if necessary.
00186     // Set up default configuration
00187     setCRCPolynomial(CRC_16_IBM);
00188     uint8_t syncwords[] = { 0x2d, 0xd4 };
00189     setSyncWords(syncwords, sizeof(syncwords)); // Same as RF22's
00190     // Reasonably fast and reliable default speed and modulation
00191     setModemConfig(GFSK_Rb5Fd10);
00192     // 3 would be sufficient, but this is the same as RF22's
00193     // actualy, 4 seems to work much better for some modulations
00194     setPreambleLength(4);
00195     // An innocuous ISM frequency, same as RF22's
00196     setFrequency(434.0);
00197     // About 2.4dBm on RFM24:
00198     setTxPower(0x10); 
00199 
00200     return true;
00201 }
00202 
00203 // C++ level interrupt handler for this instance
00204 void RH_RF24::handleInterrupt()
00205 {
00206     uint8_t status[8];
00207     command(RH_RF24_CMD_GET_INT_STATUS, NULL, 0, status, sizeof(status));
00208 
00209     // Decode and handle the interrupt bits we are interested in
00210 //    if (status[0] & RH_RF24_INT_STATUS_CHIP_INT_STATUS)
00211     if (status[0] & RH_RF24_INT_STATUS_MODEM_INT_STATUS)
00212     {
00213 //  if (status[4] & RH_RF24_INT_STATUS_INVALID_PREAMBLE)
00214     if (status[4] & RH_RF24_INT_STATUS_INVALID_SYNC)
00215     {
00216         // After INVALID_SYNC, sometimes the radio gets into a silly state and subsequently reports it for every packet
00217         // Need to reset the radio and clear the RX FIFO, cause sometimes theres junk there too
00218         _mode = RHModeIdle;
00219         clearRxFifo();
00220         clearBuffer();
00221     }
00222     }
00223     if (status[0] & RH_RF24_INT_STATUS_PH_INT_STATUS)
00224     {
00225     if (status[2] & RH_RF24_INT_STATUS_CRC_ERROR)
00226     {
00227         // CRC Error
00228         // Radio automatically went to _idleMode
00229         _mode = RHModeIdle;
00230         _rxBad++;
00231 
00232         clearRxFifo();
00233         clearBuffer();
00234     }
00235     if (status[2] & RH_RF24_INT_STATUS_PACKET_SENT)
00236     {
00237         _txGood++; 
00238         // Transmission does not automatically clear the tx buffer.
00239         // Could retransmit if we wanted
00240         // RH_RF24 configured to transition automatically to Idle after packet sent
00241         _mode = RHModeIdle;
00242         clearBuffer();
00243     }
00244     if (status[2] & RH_RF24_INT_STATUS_PACKET_RX)
00245     {
00246         // A complete message has been received with good CRC
00247         // Get the RSSI, configured to latch at sync detect in radio_config
00248         uint8_t modem_status[6];
00249         command(RH_RF24_CMD_GET_MODEM_STATUS, NULL, 0, modem_status, sizeof(modem_status));
00250         _lastRssi = modem_status[3];
00251         _lastPreambleTime = millis();
00252         
00253         // Save it in our buffer
00254         readNextFragment();
00255         // And see if we have a valid message
00256         validateRxBuf();
00257         // Radio will have transitioned automatically to the _idleMode
00258         _mode = RHModeIdle;
00259     }
00260     if (status[2] & RH_RF24_INT_STATUS_TX_FIFO_ALMOST_EMPTY)
00261     {
00262         // TX FIFO almost empty, maybe send another chunk, if there is one
00263         sendNextFragment();
00264     }
00265     if (status[2] & RH_RF24_INT_STATUS_RX_FIFO_ALMOST_FULL)
00266     {
00267         // Some more data to read, get it
00268         readNextFragment();
00269     }
00270     }
00271 }
00272 
00273 // Check whether the latest received message is complete and uncorrupted
00274 void RH_RF24::validateRxBuf()
00275 {
00276     // Validate headers etc
00277     if (_bufLen >= RH_RF24_HEADER_LEN)
00278     {
00279     _rxHeaderTo    = _buf[0];
00280     _rxHeaderFrom  = _buf[1];
00281     _rxHeaderId    = _buf[2];
00282     _rxHeaderFlags = _buf[3];
00283     if (_promiscuous ||
00284         _rxHeaderTo == _thisAddress ||
00285         _rxHeaderTo == RH_BROADCAST_ADDRESS)
00286     {
00287         // Its for us
00288         _rxGood++;
00289         _rxBufValid = true;
00290     }
00291     }
00292 }
00293 
00294 bool RH_RF24::clearRxFifo()
00295 {
00296     uint8_t fifo_clear[] = { 0x02 };
00297     return command(RH_RF24_CMD_FIFO_INFO, fifo_clear, sizeof(fifo_clear));
00298 }
00299 
00300 void RH_RF24::clearBuffer()
00301 {
00302     _bufLen = 0;
00303     _txBufSentIndex = 0;
00304     _rxBufValid = false;
00305 }
00306 
00307 // These are low level functions that call the interrupt handler for the correct
00308 // instance of RH_RF24.
00309 // 3 interrupts allows us to have 3 different devices
00310 void RH_RF24::isr0()
00311 {
00312     if (_deviceForInterrupt[0])
00313     _deviceForInterrupt[0]->handleInterrupt();
00314 }
00315 void RH_RF24::isr1()
00316 {
00317     if (_deviceForInterrupt[1])
00318     _deviceForInterrupt[1]->handleInterrupt();
00319 }
00320 void RH_RF24::isr2()
00321 {
00322     if (_deviceForInterrupt[2])
00323     _deviceForInterrupt[2]->handleInterrupt();
00324 }
00325 
00326 bool RH_RF24::available()
00327 {
00328     if (_mode == RHModeTx)
00329     return false;
00330     if (!_rxBufValid)
00331     setModeRx(); // Make sure we are receiving
00332     return _rxBufValid;
00333 }
00334 
00335 bool RH_RF24::recv(uint8_t* buf, uint8_t* len)
00336 {
00337     if (!available())
00338     return false;
00339     // CAUTION: first 4 octets of _buf contain the headers
00340     if (buf && len && (_bufLen >= RH_RF24_HEADER_LEN))
00341     {
00342     ATOMIC_BLOCK_START;
00343     if (*len > _bufLen - RH_RF24_HEADER_LEN)
00344         *len = _bufLen - RH_RF24_HEADER_LEN;
00345     memcpy(buf, _buf + RH_RF24_HEADER_LEN, *len);
00346     ATOMIC_BLOCK_END;
00347     }
00348     clearBuffer(); // Got the most recent message
00349     return true;
00350 }
00351 
00352 bool RH_RF24::send(const uint8_t* data, uint8_t len)
00353 {
00354     if (len > RH_RF24_MAX_MESSAGE_LEN)
00355     return false;
00356 
00357     waitPacketSent(); // Make sure we dont interrupt an outgoing message
00358     setModeIdle(); // Prevent RX while filling the fifo
00359 
00360     // Put the payload in the FIFO
00361     // First the length in fixed length field 1. This wont appear in the receiver fifo since
00362     // we have turned off IN_FIFO in PKT_LEN
00363     _buf[0] = len + RH_RF24_HEADER_LEN;
00364     // Now the rest of the payload in variable length field 2
00365     // First the headers
00366     _buf[1] = _txHeaderTo;
00367     _buf[2] = _txHeaderFrom;
00368     _buf[3] = _txHeaderId;
00369     _buf[4] = _txHeaderFlags;
00370     // Then the message
00371     memcpy(_buf + 1 + RH_RF24_HEADER_LEN, data, len);
00372     _bufLen = len + 1 + RH_RF24_HEADER_LEN;
00373     _txBufSentIndex = 0;
00374 
00375     // Set the field 2 length to the variable payload length
00376     uint8_t l[] = { len +  RH_RF24_HEADER_LEN};
00377     set_properties(RH_RF24_PROPERTY_PKT_FIELD_2_LENGTH_7_0, l, sizeof(l));
00378 
00379     sendNextFragment();
00380     setModeTx();
00381     return true;
00382 }
00383 
00384 // This is different to command() since we must not wait for CTS
00385 bool RH_RF24::writeTxFifo(uint8_t *data, uint8_t len)
00386 {
00387     ATOMIC_BLOCK_START;
00388     // First send the command
00389     digitalWrite(_slaveSelectPin, LOW);
00390     _spi.transfer(RH_RF24_CMD_TX_FIFO_WRITE);
00391     // Now write any write data
00392     while (len--)
00393     _spi.transfer(*data++);
00394     digitalWrite(_slaveSelectPin, HIGH);
00395     ATOMIC_BLOCK_END;
00396     return true;
00397 }
00398 
00399 void RH_RF24::sendNextFragment()
00400 {
00401     if (_txBufSentIndex < _bufLen)
00402     {
00403     // Some left to send?
00404     uint8_t len = _bufLen - _txBufSentIndex;
00405     // But dont send too much, see how much room is left
00406     uint8_t fifo_info[2];
00407     command(RH_RF24_CMD_FIFO_INFO, NULL, 0, fifo_info, sizeof(fifo_info));
00408     // fifo_info[1] is space left in TX FIFO
00409     if (len > fifo_info[1])
00410         len = fifo_info[1];
00411 
00412     writeTxFifo(_buf + _txBufSentIndex, len);
00413     _txBufSentIndex += len;
00414     }
00415 }
00416 
00417 void RH_RF24::readNextFragment()
00418 {
00419     // Get the packet length from the RX FIFO length
00420     uint8_t fifo_info[1];
00421     command(RH_RF24_CMD_FIFO_INFO, NULL, 0, fifo_info, sizeof(fifo_info));
00422     uint8_t fifo_len = fifo_info[0]; 
00423 
00424     // Check for overflow
00425     if ((_bufLen + fifo_len) > sizeof(_buf))
00426     {
00427     // Overflow pending
00428     _rxBad++;
00429     setModeIdle();
00430     clearRxFifo();
00431     clearBuffer();
00432     return;
00433     }
00434     // So we have room
00435     // Now read the fifo_len bytes from the RX FIFO
00436     // This is different to command() since we dont wait for CTS
00437     digitalWrite(_slaveSelectPin, LOW);
00438     _spi.transfer(RH_RF24_CMD_RX_FIFO_READ);
00439     uint8_t* p = _buf + _bufLen;
00440     uint8_t l = fifo_len;
00441     while (l--)
00442     *p++ = _spi.transfer(0);
00443     digitalWrite(_slaveSelectPin, HIGH);
00444     _bufLen += fifo_len;
00445 }
00446 
00447 uint8_t RH_RF24::maxMessageLength()
00448 {
00449     return RH_RF24_MAX_MESSAGE_LEN;
00450 }
00451 
00452 // Sets registers from a canned modem configuration structure
00453 void RH_RF24::setModemRegisters(const ModemConfig* config)
00454 {
00455     // This list also generated with convert.pl
00456     set_properties(0x2000, &config->prop_2000, 1);
00457     set_properties(0x2003, &config->prop_2003, 1);
00458     set_properties(0x2004, &config->prop_2004, 1);
00459     set_properties(0x2005, &config->prop_2005, 1);
00460     set_properties(0x2006, &config->prop_2006, 1);
00461     set_properties(0x200b, &config->prop_200b, 1);
00462     set_properties(0x200c, &config->prop_200c, 1);
00463     set_properties(0x2018, &config->prop_2018, 1);
00464     set_properties(0x201e, &config->prop_201e, 1);
00465     set_properties(0x201f, &config->prop_201f, 1);
00466     set_properties(0x2022, &config->prop_2022, 1);
00467     set_properties(0x2023, &config->prop_2023, 1);
00468     set_properties(0x2024, &config->prop_2024, 1);
00469     set_properties(0x2025, &config->prop_2025, 1);
00470     set_properties(0x2026, &config->prop_2026, 1);
00471     set_properties(0x2027, &config->prop_2027, 1);
00472     set_properties(0x2028, &config->prop_2028, 1);
00473     set_properties(0x2029, &config->prop_2029, 1);
00474     set_properties(0x202d, &config->prop_202d, 1);
00475     set_properties(0x202e, &config->prop_202e, 1);
00476     set_properties(0x202f, &config->prop_202f, 1);
00477     set_properties(0x2030, &config->prop_2030, 1);
00478     set_properties(0x2031, &config->prop_2031, 1);
00479     set_properties(0x2035, &config->prop_2035, 1);
00480     set_properties(0x2038, &config->prop_2038, 1);
00481     set_properties(0x2039, &config->prop_2039, 1);
00482     set_properties(0x203a, &config->prop_203a, 1);
00483     set_properties(0x203b, &config->prop_203b, 1);
00484     set_properties(0x203c, &config->prop_203c, 1);
00485     set_properties(0x203d, &config->prop_203d, 1);
00486     set_properties(0x203e, &config->prop_203e, 1);
00487     set_properties(0x203f, &config->prop_203f, 1);
00488     set_properties(0x2040, &config->prop_2040, 1);
00489     set_properties(0x2043, &config->prop_2043, 1);
00490     set_properties(0x2045, &config->prop_2045, 1);
00491     set_properties(0x2046, &config->prop_2046, 1);
00492     set_properties(0x2047, &config->prop_2047, 1);
00493     set_properties(0x204e, &config->prop_204e, 1);
00494     set_properties(0x2100, &config->prop_2100, 1);
00495     set_properties(0x2101, &config->prop_2101, 1);
00496     set_properties(0x2102, &config->prop_2102, 1);
00497     set_properties(0x2103, &config->prop_2103, 1);
00498     set_properties(0x2104, &config->prop_2104, 1);
00499     set_properties(0x2105, &config->prop_2105, 1);
00500     set_properties(0x2106, &config->prop_2106, 1);
00501     set_properties(0x2107, &config->prop_2107, 1);
00502     set_properties(0x2108, &config->prop_2108, 1);
00503     set_properties(0x2109, &config->prop_2109, 1);
00504     set_properties(0x210a, &config->prop_210a, 1);
00505     set_properties(0x210b, &config->prop_210b, 1);
00506     set_properties(0x210c, &config->prop_210c, 1);
00507     set_properties(0x210d, &config->prop_210d, 1);
00508     set_properties(0x210e, &config->prop_210e, 1);
00509     set_properties(0x210f, &config->prop_210f, 1);
00510     set_properties(0x2110, &config->prop_2110, 1);
00511     set_properties(0x2111, &config->prop_2111, 1);
00512     set_properties(0x2112, &config->prop_2112, 1);
00513     set_properties(0x2113, &config->prop_2113, 1);
00514     set_properties(0x2114, &config->prop_2114, 1);
00515     set_properties(0x2115, &config->prop_2115, 1);
00516     set_properties(0x2116, &config->prop_2116, 1);
00517     set_properties(0x2117, &config->prop_2117, 1);
00518     set_properties(0x2118, &config->prop_2118, 1);
00519     set_properties(0x2119, &config->prop_2119, 1);
00520     set_properties(0x211a, &config->prop_211a, 1);
00521     set_properties(0x211b, &config->prop_211b, 1);
00522     set_properties(0x211c, &config->prop_211c, 1);
00523     set_properties(0x211d, &config->prop_211d, 1);
00524     set_properties(0x211e, &config->prop_211e, 1);
00525     set_properties(0x211f, &config->prop_211f, 1);
00526     set_properties(0x2120, &config->prop_2120, 1);
00527     set_properties(0x2121, &config->prop_2121, 1);
00528     set_properties(0x2122, &config->prop_2122, 1);
00529     set_properties(0x2123, &config->prop_2123, 1);
00530     set_properties(0x2203, &config->prop_2203, 1);
00531     set_properties(0x2300, &config->prop_2300, 1);
00532     set_properties(0x2301, &config->prop_2301, 1);
00533     set_properties(0x2303, &config->prop_2303, 1);
00534     set_properties(0x2304, &config->prop_2304, 1);
00535     set_properties(0x2305, &config->prop_2305, 1);
00536 }
00537 
00538 // Set one of the canned Modem configs
00539 // Returns true if its a valid choice
00540 bool RH_RF24::setModemConfig(ModemConfigChoice index)
00541 {
00542     if (index > (signed int)(sizeof(MODEM_CONFIG_TABLE) / sizeof(ModemConfig)))
00543         return false;
00544 
00545     ModemConfig cfg;
00546     memcpy_P(&cfg, &MODEM_CONFIG_TABLE[index], sizeof(RH_RF24::ModemConfig));
00547     setModemRegisters(&cfg);
00548 
00549     return true;
00550 }
00551 
00552 void RH_RF24::setPreambleLength(uint16_t bytes)
00553 {
00554     uint8_t config[] = { bytes, 0x14, 0x00, 0x00, 
00555              RH_RF24_PREAMBLE_FIRST_1 | RH_RF24_PREAMBLE_LENGTH_BYTES | RH_RF24_PREAMBLE_STANDARD_1010};
00556     set_properties(RH_RF24_PROPERTY_PREAMBLE_TX_LENGTH, config, sizeof(config));
00557 }
00558 
00559 bool RH_RF24::setCRCPolynomial(CRCPolynomial polynomial)
00560 {
00561     if (polynomial >= CRC_NONE &&
00562     polynomial <= CRC_Castagnoli)
00563     {
00564     // Caution this only has effect if CRCs are enabled
00565     uint8_t config[] = { (polynomial & RH_RF24_CRC_MASK) | RH_RF24_CRC_SEED_ALL_1S };
00566     return set_properties(RH_RF24_PROPERTY_PKT_CRC_CONFIG, config, sizeof(config));
00567     }
00568     else
00569     return false;
00570 }
00571 
00572 void RH_RF24::setSyncWords(const uint8_t* syncWords, uint8_t len)
00573 {
00574     if (len > 4 || len < 1)
00575     return;
00576     uint8_t config[] = { len-1, 0, 0, 0, 0};
00577     memcpy(config+1, syncWords, len);
00578     set_properties(RH_RF24_PROPERTY_SYNC_CONFIG, config, sizeof(config));
00579 }
00580 
00581 bool RH_RF24::setFrequency(float centre, float afcPullInRange)
00582 {
00583     // See Si446x Data Sheet section 5.3.1
00584     // Also the Si446x PLL Synthesizer / VCO_CNT Calculator Rev 0.4
00585     uint8_t outdiv;
00586     uint8_t band;
00587     if (_deviceType == 0x4460 ||
00588     _deviceType == 0x4461 ||
00589     _deviceType == 0x4463)
00590     {
00591     // Non-continuous frequency bands
00592     if (centre <= 1050.0 && centre >= 850.0)
00593         outdiv = 4, band = 0;
00594     else if (centre <= 525.0 && centre >= 425.0)
00595         outdiv = 8, band = 2;
00596     else if (centre <= 350.0 && centre >= 284.0)
00597         outdiv = 12, band = 3;
00598     else if (centre <= 175.0 && centre >= 142.0)
00599         outdiv = 24, band = 5;
00600     else 
00601         return false;
00602     }
00603     else
00604     {
00605     // 0x4464
00606     // Continuous frequency bands
00607     if (centre <= 960.0 && centre >= 675.0)
00608         outdiv = 4, band = 1;
00609     else if (centre < 675.0 && centre >= 450.0)
00610         outdiv = 6, band = 2;
00611     else if (centre < 450.0 && centre >= 338.0)
00612         outdiv = 8, band = 3;
00613     else if (centre < 338.0 && centre >= 225.0)
00614         outdiv = 12, band = 4;
00615     else if (centre < 225.0 && centre >= 169.0)
00616         outdiv = 16, band = 4;
00617     else if (centre < 169.0 && centre >= 119.0)
00618         outdiv = 24, band = 5;
00619     else 
00620         return false;
00621     }
00622 
00623     // Set the MODEM_CLKGEN_BAND (not documented)
00624     uint8_t modem_clkgen[] = { band+8 };
00625     if (!set_properties(RH_RF24_PROPERTY_MODEM_CLKGEN_BAND, modem_clkgen, sizeof(modem_clkgen)))
00626     return false;
00627 
00628     centre *= 1000000.0; // Convert to Hz
00629 
00630     // Now generate the RF frequency properties
00631     // Need the Xtal/XO freq from the radio_config file:
00632     uint32_t xtal_frequency[1] = RADIO_CONFIGURATION_DATA_RADIO_XO_FREQ;
00633     unsigned long f_pfd = 2 * xtal_frequency[0] / outdiv;
00634     unsigned int n = ((unsigned int)(centre / f_pfd)) - 1;
00635     float ratio = centre / (float)f_pfd;
00636     float rest  = ratio - (float)n;
00637     unsigned long m = (unsigned long)(rest * 524288UL); 
00638     unsigned int m2 = m / 0x10000;
00639     unsigned int m1 = (m - m2 * 0x10000) / 0x100;
00640     unsigned int m0 = (m - m2 * 0x10000 - m1 * 0x100); 
00641 
00642     // PROP_FREQ_CONTROL_GROUP
00643     uint8_t freq_control[] = { n, m2, m1, m0 };
00644     return set_properties(RH_RF24_PROPERTY_FREQ_CONTROL_INTE, freq_control, sizeof(freq_control));
00645 }
00646 
00647 void RH_RF24::setModeIdle()
00648 {
00649     if (_mode != RHModeIdle)
00650     {
00651     // Set the antenna switch pins using the GPIO, assuming we have an RFM module with antenna switch
00652     uint8_t config[] = { RH_RF24_GPIO_HIGH, RH_RF24_GPIO_HIGH };
00653     command(RH_RF24_CMD_GPIO_PIN_CFG, config, sizeof(config));
00654 
00655     uint8_t state[] = { _idleMode };
00656     command(RH_RF24_CMD_REQUEST_DEVICE_STATE, state, sizeof(state));
00657     _mode = RHModeIdle;
00658     }
00659 }
00660 
00661 bool RH_RF24::sleep()
00662 {
00663     if (_mode != RHModeSleep)
00664     {
00665     uint8_t state[] = { RH_RF24_DEVICE_STATE_SLEEP };
00666     command(RH_RF24_CMD_REQUEST_DEVICE_STATE, state, sizeof(state));
00667 
00668     _mode = RHModeSleep;
00669     }
00670     return true;
00671 }
00672 
00673 void RH_RF24::setModeRx()
00674 {
00675     if (_mode != RHModeRx)
00676     {
00677     // CAUTION: we cant clear the rx buffers here, else we set up a race condition
00678     // with the _rxBufValid test in available()
00679 
00680     // Tell the receiver the max data length we will accept (a TX may have changed it)
00681     uint8_t l[] = { sizeof(_buf) };
00682     set_properties(RH_RF24_PROPERTY_PKT_FIELD_2_LENGTH_7_0, l, sizeof(l));
00683     
00684     // Set the antenna switch pins using the GPIO, assuming we have an RFM module with antenna switch
00685     uint8_t gpio_config[] = { RH_RF24_GPIO_HIGH, RH_RF24_GPIO_LOW };
00686     command(RH_RF24_CMD_GPIO_PIN_CFG, gpio_config, sizeof(gpio_config));
00687 
00688     uint8_t rx_config[] = { 0x00, RH_RF24_CONDITION_RX_START_IMMEDIATE, 0x00, 0x00, _idleMode, _idleMode, _idleMode};
00689     command(RH_RF24_CMD_START_RX, rx_config, sizeof(rx_config));
00690     _mode = RHModeRx;
00691     }
00692 }
00693 
00694 void RH_RF24::setModeTx()
00695 {
00696     if (_mode != RHModeTx)
00697     {
00698     // Set the antenna switch pins using the GPIO, assuming we have an RFM module with antenna switch
00699     uint8_t config[] = { RH_RF24_GPIO_LOW, RH_RF24_GPIO_HIGH };
00700     command(RH_RF24_CMD_GPIO_PIN_CFG, config, sizeof(config));
00701 
00702     uint8_t tx_params[] = { 0x00, 
00703                 (uint8_t)(_idleMode << 4) | RH_RF24_CONDITION_RETRANSMIT_NO | RH_RF24_CONDITION_START_IMMEDIATE};
00704     command(RH_RF24_CMD_START_TX, tx_params, sizeof(tx_params));
00705     _mode = RHModeTx;
00706     }
00707 }
00708 
00709 void RH_RF24::setTxPower(uint8_t power)
00710 {
00711     uint8_t pa_bias_clkduty = 0;
00712     // These calculations valid for advertised power from Si chips at Vcc = 3.3V
00713     // you may get lower power from RFM modules, depending on Vcc voltage, antenna etc
00714     if (_deviceType == 0x4460)
00715     {
00716     // 0x4f = 13dBm
00717     pa_bias_clkduty = 0xc0;
00718     if (power > 0x4f)
00719         power = 0x4f;
00720     }
00721     else if (_deviceType == 0x4461)
00722     {
00723     // 0x7f = 16dBm
00724     pa_bias_clkduty = 0xc0;
00725     if (power > 0x7f)
00726         power = 0x7f;
00727     }
00728     else if (_deviceType == 0x4463 || _deviceType == 0x4464 )
00729     {
00730     // 0x7f = 20dBm
00731     pa_bias_clkduty = 0x00; // Per WDS suggestion
00732     if (power > 0x7f)
00733         power = 0x7f;
00734     }
00735     uint8_t power_properties[] = {0x18, 0x00, 0x00 }; // PA_MODE from WDS sugggestions (why?)
00736     power_properties[1] = power;
00737     power_properties[2] = pa_bias_clkduty;
00738     set_properties(RH_RF24_PROPERTY_PA_MODE, power_properties, sizeof(power_properties));
00739 }
00740 
00741 // Caution: There was a bug in A1 hardware that will not handle 1 byte commands. 
00742 bool RH_RF24::command(uint8_t cmd, const uint8_t* write_buf, uint8_t write_len, uint8_t* read_buf, uint8_t read_len)
00743 {
00744     bool   done = false;
00745 
00746     ATOMIC_BLOCK_START;
00747     // First send the command
00748     digitalWrite(_slaveSelectPin, LOW);
00749     _spi.transfer(cmd);
00750 
00751     // Now write any write data
00752     if (write_buf && write_len)
00753     {
00754     while (write_len--)
00755         _spi.transfer(*write_buf++);
00756     }
00757     // Sigh, the RFM26 at least has problems if we deselect too quickly :-(
00758     // Innocuous timewaster:
00759     digitalWrite(_slaveSelectPin, LOW);
00760     // And finalise the command
00761     digitalWrite(_slaveSelectPin, HIGH);
00762 
00763     uint16_t count; // Number of times we have tried to get CTS
00764     for (count = 0; !done && count < RH_RF24_CTS_RETRIES; count++)
00765     {
00766     // Wait for the CTS
00767     digitalWrite(_slaveSelectPin, LOW);
00768 
00769     _spi.transfer(RH_RF24_CMD_READ_BUF);
00770     if (_spi.transfer(0) == RH_RF24_REPLY_CTS)
00771     {
00772         // Now read any expected reply data
00773         if (read_buf && read_len)
00774         {
00775         while (read_len--)
00776         {
00777             *read_buf++ = _spi.transfer(0);
00778         }
00779         }
00780         done = true;
00781     }
00782     // Sigh, the RFM26 at least has problems if we deselect too quickly :-(
00783     // Innocuous timewaster:
00784     digitalWrite(_slaveSelectPin, LOW);
00785     // Finalise the read
00786     digitalWrite(_slaveSelectPin, HIGH);
00787     }
00788     ATOMIC_BLOCK_END;
00789     return done; // False if too many attempts at CTS
00790 }
00791 
00792 bool RH_RF24::configure(const uint8_t* commands)
00793 {
00794     // Command strings are constructed in radio_config_Si4460.h 
00795     // Each command starts with a count of the bytes in that command:
00796     // <bytecount> <command> <bytecount-2 bytes of args/data>
00797     uint8_t next_cmd_len;
00798     
00799     while (memcpy_P(&next_cmd_len, commands, 1), next_cmd_len > 0)
00800     {
00801     uint8_t buf[20]; // As least big as the biggest permitted command/property list of 15
00802     memcpy_P(buf, commands+1, next_cmd_len);
00803     command(buf[0], buf+1, next_cmd_len - 1);
00804     commands += (next_cmd_len + 1);
00805     }
00806     return true;
00807 }
00808 
00809 void RH_RF24::power_on_reset()
00810 {
00811     // Sigh: its necessary to control the SDN pin to reset this ship. 
00812     // Tying it to GND does not produce reliable startups
00813     // Per Si4464 Data Sheet 3.3.2
00814     digitalWrite(_sdnPin, HIGH); // So we dont get a glitch after setting pinMode OUTPUT
00815 #if (RH_PLATFORM != RH_PLATFORM_MBED)
00816     pinMode(_sdnPin, OUTPUT);
00817 #endif
00818     delay(10);
00819     digitalWrite(_sdnPin, LOW);
00820     delay(10);
00821 }
00822 
00823 bool RH_RF24::cmd_clear_all_interrupts()
00824 {
00825     uint8_t write_buf[] = { 0x00, 0x00, 0x00 }; 
00826     return command(RH_RF24_CMD_GET_INT_STATUS, write_buf, sizeof(write_buf));
00827 }
00828 
00829 bool RH_RF24::set_properties(uint16_t firstProperty, const uint8_t* values, uint8_t count)
00830 {
00831     uint8_t buf[15];
00832 
00833     buf[0] = firstProperty >> 8;   // GROUP
00834     buf[1] = count;                // NUM_PROPS
00835     buf[2] = firstProperty & 0xff; // START_PROP
00836     uint8_t i;
00837     for (i = 0; i < 12 && i < count; i++)
00838     buf[3 + i] = values[i]; // DATAn
00839     return command(RH_RF24_CMD_SET_PROPERTY, buf, count + 3);
00840 }
00841 
00842 bool RH_RF24::get_properties(uint16_t firstProperty, uint8_t* values, uint8_t count)
00843 {
00844     if (count > 16)
00845     count = 16;
00846     uint8_t buf[3];
00847     buf[0] = firstProperty >> 8;   // GROUP
00848     buf[1] = count;                // NUM_PROPS
00849     buf[2] = firstProperty & 0xff; // START_PROP
00850     return command(RH_RF24_CMD_GET_PROPERTY, buf, sizeof(buf), values, count);
00851 }
00852 
00853 float RH_RF24::get_temperature()
00854 {
00855     uint8_t write_buf[] = { 0x10 };
00856     uint8_t read_buf[8];
00857     // Takes nearly 4ms
00858     command(RH_RF24_CMD_GET_ADC_READING, write_buf, sizeof(write_buf), read_buf, sizeof(read_buf));
00859     uint16_t temp_adc = (read_buf[4] << 8) | read_buf[5];
00860     return ((800 + read_buf[6]) / 4096.0) * temp_adc - ((read_buf[7] / 2) + 256);
00861 }
00862 
00863 float RH_RF24::get_battery_voltage()
00864 {
00865     uint8_t write_buf[] = { 0x08 };
00866     uint8_t read_buf[8];
00867     // Takes nearly 4ms
00868     command(RH_RF24_CMD_GET_ADC_READING, write_buf, sizeof(write_buf), read_buf, sizeof(read_buf));
00869     uint16_t battery_adc = (read_buf[2] << 8) | read_buf[3];
00870     return 3.0 * battery_adc / 1280;
00871 }
00872 
00873 float RH_RF24::get_gpio_voltage(uint8_t gpio)
00874 {
00875     uint8_t write_buf[] = { 0x04 };
00876     uint8_t read_buf[8];
00877     write_buf[0] |= (gpio & 0x3);
00878     // Takes nearly 4ms
00879     command(RH_RF24_CMD_GET_ADC_READING, write_buf, sizeof(write_buf), read_buf, sizeof(read_buf));
00880     uint16_t gpio_adc = (read_buf[0] << 8) | read_buf[1];
00881     return 3.0 * gpio_adc / 1280;
00882 }
00883 
00884 uint8_t RH_RF24::frr_read(uint8_t reg)
00885 {
00886     uint8_t ret;
00887 
00888     // Do not wait for CTS
00889     ATOMIC_BLOCK_START;
00890     // First send the command
00891     digitalWrite(_slaveSelectPin, LOW);
00892     _spi.transfer(RH_RF24_PROPERTY_FRR_CTL_A_MODE + reg);
00893     // Get the fast response
00894     ret = _spi.transfer(0);
00895     digitalWrite(_slaveSelectPin, HIGH);
00896     ATOMIC_BLOCK_END;
00897     return ret;
00898 }
00899 
00900 // List of command replies to be printed by prinRegisters()
00901 PROGMEM static const RH_RF24::CommandInfo commands[] =
00902 {
00903     { RH_RF24_CMD_PART_INFO,            8 },
00904     { RH_RF24_CMD_FUNC_INFO,            6 },
00905     { RH_RF24_CMD_GPIO_PIN_CFG,         7 },
00906     { RH_RF24_CMD_FIFO_INFO,            2 },
00907     { RH_RF24_CMD_PACKET_INFO,          2 },
00908     { RH_RF24_CMD_GET_INT_STATUS,       8 },
00909     { RH_RF24_CMD_GET_PH_STATUS,        2 },
00910     { RH_RF24_CMD_GET_MODEM_STATUS,     8 },
00911     { RH_RF24_CMD_GET_CHIP_STATUS,      3 },
00912     { RH_RF24_CMD_REQUEST_DEVICE_STATE, 2 },
00913 };
00914 #define NUM_COMMAND_INFO (sizeof(commands)/sizeof(CommandInfo))
00915 
00916 // List of properties to be printed by printRegisters()
00917 PROGMEM static const uint16_t properties[] =
00918 {
00919     RH_RF24_PROPERTY_GLOBAL_XO_TUNE,                   
00920     RH_RF24_PROPERTY_GLOBAL_CLK_CFG,                   
00921     RH_RF24_PROPERTY_GLOBAL_LOW_BATT_THRESH,           
00922     RH_RF24_PROPERTY_GLOBAL_CONFIG,                    
00923     RH_RF24_PROPERTY_GLOBAL_WUT_CONFIG,               
00924     RH_RF24_PROPERTY_GLOBAL_WUT_M_15_8,
00925     RH_RF24_PROPERTY_GLOBAL_WUT_M_7_0,
00926     RH_RF24_PROPERTY_GLOBAL_WUT_R,
00927     RH_RF24_PROPERTY_GLOBAL_WUT_LDC,
00928     RH_RF24_PROPERTY_INT_CTL_ENABLE,
00929     RH_RF24_PROPERTY_INT_CTL_PH_ENABLE,
00930     RH_RF24_PROPERTY_INT_CTL_MODEM_ENABLE,
00931     RH_RF24_PROPERTY_INT_CTL_CHIP_ENABLE,
00932     RH_RF24_PROPERTY_FRR_CTL_A_MODE,
00933     RH_RF24_PROPERTY_FRR_CTL_B_MODE,
00934     RH_RF24_PROPERTY_FRR_CTL_C_MODE,
00935     RH_RF24_PROPERTY_FRR_CTL_D_MODE,
00936     RH_RF24_PROPERTY_PREAMBLE_TX_LENGTH,
00937     RH_RF24_PROPERTY_PREAMBLE_CONFIG_STD_1,
00938     RH_RF24_PROPERTY_PREAMBLE_CONFIG_NSTD,
00939     RH_RF24_PROPERTY_PREAMBLE_CONFIG_STD_2,
00940     RH_RF24_PROPERTY_PREAMBLE_CONFIG,
00941     RH_RF24_PROPERTY_PREAMBLE_PATTERN_31_24,
00942     RH_RF24_PROPERTY_PREAMBLE_PATTERN_23_16,
00943     RH_RF24_PROPERTY_PREAMBLE_PATTERN_15_8,
00944     RH_RF24_PROPERTY_PREAMBLE_PATTERN_7_0,
00945     RH_RF24_PROPERTY_SYNC_CONFIG,
00946     RH_RF24_PROPERTY_SYNC_BITS_31_24,
00947     RH_RF24_PROPERTY_SYNC_BITS_23_16,
00948     RH_RF24_PROPERTY_SYNC_BITS_15_8,
00949     RH_RF24_PROPERTY_SYNC_BITS_7_0,
00950     RH_RF24_PROPERTY_PKT_CRC_CONFIG,
00951     RH_RF24_PROPERTY_PKT_CONFIG1,
00952     RH_RF24_PROPERTY_PKT_LEN,
00953     RH_RF24_PROPERTY_PKT_LEN_FIELD_SOURCE,
00954     RH_RF24_PROPERTY_PKT_LEN_ADJUST,
00955     RH_RF24_PROPERTY_PKT_TX_THRESHOLD,
00956     RH_RF24_PROPERTY_PKT_RX_THRESHOLD,
00957     RH_RF24_PROPERTY_PKT_FIELD_1_LENGTH_12_8,
00958     RH_RF24_PROPERTY_PKT_FIELD_1_LENGTH_7_0,
00959     RH_RF24_PROPERTY_PKT_FIELD_1_CONFIG,
00960     RH_RF24_PROPERTY_PKT_FIELD_1_CRC_CONFIG,
00961     RH_RF24_PROPERTY_PKT_FIELD_2_LENGTH_12_8,
00962     RH_RF24_PROPERTY_PKT_FIELD_2_LENGTH_7_0,
00963     RH_RF24_PROPERTY_PKT_FIELD_2_CONFIG,
00964     RH_RF24_PROPERTY_PKT_FIELD_2_CRC_CONFIG,
00965     RH_RF24_PROPERTY_PKT_FIELD_3_LENGTH_12_8,
00966     RH_RF24_PROPERTY_PKT_FIELD_3_LENGTH_7_0,
00967     RH_RF24_PROPERTY_PKT_FIELD_3_CONFIG,
00968     RH_RF24_PROPERTY_PKT_FIELD_3_CRC_CONFIG,
00969     RH_RF24_PROPERTY_PKT_FIELD_4_LENGTH_12_8,
00970     RH_RF24_PROPERTY_PKT_FIELD_4_LENGTH_7_0,
00971     RH_RF24_PROPERTY_PKT_FIELD_4_CONFIG,
00972     RH_RF24_PROPERTY_PKT_FIELD_4_CRC_CONFIG,
00973     RH_RF24_PROPERTY_PKT_FIELD_5_LENGTH_12_8,
00974     RH_RF24_PROPERTY_PKT_FIELD_5_LENGTH_7_0,
00975     RH_RF24_PROPERTY_PKT_FIELD_5_CONFIG,
00976     RH_RF24_PROPERTY_PKT_FIELD_5_CRC_CONFIG,
00977     RH_RF24_PROPERTY_PKT_RX_FIELD_1_LENGTH_12_8,
00978     RH_RF24_PROPERTY_PKT_RX_FIELD_1_LENGTH_7_0,
00979     RH_RF24_PROPERTY_PKT_RX_FIELD_1_CONFIG,
00980     RH_RF24_PROPERTY_PKT_RX_FIELD_1_CRC_CONFIG,
00981     RH_RF24_PROPERTY_PKT_RX_FIELD_2_LENGTH_12_8,
00982     RH_RF24_PROPERTY_PKT_RX_FIELD_2_LENGTH_7_0,
00983     RH_RF24_PROPERTY_PKT_RX_FIELD_2_CONFIG,
00984     RH_RF24_PROPERTY_PKT_RX_FIELD_2_CRC_CONFIG,
00985     RH_RF24_PROPERTY_PKT_RX_FIELD_3_LENGTH_12_8,
00986     RH_RF24_PROPERTY_PKT_RX_FIELD_3_LENGTH_7_0,
00987     RH_RF24_PROPERTY_PKT_RX_FIELD_3_CONFIG,
00988     RH_RF24_PROPERTY_PKT_RX_FIELD_3_CRC_CONFIG,
00989     RH_RF24_PROPERTY_PKT_RX_FIELD_4_LENGTH_12_8,
00990     RH_RF24_PROPERTY_PKT_RX_FIELD_4_LENGTH_7_0,
00991     RH_RF24_PROPERTY_PKT_RX_FIELD_4_CONFIG,
00992     RH_RF24_PROPERTY_PKT_RX_FIELD_4_CRC_CONFIG,
00993     RH_RF24_PROPERTY_PKT_RX_FIELD_5_LENGTH_12_8,
00994     RH_RF24_PROPERTY_PKT_RX_FIELD_5_LENGTH_7_0,
00995     RH_RF24_PROPERTY_PKT_RX_FIELD_5_CONFIG,
00996     RH_RF24_PROPERTY_PKT_RX_FIELD_5_CRC_CONFIG,
00997     RH_RF24_PROPERTY_MODEM_MOD_TYPE,
00998     RH_RF24_PROPERTY_MODEM_MAP_CONTROL,
00999     RH_RF24_PROPERTY_MODEM_DSM_CTRL,
01000     RH_RF24_PROPERTY_MODEM_DATA_RATE_2,
01001     RH_RF24_PROPERTY_MODEM_DATA_RATE_1,
01002     RH_RF24_PROPERTY_MODEM_DATA_RATE_0,
01003     RH_RF24_PROPERTY_MODEM_TX_NCO_MODE_3,
01004     RH_RF24_PROPERTY_MODEM_TX_NCO_MODE_2,
01005     RH_RF24_PROPERTY_MODEM_TX_NCO_MODE_1,
01006     RH_RF24_PROPERTY_MODEM_TX_NCO_MODE_0,
01007     RH_RF24_PROPERTY_MODEM_FREQ_DEV_2,
01008     RH_RF24_PROPERTY_MODEM_FREQ_DEV_1,
01009     RH_RF24_PROPERTY_MODEM_FREQ_DEV_0,
01010     RH_RF24_PROPERTY_MODEM_TX_RAMP_DELAY,
01011     RH_RF24_PROPERTY_MODEM_MDM_CTRL,
01012     RH_RF24_PROPERTY_MODEM_IF_CONTROL,
01013     RH_RF24_PROPERTY_MODEM_IF_FREQ_2,
01014     RH_RF24_PROPERTY_MODEM_IF_FREQ_1,
01015     RH_RF24_PROPERTY_MODEM_IF_FREQ_0,
01016     RH_RF24_PROPERTY_MODEM_DECIMATION_CFG1,
01017     RH_RF24_PROPERTY_MODEM_DECIMATION_CFG0,
01018     RH_RF24_PROPERTY_MODEM_BCR_OSR_1,
01019     RH_RF24_PROPERTY_MODEM_BCR_OSR_0,
01020     RH_RF24_PROPERTY_MODEM_BCR_NCO_OFFSET_2,
01021     RH_RF24_PROPERTY_MODEM_BCR_NCO_OFFSET_1,
01022     RH_RF24_PROPERTY_MODEM_BCR_NCO_OFFSET_0,
01023     RH_RF24_PROPERTY_MODEM_BCR_GAIN_1,
01024     RH_RF24_PROPERTY_MODEM_BCR_GAIN_0,
01025     RH_RF24_PROPERTY_MODEM_BCR_GEAR,
01026     RH_RF24_PROPERTY_MODEM_BCR_MISC1,
01027     RH_RF24_PROPERTY_MODEM_AFC_GEAR,
01028     RH_RF24_PROPERTY_MODEM_AFC_WAIT,
01029     RH_RF24_PROPERTY_MODEM_AFC_GAIN_1,
01030     RH_RF24_PROPERTY_MODEM_AFC_GAIN_0,
01031     RH_RF24_PROPERTY_MODEM_AFC_LIMITER_1,
01032     RH_RF24_PROPERTY_MODEM_AFC_LIMITER_0,
01033     RH_RF24_PROPERTY_MODEM_AFC_MISC,
01034     RH_RF24_PROPERTY_MODEM_AGC_CONTROL,
01035     RH_RF24_PROPERTY_MODEM_AGC_WINDOW_SIZE,
01036     RH_RF24_PROPERTY_MODEM_AGC_RFPD_DECAY,
01037     RH_RF24_PROPERTY_MODEM_AGC_IFPD_DECAY,
01038     RH_RF24_PROPERTY_MODEM_FSK4_GAIN1,
01039     RH_RF24_PROPERTY_MODEM_FSK4_GAIN0,
01040     RH_RF24_PROPERTY_MODEM_FSK4_TH1,
01041     RH_RF24_PROPERTY_MODEM_FSK4_TH0,
01042     RH_RF24_PROPERTY_MODEM_FSK4_MAP,
01043     RH_RF24_PROPERTY_MODEM_OOK_PDTC,
01044     RH_RF24_PROPERTY_MODEM_OOK_CNT1,
01045     RH_RF24_PROPERTY_MODEM_OOK_MISC,
01046     RH_RF24_PROPERTY_MODEM_RAW_SEARCH,
01047     RH_RF24_PROPERTY_MODEM_RAW_CONTROL,
01048     RH_RF24_PROPERTY_MODEM_RAW_EYE_1,
01049     RH_RF24_PROPERTY_MODEM_RAW_EYE_0,
01050     RH_RF24_PROPERTY_MODEM_ANT_DIV_MODE,
01051     RH_RF24_PROPERTY_MODEM_ANT_DIV_CONTROL,
01052     RH_RF24_PROPERTY_MODEM_RSSI_THRESH,
01053     RH_RF24_PROPERTY_MODEM_RSSI_JUMP_THRESH,
01054     RH_RF24_PROPERTY_MODEM_RSSI_CONTROL,
01055     RH_RF24_PROPERTY_MODEM_RSSI_CONTROL2,
01056     RH_RF24_PROPERTY_MODEM_RSSI_COMP,
01057     RH_RF24_PROPERTY_MODEM_ANT_DIV_CONT,
01058     RH_RF24_PROPERTY_MODEM_CLKGEN_BAND,
01059     RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COE13_7_0,
01060     RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COE12_7_0,
01061     RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COE11_7_0,
01062     RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COE10_7_0,
01063     RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COE9_7_0,
01064     RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COE8_7_0,
01065     RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COE7_7_0,
01066     RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COE6_7_0,
01067     RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COE5_7_0,
01068     RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COE4_7_0,
01069     RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COE3_7_0,
01070     RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COE2_7_0,
01071     RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COE1_7_0,
01072     RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COE0_7_0,
01073     RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COEM0,
01074     RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COEM1,
01075     RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COEM2,
01076     RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COEM3,
01077     RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COE13_7_0,
01078     RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COE12_7_0,
01079     RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COE11_7_0,
01080     RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COE10_7_0,
01081     RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COE9_7_0,
01082     RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COE8_7_0,
01083     RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COE7_7_0,
01084     RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COE6_7_0,
01085     RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COE5_7_0,
01086     RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COE4_7_0,
01087     RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COE3_7_0,
01088     RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COE2_7_0,
01089     RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COE1_7_0,
01090     RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COE0_7_0,
01091     RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COEM0,
01092     RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COEM1,
01093     RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COEM2,
01094     RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COEM3,
01095     RH_RF24_PROPERTY_PA_MODE,
01096     RH_RF24_PROPERTY_PA_PWR_LVL,
01097     RH_RF24_PROPERTY_PA_BIAS_CLKDUTY,
01098     RH_RF24_PROPERTY_PA_TC,
01099     RH_RF24_PROPERTY_SYNTH_PFDCP_CPFF,
01100     RH_RF24_PROPERTY_SYNTH_PFDCP_CPINT,
01101     RH_RF24_PROPERTY_SYNTH_VCO_KV,
01102     RH_RF24_PROPERTY_SYNTH_LPFILT3,
01103     RH_RF24_PROPERTY_SYNTH_LPFILT2,
01104     RH_RF24_PROPERTY_SYNTH_LPFILT1,
01105     RH_RF24_PROPERTY_SYNTH_LPFILT0,
01106     RH_RF24_PROPERTY_MATCH_VALUE_1,
01107     RH_RF24_PROPERTY_MATCH_MASK_1,
01108     RH_RF24_PROPERTY_MATCH_CTRL_1,
01109     RH_RF24_PROPERTY_MATCH_VALUE_2,
01110     RH_RF24_PROPERTY_MATCH_MASK_2,
01111     RH_RF24_PROPERTY_MATCH_CTRL_2,
01112     RH_RF24_PROPERTY_MATCH_VALUE_3,
01113     RH_RF24_PROPERTY_MATCH_MASK_3,
01114     RH_RF24_PROPERTY_MATCH_CTRL_3,
01115     RH_RF24_PROPERTY_MATCH_VALUE_4,
01116     RH_RF24_PROPERTY_MATCH_MASK_4,
01117     RH_RF24_PROPERTY_MATCH_CTRL_4,
01118     RH_RF24_PROPERTY_FREQ_CONTROL_INTE,
01119     RH_RF24_PROPERTY_FREQ_CONTROL_FRAC_2,
01120     RH_RF24_PROPERTY_FREQ_CONTROL_FRAC_1,
01121     RH_RF24_PROPERTY_FREQ_CONTROL_FRAC_0,
01122     RH_RF24_PROPERTY_FREQ_CONTROL_CHANNEL_STEP_SIZE_1,
01123     RH_RF24_PROPERTY_FREQ_CONTROL_CHANNEL_STEP_SIZE_0,
01124     RH_RF24_PROPERTY_FREQ_CONTROL_VCOCNT_RX_ADJ,
01125     RH_RF24_PROPERTY_RX_HOP_CONTROL,
01126     RH_RF24_PROPERTY_RX_HOP_TABLE_SIZE,
01127     RH_RF24_PROPERTY_RX_HOP_TABLE_ENTRY_0,
01128 };
01129 #define NUM_PROPERTIES (sizeof(properties)/sizeof(uint16_t))
01130 
01131 bool RH_RF24::printRegisters()
01132 {  
01133 #ifdef RH_HAVE_SERIAL
01134     uint8_t i;
01135     // First print the commands that return interesting data
01136     for (i = 0; i < NUM_COMMAND_INFO; i++)
01137     {
01138     CommandInfo cmd;
01139     memcpy_P(&cmd, &commands[i], sizeof(cmd));
01140     uint8_t buf[10]; // Big enough for the biggest command reply
01141     if (command(cmd.cmd, NULL, 0, buf, cmd.replyLen))
01142     {
01143         // Print the results:
01144         Serial.print("cmd: ");
01145         Serial.print(cmd.cmd, HEX);
01146         Serial.print(" : ");
01147         uint8_t j;
01148         for (j = 0; j < cmd.replyLen; j++)
01149         {
01150         Serial.print(buf[j], HEX);
01151         Serial.print(" ");
01152         }
01153         Serial.println("");
01154     }
01155     }
01156 
01157     // Now print the properties
01158     for (i = 0; i < NUM_PROPERTIES; i++)
01159     {
01160     uint16_t prop;
01161     memcpy_P(&prop, &properties[i], sizeof(prop));
01162     uint8_t result;
01163     get_properties(prop, &result, 1);
01164     Serial.print("prop: ");
01165     Serial.print(prop, HEX);
01166     Serial.print(": ");
01167     Serial.print(result, HEX);
01168         Serial.println("");
01169     }
01170 #endif
01171     return true;
01172 }