Library for HopeRF RFM22 transceiver module ported to mbed. Original Software from Mike McCauley (mikem@open.com.au) . See http://www.open.com.au/mikem/arduino/RF22/

Fork of RF22 by Karl Zweimüller

Revision:
5:0386600f3408
Parent:
4:f0bf38bb0ff8
Child:
7:b86825b9d74b
--- a/RF22.cpp	Sun Feb 19 21:12:10 2012 +0000
+++ b/RF22.cpp	Sat Mar 02 20:49:07 2013 +0000
@@ -1,7 +1,7 @@
 // RF22.cpp
 //
 // Copyright (C) 2011 Mike McCauley
-// $Id: RF22.cpp,v 1.13 2011/10/09 21:22:24 mikem Exp mikem $
+// $Id: RF22.cpp,v 1.17 2013/02/06 21:33:56 mikem Exp mikem $
 // ported to mbed by Karl Zweimueller
 
 
@@ -17,13 +17,14 @@
 
 // These are indexed by the values of ModemConfigChoice
 // Canned modem configurations generated with 
-// 'http://www.hoperf.com/upfile/RF22B 23B 31B 42B 43B Register Settings_RevB1-v5.xls'
+// http://www.hoperf.com/upload/rf/RF22B%2023B%2031B%2042B%2043B%20Register%20Settings_RevB1-v5.xls
 // Stored in flash (program) memory to save SRAM
 /*PROGMEM */ static const RF22::ModemConfig MODEM_CONFIG_TABLE[] =
 {
     { 0x2b, 0x03, 0xf4, 0x20, 0x41, 0x89, 0x00, 0x36, 0x40, 0x0a, 0x1d, 0x80, 0x60, 0x10, 0x62, 0x2c, 0x00, 0x08 }, // Unmodulated carrier
     { 0x2b, 0x03, 0xf4, 0x20, 0x41, 0x89, 0x00, 0x36, 0x40, 0x0a, 0x1d, 0x80, 0x60, 0x10, 0x62, 0x2c, 0x33, 0x08 }, // FSK, PN9 random modulation, 2, 5
 
+    // All the following enable FIFO with reg 71
     //  1c,   1f,   20,   21,   22,   23,   24,   25,   2c,   2d,   2e,   58,   69,   6e,   6f,   70,   71,   72
     // FSK, No Manchester, Max Rb err <1%, Xtal Tol 20ppm
     { 0x2b, 0x03, 0xf4, 0x20, 0x41, 0x89, 0x00, 0x36, 0x40, 0x0a, 0x1d, 0x80, 0x60, 0x10, 0x62, 0x2c, 0x22, 0x08 }, // 2, 5
@@ -167,9 +168,8 @@
     spiWrite(RF22_REG_05_INTERRUPT_ENABLE1, RF22_ENTXFFAEM | RF22_ENRXFFAFULL | RF22_ENPKSENT | RF22_ENPKVALID | RF22_ENCRCERROR | RF22_ENFFERR);
     spiWrite(RF22_REG_06_INTERRUPT_ENABLE2, RF22_ENPREAVAL);
 
-    // Set some defaults. An innocuous ISM frequency
-    setFrequency(868.0);
-//    setFrequency(434.0);
+    // Set some defaults. An innocuous ISM frequency, and reasonable pull-in
+    setFrequency(434.0, 0.05);
 //    setFrequency(900.0);
     // Some slow, reliable default speed and modulation
     setModemConfig(FSK_Rb2_4Fd36);
@@ -181,7 +181,7 @@
 // Set the AFC for receiver to max. 0,1MHz
 // Other AFC-Registers have PowerOnValues which enable AFC
 // RF22_AFC_LIMIT                          0x50   =0,1MHz
-   spiWrite(RF22_REG_2A_AFC_LIMITER, RF22_AFC_LIMIT);  // POR=0x00 = OFF
+//   spiWrite(RF22_REG_2A_AFC_LIMITER, RF22_AFC_LIMIT);  // POR=0x00 = OFF
 
     return true;
 }
@@ -197,7 +197,8 @@
     spiBurstRead(RF22_REG_03_INTERRUPT_STATUS1, _lastInterruptFlags, 2);
 
 #if 0
-    pc.print("interrupt ");
+    // Caution: Serial printing in this interrupt routine can cause mysterious crashes
+    Serial.print("interrupt ");
     Serial.print(_lastInterruptFlags[0], HEX);
     Serial.print(" ");
     Serial.println(_lastInterruptFlags[1], HEX);
@@ -205,7 +206,7 @@
     Serial.println("FUNNY: no interrupt!");
 #endif
 
