forked from LowPowerLab/RFM12B
-
Notifications
You must be signed in to change notification settings - Fork 0
/
RFM12B.h
258 lines (224 loc) · 8.86 KB
/
RFM12B.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
// RFM12B driver definitions
// http://opensource.org/licenses/mit-license.php
// 2012-12-12 (C) [email protected]
// Based on the RFM12 driver from jeelabs.com (2009-02-09 <[email protected]>)
#ifndef RFM12B_h
#define RFM12B_h
#define RF69_COMPAT 1
#define DISABLE_RSSI_CHECK 0
#include <inttypes.h>
#include <avr/io.h>
#include <util/crc16.h>
#include <avr/eeprom.h>
#include <avr/sleep.h>
#if ARDUINO >= 100
#include <Arduino.h> // Arduino 1.0
#else
#include <WProgram.h> // Arduino 0022
#endif
///RF12 Driver version
#define OPTIMIZE_SPI 1 // uncomment this to write to the RFM12B @ 8 Mhz
/// RF12 CTL bit mask.
//#define RF12_HDR_CTL 0x80
/// RF12 DST bit mask.
//#define RF12_HDR_DST 0x40
/// RF12 ACK bit mask.
//#define RF12_HDR_ACK 0x20
/// RF12 HDR bit mask.
//#define RF12_HDR_MASK 0x1F
/// RF12 SENDER extracted from last packet
//#define RF12_SOURCEID rf12_hdr & RF12_HDR_MASK
/// RF12 Maximum message size in bytes.
#define RF12_MAXDATA 128
/// Max transmit/receive buffer: 4 header + data + 2 crc bytes
#define RF_MAX (RF12_MAXDATA + 6)
//frequency bands
#define RF12_315MHZ 0
#define RF12_433MHZ 1
#define RF12_868MHZ 2
#define RF12_915MHZ 3
//Low batteery threshold (eg 2v25 = 2.25V)
#define RF12_2v25 0
#define RF12_2v55 3
#define RF12_2v65 4
#define RF12_2v75 5
#define RF12_3v05 8
#define RF12_3v15 9
#define RF12_3v25 10
#define RF12_HDR_IDMASK 0x7F
#define RF12_HDR_ACKCTLMASK 0x80
#define RF12_DESTID (rf12_hdr1 & RF12_HDR_IDMASK)
#define RF12_SOURCEID (rf12_hdr2 & RF12_HDR_IDMASK)
// shorthands to simplify sending out the proper ACK when requested
#if !defined(RF69_COMPAT)
#define RF12_WANTS_ACK ((rf12_hdr2 & RF12_HDR_ACKCTLMASK) && !(rf12_hdr1 & RF12_HDR_ACKCTLMASK))
#else
#define RF12_WANTS_ACK ((rf12_hdr3 & 0x40) && !(rf12_hdr1 & 0x80))
#endif
// options for RF12_sleep()
#define RF12_SLEEP 0
#define RF12_WAKEUP -1
#if !defined(RF69_COMPAT)
/// Shorthand for RF12 group byte in rf12_buf.
#define rf12_grp rf12_buf[0]
/// pointer to 1st header byte in rf12_buf (CTL + DESTINATIONID)
#define rf12_hdr1 rf12_buf[1]
/// pointer to 2nd header byte in rf12_buf (ACK + SOURCEID)
#define rf12_hdr2 rf12_buf[2]
/// Shorthand for RF12 length byte in rf12_buf.
#define rf12_len rf12_buf[3]
/// Shorthand for first RF12 data byte in rf12_buf.
#define rf12_data (rf12_buf + 4)
#else
/// Shorthand for RF12 group byte in rf12_buf.
#define rf12_grp rf12_buf[0]
/// pointer to 1st header byte in rf12_buf (DESTINATIONID)
#define rf12_hdr1 rf12_buf[2]
/// pointer to 2nd header byte in rf12_buf (SOURCEID)
#define rf12_hdr2 rf12_buf[3]
/// pointer to 3rd header byte in rf12_bug (CTL + ACK)
#define rf12_hdr3 rf12_buf[4]
/// Shorthand for RF12 length byte in rf12_buf
#define rf12_len rf12_buf[1]
/// Shorthand for first RF12 data byte in rf12_buf.
#define rf12_data (rf12_buf + 5)
#endif
// pin change interrupts are currently only supported on ATmega328's
// #define PINCHG_IRQ 1 // uncomment this to use pin-change interrupts
// pins used for the RFM12B interface - yes, there *is* logic in this madness:
// - leave RFM_IRQ set to the pin which corresponds with INT0, because the
// current driver code will use attachInterrupt() to hook into that
// - (new) you can now change RFM_IRQ, if you also enable PINCHG_IRQ - this
// will switch to pin change interrupts instead of attach/detachInterrupt()
// - use SS_DDR, SS_PORT, and SS_BIT to define the pin you will be using as
// select pin for the RFM12B (you're free to set them to anything you like)
// - please leave SPI_SS, SPI_MOSI, SPI_MISO, and SPI_SCK as is, i.e. pointing
// to the hardware-supported SPI pins on the ATmega, *including* SPI_SS !
#if defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1280__)
#define RFM_IRQ 2
#define SS_DDR DDRB
#define SS_PORT PORTB
#define SS_BIT 0
#define SPI_SS 53 // PB0, pin 19
#define SPI_MOSI 51 // PB2, pin 21
#define SPI_MISO 50 // PB3, pin 22
#define SPI_SCK 52 // PB1, pin 20
#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__)
#define RFM_IRQ 10
#define SS_DDR DDRB
#define SS_PORT PORTB
#define SS_BIT 4
#define SPI_SS 4
#define SPI_MOSI 5
#define SPI_MISO 6
#define SPI_SCK 7
#elif defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny44__)
#define RFM_IRQ 2
#define SS_DDR DDRB
#define SS_PORT PORTB
#define SS_BIT 1
#define SPI_SS 1 // PB1, pin 3
#define SPI_MISO 4 // PA6, pin 7
#define SPI_MOSI 5 // PA5, pin 8
#define SPI_SCK 6 // PA4, pin 9
#elif defined(__AVR_ATmega32U4__) //Arduino Leonardo, MoteinoLeo
#define RFM_IRQ 0 // PD0, INT0, Digital3
#define SS_DDR DDRB
#define SS_PORT PORTB
//OLD from Jeelib: #define SS_BIT 6 // Dig10, PB6
#define SS_BIT 0 // Dig17, PB0
#define SPI_SS 17 // PB0, pin 8, Digital17
#define SPI_MISO 14 // PB3, pin 11, Digital14
#define SPI_MOSI 16 // PB2, pin 10, Digital16
#define SPI_SCK 15 // PB1, pin 9, Digital15
#else
// ATmega168, ATmega328, etc.
#define RFM_IRQ 2
#define SS_DDR DDRB
#define SS_PORT PORTB
#define SS_BIT 2 // for PORTB: 2 = d.10, 1 = d.9, 0 = d.8
#define SPI_SS 10 // PB2, pin 16
#define SPI_MOSI 11 // PB3, pin 17
#define SPI_MISO 12 // PB4, pin 18
#define SPI_SCK 13 // PB5, pin 19
#endif
// RF12 command codes
#define RF_RECEIVER_ON 0x82DD
#define RF_XMITTER_ON 0x823D
#define RF_IDLE_MODE 0x820D
#define RF_SLEEP_MODE 0x8205
#define RF_WAKEUP_MODE 0x8207
#define RF_TXREG_WRITE 0xB800
#define RF_RX_FIFO_READ 0xB000
#define RF_WAKEUP_TIMER 0xE000
//RF12 status bits
#define RF_LBD_BIT 0x0400
#define RF_RSSI_BIT 0x0100
// transceiver states, these determine what to do with each interrupt
enum {
TXCRC1, TXCRC2, TXTAIL, TXDONE, TXIDLE,
TXRECV,
TXPRE1, TXPRE2, TXPRE3, TXSYN1, TXSYN2,
};
extern volatile uint8_t rf12_buf[RF_MAX]; // recv/xmit buf, including hdr & crc bytes
class RFM12B
{
static volatile uint8_t rxfill; // number of data bytes in rf12_buf
static volatile int8_t rxstate; // current transceiver state
static volatile uint16_t rf12_crc; // running crc value
static uint32_t seqNum; // encrypted send sequence number
static uint32_t cryptKey[4]; // encryption key to use
static long rf12_seq; // seq number of encrypted packet (or -1)
static uint8_t cs_pin; // chip select pin
void (*crypter)(bool); // does en-/decryption (null if disabled)
static uint8_t Byte(uint8_t out);
static uint16_t XFERSlow(uint16_t cmd);
static void XFER(uint16_t cmd);
void SPIInit();
#if defined(RF69_COMPAT)
volatile uint8_t* Data;
volatile uint8_t* DataLen;
#endif
public:
//constructor
RFM12B():Data(rf12_data),DataLen(&rf12_len){}
static uint8_t networkID; // network group
static uint8_t nodeID; // address of this node
static const byte DATAMAXLEN;
#if !defined(RF69_COMPAT) //don't hold the same values in COMPAT mode, so use the accessor functions
volatile uint8_t* Data;
volatile uint8_t* DataLen;
#endif
static void InterruptHandler();
//Defaults: Group: 0xAA=170, transmit power: 0(max), KBPS: 38.3Kbps (air transmission baud - has to be same on all radios in same group)
void Initialize(uint8_t nodeid, uint8_t freqBand, uint8_t groupid=0xAA, uint8_t txPower=0, uint8_t airKbps=0x7F, uint8_t lowVoltageThreshold=RF12_2v75);
void SetCS(uint8_t pin);
void ReceiveStart();
bool ReceiveComplete();
bool CanSend();
uint16_t Control(uint16_t cmd);
void SendStart(uint8_t toNodeId, bool requestACK=false, bool sendACK=false);
void SendStart(uint8_t toNodeId, const void* sendBuf, uint8_t sendLen, bool requestACK=false, bool sendACK=false, uint8_t waitMode=SLEEP_MODE_STANDBY);
void SendACK(const void* sendBuf = "", uint8_t sendLen=0, uint8_t waitMode=SLEEP_MODE_IDLE);
void Send(uint8_t toNodeId, const void* sendBuf, uint8_t sendLen, bool requestACK = false, uint8_t waitMode=SLEEP_MODE_STANDBY);
void SendWait(uint8_t waitMode=0);
void OnOff(uint8_t value);
void Sleep(char n);
void Sleep();
void Wakeup();
volatile uint8_t * GetData();
uint8_t GetDataLen(); //how many bytes were received
uint8_t GetSender();
bool LowBattery();
bool ACKRequested();
bool ACKReceived(uint8_t fromNodeID=0);
static void CryptFunction(bool sending);
void Encrypt(const uint8_t* key, uint8_t keyLen = 16);
#if !defined(RF69_COMPAT)
bool CRCPass() { return rf12_crc == 0; }
#else
bool CRCPass() { return rf12_crc == 0x1d0f; }
#endif
bool ReceiveStarted();
};
#endif