Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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 }
Generated on Tue Jul 12 2022 18:05:55 by
1.7.2