diff --git a/JeeLib.h b/JeeLib.h index ddcfb6d9..755fb129 100644 --- a/JeeLib.h +++ b/JeeLib.h @@ -14,15 +14,6 @@ #define RF69_COMPAT 0 #endif -// Modify the RF12 driver in such a way that it can inter-operate with RFM69 -// modules running in "native" mode. This affects packet layout and some more. - -#if RF12_COMPAT -#include -#elif !defined(RF12_COMPAT) -#define RF12_COMPAT 0 -#endif - #include #include #include diff --git a/RF12.cpp b/RF12.cpp index 59456260..ac765cde 100644 --- a/RF12.cpp +++ b/RF12.cpp @@ -13,6 +13,16 @@ #include // Arduino 0022 #endif +#if RF12_COMPAT +#define rf12_rawlen rf12_buf[1] +#define rf12_dest (rf12_buf[2] & RF12_HDR_MASK) +#define rf12_orig (rf12_buf[3] & RF12_HDR_MASK) +#else +#define rf12_rawlen rf12_len +// #define rf12_dest (rf12_hdr & RF12_HDR_DST ? rf12_hdr & RF12_HDR_MASK : 0) +// #define rf12_orig (rf12_hdr & RF12_HDR_DST ? 0 : rf12_hdr & RF12_HDR_MASK) +#endif + // #define OPTIMIZE_SPI 1 // uncomment this to write to the RFM12B @ 8 Mhz // pin change interrupts are currently only supported on ATmega328's @@ -68,9 +78,9 @@ #define SPI_MOSI 5 // PA5, pin 8 #define SPI_SCK 6 // PA4, pin 9 -#elif defined(__AVR_ATmega32U4__) //Arduino Leonardo +#elif defined(__AVR_ATmega32U4__) //Arduino Leonardo -#define RFM_IRQ 0 // PD0, INT0, Digital3 +#define RFM_IRQ 0 // PD0, INT0, Digital3 #define SS_DDR DDRB #define SS_PORT PORTB #define SS_BIT 6 // Dig10, PB6 @@ -94,7 +104,7 @@ #define SPI_MISO 12 // PB4, pin 18 #define SPI_SCK 13 // PB5, pin 19 -#endif +#endif // RF12 command codes #define RF_RECV_CONTROL 0x94A0 @@ -113,7 +123,7 @@ // bits in the node id configuration byte #define NODE_BAND 0xC0 // frequency band -#define NODE_ID 0x1F // id of this node, as A..Z or 1..31 +#define NODE_ID RF12_HDR_MASK // id of this node, as A..Z or 1..31 // transceiver states, these determine what to do with each interrupt enum { @@ -150,7 +160,7 @@ void (*crypter)(uint8_t); // does en-/decryption (null if disabled) // function to set chip select pin from within sketch void rf12_set_cs (uint8_t pin) { -#if defined(__AVR_ATmega32U4__) //Arduino Leonardo +#if defined(__AVR_ATmega32U4__) //Arduino Leonardo cs_pin = pin - 4; // Dig10 (PB6), Dig9 (PB5), or Dig8 (PB4) #elif defined(__AVR_ATmega168__) || defined(__AVR_ATmega328__) || defined (__AVR_ATmega328P__) // ATmega168, ATmega328 cs_pin = pin - 8; // Dig10 (PB2), Dig9 (PB1), or Dig8 (PB0) @@ -167,7 +177,7 @@ void rf12_spiInit () { pinMode(SPI_MOSI, OUTPUT); pinMode(SPI_MISO, INPUT); pinMode(SPI_SCK, OUTPUT); -#ifdef SPCR +#ifdef SPCR SPCR = _BV(SPE) | _BV(MSTR); #if F_CPU > 10000000 // use clk/2 (2x 1/4th) for sending (and clk/8 for recv, see rf12_xferSlow) @@ -176,7 +186,7 @@ void rf12_spiInit () { #else // ATtiny USICR = bit(USIWM0); -#endif +#endif pinMode(RFM_IRQ, INPUT); digitalWrite(RFM_IRQ, 1); // pull-up } @@ -248,7 +258,7 @@ static void rf12_xfer (uint16_t cmd) { /// /// This call will briefly disable interrupts to avoid clashes on the SPI bus. /// -/// Returns the 16-bit value returned by SPI. Probably only useful with a +/// Returns the 16-bit value returned by SPI. Probably only useful with a /// "0x0000" status poll command. /// @param cmd RF12 command, topmost bits determines which register is affected. uint16_t rf12_control(uint16_t cmd) { @@ -288,18 +298,18 @@ uint16_t rf12_control(uint16_t cmd) { static void rf12_interrupt () { // a transfer of 2x 16 bits @ 2 MHz over SPI takes 2x 8 us inside this ISR // correction: now takes 2 + 8 µs, since sending can be done at 8 MHz - rf12_xfer(0x0000); + rf12_xfer(0x0000); if (rxstate == TXRECV) { uint8_t in = rf12_xferSlow(RF_RX_FIFO_READ); if (rxfill == 0 && group != 0) rf12_buf[rxfill++] = group; - + rf12_buf[rxfill++] = in; rf12_crc = _crc16_update(rf12_crc, in); - if (rxfill >= rf12_len + 5 || rxfill >= RF_MAX) + if (rxfill >= rf12_rawlen + 5 || rxfill >= RF_MAX) rf12_xfer(RF_IDLE_MODE); } else { uint8_t out; @@ -317,7 +327,7 @@ static void rf12_interrupt () { case TXDONE: rf12_xfer(RF_IDLE_MODE); // fall through default: out = 0xAA; } - + rf12_xfer(RF_TXREG_WRITE + out); } } @@ -329,7 +339,7 @@ static void rf12_interrupt () { rf12_interrupt(); } #elif RFM_IRQ < 16 - ISR(PCINT1_vect) { + ISR(PCINT1_vect) { while (!bitRead(PINC, RFM_IRQ - 8)) rf12_interrupt(); } @@ -343,22 +353,22 @@ static void rf12_interrupt () { static void rf12_recvStart () { if (rf12_fixed_pkt_len) { - rf12_len = rf12_fixed_pkt_len; + rf12_rawlen = rf12_fixed_pkt_len; rf12_grp = rf12_hdr = 0; rxfill = 3; } else - rxfill = rf12_len = 0; + rxfill = rf12_rawlen = 0; rf12_crc = ~0; #if RF12_VERSION >= 2 if (group != 0) rf12_crc = _crc16_update(~0, group); #endif - rxstate = TXRECV; + rxstate = TXRECV; rf12_xfer(RF_RECEIVER_ON); } -#include +#include #include // needed to avoid a linker error :( /// @details @@ -388,12 +398,18 @@ static void rf12_recvStart () { /// } /// @see http://jeelabs.org/2010/12/11/rf12-acknowledgements/ uint8_t rf12_recvDone () { - if (rxstate == TXRECV && (rxfill >= rf12_len + 5 || rxfill >= RF_MAX)) { + if (rxstate == TXRECV && (rxfill >= rf12_rawlen + 5 || rxfill >= RF_MAX)) { rxstate = TXIDLE; if (rf12_len > RF12_MAXDATA) rf12_crc = 1; // force bad crc if packet length is invalid +#if RF12_COMPAT + if (rf12_dest == 0 || (nodeid & NODE_ID) == 63 || + (rf12_dest == (nodeid & NODE_ID))) +#else if (!(rf12_hdr & RF12_HDR_DST) || (nodeid & NODE_ID) == 31 || - (rf12_hdr & RF12_HDR_MASK) == (nodeid & NODE_ID)) { + (rf12_hdr & RF12_HDR_MASK) == (nodeid & NODE_ID)) +#endif + { if (rf12_crc == 0 && crypter != 0) crypter(0); else @@ -437,7 +453,7 @@ void rf12_sendStart (uint8_t hdr) { (hdr & ~RF12_HDR_MASK) + (nodeid & NODE_ID); if (crypter != 0) crypter(1); - + rf12_crc = ~0; #if RF12_VERSION >= 2 rf12_crc = _crc16_update(rf12_crc, group); @@ -455,7 +471,7 @@ void rf12_sendStart (uint8_t hdr) { /// /// The rf12_sendStart() function may only be called in two specific situations: /// -/// * right after rf12_recvDone() returns true - used for sending replies / +/// * right after rf12_recvDone() returns true - used for sending replies / /// acknowledgements /// * right after rf12_canSend() returns true - used to send requests out /// @@ -475,7 +491,7 @@ void rf12_sendStart (uint8_t hdr) { /// @param ptr Pointer to the data to send as packet. /// @param len Number of data bytes to send. Must be in the range 0 .. 65. void rf12_sendStart (uint8_t hdr, const void* ptr, uint8_t len) { - rf12_len = len; + rf12_rawlen = len; memcpy((void*) rf12_data, ptr, len); rf12_sendStart(hdr); } @@ -493,14 +509,14 @@ void rf12_sendNow (uint8_t hdr, const void* ptr, uint8_t len) { rf12_recvDone(); // keep the driver state machine going, ignore incoming rf12_sendStart(hdr, ptr, len); } - + /// @details /// Wait for completion of the preceding rf12_sendStart() call, using the /// specified low-power mode. /// @note rf12_sendWait() should only be called right after rf12_sendStart(). /// @param mode Power-down mode during wait: 0 = NORMAL, 1 = IDLE, 2 = STANDBY, -/// 3 = PWR_DOWN. Values 2 and 3 can cause the millisecond time to -/// lose a few interrupts. Value 3 can only be used if the ATmega +/// 3 = PWR_DOWN. Values 2 and 3 can cause the millisecond time to +/// lose a few interrupts. Value 3 can only be used if the ATmega /// fuses have been set for fast startup, i.e. 258 CK - the default /// Arduino fuse settings are not suitable for full power down. void rf12_sendWait (uint8_t mode) { @@ -535,7 +551,7 @@ void rf12_sendWait (uint8_t mode) { /// RF12_433MHZ, RF12_868MHZ, RF12_915MHZ. You should use the one /// matching the module you have, to get a useful TX/RX range. /// @param g Net groups are used to separate nodes: only nodes in the same net -/// group can communicate with each other. Valid values are 1 to 212. +/// group can communicate with each other. Valid values are 1 to 212. /// This parameter is optional, it defaults to 212 (0xD4) when omitted. /// This is the only allowed value for RFM12 modules, only RFM12B /// modules support other group values. @@ -556,34 +572,34 @@ uint8_t rf12_initialize (uint8_t id, uint8_t band, uint8_t g, uint16_t f) { group = g; frequency = f; // caller should validate! if (frequency < 96) frequency = 1600; - + rf12_spiInit(); rf12_xfer(0x0000); // initial SPI transfer added to avoid power-up problem rf12_xfer(RF_SLEEP_MODE); // DC (disable clk pin), enable lbd - + // wait until RFM12B is out of power-up reset, this takes several *seconds* rf12_xfer(RF_TXREG_WRITE); // in case we're still in OOK mode while (digitalRead(RFM_IRQ) == 0) rf12_xfer(0x0000); - - rf12_xfer(0x80C7 | (band << 4)); // EL (ena TX), EF (ena RX FIFO), 12.0pF - rf12_xfer(0xA000 + frequency); // 96-3960 freq range of values within band + + rf12_xfer(0x80C7 | (band << 4)); // EL (ena TX), EF (ena RX FIFO), 12.0pF + rf12_xfer(0xA000 + frequency); // 96-3960 freq range of values within band rf12_xfer(0xC606); // approx 49.2 Kbps, i.e. 10000/29/(1+6) Kbps - rf12_xfer(0x94A2); // VDI,FAST,134kHz,0dBm,-91dBm - rf12_xfer(0xC2AC); // AL,!ml,DIG,DQD4 + rf12_xfer(0x94A2); // VDI,FAST,134kHz,0dBm,-91dBm + rf12_xfer(0xC2AC); // AL,!ml,DIG,DQD4 if (group != 0) { - rf12_xfer(0xCA83); // FIFO8,2-SYNC,!ff,DR - rf12_xfer(0xCE00 | group); // SYNC=2DXX; + rf12_xfer(0xCA83); // FIFO8,2-SYNC,!ff,DR + rf12_xfer(0xCE00 | group); // SYNC=2DXX; } else { - rf12_xfer(0xCA8B); // FIFO8,1-SYNC,!ff,DR - rf12_xfer(0xCE2D); // SYNC=2D; + rf12_xfer(0xCA8B); // FIFO8,1-SYNC,!ff,DR + rf12_xfer(0xCE2D); // SYNC=2D; } - rf12_xfer(0xC483); // @PWR,NO RSTRIC,!st,!fi,OE,EN - rf12_xfer(0x9850); // !mp,90kHz,MAX OUT - rf12_xfer(0xCC77); // OB1,OB0, LPX,!ddy,DDIT,BW0 - rf12_xfer(0xE000); // NOT USE - rf12_xfer(0xC800); // NOT USE - rf12_xfer(0xC049); // 1.66MHz,3.1V + rf12_xfer(0xC483); // @PWR,NO RSTRIC,!st,!fi,OE,EN + rf12_xfer(0x9850); // !mp,90kHz,MAX OUT + rf12_xfer(0xCC77); // OB1,OB0, LPX,!ddy,DDIT,BW0 + rf12_xfer(0xE000); // NOT USE + rf12_xfer(0xC800); // NOT USE + rf12_xfer(0xC049); // 1.66MHz,3.1V rxstate = TXIDLE; #if PINCHG_IRQ @@ -618,7 +634,7 @@ uint8_t rf12_initialize (uint8_t id, uint8_t band, uint8_t g, uint16_t f) { else detachInterrupt(0); #endif - + return nodeid; } @@ -643,7 +659,7 @@ void rf12_onOff (uint8_t value) { /// @details /// This calls rf12_initialize() with settings obtained from EEPROM address /// 0x20 .. 0x3F. These settings can be filled in by the RF12demo sketch in the -/// RFM12B library. If the checksum included in those bytes is not valid, +/// RFM12B library. If the checksum included in those bytes is not valid, /// rf12_initialize() will not be called. /// /// As side effect, rf12_config() also writes the current configuration to the @@ -657,14 +673,14 @@ uint8_t rf12_configSilent () { } if (crc || eeprom_read_byte(RF12_EEPROM_ADDR + 2) != RF12_EEPROM_VERSION) return 0; - - uint8_t nodeId = 0, group = 0; - uint16_t frequency = 0; - + + uint8_t nodeId = 0, group = 0; + uint16_t frequency = 0; + nodeId = eeprom_read_byte(RF12_EEPROM_ADDR + 0); group = eeprom_read_byte(RF12_EEPROM_ADDR + 1); frequency = eeprom_read_word((uint16_t*) (RF12_EEPROM_ADDR + 4)); - + rf12_initialize(nodeId, nodeId >> 6, group, frequency); return nodeId & RF12_HDR_MASK; } @@ -676,7 +692,7 @@ void rf12_configDump () { uint8_t nodeId = eeprom_read_byte(RF12_EEPROM_ADDR); uint8_t flags = eeprom_read_byte(RF12_EEPROM_ADDR + 3); uint16_t freq = eeprom_read_word((uint16_t*) (RF12_EEPROM_ADDR + 4)); - + // " A i1 g178 @ 868 MHz " Serial.print(' '); Serial.print((char) ('@' + (nodeId & RF12_HDR_MASK))); @@ -724,10 +740,10 @@ uint8_t rf12_config (uint8_t show) { /// This function can also be used as low-power watchdog, by putting the radio /// to sleep and having it raise an interrupt between about 30 milliseconds /// and 4 seconds later. -/// @param n If RF12SLEEP (0), put the radio to sleep - no scheduled wakeup. -/// If RF12WAKEUP (-1), wake the radio up so that the next call to +/// @param n If RF12SLEEP (0), put the radio to sleep - no scheduled wakeup. +/// If RF12WAKEUP (-1), wake the radio up so that the next call to /// rf12_recvDone() can restore normal reception. If value is in the -/// range 1 .. 127, then the radio will go to sleep and generate an +/// range 1 .. 127, then the radio will go to sleep and generate an /// interrupt approximately 32*value miliiseconds later. /// @todo Figure out how to get the "watchdog" mode working reliably. void rf12_sleep (char n) { @@ -758,19 +774,19 @@ char rf12_lowbat () { /// /// * On the 433 and 915 MHz frequency bands, this is fixed at 100 msec (10 /// packets/second). -/// +/// /// * On the 866 MHz band, the frequency depends on the number of bytes sent: /// for 1-byte packets, it'll be up to 7 packets/second, for 66-byte bytes of /// data it will be around 1 packet/second. -/// +/// /// This function should be called after the RF12 driver has been initialized, /// using either rf12_initialize() or rf12_config(). -/// @param secs The minimal number of seconds between new data packets (from 1 -/// to 255). With a 0 argument, packets will be sent as fast as -/// possible: on the 433 and 915 MHz frequency bands, this is fixed -/// at 100 msec (10 packets/second). On 866 MHz, the frequency -/// depends on the number of bytes sent: for 1-byte packets, it -/// will be up to 7 packets/second, for 66-byte bytes of data it +/// @param secs The minimal number of seconds between new data packets (from 1 +/// to 255). With a 0 argument, packets will be sent as fast as +/// possible: on the 433 and 915 MHz frequency bands, this is fixed +/// at 100 msec (10 packets/second). On 866 MHz, the frequency +/// depends on the number of bytes sent: for 1-byte packets, it +/// will be up to 7 packets/second, for 66-byte bytes of data it /// drops to approx. 1 packet/second. /// @note To be used in combination with rf12_easyPoll() and rf12_easySend(). void rf12_easyInit (uint8_t secs) { @@ -778,11 +794,11 @@ void rf12_easyInit (uint8_t secs) { } /// @details -/// Needs to be called often to keep the easy transmission mechanism going, -/// i.e. once per millisecond or more in normal use. Failure to poll frequently +/// Needs to be called often to keep the easy transmission mechanism going, +/// i.e. once per millisecond or more in normal use. Failure to poll frequently /// enough is relatively harmless but may lead to lost acknowledgements. /// @returns 1 = an ack has been received with actual data in it, use rf12len -/// and rf12data to access it. 0 = there is nothing to do, the last +/// and rf12data to access it. 0 = there is nothing to do, the last /// send has been ack'ed or more than 8 re-transmits have failed. /// -1 = still sending or waiting for an ack to come in /// @note To be used in combination with rf12_easyInit() and rf12_easySend(). @@ -829,7 +845,7 @@ char rf12_easyPoll () { /// rf12_easyInit() call, even if called more often. /// /// Only packets which differ from the previous packet will actually be sent. -/// To force re-transmission even if the data hasn't changed, call +/// To force re-transmission even if the data hasn't changed, call /// "rf12_easySend(0,0)". This can be used to give a "sign of life" every once /// in a while, and to recover when the receiving node has been rebooted and no /// longer has the previous data. @@ -892,15 +908,15 @@ void rf12_setRawRecvMode(uint8_t fixed_pkt_len) { static void cryptFun (uint8_t send) { uint32_t y, z, sum, *v = (uint32_t*) rf12_data; uint8_t p, e, rounds = 6; - + if (send) { // pad with 1..4-byte sequence number *(uint32_t*)(rf12_data + rf12_len) = ++seqNum; uint8_t pad = 3 - (rf12_len & 3); - rf12_len += pad; + rf12_rawlen += pad; rf12_data[rf12_len] &= 0x3F; rf12_data[rf12_len] |= pad << 6; - ++rf12_len; + ++rf12_rawlen; // actual encoding char n = rf12_len / 4; if (n > 1) { @@ -931,10 +947,10 @@ static void cryptFun (uint8_t send) { } // strip sequence number from the end again if (n > 0) { - uint8_t pad = rf12_data[--rf12_len] >> 6; + uint8_t pad = rf12_data[--rf12_rawlen] >> 6; rf12_seq = rf12_data[rf12_len] & 0x3F; while (pad-- > 0) - rf12_seq = (rf12_seq << 8) | rf12_data[--rf12_len]; + rf12_seq = (rf12_seq << 8) | rf12_data[--rf12_rawlen]; } } } @@ -958,8 +974,8 @@ static void cryptFun (uint8_t send) { /// There is a "long rf12seq" global which is set to the received sequence /// number (only valid right after rf12recvDone() returns true). When encryption /// is not enabled, this global is set to -1. -/// @param key Pointer to a 16-byte (128-bit) encryption key to use for all -/// packet data. A null pointer disables encryption again. Note: +/// @param key Pointer to a 16-byte (128-bit) encryption key to use for all +/// packet data. A null pointer disables encryption again. Note: /// this is an EEPROM address, not RAM! - RF12_EEPROM_EKEY is a great /// value to use, as defined in the include file, but another address /// can be specified if needed. diff --git a/RF12.h b/RF12.h index 2986d1f0..cf312edc 100644 --- a/RF12.h +++ b/RF12.h @@ -6,6 +6,10 @@ /// @file /// RFM12B driver definitions +// Modify the RF12 driver in such a way that it can inter-operate with RFM69 +// modules running in "native" mode. This affects packet layout and some more. +#define RF12_COMPAT 1 + #include /// RFM12B Protocol version. @@ -15,6 +19,19 @@ /// Shorthand for RFM12B group byte in rf12_buf. #define rf12_grp rf12_buf[0] + +#if RF12_COMPAT +#define rf12_len (rf12_buf[1] - 2) +#define rf12_dst rf12_buf[2] // parity bits and dest addr +#define rf12_hdr rf12_buf[3] // flag bits and origin addr +#define rf12_data (rf12_buf + 4) + +#define RF12_HDR_CTL 0x80 +#define RF12_HDR_DST 0 // never set in native RF69 packets +#define RF12_HDR_ACK 0x40 +#define RF12_HDR_MASK 0x3F +#else + /// Shorthand for RFM12B header byte in rf12_buf. #define rf12_hdr rf12_buf[1] /// Shorthand for RFM12B length byte in rf12_buf. @@ -31,6 +48,8 @@ /// RFM12B HDR bit mask. #define RF12_HDR_MASK 0x1F +#endif + /// RFM12B Maximum message size in bytes. #define RF12_MAXDATA 66 @@ -50,7 +69,7 @@ /// Shorthand to simplify sending out the proper ACK reply. #define RF12_ACK_REPLY (rf12_hdr & RF12_HDR_DST ? RF12_HDR_CTL : \ RF12_HDR_CTL | RF12_HDR_DST | (rf12_hdr & RF12_HDR_MASK)) - + // options for RF12_sleep() #define RF12_SLEEP 0 ///< Enter sleep mode. #define RF12_WAKEUP -1 ///< Wake up from sleep mode. @@ -131,7 +150,7 @@ void rf12_setRawRecvMode(uint8_t fixed_pkt_len); uint16_t rf12_control(uint16_t cmd); /// See http://blog.strobotics.com.au/2009/07/27/rfm12-tutorial-part-3a/ -/// Transmissions are packetized, don't assume you can sustain these speeds! +/// Transmissions are packetized, don't assume you can sustain these speeds! /// /// @note Data rates are approximate. For higher data rates you may need to /// alter receiver radio bandwidth and transmitter modulator bandwidth. diff --git a/RF12_compat.h b/RF12_compat.h deleted file mode 100644 index e69de29b..00000000 diff --git a/examples/RF12/rf12compat/rf12compat.ino b/examples/RF12/rf12compat/rf12compat.ino index 3b5f5cf4..02ea253e 100644 --- a/examples/RF12/rf12compat/rf12compat.ino +++ b/examples/RF12/rf12compat/rf12compat.ino @@ -2,24 +2,27 @@ /// Test for making the RFM12 modules compatible with RFM69 in native mode. // 2015-05-19 http://opensource.org/licenses/mit-license.php -#define RF12_COMPAT 1 #include void setup() { Serial.begin(57600); Serial.println("\n[rf12compat]"); - rf12_initialize(31, RF12_868MHZ, 42, 1720); // 868.6 MHz for testing + rf12_initialize(63, RF12_868MHZ, 42, 1720); // 868.6 MHz for testing } void loop() { if (rf12_recvDone()) { - Serial.print("OK "); - for (byte i = 0; i < rf12_len; ++i) { + Serial.print("OK dst: "); + Serial.print(rf12_dst, HEX); + Serial.print(" hdr: "); + Serial.print(rf12_hdr, HEX); + Serial.print(' '); + // include the two CRC bytes at the end + for (int i = 0; i < rf12_len + 2; ++i) { Serial.print(rf12_data[i] >> 4, HEX); Serial.print(rf12_data[i] & 0xF, HEX); - Serial.print(' '); } - Serial.print("crc: "); + Serial.print(" crc: "); Serial.println(rf12_crc); } }