-/*
+#if 0
     // TESTING: fake an RF22_IFFERROR
     static int counter = 0;
     if (_lastInterruptFlags[0] & RF22_IPKSENT && counter++ == 10)
@@ -213,7 +214,7 @@
     _lastInterruptFlags[0] = RF22_IFFERROR;
     counter = 0;
     }
-*/
+#endif
 
     if (_lastInterruptFlags[0] & RF22_IFFERROR)
     {
@@ -229,7 +230,7 @@
     {
     // See if more data has to be loaded into the Tx FIFO 
     sendNextFragment();
-//    Serial.println("TXFFAEM");  
+//  Serial.println("ITXFFAEM");  
     }
     if (_lastInterruptFlags[0] & RF22_IRXFFAFULL)
     {
@@ -252,28 +253,42 @@
     }
     if (_lastInterruptFlags[0] & RF22_IPKSENT)
     {
-//    Serial.println("PKSENT");   
+//  Serial.println("IPKSENT");   
     _txGood++; 
     led4 = !led4;
     // Transmission does not automatically clear the tx buffer.
     // Could retransmit if we wanted
-    _txPacketSent = true;
     // RF22 transitions automatically to Idle
     _mode = RF22_MODE_IDLE;
     }
     if (_lastInterruptFlags[0] & RF22_IPKVALID)
     {
-//    Serial.println("IPKVALID");    
     uint8_t len = spiRead(RF22_REG_4B_RECEIVED_PACKET_LENGTH);
+//  Serial.println("IPKVALID");   
+//  Serial.println(len);   
+//  Serial.println(_bufLen);   
+
     // May have already read one or more fragments
     // Get any remaining unread octets, based on the expected length
-    len -= _bufLen;
-    spiBurstRead(RF22_REG_7F_FIFO_ACCESS, _buf + _bufLen, len);
+    // First make sure we dont overflow the buffer in the case of a stupid length
+    // or partial bad receives
+    if (   len >  RF22_MAX_MESSAGE_LEN
+        || len < _bufLen)
+    {
+        _rxBad++;
+        _mode = RF22_MODE_IDLE;
+        clearRxBuf();
+        return; // Hmmm receiver buffer overflow. 
+    }
+
+    spiBurstRead(RF22_REG_7F_FIFO_ACCESS, _buf + _bufLen, len - _bufLen);
     _rxGood++;
-    led3 = !led3;
-    _bufLen += len;
+    _bufLen = len;
     _mode = RF22_MODE_IDLE;
     _rxBufValid = true;
+
+    led3 = !led3;
+
     }
     if (_lastInterruptFlags[0] & RF22_ICRCERROR)
     {
@@ -287,7 +302,7 @@
     }
     if (_lastInterruptFlags[1] & RF22_IPREAVAL)
     {
-//    Serial.println("ENPREAVAL");  
+//  Serial.println("IPREAVAL");  
     _lastRssi = spiRead(RF22_REG_26_RSSI);
     clearRxBuf();
     }
@@ -350,7 +365,7 @@
     _slaveSelectPin = 1;
 }
 
-void RF22::spiBurstWrite(uint8_t reg, uint8_t* src, uint8_t len)
+void RF22::spiBurstWrite(uint8_t reg, const uint8_t* src, uint8_t len)
 {
     //digitalWrite(_slaveSelectPin, LOW);
     _slaveSelectPin = 0;
@@ -409,17 +424,27 @@
 }
 
 // Returns true if centre + (fhch * fhs) is within limits
-// Caution, different versions of the RF22 suport different max freq
+// Caution, different versions of the RF22 support different max freq
 // so YMMV
-boolean RF22::setFrequency(float centre)
+boolean RF22::setFrequency(float centre, float afcPullInRange)
 {
     uint8_t fbsel = RF22_SBSEL;
+    uint8_t afclimiter;
     if (centre < 240.0 || centre > 960.0) // 930.0 for early silicon
     return false;
     if (centre >= 480.0)
     {
+    if (afcPullInRange < 0.0 || afcPullInRange > 0.318750)
+        return false;
     centre /= 2;
     fbsel |= RF22_HBSEL;
+    afclimiter = afcPullInRange * 1000000.0 / 1250.0;
+    }
+    else
+    {
+    if (afcPullInRange < 0.0 || afcPullInRange > 0.159375)
+        return false;
+    afclimiter = afcPullInRange * 1000000.0 / 625.0;
     }
     centre /= 10.0;
     float integerPart = floor(centre);
@@ -433,6 +458,7 @@
     spiWrite(RF22_REG_75_FREQUENCY_BAND_SELECT, fbsel);
     spiWrite(RF22_REG_76_NOMINAL_CARRIER_FREQUENCY1, fc >> 8);
     spiWrite(RF22_REG_77_NOMINAL_CARRIER_FREQUENCY0, fc & 0xff);
+    spiWrite(RF22_REG_2A_AFC_LIMITER, afclimiter);
     return !(statusRead() & RF22_FREQERR);
 }
 
@@ -491,7 +517,17 @@
     {
     setMode(_idleMode | RF22_TXON);
     _mode = RF22_MODE_TX;
+    // Hmmm, if you dont clear the RX FIFO here, then it appears that going
+    // to transmit mode in the middle of a receive can corrupt the
+    // RX FIFO
+    resetRxFifo();
+    clearRxBuf();
     }
+    }
+
+uint8_t  RF22::mode()
+{
+    return _mode;
 }
 
 void RF22::setTxPower(uint8_t power)
