Prechádzať zdrojové kódy

Tx: data feeder of current signal refactored.

antirez 3 rokov pred
rodič
commit
2fe4ce34d2
2 zmenil súbory, kde vykonal 91 pridanie a 52 odobranie
  1. 1 0
      app.h
  2. 90 52
      view_info.c

+ 1 - 0
app.h

@@ -116,6 +116,7 @@ typedef struct ProtoViewMsgInfo {
                                    integer. */
 } ProtoViewMsgInfo;
 
+/* Our main application context. */
 struct ProtoViewApp {
     /* GUI */
     Gui *gui;

+ 90 - 52
view_info.c

@@ -5,23 +5,14 @@
 #include <gui/view_i.h>
 #include <lib/toolbox/random_name.h>
 
+/* This view has subviews accessible navigating up/down. This
+ * enumaration is used to track the currently active subview. */
 enum {
     SubViewInfoMain,
     SubViewInfoSave,
     SubViewInfoLast, /* Just a sentinel. */
 };
 
-/* This is the context we pass to the data yield callback for
- * asynchronous tx. */
-#define SENDSIGNAL_CURPOS_START_GAP UINT32_MAX-1
-#define SENDSIGNAL_CURPOS_END_GAP UINT32_MAX-2
-typedef struct {
-    uint32_t curpos;        // Current bit position of data to send
-    ProtoViewApp *app;      // App reference.
-    uint32_t start_gap_dur;
-    uint32_t end_gap_dur;
-} SendSignalState;
-
 /* Our view private data. */
 #define SAVE_FILENAME_LEN 64
 typedef struct {
@@ -147,52 +138,102 @@ void set_signal_random_filename(ProtoViewApp *app, char *buf, size_t buflen) {
     str_replace(buf,'/','_');
 }
 
+/* ========================== Signal transmission =========================== */
+
+/* This is the context we pass to the data yield callback for
+ * asynchronous tx. */
+typedef enum {
+    SendSignalSendStartGap,
+    SendSignalSendBits,
+    SendSignalSendEndGap,
+    SendSignalEndTransmission
+} SendSignalState;
+
+#define PROTOVIEW_SENDSIGNAL_START_GAP 10000  /* microseconds. */
+#define PROTOVIEW_SENDSIGNAL_END_GAP 10000    /* microseconds. */
+
+typedef struct {
+    SendSignalState state;  // Current state.
+    uint32_t curpos;        // Current bit position of data to send.
+    ProtoViewApp *app;      // App reference.
+    uint32_t start_gap_dur; // Gap to send at the start.
+    uint32_t end_gap_dur;   // Gap to send at the end.
+} SendSignalCtx;
+
+/* Setup the state context for the callback responsible to feed data
+ * to the subghz async tx system. */
+static void send_signal_init(SendSignalCtx *ss, ProtoViewApp *app) {
+    ss->state = SendSignalSendStartGap;
+    ss->curpos = 0;
+    ss->app = app;
+    ss->start_gap_dur = PROTOVIEW_SENDSIGNAL_START_GAP;
+    ss->end_gap_dur = PROTOVIEW_SENDSIGNAL_END_GAP;
+}
+
 /* Send signal data feeder callback. When the asynchronous transmission is
- * active, this function is called to return new samples as LevelDuration
- * types (that is a structure with level, that is pulse or gap, and
- * duration in microseconds). The position into the transmission is stored
- * in the context 'ctx':
+ * active, this function is called to return new samples from the currently
+ * decoded signal in app->msg_info. The subghz subsystem aspects this function,
+ * that is the data feeder, to return LevelDuration types (that is a structure
+ * with level, that is pulse or gap, and duration in microseconds).
+ *
+ * The position into the transmission is stored in the context 'ctx', that
+ * references a SendSignalCtx structure.
  *
- * In the SendSignalState structure 'ss' we remember at which bit of the
- * message we are in ss->curoff, however this offset has two special
- * values to indicate we need to send the initial and final gap.
+ * In the SendSignalCtx structure 'ss' we remember at which bit of the
+ * message we are, in ss->curoff. We also send a start and end gap in order
+ * to make sure the transmission is clear.
  */
 LevelDuration radio_tx_feed_data(void *ctx) {
-    SendSignalState *ss = ctx;
-    uint32_t dur = 0, j;
-    uint32_t level = 0;
-
-    if (ss->start_gap_dur) {
-        LevelDuration ld = level_duration_make(0,ss->start_gap_dur);
-        ss->start_gap_dur = 0;
-        ss->curpos = 0;
-        return ld;
-    }
+    SendSignalCtx *ss = ctx;
 
-    if (ss->curpos >= ss->app->msg_info->pulses_count) {
-        if (ss->end_gap_dur) {
-            LevelDuration ld = level_duration_make(0,ss->end_gap_dur);
-            ss->end_gap_dur = 0;
-            return ld;
-        } else {
-            return level_duration_reset();
-        }
+    /* Send start gap. */
+    if (ss->state == SendSignalSendStartGap) {
+        ss->state = SendSignalSendBits;
+        return level_duration_make(0,ss->start_gap_dur);
     }
 
-    for (j = 0; ss->curpos+j < ss->app->msg_info->pulses_count; j++) {
-        uint32_t l = bitmap_get(ss->app->msg_info->bits,
-                            ss->app->msg_info->bits_bytes,
-                            ss->curpos+j);
-        if (j == 0) {
-            level = l;
+    /* Send data. */
+    if (ss->state == SendSignalSendBits) {
+        uint32_t dur = 0, j;
+        uint32_t level = 0;
+
+        /* Let's see how many consecutive bits we have with the same
+         * level. */
+        for (j = 0; ss->curpos+j < ss->app->msg_info->pulses_count; j++) {
+            uint32_t l = bitmap_get(ss->app->msg_info->bits,
+                                ss->app->msg_info->bits_bytes,
+                                ss->curpos+j);
+            if (j == 0) {
+                /* At the first bit of this sequence, we store the
+                 * level of the sequence. */
+                level = l;
+                dur += ss->app->msg_info->short_pulse_dur;
+                continue;
+            }
+
+            /* As long as the level is the same, we update the duration.
+             * Otherwise stop the loop and return this sample. */
+            if (l != level) break;
             dur += ss->app->msg_info->short_pulse_dur;
-            continue;
         }
-        if (l != level) break;
-        dur += ss->app->msg_info->short_pulse_dur;
+        ss->curpos += j;
+
+        /* If this was the last set of bits, change the state to
+         * send the final gap. */
+        if (ss->curpos >= ss->app->msg_info->pulses_count)
+            ss->state = SendSignalSendEndGap;
+        return level_duration_make(level, dur);
     }
-    ss->curpos += j;
-    return level_duration_make(level, dur);
+
+    /* Send end gap. */
+    if (ss->state == SendSignalSendEndGap) {
+        ss->state = SendSignalEndTransmission;
+        return level_duration_make(0,ss->end_gap_dur);
+    }
+
+    /* End transmission. Here state is guaranteed
+     * to be SendSignalEndTransmission */
+    return level_duration_reset();
 }
 
 /* Handle input for the info view. */
@@ -221,11 +262,8 @@ void process_input_info(ProtoViewApp *app, InputEvent input) {
             show_keyboard(app, privdata->filename, SAVE_FILENAME_LEN,
                           text_input_done_callback);
         } else if (input.type == InputTypeShort && input.key == InputKeyOk) {
-            SendSignalState send_state;
-            send_state.curpos = SENDSIGNAL_CURPOS_START_GAP;
-            send_state.app = app;
-            send_state.start_gap_dur = 10000;
-            send_state.end_gap_dur = 10000;
+            SendSignalCtx send_state;
+            send_signal_init(&send_state,app);
             radio_tx_signal(app,radio_tx_feed_data,&send_state);
         }
     }