Cody Tolene 1 год назад
Родитель
Сommit
e84ce5f390
2 измененных файлов с 105 добавлено и 4 удалено
  1. 100 4
      views/camera_suite_view_wifi_camera.c
  2. 5 0
      views/camera_suite_view_wifi_camera.h

+ 100 - 4
views/camera_suite_view_wifi_camera.c

@@ -29,13 +29,63 @@ static void camera_suite_view_wifi_camera_draw(Canvas* canvas, void* model) {
     canvas_set_font(canvas, FontSecondary);
     canvas_draw_frame(canvas, 0, 0, FRAME_WIDTH, FRAME_HEIGHT);
 
-    canvas_draw_str_aligned(canvas, 3, 3, AlignLeft, AlignTop, "Feature coming soon!");
+    canvas_draw_str_aligned(canvas, 3, 3, AlignLeft, AlignTop, "Starting WiFi Stream at:");
 
     // Draw log from camera.
     canvas_draw_str_aligned(
         canvas, 3, 13, AlignLeft, AlignTop, furi_string_get_cstr(instance->log));
 }
 
+static int32_t camera_suite_wifi_camera_worker(void* context) {
+    furi_assert(context);
+
+    CameraSuiteViewWiFiCamera* instance = context;
+
+    while(1) {
+        uint32_t events =
+            furi_thread_flags_wait(WIFI_WORKER_EVENTS_MASK, FuriFlagWaitAny, FuriWaitForever);
+
+        // Check if an error occurred.
+        furi_check((events & FuriFlagError) == 0);
+
+        // Check if the thread should stop.
+        if(events & WorkerEventStop) {
+            break;
+        } else if(events & WorkerEventRx) {
+            size_t length = 0;
+            do {
+                size_t buffer_size = 320;
+                uint8_t data[buffer_size];
+                length =
+                    furi_stream_buffer_receive(instance->wifi_rx_stream, data, buffer_size, 0);
+                if(length > 0) {
+                    data[length] = '\0';
+
+                    with_view_model(
+                        instance->view,
+                        CameraSuiteViewWiFiCameraModel * model,
+                        {
+                            furi_string_cat_printf(model->log, "%s", data);
+
+                            // Truncate if too long.
+                            model->log_strlen += length;
+                            if(model->log_strlen >= 4096 - 1) {
+                                furi_string_right(model->log, model->log_strlen / 2);
+                                model->log_strlen = furi_string_size(model->log) + length;
+                            }
+                        },
+                        true);
+                }
+            } while(length > 0);
+
+            with_view_model(
+                instance->view, CameraSuiteViewWiFiCameraModel * model, { UNUSED(model); }, true);
+        }
+    }
+
+    return 0;
+}
+
 static bool camera_suite_view_wifi_camera_input(InputEvent* event, void* context) {
     furi_assert(context);
     furi_assert(event);
@@ -68,8 +118,8 @@ static bool camera_suite_view_wifi_camera_input(InputEvent* event, void* context
                     UNUSED(model);
 
                     // Stop camera WiFi stream.
-                    // furi_hal_uart_tx(furihaluartidusart1, (uint8_t[]){'w'}, 1);
-                    // furi_delay_ms(50);
+                    furi_hal_uart_tx(FuriHalUartIdUSART1, (uint8_t[]){'w'}, 1);
+                    furi_delay_ms(50);
 
                     // Go back to the main menu.
                     instance->callback(CameraSuiteCustomEventSceneCameraBack, instance->context);
@@ -108,7 +158,7 @@ static void camera_suite_view_wifi_camera_enter(void* context) {
     CameraSuiteViewWiFiCamera* instance = (CameraSuiteViewWiFiCamera*)context;
 
     // Start wifi camera stream.
-    // furi_hal_uart_tx(FuriHalUartIdUSART1, (uint8_t[]){'W'}, 1);
+    furi_hal_uart_tx(FuriHalUartIdUSART1, (uint8_t[]){'W'}, 1);
 
     with_view_model(
         instance->view,
@@ -117,6 +167,22 @@ static void camera_suite_view_wifi_camera_enter(void* context) {
         true);
 }
 
+static void wifi_camera_on_irq_cb(UartIrqEvent uartIrqEvent, uint8_t data, void* context) {
+    furi_assert(uartIrqEvent);
+    furi_assert(data);
+    furi_assert(context);
+
+    // Cast `context` to `CameraSuiteViewWiFiCamera*` and store it in `instance`.
+    CameraSuiteViewWiFiCamera* instance = context;
+
+    // If `uartIrqEvent` is `UartIrqEventRXNE`, send the data to the
+    // `wifi_rx_stream` and set the `WorkerEventRx` flag.
+    if(uartIrqEvent == UartIrqEventRXNE) {
+        furi_stream_buffer_send(instance->wifi_rx_stream, &data, 1, 0);
+        furi_thread_flags_set(furi_thread_get_id(instance->wifi_worker_thread), WorkerEventRx);
+    }
+}
+
 CameraSuiteViewWiFiCamera* camera_suite_view_wifi_camera_alloc() {
     // Allocate memory for the instance
     CameraSuiteViewWiFiCamera* instance = malloc(sizeof(CameraSuiteViewWiFiCamera));
@@ -131,6 +197,24 @@ CameraSuiteViewWiFiCamera* camera_suite_view_wifi_camera_alloc() {
     // Set context for the view (furi_assert crashes in events without this)
     view_set_context(instance->view, instance);
 
+    // Allocate a stream buffer
+    instance->wifi_rx_stream = furi_stream_buffer_alloc(1024, 1);
+
+    // Allocate a thread for this camera to run on.
+    FuriThread* thread = furi_thread_alloc_ex(
+        "Camera_Suite_WiFi_Rx_Thread", 1024, camera_suite_wifi_camera_worker, instance);
+    instance->wifi_worker_thread = thread;
+    furi_thread_start(instance->wifi_worker_thread);
+
+    // Disable console.
+    furi_hal_console_disable();
+
+    // 115200 is the default baud rate for the ESP32-CAM.
+    furi_hal_uart_set_br(FuriHalUartIdUSART1, 230400);
+
+    // Enable UART1 and set the IRQ callback.
+    furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, wifi_camera_on_irq_cb, instance);
+
     // Set draw callback
     view_set_draw_callback(instance->view, (ViewDrawCallback)camera_suite_view_wifi_camera_draw);
 
@@ -155,6 +239,18 @@ CameraSuiteViewWiFiCamera* camera_suite_view_wifi_camera_alloc() {
 void camera_suite_view_wifi_camera_free(CameraSuiteViewWiFiCamera* instance) {
     furi_assert(instance);
 
+    // Remove the IRQ callback.
+    furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, NULL, NULL);
+
+    // Free the worker thread.
+    furi_thread_free(instance->wifi_worker_thread);
+
+    // Free the allocated stream buffer.
+    furi_stream_buffer_free(instance->wifi_rx_stream);
+
+    // Re-enable the console.
+    furi_hal_console_enable();
+
     with_view_model(
         instance->view,
         CameraSuiteViewWiFiCameraModel * model,

+ 5 - 0
views/camera_suite_view_wifi_camera.h

@@ -18,16 +18,21 @@
 
 #include "../helpers/camera_suite_custom_event.h"
 
+#define WIFI_WORKER_EVENTS_MASK (WorkerEventStop | WorkerEventRx)
+
 typedef void (*CameraSuiteViewWiFiCameraCallback)(CameraSuiteCustomEvent event, void* context);
 
 typedef struct CameraSuiteViewWiFiCamera {
     View* view;
     CameraSuiteViewCameraCallback callback;
     void* context;
+    FuriStreamBuffer* wifi_rx_stream;
+    FuriThread* wifi_worker_thread;
 } CameraSuiteViewWiFiCamera;
 
 typedef struct {
     FuriString* log;
+    size_t log_strlen;
 } CameraSuiteViewWiFiCameraModel;
 
 CameraSuiteViewWiFiCamera* camera_suite_view_wifi_camera_alloc();