@@ -500,7 +536,7 @@
 }
 
 // Sets registers from a canned modem configuration structure
-void RF22::setModemRegisters(ModemConfig* config)
+void RF22::setModemRegisters(const ModemConfig* config)
 {
     spiWrite(RF22_REG_1C_IF_FILTER_BANDWIDTH,                    config->reg_1c);
     spiWrite(RF22_REG_1F_CLOCK_RECOVERY_GEARSHIFT_OVERRIDE,      config->reg_1f);
@@ -532,7 +568,7 @@
 }
 
 // Caution doesnt set sync word len in Header Control 2 0x33
-void RF22::setSyncWords(uint8_t* syncWords, uint8_t len)
+void RF22::setSyncWords(const uint8_t* syncWords, uint8_t len)
 {
     spiBurstWrite(RF22_REG_36_SYNC_WORD3, syncWords, len);
 }
@@ -545,7 +581,8 @@
 
 boolean RF22::available()
 {
-    setModeRx();
+    if (!_rxBufValid)
+    setModeRx(); // Make sure we are receiving
     return _rxBufValid;
 }
 
@@ -571,8 +608,29 @@
 
 void RF22::waitPacketSent()
 {
-    while (!_txPacketSent)
-    ;
+    while (_mode == RF22_MODE_TX)
+    ; // Wait for any previous transmit to finish
+}
+
+// Diagnostic help
+void RF22::printBuffer(const char* prompt, const uint8_t* buf, uint8_t len)
+{
+#ifdef RF22_HAVE_SERIAL
+    uint8_t i;
+
+    Serial.println(prompt);
+    for (i = 0; i < len; i++)
+    {
+    if (i % 16 == 15)
+        Serial.println(buf[i], HEX);
+    else
+    {
+        Serial.print(buf[i], HEX);
+        Serial.print(' ');
+    }
+    }
+    Serial.println(' ');
+#endif
 }
 
 boolean RF22::recv(uint8_t* buf, uint8_t* len)
@@ -583,6 +641,8 @@
     *len = _bufLen;
     memcpy(buf, _buf, *len);
     clearRxBuf();
+//    printBuffer("recv:", buf, *len);
+//    }
     return true;
 }
 
@@ -600,36 +660,44 @@
     setModeTx(); // Start the transmitter, turns off the receiver
 }
 
-// Restart the trasnmission of a packet that had a problem
+// Restart the transmission of a packet that had a problem
 void RF22::restartTransmit()
 {
     _mode = RF22_MODE_IDLE;
     _txBufSentIndex = 0;
-    _txPacketSent = false;
 //        Serial.println("Restart");
     startTransmit();
 }
 
-boolean RF22::send(uint8_t* data, uint8_t len)
+boolean RF22::send(const uint8_t* data, uint8_t len)
 {
-    setModeIdle();
-    fillTxBuf(data, len);
+    waitPacketSent();
+//    ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
+    {
+    if (!fillTxBuf(data, len))
+        return false;
     startTransmit();
+    }
+//    printBuffer("send:", data, len);
     return true;
 }
 
-boolean RF22::fillTxBuf(uint8_t* data, uint8_t len)
+boolean RF22::fillTxBuf(const uint8_t* data, uint8_t len)
 {
     clearTxBuf();
+    if (!len)
+    return false; 
     return appendTxBuf(data, len);
 }
 
-boolean RF22::appendTxBuf(uint8_t* data, uint8_t len)
+boolean RF22::appendTxBuf(const uint8_t* data, uint8_t len)
 {
     if (((uint16_t)_bufLen + len) > RF22_MAX_MESSAGE_LEN)
     return false;
     memcpy(_buf + _bufLen, data, len);
     _bufLen += len;
+    
+//    printBuffer("txbuf:", _buf, _bufLen);
     return true;
 }
 
@@ -638,7 +706,7 @@
 {
     if (_txBufSentIndex < _bufLen)
     {
-    // Some left to send
+    // Some left to send?
     uint8_t len = _bufLen - _txBufSentIndex;
     // But dont send too much
     if (len > (RF22_FIFO_SIZE - RF22_TXFFAEM_THRESHOLD - 1))
@@ -649,14 +717,12 @@
 }
 
 // Assumption: there are at least RF22_RXFFAFULL_THRESHOLD in the RX FIFO
-// That means it should only be called after a RXAFULL interrupt
+// That means it should only be called after a RXFFAFULL interrupt
 void RF22::readNextFragment()
 {
     if (((uint16_t)_bufLen + RF22_RXFFAFULL_THRESHOLD) > RF22_MAX_MESSAGE_LEN)
-    {
-    // Hmmm receiver overflow. Should never occur
-    return;
-    }
+    return; // Hmmm receiver overflow. Should never occur
+
     // Read the RF22_RXFFAFULL_THRESHOLD octets that should be there
     spiBurstRead(RF22_REG_7F_FIFO_ACCESS, _buf + _bufLen, RF22_RXFFAFULL_THRESHOLD);
     _bufLen += RF22_RXFFAFULL_THRESHOLD;