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.
Fork of RadioHead-148 by
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 20:15:57 by
1.7.2
