-
Notifications
You must be signed in to change notification settings - Fork 38
/
radio.c
393 lines (325 loc) · 9.87 KB
/
radio.c
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
#include <stdint.h>
#include <string.h>
#include "hardware.h"
#include "serial.h"
#include "commands.h"
#include "timer.h"
#include "encoding.h"
#include "fifo.h"
#include "statistics.h"
#include "radio.h"
#define RX_FIFO_SIZE 32
#define TX_BUF_SIZE 255
static volatile uint8_t __xdata radio_rx_buf[RX_FIFO_SIZE];
static fifo_buffer __xdata rx_fifo;
static volatile uint8_t rx_len;
static volatile uint8_t __xdata radio_tx_buf[TX_BUF_SIZE];
static volatile uint8_t __xdata radio_tx_buf_read_idx;
static volatile uint8_t __xdata radio_tx_buf_len;
static volatile uint16_t __xdata preamble_word;
static volatile uint8_t stop_custom_preamble_semaphore;
// TX States
enum TxState {
TxStatePreambleByte0 = 0x00,
TxStatePreambleByte1 = 0x01,
TxStatePreambleDefault = 0x02,
TxStateSync0 = 0x03,
TxStateSync1 = 0x04,
TxStateData = 0x05,
TxStateDone = 0x06,
};
volatile enum TxState tx_state;
EncodingType encoding_type = EncodingTypeNone;
void configure_radio()
{
/* RF settings SoC: CC1110 */
SYNC1 = 0xFF; // sync word, high byte
SYNC0 = 0x00; // sync word, low byte
PKTLEN = 0xFF; // packet length
PKTCTRL1 = 0x00; // packet automation control
PKTCTRL0 = 0x00; // packet automation control
ADDR = 0x00;
// CHANNR: See the locale-specific section below
FSCTRL1 = 0x06; // frequency synthesizer control
FSCTRL0 = 0x00;
// FREQ0/FREQ1/FREQ2: See the locale-specific section below
MDMCFG4 = 0x99; // 150.5 kHz rx filter bandwidth. Narrower can improve range,
// but then freq must be dialed in more tightly, which does not
// allow for variation we see with pump in free space vs on body.
MDMCFG3 = 0x66; // modem configuration
MDMCFG2 = 0x33; // modem configuration
MDMCFG1 = 0x61; // modem configuration
MDMCFG0 = 0x7E; // modem configuration
DEVIATN = 0x15; // modem deviation setting
MCSM2 = 0x07;
MCSM1 = 0x30;
MCSM0 = 0x18; // main radio control state machine configuration
FOCCFG = 0x17; // frequency offset compensation configuration
BSCFG = 0x6C; // bit synchronization configuration
FREND1 = 0xB6; // front end tx configuration
FREND0 = 0x11; // front end tx configuration
FSCAL3 = 0xE9; // frequency synthesizer calibration
FSCAL2 = 0x2A; // frequency synthesizer calibration
FSCAL1 = 0x00; // frequency synthesizer calibration
FSCAL0 = 0x1F; // frequency synthesizer calibration
TEST1 = 0x31; // various test settings
TEST0 = 0x09; // various test settings
PA_TABLE0 = 0x00; // needs to be explicitly set!
// PA_TABLE1: See the locale-specific section below
AGCCTRL2 = 0x07; // 0x03 to 0x07 - default: 0x03
AGCCTRL1 = 0x00; // 0x00 - default: 0x40
AGCCTRL0 = 0x91; // 0x91 or 0x92 - default: 0x91
#if US_RADIO_LOCALE
FREQ2 = 0x26; // 916.541MHz is midpoint between freq of pump in free space,
FREQ1 = 0x30; // and pump held close to the body.
FREQ0 = 0x70; //
CHANNR = 0x02; // channel number
PA_TABLE1 = 0xC0; // pa power setting 10 dBm
#else
FREQ2 = 0x24; // frequency control word, high byte
FREQ1 = 0x2E; // frequency control word, middle byte
FREQ0 = 0x38; // frequency control word, low byte
CHANNR = 0x00; // channel number
PA_TABLE1 = 0xC2; // Max configurable power output at this frequency is 0xC2
#endif
IEN2 |= IEN2_RFIE;
RFTXRXIE = 1;
fifo_init(&rx_fifo, radio_rx_buf, RX_FIFO_SIZE);
}
// Set software based encoding
bool set_encoding_type(EncodingType new_type) {
if (new_type <= MaxEncodingTypeValue) {
encoding_type = new_type;
return true;
} else {
return false;
}
}
inline void put_rx(uint8_t data) {
if (!fifo_put(&rx_fifo, data)) {
radio_rx_fifo_overflow_count++;
}
}
void rftxrx_isr(void) __interrupt RFTXRX_VECTOR {
uint8_t d_byte;
if (MARCSTATE==MARC_STATE_RX) {
d_byte = RFD;
if (rx_len == 0) {
put_rx(RSSI);
put_rx(packet_rx_count & 0xff);
rx_len = 2;
}
put_rx(d_byte);
rx_len++;
}
else if (MARCSTATE==MARC_STATE_TX) {
switch (tx_state) {
case TxStatePreambleByte0:
RFD = preamble_word >> 8;
tx_state = TxStatePreambleByte1;
break;
case TxStatePreambleByte1:
RFD = preamble_word & 0xff;
if (stop_custom_preamble_semaphore) {
tx_state = TxStateSync1;
} else {
tx_state = TxStatePreambleByte0;
}
break;
case TxStateSync1:
RFD = SYNC1;
tx_state = TxStateSync0;
break;
case TxStateSync0:
RFD = SYNC0;
tx_state = TxStateData;
break;
case TxStateData:
RFD = radio_tx_buf[radio_tx_buf_read_idx++];
if (radio_tx_buf_read_idx >= radio_tx_buf_len) {
tx_state = TxStateDone;
}
break;
case TxStateDone:
// Letting RFD go empty will make the radio stop TX mode.
//RFD = 0;
break;
case TxStatePreambleDefault:
break;
}
}
}
void rf_isr(void) __interrupt RF_VECTOR {
S1CON &= ~0x03; // Clear CPU interrupt flag
if(RFIF & 0x80) // TX underflow
{
// Underflow
RFST = RFST_SIDLE;
RFIF &= ~0x80; // Clear module interrupt flag
}
else if(RFIF & 0x40) // RX overflow
{
radio_rx_overflow_count++;
RFIF &= ~0x40; // Clear module interrupt flag
}
else if(RFIF & 0x20) // RX timeout
{
RFIF &= ~0x20; // Clear module interrupt flag
}
// Use ”else if” to check and handle other RFIF flags
}
void send_packet_from_serial(uint8_t channel, uint8_t repeat_count, uint16_t delay_ms, uint16_t preamble_extend_ms, uint8_t len) {
uint8_t s_byte;
uint16_t send_count = 0;
uint16_t total_send_count = repeat_count + 1;
Encoder encoder;
EncoderState encoder_state;
init_encoder(encoding_type, &encoder, &encoder_state);
mode_registers_enact(&tx_registers);
CHANNR = channel;
radio_tx_buf_len = 0;
while (len > 0) {
s_byte = serial_rx_byte();
len--;
encoder.add_raw_byte(&encoder_state, s_byte);
while (encoder.next_encoded_byte(&encoder_state, &s_byte, len == 0)) {
if (radio_tx_buf_len+1 < TX_BUF_SIZE) {
radio_tx_buf[radio_tx_buf_len++] = s_byte;
}
}
}
while(send_count < total_send_count) {
// delay
if (send_count > 0 && delay_ms > 0) {
delay(delay_ms);
}
feed_watchdog();
send_from_tx_buf(channel, preamble_extend_ms);
send_count++;
}
}
void send_from_tx_buf(uint8_t channel, uint16_t preamble_extend_ms) {
uint8_t pktlen_save;
uint8_t mdmcfg2_save;
uint8_t pktctrl0_save;
mdmcfg2_save = MDMCFG2;
pktlen_save = PKTLEN;
pktctrl0_save = PKTCTRL0;
packet_tx_count++;
if (preamble_word != 0) {
// save and turn off preamble/sync registers
MDMCFG2 &= 0b11111100; // Disable PREAMBLE/SYNC
PKTCTRL0 = (PKTCTRL0 & ~0b11) | 0b10; // Enter "infinite" tx mode
PKTLEN = 0;
stop_custom_preamble_semaphore = 0;
tx_state = TxStatePreambleByte0;
} else {
if (preamble_extend_ms) {
tx_state = TxStatePreambleDefault;
} else {
tx_state = TxStateData;
}
PKTLEN = radio_tx_buf_len;
}
RFST = RFST_SIDLE;
while(MARCSTATE!=MARC_STATE_IDLE);
CHANNR = channel;
radio_tx_buf_read_idx = 0;
// Turn on radio (interrupts will start again)
RFST = RFST_STX;
while(MARCSTATE!=MARC_STATE_TX);
if (preamble_extend_ms > 0) {
delay(preamble_extend_ms);
if(preamble_word==0) {
tx_state = TxStateData;
TCON |= 0b10; // Manually trigger RFTXRX vector.
}
}
if (preamble_word != 0) {
stop_custom_preamble_semaphore = 1;
}
// wait for sending to finish
while(MARCSTATE==MARC_STATE_TX);
if (MARCSTATE==MARC_STATE_TX_UNDERFLOW) {
RFST = RFST_SIDLE;
}
PKTLEN = pktlen_save;
MDMCFG2 = mdmcfg2_save;
PKTCTRL0 = pktctrl0_save;
}
uint8_t get_packet_and_write_to_serial(uint8_t channel, uint32_t timeout_ms, uint8_t use_pktlen) {
uint8_t read_idx = 0;
uint8_t d_byte = 0;
uint8_t rval = 0;
uint8_t encoding_error = 0;
uint32_t timer_start;
Decoder __xdata decoder;
DecoderState __xdata decoder_state;
if (timeout_ms > 0) {
read_timer(&timer_start);
}
mode_registers_enact(&rx_registers);
init_decoder(encoding_type, &decoder, &decoder_state);
RFST = RFST_SIDLE;
while(MARCSTATE!=MARC_STATE_IDLE);
CHANNR = channel;
rx_len = 0;
memset((void*)radio_rx_buf, 0x11, RX_FIFO_SIZE);
RFST = RFST_SRX;
while(MARCSTATE!=MARC_STATE_RX);
while(1) {
feed_watchdog();
// Waiting for isr to put radio bytes into rx_fifo
if (!fifo_empty(&rx_fifo)) {
d_byte = fifo_get(&rx_fifo);
read_idx++;
// Send status code
if (read_idx == 1) {
led_set_diagnostic(BlueLED, LEDStateOn);
serial_tx_byte(RESPONSE_CODE_SUCCESS);
}
// First two bytes are rssi and packet #
if (read_idx < 3) {
serial_tx_byte(d_byte);
} else {
encoding_error = decoder.add_encoded_byte(&decoder_state, d_byte);
while (decoder.next_decoded_byte(&decoder_state, &d_byte)) {
serial_tx_byte(d_byte);
}
}
if (encoding_error) {
break;
}
// Check for end of packet
if (use_pktlen && read_idx == PKTLEN) {
break;
}
}
if (timeout_ms > 0 && check_elapsed(timer_start, timeout_ms)) {
rval = RESPONSE_CODE_RX_TIMEOUT;
break;
}
// Also going to watch serial in case the client wants to interrupt rx
if (SERIAL_DATA_AVAILABLE) {
// Received a byte from uart while waiting for radio packet
// We will interrupt the RX and go handle the command.
interrupting_cmd = serial_rx_byte();
rval = RESPONSE_CODE_CMD_INTERRUPTED;
break;
}
}
RFST = RFST_SIDLE;
while(MARCSTATE!=MARC_STATE_IDLE);
while(!fifo_empty(&rx_fifo)) {
fifo_get(&rx_fifo);
}
if (rval == 0) {
packet_rx_count++;
}
led_set_diagnostic(BlueLED, LEDStateOff);
return rval;
}
// Set software based preamble, 0 = disable
void radio_set_preamble(uint16_t p) {
preamble_word = p;
}