1 /** @file
2 Pulse detection functions.
3
4 Copyright (C) 2015 Tommy Vestermark
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 */
11
12 #include "pulse_detect.h"
13 #include "rfraw.h"
14 #include "pulse_demod.h"
15 #include "pulse_detect_fsk.h"
16 #include "baseband.h"
17 #include "util.h"
18 #include "r_device.h"
19 #include "r_util.h"
20 #include "fatal.h"
21 #include <limits.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25
pulse_data_clear(pulse_data_t * data)26 void pulse_data_clear(pulse_data_t *data)
27 {
28 *data = (pulse_data_t const){0};
29 }
30
pulse_data_shift(pulse_data_t * data)31 void pulse_data_shift(pulse_data_t *data)
32 {
33 int offs = PD_MAX_PULSES / 2; // shift out half the data
34 memmove(data->pulse, &data->pulse[offs], (PD_MAX_PULSES - offs) * sizeof(*data->pulse));
35 memmove(data->gap, &data->gap[offs], (PD_MAX_PULSES - offs) * sizeof(*data->gap));
36 data->num_pulses -= offs;
37 data->offset += offs;
38 }
39
pulse_data_print(pulse_data_t const * data)40 void pulse_data_print(pulse_data_t const *data)
41 {
42 fprintf(stderr, "Pulse data: %u pulses\n", data->num_pulses);
43 for (unsigned n = 0; n < data->num_pulses; ++n) {
44 fprintf(stderr, "[%3u] Pulse: %4d, Gap: %4d, Period: %4d\n", n, data->pulse[n], data->gap[n], data->pulse[n] + data->gap[n]);
45 }
46 }
47
bounded_memset(void * b,int c,int64_t size,int64_t offset,int64_t len)48 static void *bounded_memset(void *b, int c, int64_t size, int64_t offset, int64_t len)
49 {
50 if (offset < 0) {
51 len += offset; // reduce len by negative offset
52 offset = 0;
53 }
54 if (offset + len > size) {
55 len = size - offset; // clip excessive len
56 }
57 if (len > 0)
58 memset((char *)b + offset, c, (size_t)len);
59 return b;
60 }
61
pulse_data_dump_raw(uint8_t * buf,unsigned len,uint64_t buf_offset,pulse_data_t const * data,uint8_t bits)62 void pulse_data_dump_raw(uint8_t *buf, unsigned len, uint64_t buf_offset, pulse_data_t const *data, uint8_t bits)
63 {
64 int64_t pos = data->offset - buf_offset;
65 for (unsigned n = 0; n < data->num_pulses; ++n) {
66 bounded_memset(buf, 0x01 | bits, len, pos, data->pulse[n]);
67 pos += data->pulse[n];
68 bounded_memset(buf, 0x01, len, pos, data->gap[n]);
69 pos += data->gap[n];
70 }
71 }
72
chk_ret(int ret)73 static inline void chk_ret(int ret)
74 {
75 if (ret < 0) {
76 perror("File output error");
77 exit(1);
78 }
79 }
80
pulse_data_print_vcd_header(FILE * file,uint32_t sample_rate)81 void pulse_data_print_vcd_header(FILE *file, uint32_t sample_rate)
82 {
83 char time_str[LOCAL_TIME_BUFLEN];
84 char *timescale;
85 if (sample_rate <= 500000)
86 timescale = "1 us";
87 else
88 timescale = "100 ns";
89 chk_ret(fprintf(file, "$date %s $end\n", format_time_str(time_str, NULL, 0, 0)));
90 chk_ret(fprintf(file, "$version rtl_433 0.1.0 $end\n"));
91 chk_ret(fprintf(file, "$comment Acquisition at %s Hz $end\n", nice_freq(sample_rate)));
92 chk_ret(fprintf(file, "$timescale %s $end\n", timescale));
93 chk_ret(fprintf(file, "$scope module rtl_433 $end\n"));
94 chk_ret(fprintf(file, "$var wire 1 / FRAME $end\n"));
95 chk_ret(fprintf(file, "$var wire 1 ' AM $end\n"));
96 chk_ret(fprintf(file, "$var wire 1 \" FM $end\n"));
97 chk_ret(fprintf(file, "$upscope $end\n"));
98 chk_ret(fprintf(file, "$enddefinitions $end\n"));
99 chk_ret(fprintf(file, "#0 0/ 0' 0\"\n"));
100 }
101
pulse_data_print_vcd(FILE * file,pulse_data_t const * data,int ch_id)102 void pulse_data_print_vcd(FILE *file, pulse_data_t const *data, int ch_id)
103 {
104 float scale;
105 if (data->sample_rate <= 500000)
106 scale = 1000000 / data->sample_rate; // unit: 1 us
107 else
108 scale = 10000000 / data->sample_rate; // unit: 100 ns
109 uint64_t pos = data->offset;
110 for (unsigned n = 0; n < data->num_pulses; ++n) {
111 if (n == 0)
112 chk_ret(fprintf(file, "#%.f 1/ 1%c\n", pos * scale, ch_id));
113 else
114 chk_ret(fprintf(file, "#%.f 1%c\n", pos * scale, ch_id));
115 pos += data->pulse[n];
116 chk_ret(fprintf(file, "#%.f 0%c\n", pos * scale, ch_id));
117 pos += data->gap[n];
118 }
119 if (data->num_pulses > 0)
120 chk_ret(fprintf(file, "#%.f 0/\n", pos * scale));
121 }
122
pulse_data_load(FILE * file,pulse_data_t * data,uint32_t sample_rate)123 void pulse_data_load(FILE *file, pulse_data_t *data, uint32_t sample_rate)
124 {
125 char s[1024];
126 int i = 0;
127 int size = sizeof(data->pulse) / sizeof(*data->pulse);
128
129 pulse_data_clear(data);
130 data->sample_rate = sample_rate;
131 double to_sample = sample_rate / 1e6;
132 // read line-by-line
133 while (i < size && fgets(s, sizeof(s), file)) {
134 // TODO: we should parse sample rate and timescale
135 if (!strncmp(s, ";freq1", 6)) {
136 data->freq1_hz = strtol(s + 6, NULL, 10);
137 }
138 if (!strncmp(s, ";freq2", 6)) {
139 data->freq2_hz = strtol(s + 6, NULL, 10);
140 }
141 if (*s == ';') {
142 if (i) {
143 break; // end or next header found
144 }
145 else {
146 continue; // still reading a header
147 }
148 }
149 if (rfraw_check(s)) {
150 rfraw_parse(data, s);
151 i = data->num_pulses;
152 continue;
153 }
154 // parse two ints.
155 char *p = s;
156 char *endptr;
157 long mark = strtol(p, &endptr, 10);
158 p = endptr + 1;
159 long space = strtol(p, &endptr, 10);
160 //fprintf(stderr, "read: mark %ld space %ld\n", mark, space);
161 data->pulse[i] = (int)(to_sample * mark);
162 data->gap[i++] = (int)(to_sample * space);
163 }
164 //fprintf(stderr, "read %d pulses\n", i);
165 data->num_pulses = i;
166 }
167
pulse_data_print_pulse_header(FILE * file)168 void pulse_data_print_pulse_header(FILE *file)
169 {
170 char time_str[LOCAL_TIME_BUFLEN];
171
172 chk_ret(fprintf(file, ";pulse data\n"));
173 chk_ret(fprintf(file, ";version 1\n"));
174 chk_ret(fprintf(file, ";timescale 1us\n"));
175 //chk_ret(fprintf(file, ";samplerate %u\n", data->sample_rate));
176 chk_ret(fprintf(file, ";created %s\n", format_time_str(time_str, NULL, 1, 0)));
177 }
178
pulse_data_dump(FILE * file,pulse_data_t * data)179 void pulse_data_dump(FILE *file, pulse_data_t *data)
180 {
181 if (data->fsk_f2_est) {
182 chk_ret(fprintf(file, ";fsk %u pulses\n", data->num_pulses));
183 chk_ret(fprintf(file, ";freq1 %.0f\n", data->freq1_hz));
184 chk_ret(fprintf(file, ";freq2 %.0f\n", data->freq2_hz));
185 }
186 else {
187 chk_ret(fprintf(file, ";ook %u pulses\n", data->num_pulses));
188 chk_ret(fprintf(file, ";freq1 %.0f\n", data->freq1_hz));
189 }
190 chk_ret(fprintf(file, ";centerfreq %.0f Hz\n", data->centerfreq_hz));
191 chk_ret(fprintf(file, ";samplerate %u Hz\n", data->sample_rate));
192 chk_ret(fprintf(file, ";sampledepth %u bits\n", data->depth_bits));
193 chk_ret(fprintf(file, ";range %.1f dB\n", data->range_db));
194 chk_ret(fprintf(file, ";rssi %.1f dB\n", data->rssi_db));
195 chk_ret(fprintf(file, ";snr %.1f dB\n", data->snr_db));
196 chk_ret(fprintf(file, ";noise %.1f dB\n", data->noise_db));
197
198 double to_us = 1e6 / data->sample_rate;
199 for (unsigned i = 0; i < data->num_pulses; ++i) {
200 chk_ret(fprintf(file, "%.0f %.0f\n", data->pulse[i] * to_us, data->gap[i] * to_us));
201 }
202 chk_ret(fprintf(file, ";end\n"));
203 }
204
pulse_data_print_data(pulse_data_t * data)205 data_t *pulse_data_print_data(pulse_data_t *data)
206 {
207 int pulses[2 * PD_MAX_PULSES];
208 double to_us = 1e6 / data->sample_rate;
209 for (unsigned i = 0; i < data->num_pulses; ++i) {
210 pulses[i * 2 + 0] = data->pulse[i] * to_us;
211 pulses[i * 2 + 1] = data->gap[i] * to_us;
212 }
213
214 /* clang-format off */
215 return data_make(
216 "mod", "", DATA_STRING, (data->fsk_f2_est) ? "FSK" : "OOK",
217 "count", "", DATA_INT, data->num_pulses,
218 "pulses", "", DATA_ARRAY, data_array(2 * data->num_pulses, DATA_INT, pulses),
219 "freq1_Hz", "", DATA_FORMAT, "%u Hz", DATA_INT, (unsigned)data->freq1_hz,
220 "freq2_Hz", "", DATA_COND, data->fsk_f2_est, DATA_FORMAT, "%u Hz", DATA_INT, (unsigned)data->freq2_hz,
221 "freq_Hz", "", DATA_INT, (unsigned)data->centerfreq_hz,
222 "rate_Hz", "", DATA_INT, data->sample_rate,
223 "depth_bits", "", DATA_INT, data->depth_bits,
224 "range_dB", "", DATA_FORMAT, "%.1f dB", DATA_DOUBLE, data->range_db,
225 "rssi_dB", "", DATA_FORMAT, "%.1f dB", DATA_DOUBLE, data->rssi_db,
226 "snr_dB", "", DATA_FORMAT, "%.1f dB", DATA_DOUBLE, data->snr_db,
227 "noise_dB", "", DATA_FORMAT, "%.1f dB", DATA_DOUBLE, data->noise_db,
228 NULL);
229 /* clang-format on */
230 }
231
232 // OOK adaptive level estimator constants
233 #define OOK_MAX_HIGH_LEVEL DB_TO_AMP(0) // Maximum estimate for high level (-0 dB)
234 #define OOK_MAX_LOW_LEVEL DB_TO_AMP(-15) // Maximum estimate for low level
235 #define OOK_EST_HIGH_RATIO 64 // Constant for slowness of OOK high level estimator
236 #define OOK_EST_LOW_RATIO 1024 // Constant for slowness of OOK low level (noise) estimator (very slow)
237
238 /// Internal state data for pulse_pulse_package()
239 struct pulse_detect {
240 int use_mag_est; ///< Whether the envelope data is an amplitude or magnitude.
241 int ook_fixed_high_level; ///< Manual detection level override, 0 = auto.
242 int ook_min_high_level; ///< Minimum estimate of high level (-12 dB: 1000 amp, 4000 mag).
243 int ook_high_low_ratio; ///< Default ratio between high and low (noise) level (9 dB: x8 amp, 11 dB: x3.6 mag).
244
245 enum {
246 PD_OOK_STATE_IDLE = 0,
247 PD_OOK_STATE_PULSE = 1,
248 PD_OOK_STATE_GAP_START = 2,
249 PD_OOK_STATE_GAP = 3
250 } ook_state;
251 int pulse_length; ///< Counter for internal pulse detection
252 int max_pulse; ///< Size of biggest pulse detected
253
254 int data_counter; ///< Counter for how much of data chunk is processed
255 int lead_in_counter; ///< Counter for allowing initial noise estimate to settle
256
257 int ook_low_estimate; ///< Estimate for the OOK low level (base noise level) in the envelope data
258 int ook_high_estimate; ///< Estimate for the OOK high level
259
260 int verbosity; ///< Debug output verbosity, 0=None, 1=Levels, 2=Histograms
261
262 pulse_FSK_state_t FSK_state;
263 };
264
pulse_detect_create()265 pulse_detect_t *pulse_detect_create()
266 {
267 pulse_detect_t *pulse_detect = calloc(1, sizeof(pulse_detect_t));
268 if (!pulse_detect) {
269 WARN_CALLOC("pulse_detect_create()");
270 return NULL;
271 }
272
273 pulse_detect_set_levels(pulse_detect, 0, 0.0, -12.1442, 9.0, 0);
274
275 return pulse_detect;
276 }
277
pulse_detect_free(pulse_detect_t * pulse_detect)278 void pulse_detect_free(pulse_detect_t *pulse_detect)
279 {
280 free(pulse_detect);
281 }
282
pulse_detect_set_levels(pulse_detect_t * pulse_detect,int use_mag_est,float fixed_high_level,float min_high_level,float high_low_ratio,int verbosity)283 void pulse_detect_set_levels(pulse_detect_t *pulse_detect, int use_mag_est, float fixed_high_level, float min_high_level, float high_low_ratio, int verbosity)
284 {
285 pulse_detect->use_mag_est = use_mag_est;
286 if (use_mag_est) {
287 pulse_detect->ook_fixed_high_level = fixed_high_level < 0.0 ? DB_TO_MAG(fixed_high_level) : 0;
288 pulse_detect->ook_min_high_level = DB_TO_MAG(min_high_level);
289 pulse_detect->ook_high_low_ratio = DB_TO_MAG_F(high_low_ratio);
290 }
291 else { // amp est
292 pulse_detect->ook_fixed_high_level = fixed_high_level < 0.0 ? DB_TO_AMP(fixed_high_level) : 0;
293 pulse_detect->ook_min_high_level = DB_TO_AMP(min_high_level);
294 pulse_detect->ook_high_low_ratio = DB_TO_AMP_F(high_low_ratio);
295 }
296 pulse_detect->verbosity = verbosity;
297
298 //fprintf(stderr, "fixed_high_level %.1f (%d), min_high_level %.1f (%d), high_low_ratio %.1f (%d)\n",
299 // fixed_high_level, pulse_detect->ook_fixed_high_level,
300 // min_high_level, pulse_detect->ook_min_high_level,
301 // high_low_ratio, pulse_detect->ook_high_low_ratio);
302 }
303
304 /// convert amplitude (16384 FS) to attenuation in (integer) dB, offset by 3.
amp_to_att(int a)305 static inline int amp_to_att(int a)
306 {
307 if (a > 32690) return 0; // = 10^(( 3 + 42.1442) / 10)
308 if (a > 25967) return 1; // = 10^(( 2 + 42.1442) / 10)
309 if (a > 20626) return 2; // = 10^(( 1 + 42.1442) / 10)
310 if (a > 16383) return 3; // = 10^(( 0 + 42.1442) / 10)
311 if (a > 13014) return 4; // = 10^((-1 + 42.1442) / 10)
312 if (a > 10338) return 5; // = 10^((-2 + 42.1442) / 10)
313 if (a > 8211) return 6; // = 10^((-3 + 42.1442) / 10)
314 if (a > 6523) return 7; // = 10^((-4 + 42.1442) / 10)
315 if (a > 5181) return 8; // = 10^((-5 + 42.1442) / 10)
316 if (a > 4115) return 9; // = 10^((-6 + 42.1442) / 10)
317 if (a > 3269) return 10; // = 10^((-7 + 42.1442) / 10)
318 if (a > 2597) return 11; // = 10^((-8 + 42.1442) / 10)
319 if (a > 2063) return 12; // = 10^((-9 + 42.1442) / 10)
320 if (a > 1638) return 13; // = 10^((-10 + 42.1442) / 10)
321 if (a > 1301) return 14; // = 10^((-11 + 42.1442) / 10)
322 if (a > 1034) return 15; // = 10^((-12 + 42.1442) / 10)
323 if (a > 821) return 16; // = 10^((-13 + 42.1442) / 10)
324 if (a > 652) return 17; // = 10^((-14 + 42.1442) / 10)
325 if (a > 518) return 18; // = 10^((-15 + 42.1442) / 10)
326 if (a > 412) return 19; // = 10^((-16 + 42.1442) / 10)
327 if (a > 327) return 20; // = 10^((-17 + 42.1442) / 10)
328 if (a > 260) return 21; // = 10^((-18 + 42.1442) / 10)
329 if (a > 206) return 22; // = 10^((-19 + 42.1442) / 10)
330 if (a > 164) return 23; // = 10^((-20 + 42.1442) / 10)
331 if (a > 130) return 24; // = 10^((-21 + 42.1442) / 10)
332 if (a > 103) return 25; // = 10^((-22 + 42.1442) / 10)
333 if (a > 82) return 26; // = 10^((-23 + 42.1442) / 10)
334 if (a > 65) return 27; // = 10^((-24 + 42.1442) / 10)
335 if (a > 52) return 28; // = 10^((-25 + 42.1442) / 10)
336 if (a > 41) return 29; // = 10^((-26 + 42.1442) / 10)
337 if (a > 33) return 30; // = 10^((-27 + 42.1442) / 10)
338 if (a > 26) return 31; // = 10^((-28 + 42.1442) / 10)
339 if (a > 21) return 32; // = 10^((-29 + 42.1442) / 10)
340 if (a > 16) return 33; // = 10^((-30 + 42.1442) / 10)
341 if (a > 13) return 34; // = 10^((-31 + 42.1442) / 10)
342 if (a > 10) return 35; // = 10^((-32 + 42.1442) / 10)
343 return 36;
344 }
345 /// convert magnitude (16384 FS) to attenuation in (integer) dB, offset by 3.
mag_to_att(int m)346 static inline int mag_to_att(int m)
347 {
348 if (m > 23143) return 0; // = 10^(( 3 + 84.2884) / 20)
349 if (m > 20626) return 1; // = 10^(( 2 + 84.2884) / 20)
350 if (m > 18383) return 2; // = 10^(( 1 + 84.2884) / 20)
351 if (m > 16383) return 3; // = 10^(( 0 + 84.2884) / 20)
352 if (m > 14602) return 4; // = 10^((-1 + 84.2884) / 20)
353 if (m > 13014) return 5; // = 10^((-2 + 84.2884) / 20)
354 if (m > 11599) return 6; // = 10^((-3 + 84.2884) / 20)
355 if (m > 10338) return 7; // = 10^((-4 + 84.2884) / 20)
356 if (m > 9213) return 8; // = 10^((-5 + 84.2884) / 20)
357 if (m > 8211) return 9; // = 10^((-6 + 84.2884) / 20)
358 if (m > 7318) return 10; // = 10^((-7 + 84.2884) / 20)
359 if (m > 6523) return 11; // = 10^((-8 + 84.2884) / 20)
360 if (m > 5813) return 12; // = 10^((-9 + 84.2884) / 20)
361 if (m > 5181) return 13; // = 10^((-10 + 84.2884) / 20)
362 if (m > 4618) return 14; // = 10^((-11 + 84.2884) / 20)
363 if (m > 4115) return 15; // = 10^((-12 + 84.2884) / 20)
364 if (m > 3668) return 16; // = 10^((-13 + 84.2884) / 20)
365 if (m > 3269) return 17; // = 10^((-14 + 84.2884) / 20)
366 if (m > 2914) return 18; // = 10^((-15 + 84.2884) / 20)
367 if (m > 2597) return 19; // = 10^((-16 + 84.2884) / 20)
368 if (m > 2314) return 20; // = 10^((-17 + 84.2884) / 20)
369 if (m > 2063) return 21; // = 10^((-18 + 84.2884) / 20)
370 if (m > 1838) return 22; // = 10^((-19 + 84.2884) / 20)
371 if (m > 1638) return 23; // = 10^((-20 + 84.2884) / 20)
372 if (m > 1460) return 24; // = 10^((-21 + 84.2884) / 20)
373 if (m > 1301) return 25; // = 10^((-22 + 84.2884) / 20)
374 if (m > 1160) return 26; // = 10^((-23 + 84.2884) / 20)
375 if (m > 1034) return 27; // = 10^((-24 + 84.2884) / 20)
376 if (m > 921) return 28; // = 10^((-25 + 84.2884) / 20)
377 if (m > 821) return 29; // = 10^((-26 + 84.2884) / 20)
378 if (m > 732) return 30; // = 10^((-27 + 84.2884) / 20)
379 if (m > 652) return 31; // = 10^((-28 + 84.2884) / 20)
380 if (m > 581) return 32; // = 10^((-29 + 84.2884) / 20)
381 if (m > 518) return 33; // = 10^((-30 + 84.2884) / 20)
382 if (m > 462) return 34; // = 10^((-31 + 84.2884) / 20)
383 if (m > 412) return 35; // = 10^((-32 + 84.2884) / 20)
384 return 36;
385 }
386 /// print a simple attenuation histogram.
print_att_hist(char const * s,int att_hist[])387 static void print_att_hist(char const *s, int att_hist[])
388 {
389 fprintf(stderr, "\n%s\n", s);
390 for (int i = 0; i < 37; ++i)
391 fprintf(stderr, ">%3d dB: %5d smps\n", 3 - i, att_hist[i]);
392 }
393
394 /// Demodulate On/Off Keying (OOK) and Frequency Shift Keying (FSK) from an envelope signal
pulse_detect_package(pulse_detect_t * pulse_detect,int16_t const * envelope_data,int16_t const * fm_data,int len,uint32_t samp_rate,uint64_t sample_offset,pulse_data_t * pulses,pulse_data_t * fsk_pulses,unsigned fpdm)395 int pulse_detect_package(pulse_detect_t *pulse_detect, int16_t const *envelope_data, int16_t const *fm_data, int len, uint32_t samp_rate, uint64_t sample_offset, pulse_data_t *pulses, pulse_data_t *fsk_pulses, unsigned fpdm)
396 {
397 int att_hist[37] = {0};
398 int const samples_per_ms = samp_rate / 1000;
399 pulse_detect_t *s = pulse_detect;
400 s->ook_high_estimate = MAX(s->ook_high_estimate, pulse_detect->ook_min_high_level); // Be sure to set initial minimum level
401
402 if (s->data_counter == 0) {
403 // age the pulse_data if this is a fresh buffer
404 pulses->start_ago += len;
405 fsk_pulses->start_ago += len;
406 }
407
408 // Process all new samples
409 while (s->data_counter < len) {
410 // Calculate OOK detection threshold and hysteresis
411 int16_t const am_n = envelope_data[s->data_counter];
412 if (pulse_detect->verbosity) {
413 int att = pulse_detect->use_mag_est ? mag_to_att(am_n) : amp_to_att(am_n);
414 att_hist[att]++;
415 }
416 int16_t ook_threshold = (s->ook_low_estimate + s->ook_high_estimate) / 2;
417 if (pulse_detect->ook_fixed_high_level != 0)
418 ook_threshold = pulse_detect->ook_fixed_high_level; // Manual override
419 int16_t const ook_hysteresis = ook_threshold / 8; // +-12%
420
421 // OOK State machine
422 switch (s->ook_state) {
423 case PD_OOK_STATE_IDLE:
424 if (am_n > (ook_threshold + ook_hysteresis) // Above threshold?
425 && s->lead_in_counter > OOK_EST_LOW_RATIO) { // Lead in counter to stabilize noise estimate
426 // Initialize all data
427 pulse_data_clear(pulses);
428 pulse_data_clear(fsk_pulses);
429 pulses->sample_rate = samp_rate;
430 fsk_pulses->sample_rate = samp_rate;
431 pulses->offset = sample_offset + s->data_counter;
432 fsk_pulses->offset = sample_offset + s->data_counter;
433 pulses->start_ago = len - s->data_counter;
434 fsk_pulses->start_ago = len - s->data_counter;
435 s->pulse_length = 0;
436 s->max_pulse = 0;
437 s->FSK_state = (pulse_FSK_state_t){0};
438 s->FSK_state.var_test_max = INT16_MIN;
439 s->FSK_state.var_test_min = INT16_MAX;
440 s->FSK_state.skip_samples = 40;
441 s->ook_state = PD_OOK_STATE_PULSE;
442 }
443 else { // We are still idle..
444 // Estimate low (noise) level
445 int const ook_low_delta = am_n - s->ook_low_estimate;
446 s->ook_low_estimate += ook_low_delta / OOK_EST_LOW_RATIO;
447 s->ook_low_estimate += ((ook_low_delta > 0) ? 1 : -1); // Hack to compensate for lack of fixed-point scaling
448 // Calculate default OOK high level estimate
449 s->ook_high_estimate = pulse_detect->ook_high_low_ratio * s->ook_low_estimate; // Default is a ratio of low level
450 s->ook_high_estimate = MAX(s->ook_high_estimate, pulse_detect->ook_min_high_level);
451 s->ook_high_estimate = MIN(s->ook_high_estimate, OOK_MAX_HIGH_LEVEL);
452 if (s->lead_in_counter <= OOK_EST_LOW_RATIO) s->lead_in_counter++; // Allow initial estimate to settle
453 }
454 break;
455 case PD_OOK_STATE_PULSE:
456 s->pulse_length++;
457 // End of pulse detected?
458 if (am_n < (ook_threshold - ook_hysteresis)) { // Gap?
459 // Check for spurious short pulses
460 if (s->pulse_length < PD_MIN_PULSE_SAMPLES) {
461 s->ook_state = PD_OOK_STATE_IDLE;
462 }
463 else {
464 // Continue with OOK decoding
465 pulses->pulse[pulses->num_pulses] = s->pulse_length; // Store pulse width
466 s->max_pulse = MAX(s->pulse_length, s->max_pulse); // Find largest pulse
467 s->pulse_length = 0;
468 s->ook_state = PD_OOK_STATE_GAP_START;
469 }
470 }
471 // Still pulse
472 else {
473 // Calculate OOK high level estimate
474 s->ook_high_estimate += am_n / OOK_EST_HIGH_RATIO - s->ook_high_estimate / OOK_EST_HIGH_RATIO;
475 s->ook_high_estimate = MAX(s->ook_high_estimate, pulse_detect->ook_min_high_level);
476 s->ook_high_estimate = MIN(s->ook_high_estimate, OOK_MAX_HIGH_LEVEL);
477 // Estimate pulse carrier frequency
478 pulses->fsk_f1_est += fm_data[s->data_counter] / OOK_EST_HIGH_RATIO - pulses->fsk_f1_est / OOK_EST_HIGH_RATIO;
479 }
480 // FSK Demodulation
481 if (pulses->num_pulses == 0) { // Only during first pulse
482 if (fpdm == FSK_PULSE_DETECT_OLD)
483 pulse_FSK_detect(fm_data[s->data_counter], fsk_pulses, &s->FSK_state);
484 else
485 pulse_FSK_detect_mm(fm_data[s->data_counter], fsk_pulses, &s->FSK_state);
486 }
487 break;
488 case PD_OOK_STATE_GAP_START: // Beginning of gap - it might be a spurious gap
489 s->pulse_length++;
490 // Pulse detected again already? (This is a spurious short gap)
491 if (am_n > (ook_threshold + ook_hysteresis)) { // New pulse?
492 s->pulse_length += pulses->pulse[pulses->num_pulses]; // Restore counter
493 s->ook_state = PD_OOK_STATE_PULSE;
494 }
495 // Or this gap is for real?
496 else if (s->pulse_length >= PD_MIN_PULSE_SAMPLES) {
497 s->ook_state = PD_OOK_STATE_GAP;
498 // Determine if FSK modulation is detected
499 if (fsk_pulses->num_pulses > PD_MIN_PULSES) {
500 // Store last pulse/gap
501 if (fpdm == FSK_PULSE_DETECT_OLD)
502 pulse_FSK_wrap_up(fsk_pulses, &s->FSK_state);
503 // Store estimates
504 fsk_pulses->fsk_f1_est = s->FSK_state.fm_f1_est;
505 fsk_pulses->fsk_f2_est = s->FSK_state.fm_f2_est;
506 fsk_pulses->ook_low_estimate = s->ook_low_estimate;
507 fsk_pulses->ook_high_estimate = s->ook_high_estimate;
508 pulses->end_ago = len - s->data_counter;
509 fsk_pulses->end_ago = len - s->data_counter;
510 s->ook_state = PD_OOK_STATE_IDLE; // Ensure everything is reset
511 if (pulse_detect->verbosity > 1)
512 print_att_hist("PULSE_DATA_FSK", att_hist);
513 if (pulse_detect->verbosity)
514 fprintf(stderr, "Levels low: -%d dB high: -%d dB thres: -%d dB hyst: (-%d to -%d dB)\n",
515 mag_to_att(s->ook_low_estimate), mag_to_att(s->ook_high_estimate),
516 mag_to_att(ook_threshold),
517 mag_to_att(ook_threshold + ook_hysteresis),
518 mag_to_att(ook_threshold - ook_hysteresis));
519 return PULSE_DATA_FSK;
520 }
521 } // if
522 // FSK Demodulation (continue during short gap - we might return...)
523 if (pulses->num_pulses == 0) { // Only during first pulse
524 if (fpdm == FSK_PULSE_DETECT_OLD)
525 pulse_FSK_detect(fm_data[s->data_counter], fsk_pulses, &s->FSK_state);
526 else
527 pulse_FSK_detect_mm(fm_data[s->data_counter], fsk_pulses, &s->FSK_state);
528 }
529 break;
530 case PD_OOK_STATE_GAP:
531 s->pulse_length++;
532 // New pulse detected?
533 if (am_n > (ook_threshold + ook_hysteresis)) { // New pulse?
534 pulses->gap[pulses->num_pulses] = s->pulse_length; // Store gap width
535 pulses->num_pulses++; // Next pulse
536
537 // EOP if too many pulses
538 if (pulses->num_pulses >= PD_MAX_PULSES) {
539 s->ook_state = PD_OOK_STATE_IDLE;
540 // Store estimates
541 pulses->ook_low_estimate = s->ook_low_estimate;
542 pulses->ook_high_estimate = s->ook_high_estimate;
543 pulses->end_ago = len - s->data_counter;
544 if (pulse_detect->verbosity > 1)
545 print_att_hist("PULSE_DATA_OOK MAX_PULSES", att_hist);
546 return PULSE_DATA_OOK; // End Of Package!!
547 }
548
549 s->pulse_length = 0;
550 s->ook_state = PD_OOK_STATE_PULSE;
551 }
552
553 // EOP if gap is too long
554 if (((s->pulse_length > (PD_MAX_GAP_RATIO * s->max_pulse)) // gap/pulse ratio exceeded
555 && (s->pulse_length > (PD_MIN_GAP_MS * samples_per_ms))) // Minimum gap exceeded
556 || (s->pulse_length > (PD_MAX_GAP_MS * samples_per_ms))) { // maximum gap exceeded
557 pulses->gap[pulses->num_pulses] = s->pulse_length; // Store gap width
558 pulses->num_pulses++; // Store last pulse
559 s->ook_state = PD_OOK_STATE_IDLE;
560 // Store estimates
561 pulses->ook_low_estimate = s->ook_low_estimate;
562 pulses->ook_high_estimate = s->ook_high_estimate;
563 pulses->end_ago = len - s->data_counter;
564 if (pulse_detect->verbosity > 1)
565 print_att_hist("PULSE_DATA_OOK EOP", att_hist);
566 if (pulse_detect->verbosity)
567 fprintf(stderr, "Levels low: -%d dB high: -%d dB thres: -%d dB hyst: (-%d to -%d dB)\n",
568 mag_to_att(s->ook_low_estimate), mag_to_att(s->ook_high_estimate),
569 mag_to_att(ook_threshold),
570 mag_to_att(ook_threshold + ook_hysteresis),
571 mag_to_att(ook_threshold - ook_hysteresis));
572 return PULSE_DATA_OOK; // End Of Package!!
573 }
574 break;
575 default:
576 fprintf(stderr, "demod_OOK(): Unknown state!!\n");
577 s->ook_state = PD_OOK_STATE_IDLE;
578 } // switch
579 s->data_counter++;
580 } // while
581
582 s->data_counter = 0;
583 if (pulse_detect->verbosity > 2)
584 print_att_hist("Out of data", att_hist);
585 return 0; // Out of data
586 }
587