mBed RFM12B module library

Dependents:   _EXAMPLE_RFM12B

Fork of RF12B by Sukkin Pang

RFM12B Library

The main purpose of this library was to implement the RFM12B module in order to be able to establish communication with the Moteino (arduino clone that uses the RFM12B).

In order to achieve my goal I was highly inspired by RF12B library from pangsk https://mbed.org/users/pangsk/ and by RFM12B arduino library made by Felix Rusu (http://lowpowerlab.com/blog/2012/12/28/rfm12b-arduino-library/)

Who/What is Moteino? (http://lowpowerlab.com/moteino/)

Committer:
hajesusrodrigues
Date:
Fri May 31 16:34:12 2013 +0000
Revision:
8:7d282360721a
Parent:
7:19d9da22271a
Implementation of Sleep/WakeUp/LowBattery methods.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
hajesusrodrigues 6:52322349ee10 1 /*
hajesusrodrigues 6:52322349ee10 2 RFM12B Library. Based on work done by JeeLabs.org ported to mBed by SK Pang.
hajesusrodrigues 6:52322349ee10 3 http://jeelabs.net/projects/cafe/wiki/RF12
hajesusrodrigues 8:7d282360721a 4 Jan 2012 skpang.co.uk
hajesusrodrigues 8:7d282360721a 5
hajesusrodrigues 8:7d282360721a 6 RFM12B Library (Moteino Comunication Protocol). Based on work done by Felix Rusu ported to mBed by Hugo Rodrigues
hajesusrodrigues 8:7d282360721a 7 http://lowpowerlab.com/blog/2012/12/28/rfm12b-arduino-library/
hajesusrodrigues 8:7d282360721a 8 May 2013 Hugo Rodrigues
pangsk 0:66fdbf2cc578 9
hajesusrodrigues 6:52322349ee10 10 http://opensource.org/licenses/mit-license.php
pangsk 0:66fdbf2cc578 11
hajesusrodrigues 6:52322349ee10 12 Permission is hereby granted, free of charge, to any person obtaining a copy
hajesusrodrigues 6:52322349ee10 13 of this software and associated documentation files (the "Software"), to deal
hajesusrodrigues 6:52322349ee10 14 in the Software without restriction, including without limitation the rights
hajesusrodrigues 6:52322349ee10 15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
hajesusrodrigues 6:52322349ee10 16 copies of the Software, and to permit persons to whom the Software is
hajesusrodrigues 6:52322349ee10 17 furnished to do so, subject to the following conditions:
pangsk 0:66fdbf2cc578 18
hajesusrodrigues 6:52322349ee10 19 The above copyright notice and this permission notice shall be included in
hajesusrodrigues 6:52322349ee10 20 all copies or substantial portions of the Software.
pangsk 0:66fdbf2cc578 21
hajesusrodrigues 6:52322349ee10 22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
hajesusrodrigues 6:52322349ee10 23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
hajesusrodrigues 6:52322349ee10 24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
hajesusrodrigues 6:52322349ee10 25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
hajesusrodrigues 6:52322349ee10 26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
hajesusrodrigues 6:52322349ee10 27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
hajesusrodrigues 6:52322349ee10 28 THE SOFTWARE.
hajesusrodrigues 6:52322349ee10 29 */
pangsk 0:66fdbf2cc578 30
hajesusrodrigues 6:52322349ee10 31 #include "RFM12B.h"
hajesusrodrigues 6:52322349ee10 32
hajesusrodrigues 6:52322349ee10 33 RFM12B::RFM12B(PinName _SDI, PinName _SDO, PinName _SCK, PinName _NCS, PinName _NIRQ, PinName _NIRQ_LED) :
hajesusrodrigues 7:19d9da22271a 34 spi(_SDI, _SDO, _SCK), NCS(_NCS), NIRQ(_NIRQ), NIRQ_in(_NIRQ), NIRQ_LED(_NIRQ_LED)
hajesusrodrigues 7:19d9da22271a 35 {
pangsk 0:66fdbf2cc578 36
hajesusrodrigues 6:52322349ee10 37 useEncryption = false;
hajesusrodrigues 6:52322349ee10 38
hajesusrodrigues 6:52322349ee10 39 /* SPI frequency, 8 bit word length, polarity and phase */
hajesusrodrigues 6:52322349ee10 40 spi.format(8, 0);
pangsk 0:66fdbf2cc578 41 spi.frequency(2000000);
pangsk 0:66fdbf2cc578 42
pangsk 0:66fdbf2cc578 43 /* Set ~CS high */
pangsk 0:66fdbf2cc578 44 NCS = 1;
pangsk 0:66fdbf2cc578 45
pangsk 0:66fdbf2cc578 46 /* Setup interrupt to happen on falling edge of NIRQ */
hajesusrodrigues 6:52322349ee10 47 NIRQ.fall(this, &RFM12B::InterruptHandler);
pangsk 0:66fdbf2cc578 48 }
pangsk 0:66fdbf2cc578 49
hajesusrodrigues 7:19d9da22271a 50 int RFM12B::writeCmd(int cmd)
hajesusrodrigues 7:19d9da22271a 51 {
pangsk 0:66fdbf2cc578 52 NCS = 0;
hajesusrodrigues 6:52322349ee10 53 int recv = spi.write(cmd >> 8);
pangsk 0:66fdbf2cc578 54 recv = spi.write(cmd);
pangsk 0:66fdbf2cc578 55 NCS = 1;
pangsk 0:66fdbf2cc578 56 return recv;
pangsk 0:66fdbf2cc578 57 }
pangsk 0:66fdbf2cc578 58
hajesusrodrigues 7:19d9da22271a 59 uint16_t RFM12B::crc16_update(uint16_t crc, uint8_t data)
hajesusrodrigues 7:19d9da22271a 60 {
pangsk 0:66fdbf2cc578 61 int i;
pangsk 0:66fdbf2cc578 62
pangsk 0:66fdbf2cc578 63 crc ^= data;
hajesusrodrigues 6:52322349ee10 64 for (i = 0; i < 8; ++i) {
pangsk 0:66fdbf2cc578 65 if (crc & 1)
hajesusrodrigues 6:52322349ee10 66 crc = (crc >> 1) ^ 0xA001;
pangsk 0:66fdbf2cc578 67 else
hajesusrodrigues 6:52322349ee10 68 crc = (crc >> 1);
pangsk 0:66fdbf2cc578 69 }
pangsk 0:66fdbf2cc578 70
pangsk 0:66fdbf2cc578 71 return crc;
pangsk 0:66fdbf2cc578 72 }
pangsk 0:66fdbf2cc578 73
hajesusrodrigues 7:19d9da22271a 74 uint8_t RFM12B::byte(uint8_t out)
hajesusrodrigues 7:19d9da22271a 75 {
hajesusrodrigues 6:52322349ee10 76 return spi.write(out);
hajesusrodrigues 6:52322349ee10 77 }
pangsk 0:66fdbf2cc578 78
hajesusrodrigues 7:19d9da22271a 79 uint16_t RFM12B::xfer(uint16_t cmd)
hajesusrodrigues 7:19d9da22271a 80 {
hajesusrodrigues 6:52322349ee10 81 NCS = 0;
hajesusrodrigues 6:52322349ee10 82 uint16_t reply = byte(cmd >> 8) << 8;
hajesusrodrigues 6:52322349ee10 83 reply |= byte(cmd);
hajesusrodrigues 6:52322349ee10 84 NCS = 1;
hajesusrodrigues 6:52322349ee10 85 return reply;
hajesusrodrigues 6:52322349ee10 86 }
hajesusrodrigues 6:52322349ee10 87
hajesusrodrigues 6:52322349ee10 88 // Call this once with params:
hajesusrodrigues 6:52322349ee10 89 // - node ID (0-31)
hajesusrodrigues 6:52322349ee10 90 // - frequency band (RF12_433MHZ, RF12_868MHZ, RF12_915MHZ)
hajesusrodrigues 6:52322349ee10 91 // - networkid [optional - default = 170] (0-255 for RF12B, only 212 allowed for RF12)
hajesusrodrigues 6:52322349ee10 92 // - txPower [optional - default = 0 (max)] (7 is min value)
hajesusrodrigues 6:52322349ee10 93 // - airKbps [optional - default = 38.31Kbps]
hajesusrodrigues 7:19d9da22271a 94 void RFM12B::Initialize(uint8_t nodeid, uint8_t freqBand, uint8_t groupid, uint8_t txPower, uint8_t airKbps)
hajesusrodrigues 7:19d9da22271a 95 {
hajesusrodrigues 6:52322349ee10 96
hajesusrodrigues 6:52322349ee10 97 nodeID = nodeid;
hajesusrodrigues 6:52322349ee10 98 networkID = groupid;
hajesusrodrigues 6:52322349ee10 99 rf12_grp= groupid;
hajesusrodrigues 6:52322349ee10 100
hajesusrodrigues 6:52322349ee10 101 writeCmd(0x0000); // initial SPI transfer added to avoid power-up problem
hajesusrodrigues 6:52322349ee10 102 writeCmd(RF_SLEEP_MODE); // DC (disable clk pin), enable lbd
hajesusrodrigues 6:52322349ee10 103
hajesusrodrigues 6:52322349ee10 104 // wait until RFM12B is out of power-up reset, this takes several *seconds*
hajesusrodrigues 6:52322349ee10 105 writeCmd(RF_TXREG_WRITE); // in case we're still in OOK mode
hajesusrodrigues 6:52322349ee10 106
hajesusrodrigues 6:52322349ee10 107 while (NIRQ == 0)
hajesusrodrigues 6:52322349ee10 108 writeCmd(0x0000);
hajesusrodrigues 6:52322349ee10 109
hajesusrodrigues 6:52322349ee10 110 writeCmd(0x80C7 | (freqBand << 4)); // EL (ena TX), EF (ena RX FIFO), 12.0pF
hajesusrodrigues 6:52322349ee10 111 writeCmd(0xA640); // Frequency is exactly 434/868/915MHz (whatever freqBand is)
hajesusrodrigues 6:52322349ee10 112 writeCmd(0xC600 + airKbps); //Air transmission baud rate: 0x08= ~38.31Kbps
hajesusrodrigues 6:52322349ee10 113 writeCmd(0x94A2); // VDI,FAST,134kHz,0dBm,-91dBm
hajesusrodrigues 6:52322349ee10 114 writeCmd(0xC2AC); // AL,!ml,DIG,DQD4
hajesusrodrigues 6:52322349ee10 115 if (networkID != 0) {
hajesusrodrigues 6:52322349ee10 116 writeCmd(0xCA83); // FIFO8,2-SYNC,!ff,DR
hajesusrodrigues 6:52322349ee10 117 writeCmd(0xCE00 | networkID); // SYNC=2DXX
hajesusrodrigues 6:52322349ee10 118 } else {
hajesusrodrigues 6:52322349ee10 119 writeCmd(0xCA8B); // FIFO8,1-SYNC,!ff,DR
hajesusrodrigues 6:52322349ee10 120 writeCmd(0xCE2D); // SYNC=2D
hajesusrodrigues 6:52322349ee10 121 }
hajesusrodrigues 6:52322349ee10 122
hajesusrodrigues 6:52322349ee10 123 writeCmd(0xC483); // @PWR,NO RSTRIC,!st,!fi,OE,EN
hajesusrodrigues 6:52322349ee10 124 writeCmd(0x9850 | (txPower > 7 ? 7 : txPower)); // !mp,90kHz,MAX OUT
hajesusrodrigues 6:52322349ee10 125 writeCmd(0xCC77); // OB1, OB0, LPX, ddy, DDIT, BW0
hajesusrodrigues 6:52322349ee10 126 writeCmd(0xE000); // NOT USE
hajesusrodrigues 6:52322349ee10 127 writeCmd(0xC800); // NOT USE
hajesusrodrigues 6:52322349ee10 128 writeCmd(0xC049); // 1.66MHz,3.1V
hajesusrodrigues 6:52322349ee10 129
hajesusrodrigues 6:52322349ee10 130 rxstate = TXIDLE;
hajesusrodrigues 6:52322349ee10 131 }
hajesusrodrigues 6:52322349ee10 132
hajesusrodrigues 7:19d9da22271a 133 void RFM12B::InterruptHandler()
hajesusrodrigues 7:19d9da22271a 134 {
hajesusrodrigues 6:52322349ee10 135
hajesusrodrigues 6:52322349ee10 136 NIRQ_LED = 1;
hajesusrodrigues 6:52322349ee10 137
hajesusrodrigues 6:52322349ee10 138 // a transfer of 2x 16 bits @ 2 MHz over SPI takes 2x 8 us inside this ISR
hajesusrodrigues 6:52322349ee10 139 writeCmd(0x0000);
hajesusrodrigues 6:52322349ee10 140
hajesusrodrigues 6:52322349ee10 141 if (rxstate == TXRECV) {
hajesusrodrigues 6:52322349ee10 142 uint8_t in = xfer(RF_RX_FIFO_READ);
hajesusrodrigues 6:52322349ee10 143
hajesusrodrigues 6:52322349ee10 144 if (rxfill == 0 && networkID != 0)
hajesusrodrigues 6:52322349ee10 145 rf12_buf[rxfill++] = networkID;
hajesusrodrigues 6:52322349ee10 146
hajesusrodrigues 6:52322349ee10 147 rf12_buf[rxfill++] = in;
hajesusrodrigues 6:52322349ee10 148 rf12_crc = crc16_update(rf12_crc, in);
pangsk 0:66fdbf2cc578 149
hajesusrodrigues 6:52322349ee10 150 if (rxfill >= rf12_len+ 6 || rxfill >= RF_MAX)
hajesusrodrigues 6:52322349ee10 151 xfer(RF_IDLE_MODE);
hajesusrodrigues 6:52322349ee10 152 } else {
hajesusrodrigues 6:52322349ee10 153 uint8_t out;
pangsk 0:66fdbf2cc578 154
hajesusrodrigues 6:52322349ee10 155 if (rxstate < 0) {
hajesusrodrigues 6:52322349ee10 156 uint8_t pos = 4 + rf12_len + rxstate++;
hajesusrodrigues 6:52322349ee10 157 out = rf12_buf[pos];
hajesusrodrigues 6:52322349ee10 158 rf12_crc = crc16_update(rf12_crc, out);
hajesusrodrigues 6:52322349ee10 159 } else {
hajesusrodrigues 6:52322349ee10 160 switch (rxstate++) {
hajesusrodrigues 7:19d9da22271a 161 case TXSYN1:
hajesusrodrigues 7:19d9da22271a 162 out = 0x2D;
hajesusrodrigues 7:19d9da22271a 163 break;
hajesusrodrigues 7:19d9da22271a 164 case TXSYN2:
hajesusrodrigues 7:19d9da22271a 165 out = rf12_grp;
hajesusrodrigues 7:19d9da22271a 166 rxstate = - (3 + rf12_len);
hajesusrodrigues 7:19d9da22271a 167 break;
hajesusrodrigues 7:19d9da22271a 168 case TXCRC1:
hajesusrodrigues 7:19d9da22271a 169 out = rf12_crc;
hajesusrodrigues 7:19d9da22271a 170 break;
hajesusrodrigues 7:19d9da22271a 171 case TXCRC2:
hajesusrodrigues 7:19d9da22271a 172 out = rf12_crc >> 8;
hajesusrodrigues 7:19d9da22271a 173 break;
hajesusrodrigues 7:19d9da22271a 174 case TXDONE:
hajesusrodrigues 7:19d9da22271a 175 xfer(RF_IDLE_MODE); // fall through
hajesusrodrigues 7:19d9da22271a 176 out = 0xAA;
hajesusrodrigues 7:19d9da22271a 177 break;
hajesusrodrigues 7:19d9da22271a 178 default:
hajesusrodrigues 7:19d9da22271a 179 out = 0xAA;
hajesusrodrigues 6:52322349ee10 180 }
hajesusrodrigues 6:52322349ee10 181 }
hajesusrodrigues 6:52322349ee10 182 xfer(RF_TXREG_WRITE + out);
hajesusrodrigues 6:52322349ee10 183 }
hajesusrodrigues 6:52322349ee10 184 NIRQ_LED = 0;
hajesusrodrigues 6:52322349ee10 185 }
pangsk 0:66fdbf2cc578 186
hajesusrodrigues 7:19d9da22271a 187 void RFM12B::ReceiveStart(void)
hajesusrodrigues 7:19d9da22271a 188 {
hajesusrodrigues 6:52322349ee10 189 rxfill = rf12_len= 0;
hajesusrodrigues 6:52322349ee10 190 rf12_crc = ~0;
hajesusrodrigues 6:52322349ee10 191
hajesusrodrigues 6:52322349ee10 192 if (networkID != 0)
hajesusrodrigues 6:52322349ee10 193 rf12_crc = crc16_update(~0, networkID);
hajesusrodrigues 6:52322349ee10 194
hajesusrodrigues 6:52322349ee10 195 rxstate = TXRECV;
hajesusrodrigues 6:52322349ee10 196 xfer(RF_RECEIVER_ON);
hajesusrodrigues 6:52322349ee10 197 }
hajesusrodrigues 6:52322349ee10 198
hajesusrodrigues 7:19d9da22271a 199 bool RFM12B::ReceiveComplete(void)
hajesusrodrigues 7:19d9da22271a 200 {
hajesusrodrigues 6:52322349ee10 201 if (rxstate == TXRECV && (rxfill >= rf12_len+ 6 || rxfill >= RF_MAX)) {
hajesusrodrigues 6:52322349ee10 202 rxstate = TXIDLE;
hajesusrodrigues 6:52322349ee10 203
hajesusrodrigues 6:52322349ee10 204 if (rf12_len > RF12_MAXDATA) {
hajesusrodrigues 6:52322349ee10 205 rf12_crc = 1; // force bad crc if packet length is invalid
hajesusrodrigues 6:52322349ee10 206 }
hajesusrodrigues 6:52322349ee10 207 if (RF12_DESTID == 0 || RF12_DESTID == nodeID) {
hajesusrodrigues 6:52322349ee10 208
hajesusrodrigues 6:52322349ee10 209 if (rf12_crc == 0 && useEncryption)
hajesusrodrigues 6:52322349ee10 210 Encryption(false);
hajesusrodrigues 6:52322349ee10 211 else
hajesusrodrigues 6:52322349ee10 212 rf12_seq = -1;
hajesusrodrigues 6:52322349ee10 213
hajesusrodrigues 6:52322349ee10 214 #ifdef DEBUG
hajesusrodrigues 6:52322349ee10 215 printf("\nReceived message from [%d]; crc:%x, len: %d, message: ", RF12_SOURCEID, rf12_crc, rf12_len);
hajesusrodrigues 6:52322349ee10 216 for (int i=0; i<rf12_len; i++) {
hajesusrodrigues 6:52322349ee10 217 printf("%c", rf12_data[i]);
hajesusrodrigues 6:52322349ee10 218 }
hajesusrodrigues 6:52322349ee10 219 printf("\n");
hajesusrodrigues 6:52322349ee10 220 #endif
hajesusrodrigues 6:52322349ee10 221
hajesusrodrigues 6:52322349ee10 222 return true; // it's a broadcast packet or it's addressed to this node
hajesusrodrigues 6:52322349ee10 223 }
hajesusrodrigues 6:52322349ee10 224 }
hajesusrodrigues 6:52322349ee10 225 if (rxstate == TXIDLE)
hajesusrodrigues 6:52322349ee10 226 ReceiveStart();
hajesusrodrigues 6:52322349ee10 227
hajesusrodrigues 6:52322349ee10 228 return false;
hajesusrodrigues 6:52322349ee10 229 }
pangsk 0:66fdbf2cc578 230
hajesusrodrigues 7:19d9da22271a 231 bool RFM12B::CanSend()
hajesusrodrigues 7:19d9da22271a 232 {
hajesusrodrigues 6:52322349ee10 233 // no need to test with interrupts disabled: state TXRECV is only reached
hajesusrodrigues 6:52322349ee10 234 // outside of ISR and we don't care if rxfill jumps from 0 to 1 here
hajesusrodrigues 6:52322349ee10 235 if (rxstate == TXRECV && rxfill == 0 && (byte(0x00) & (RF_RSSI_BIT >> 8)) == 0) {
hajesusrodrigues 6:52322349ee10 236 xfer(RF_IDLE_MODE); // stop receiver
hajesusrodrigues 6:52322349ee10 237 rxstate = TXIDLE;
hajesusrodrigues 6:52322349ee10 238 return true;
hajesusrodrigues 6:52322349ee10 239 }
hajesusrodrigues 6:52322349ee10 240 return false;
hajesusrodrigues 6:52322349ee10 241 }
pangsk 0:66fdbf2cc578 242
hajesusrodrigues 7:19d9da22271a 243 void RFM12B::SendStart(uint8_t toNodeID, bool requestACK, bool sendACK)
hajesusrodrigues 7:19d9da22271a 244 {
hajesusrodrigues 6:52322349ee10 245
hajesusrodrigues 6:52322349ee10 246 rf12_hdr1= toNodeID | (sendACK ? RF12_HDR_ACKCTLMASK : 0);
hajesusrodrigues 6:52322349ee10 247 rf12_hdr2= nodeID | (requestACK ? RF12_HDR_ACKCTLMASK : 0);
hajesusrodrigues 6:52322349ee10 248
hajesusrodrigues 6:52322349ee10 249 #ifdef DEBUG
hajesusrodrigues 6:52322349ee10 250 printf("SendStart to Node [%d], from Node [%d] \n", toNodeID, nodeID);
hajesusrodrigues 6:52322349ee10 251 #endif
hajesusrodrigues 6:52322349ee10 252
hajesusrodrigues 6:52322349ee10 253 if (useEncryption)
hajesusrodrigues 6:52322349ee10 254 Encryption(true);
hajesusrodrigues 6:52322349ee10 255
hajesusrodrigues 6:52322349ee10 256 rf12_crc = ~0;
hajesusrodrigues 6:52322349ee10 257 rf12_crc = crc16_update(rf12_crc, rf12_grp);
hajesusrodrigues 6:52322349ee10 258 rxstate = TXPRE1;
hajesusrodrigues 6:52322349ee10 259
hajesusrodrigues 6:52322349ee10 260 xfer(RF_XMITTER_ON); // bytes will be fed via interrupts
hajesusrodrigues 6:52322349ee10 261 }
hajesusrodrigues 6:52322349ee10 262
hajesusrodrigues 7:19d9da22271a 263 void RFM12B::SendStart(uint8_t toNodeID, const void* sendBuf, uint8_t sendLen, bool requestACK, bool sendACK)
hajesusrodrigues 7:19d9da22271a 264 {
hajesusrodrigues 7:19d9da22271a 265
hajesusrodrigues 6:52322349ee10 266 rf12_len = sendLen;
hajesusrodrigues 6:52322349ee10 267 memcpy((void*) rf12_data, sendBuf, sendLen);
hajesusrodrigues 7:19d9da22271a 268
hajesusrodrigues 6:52322349ee10 269 #ifdef DEBUG
hajesusrodrigues 7:19d9da22271a 270 printf("\nSending message from [%d]; crc:%x, len: %d, message: ", nodeID, rf12_crc, rf12_len);
hajesusrodrigues 7:19d9da22271a 271 for (int i=0; i<rf12_len; i++) {
hajesusrodrigues 7:19d9da22271a 272 printf("%c", rf12_data[i]);
hajesusrodrigues 7:19d9da22271a 273 }
hajesusrodrigues 6:52322349ee10 274 #endif
hajesusrodrigues 7:19d9da22271a 275
hajesusrodrigues 6:52322349ee10 276
hajesusrodrigues 6:52322349ee10 277 SendStart(toNodeID, requestACK, sendACK);
hajesusrodrigues 6:52322349ee10 278 }
hajesusrodrigues 6:52322349ee10 279
hajesusrodrigues 6:52322349ee10 280 /// Should be called immediately after reception in case sender wants ACK
hajesusrodrigues 7:19d9da22271a 281 void RFM12B::SendACK(const void* sendBuf, uint8_t sendLen)
hajesusrodrigues 7:19d9da22271a 282 {
hajesusrodrigues 6:52322349ee10 283 while (!CanSend())
hajesusrodrigues 6:52322349ee10 284 ReceiveComplete();
hajesusrodrigues 6:52322349ee10 285 SendStart(RF12_SOURCEID, sendBuf, (sendLen > 0) ? sendLen: strlen((const char*)sendBuf), false, true);
hajesusrodrigues 6:52322349ee10 286 }
hajesusrodrigues 6:52322349ee10 287
hajesusrodrigues 7:19d9da22271a 288 void RFM12B::Send(uint8_t toNodeID, const void* sendBuf, uint8_t sendLen, bool requestACK)
hajesusrodrigues 7:19d9da22271a 289 {
hajesusrodrigues 6:52322349ee10 290 while (!CanSend())
hajesusrodrigues 6:52322349ee10 291 ReceiveComplete();
hajesusrodrigues 6:52322349ee10 292 SendStart(toNodeID, sendBuf, (sendLen > 0) ? sendLen: strlen((const char*)sendBuf) , requestACK, false);
hajesusrodrigues 6:52322349ee10 293 }
hajesusrodrigues 6:52322349ee10 294
hajesusrodrigues 7:19d9da22271a 295 uint8_t RFM12B::GetSender(void)
hajesusrodrigues 7:19d9da22271a 296 {
hajesusrodrigues 6:52322349ee10 297 return RF12_SOURCEID;
hajesusrodrigues 6:52322349ee10 298 }
hajesusrodrigues 6:52322349ee10 299
hajesusrodrigues 7:19d9da22271a 300 volatile uint8_t * RFM12B::GetData(void)
hajesusrodrigues 7:19d9da22271a 301 {
hajesusrodrigues 6:52322349ee10 302
hajesusrodrigues 6:52322349ee10 303 return (uint8_t*) rf12_data;
hajesusrodrigues 6:52322349ee10 304 }
hajesusrodrigues 6:52322349ee10 305
hajesusrodrigues 7:19d9da22271a 306 uint8_t RFM12B::GetDataLen(void)
hajesusrodrigues 7:19d9da22271a 307 {
hajesusrodrigues 6:52322349ee10 308 return rf12_len;
hajesusrodrigues 6:52322349ee10 309 }
hajesusrodrigues 6:52322349ee10 310
hajesusrodrigues 7:19d9da22271a 311 bool RFM12B::ACKRequested()
hajesusrodrigues 7:19d9da22271a 312 {
hajesusrodrigues 6:52322349ee10 313 return RF12_WANTS_ACK;
hajesusrodrigues 6:52322349ee10 314 }
pangsk 0:66fdbf2cc578 315
hajesusrodrigues 6:52322349ee10 316 /// Should be polled immediately after sending a packet with ACK request
hajesusrodrigues 7:19d9da22271a 317 bool RFM12B::ACKReceived(uint8_t fromNodeID)
hajesusrodrigues 7:19d9da22271a 318 {
hajesusrodrigues 6:52322349ee10 319 if (ReceiveComplete())
hajesusrodrigues 6:52322349ee10 320 return CRC_Pass() && RF12_DESTID == nodeID && (RF12_SOURCEID == fromNodeID || fromNodeID == 0) && (rf12_hdr1&RF12_HDR_ACKCTLMASK) &&
hajesusrodrigues 7:19d9da22271a 321 !(rf12_hdr2 & RF12_HDR_ACKCTLMASK);
hajesusrodrigues 6:52322349ee10 322 return false;
hajesusrodrigues 6:52322349ee10 323 }
pangsk 0:66fdbf2cc578 324
hajesusrodrigues 7:19d9da22271a 325 bool RFM12B::CRC_Pass(void)
hajesusrodrigues 7:19d9da22271a 326 {
hajesusrodrigues 6:52322349ee10 327 return (rf12_crc == 0);
hajesusrodrigues 6:52322349ee10 328 }
pangsk 0:66fdbf2cc578 329
hajesusrodrigues 6:52322349ee10 330 // XXTEA by David Wheeler, adapted from http://en.wikipedia.org/wiki/XXTEA
hajesusrodrigues 6:52322349ee10 331 #define DELTA 0x9E3779B9
hajesusrodrigues 6:52322349ee10 332 #define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (cryptKey[(uint8_t)((p&3)^e)] ^ z)))
hajesusrodrigues 7:19d9da22271a 333 void RFM12B::Encryption(bool encrypt)
hajesusrodrigues 7:19d9da22271a 334 {
hajesusrodrigues 6:52322349ee10 335
hajesusrodrigues 6:52322349ee10 336 uint32_t y, z, sum, *v = (uint32_t*) rf12_data;
hajesusrodrigues 6:52322349ee10 337 uint8_t p, e, rounds = 6;
hajesusrodrigues 6:52322349ee10 338
hajesusrodrigues 6:52322349ee10 339 if (encrypt) {
hajesusrodrigues 6:52322349ee10 340 // pad with 1..4-byte sequence number
hajesusrodrigues 6:52322349ee10 341 *(uint32_t*) (rf12_data + rf12_len) = ++seqNum;
hajesusrodrigues 6:52322349ee10 342 uint8_t pad = 3 - (rf12_len & 3);
hajesusrodrigues 6:52322349ee10 343 rf12_len += pad;
hajesusrodrigues 6:52322349ee10 344 rf12_data[rf12_len] &= 0x3F;
hajesusrodrigues 6:52322349ee10 345 rf12_data[rf12_len] |= pad << 6;
hajesusrodrigues 6:52322349ee10 346 ++rf12_len;
hajesusrodrigues 6:52322349ee10 347 // actual encoding
hajesusrodrigues 6:52322349ee10 348 char n = rf12_len / 4;
hajesusrodrigues 6:52322349ee10 349 if (n > 1) {
hajesusrodrigues 6:52322349ee10 350 sum = 0;
hajesusrodrigues 6:52322349ee10 351 z = v[n-1];
hajesusrodrigues 6:52322349ee10 352 do {
hajesusrodrigues 6:52322349ee10 353 sum += DELTA;
hajesusrodrigues 6:52322349ee10 354 e = (sum >> 2) & 3;
hajesusrodrigues 6:52322349ee10 355 for (p=0; p<n-1; p++)
hajesusrodrigues 6:52322349ee10 356 y = v[p+1], z = v[p] += MX;
hajesusrodrigues 6:52322349ee10 357 y = v[0];
hajesusrodrigues 6:52322349ee10 358 z = v[n-1] += MX;
hajesusrodrigues 7:19d9da22271a 359 } while (--rounds);
hajesusrodrigues 6:52322349ee10 360 }
hajesusrodrigues 6:52322349ee10 361 } else if (rf12_crc == 0) {
hajesusrodrigues 6:52322349ee10 362 // actual decoding
hajesusrodrigues 6:52322349ee10 363 char n = rf12_len / 4;
hajesusrodrigues 6:52322349ee10 364 if (n > 1) {
hajesusrodrigues 6:52322349ee10 365 sum = rounds*DELTA;
hajesusrodrigues 6:52322349ee10 366 y = v[0];
hajesusrodrigues 6:52322349ee10 367 do {
hajesusrodrigues 6:52322349ee10 368 e = (sum >> 2) & 3;
hajesusrodrigues 6:52322349ee10 369 for (p=n-1; p>0; p--)
hajesusrodrigues 6:52322349ee10 370 z = v[p-1], y = v[p] -= MX;
hajesusrodrigues 6:52322349ee10 371 z = v[n-1];
hajesusrodrigues 6:52322349ee10 372 y = v[0] -= MX;
hajesusrodrigues 7:19d9da22271a 373 } while ((sum -= DELTA) != 0);
hajesusrodrigues 6:52322349ee10 374 }
hajesusrodrigues 6:52322349ee10 375 // strip sequence number from the end again
hajesusrodrigues 6:52322349ee10 376 if (n > 0) {
hajesusrodrigues 6:52322349ee10 377 uint8_t pad = rf12_data[--rf12_len] >> 6;
hajesusrodrigues 6:52322349ee10 378 rf12_seq = rf12_data[rf12_len] & 0x3F;
hajesusrodrigues 6:52322349ee10 379 while (pad-- > 0)
hajesusrodrigues 6:52322349ee10 380 rf12_seq = (rf12_seq << 8) | rf12_data[--rf12_len];
hajesusrodrigues 6:52322349ee10 381 }
hajesusrodrigues 6:52322349ee10 382 }
hajesusrodrigues 6:52322349ee10 383
hajesusrodrigues 6:52322349ee10 384 }
hajesusrodrigues 6:52322349ee10 385
hajesusrodrigues 7:19d9da22271a 386 void RFM12B::SetEncryptionKey(const uint8_t* key)
hajesusrodrigues 7:19d9da22271a 387 {
hajesusrodrigues 6:52322349ee10 388 if (key != 0) {
hajesusrodrigues 6:52322349ee10 389 for (uint8_t i = 0; i < sizeof cryptKey; ++i)
hajesusrodrigues 6:52322349ee10 390 ((uint8_t*) cryptKey)[i] = key[i];
hajesusrodrigues 6:52322349ee10 391
hajesusrodrigues 6:52322349ee10 392 useEncryption = true;
hajesusrodrigues 6:52322349ee10 393 } else
hajesusrodrigues 6:52322349ee10 394 useEncryption = false;
hajesusrodrigues 6:52322349ee10 395 }
hajesusrodrigues 8:7d282360721a 396
hajesusrodrigues 8:7d282360721a 397 void RFM12B::Sleep(int n)
hajesusrodrigues 8:7d282360721a 398 {
hajesusrodrigues 8:7d282360721a 399 if (n < 0)
hajesusrodrigues 8:7d282360721a 400 xfer(RF_IDLE_MODE);
hajesusrodrigues 8:7d282360721a 401 else {
hajesusrodrigues 8:7d282360721a 402 xfer(RF_WAKEUP_TIMER | 0x0500 | n);
hajesusrodrigues 8:7d282360721a 403 xfer(RF_SLEEP_MODE);
hajesusrodrigues 8:7d282360721a 404 if (n > 0)
hajesusrodrigues 8:7d282360721a 405 xfer(RF_WAKEUP_MODE);
hajesusrodrigues 8:7d282360721a 406 }
hajesusrodrigues 8:7d282360721a 407 rxstate = TXIDLE;
hajesusrodrigues 8:7d282360721a 408 }
hajesusrodrigues 8:7d282360721a 409 void RFM12B::Sleep()
hajesusrodrigues 8:7d282360721a 410 {
hajesusrodrigues 8:7d282360721a 411 Sleep(0);
hajesusrodrigues 8:7d282360721a 412 }
hajesusrodrigues 8:7d282360721a 413 void RFM12B::Wakeup()
hajesusrodrigues 8:7d282360721a 414 {
hajesusrodrigues 8:7d282360721a 415 Sleep(-1);
hajesusrodrigues 8:7d282360721a 416 }
hajesusrodrigues 8:7d282360721a 417
hajesusrodrigues 8:7d282360721a 418 bool RFM12B::LowBattery()
hajesusrodrigues 8:7d282360721a 419 {
hajesusrodrigues 8:7d282360721a 420 return (xfer(0x0000) & RF_LBD_BIT) != 0;
hajesusrodrigues 8:7d282360721a 421 }