signal.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  1. /* Copyright (C) 2022-2023 Salvatore Sanfilippo -- All Rights Reserved
  2. * See the LICENSE file for information about the license. */
  3. #include "app.h"
  4. bool decode_signal(RawSamplesBuffer *s, uint64_t len, ProtoViewMsgInfo *info);
  5. /* =============================================================================
  6. * Raw signal detection
  7. * ===========================================================================*/
  8. /* Return the time difference between a and b, always >= 0 since
  9. * the absolute value is returned. */
  10. uint32_t duration_delta(uint32_t a, uint32_t b) {
  11. return a > b ? a - b : b - a;
  12. }
  13. /* Reset the current signal, so that a new one can be detected. */
  14. void reset_current_signal(ProtoViewApp *app) {
  15. app->signal_bestlen = 0;
  16. app->signal_offset = 0;
  17. app->signal_decoded = false;
  18. raw_samples_reset(DetectedSamples);
  19. raw_samples_reset(RawSamples);
  20. free_msg_info(app->msg_info);
  21. app->msg_info = NULL;
  22. }
  23. /* This function starts scanning samples at offset idx looking for the
  24. * longest run of pulses, either high or low, that are not much different
  25. * from each other, for a maximum of three duration classes.
  26. * So for instance 50 successive pulses that are roughly long 340us or 670us
  27. * will be sensed as a coherent signal (example: 312, 361, 700, 334, 667, ...)
  28. *
  29. * The classes are counted separtely for high and low signals (RF on / off)
  30. * because many devices tend to have different pulse lenghts depending on
  31. * the level of the pulse.
  32. *
  33. * For instance Oregon2 sensors, in the case of protocol 2.1 will send
  34. * pulses of ~400us (RF on) VS ~580us (RF off). */
  35. #define SEARCH_CLASSES 3
  36. uint32_t search_coherent_signal(RawSamplesBuffer *s, uint32_t idx, uint32_t min_duration) {
  37. struct {
  38. uint32_t dur[2]; /* dur[0] = low, dur[1] = high */
  39. uint32_t count[2]; /* Associated observed frequency. */
  40. } classes[SEARCH_CLASSES];
  41. memset(classes,0,sizeof(classes));
  42. // Set a min/max duration limit for samples to be considered part of a
  43. // coherent signal. The maximum length is fixed while the minimum
  44. // is passed as argument, as depends on the data rate and in general
  45. // on the signal to analyze.
  46. uint32_t max_duration = 4000;
  47. uint32_t len = 0; /* Observed len of coherent samples. */
  48. s->short_pulse_dur = 0;
  49. for (uint32_t j = idx; j < idx+500; j++) {
  50. bool level;
  51. uint32_t dur;
  52. raw_samples_get(s, j, &level, &dur);
  53. if (dur < min_duration || dur > max_duration) break; /* return. */
  54. /* Let's see if it matches a class we already have or if we
  55. * can populate a new (yet empty) class. */
  56. uint32_t k;
  57. for (k = 0; k < SEARCH_CLASSES; k++) {
  58. if (classes[k].count[level] == 0) {
  59. classes[k].dur[level] = dur;
  60. classes[k].count[level] = 1;
  61. break; /* Sample accepted. */
  62. } else {
  63. uint32_t classavg = classes[k].dur[level];
  64. uint32_t count = classes[k].count[level];
  65. uint32_t delta = duration_delta(dur,classavg);
  66. /* Is the difference in duration between this signal and
  67. * the class we are inspecting less than a given percentage?
  68. * If so, accept this signal. */
  69. if (delta < classavg/5) { /* 100%/5 = 20%. */
  70. /* It is useful to compute the average of the class
  71. * we are observing. We know how many samples we got so
  72. * far, so we can recompute the average easily.
  73. * By always having a better estimate of the pulse len
  74. * we can avoid missing next samples in case the first
  75. * observed samples are too off. */
  76. classavg = ((classavg * count) + dur) / (count+1);
  77. classes[k].dur[level] = classavg;
  78. classes[k].count[level]++;
  79. break; /* Sample accepted. */
  80. }
  81. }
  82. }
  83. if (k == SEARCH_CLASSES) break; /* No match, return. */
  84. /* If we are here, we accepted this sample. Try with the next
  85. * one. */
  86. len++;
  87. }
  88. /* Update the buffer setting the shortest pulse we found
  89. * among the three classes. This will be used when scaling
  90. * for visualization. */
  91. uint32_t short_dur[2] = {0,0};
  92. for (int j = 0; j < SEARCH_CLASSES; j++) {
  93. for (int level = 0; level < 2; level++) {
  94. if (classes[j].dur[level] == 0) continue;
  95. if (classes[j].count[level] < 3) continue;
  96. if (short_dur[level] == 0 ||
  97. short_dur[level] > classes[j].dur[level])
  98. {
  99. short_dur[level] = classes[j].dur[level];
  100. }
  101. }
  102. }
  103. /* Use the average between high and low short pulses duration.
  104. * Often they are a bit different, and using the average is more robust
  105. * when we do decoding sampling at short_pulse_dur intervals. */
  106. if (short_dur[0] == 0) short_dur[0] = short_dur[1];
  107. if (short_dur[1] == 0) short_dur[1] = short_dur[0];
  108. s->short_pulse_dur = (short_dur[0]+short_dur[1])/2;
  109. return len;
  110. }
  111. /* Called when we detect a message. Just blinks when the message was
  112. * not decoded. Vibrates, too, when the message was correctly decoded. */
  113. void notify_signal_detected(ProtoViewApp *app, bool decoded) {
  114. static const NotificationSequence decoded_seq = {
  115. &message_vibro_on,
  116. &message_green_255,
  117. &message_delay_50,
  118. &message_green_0,
  119. &message_vibro_off,
  120. NULL
  121. };
  122. static const NotificationSequence unknown_seq = {
  123. &message_red_255,
  124. &message_delay_50,
  125. &message_red_0,
  126. NULL
  127. };
  128. if (decoded)
  129. notification_message(app->notification, &decoded_seq);
  130. else
  131. notification_message(app->notification, &unknown_seq);
  132. }
  133. /* Search the source buffer with the stored signal (last N samples received)
  134. * in order to find a coherent signal. If a signal that does not appear to
  135. * be just noise is found, it is set in DetectedSamples global signal
  136. * buffer, that is what is rendered on the screen. */
  137. void scan_for_signal(ProtoViewApp *app, RawSamplesBuffer *source, uint32_t min_duration) {
  138. /* We need to work on a copy: the source buffer may be populated
  139. * by the background thread receiving data. */
  140. RawSamplesBuffer *copy = raw_samples_alloc();
  141. raw_samples_copy(copy,source);
  142. /* Try to seek on data that looks to have a regular high low high low
  143. * pattern. */
  144. uint32_t minlen = 18; /* Min run of coherent samples. With less
  145. than a few samples it's very easy to
  146. mistake noise for signal. */
  147. uint32_t i = 0;
  148. while (i < copy->total-1) {
  149. uint32_t thislen = search_coherent_signal(copy,i,min_duration);
  150. /* For messages that are long enough, attempt decoding. */
  151. if (thislen > minlen) {
  152. /* Allocate the message information that some decoder may
  153. * fill, in case it is able to decode a message. */
  154. ProtoViewMsgInfo *info = malloc(sizeof(ProtoViewMsgInfo));
  155. init_msg_info(info,app);
  156. info->short_pulse_dur = copy->short_pulse_dur;
  157. uint32_t saved_idx = copy->idx; /* Save index, see later. */
  158. /* decode_signal() expects the detected signal to start
  159. * from index zero .*/
  160. raw_samples_center(copy,i);
  161. bool decoded = decode_signal(copy,thislen,info);
  162. copy->idx = saved_idx; /* Restore the index as we are scanning
  163. the signal in the loop. */
  164. /* Accept this signal as the new signal if either it's longer
  165. * than the previous undecoded one, or the previous one was
  166. * unknown and this is decoded. */
  167. if ((thislen > app->signal_bestlen && app->signal_decoded == false)
  168. || (app->signal_decoded == false && decoded))
  169. {
  170. free_msg_info(app->msg_info);
  171. app->msg_info = info;
  172. app->signal_bestlen = thislen;
  173. app->signal_decoded = decoded;
  174. raw_samples_copy(DetectedSamples,copy);
  175. raw_samples_center(DetectedSamples,i);
  176. FURI_LOG_E(TAG, "===> Displayed sample updated (%d samples %lu us)",
  177. (int)thislen, DetectedSamples->short_pulse_dur);
  178. adjust_raw_view_scale(app,DetectedSamples->short_pulse_dur);
  179. notify_signal_detected(app,decoded);
  180. } else {
  181. /* If the structure was not filled, discard it. Otherwise
  182. * now the owner is app->msg_info. */
  183. free_msg_info(info);
  184. }
  185. }
  186. i += thislen ? thislen : 1;
  187. }
  188. raw_samples_free(copy);
  189. }
  190. /* =============================================================================
  191. * Decoding
  192. *
  193. * The following code will translates the raw singals as received by
  194. * the CC1101 into logical signals: a bitmap of 0s and 1s sampled at
  195. * the detected data clock interval.
  196. *
  197. * Then the converted signal is passed to the protocols decoders, that look
  198. * for protocol-specific information. We stop at the first decoder that is
  199. * able to decode the data, so protocols here should be registered in
  200. * order of complexity and specificity, with the generic ones at the end.
  201. * ===========================================================================*/
  202. /* Set the 'bitpos' bit to value 'val', in the specified bitmap
  203. * 'b' of len 'blen'.
  204. * Out of range bits will silently be discarded. */
  205. void bitmap_set(uint8_t *b, uint32_t blen, uint32_t bitpos, bool val) {
  206. uint32_t byte = bitpos/8;
  207. uint32_t bit = 7-(bitpos&7);
  208. if (byte >= blen) return;
  209. if (val)
  210. b[byte] |= 1<<bit;
  211. else
  212. b[byte] &= ~(1<<bit);
  213. }
  214. /* Get the bit 'bitpos' of the bitmap 'b' of 'blen' bytes.
  215. * Out of range bits return false (not bit set). */
  216. bool bitmap_get(uint8_t *b, uint32_t blen, uint32_t bitpos) {
  217. uint32_t byte = bitpos/8;
  218. uint32_t bit = 7-(bitpos&7);
  219. if (byte >= blen) return 0;
  220. return (b[byte] & (1<<bit)) != 0;
  221. }
  222. /* Copy 'count' bits from the bitmap 's' of 'slen' total bytes, to the
  223. * bitmap 'd' of 'dlen' total bytes. The bits are copied starting from
  224. * offset 'soff' of the source bitmap to the offset 'doff' of the
  225. * destination bitmap. */
  226. void bitmap_copy(uint8_t *d, uint32_t dlen, uint32_t doff,
  227. uint8_t *s, uint32_t slen, uint32_t soff,
  228. uint32_t count)
  229. {
  230. /* If we are byte-aligned in both source and destination, use a fast
  231. * path for the number of bytes we can consume this way. */
  232. if ((doff & 7) == 0 && (soff & 7) == 0) {
  233. uint32_t didx = doff/8;
  234. uint32_t sidx = soff/8;
  235. while(count > 8 && didx < dlen && sidx < slen) {
  236. d[didx++] = s[sidx++];
  237. count -= 8;
  238. }
  239. doff = didx * 8;
  240. soff = sidx * 8;
  241. /* Note that if we entered this path, the count at the end
  242. * of the loop will be < 8. */
  243. }
  244. /* Copy the bits needed to reach an offset where we can copy
  245. * two half bytes of src to a full byte of destination. */
  246. while(count > 8 && (doff&7) != 0) {
  247. bool bit = bitmap_get(s,slen,soff++);
  248. bitmap_set(d,dlen,doff++,bit);
  249. count--;
  250. }
  251. /* If we are here and count > 8, we have an offset that is byte aligned
  252. * to the destination bitmap, but not aligned to the source bitmap.
  253. * We can copy fast enough by shifting each two bytes of the original
  254. * bitmap.
  255. *
  256. * This is how it works:
  257. *
  258. * dst:
  259. * +--------+--------+--------+
  260. * | 0 | 1 | 2 |
  261. * | | | | <- data to fill
  262. * +--------+--------+--------+
  263. * ^
  264. * |
  265. * doff = 8
  266. *
  267. * src:
  268. * +--------+--------+--------+
  269. * | 0 | 1 | 2 |
  270. * |hellowor|ld!HELLO|WORLDS!!| <- data to copy
  271. * +--------+--------+--------+
  272. * ^
  273. * |
  274. * soff = 11
  275. *
  276. * skew = 11%8 = 3
  277. * each destination byte in dst will receive:
  278. *
  279. * dst[doff/8] = (src[soff/8] << skew) | (src[soff/8+1] >> (8-skew))
  280. *
  281. * dstbyte = doff/8 = 8/8 = 1
  282. * srcbyte = soff/8 = 11/8 = 1
  283. *
  284. * so dst[1] will get:
  285. * src[1] << 3, that is "ld!HELLO" << 3 = "HELLO..."
  286. * xored with
  287. * src[2] << 5, that is "WORLDS!!" >> 5 = ".....WOR"
  288. * That is "HELLOWOR"
  289. */
  290. if (count > 8) {
  291. uint8_t skew = soff % 8; /* Don't worry, compiler will optimize. */
  292. uint32_t didx = doff/8;
  293. uint32_t sidx = soff/8;
  294. while(count > 8 && didx < dlen && sidx < slen) {
  295. d[didx] = ((s[sidx] << skew) |
  296. (s[sidx+1] >> (8-skew)));
  297. sidx++;
  298. didx++;
  299. soff += 8;
  300. doff += 8;
  301. count -= 8;
  302. }
  303. }
  304. /* Here count is guaranteed to be < 8.
  305. * Copy the final bits bit by bit. */
  306. while(count) {
  307. bool bit = bitmap_get(s,slen,soff++);
  308. bitmap_set(d,dlen,doff++,bit);
  309. count--;
  310. }
  311. }
  312. /* We decode bits assuming the first bit we receive is the MSB
  313. * (see bitmap_set/get functions). Certain devices send data
  314. * encoded in the reverse way. */
  315. void bitmap_reverse_bytes_bits(uint8_t *p, uint32_t len) {
  316. for (uint32_t j = 0; j < len; j++) {
  317. uint32_t b = p[j];
  318. /* Step 1: swap the two nibbles: 12345678 -> 56781234 */
  319. b = (b&0xf0)>>4 | (b&0x0f)<<4;
  320. /* Step 2: swap adjacent pairs : 56781234 -> 78563412 */
  321. b = (b&0xcc)>>2 | (b&0x33)<<2;
  322. /* Step 3: swap adjacent bits : 78563412 -> 87654321 */
  323. b = (b&0xaa)>>1 | (b&0x55)<<1;
  324. p[j] = b;
  325. }
  326. }
  327. /* Return true if the specified sequence of bits, provided as a string in the
  328. * form "11010110..." is found in the 'b' bitmap of 'blen' bits at 'bitpos'
  329. * position. */
  330. bool bitmap_match_bits(uint8_t *b, uint32_t blen, uint32_t bitpos, const char *bits) {
  331. for (size_t j = 0; bits[j]; j++) {
  332. bool expected = (bits[j] == '1') ? true : false;
  333. if (bitmap_get(b,blen,bitpos+j) != expected) return false;
  334. }
  335. return true;
  336. }
  337. /* Search for the specified bit sequence (see bitmap_match_bits() for details)
  338. * in the bitmap 'b' of 'blen' bytes, looking forward at most 'maxbits' ahead.
  339. * Returns the offset (in bits) of the match, or BITMAP_SEEK_NOT_FOUND if not
  340. * found.
  341. *
  342. * Note: there are better algorithms, such as Boyer-Moore. Here we hope that
  343. * for the kind of patterns we search we'll have a lot of early stops so
  344. * we use a vanilla approach. */
  345. uint32_t bitmap_seek_bits(uint8_t *b, uint32_t blen, uint32_t startpos, uint32_t maxbits, const char *bits) {
  346. uint32_t endpos = startpos+blen*8;
  347. uint32_t end2 = startpos+maxbits;
  348. if (end2 < endpos) endpos = end2;
  349. for (uint32_t j = startpos; j < endpos; j++)
  350. if (bitmap_match_bits(b,blen,j,bits)) return j;
  351. return BITMAP_SEEK_NOT_FOUND;
  352. }
  353. /* Set the pattern 'pat' into the bitmap 'b' of max length 'blen' bytes,
  354. * starting from the specified offset.
  355. *
  356. * The pattern is given as a string of 0s and 1s characters, like "01101001".
  357. * This function is useful in order to set the test vectors in the protocol
  358. * decoders, to see if the decoding works regardless of the fact we are able
  359. * to actually receive a given signal. */
  360. void bitmap_set_pattern(uint8_t *b, uint32_t blen, uint32_t off, const char *pat) {
  361. uint32_t i = 0;
  362. while(pat[i]) {
  363. bitmap_set(b,blen,i+off,pat[i] == '1');
  364. i++;
  365. }
  366. }
  367. /* Take the raw signal and turn it into a sequence of bits inside the
  368. * buffer 'b'. Note that such 0s and 1s are NOT the actual data in the
  369. * signal, but is just a low level representation of the line code. Basically
  370. * if the short pulse we find in the signal is 320us, we convert high and
  371. * low levels in the raw sample in this way:
  372. *
  373. * If for instance we see a high level lasting ~600 us, we will add
  374. * two 1s bit. If then the signal goes down for 330us, we will add one zero,
  375. * and so forth. So for each period of high and low we find the closest
  376. * multiple and set the relevant number of bits.
  377. *
  378. * In case of a short pulse of 320us detected, 320*2 is the closest to a
  379. * high pulse of 600us, so 2 bits will be set.
  380. *
  381. * In other terms what this function does is sampling the signal at
  382. * fixed 'rate' intervals.
  383. *
  384. * This representation makes it simple to decode the signal at a higher
  385. * level later, translating it from Marshal coding or other line codes
  386. * to the actual bits/bytes.
  387. *
  388. * The 'idx' argument marks the detected signal start index into the
  389. * raw samples buffer. The 'count' tells the function how many raw
  390. * samples to convert into bits. The function returns the number of
  391. * bits set into the buffer 'b'. The 'rate' argument, in microseconds, is
  392. * the detected short-pulse duration. We expect the line code to be
  393. * meaningful when interpreted at multiples of 'rate'. */
  394. uint32_t convert_signal_to_bits(uint8_t *b, uint32_t blen, RawSamplesBuffer *s, uint32_t idx, uint32_t count, uint32_t rate) {
  395. if (rate == 0) return 0; /* We can't perform the conversion. */
  396. uint32_t bitpos = 0;
  397. for (uint32_t j = 0; j < count; j++) {
  398. uint32_t dur;
  399. bool level;
  400. raw_samples_get(s, j+idx, &level, &dur);
  401. uint32_t numbits = dur / rate; /* full bits that surely fit. */
  402. uint32_t rest = dur % rate; /* How much we are left with. */
  403. if (rest > rate/2) numbits++; /* There is another one. */
  404. /* Limit how much a single sample can spawn. There are likely no
  405. * protocols doing such long pulses when the rate is low. */
  406. if (numbits > 1024) numbits = 1024;
  407. if (0) /* Super verbose, so not under the DEBUG_MSG define. */
  408. FURI_LOG_E(TAG, "%lu converted into %lu (%d) bits",
  409. dur,numbits,(int)level);
  410. /* If the signal is too short, let's claim it an interference
  411. * and ignore it completely. */
  412. if (numbits == 0) continue;
  413. while(numbits--) bitmap_set(b,blen,bitpos++,level);
  414. }
  415. return bitpos;
  416. }
  417. /* This function converts the line code used to the final data representation.
  418. * The representation is put inside 'buf', for up to 'buflen' bytes of total
  419. * data. For instance in order to convert manchester you can use "10" and "01"
  420. * as zero and one patterns. However this function does not handle differential
  421. * encodings. See below for convert_from_diff_manchester().
  422. *
  423. * The function returns the number of bits converted. It will stop as soon
  424. * as it finds a pattern that does not match zero or one patterns, or when
  425. * the end of the bitmap pointed by 'bits' is reached (the length is
  426. * specified in bytes by the caller, via the 'len' parameters).
  427. *
  428. * The decoding starts at the specified offset (in bits) 'off'. */
  429. uint32_t convert_from_line_code(uint8_t *buf, uint64_t buflen, uint8_t *bits, uint32_t len, uint32_t off, const char *zero_pattern, const char *one_pattern)
  430. {
  431. uint32_t decoded = 0; /* Number of bits extracted. */
  432. len *= 8; /* Convert bytes to bits. */
  433. while(off < len) {
  434. bool bitval;
  435. if (bitmap_match_bits(bits,len,off,zero_pattern)) {
  436. bitval = false;
  437. off += strlen(zero_pattern);
  438. } else if (bitmap_match_bits(bits,len,off,one_pattern)) {
  439. bitval = true;
  440. off += strlen(one_pattern);
  441. } else {
  442. break;
  443. }
  444. bitmap_set(buf,buflen,decoded++,bitval);
  445. if (decoded/8 == buflen) break; /* No space left on target buffer. */
  446. }
  447. return decoded;
  448. }
  449. /* Convert the differential Manchester code to bits. This is similar to
  450. * convert_from_line_code() but specific for Manchester. The user must
  451. * supply the value of the previous symbol before this stream, since
  452. * in differential codings the next bits depend on the previous one.
  453. *
  454. * Parameters and return values are like convert_from_line_code(). */
  455. uint32_t convert_from_diff_manchester(uint8_t *buf, uint64_t buflen, uint8_t *bits, uint32_t len, uint32_t off, bool previous)
  456. {
  457. uint32_t decoded = 0;
  458. len *= 8; /* Conver to bits. */
  459. for (uint32_t j = off; j < len; j += 2) {
  460. bool b0 = bitmap_get(bits,len,j);
  461. bool b1 = bitmap_get(bits,len,j+1);
  462. if (b0 == previous) break; /* Each new bit must switch value. */
  463. bitmap_set(buf,buflen,decoded++,b0 == b1);
  464. previous = b1;
  465. if (decoded/8 == buflen) break; /* No space left on target buffer. */
  466. }
  467. return decoded;
  468. }
  469. /* Supported protocols go here, with the relevant implementation inside
  470. * protocols/<name>.c */
  471. extern ProtoViewDecoder Oregon2Decoder;
  472. extern ProtoViewDecoder B4B1Decoder;
  473. extern ProtoViewDecoder RenaultTPMSDecoder;
  474. extern ProtoViewDecoder ToyotaTPMSDecoder;
  475. extern ProtoViewDecoder SchraderTPMSDecoder;
  476. extern ProtoViewDecoder SchraderEG53MA4TPMSDecoder;
  477. extern ProtoViewDecoder CitroenTPMSDecoder;
  478. extern ProtoViewDecoder FordTPMSDecoder;
  479. extern ProtoViewDecoder KeeloqDecoder;
  480. extern ProtoViewDecoder ProtoViewChatDecoder;
  481. ProtoViewDecoder *Decoders[] = {
  482. &Oregon2Decoder, /* Oregon sensors v2.1 protocol. */
  483. &B4B1Decoder, /* PT, SC, ... 24 bits remotes. */
  484. &RenaultTPMSDecoder, /* Renault TPMS. */
  485. &ToyotaTPMSDecoder, /* Toyota TPMS. */
  486. &SchraderTPMSDecoder, /* Schrader TPMS. */
  487. &SchraderEG53MA4TPMSDecoder, /* Schrader EG53MA4 TPMS. */
  488. &CitroenTPMSDecoder, /* Citroen TPMS. */
  489. &FordTPMSDecoder, /* Ford TPMS. */
  490. &KeeloqDecoder, /* Keeloq remote. */
  491. &ProtoViewChatDecoder, /* Protoview simple text messages. */
  492. NULL
  493. };
  494. /* Free the message info and allocated data. */
  495. void free_msg_info(ProtoViewMsgInfo *i) {
  496. if (i == NULL) return;
  497. fieldset_free(i->fieldset);
  498. free(i->bits);
  499. free(i);
  500. }
  501. /* Reset the message info structure before passing it to the decoding
  502. * functions. */
  503. void init_msg_info(ProtoViewMsgInfo *i, ProtoViewApp *app) {
  504. UNUSED(app);
  505. memset(i,0,sizeof(ProtoViewMsgInfo));
  506. i->bits = NULL;
  507. i->fieldset = fieldset_new();
  508. }
  509. /* This function is called when a new signal is detected. It converts it
  510. * to a bitstream, and the calls the protocol specific functions for
  511. * decoding. If the signal was decoded correctly by some protocol, true
  512. * is returned. Otherwise false is returned. */
  513. bool decode_signal(RawSamplesBuffer *s, uint64_t len, ProtoViewMsgInfo *info) {
  514. uint32_t bitmap_bits_size = 4096*8;
  515. uint32_t bitmap_size = bitmap_bits_size/8;
  516. /* We call the decoders with an offset a few samples before the actual
  517. * signal detected and for a len of a few bits after its end. */
  518. uint32_t before_samples = 32;
  519. uint32_t after_samples = 100;
  520. uint8_t *bitmap = malloc(bitmap_size);
  521. uint32_t bits = convert_signal_to_bits(bitmap,bitmap_size,s,-before_samples,len+before_samples+after_samples,s->short_pulse_dur);
  522. if (DEBUG_MSG) { /* Useful for debugging purposes. Don't remove. */
  523. char *str = malloc(1024);
  524. uint32_t j;
  525. for (j = 0; j < bits && j < 1023; j++) {
  526. str[j] = bitmap_get(bitmap,bitmap_size,j) ? '1' : '0';
  527. }
  528. str[j] = 0;
  529. FURI_LOG_E(TAG, "%lu bits sampled: %s", bits, str);
  530. free(str);
  531. }
  532. /* Try all the decoders available. */
  533. int j = 0;
  534. bool decoded = false;
  535. while(Decoders[j]) {
  536. uint32_t start_time = furi_get_tick();
  537. decoded = Decoders[j]->decode(bitmap,bitmap_size,bits,info);
  538. uint32_t delta = furi_get_tick() - start_time;
  539. FURI_LOG_E(TAG, "Decoder %s took %lu ms",
  540. Decoders[j]->name, (unsigned long)delta);
  541. if (decoded) {
  542. info->decoder = Decoders[j];
  543. break;
  544. }
  545. j++;
  546. }
  547. if (!decoded) {
  548. FURI_LOG_E(TAG, "No decoding possible");
  549. } else {
  550. FURI_LOG_E(TAG, "+++ Decoded %s", info->decoder->name);
  551. /* The message was correctly decoded: fill the info structure
  552. * with the decoded signal. The decoder may not implement offset/len
  553. * filling of the structure. In such case we have no info and
  554. * pulses_count will be set to zero. */
  555. if (info->pulses_count) {
  556. info->bits_bytes = (info->pulses_count+7)/8; // Round to full byte.
  557. info->bits = malloc(info->bits_bytes);
  558. bitmap_copy(info->bits,info->bits_bytes,0,
  559. bitmap,bitmap_size,info->start_off,
  560. info->pulses_count);
  561. }
  562. }
  563. free(bitmap);
  564. return decoded;
  565. }