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_RF22.cpp
00001 // RH_RF22.cpp 00002 // 00003 // Copyright (C) 2011 Mike McCauley 00004 // $Id: RH_RF22.cpp,v 1.24 2015/05/17 00:11:26 mikem Exp $ 00005 00006 #include <RH_RF22.h> 00007 00008 // Interrupt vectors for the 2 Arduino interrupt pins 00009 // Each interrupt can be handled by a different instance of RH_RF22, allowing you to have 00010 // 2 RH_RF22s per Arduino 00011 RH_RF22* RH_RF22::_deviceForInterrupt[RH_RF22_NUM_INTERRUPTS] = {0, 0, 0}; 00012 uint8_t RH_RF22::_interruptCount = 0; // Index into _deviceForInterrupt for next device 00013 00014 // These are indexed by the values of ModemConfigChoice 00015 // Canned modem configurations generated with 00016 // http://www.hoperf.com/upload/rf/RH_RF22B%2023B%2031B%2042B%2043B%20Register%20Settings_RevB1-v5.xls 00017 // Stored in flash (program) memory to save SRAM 00018 PROGMEM static const RH_RF22::ModemConfig MODEM_CONFIG_TABLE[] = 00019 { 00020 { 0x2b, 0x03, 0xf4, 0x20, 0x41, 0x89, 0x00, 0x36, 0x40, 0x0a, 0x1d, 0x80, 0x60, 0x10, 0x62, 0x2c, 0x00, 0x08 }, // Unmodulated carrier 00021 { 0x2b, 0x03, 0xf4, 0x20, 0x41, 0x89, 0x00, 0x36, 0x40, 0x0a, 0x1d, 0x80, 0x60, 0x10, 0x62, 0x2c, 0x33, 0x08 }, // FSK, PN9 random modulation, 2, 5 00022 00023 // All the following enable FIFO with reg 71 00024 // 1c, 1f, 20, 21, 22, 23, 24, 25, 2c, 2d, 2e, 58, 69, 6e, 6f, 70, 71, 72 00025 // FSK, No Manchester, Max Rb err <1%, Xtal Tol 20ppm 00026 { 0x2b, 0x03, 0xf4, 0x20, 0x41, 0x89, 0x00, 0x36, 0x40, 0x0a, 0x1d, 0x80, 0x60, 0x10, 0x62, 0x2c, 0x22, 0x08 }, // 2, 5 00027 { 0x1b, 0x03, 0x41, 0x60, 0x27, 0x52, 0x00, 0x07, 0x40, 0x0a, 0x1e, 0x80, 0x60, 0x13, 0xa9, 0x2c, 0x22, 0x3a }, // 2.4, 36 00028 { 0x1d, 0x03, 0xa1, 0x20, 0x4e, 0xa5, 0x00, 0x13, 0x40, 0x0a, 0x1e, 0x80, 0x60, 0x27, 0x52, 0x2c, 0x22, 0x48 }, // 4.8, 45 00029 { 0x1e, 0x03, 0xd0, 0x00, 0x9d, 0x49, 0x00, 0x45, 0x40, 0x0a, 0x20, 0x80, 0x60, 0x4e, 0xa5, 0x2c, 0x22, 0x48 }, // 9.6, 45 00030 { 0x2b, 0x03, 0x34, 0x02, 0x75, 0x25, 0x07, 0xff, 0x40, 0x0a, 0x1b, 0x80, 0x60, 0x9d, 0x49, 0x2c, 0x22, 0x0f }, // 19.2, 9.6 00031 { 0x02, 0x03, 0x68, 0x01, 0x3a, 0x93, 0x04, 0xd5, 0x40, 0x0a, 0x1e, 0x80, 0x60, 0x09, 0xd5, 0x0c, 0x22, 0x1f }, // 38.4, 19.6 00032 { 0x06, 0x03, 0x45, 0x01, 0xd7, 0xdc, 0x07, 0x6e, 0x40, 0x0a, 0x2d, 0x80, 0x60, 0x0e, 0xbf, 0x0c, 0x22, 0x2e }, // 57.6. 28.8 00033 { 0x8a, 0x03, 0x60, 0x01, 0x55, 0x55, 0x02, 0xad, 0x40, 0x0a, 0x50, 0x80, 0x60, 0x20, 0x00, 0x0c, 0x22, 0xc8 }, // 125, 125 00034 00035 { 0x2b, 0x03, 0xa1, 0xe0, 0x10, 0xc7, 0x00, 0x09, 0x40, 0x0a, 0x1d, 0x80, 0x60, 0x04, 0x32, 0x2c, 0x22, 0x04 }, // 512 baud, FSK, 2.5 Khz fd for POCSAG compatibility 00036 { 0x27, 0x03, 0xa1, 0xe0, 0x10, 0xc7, 0x00, 0x06, 0x40, 0x0a, 0x1d, 0x80, 0x60, 0x04, 0x32, 0x2c, 0x22, 0x07 }, // 512 baud, FSK, 4.5 Khz fd for POCSAG compatibility 00037 00038 // GFSK, No Manchester, Max Rb err <1%, Xtal Tol 20ppm 00039 // These differ from FSK only in register 71, for the modulation type 00040 { 0x2b, 0x03, 0xf4, 0x20, 0x41, 0x89, 0x00, 0x36, 0x40, 0x0a, 0x1d, 0x80, 0x60, 0x10, 0x62, 0x2c, 0x23, 0x08 }, // 2, 5 00041 { 0x1b, 0x03, 0x41, 0x60, 0x27, 0x52, 0x00, 0x07, 0x40, 0x0a, 0x1e, 0x80, 0x60, 0x13, 0xa9, 0x2c, 0x23, 0x3a }, // 2.4, 36 00042 { 0x1d, 0x03, 0xa1, 0x20, 0x4e, 0xa5, 0x00, 0x13, 0x40, 0x0a, 0x1e, 0x80, 0x60, 0x27, 0x52, 0x2c, 0x23, 0x48 }, // 4.8, 45 00043 { 0x1e, 0x03, 0xd0, 0x00, 0x9d, 0x49, 0x00, 0x45, 0x40, 0x0a, 0x20, 0x80, 0x60, 0x4e, 0xa5, 0x2c, 0x23, 0x48 }, // 9.6, 45 00044 { 0x2b, 0x03, 0x34, 0x02, 0x75, 0x25, 0x07, 0xff, 0x40, 0x0a, 0x1b, 0x80, 0x60, 0x9d, 0x49, 0x2c, 0x23, 0x0f }, // 19.2, 9.6 00045 { 0x02, 0x03, 0x68, 0x01, 0x3a, 0x93, 0x04, 0xd5, 0x40, 0x0a, 0x1e, 0x80, 0x60, 0x09, 0xd5, 0x0c, 0x23, 0x1f }, // 38.4, 19.6 00046 { 0x06, 0x03, 0x45, 0x01, 0xd7, 0xdc, 0x07, 0x6e, 0x40, 0x0a, 0x2d, 0x80, 0x60, 0x0e, 0xbf, 0x0c, 0x23, 0x2e }, // 57.6. 28.8 00047 { 0x8a, 0x03, 0x60, 0x01, 0x55, 0x55, 0x02, 0xad, 0x40, 0x0a, 0x50, 0x80, 0x60, 0x20, 0x00, 0x0c, 0x23, 0xc8 }, // 125, 125 00048 00049 // OOK, No Manchester, Max Rb err <1%, Xtal Tol 20ppm 00050 { 0x51, 0x03, 0x68, 0x00, 0x3a, 0x93, 0x01, 0x3d, 0x2c, 0x11, 0x28, 0x80, 0x60, 0x09, 0xd5, 0x2c, 0x21, 0x08 }, // 1.2, 75 00051 { 0xc8, 0x03, 0x39, 0x20, 0x68, 0xdc, 0x00, 0x6b, 0x2a, 0x08, 0x2a, 0x80, 0x60, 0x13, 0xa9, 0x2c, 0x21, 0x08 }, // 2.4, 335 00052 { 0xc8, 0x03, 0x9c, 0x00, 0xd1, 0xb7, 0x00, 0xd4, 0x29, 0x04, 0x29, 0x80, 0x60, 0x27, 0x52, 0x2c, 0x21, 0x08 }, // 4.8, 335 00053 { 0xb8, 0x03, 0x9c, 0x00, 0xd1, 0xb7, 0x00, 0xd4, 0x28, 0x82, 0x29, 0x80, 0x60, 0x4e, 0xa5, 0x2c, 0x21, 0x08 }, // 9.6, 335 00054 { 0xa8, 0x03, 0x9c, 0x00, 0xd1, 0xb7, 0x00, 0xd4, 0x28, 0x41, 0x29, 0x80, 0x60, 0x9d, 0x49, 0x2c, 0x21, 0x08 }, // 19.2, 335 00055 { 0x98, 0x03, 0x9c, 0x00, 0xd1, 0xb7, 0x00, 0xd4, 0x28, 0x20, 0x29, 0x80, 0x60, 0x09, 0xd5, 0x0c, 0x21, 0x08 }, // 38.4, 335 00056 { 0x98, 0x03, 0x96, 0x00, 0xda, 0x74, 0x00, 0xdc, 0x28, 0x1f, 0x29, 0x80, 0x60, 0x0a, 0x3d, 0x0c, 0x21, 0x08 }, // 40, 335 00057 }; 00058 00059 RH_RF22::RH_RF22(PINS slaveSelectPin, PINS interruptPin, RHGenericSPI& spi) 00060 : 00061 RHSPIDriver(slaveSelectPin, spi), 00062 _interruptPin(interruptPin) 00063 { 00064 _idleMode = RH_RF22_XTON; // Default idle state is READY mode 00065 _polynomial = CRC_16_IBM; // Historical 00066 _myInterruptIndex = 0xff; // Not allocated yet 00067 } 00068 00069 void RH_RF22::setIdleMode(uint8_t idleMode) 00070 { 00071 _idleMode = idleMode; 00072 } 00073 00074 bool RH_RF22::init() 00075 { 00076 if (!RHSPIDriver::init()) 00077 return false; 00078 00079 #if (RH_PLATFORM != RH_PLATFORM_MBED) 00080 // Determine the interrupt number that corresponds to the interruptPin 00081 int interruptNumber = digitalPinToInterrupt(_interruptPin); 00082 if (interruptNumber == NOT_AN_INTERRUPT) 00083 return false; 00084 #endif 00085 00086 // Software reset the device 00087 reset(); 00088 00089 // Get the device type and check it 00090 // This also tests whether we are really connected to a device 00091 _deviceType = spiRead(RH_RF22_REG_00_DEVICE_TYPE); 00092 if ( _deviceType != RH_RF22_DEVICE_TYPE_RX_TRX 00093 && _deviceType != RH_RF22_DEVICE_TYPE_TX) 00094 { 00095 return false; 00096 } 00097 00098 00099 #if (RH_PLATFORM != RH_PLATFORM_MBED) 00100 // Add by Adrien van den Bossche <vandenbo@univ-tlse2.fr> for Teensy 00101 // ARM M4 requires the below. else pin interrupt doesn't work properly. 00102 // On all other platforms, its innocuous, belt and braces 00103 pinMode(_interruptPin, INPUT); 00104 #endif 00105 00106 // Enable interrupt output on the radio. Interrupt line will now go high until 00107 // an interrupt occurs 00108 spiWrite(RH_RF22_REG_05_INTERRUPT_ENABLE1, RH_RF22_ENTXFFAEM | RH_RF22_ENRXFFAFULL | RH_RF22_ENPKSENT | RH_RF22_ENPKVALID | RH_RF22_ENCRCERROR | RH_RF22_ENFFERR); 00109 spiWrite(RH_RF22_REG_06_INTERRUPT_ENABLE2, RH_RF22_ENPREAVAL); 00110 00111 // Set up interrupt handler 00112 // Since there are a limited number of interrupt glue functions isr*() available, 00113 // we can only support a limited number of devices simultaneously 00114 // On some devices, notably most Arduinos, the interrupt pin passed in is actually the 00115 // interrupt number. You have to figure out the interruptnumber-to-interruptpin mapping 00116 // yourself based on knowledge of what Arduino board you are running on. 00117 if (_myInterruptIndex == 0xff) 00118 { 00119 // First run, no interrupt allocated yet 00120 if (_interruptCount <= RH_RF22_NUM_INTERRUPTS) 00121 _myInterruptIndex = _interruptCount++; 00122 else 00123 return false; // Too many devices, not enough interrupt vectors 00124 } 00125 _deviceForInterrupt[_myInterruptIndex] = this; 00126 00127 #if (RH_PLATFORM == RH_PLATFORM_MBED) 00128 if (_myInterruptIndex == 0) 00129 _interruptPin.fall(&isr0); 00130 else if (_myInterruptIndex == 1) 00131 _interruptPin.fall(&isr1); 00132 else if (_myInterruptIndex == 2) 00133 _interruptPin.fall(&isr2); 00134 else 00135 return false; // Too many devices, not enough interrupt vectors 00136 #else 00137 if (_myInterruptIndex == 0) 00138 attachInterrupt(interruptNumber, isr0, FALLING); 00139 else if (_myInterruptIndex == 1) 00140 attachInterrupt(interruptNumber, isr1, FALLING); 00141 else if (_myInterruptIndex == 2) 00142 attachInterrupt(interruptNumber, isr2, FALLING); 00143 else 00144 return false; // Too many devices, not enough interrupt vectors 00145 #endif 00146 00147 setModeIdle(); 00148 00149 clearTxBuf(); 00150 clearRxBuf(); 00151 00152 // Most of these are the POR default 00153 spiWrite(RH_RF22_REG_7D_TX_FIFO_CONTROL2, RH_RF22_TXFFAEM_THRESHOLD); 00154 spiWrite(RH_RF22_REG_7E_RX_FIFO_CONTROL, RH_RF22_RXFFAFULL_THRESHOLD); 00155 spiWrite(RH_RF22_REG_30_DATA_ACCESS_CONTROL, RH_RF22_ENPACRX | RH_RF22_ENPACTX | RH_RF22_ENCRC | (_polynomial & RH_RF22_CRC)); 00156 00157 // Configure the message headers 00158 // Here we set up the standard packet format for use by the RH_RF22 library 00159 // 8 nibbles preamble 00160 // 2 SYNC words 2d, d4 00161 // Header length 4 (to, from, id, flags) 00162 // 1 octet of data length (0 to 255) 00163 // 0 to 255 octets data 00164 // 2 CRC octets as CRC16(IBM), computed on the header, length and data 00165 // On reception the to address is check for validity against RH_RF22_REG_3F_CHECK_HEADER3 00166 // or the broadcast address of 0xff 00167 // If no changes are made after this, the transmitted 00168 // to address will be 0xff, the from address will be 0xff 00169 // and all such messages will be accepted. This permits the out-of the box 00170 // RH_RF22 config to act as an unaddresed, unreliable datagram service 00171 spiWrite(RH_RF22_REG_32_HEADER_CONTROL1, RH_RF22_BCEN_HEADER3 | RH_RF22_HDCH_HEADER3); 00172 spiWrite(RH_RF22_REG_33_HEADER_CONTROL2, RH_RF22_HDLEN_4 | RH_RF22_SYNCLEN_2); 00173 00174 setPreambleLength(8); 00175 uint8_t syncwords[] = { 0x2d, 0xd4 }; 00176 setSyncWords(syncwords, sizeof(syncwords)); 00177 setPromiscuous(false); 00178 00179 // Set some defaults. An innocuous ISM frequency, and reasonable pull-in 00180 setFrequency(434.0, 0.05); 00181 // setFrequency(900.0); 00182 // Some slow, reliable default speed and modulation 00183 setModemConfig(FSK_Rb2_4Fd36); 00184 // setModemConfig(FSK_Rb125Fd125); 00185 setGpioReversed(false); 00186 // Lowish power 00187 setTxPower(RH_RF22_TXPOW_8DBM); 00188 00189 return true; 00190 } 00191 00192 // C++ level interrupt handler for this instance 00193 void RH_RF22::handleInterrupt() 00194 { 00195 uint8_t _lastInterruptFlags[2]; 00196 // Read the interrupt flags which clears the interrupt 00197 spiBurstRead(RH_RF22_REG_03_INTERRUPT_STATUS1, _lastInterruptFlags, 2); 00198 00199 #if 0 00200 // DEVELOPER TESTING ONLY 00201 // Caution: Serial printing in this interrupt routine can cause mysterious crashes 00202 Serial.print("interrupt "); 00203 Serial.print(_lastInterruptFlags[0], HEX); 00204 Serial.print(" "); 00205 Serial.println(_lastInterruptFlags[1], HEX); 00206 if (_lastInterruptFlags[0] == 0 && _lastInterruptFlags[1] == 0) 00207 Serial.println("FUNNY: no interrupt!"); 00208 #endif 00209 00210 #if 0 00211 // DEVELOPER TESTING ONLY 00212 // TESTING: fake an RH_RF22_IFFERROR 00213 static int counter = 0; 00214 if (_lastInterruptFlags[0] & RH_RF22_IPKSENT && counter++ == 10) 00215 { 00216 _lastInterruptFlags[0] = RH_RF22_IFFERROR; 00217 counter = 0; 00218 } 00219 #endif 00220 00221 if (_lastInterruptFlags[0] & RH_RF22_IFFERROR) 00222 { 00223 resetFifos(); // Clears the interrupt 00224 if (_mode == RHModeTx) 00225 restartTransmit(); 00226 else if (_mode == RHModeRx) 00227 clearRxBuf(); 00228 // Serial.println("IFFERROR"); 00229 } 00230 // Caution, any delay here may cause a FF underflow or overflow 00231 if (_lastInterruptFlags[0] & RH_RF22_ITXFFAEM) 00232 { 00233 // See if more data has to be loaded into the Tx FIFO 00234 sendNextFragment(); 00235 // Serial.println("ITXFFAEM"); 00236 } 00237 if (_lastInterruptFlags[0] & RH_RF22_IRXFFAFULL) 00238 { 00239 // Caution, any delay here may cause a FF overflow 00240 // Read some data from the Rx FIFO 00241 readNextFragment(); 00242 // Serial.println("IRXFFAFULL"); 00243 } 00244 if (_lastInterruptFlags[0] & RH_RF22_IEXT) 00245 { 00246 // This is not enabled by the base code, but users may want to enable it 00247 handleExternalInterrupt(); 00248 // Serial.println("IEXT"); 00249 } 00250 if (_lastInterruptFlags[1] & RH_RF22_IWUT) 00251 { 00252 // This is not enabled by the base code, but users may want to enable it 00253 handleWakeupTimerInterrupt(); 00254 // Serial.println("IWUT"); 00255 } 00256 if (_lastInterruptFlags[0] & RH_RF22_IPKSENT) 00257 { 00258 // Serial.println("IPKSENT"); 00259 _txGood++; 00260 // Transmission does not automatically clear the tx buffer. 00261 // Could retransmit if we wanted 00262 // RH_RF22 transitions automatically to Idle 00263 _mode = RHModeIdle; 00264 } 00265 if (_lastInterruptFlags[0] & RH_RF22_IPKVALID) 00266 { 00267 uint8_t len = spiRead(RH_RF22_REG_4B_RECEIVED_PACKET_LENGTH); 00268 // Serial.println("IPKVALID"); 00269 00270 // May have already read one or more fragments 00271 // Get any remaining unread octets, based on the expected length 00272 // First make sure we dont overflow the buffer in the case of a stupid length 00273 // or partial bad receives 00274 if ( len > RH_RF22_MAX_MESSAGE_LEN 00275 || len < _bufLen) 00276 { 00277 _rxBad++; 00278 _mode = RHModeIdle; 00279 clearRxBuf(); 00280 return; // Hmmm receiver buffer overflow. 00281 } 00282 00283 spiBurstRead(RH_RF22_REG_7F_FIFO_ACCESS, _buf + _bufLen, len - _bufLen); 00284 _rxHeaderTo = spiRead(RH_RF22_REG_47_RECEIVED_HEADER3); 00285 _rxHeaderFrom = spiRead(RH_RF22_REG_48_RECEIVED_HEADER2); 00286 _rxHeaderId = spiRead(RH_RF22_REG_49_RECEIVED_HEADER1); 00287 _rxHeaderFlags = spiRead(RH_RF22_REG_4A_RECEIVED_HEADER0); 00288 _rxGood++; 00289 _bufLen = len; 00290 _mode = RHModeIdle; 00291 _rxBufValid = true; 00292 } 00293 if (_lastInterruptFlags[0] & RH_RF22_ICRCERROR) 00294 { 00295 // Serial.println("ICRCERR"); 00296 _rxBad++; 00297 clearRxBuf(); 00298 resetRxFifo(); 00299 _mode = RHModeIdle; 00300 setModeRx(); // Keep trying 00301 } 00302 if (_lastInterruptFlags[1] & RH_RF22_IPREAVAL) 00303 { 00304 // Serial.println("IPREAVAL"); 00305 _lastRssi = (int8_t)(-120 + ((spiRead(RH_RF22_REG_26_RSSI) / 2))); 00306 _lastPreambleTime = millis(); 00307 resetRxFifo(); 00308 clearRxBuf(); 00309 } 00310 } 00311 00312 // These are low level functions that call the interrupt handler for the correct 00313 // instance of RH_RF22. 00314 // 3 interrupts allows us to have 3 different devices 00315 void RH_RF22::isr0() 00316 { 00317 if (_deviceForInterrupt[0]) 00318 _deviceForInterrupt[0]->handleInterrupt(); 00319 } 00320 void RH_RF22::isr1() 00321 { 00322 if (_deviceForInterrupt[1]) 00323 _deviceForInterrupt[1]->handleInterrupt(); 00324 } 00325 void RH_RF22::isr2() 00326 { 00327 if (_deviceForInterrupt[2]) 00328 _deviceForInterrupt[2]->handleInterrupt(); 00329 } 00330 00331 void RH_RF22::reset() 00332 { 00333 spiWrite(RH_RF22_REG_07_OPERATING_MODE1, RH_RF22_SWRES); 00334 // Wait for it to settle 00335 delay(1); // SWReset time is nominally 100usec 00336 } 00337 00338 uint8_t RH_RF22::statusRead() 00339 { 00340 return spiRead(RH_RF22_REG_02_DEVICE_STATUS); 00341 } 00342 00343 uint8_t RH_RF22::adcRead(uint8_t adcsel, 00344 uint8_t adcref , 00345 uint8_t adcgain, 00346 uint8_t adcoffs) 00347 { 00348 uint8_t configuration = adcsel | adcref | (adcgain & RH_RF22_ADCGAIN); 00349 spiWrite(RH_RF22_REG_0F_ADC_CONFIGURATION, configuration | RH_RF22_ADCSTART); 00350 spiWrite(RH_RF22_REG_10_ADC_SENSOR_AMP_OFFSET, adcoffs); 00351 00352 // Conversion time is nominally 305usec 00353 // Wait for the DONE bit 00354 while (!(spiRead(RH_RF22_REG_0F_ADC_CONFIGURATION) & RH_RF22_ADCDONE)) 00355 ; 00356 // Return the value 00357 return spiRead(RH_RF22_REG_11_ADC_VALUE); 00358 } 00359 00360 uint8_t RH_RF22::temperatureRead(uint8_t tsrange, uint8_t tvoffs) 00361 { 00362 spiWrite(RH_RF22_REG_12_TEMPERATURE_SENSOR_CALIBRATION, tsrange | RH_RF22_ENTSOFFS); 00363 spiWrite(RH_RF22_REG_13_TEMPERATURE_VALUE_OFFSET, tvoffs); 00364 return adcRead(RH_RF22_ADCSEL_INTERNAL_TEMPERATURE_SENSOR | RH_RF22_ADCREF_BANDGAP_VOLTAGE); 00365 } 00366 00367 uint16_t RH_RF22::wutRead() 00368 { 00369 uint8_t buf[2]; 00370 spiBurstRead(RH_RF22_REG_17_WAKEUP_TIMER_VALUE1, buf, 2); 00371 return ((uint16_t)buf[0] << 8) | buf[1]; // Dont rely on byte order 00372 } 00373 00374 // RFM-22 doc appears to be wrong: WUT for wtm = 10000, r, = 0, d = 0 is about 1 sec 00375 void RH_RF22::setWutPeriod(uint16_t wtm, uint8_t wtr, uint8_t wtd) 00376 { 00377 uint8_t period[3]; 00378 00379 period[0] = ((wtr & 0xf) << 2) | (wtd & 0x3); 00380 period[1] = wtm >> 8; 00381 period[2] = wtm & 0xff; 00382 spiBurstWrite(RH_RF22_REG_14_WAKEUP_TIMER_PERIOD1, period, sizeof(period)); 00383 } 00384 00385 // Returns true if centre + (fhch * fhs) is within limits 00386 // Caution, different versions of the RH_RF22 support different max freq 00387 // so YMMV 00388 bool RH_RF22::setFrequency(float centre, float afcPullInRange) 00389 { 00390 uint8_t fbsel = RH_RF22_SBSEL; 00391 uint8_t afclimiter; 00392 if (centre < 240.0 || centre > 960.0) // 930.0 for early silicon 00393 return false; 00394 if (centre >= 480.0) 00395 { 00396 if (afcPullInRange < 0.0 || afcPullInRange > 0.318750) 00397 return false; 00398 centre /= 2; 00399 fbsel |= RH_RF22_HBSEL; 00400 afclimiter = afcPullInRange * 1000000.0 / 1250.0; 00401 } 00402 else 00403 { 00404 if (afcPullInRange < 0.0 || afcPullInRange > 0.159375) 00405 return false; 00406 afclimiter = afcPullInRange * 1000000.0 / 625.0; 00407 } 00408 centre /= 10.0; 00409 float integerPart = floor(centre); 00410 float fractionalPart = centre - integerPart; 00411 00412 uint8_t fb = (uint8_t)integerPart - 24; // Range 0 to 23 00413 fbsel |= fb; 00414 uint16_t fc = fractionalPart * 64000; 00415 spiWrite(RH_RF22_REG_73_FREQUENCY_OFFSET1, 0); // REVISIT 00416 spiWrite(RH_RF22_REG_74_FREQUENCY_OFFSET2, 0); 00417 spiWrite(RH_RF22_REG_75_FREQUENCY_BAND_SELECT, fbsel); 00418 spiWrite(RH_RF22_REG_76_NOMINAL_CARRIER_FREQUENCY1, fc >> 8); 00419 spiWrite(RH_RF22_REG_77_NOMINAL_CARRIER_FREQUENCY0, fc & 0xff); 00420 spiWrite(RH_RF22_REG_2A_AFC_LIMITER, afclimiter); 00421 return !(statusRead() & RH_RF22_FREQERR); 00422 } 00423 00424 // Step size in 10kHz increments 00425 // Returns true if centre + (fhch * fhs) is within limits 00426 bool RH_RF22::setFHStepSize(uint8_t fhs) 00427 { 00428 spiWrite(RH_RF22_REG_7A_FREQUENCY_HOPPING_STEP_SIZE, fhs); 00429 return !(statusRead() & RH_RF22_FREQERR); 00430 } 00431 00432 // Adds fhch * fhs to centre frequency 00433 // Returns true if centre + (fhch * fhs) is within limits 00434 bool RH_RF22::setFHChannel(uint8_t fhch) 00435 { 00436 spiWrite(RH_RF22_REG_79_FREQUENCY_HOPPING_CHANNEL_SELECT, fhch); 00437 return !(statusRead() & RH_RF22_FREQERR); 00438 } 00439 00440 uint8_t RH_RF22::rssiRead() 00441 { 00442 return spiRead(RH_RF22_REG_26_RSSI); 00443 } 00444 00445 uint8_t RH_RF22::ezmacStatusRead() 00446 { 00447 return spiRead(RH_RF22_REG_31_EZMAC_STATUS); 00448 } 00449 00450 void RH_RF22::setOpMode(uint8_t mode) 00451 { 00452 spiWrite(RH_RF22_REG_07_OPERATING_MODE1, mode); 00453 } 00454 00455 void RH_RF22::setModeIdle() 00456 { 00457 if (_mode != RHModeIdle) 00458 { 00459 setOpMode(_idleMode); 00460 _mode = RHModeIdle; 00461 } 00462 } 00463 00464 bool RH_RF22::sleep() 00465 { 00466 if (_mode != RHModeSleep) 00467 { 00468 setOpMode(0); 00469 _mode = RHModeSleep; 00470 } 00471 return true; 00472 } 00473 00474 void RH_RF22::setModeRx() 00475 { 00476 if (_mode != RHModeRx) 00477 { 00478 setOpMode(_idleMode | RH_RF22_RXON); 00479 _mode = RHModeRx; 00480 } 00481 } 00482 00483 void RH_RF22::setModeTx() 00484 { 00485 if (_mode != RHModeTx) 00486 { 00487 setOpMode(_idleMode | RH_RF22_TXON); 00488 // Hmmm, if you dont clear the RX FIFO here, then it appears that going 00489 // to transmit mode in the middle of a receive can corrupt the 00490 // RX FIFO 00491 resetRxFifo(); 00492 _mode = RHModeTx; 00493 } 00494 } 00495 00496 void RH_RF22::setTxPower(uint8_t power) 00497 { 00498 spiWrite(RH_RF22_REG_6D_TX_POWER, power | RH_RF22_LNA_SW); // On RF23, LNA_SW must be set. 00499 } 00500 00501 // Sets registers from a canned modem configuration structure 00502 void RH_RF22::setModemRegisters(const ModemConfig* config) 00503 { 00504 spiWrite(RH_RF22_REG_1C_IF_FILTER_BANDWIDTH, config->reg_1c); 00505 spiWrite(RH_RF22_REG_1F_CLOCK_RECOVERY_GEARSHIFT_OVERRIDE, config->reg_1f); 00506 spiBurstWrite(RH_RF22_REG_20_CLOCK_RECOVERY_OVERSAMPLING_RATE, &config->reg_20, 6); 00507 spiBurstWrite(RH_RF22_REG_2C_OOK_COUNTER_VALUE_1, &config->reg_2c, 3); 00508 spiWrite(RH_RF22_REG_58_CHARGE_PUMP_CURRENT_TRIMMING, config->reg_58); 00509 spiWrite(RH_RF22_REG_69_AGC_OVERRIDE1, config->reg_69); 00510 spiBurstWrite(RH_RF22_REG_6E_TX_DATA_RATE1, &config->reg_6e, 5); 00511 } 00512 00513 // Set one of the canned FSK Modem configs 00514 // Returns true if its a valid choice 00515 bool RH_RF22::setModemConfig(ModemConfigChoice index) 00516 { 00517 if (index > (signed int)(sizeof(MODEM_CONFIG_TABLE) / sizeof(ModemConfig))) 00518 return false; 00519 00520 RH_RF22::ModemConfig cfg; 00521 memcpy_P(&cfg, &MODEM_CONFIG_TABLE[index], sizeof(RH_RF22::ModemConfig)); 00522 setModemRegisters(&cfg); 00523 00524 return true; 00525 } 00526 00527 // REVISIT: top bit is in Header Control 2 0x33 00528 void RH_RF22::setPreambleLength(uint8_t nibbles) 00529 { 00530 spiWrite(RH_RF22_REG_34_PREAMBLE_LENGTH, nibbles); 00531 } 00532 00533 // Caution doesnt set sync word len in Header Control 2 0x33 00534 void RH_RF22::setSyncWords(const uint8_t* syncWords, uint8_t len) 00535 { 00536 spiBurstWrite(RH_RF22_REG_36_SYNC_WORD3, syncWords, len); 00537 } 00538 00539 void RH_RF22::clearRxBuf() 00540 { 00541 ATOMIC_BLOCK_START; 00542 _bufLen = 0; 00543 _rxBufValid = false; 00544 ATOMIC_BLOCK_END; 00545 } 00546 00547 bool RH_RF22::available() 00548 { 00549 if (!_rxBufValid) 00550 { 00551 if (_mode == RHModeTx) 00552 return false; 00553 setModeRx(); // Make sure we are receiving 00554 } 00555 return _rxBufValid; 00556 } 00557 00558 bool RH_RF22::recv(uint8_t* buf, uint8_t* len) 00559 { 00560 if (!available()) 00561 return false; 00562 00563 if (buf && len) 00564 { 00565 ATOMIC_BLOCK_START; 00566 if (*len > _bufLen) 00567 *len = _bufLen; 00568 memcpy(buf, _buf, *len); 00569 ATOMIC_BLOCK_END; 00570 } 00571 clearRxBuf(); 00572 // printBuffer("recv:", buf, *len); 00573 return true; 00574 } 00575 00576 void RH_RF22::clearTxBuf() 00577 { 00578 ATOMIC_BLOCK_START; 00579 _bufLen = 0; 00580 _txBufSentIndex = 0; 00581 ATOMIC_BLOCK_END; 00582 } 00583 00584 void RH_RF22::startTransmit() 00585 { 00586 sendNextFragment(); // Actually the first fragment 00587 spiWrite(RH_RF22_REG_3E_PACKET_LENGTH, _bufLen); // Total length that will be sent 00588 setModeTx(); // Start the transmitter, turns off the receiver 00589 } 00590 00591 // Restart the transmission of a packet that had a problem 00592 void RH_RF22::restartTransmit() 00593 { 00594 _mode = RHModeIdle; 00595 _txBufSentIndex = 0; 00596 // Serial.println("Restart"); 00597 startTransmit(); 00598 } 00599 00600 bool RH_RF22::send(const uint8_t* data, uint8_t len) 00601 { 00602 bool ret = true; 00603 waitPacketSent(); 00604 ATOMIC_BLOCK_START; 00605 spiWrite(RH_RF22_REG_3A_TRANSMIT_HEADER3, _txHeaderTo); 00606 spiWrite(RH_RF22_REG_3B_TRANSMIT_HEADER2, _txHeaderFrom); 00607 spiWrite(RH_RF22_REG_3C_TRANSMIT_HEADER1, _txHeaderId); 00608 spiWrite(RH_RF22_REG_3D_TRANSMIT_HEADER0, _txHeaderFlags); 00609 if (!fillTxBuf(data, len)) 00610 ret = false; 00611 else 00612 startTransmit(); 00613 ATOMIC_BLOCK_END; 00614 // printBuffer("send:", data, len); 00615 return ret; 00616 } 00617 00618 bool RH_RF22::fillTxBuf(const uint8_t* data, uint8_t len) 00619 { 00620 clearTxBuf(); 00621 if (!len) 00622 return false; 00623 return appendTxBuf(data, len); 00624 } 00625 00626 bool RH_RF22::appendTxBuf(const uint8_t* data, uint8_t len) 00627 { 00628 if (((uint16_t)_bufLen + len) > RH_RF22_MAX_MESSAGE_LEN) 00629 return false; 00630 ATOMIC_BLOCK_START; 00631 memcpy(_buf + _bufLen, data, len); 00632 _bufLen += len; 00633 ATOMIC_BLOCK_END; 00634 // printBuffer("txbuf:", _buf, _bufLen); 00635 return true; 00636 } 00637 00638 // Assumption: there is currently <= RH_RF22_TXFFAEM_THRESHOLD bytes in the Tx FIFO 00639 void RH_RF22::sendNextFragment() 00640 { 00641 if (_txBufSentIndex < _bufLen) 00642 { 00643 // Some left to send? 00644 uint8_t len = _bufLen - _txBufSentIndex; 00645 // But dont send too much 00646 if (len > (RH_RF22_FIFO_SIZE - RH_RF22_TXFFAEM_THRESHOLD - 1)) 00647 len = (RH_RF22_FIFO_SIZE - RH_RF22_TXFFAEM_THRESHOLD - 1); 00648 spiBurstWrite(RH_RF22_REG_7F_FIFO_ACCESS, _buf + _txBufSentIndex, len); 00649 // printBuffer("frag:", _buf + _txBufSentIndex, len); 00650 _txBufSentIndex += len; 00651 } 00652 } 00653 00654 // Assumption: there are at least RH_RF22_RXFFAFULL_THRESHOLD in the RX FIFO 00655 // That means it should only be called after a RXFFAFULL interrupt 00656 void RH_RF22::readNextFragment() 00657 { 00658 if (((uint16_t)_bufLen + RH_RF22_RXFFAFULL_THRESHOLD) > RH_RF22_MAX_MESSAGE_LEN) 00659 return; // Hmmm receiver overflow. Should never occur 00660 00661 // Read the RH_RF22_RXFFAFULL_THRESHOLD octets that should be there 00662 spiBurstRead(RH_RF22_REG_7F_FIFO_ACCESS, _buf + _bufLen, RH_RF22_RXFFAFULL_THRESHOLD); 00663 _bufLen += RH_RF22_RXFFAFULL_THRESHOLD; 00664 } 00665 00666 // Clear the FIFOs 00667 void RH_RF22::resetFifos() 00668 { 00669 spiWrite(RH_RF22_REG_08_OPERATING_MODE2, RH_RF22_FFCLRRX | RH_RF22_FFCLRTX); 00670 spiWrite(RH_RF22_REG_08_OPERATING_MODE2, 0); 00671 } 00672 00673 // Clear the Rx FIFO 00674 void RH_RF22::resetRxFifo() 00675 { 00676 spiWrite(RH_RF22_REG_08_OPERATING_MODE2, RH_RF22_FFCLRRX); 00677 spiWrite(RH_RF22_REG_08_OPERATING_MODE2, 0); 00678 } 00679 00680 // CLear the TX FIFO 00681 void RH_RF22::resetTxFifo() 00682 { 00683 spiWrite(RH_RF22_REG_08_OPERATING_MODE2, RH_RF22_FFCLRTX); 00684 spiWrite(RH_RF22_REG_08_OPERATING_MODE2, 0); 00685 } 00686 00687 // Default implmentation does nothing. Override if you wish 00688 void RH_RF22::handleExternalInterrupt() 00689 { 00690 } 00691 00692 // Default implmentation does nothing. Override if you wish 00693 void RH_RF22::handleWakeupTimerInterrupt() 00694 { 00695 } 00696 00697 void RH_RF22::setPromiscuous(bool promiscuous) 00698 { 00699 RHSPIDriver::setPromiscuous(promiscuous); 00700 spiWrite(RH_RF22_REG_43_HEADER_ENABLE3, promiscuous ? 0x00 : 0xff); 00701 } 00702 00703 bool RH_RF22::setCRCPolynomial(CRCPolynomial polynomial) 00704 { 00705 if (polynomial >= CRC_CCITT && 00706 polynomial <= CRC_Biacheva) 00707 { 00708 _polynomial = polynomial; 00709 return true; 00710 } 00711 else 00712 return false; 00713 } 00714 00715 uint8_t RH_RF22::maxMessageLength() 00716 { 00717 return RH_RF22_MAX_MESSAGE_LEN; 00718 } 00719 00720 void RH_RF22::setThisAddress(uint8_t thisAddress) 00721 { 00722 RHSPIDriver::setThisAddress(thisAddress); 00723 spiWrite(RH_RF22_REG_3F_CHECK_HEADER3, thisAddress); 00724 } 00725 00726 uint32_t RH_RF22::getLastPreambleTime() 00727 { 00728 return _lastPreambleTime; 00729 } 00730 00731 void RH_RF22::setGpioReversed(bool gpioReversed) 00732 { 00733 // Ensure the antenna can be switched automatically according to transmit and receive 00734 // This assumes GPIO0(out) is connected to TX_ANT(in) to enable tx antenna during transmit 00735 // This assumes GPIO1(out) is connected to RX_ANT(in) to enable rx antenna during receive 00736 if (gpioReversed) 00737 { 00738 // Reversed for HAB-RFM22B-BOA HAB-RFM22B-BO, also Si4432 sold by Dorji.com via Tindie.com. 00739 spiWrite(RH_RF22_REG_0B_GPIO_CONFIGURATION0, 0x15) ; // RX state 00740 spiWrite(RH_RF22_REG_0C_GPIO_CONFIGURATION1, 0x12) ; // TX state 00741 } 00742 else 00743 { 00744 spiWrite(RH_RF22_REG_0B_GPIO_CONFIGURATION0, 0x12) ; // TX state 00745 spiWrite(RH_RF22_REG_0C_GPIO_CONFIGURATION1, 0x15) ; // RX state 00746 } 00747 } 00748
Generated on Tue Jul 12 2022 18:05:55 by
