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.
Dependencies: EthernetNetIf mbed
RF12B/RF12B.cpp@0:7f301f08b68f, 2012-01-02 (annotated)
- Committer:
- pangsk
- Date:
- Mon Jan 02 20:03:01 2012 +0000
- Revision:
- 0:7f301f08b68f
Initial release.
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| pangsk | 0:7f301f08b68f | 1 | /* RF12B Library. Based on work done by JeeLabs.org ported to mbed by SK Pang. |
| pangsk | 0:7f301f08b68f | 2 | http://jeelabs.net/projects/cafe/wiki/RF12 |
| pangsk | 0:7f301f08b68f | 3 | |
| pangsk | 0:7f301f08b68f | 4 | http://opensource.org/licenses/mit-license.php |
| pangsk | 0:7f301f08b68f | 5 | |
| pangsk | 0:7f301f08b68f | 6 | Jan 2012 skpang.co.uk |
| pangsk | 0:7f301f08b68f | 7 | |
| pangsk | 0:7f301f08b68f | 8 | */ |
| pangsk | 0:7f301f08b68f | 9 | |
| pangsk | 0:7f301f08b68f | 10 | #include "RF12B.h" |
| pangsk | 0:7f301f08b68f | 11 | |
| pangsk | 0:7f301f08b68f | 12 | // RF12 command codes |
| pangsk | 0:7f301f08b68f | 13 | #define RF_RECEIVER_ON 0x82DD |
| pangsk | 0:7f301f08b68f | 14 | #define RF_XMITTER_ON 0x823D |
| pangsk | 0:7f301f08b68f | 15 | #define RF_IDLE_MODE 0x820D |
| pangsk | 0:7f301f08b68f | 16 | #define RF_SLEEP_MODE 0x8205 |
| pangsk | 0:7f301f08b68f | 17 | #define RF_WAKEUP_MODE 0x8207 |
| pangsk | 0:7f301f08b68f | 18 | #define RF_TXREG_WRITE 0xB800 |
| pangsk | 0:7f301f08b68f | 19 | #define RF_RX_FIFO_READ 0xB000 |
| pangsk | 0:7f301f08b68f | 20 | #define RF_WAKEUP_TIMER 0xE000 |
| pangsk | 0:7f301f08b68f | 21 | |
| pangsk | 0:7f301f08b68f | 22 | // RF12 status bits |
| pangsk | 0:7f301f08b68f | 23 | #define RF_LBD_BIT 0x0400 |
| pangsk | 0:7f301f08b68f | 24 | #define RF_RSSI_BIT 0x0100 |
| pangsk | 0:7f301f08b68f | 25 | |
| pangsk | 0:7f301f08b68f | 26 | // bits in the node id configuration byte |
| pangsk | 0:7f301f08b68f | 27 | #define NODE_BAND 0xC0 // frequency band |
| pangsk | 0:7f301f08b68f | 28 | #define NODE_ACKANY 0x20 // ack on broadcast packets if set |
| pangsk | 0:7f301f08b68f | 29 | #define NODE_ID 0x1F // id of this node, as A..Z or 1..31 |
| pangsk | 0:7f301f08b68f | 30 | |
| pangsk | 0:7f301f08b68f | 31 | // transceiver states, these determine what to do with each interrupt |
| pangsk | 0:7f301f08b68f | 32 | enum { |
| pangsk | 0:7f301f08b68f | 33 | TXCRC1, TXCRC2, TXTAIL, TXDONE, TXIDLE, |
| pangsk | 0:7f301f08b68f | 34 | TXRECV, |
| pangsk | 0:7f301f08b68f | 35 | TXPRE1, TXPRE2, TXPRE3, TXSYN1, TXSYN2, |
| pangsk | 0:7f301f08b68f | 36 | }; |
| pangsk | 0:7f301f08b68f | 37 | |
| pangsk | 0:7f301f08b68f | 38 | DigitalOut rfled(LED3); |
| pangsk | 0:7f301f08b68f | 39 | DigitalOut t1(p5); |
| pangsk | 0:7f301f08b68f | 40 | DigitalOut t2(p6); |
| pangsk | 0:7f301f08b68f | 41 | |
| pangsk | 0:7f301f08b68f | 42 | RF12B::RF12B(PinName _SDI, |
| pangsk | 0:7f301f08b68f | 43 | PinName _SDO, |
| pangsk | 0:7f301f08b68f | 44 | PinName _SCK, |
| pangsk | 0:7f301f08b68f | 45 | PinName _NCS, |
| pangsk | 0:7f301f08b68f | 46 | PinName _NIRQ):spi(_SDI, _SDO, _SCK), |
| pangsk | 0:7f301f08b68f | 47 | NCS(_NCS), NIRQ(_NIRQ), NIRQ_in(_NIRQ), rfled(LED3),t1(p5),t2(p6) { |
| pangsk | 0:7f301f08b68f | 48 | |
| pangsk | 0:7f301f08b68f | 49 | /* SPI frequency, word lenght, polarity and phase */ |
| pangsk | 0:7f301f08b68f | 50 | spi.format(8,0); |
| pangsk | 0:7f301f08b68f | 51 | spi.frequency(2000000); |
| pangsk | 0:7f301f08b68f | 52 | |
| pangsk | 0:7f301f08b68f | 53 | /* Set ~CS high */ |
| pangsk | 0:7f301f08b68f | 54 | NCS = 1; |
| pangsk | 0:7f301f08b68f | 55 | |
| pangsk | 0:7f301f08b68f | 56 | /* Setup interrupt to happen on falling edge of NIRQ */ |
| pangsk | 0:7f301f08b68f | 57 | NIRQ.fall(this, &RF12B::rxISR); |
| pangsk | 0:7f301f08b68f | 58 | } |
| pangsk | 0:7f301f08b68f | 59 | |
| pangsk | 0:7f301f08b68f | 60 | |
| pangsk | 0:7f301f08b68f | 61 | /********************************************************************** |
| pangsk | 0:7f301f08b68f | 62 | * PRIVATE FUNCTIONS |
| pangsk | 0:7f301f08b68f | 63 | *********************************************************************/ |
| pangsk | 0:7f301f08b68f | 64 | |
| pangsk | 0:7f301f08b68f | 65 | /* Initialises the RF12B module */ |
| pangsk | 0:7f301f08b68f | 66 | void RF12B::init(uint8_t id, uint8_t band, uint8_t g) { |
| pangsk | 0:7f301f08b68f | 67 | |
| pangsk | 0:7f301f08b68f | 68 | nodeid = id; |
| pangsk | 0:7f301f08b68f | 69 | group = g; |
| pangsk | 0:7f301f08b68f | 70 | rf12_grp = g; |
| pangsk | 0:7f301f08b68f | 71 | |
| pangsk | 0:7f301f08b68f | 72 | writeCmd(0x0000); // intitial SPI transfer added to avoid power-up problem |
| pangsk | 0:7f301f08b68f | 73 | writeCmd(RF_SLEEP_MODE); // DC (disable clk pin), enable lbd |
| pangsk | 0:7f301f08b68f | 74 | |
| pangsk | 0:7f301f08b68f | 75 | // wait until RFM12B is out of power-up reset, this takes several *seconds* |
| pangsk | 0:7f301f08b68f | 76 | writeCmd(RF_TXREG_WRITE); // in case we're still in OOK mode |
| pangsk | 0:7f301f08b68f | 77 | |
| pangsk | 0:7f301f08b68f | 78 | while (NIRQ == 0) writeCmd(0x0000); |
| pangsk | 0:7f301f08b68f | 79 | |
| pangsk | 0:7f301f08b68f | 80 | writeCmd(0x80C7 | (2 << 4)); // EL (ena TX), EF (ena RX FIFO), 12.0pF |
| pangsk | 0:7f301f08b68f | 81 | writeCmd(0xA640); // 868MHz |
| pangsk | 0:7f301f08b68f | 82 | writeCmd(0xC606); // approx 49.2 Kbps, i.e. 10000/29/(1+6) Kbps |
| pangsk | 0:7f301f08b68f | 83 | writeCmd(0x94A2); // VDI,FAST,134kHz,0dBm,-91dBm |
| pangsk | 0:7f301f08b68f | 84 | writeCmd(0xC2AC); // AL,!ml,DIG,DQD4 |
| pangsk | 0:7f301f08b68f | 85 | |
| pangsk | 0:7f301f08b68f | 86 | writeCmd(0xCA83); // FIFO8,2-SYNC,!ff,DR |
| pangsk | 0:7f301f08b68f | 87 | writeCmd(0xCE00 | 1); // SYNC=2DXX; |
| pangsk | 0:7f301f08b68f | 88 | |
| pangsk | 0:7f301f08b68f | 89 | writeCmd(0xC483); // @PWR,NO RSTRIC,!st,!fi,OE,EN |
| pangsk | 0:7f301f08b68f | 90 | writeCmd(0x9850); // !mp,90kHz,MAX OUT |
| pangsk | 0:7f301f08b68f | 91 | writeCmd(0xCC77); // OB1,OB0, LPX,!ddy,DDIT,BW0 |
| pangsk | 0:7f301f08b68f | 92 | writeCmd(0xE000); // NOT USE |
| pangsk | 0:7f301f08b68f | 93 | writeCmd(0xC800); // NOT USE |
| pangsk | 0:7f301f08b68f | 94 | writeCmd(0xC049); // 1.66MHz,3.1V |
| pangsk | 0:7f301f08b68f | 95 | |
| pangsk | 0:7f301f08b68f | 96 | rxstate = TXIDLE; |
| pangsk | 0:7f301f08b68f | 97 | |
| pangsk | 0:7f301f08b68f | 98 | rfled = 0; |
| pangsk | 0:7f301f08b68f | 99 | } |
| pangsk | 0:7f301f08b68f | 100 | |
| pangsk | 0:7f301f08b68f | 101 | /* Write a command to the RF Module */ |
| pangsk | 0:7f301f08b68f | 102 | unsigned int RF12B::writeCmd(unsigned int cmd) { |
| pangsk | 0:7f301f08b68f | 103 | NCS = 0; |
| pangsk | 0:7f301f08b68f | 104 | unsigned int recv = spi.write(cmd >>8); |
| pangsk | 0:7f301f08b68f | 105 | recv = spi.write(cmd); |
| pangsk | 0:7f301f08b68f | 106 | NCS = 1; |
| pangsk | 0:7f301f08b68f | 107 | return recv; |
| pangsk | 0:7f301f08b68f | 108 | } |
| pangsk | 0:7f301f08b68f | 109 | |
| pangsk | 0:7f301f08b68f | 110 | /* Sends a byte of data across RF */ |
| pangsk | 0:7f301f08b68f | 111 | void RF12B::send(unsigned char data) { |
| pangsk | 0:7f301f08b68f | 112 | while (NIRQ); |
| pangsk | 0:7f301f08b68f | 113 | writeCmd(0xB800 + data); |
| pangsk | 0:7f301f08b68f | 114 | } |
| pangsk | 0:7f301f08b68f | 115 | |
| pangsk | 0:7f301f08b68f | 116 | |
| pangsk | 0:7f301f08b68f | 117 | /* Interrupt routine for data reception and Txing */ |
| pangsk | 0:7f301f08b68f | 118 | void RF12B::rxISR() { |
| pangsk | 0:7f301f08b68f | 119 | |
| pangsk | 0:7f301f08b68f | 120 | // a transfer of 2x 16 bits @ 2 MHz over SPI takes 2x 8 us inside this ISR |
| pangsk | 0:7f301f08b68f | 121 | writeCmd(0x0000); |
| pangsk | 0:7f301f08b68f | 122 | |
| pangsk | 0:7f301f08b68f | 123 | if (rxstate == TXRECV) { |
| pangsk | 0:7f301f08b68f | 124 | uint8_t in = rf12_xfer(RF_RX_FIFO_READ); |
| pangsk | 0:7f301f08b68f | 125 | |
| pangsk | 0:7f301f08b68f | 126 | if (rxfill == 0 && group != 0) |
| pangsk | 0:7f301f08b68f | 127 | rf12_buf[rxfill++] = group; |
| pangsk | 0:7f301f08b68f | 128 | |
| pangsk | 0:7f301f08b68f | 129 | rf12_buf[rxfill++] = in; |
| pangsk | 0:7f301f08b68f | 130 | rf12_crc = _crc16_update(rf12_crc, in); |
| pangsk | 0:7f301f08b68f | 131 | |
| pangsk | 0:7f301f08b68f | 132 | if (rxfill >= rf12_len + 5 || rxfill >= RF_MAX) |
| pangsk | 0:7f301f08b68f | 133 | rf12_xfer(RF_IDLE_MODE); |
| pangsk | 0:7f301f08b68f | 134 | } else { |
| pangsk | 0:7f301f08b68f | 135 | uint8_t out; |
| pangsk | 0:7f301f08b68f | 136 | |
| pangsk | 0:7f301f08b68f | 137 | if (rxstate < 0) { |
| pangsk | 0:7f301f08b68f | 138 | uint8_t pos = 3 + rf12_len + rxstate++; |
| pangsk | 0:7f301f08b68f | 139 | out = rf12_buf[pos]; |
| pangsk | 0:7f301f08b68f | 140 | rf12_crc = _crc16_update(rf12_crc, out); |
| pangsk | 0:7f301f08b68f | 141 | } else |
| pangsk | 0:7f301f08b68f | 142 | switch (rxstate++) { |
| pangsk | 0:7f301f08b68f | 143 | case TXSYN1: out = 0x2D; break; |
| pangsk | 0:7f301f08b68f | 144 | case TXSYN2: out = rf12_grp; rxstate = - (2 + rf12_len); break; |
| pangsk | 0:7f301f08b68f | 145 | case TXCRC1: out = rf12_crc; break; |
| pangsk | 0:7f301f08b68f | 146 | case TXCRC2: out = rf12_crc >> 8; break; |
| pangsk | 0:7f301f08b68f | 147 | case TXDONE: rf12_xfer(RF_IDLE_MODE); // fall through |
| pangsk | 0:7f301f08b68f | 148 | default: out = 0xAA; |
| pangsk | 0:7f301f08b68f | 149 | } |
| pangsk | 0:7f301f08b68f | 150 | |
| pangsk | 0:7f301f08b68f | 151 | rf12_xfer(RF_TXREG_WRITE + out); |
| pangsk | 0:7f301f08b68f | 152 | } |
| pangsk | 0:7f301f08b68f | 153 | } |
| pangsk | 0:7f301f08b68f | 154 | |
| pangsk | 0:7f301f08b68f | 155 | |
| pangsk | 0:7f301f08b68f | 156 | void RF12B::rf12_sendStart (uint8_t hdr, const void* ptr, uint8_t len) |
| pangsk | 0:7f301f08b68f | 157 | { |
| pangsk | 0:7f301f08b68f | 158 | rf12_len = len; |
| pangsk | 0:7f301f08b68f | 159 | memcpy((void*) rf12_data, ptr, len); |
| pangsk | 0:7f301f08b68f | 160 | |
| pangsk | 0:7f301f08b68f | 161 | rf12_sendStart2(hdr); |
| pangsk | 0:7f301f08b68f | 162 | |
| pangsk | 0:7f301f08b68f | 163 | } |
| pangsk | 0:7f301f08b68f | 164 | void RF12B::rf12_sendStart2 (uint8_t hdr) { |
| pangsk | 0:7f301f08b68f | 165 | rf12_hdr = hdr & RF12_HDR_DST ? hdr : |
| pangsk | 0:7f301f08b68f | 166 | (hdr & ~RF12_HDR_MASK) + (nodeid & NODE_ID); |
| pangsk | 0:7f301f08b68f | 167 | |
| pangsk | 0:7f301f08b68f | 168 | /* if (crypter != 0) |
| pangsk | 0:7f301f08b68f | 169 | crypter(1); |
| pangsk | 0:7f301f08b68f | 170 | */ |
| pangsk | 0:7f301f08b68f | 171 | rf12_crc = ~0; |
| pangsk | 0:7f301f08b68f | 172 | |
| pangsk | 0:7f301f08b68f | 173 | rf12_crc = _crc16_update(rf12_crc, rf12_grp); |
| pangsk | 0:7f301f08b68f | 174 | rxstate = TXPRE1; |
| pangsk | 0:7f301f08b68f | 175 | |
| pangsk | 0:7f301f08b68f | 176 | rf12_xfer(RF_XMITTER_ON); // bytes will be fed via interrupts |
| pangsk | 0:7f301f08b68f | 177 | } |
| pangsk | 0:7f301f08b68f | 178 | |
| pangsk | 0:7f301f08b68f | 179 | |
| pangsk | 0:7f301f08b68f | 180 | uint16_t RF12B::rf12_xfer (uint16_t cmd) { |
| pangsk | 0:7f301f08b68f | 181 | NCS = 0; |
| pangsk | 0:7f301f08b68f | 182 | uint16_t reply = rf12_byte(cmd >> 8) << 8; |
| pangsk | 0:7f301f08b68f | 183 | reply |= rf12_byte(cmd); |
| pangsk | 0:7f301f08b68f | 184 | NCS = 1; |
| pangsk | 0:7f301f08b68f | 185 | return reply; |
| pangsk | 0:7f301f08b68f | 186 | } |
| pangsk | 0:7f301f08b68f | 187 | |
| pangsk | 0:7f301f08b68f | 188 | void RF12B::rf12_recvStart (void) { |
| pangsk | 0:7f301f08b68f | 189 | rxfill = rf12_len = 0; |
| pangsk | 0:7f301f08b68f | 190 | rf12_crc = ~0; |
| pangsk | 0:7f301f08b68f | 191 | |
| pangsk | 0:7f301f08b68f | 192 | if (group != 0) |
| pangsk | 0:7f301f08b68f | 193 | rf12_crc = _crc16_update(~0, group); |
| pangsk | 0:7f301f08b68f | 194 | |
| pangsk | 0:7f301f08b68f | 195 | rxstate = TXRECV; |
| pangsk | 0:7f301f08b68f | 196 | rf12_xfer(RF_RECEIVER_ON); |
| pangsk | 0:7f301f08b68f | 197 | } |
| pangsk | 0:7f301f08b68f | 198 | uint16_t RF12B::check_crc(void) |
| pangsk | 0:7f301f08b68f | 199 | { |
| pangsk | 0:7f301f08b68f | 200 | |
| pangsk | 0:7f301f08b68f | 201 | return rf12_crc; |
| pangsk | 0:7f301f08b68f | 202 | } |
| pangsk | 0:7f301f08b68f | 203 | uint8_t RF12B::length(void) |
| pangsk | 0:7f301f08b68f | 204 | { |
| pangsk | 0:7f301f08b68f | 205 | |
| pangsk | 0:7f301f08b68f | 206 | return rf12_len; |
| pangsk | 0:7f301f08b68f | 207 | } |
| pangsk | 0:7f301f08b68f | 208 | uint8_t* RF12B::get_data(void) |
| pangsk | 0:7f301f08b68f | 209 | { |
| pangsk | 0:7f301f08b68f | 210 | return (uint8_t*)rf12_data; |
| pangsk | 0:7f301f08b68f | 211 | |
| pangsk | 0:7f301f08b68f | 212 | } |
| pangsk | 0:7f301f08b68f | 213 | |
| pangsk | 0:7f301f08b68f | 214 | |
| pangsk | 0:7f301f08b68f | 215 | uint8_t RF12B::rf12_recvDone (void) { |
| pangsk | 0:7f301f08b68f | 216 | |
| pangsk | 0:7f301f08b68f | 217 | if (rxstate == TXRECV && (rxfill >= rf12_len + 5 || rxfill >= RF_MAX)) { |
| pangsk | 0:7f301f08b68f | 218 | rxstate = TXIDLE; |
| pangsk | 0:7f301f08b68f | 219 | |
| pangsk | 0:7f301f08b68f | 220 | if (rf12_len > RF12_MAXDATA) |
| pangsk | 0:7f301f08b68f | 221 | rf12_crc = 1; // force bad crc if packet length is invalid |
| pangsk | 0:7f301f08b68f | 222 | if (!(rf12_hdr & RF12_HDR_DST) || (nodeid & NODE_ID) == 31 || |
| pangsk | 0:7f301f08b68f | 223 | (rf12_hdr & RF12_HDR_MASK) == (nodeid & NODE_ID)) { |
| pangsk | 0:7f301f08b68f | 224 | /* |
| pangsk | 0:7f301f08b68f | 225 | for(i=0;i<rf12_len+6;i++) |
| pangsk | 0:7f301f08b68f | 226 | { |
| pangsk | 0:7f301f08b68f | 227 | printf("%X ",rf12_buf[i]); |
| pangsk | 0:7f301f08b68f | 228 | } |
| pangsk | 0:7f301f08b68f | 229 | printf(" crc:%x",rf12_crc); |
| pangsk | 0:7f301f08b68f | 230 | */ |
| pangsk | 0:7f301f08b68f | 231 | /* |
| pangsk | 0:7f301f08b68f | 232 | if (rf12_crc == 0 && crypter != 0) |
| pangsk | 0:7f301f08b68f | 233 | crypter(0); |
| pangsk | 0:7f301f08b68f | 234 | else |
| pangsk | 0:7f301f08b68f | 235 | rf12_seq = -1; |
| pangsk | 0:7f301f08b68f | 236 | */ |
| pangsk | 0:7f301f08b68f | 237 | return 1; // it's a broadcast packet or it's addressed to this node |
| pangsk | 0:7f301f08b68f | 238 | |
| pangsk | 0:7f301f08b68f | 239 | } |
| pangsk | 0:7f301f08b68f | 240 | } |
| pangsk | 0:7f301f08b68f | 241 | if (rxstate == TXIDLE) |
| pangsk | 0:7f301f08b68f | 242 | rf12_recvStart(); |
| pangsk | 0:7f301f08b68f | 243 | return 0; |
| pangsk | 0:7f301f08b68f | 244 | } |
| pangsk | 0:7f301f08b68f | 245 | |
| pangsk | 0:7f301f08b68f | 246 | uint8_t RF12B::rf12_byte(uint8_t out) |
| pangsk | 0:7f301f08b68f | 247 | { |
| pangsk | 0:7f301f08b68f | 248 | unsigned char recv = spi.write(out); |
| pangsk | 0:7f301f08b68f | 249 | |
| pangsk | 0:7f301f08b68f | 250 | return recv; |
| pangsk | 0:7f301f08b68f | 251 | } |
| pangsk | 0:7f301f08b68f | 252 | |
| pangsk | 0:7f301f08b68f | 253 | uint16_t RF12B::_crc16_update(uint16_t crc, uint8_t data) { |
| pangsk | 0:7f301f08b68f | 254 | int i; |
| pangsk | 0:7f301f08b68f | 255 | |
| pangsk | 0:7f301f08b68f | 256 | crc ^= data; |
| pangsk | 0:7f301f08b68f | 257 | for (i = 0; i < 8; ++i) |
| pangsk | 0:7f301f08b68f | 258 | { |
| pangsk | 0:7f301f08b68f | 259 | if (crc & 1) |
| pangsk | 0:7f301f08b68f | 260 | crc = (crc >> 1) ^ 0xA001; |
| pangsk | 0:7f301f08b68f | 261 | else |
| pangsk | 0:7f301f08b68f | 262 | crc = (crc >> 1); |
| pangsk | 0:7f301f08b68f | 263 | } |
| pangsk | 0:7f301f08b68f | 264 | |
| pangsk | 0:7f301f08b68f | 265 | return crc; |
| pangsk | 0:7f301f08b68f | 266 | } |
| pangsk | 0:7f301f08b68f | 267 | |
| pangsk | 0:7f301f08b68f | 268 | |
| pangsk | 0:7f301f08b68f | 269 | |
| pangsk | 0:7f301f08b68f | 270 | |
| pangsk | 0:7f301f08b68f | 271 | |
| pangsk | 0:7f301f08b68f | 272 | |
| pangsk | 0:7f301f08b68f | 273 | |
| pangsk | 0:7f301f08b68f | 274 | |
| pangsk | 0:7f301f08b68f | 275 | |
| pangsk | 0:7f301f08b68f | 276 |