Bläddra i källkod

Direct sampling: kinda working.

antirez 3 år sedan
förälder
incheckning
0cc1128ac5
4 ändrade filer med 129 tillägg och 28 borttagningar
  1. 35 20
      app.c
  2. 6 0
      app.h
  3. 77 5
      app_subghz.c
  4. 11 3
      view_direct_sampling.c

+ 35 - 20
app.c

@@ -123,23 +123,33 @@ ProtoViewApp* protoview_app_alloc() {
     app->txrx = malloc(sizeof(ProtoViewTxRx));
 
     /* Setup rx worker and environment. */
-    app->txrx->worker = subghz_worker_alloc();
-
-#ifdef PROTOVIEW_DISABLE_SUBGHZ_FILTER
-    app->txrx->worker->filter_running = 0;
-#endif
-
-    app->txrx->environment = subghz_environment_alloc();
-    subghz_environment_set_protocol_registry(
-        app->txrx->environment, (void*)&protoview_protocol_registry);
-    app->txrx->receiver = subghz_receiver_alloc_init(app->txrx->environment);
-
-    subghz_receiver_set_filter(app->txrx->receiver, SubGhzProtocolFlag_Decodable);
-    subghz_worker_set_overrun_callback(
-        app->txrx->worker, (SubGhzWorkerOverrunCallback)subghz_receiver_reset);
-    subghz_worker_set_pair_callback(
-        app->txrx->worker, (SubGhzWorkerPairCallback)subghz_receiver_decode);
-    subghz_worker_set_context(app->txrx->worker, app->txrx->receiver);
+    app->txrx->debug_direct_sampling = true;
+    if (app->txrx->debug_direct_sampling) {
+        app->txrx->ds_thread = NULL;
+    } else {
+        app->txrx->worker = subghz_worker_alloc();
+    #ifdef PROTOVIEW_DISABLE_SUBGHZ_FILTER
+        app->txrx->worker->filter_running = 0;
+    #endif
+
+        app->txrx->environment = subghz_environment_alloc();
+
+        subghz_environment_set_protocol_registry(
+            app->txrx->environment, (void*)&protoview_protocol_registry);
+
+        app->txrx->receiver =
+            subghz_receiver_alloc_init(app->txrx->environment);
+
+        subghz_receiver_set_filter(app->txrx->receiver,
+                                   SubGhzProtocolFlag_Decodable);
+        subghz_worker_set_overrun_callback(
+            app->txrx->worker,
+            (SubGhzWorkerOverrunCallback)subghz_receiver_reset);
+
+        subghz_worker_set_pair_callback(
+            app->txrx->worker, (SubGhzWorkerPairCallback)subghz_receiver_decode);
+        subghz_worker_set_context(app->txrx->worker, app->txrx->receiver);
+    }
     
     app->frequency = subghz_setting_get_default_frequency(app->setting);
     app->modulation = 0; /* Defaults to ProtoViewModulations[0]. */
@@ -171,9 +181,11 @@ void protoview_app_free(ProtoViewApp *app) {
     subghz_setting_free(app->setting);
 
     // Worker stuff.
-    subghz_receiver_free(app->txrx->receiver);
-    subghz_environment_free(app->txrx->environment);
-    subghz_worker_free(app->txrx->worker);
+    if (!app->txrx->debug_direct_sampling) {
+        subghz_receiver_free(app->txrx->receiver);
+        subghz_environment_free(app->txrx->environment);
+        subghz_worker_free(app->txrx->worker);
+    }
     free(app->txrx);
 
     // Raw samples buffers.
@@ -196,6 +208,9 @@ int32_t protoview_app_entry(void* p) {
     UNUSED(p);
     ProtoViewApp *app = protoview_app_alloc();
 
+    printf("%llu\n", (unsigned long long) DWT->CYCCNT);
+    printf("%llu\n", (unsigned long long) DWT->CYCCNT);
+
     /* Create a timer. We do data analysis in the callback. */
     FuriTimer *timer = furi_timer_alloc(timer_callback, FuriTimerTypePeriodic, app);
     furi_timer_start(timer, furi_kernel_get_tick_frequency() / 4);

+ 6 - 0
app.h

@@ -65,7 +65,11 @@ extern ProtoViewModulation ProtoViewModulations[]; /* In app_subghz.c */
  * It receives data and we get our protocol "feed" callback called
  * with the level (1 or 0) and duration. */
 struct ProtoViewTxRx {
+    int debug_direct_sampling;  /* Ready from GDO0 in a busy loop. Only
+                                   for testing. */
     SubGhzWorker* worker;       /* Our background worker. */
+    FuriThread *ds_thread;      /* Direct sampling thread. */
+    bool ds_thread_running;     /* Exit condition for the thread. */
     SubGhzEnvironment* environment;
     SubGhzReceiver* receiver;
     TxRxState txrx_state; /* Receiving, idle or sleeping? */
@@ -136,6 +140,8 @@ uint32_t radio_rx(ProtoViewApp* app);
 void radio_idle(ProtoViewApp* app);
 void radio_rx_end(ProtoViewApp* app);
 void radio_sleep(ProtoViewApp* app);
+void raw_sampling_worker_start(ProtoViewApp *app);
+void raw_sampling_worker_stop(ProtoViewApp *app);
 
 /* signal.c */
 uint32_t duration_delta(uint32_t a, uint32_t b);

+ 77 - 5
app_subghz.c

@@ -6,6 +6,9 @@
 
 #include <flipper_format/flipper_format_i.h>
 
+void raw_sampling_worker_start(ProtoViewApp *app);
+void raw_sampling_worker_stop(ProtoViewApp *app);
+
 ProtoViewModulation ProtoViewModulations[] = {
     {"OOK 650Khz", FuriHalSubGhzPresetOok650Async, NULL},
     {"OOK 270Khz", FuriHalSubGhzPresetOok270Async, NULL},
@@ -53,9 +56,14 @@ uint32_t radio_rx(ProtoViewApp* app) {
     furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
     furi_hal_subghz_flush_rx();
     furi_hal_subghz_rx();
+    if (!app->txrx->debug_direct_sampling) {
 
-    furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, app->txrx->worker);
-    subghz_worker_start(app->txrx->worker);
+        furi_hal_subghz_start_async_rx(subghz_worker_rx_callback,
+                                       app->txrx->worker);
+        subghz_worker_start(app->txrx->worker);
+    } else {
+        raw_sampling_worker_start(app);
+    }
     app->txrx->txrx_state = TxRxStateRx;
     return value;
 }
@@ -64,9 +72,13 @@ uint32_t radio_rx(ProtoViewApp* app) {
 void radio_rx_end(ProtoViewApp* app) {
     furi_assert(app);
     if (app->txrx->txrx_state == TxRxStateRx) {
-        if(subghz_worker_is_running(app->txrx->worker)) {
-            subghz_worker_stop(app->txrx->worker);
-            furi_hal_subghz_stop_async_rx();
+        if (!app->txrx->debug_direct_sampling) {
+            if(subghz_worker_is_running(app->txrx->worker)) {
+                subghz_worker_stop(app->txrx->worker);
+                furi_hal_subghz_stop_async_rx();
+            }
+        } else {
+            raw_sampling_worker_stop(app);
         }
     }
     furi_hal_subghz_idle();
@@ -84,3 +96,63 @@ void radio_sleep(ProtoViewApp* app) {
     furi_hal_subghz_sleep();
     app->txrx->txrx_state = TxRxStateSleep;
 }
+
+/* ============================= Raw sampling mode =============================
+ * This is useful only for debugging: in this mode instead of using the
+ * subghz thread, we read in a busy loop from the GDO0 pin of the CC1101
+ * in order to get exactly what the chip is receiving. Then using the
+ * CPU ticks counter we fill the buffer of data with the pulses level
+ * and duration. */
+
+int32_t direct_sampling_thread(void *ctx) {
+    ProtoViewApp *app = ctx;
+    bool last_level = false;
+    uint32_t last_change_time = DWT->CYCCNT;
+
+    while(app->txrx->ds_thread_running) {
+        uint32_t d[10];
+        for (uint32_t j = 0; j < 500; j++) {
+            uint32_t maxloops = 50000;
+            while(maxloops-- && app->txrx->ds_thread_running) {
+                bool l = furi_hal_gpio_read(&gpio_cc1101_g0);
+                if (l != last_level) break;
+            }
+            if (maxloops == 0) {
+                FURI_LOG_E(TAG, "Max loops reached in DS");
+                furi_delay_tick(1);
+            }
+            /* g0 no longer equal to last level. */
+            uint32_t now = DWT->CYCCNT;
+            uint32_t dur = now - last_change_time;
+            dur /= furi_hal_cortex_instructions_per_microsecond();
+            raw_samples_add(RawSamples, last_level, dur);
+            last_level = !last_level; /* What g0 is now. */
+            last_change_time = now;
+            if (j < 10) d[j] = dur;
+            if (!app->txrx->ds_thread_running) break;
+        }
+
+        for (uint32_t j = 0; j < 10; j++) {
+            FURI_LOG_E(TAG, "dur[%u]: %u",
+                (unsigned int)j, (unsigned int)d[j]);
+        }
+        furi_delay_tick(200);
+    }
+    FURI_LOG_E(TAG, "Exiting DS thread");
+    return 0;
+}
+
+void raw_sampling_worker_start(ProtoViewApp *app) {
+    if (app->txrx->ds_thread != NULL) return;
+    app->txrx->ds_thread_running = true;
+    app->txrx->ds_thread = furi_thread_alloc_ex("ProtoView DS", 2048, direct_sampling_thread, app);
+    furi_thread_start(app->txrx->ds_thread);
+}
+
+void raw_sampling_worker_stop(ProtoViewApp *app) {
+    if (app->txrx->ds_thread == NULL) return;
+    app->txrx->ds_thread_running = false;
+    furi_thread_join(app->txrx->ds_thread);
+    furi_thread_free(app->txrx->ds_thread);
+    app->txrx->ds_thread = NULL;
+}

+ 11 - 3
view_direct_sampling.c

@@ -16,7 +16,7 @@ void render_view_direct_sampling(Canvas *const canvas, ProtoViewApp *app) {
             /* Busy loop: this is a terrible approach as it blocks
              * everything else, but for now it's the best we can do
              * to obtain direct data with some spacing. */
-            uint32_t x = 500; while(x--);
+            // uint32_t x = 500; while(x--);
         }
     }
     canvas_set_font(canvas, FontSecondary);
@@ -33,14 +33,22 @@ void process_input_direct_sampling(ProtoViewApp *app, InputEvent input) {
 /* Enter view. Stop the subghz thread to prevent access as we read
  * the CC1101 data directly. */
 void view_enter_direct_sampling(ProtoViewApp *app) {
-    if (app->txrx->txrx_state == TxRxStateRx) {
+    if (app->txrx->txrx_state == TxRxStateRx &&
+        !app->txrx->debug_direct_sampling)
+    {
         subghz_worker_stop(app->txrx->worker);
+    } else {
+        raw_sampling_worker_stop(app);
     }
 }
 
 /* Exit view. Restore the subghz thread. */
 void view_exit_direct_sampling(ProtoViewApp *app) {
-    if (app->txrx->txrx_state == TxRxStateRx) {
+    if (app->txrx->txrx_state == TxRxStateRx &&
+        !app->txrx->debug_direct_sampling)
+    {
         subghz_worker_start(app->txrx->worker);
+    } else {
+        raw_sampling_worker_start(app);
     }
 }