-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathrc_rx.c
466 lines (367 loc) · 10.7 KB
/
rc_rx.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
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
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
#define MODULE_NAME RC_RX
#include <string.h>
#include <stdio.h>
#include "bsp.h"
#include "mcal.h"
#include "trace.h"
#include "cbuf.h"
//#define RC_RX_TEST 0
#define RX_POLL_PERIOD_US 25
#define TIME_TABLE_SIZE 256
#ifndef RC_RX_TEST
static tim_t *rcTim=0;
#endif
static volatile uint8_t time_table_length;
static volatile uint8_t time_table_idx;
static volatile uint8_t rcTxPin;
static volatile uint8_t rcRepeat;
static volatile uint8_t rcState;
static volatile uint8_t rcTxPinState = 0;
#define rx_fifo_SIZE 256
volatile struct {
uint16_t m_getIdx;
uint16_t m_putIdx;
uint16_t m_entry[rx_fifo_SIZE];
} rx_fifo;
#define RX_IDLE_TIME (50000 / RX_POLL_PERIOD_US)
static uint8_t prev_rx_pin_state = 0;
static uint16_t rx_pin_stable_count = RX_IDLE_TIME; // Start in idle state
#if RC_RX_TEST
static uint16_t test_idx = 0;
static int test_period_counter = 0;
static uint8_t test_pin_state = 0;
static void test_init(void)
{
test_period_counter = tx_time_table[0];
test_idx = 1;
test_pin_state = 1;
}
static uint8_t simulated_rc_pin(void)
{
if(test_period_counter <= 0) {
if(test_idx < tx_time_table_length) {
test_pin_state = !test_pin_state; // Toggle pin
test_period_counter = tx_time_table[test_idx];
test_idx++; // Advance to next period
} else {
test_pin_state = 0; // Idle low
}
} else {
test_period_counter-=RX_POLL_PERIOD_US;
}
return test_pin_state;
}
#define rx_rc_pin_get() simulated_rc_pin()
#else
#define rx_rc_pin_get() GPIO_read(BSP_433MHZ_RX) // GPIO_read(BSP_433MHZ_RX)
#endif
static uint32_t repeat_supress_tmr = 0;
static uint8_t rx_found_valid = 0;
#define DIG_FILTER_MAX 6
#define DIG_FILTER_VALUE_LOW 2
#define DIG_FILTER_VALUE_HIGH 4
static uint8_t dig_filter = 0;
static void timer_cb(void *ctx)
{
if(repeat_supress_tmr != 0) {
repeat_supress_tmr--;
}
uint8_t din = rx_rc_pin_get();
// If rx pin have not changed state
if(prev_rx_pin_state == din) {
// dont roll over
if(rx_pin_stable_count < RX_IDLE_TIME) {// If not in idle state
rx_pin_stable_count++;
/*
if(rx_pin_stable_count >= RX_IDLE_TIME) {// No activity for 50ms, become idle
if(!CBUF_IsFull(rx_fifo)) {
CBUF_Push(rx_fifo, 0); // Signal reset state machine
rx_found_valid = 0;
TTRACE(TTRACE_WARN, "rc_timer_cb: Return to idle\n");
} else {
TTRACE(TTRACE_WARN, "rc_timer_cb: FIFO full\n");
}
}
*/
}
} else { // Changed state
if(rx_pin_stable_count > 4) {
uint32_t us = 0;
if(rx_pin_stable_count < RX_IDLE_TIME) {
us = rx_pin_stable_count * RX_POLL_PERIOD_US;
}
CBUF_Push(rx_fifo, us);
prev_rx_pin_state = din; // Update prev pin state
rx_pin_stable_count = 0; // Reset stable counter
}
}
}
#define ANSLUT_PULSE_HIGH 250
#define ANSLUT_PULSE_ONE_LOW 250
#define ANSLUT_PULSE_ZERO_LOW 1450 //1250
#define ANSLUT_PULSE_SYNC_LOW 2750 //2500
#define ANSLUT_PULSE_PAUSE_LOW 10750
#define nexa_is_short_pulse(_usec) (_usec >= (ANSLUT_PULSE_HIGH-150) && _usec <= (ANSLUT_PULSE_HIGH+125))
#define nexa_is_long_pulse(_usec) (_usec > (ANSLUT_PULSE_ZERO_LOW-350) && _usec < (ANSLUT_PULSE_ZERO_LOW+350))
#define bm_add_bit(bm, b) bm = (bm << 1) | ((b) != 0)
#define bm_get_bit(bm, b) ((bm & (1 << b)) != 0)
typedef struct
{
uint8_t state;
uint16_t hl;
uint16_t ll;
uint32_t data;
uint32_t correct_decodes;
uint16_t sync_len;
} ev1527_t;
static int ev1527_decode(ev1527_t *self, uint16_t pw, char *s, int sl, uint32_t min_sync_len, uint32_t short_long_delimiter)
{
int res = 0;
if(pw < 100 || pw > 30000) {
if(self->state != 0) {
TTRACE(TTRACE_INFO, "EV1527: Wrong pulse length %dus, resetting to idle state from state %d\n", pw, self->state);
}
self->state = 0;
GPIO_write(BSP_LED_RX, 1);
} else if(pw > min_sync_len && pw < (min_sync_len+3000)) {
self->sync_len = pw;
self->data = 0;
self->state = 2;
self->hl = self->ll = 0;
} else if(self->state >= 2) {
if(pw > short_long_delimiter*2) {
if(self->state > 2) {
TTRACE(TTRACE_INFO, "EV1527: To long data pulse %dus in state %d\n", pw, self->state);
}
self->state = 0;
GPIO_write(BSP_LED_RX, 1);
} else {
if(self->state == 2) {
TTRACE(TTRACE_INFO, "EV1527: Sync + first pulse received, sync pw=%d\n", self->sync_len);
}
if(self->state & 1) {
bm_add_bit(self->data, pw > short_long_delimiter);
}
if(pw > short_long_delimiter) {
self->hl += pw;
} else {
self->ll += pw;
}
self->state++;
// Light up RX led if at least some bits are received
if(self->state == 24) {
GPIO_write(BSP_LED_RX, 0);
}
else if(self->state >= (24*2)+2) {
self->correct_decodes++;
TTRACE(TTRACE_INFO, "EV1527: 0x%x lo %d, high %d, n: %d\n", self->data, self->ll, self->hl, self->correct_decodes);
snprintf(s, sl, "EV1527: %lu",self->data);
self->hl /= 24;
self->ll /= 24; // Take average
res = 1;
GPIO_write(BSP_LED_RX, 1);
self->state = 0;
}
}
}
return res;
}
static uint8_t nexa_state=0;
static uint32_t nexa_data=0;
static int nexa_decode(uint16_t pw, char *s, int sl)
{
int res = 0;
if(pw == 0) {
nexa_state = 0;
} else if(pw < 2900 && pw > 2300 ) {// Sync low
nexa_data = 0;
nexa_state = 4;
} else if(nexa_state >= 4) {
if((nexa_state & 1) == 0) {
if(nexa_is_short_pulse(pw) == 0) {
nexa_state = 0; // High pulse expected to be short
}
} else if((nexa_state & 3) == 1) {
bm_add_bit(nexa_data, nexa_is_long_pulse(pw));
} else {
if(bm_get_bit(nexa_data, 0) != nexa_is_short_pulse(pw)) { // If long low pulse where detected (1) in state&3=1, expect this to be short
nexa_state = 0;
}
}
nexa_state++;
if(nexa_state >= (128+4)) {
TTRACE(TTRACE_INFO, "NEXA: 0x%x\n", nexa_data);
TTRACE(TTRACE_INFO, "NEXA: house code 0x%x, unit %d, cmd: %d, channel: %d\n",
nexa_data >> 6, nexa_data & 3, (nexa_data>>4) & 3, (nexa_data>>2) & 3);
snprintf(s, sl, "NEXA: %lu",nexa_data);
res = 1;
nexa_state = 0;
}
}
return res;
}
/*
From:
https://forum.pilight.org/Thread-Elro-Flamingo-FA20RF-Smoke-detector
Test Button press 1
--[RESULTS]--
hardware: 433gpio
pulse: 3
rawlen: 52
binlen: 13
pulselen: 393
Raw code:
8253 786 786 1572 786 2751 786 2751 786 2751 786 1572 786 1572 786 1572 786 2751 786 2751 786 1572 786 2751 786 2751
786 2751 786 1572 786 1572 786 2751 786 2751 786 1572 786 2751 786 2751 786 1572 786 2751 786 2751 786 1179 786 13362
Binary code:
1111111111111
Test Button press 2
--[RESULTS]--
hardware: 433gpio
pulse: 4
rawlen: 52
binlen: 13
pulselen: 393
Raw code:
8253 786 786 1572 786 2751 786 2751 786 2751 786 1572 786 1572 786 1572 786 2751 786 2751 786 1572 786 2751 786 2751
786 2751 786 1572 786 1572 786 2751 786 2751 786 1572 786 2751 786 2751 786 1572 786 2751 786 2751 786 1572 786 13362
Binary code:
1111111111111
Smoke Alert
--[RESULTS]--
hardware: 433gpio
pulse: 2
rawlen: 52
binlen: 13
pulselen: 391
Raw code:
8211 782 782 1564 782 2737 782 2737 782 2737 782 1564 782 1564 782 1564 782 2737 782 2737 782 1564 782 2737 782 2737
782 2737 782 1564 782 1564 782 2737 782 2737 782 1564 782 2737 782 2737 782 1564 782 2737 782 2737 782 1564 782 13294
*/
static uint8_t fl_state=0;
static uint32_t fl_data=0;
static int flamingo_decode(uint16_t pw, char *s, int sl)
{
int res = 0;
if(pw == 0) {
fl_state = 0;
} else if(pw < 9000 && pw > 7000 ) {// Sync
fl_data = 0;
fl_state = 2;
} else if(fl_state >= 2) {
if(pw >= 1200 && pw <= 1500) {
fl_data <<= 1;
} else if(pw >= 2400 && pw <= 2900) {
fl_data = (fl_data << 1) | 1;
}
fl_state++;
if(fl_state >= (50+2)) {
TTRACE(TTRACE_INFO, "FLAMINGO: 0x%x\n", fl_data);
snprintf(s, sl, "FLAMINGO: %lu",fl_data);
res = 1;
fl_state = 0;
}
}
return res;
}
#define DBG_MAX_PULSES 64
static uint8_t dbg_state=0;
static uint16_t dbg_pulses[DBG_MAX_PULSES];
static uint16_t dbg_longest = 0;
static uint16_t dbg_shortest = 65535;
static int debug_decode(uint16_t pw, char *s, int sl)
{
int res = 0;
if(pw > dbg_longest) {
dbg_longest = pw;
}
if(pw < dbg_shortest) {
dbg_shortest = pw;
}
// If a sync or reset
if(pw > 2000 || pw == 0) {
// If at least this many pulses received
if(dbg_state > 24) {
// Print pulse times all pulses
int o = snprintf(s, sl, "DBG: ");
for(int n = 0; n < dbg_state && sl > o; n++) {
o+= snprintf(s+o, sl-o, "%u,", dbg_pulses[n]);
}
// Indicate data received
res = 1;
}
// If reset set state to 0 otherwise start receiving
dbg_state = (pw == 0) ? 0 : 1;
}
// If not in reset state
if(dbg_state > 0) {
// Store pulse length
if(dbg_state <= DBG_MAX_PULSES) {
dbg_pulses[dbg_state-1] = pw;
}
dbg_state++;
}
return res;
}
static ev1527_t ev1527_slow, ev1527_fast;
void rc_start_rx(void)
{
rx_pin_stable_count = 0;
time_table_idx = 0;
prev_rx_pin_state = 0;
}
// Previously decoded string
static char decs_prev[128] = {0};
static void rc_publish_if_no_repeat(char *decs)
{
// If decode string is different or repeat suppress timer count down to zero
if(strcmp(decs_prev, decs_prev) != 0 || repeat_supress_tmr == 0) {
strcpy(decs_prev, decs);
repeat_supress_tmr = 1000000 / RX_POLL_PERIOD_US;
}
}
static char debug_s[256];
void rc_rx_poll(void)
{
int res;
char decs[128];
while(!CBUF_IsEmpty(rx_fifo)) {
uint16_t pw = CBUF_Pop(rx_fifo);
// EV1527 with slow timing
/*
res = ev1527_decode(&ev1527_slow, pw, decs, sizeof(decs), 13000, 950);
if(res) {
TTRACE(TTRACE_INFO, "RC_PARSE: Found EV1527 slow rc string %s\n", decs);
rc_publish_if_no_repeat(decs);
}
// EV1527 with fast timing
res = ev1527_decode(&ev1527_fast, pw, decs, sizeof(decs), 6000, 450);
if(res) {
TTRACE(TTRACE_INFO, "RC_PARSE: Found EV1527 fast rc string %s\n", decs);
rc_publish_if_no_repeat(decs);
}
res = nexa_decode(pw, decs, sizeof(decs));
if(res) {
rc_publish_if_no_repeat(decs);
}
res = flamingo_decode(pw, decs, sizeof(decs));
if(res) {
rc_publish_if_no_repeat(decs);
}
*/
res = debug_decode(pw, debug_s, sizeof(debug_s));
if(res) {
TTRACE(TTRACE_INFO, "%s\n", debug_s);
}
}
}
void rc_rx_init(void)
{
TTRACE(TTRACE_INFO, "RC_RX init\n");
CBUF_Init(rx_fifo);
rcTim = TIM_create(BSP_RC_TIMER);
TIM_configure(rcTim, 1000000, RX_POLL_PERIOD_US);
TIM_setOverFlowCallback(rcTim, timer_cb, 0);
TIM_start(rcTim);
rc_start_rx();
}