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); 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) rf12_xfer(RF_IDLE_MODE); } else { uint8_t out; if (rxstate < 0) { uint8_t pos = 3 + rf12_len + rxstate++; out = rf12_buf[pos]; rf12_crc = _crc16_update(rf12_crc, out); } else switch (rxstate++) { case TXSYN1: out = 0x2D; break; case TXSYN2: out = group; rxstate = - (2 + rf12_len); break; case TXCRC1: out = rf12_crc; break; case TXCRC2: out = rf12_crc >> 8; break; case TXDONE: rf12_xfer(RF_IDLE_MODE); // fall through default: out = 0xAA; } rf12_xfer(RF_TXREG_WRITE + out); } }
static void rf12_recvStart () { if (rf12_fixed_pkt_len) { rf12_len = rf12_fixed_pkt_len; rf12_grp = rf12_hdr = 0; rxfill = 3; } else rxfill = rf12_len = 0; rf12_crc = ~0; #if RF12_VERSION >= 2 if (group != 0) rf12_crc = _crc16_update(~0, group); #endif rxstate = TXRECV; rf12_xfer(RF_RECEIVER_ON); }
/// @details /// This can be used to send out slow bit-by-bit On Off Keying signals to other /// devices such as remotely controlled power switches operating in the 433, /// 868, or 915 MHz bands. /// /// To use this, you need to first call rf12initialize() with a zero node ID /// and the proper frequency band. Then call rf12onOff() in the exact timing /// you need for sending out the signal. Once done, either call rf12onOff(0) to /// turn the transmitter off, or reinitialize the wireless module completely /// with a call to rf12initialize(). /// @param value Turn the transmitter on (if true) or off (if false). /// @note The timing of this function is relatively coarse, because SPI /// transfers are used to enable / disable the transmitter. This will add some /// jitter to the signal, probably in the order of 10 µsec. void rf12_onOff (uint8_t value) { rf12_xfer(value ? RF_XMITTER_ON : RF_IDLE_MODE); }
/// @details /// Call this once with the node ID (0-31), frequency band (0-3), and /// optional group (0-255 for RFM12B, only 212 allowed for RFM12). /// @param id The ID of this wireless node. ID's should be unique within the /// netGroup in which this node is operating. The ID range is 0 to 31, /// but only 1..30 are available for normal use. You can pass a single /// capital letter as node ID, with 'A' .. 'Z' corresponding to the /// node ID's 1..26, but this convention is now discouraged. ID 0 is /// reserved for OOK use, node ID 31 is special because it will pick /// up packets for any node (in the same netGroup). /// @param band This determines in which frequency range the wireless module /// will operate. The following pre-defined constants are available: /// 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. /// 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. /// @param f Frequency correction to apply. Defaults to 1600, per RF12 docs. /// This parameter is optional, and was added in February 2014. /// @returns the nodeId, to be compatible with rf12_config(). /// /// Programming Tips /// ---------------- /// Note that rf12_initialize() does not use the EEprom netId and netGroup /// settings, nor does it change the EEPROM settings. To use the netId and /// netGroup settings saved in EEPROM use rf12_config() instead of /// rf12_initialize. The choice whether to use rf12_initialize() or /// rf12_config() at the top of every sketch is one of personal preference. /// To set EEPROM settings for use with rf12_config() use the RF12demo sketch. uint8_t rf12_initialize (uint8_t id, uint8_t band, uint8_t g, uint16_t f) { nodeid = id; 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(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 if (group != 0) { 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(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 #if RFM_IRQ < 8 if ((nodeid & NODE_ID) != 0) { bitClear(DDRB, RFM_IRQ); // input bitSet(PORTB, RFM_IRQ); // pull-up bitSet(PCMSK0, RFM_IRQ); // pin-change bitSet(PCICR, PCIE0); // enable } else bitClear(PCMSK0, RFM_IRQ); #elif RFM_IRQ < 15 if ((nodeid & NODE_ID) != 0) { bitClear(DDRC, RFM_IRQ - 8); // input bitSet(PORTC, RFM_IRQ - 8); // pull-up bitSet(PCMSK1, RFM_IRQ - 8); // pin-change bitSet(PCICR, PCIE1); // enable } else bitClear(PCMSK1, RFM_IRQ - 8); #else if ((nodeid & NODE_ID) != 0) { bitClear(DDRD, RFM_IRQ - 16); // input bitSet(PORTD, RFM_IRQ - 16); // pull-up bitSet(PCMSK2, RFM_IRQ - 16); // pin-change bitSet(PCICR, PCIE2); // enable } else bitClear(PCMSK2, RFM_IRQ - 16); #endif #else if ((nodeid & NODE_ID) != 0) attachInterrupt(0, rf12_interrupt, LOW); else detachInterrupt(0); #endif return nodeid; }
/// @details /// Brings RFM12 in idle-mode. static void rf12_idle() { rfmstate &= ~B11110000; // switch off synthesizer, transmitter, receiver and baseband rfmstate |= B00001000; // make sure crystal is running rf12_xfer(rfmstate); }
/// @details /// This call provides direct access to the RFM12B registers. If you're careful /// to avoid configuring the wireless module in a way which stops the driver /// from functioning, this can be used to adjust frequencies, power levels, /// RSSI threshold, etc. See the RFM12B wireless module documentation. /// /// OBSOLETE! Use rf12_xfer instead. /// /// This function does no longer return anything. /// @param cmd RF12 command, topmost bits determines which register is affected. uint16_t rf12_control(uint16_t cmd) { return rf12_xfer(cmd); }
/// @details /// Handles a RFM12 interrupt depending on rxstate and the status reported by the RF /// module. static void rf12_interrupt() { uint8_t in; state = rf12_xferState(&in); // data received or byte needed for sending if (state & RF_FIFO_BIT) { if (rxstate == TXRECV) { // we are receiving if (rxfill == 0 && group != 0) { rf12_buf[rxfill++] = group; #if 0 if (fixedLength) { rf12_crc8 = 0; if (((in & 0xF0) == 0xA0) && (fixedLength > 10) && (fixedLengthBase < 10)) { minLengthCrcOk = 10; // otherwise repeating Fine Offset packages are missed } else { minLengthCrcOk = fixedLengthBase; } } #endif } rf12_buf[rxfill++] = in; if (fixedLength) { #if 0 if ((rxfill == 2) && ((in & 0xF) >= 4) && ((in & 0xF) <= 5) && ((rf12_buf[1] & 0xF) == 0xA)) { minLengthCrcOk = fixedLength; fixedLength = 13 + 1; // ws1600 is longer } #endif rf12_crc8 = _crc8_update(rf12_crc8, in); } else { rf12_crc = _crc16_update(rf12_crc, in); } // do drssi binary-tree search if ( drssi < 3 && ((rxfill-2)%drssi_bytes_per_decision)==0 ) {// not yet final value // top nibble when going up, bottom one when going down drssi = bitRead(state,8) ? (drssi_dec_tree[drssi] & B1111) : (drssi_dec_tree[drssi] >> 4); if ( drssi < 3 ) { // not yet final destination, set new threshold rf12_xfer(RF_RECV_CONTROL | drssi*2+1); } } // check if we got all the bytes (or maximum packet length was reached) if (fixedLength) { if ((rf12_crc8 == 0) && minLengthCrcOk > 0 && (rxfill >= minLengthCrcOk)) { rf12_buf[0] = rxfill; #if 0 while (rxfill < fixedLength) { rf12_buf[rxfill++] = 0; } #endif rf12_idle(); } else if (rxfill >= fixedLength || rxfill >= RF_MAX) { rf12_buf[0] = rxfill; rf12_idle(); } } else if (rxfill >= rf12_len + 5 || rxfill >= RF_MAX) { rf12_idle(); } } else { // we are sending
// access to the RFM12B internal registers with interrupts disabled uint16_t rf12_control(uint16_t cmd) { bitClear(EIMSK, INT0); uint16_t r = rf12_xfer(cmd); bitSet(EIMSK, INT0); return r; }
/*! Call this once with the node ID (0-31), frequency band (0-3), and optional group (0-255 for RF12B, only 212 allowed for RF12). */ void rf12_initialize () { spi_initialize(); pinMode(RFM_IRQ, INPUT); digitalWrite(RFM_IRQ, 1); // pull-up rf12_xfer(0x0000); // intitial 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 | (RF12_433MHZ << 4)); // EL (ena TX), EF (ena RX FIFO), 12.0pF rf12_xfer(0xA640); // 868MHz 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(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 rxstate = TXIDLE; attachInterrupt(0, rf12_interrupt, LOW); }