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
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
|
#include <stdlib.h>
#include <avr/io.h>
#include <util/delay.h>
#include "radio.h"
#include "serial.h"
#define SPI_SS PB2
#define SPI_SCK PB5
#define SPI_MISO PB4
#define SPI_MOSI PB3
#define SPI_DDR DDRB
#define SPI_PORT PORTB
// Register names
#define RH_RF69_REG_00_FIFO 0x00
#define RH_RF69_REG_01_OPMODE 0x01
#define RH_RF69_REG_02_DATAMODUL 0x02
#define RH_RF69_REG_03_BITRATEMSB 0x03
#define RH_RF69_REG_04_BITRATELSB 0x04
#define RH_RF69_REG_05_FDEVMSB 0x05
#define RH_RF69_REG_06_FDEVLSB 0x06
#define RH_RF69_REG_07_FRFMSB 0x07
#define RH_RF69_REG_08_FRFMID 0x08
#define RH_RF69_REG_09_FRFLSB 0x09
#define RH_RF69_REG_0A_OSC1 0x0a
#define RH_RF69_REG_0B_AFCCTRL 0x0b
#define RH_RF69_REG_0C_RESERVED 0x0c
#define RH_RF69_REG_0D_LISTEN1 0x0d
#define RH_RF69_REG_0E_LISTEN2 0x0e
#define RH_RF69_REG_0F_LISTEN3 0x0f
#define RH_RF69_REG_10_VERSION 0x10
#define RH_RF69_REG_11_PALEVEL 0x11
#define RH_RF69_REG_12_PARAMP 0x12
#define RH_RF69_REG_13_OCP 0x13
#define RH_RF69_REG_14_RESERVED 0x14
#define RH_RF69_REG_15_RESERVED 0x15
#define RH_RF69_REG_16_RESERVED 0x16
#define RH_RF69_REG_17_RESERVED 0x17
#define RH_RF69_REG_18_LNA 0x18
#define RH_RF69_REG_19_RXBW 0x19
#define RH_RF69_REG_1A_AFCBW 0x1a
#define RH_RF69_REG_1B_OOKPEAK 0x1b
#define RH_RF69_REG_1C_OOKAVG 0x1c
#define RH_RF69_REG_1D_OOKFIX 0x1d
#define RH_RF69_REG_1E_AFCFEI 0x1e
#define RH_RF69_REG_1F_AFCMSB 0x1f
#define RH_RF69_REG_20_AFCLSB 0x20
#define RH_RF69_REG_21_FEIMSB 0x21
#define RH_RF69_REG_22_FEILSB 0x22
#define RH_RF69_REG_23_RSSICONFIG 0x23
#define RH_RF69_REG_24_RSSIVALUE 0x24
#define RH_RF69_REG_25_DIOMAPPING1 0x25
#define RH_RF69_REG_26_DIOMAPPING2 0x26
#define RH_RF69_REG_27_IRQFLAGS1 0x27
#define RH_RF69_REG_28_IRQFLAGS2 0x28
#define RH_RF69_REG_29_RSSITHRESH 0x29
#define RH_RF69_REG_2A_RXTIMEOUT1 0x2a
#define RH_RF69_REG_2B_RXTIMEOUT2 0x2b
#define RH_RF69_REG_2C_PREAMBLEMSB 0x2c
#define RH_RF69_REG_2D_PREAMBLELSB 0x2d
#define RH_RF69_REG_2E_SYNCCONFIG 0x2e
#define RH_RF69_REG_2F_SYNCVALUE1 0x2f
// another 7 sync word bytes follow, 30 through 36 inclusive
#define RH_RF69_REG_37_PACKETCONFIG1 0x37
#define RH_RF69_REG_38_PAYLOADLENGTH 0x38
#define RH_RF69_REG_39_NODEADRS 0x39
#define RH_RF69_REG_3A_BROADCASTADRS 0x3a
#define RH_RF69_REG_3B_AUTOMODES 0x3b
#define RH_RF69_REG_3C_FIFOTHRESH 0x3c
#define RH_RF69_REG_3D_PACKETCONFIG2 0x3d
#define RH_RF69_REG_3E_AESKEY1 0x3e
// Another 15 AES key bytes follow
#define RH_RF69_REG_4E_TEMP1 0x4e
#define RH_RF69_REG_4F_TEMP2 0x4f
#define RH_RF69_REG_58_TESTLNA 0x58
#define RH_RF69_REG_5A_TESTPA1 0x5a
#define RH_RF69_REG_5C_TESTPA2 0x5c
#define RH_RF69_REG_6F_TESTDAGC 0x6f
#define RH_RF69_REG_71_TESTAFC 0x71
// RH_RF69_REG_01_OPMODE
#define RH_RF69_OPMODE_SEQUENCEROFF 0x80
#define RH_RF69_OPMODE_LISTENON 0x40
#define RH_RF69_OPMODE_LISTENABORT 0x20
#define RH_RF69_OPMODE_MODE 0x1c
#define RH_RF69_OPMODE_MODE_SLEEP 0x00
#define RH_RF69_OPMODE_MODE_STDBY 0x04
#define RH_RF69_OPMODE_MODE_FS 0x08
#define RH_RF69_OPMODE_MODE_TX 0x0c
#define RH_RF69_OPMODE_MODE_RX 0x10
// RH_RF69_REG_02_DATAMODUL
#define RH_RF69_DATAMODUL_DATAMODE 0x60
#define RH_RF69_DATAMODUL_DATAMODE_PACKET 0x00
#define RH_RF69_DATAMODUL_DATAMODE_CONT_WITH_SYNC 0x40
#define RH_RF69_DATAMODUL_DATAMODE_CONT_WITHOUT_SYNC 0x60
#define RH_RF69_DATAMODUL_MODULATIONTYPE 0x18
#define RH_RF69_DATAMODUL_MODULATIONTYPE_FSK 0x00
#define RH_RF69_DATAMODUL_MODULATIONTYPE_OOK 0x08
#define RH_RF69_DATAMODUL_MODULATIONSHAPING 0x03
#define RH_RF69_DATAMODUL_MODULATIONSHAPING_FSK_NONE 0x00
#define RH_RF69_DATAMODUL_MODULATIONSHAPING_FSK_BT1_0 0x01
#define RH_RF69_DATAMODUL_MODULATIONSHAPING_FSK_BT0_5 0x02
#define RH_RF69_DATAMODUL_MODULATIONSHAPING_FSK_BT0_3 0x03
#define RH_RF69_DATAMODUL_MODULATIONSHAPING_OOK_NONE 0x00
#define RH_RF69_DATAMODUL_MODULATIONSHAPING_OOK_BR 0x01
#define RH_RF69_DATAMODUL_MODULATIONSHAPING_OOK_2BR 0x02
// RH_RF69_REG_11_PALEVEL
#define RH_RF69_PALEVEL_PA0ON 0x80
#define RH_RF69_PALEVEL_PA1ON 0x40
#define RH_RF69_PALEVEL_PA2ON 0x20
#define RH_RF69_PALEVEL_OUTPUTPOWER 0x1f
// RH_RF69_REG_23_RSSICONFIG
#define RH_RF69_RSSICONFIG_RSSIDONE 0x02
#define RH_RF69_RSSICONFIG_RSSISTART 0x01
// RH_RF69_REG_25_DIOMAPPING1
#define RH_RF69_DIOMAPPING1_DIO0MAPPING 0xc0
#define RH_RF69_DIOMAPPING1_DIO0MAPPING_00 0x00
#define RH_RF69_DIOMAPPING1_DIO0MAPPING_01 0x40
#define RH_RF69_DIOMAPPING1_DIO0MAPPING_10 0x80
#define RH_RF69_DIOMAPPING1_DIO0MAPPING_11 0xc0
#define RH_RF69_DIOMAPPING1_DIO1MAPPING 0x30
#define RH_RF69_DIOMAPPING1_DIO1MAPPING_00 0x00
#define RH_RF69_DIOMAPPING1_DIO1MAPPING_01 0x10
#define RH_RF69_DIOMAPPING1_DIO1MAPPING_10 0x20
#define RH_RF69_DIOMAPPING1_DIO1MAPPING_11 0x30
#define RH_RF69_DIOMAPPING1_DIO2MAPPING 0x0c
#define RH_RF69_DIOMAPPING1_DIO2MAPPING_00 0x00
#define RH_RF69_DIOMAPPING1_DIO2MAPPING_01 0x04
#define RH_RF69_DIOMAPPING1_DIO2MAPPING_10 0x08
#define RH_RF69_DIOMAPPING1_DIO2MAPPING_11 0x0c
#define RH_RF69_DIOMAPPING1_DIO3MAPPING 0x03
#define RH_RF69_DIOMAPPING1_DIO3MAPPING_00 0x00
#define RH_RF69_DIOMAPPING1_DIO3MAPPING_01 0x01
#define RH_RF69_DIOMAPPING1_DIO3MAPPING_10 0x02
#define RH_RF69_DIOMAPPING1_DIO3MAPPING_11 0x03
// RH_RF69_REG_26_DIOMAPPING2
#define RH_RF69_DIOMAPPING2_DIO4MAPPING 0xc0
#define RH_RF69_DIOMAPPING2_DIO4MAPPING_00 0x00
#define RH_RF69_DIOMAPPING2_DIO4MAPPING_01 0x40
#define RH_RF69_DIOMAPPING2_DIO4MAPPING_10 0x80
#define RH_RF69_DIOMAPPING2_DIO4MAPPING_11 0xc0
#define RH_RF69_DIOMAPPING2_DIO5MAPPING 0x30
#define RH_RF69_DIOMAPPING2_DIO5MAPPING_00 0x00
#define RH_RF69_DIOMAPPING2_DIO5MAPPING_01 0x10
#define RH_RF69_DIOMAPPING2_DIO5MAPPING_10 0x20
#define RH_RF69_DIOMAPPING2_DIO5MAPPING_11 0x30
#define RH_RF69_DIOMAPPING2_CLKOUT 0x07
#define RH_RF69_DIOMAPPING2_CLKOUT_FXOSC_ 0x00
#define RH_RF69_DIOMAPPING2_CLKOUT_FXOSC_2 0x01
#define RH_RF69_DIOMAPPING2_CLKOUT_FXOSC_4 0x02
#define RH_RF69_DIOMAPPING2_CLKOUT_FXOSC_8 0x03
#define RH_RF69_DIOMAPPING2_CLKOUT_FXOSC_16 0x04
#define RH_RF69_DIOMAPPING2_CLKOUT_FXOSC_32 0x05
#define RH_RF69_DIOMAPPING2_CLKOUT_FXOSC_RC 0x06
#define RH_RF69_DIOMAPPING2_CLKOUT_FXOSC_OFF 0x07
// RH_RF69_REG_27_IRQFLAGS1
#define RH_RF69_IRQFLAGS1_MODEREADY 0x80
#define RH_RF69_IRQFLAGS1_RXREADY 0x40
#define RH_RF69_IRQFLAGS1_TXREADY 0x20
#define RH_RF69_IRQFLAGS1_PLLLOCK 0x10
#define RH_RF69_IRQFLAGS1_RSSI 0x08
#define RH_RF69_IRQFLAGS1_TIMEOUT 0x04
#define RH_RF69_IRQFLAGS1_AUTOMODE 0x02
#define RH_RF69_IRQFLAGS1_SYNADDRESSMATCH 0x01
// RH_RF69_REG_28_IRQFLAGS2
#define RH_RF69_IRQFLAGS2_FIFOFULL 0x80
#define RH_RF69_IRQFLAGS2_FIFONOTEMPTY 0x40
#define RH_RF69_IRQFLAGS2_FIFOLEVEL 0x20
#define RH_RF69_IRQFLAGS2_FIFOOVERRUN 0x10
#define RH_RF69_IRQFLAGS2_PACKETSENT 0x08
#define RH_RF69_IRQFLAGS2_PAYLOADREADY 0x04
#define RH_RF69_IRQFLAGS2_CRCOK 0x02
// RH_RF69_REG_2E_SYNCCONFIG
#define RH_RF69_SYNCCONFIG_SYNCON 0x80
#define RH_RF69_SYNCCONFIG_FIFOFILLCONDITION_MANUAL 0x40
#define RH_RF69_SYNCCONFIG_SYNCSIZE 0x38
#define RH_RF69_SYNCCONFIG_SYNCSIZE_1 0x00
#define RH_RF69_SYNCCONFIG_SYNCSIZE_2 0x08
#define RH_RF69_SYNCCONFIG_SYNCSIZE_3 0x10
#define RH_RF69_SYNCCONFIG_SYNCSIZE_4 0x18
#define RH_RF69_SYNCCONFIG_SYNCSIZE_5 0x20
#define RH_RF69_SYNCCONFIG_SYNCSIZE_6 0x28
#define RH_RF69_SYNCCONFIG_SYNCSIZE_7 0x30
#define RH_RF69_SYNCCONFIG_SYNCSIZE_8 0x38
#define RH_RF69_SYNCCONFIG_SYNCSIZE_SYNCTOL 0x07
// RH_RF69_REG_37_PACKETCONFIG1
#define RH_RF69_PACKETCONFIG1_PACKETFORMAT_VARIABLE 0x80
#define RH_RF69_PACKETCONFIG1_DCFREE 0x60
#define RH_RF69_PACKETCONFIG1_DCFREE_NONE 0x00
#define RH_RF69_PACKETCONFIG1_DCFREE_MANCHESTER 0x20
#define RH_RF69_PACKETCONFIG1_DCFREE_WHITENING 0x40
#define RH_RF69_PACKETCONFIG1_DCFREE_RESERVED 0x60
#define RH_RF69_PACKETCONFIG1_CRC_ON 0x10
#define RH_RF69_PACKETCONFIG1_CRCAUTOCLEAROFF 0x08
#define RH_RF69_PACKETCONFIG1_ADDRESSFILTERING 0x06
#define RH_RF69_PACKETCONFIG1_ADDRESSFILTERING_NONE 0x00
#define RH_RF69_PACKETCONFIG1_ADDRESSFILTERING_NODE 0x02
#define RH_RF69_PACKETCONFIG1_ADDRESSFILTERING_NODE_BC 0x04
#define RH_RF69_PACKETCONFIG1_ADDRESSFILTERING_RESERVED 0x06
// RH_RF69_REG_3B_AUTOMODES
#define RH_RF69_AUTOMODE_ENTER_COND_NONE 0x00
#define RH_RF69_AUTOMODE_ENTER_COND_FIFO_NOT_EMPTY 0x20
#define RH_RF69_AUTOMODE_ENTER_COND_FIFO_LEVEL 0x40
#define RH_RF69_AUTOMODE_ENTER_COND_CRC_OK 0x60
#define RH_RF69_AUTOMODE_ENTER_COND_PAYLOAD_READY 0x80
#define RH_RF69_AUTOMODE_ENTER_COND_SYNC_ADDRESS 0xa0
#define RH_RF69_AUTOMODE_ENTER_COND_PACKET_SENT 0xc0
#define RH_RF69_AUTOMODE_ENTER_COND_FIFO_EMPTY 0xe0
#define RH_RF69_AUTOMODE_EXIT_COND_NONE 0x00
#define RH_RF69_AUTOMODE_EXIT_COND_FIFO_EMPTY 0x04
#define RH_RF69_AUTOMODE_EXIT_COND_FIFO_LEVEL 0x08
#define RH_RF69_AUTOMODE_EXIT_COND_CRC_OK 0x0c
#define RH_RF69_AUTOMODE_EXIT_COND_PAYLOAD_READY 0x10
#define RH_RF69_AUTOMODE_EXIT_COND_SYNC_ADDRESS 0x14
#define RH_RF69_AUTOMODE_EXIT_COND_PACKET_SENT 0x18
#define RH_RF69_AUTOMODE_EXIT_COND_TIMEOUT 0x1c
#define RH_RF69_AUTOMODE_INTERMEDIATE_MODE_SLEEP 0x00
#define RH_RF69_AUTOMODE_INTERMEDIATE_MODE_STDBY 0x01
#define RH_RF69_AUTOMODE_INTERMEDIATE_MODE_RX 0x02
#define RH_RF69_AUTOMODE_INTERMEDIATE_MODE_TX 0x03
// RH_RF69_REG_3C_FIFOTHRESH
#define RH_RF69_FIFOTHRESH_TXSTARTCONDITION_NOTEMPTY 0x80
#define RH_RF69_FIFOTHRESH_FIFOTHRESHOLD 0x7f
// RH_RF69_REG_3D_PACKETCONFIG2
#define RH_RF69_PACKETCONFIG2_INTERPACKETRXDELAY 0xf0
#define RH_RF69_PACKETCONFIG2_RESTARTRX 0x04
#define RH_RF69_PACKETCONFIG2_AUTORXRESTARTON 0x02
#define RH_RF69_PACKETCONFIG2_AESON 0x01
// RH_RF69_REG_4E_TEMP1
#define RH_RF69_TEMP1_TEMPMEASSTART 0x08
#define RH_RF69_TEMP1_TEMPMEASRUNNING 0x04
// RH_RF69_REG_5A_TESTPA1
#define RH_RF69_TESTPA1_NORMAL 0x55
#define RH_RF69_TESTPA1_BOOST 0x5d
// RH_RF69_REG_5C_TESTPA2
#define RH_RF69_TESTPA2_NORMAL 0x70
#define RH_RF69_TESTPA2_BOOST 0x7c
// RH_RF69_REG_6F_TESTDAGC
#define RH_RF69_TESTDAGC_CONTINUOUSDAGC_NORMAL 0x00
#define RH_RF69_TESTDAGC_CONTINUOUSDAGC_IMPROVED_LOWBETAON 0x20
#define RH_RF69_TESTDAGC_CONTINUOUSDAGC_IMPROVED_LOWBETAOFF 0x30
enum OpMode { DEFAULT, STDBY, TX, RX };
static enum OpMode mode = DEFAULT;
static power = 0;
static inline uint8_t read_reg(uint8_t reg)
{
SPI_PORT &= ~(1 << SPI_SS);
SPDR = reg & 0x7F;
while (!(SPSR & (1 << SPIF)))
;
SPDR = 0;
while (!(SPSR & (1 << SPIF)))
;
SPI_PORT |= (1 << SPI_SS);
return SPDR;
}
static inline void write_reg(uint8_t reg, uint8_t val)
{
SPI_PORT &= ~(1 << SPI_SS);
SPDR = reg | 0x80;
while (!(SPSR & (1 << SPIF)))
;
SPDR = val;
while (!(SPSR & (1 << SPIF)))
;
SPI_PORT |= (1 << SPI_SS);
}
static inline void set_mode(uint8_t m)
{
uint8_t opmode;
opmode = read_reg(RH_RF69_REG_01_OPMODE);
opmode &= ~RH_RF69_OPMODE_MODE;
opmode |= (m & RH_RF69_OPMODE_MODE);
write_reg(RH_RF69_REG_01_OPMODE, opmode);
while (!(read_reg(RH_RF69_REG_27_IRQFLAGS1)
& RH_RF69_IRQFLAGS1_MODEREADY))
;
}
static inline void set_mode_stdby(void)
{
if (mode != STDBY) {
if (power >= 18) {
write_reg(RH_RF69_REG_5A_TESTPA1, RH_RF69_TESTPA1_NORMAL);
write_reg(RH_RF69_REG_5C_TESTPA2, RH_RF69_TESTPA2_NORMAL);
}
set_mode(RH_RF69_OPMODE_MODE_STDBY);
mode = STDBY;
}
}
void radio_send(const char *data, uint8_t n)
{
uint8_t i;
write_reg(0x01, 0x04);
while (!(read_reg(0x27) & 0x80))
;
SPI_PORT &= ~(1 << SPI_SS);
SPDR = 0x00 | 0x80;
while (!(SPSR & (1 << SPIF)))
;
for (i = 0; i < n; i++) {
SPDR = data[i];
while (!(SPSR & (1 << SPIF)))
;
}
SPI_PORT |= (1 << SPI_SS);
// todo: high power settings?
write_reg(0x01, 0x0C);
while (!(read_reg(0x28) & 0x08))
;
write_reg(0x01, 0x04);
while (!(read_reg(0x27) & 0x80))
;
}
uint8_t radio_recv(char *buf, uint8_t n)
{
uint8_t read_len;
read_len = 0;
write_reg(0x01, 0x04);
while (!(read_reg(0x27) & 0x80))
;
SPI_PORT &= ~(1 << SPI_SS);
SPDR = 0x00 | 0x7F;
while (!(SPSR & (1 << SPIF)))
;
while (read_len < n) {
SPDR = 0;
while (!(SPSR & (1 << SPIF)))
;
buf[read_len++] = SPDR;
}
SPI_PORT |= (1 << SPI_SS);
return read_len;
}
void radio_listen(void)
{
write_reg(0x01, (read_reg(0x01) & 0xE3) | 0x10);
while (!(read_reg(0x27) & 0x80))
;
// todo: go to low power mode
}
void radio_init(const struct radio_cfg *cfg)
{
SPI_DDR |= (1 << SPI_SS) | (1 << SPI_SCK) | (1 << SPI_MOSI);
SPI_PORT |= (1 << SPI_SS);
SPCR |= (1 << SPE) | (1 << MSTR);
set_mode_stdby();
// LNA, AFC and RXBW settings
write_reg(0x18, 0x88);
write_reg(0x19, 0x55);
write_reg(0x1A, 0x8B);
// DIO mappings: IRQ on DIO0
write_reg(0x25, 0x40);
write_reg(0x26, 0x07);
// RSSI threshold
write_reg(0x29, 0xE4);
// sync config
write_reg(0x2E, 0x80);
write_reg(0x2F, cfg->netid);
// packet config
write_reg(0x37, 0x10);
write_reg(0x38, cfg->payload_len);
write_reg(0x39, cfg->nodeid);
// fifo config
write_reg(0x3C, 0x8F);
// DAGC config
write_reg(0x6F, 0x30);
}
|