Просмотр исходного кода

Fixes, comments, Oregon2 basic protocol.

antirez 3 лет назад
Родитель
Сommit
0f442527f7
9 измененных файлов с 174 добавлено и 36 удалено
  1. 1 0
      app.c
  2. 12 1
      app.h
  3. 6 0
      app_buffer.c
  4. 1 0
      app_buffer.h
  5. 1 1
      application.fam
  6. 5 3
      protocols/b4b1.c
  7. 77 3
      protocols/oregon2.c
  8. 70 24
      signal.c
  9. 1 4
      view_raw_signal.c

+ 1 - 0
app.c

@@ -65,6 +65,7 @@ ProtoViewApp* protoview_app_alloc() {
 
     // Signal found and visualization defaults
     app->signal_bestlen = 0;
+    app->signal_decoded = false;
     app->us_scale = PROTOVIEW_RAW_VIEW_DEFAULT_SCALE;
     app->signal_offset = 0;
 

+ 12 - 1
app.h

@@ -79,6 +79,7 @@ struct ProtoViewApp {
     /* Generic app state. */
     int running;             /* Once false exists the app. */
     uint32_t signal_bestlen; /* Longest coherent signal observed so far. */
+    bool signal_decoded;     /* Was the current signal decoded? */
 
     /* Raw view apps state. */
     uint32_t us_scale;       /* microseconds per pixel. */
@@ -107,7 +108,14 @@ typedef struct ProtoViewMsgInfo {
 
 typedef struct ProtoViewDecoder {
     const char *name;   /* Protocol name. */
-    bool (*decode)(uint8_t *bits, uint64_t numbits, ProtoViewMsgInfo *info);
+    /* The decode function takes a buffer that is actually a bitmap, with
+     * high and low levels represented as 0 and 1. The number of high/low
+     * pulses represented by the bitmap is passed as the 'numbits' argument,
+     * while 'numbytes' represents the total size of the bitmap pointed by
+     * 'bits'. So 'numbytes' is mainly useful to pass as argument to other
+     * functions that perform bit extraction with bound checking, such as
+     * bitmap_get() and so forth. */
+    bool (*decode)(uint8_t *bits, uint32_t numbytes, uint32_t numbits, ProtoViewMsgInfo *info);
 } ProtoViewDecoder;
 
 extern RawSamplesBuffer *RawSamples, *DetectedSamples;
@@ -121,8 +129,11 @@ void radio_sleep(ProtoViewApp* app);
 
 /* signal.c */
 uint32_t duration_delta(uint32_t a, uint32_t b);
+void reset_current_signal(ProtoViewApp *app);
 void scan_for_signal(ProtoViewApp *app);
 bool bitmap_get(uint8_t *b, uint32_t blen, uint32_t bitpos);
+void bitmap_set(uint8_t *b, uint32_t blen, uint32_t bitpos, bool val);
+void bitmap_invert_bytes_bits(uint8_t *p, uint32_t len);
 bool bitmap_match_bits(uint8_t *b, uint32_t blen, uint32_t bitpos, const char *bits);
 uint32_t bitmap_seek_bits(uint8_t *b, uint32_t blen, uint32_t startpos, const char *bits);
 uint32_t convert_from_line_code(uint8_t *buf, uint64_t buflen, uint8_t *bits, uint32_t len, uint32_t offset, const char *zero_pattern, const char *one_pattern);

+ 6 - 0
app_buffer.c

@@ -34,6 +34,12 @@ void raw_samples_reset(RawSamplesBuffer *s) {
     furi_mutex_release(s->mutex);
 }
 
+/* Set the raw sample internal index so that what is currently at
+ * offset 'offset', will appear to be at 0 index. */
+void raw_samples_center(RawSamplesBuffer *s, uint32_t offset) {
+    s->idx = (s->idx+offset) % RAW_SAMPLES_NUM;
+}
+
 /* Add the specified sample in the circular buffer. */
 void raw_samples_add(RawSamplesBuffer *s, bool level, uint32_t dur) {
     furi_mutex_acquire(s->mutex,FuriWaitForever);

+ 1 - 0
app_buffer.h

@@ -23,6 +23,7 @@ typedef struct RawSamplesBuffer {
 
 RawSamplesBuffer *raw_samples_alloc(void);
 void raw_samples_reset(RawSamplesBuffer *s);
+void raw_samples_center(RawSamplesBuffer *s, uint32_t offset);
 void raw_samples_add(RawSamplesBuffer *s, bool level, uint32_t dur);
 void raw_samples_get(RawSamplesBuffer *s, uint32_t idx, bool *level, uint32_t *dur);
 void raw_samples_copy(RawSamplesBuffer *dst, RawSamplesBuffer *src);

+ 1 - 1
application.fam

@@ -5,7 +5,7 @@ App(
     entry_point="protoview_app_entry",
     cdefines=["APP_PROTOVIEW"],
     requires=["gui"],
-    stack_size=8 * 1024,
+    stack_size=8*1024,
     order=50,
     fap_icon="appicon.png",
     fap_category="Tools",

+ 5 - 3
protocols/b4b1.c

@@ -7,7 +7,8 @@
 
 #include "../app.h"
 
-static bool decode(uint8_t *bits, uint64_t numbits, ProtoViewMsgInfo *info) {
+static bool decode(uint8_t *bits, uint32_t numbytes, uint32_t numbits, ProtoViewMsgInfo *info) {
+    if (numbits < 30) return false;
     const char *sync_patterns[3] = {
         "10000000000000000000000000000001", /* 30 zero bits. */
         "100000000000000000000000000000001", /* 31 zero bits. */
@@ -17,7 +18,7 @@ static bool decode(uint8_t *bits, uint64_t numbits, ProtoViewMsgInfo *info) {
     uint32_t off;
     int j;
     for (j = 0; j < 3; j++) {
-        off = bitmap_seek_bits(bits,numbits,0,sync_patterns[j]);
+        off = bitmap_seek_bits(bits,numbytes,0,sync_patterns[j]);
         if (off != BITMAP_SEEK_NOT_FOUND) break;
     }
     if (off == BITMAP_SEEK_NOT_FOUND) return false;
@@ -26,10 +27,11 @@ static bool decode(uint8_t *bits, uint64_t numbits, ProtoViewMsgInfo *info) {
 
     uint8_t d[3]; /* 24 bits of data. */
     uint32_t decoded =
-        convert_from_line_code(d,sizeof(d),bits,numbits,off,"1000","1110");
+        convert_from_line_code(d,sizeof(d),bits,numbytes,off,"1000","1110");
 
     if (DEBUG_MSG) FURI_LOG_E(TAG, "B4B1 decoded: %lu",decoded);
     if (decoded != 24) return false;
+    bitmap_invert_bytes_bits(d,sizeof(d));
     snprintf(info->name,PROTOVIEW_MSG_STR_LEN,"PT/SC remote");
     snprintf(info->raw,PROTOVIEW_MSG_STR_LEN,"%02X%02X%02X",d[0],d[1],d[2]);
     info->len = off+(4*24);

+ 77 - 3
protocols/oregon2.c

@@ -1,12 +1,86 @@
 #include "../app.h"
 
-static bool decode(uint8_t *bits, uint64_t numbits, ProtoViewMsgInfo *info) {
+#if 0
+/* Invert byte ordering. */
+static void invert_nibbles(uint8_t *p, uint32_t len) {
+    len *= 8;
+    for (uint32_t j = 0; j < len; j += 4) {
+        bool b0 = bitmap_get(p,len,j);
+        bool b1 = bitmap_get(p,len,j+1);
+        bool b2 = bitmap_get(p,len,j+2);
+        bool b3 = bitmap_get(p,len,j+3);
+        bitmap_set(p,len,j,b3);
+        bitmap_set(p,len,j+1,b2);
+        bitmap_set(p,len,j+2,b1);
+        bitmap_set(p,len,j+3,b0);
+    }
+}
+#endif
+
+static bool decode(uint8_t *bits, uint32_t numbytes, uint32_t numbits, ProtoViewMsgInfo *info) {
+    if (numbits < 32) return false;
     const char *sync_pattern = "01100110" "01100110" "10010110" "10010110";
-    uint64_t off = bitmap_seek_bits(bits,numbits,0,sync_pattern);
+    uint64_t off = bitmap_seek_bits(bits,numbytes,0,sync_pattern);
     if (off == BITMAP_SEEK_NOT_FOUND) return false;
-
     FURI_LOG_E(TAG, "Oregon2 prelude+sync found");
+
+    off += 32; /* Skip preamble. */
+
+    FURI_LOG_E(TAG, "Bits: %d%d%d%d",
+        bitmap_get(bits,numbytes,off),
+        bitmap_get(bits,numbytes,off+1),
+        bitmap_get(bits,numbytes,off+2),
+        bitmap_get(bits,numbytes,off+3));
+
+    FURI_LOG_E(TAG, "Bits: %d%d%d%d",
+        bitmap_get(bits,numbytes,off+4),
+        bitmap_get(bits,numbytes,off+5),
+        bitmap_get(bits,numbytes,off+6),
+        bitmap_get(bits,numbytes,off+7));
+
+    FURI_LOG_E(TAG, "Bits: %d%d%d%d",
+        bitmap_get(bits,numbytes,off+8),
+        bitmap_get(bits,numbytes,off+9),
+        bitmap_get(bits,numbytes,off+10),
+        bitmap_get(bits,numbytes,off+11));
+
+    FURI_LOG_E(TAG, "Bits: %d%d%d%d",
+        bitmap_get(bits,numbytes,off+12),
+        bitmap_get(bits,numbytes,off+13),
+        bitmap_get(bits,numbytes,off+14),
+        bitmap_get(bits,numbytes,off+15));
+
+    uint8_t buffer[8];
+    uint32_t decoded =
+        convert_from_line_code(buffer,sizeof(buffer),bits,numbytes,off,"1001","0110");
+    FURI_LOG_E(TAG, "Oregon2 decoded bits: %lu", decoded);
+
+    char temp[3] = {0}, deviceid[2] = {0};
+    for (int j = 0; j < 64; j += 4) {
+        uint8_t nib[1];
+        nib[0] = 0;
+        bitmap_set(nib,1,0,bitmap_get(buffer,8,j+0));
+        bitmap_set(nib,1,1,bitmap_get(buffer,8,j+1));
+        bitmap_set(nib,1,2,bitmap_get(buffer,8,j+2));
+        bitmap_set(nib,1,3,bitmap_get(buffer,8,j+3));
+        FURI_LOG_E(TAG, "Not inverted nibble[%d]: %x", j/4, (unsigned int)nib[0]);
+        switch(j/4) {
+        case 1: deviceid[0] |= nib[0]; break;
+        case 0: deviceid[0] |= nib[0] << 4; break;
+        case 3: deviceid[1] |= nib[0]; break;
+        case 2: deviceid[1] |= nib[0] << 4; break;
+        case 10: temp[0] = nib[0]; break;
+        case 9: temp[1] = nib[0]; break;
+        case 8: temp[2] = nib[0]; break;
+        }
+    }
+
     snprintf(info->name,sizeof(info->name),"%s","Oregon v2.1");
+    snprintf(info->raw,sizeof(info->raw),"%08llX", *((uint64_t*)buffer));
+    snprintf(info->info1,sizeof(info->info1),"Temp %d%d.%d",
+        temp[0],temp[1],temp[2]);
+    snprintf(info->info2,sizeof(info->info2),"ID %02X%02X",
+        deviceid[0], deviceid[1]);
     return true;
 }
 

+ 70 - 24
signal.c

@@ -3,7 +3,8 @@
 
 #include "app.h"
 
-void decode_signal(RawSamplesBuffer *s, uint64_t len);
+bool decode_signal(RawSamplesBuffer *s, uint64_t len, ProtoViewMsgInfo *info);
+void initialize_msg_info(ProtoViewMsgInfo *i);
 
 /* =============================================================================
  * Raw signal detection
@@ -15,6 +16,15 @@ uint32_t duration_delta(uint32_t a, uint32_t b) {
     return a > b ? a - b : b - a;
 }
 
+/* Reset the current signal, so that a new one can be detected. */
+void reset_current_signal(ProtoViewApp *app) {
+    app->signal_bestlen = 0;
+    app->signal_offset = 0;
+    app->signal_decoded = false;
+    raw_samples_reset(DetectedSamples);
+    raw_samples_reset(RawSamples);
+}
+
 /* This function starts scanning samples at offset idx looking for the
  * longest run of pulses, either high or low, that are not much different
  * from each other, for a maximum of three duration classes.
@@ -126,15 +136,34 @@ void scan_for_signal(ProtoViewApp *app) {
 
     uint32_t i = 0;
     while (i < copy->total-1) {
+        ProtoViewMsgInfo info;
         uint32_t thislen = search_coherent_signal(copy,i);
-        if (thislen > minlen && thislen > app->signal_bestlen) {
-            app->signal_bestlen = thislen;
-            raw_samples_copy(DetectedSamples,copy);
-            DetectedSamples->idx = (DetectedSamples->idx+i)%
-                                   DetectedSamples->total;
-            FURI_LOG_E(TAG, "Displayed sample updated (%d samples %lu us)",
-                (int)thislen, DetectedSamples->short_pulse_dur);
-            decode_signal(DetectedSamples,thislen);
+
+        /* For messages that are long enough, attempt decoding. */
+        if (thislen > minlen) {
+
+            initialize_msg_info(&info);
+            uint32_t saved_idx = copy->idx; /* Save index, see later. */
+            /* decode_signal() expects the detected signal to start
+             * from index .*/
+            raw_samples_center(copy,i);
+            bool decoded = decode_signal(copy,thislen,&info);
+            copy->idx = saved_idx; /* Restore the index as we are scanning
+                                      the signal in the loop. */
+
+            /* Accept this signal as the new signal if either it's longer
+             * than the previous one, or the previous one was unknown and
+             * this is decoded. */
+            if (thislen > app->signal_bestlen ||
+                (app->signal_decoded == false && decoded))
+            {
+                app->signal_bestlen = thislen;
+                app->signal_decoded = decoded;
+                raw_samples_copy(DetectedSamples,copy);
+                raw_samples_center(DetectedSamples,i);
+                FURI_LOG_E(TAG, "Displayed sample updated (%d samples %lu us)",
+                    (int)thislen, DetectedSamples->short_pulse_dur);
+            }
         }
         i += thislen ? thislen : 1;
     }
@@ -176,6 +205,17 @@ bool bitmap_get(uint8_t *b, uint32_t blen, uint32_t bitpos) {
     return (b[byte] & (1<<bit)) != 0;
 }
 
+/* We decode bits assuming the first bit we receive is the LSB
+ * (see bitmap_set/get functions). Many devices send data
+ * encoded in the reverse way. */
+void bitmap_invert_bytes_bits(uint8_t *p, uint32_t len) {
+    for (uint32_t j = 0; j < len*8; j += 8) {
+        bool bits[8];
+        for (int i = 0; i < 8; i++) bits[i] = bitmap_get(p,len,j+i);
+        for (int i = 0; i < 8; i++) bitmap_set(p,len,j+i,bits[7-i]);
+    }
+}
+
 /* Return true if the specified sequence of bits, provided as a string in the
  * form "11010110..." is found in the 'b' bitmap of 'blen' bits at 'bitpos'
  * position. */
@@ -267,23 +307,27 @@ uint32_t convert_signal_to_bits(uint8_t *b, uint32_t blen, RawSamplesBuffer *s,
  * representation. In such a case I could use "10??" and "01??".
  *
  * The function returns the number of bits converted. It will stop as soon
- * as it finds a pattern that does not match zero or one patterns. The
- * decoding starts at the specified offset 'off'. */
+ * as it finds a pattern that does not match zero or one patterns, or when
+ * the end of the bitmap pointed by 'bits' is reached (the length is
+ * specified in bytes by the caller, via the 'len' parameters).
+ *
+ * The decoding starts at the specified offset (in bits) 'off'. */
 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)
 {
     uint32_t decoded = 0; /* Number of bits extracted. */
+    len *= 8; /* Convert bytes to bits. */
     while(off < len) {
-        bool level;
+        bool bitval;
         if (bitmap_match_bits(bits,len,off,zero_pattern)) {
-            level = true;
+            bitval = false;
             off += strlen(zero_pattern);
         } else if (bitmap_match_bits(bits,len,off,one_pattern)) {
-            level = false;
-            off += strlen(zero_pattern);
+            bitval = true;
+            off += strlen(one_pattern);
         } else {
             break;
         }
-        bitmap_set(buf,buflen,decoded++,level);
+        bitmap_set(buf,buflen,decoded++,bitval);
         if (decoded/8 == buflen) break; /* No space left on target buffer. */
     }
     return decoded;
@@ -309,8 +353,9 @@ void initialize_msg_info(ProtoViewMsgInfo *i) {
 
 /* This function is called when a new signal is detected. It converts it
  * to a bitstream, and the calls the protocol specific functions for
- * decoding. */
-void decode_signal(RawSamplesBuffer *s, uint64_t len) {
+ * decoding. If the signal was decoded correctly by some protocol, true
+ * is returned. Otherwise false is returned. */
+bool decode_signal(RawSamplesBuffer *s, uint64_t len, ProtoViewMsgInfo *info) {
     uint32_t bitmap_bits_size = 4096*8;
     uint32_t bitmap_size = bitmap_bits_size/8;
 
@@ -328,28 +373,29 @@ void decode_signal(RawSamplesBuffer *s, uint64_t len) {
             str[j] = bitmap_get(bitmap,bitmap_size,j) ? '1' : '0';
         }
         str[j] = 0;
-        FURI_LOG_E(TAG, "%lu bits decoded: %s", bits, str);
+        FURI_LOG_E(TAG, "%lu bits sampled: %s", bits, str);
         free(str);
     }
 
     /* Try all the decoders available. */
     int j = 0;
-    ProtoViewMsgInfo info;
-    initialize_msg_info(&info);
 
+    bool decoded = false;
     while(Decoders[j]) {
         FURI_LOG_E(TAG, "Calling decoder %s", Decoders[j]->name);
-        if (Decoders[j]->decode(bitmap,bits,&info)) {
+        if (Decoders[j]->decode(bitmap,bitmap_size,bits,info)) {
             FURI_LOG_E(TAG, "Message detected by %s", Decoders[j]->name);
+            decoded = true;
             break;
         }
         j++;
     }
 
-    if (Decoders[j] == NULL) {
+    if (!decoded) {
         FURI_LOG_E(TAG, "No decoding possible");
     } else {
-        FURI_LOG_E(TAG, "Decoded %s, raw=%s", info.name, info.raw);
+        FURI_LOG_E(TAG, "Decoded %s, raw=%s info=[%s,%s,%s]", info->name, info->raw, info->info1, info->info2, info->info3);
     }
     free(bitmap);
+    return decoded;
 }

+ 1 - 4
view_raw_signal.c

@@ -80,10 +80,7 @@ void process_input_raw_pulses(ProtoViewApp *app, InputEvent input) {
     } else if (input.type == InputTypeShort) {
         if (input.key == InputKeyOk) {
             /* Reset the current sample to capture the next. */
-            app->signal_bestlen = 0;
-            app->signal_offset = 0;
-            raw_samples_reset(DetectedSamples);
-            raw_samples_reset(RawSamples);
+            reset_current_signal(app);
         } else if (input.key == InputKeyDown) {
             /* Rescaling. The set becomes finer under 50us per pixel. */
             uint32_t scale_step = app->us_scale >= 50 ? 50 : 10;