Cody Tolene 2 лет назад
Родитель
Сommit
42a1ab9e22
5 измененных файлов с 114 добавлено и 91 удалено
  1. 2 2
      arduino-cli.yaml
  2. 74 57
      fap/views/camera_suite_view_camera.c
  3. 14 6
      fap/views/camera_suite_view_camera.h
  4. 19 21
      firmware/firmware.ino
  5. 5 5
      firware-flash.bat

+ 2 - 2
arduino-cli.yaml

@@ -1,6 +1,6 @@
 board_manager:
 board_manager:
   additional_urls:
   additional_urls:
-    - https://dl.espressif.com/dl/package_esp32_index.json
+  - https://dl.espressif.com/dl/package_esp32_index.json
 build_cache:
 build_cache:
   compilations_before_purge: 10
   compilations_before_purge: 10
   ttl: 720h0m0s
   ttl: 720h0m0s
@@ -8,7 +8,7 @@ daemon:
   port: "50051"
   port: "50051"
 directories:
 directories:
   data: C:\temp\arduino-cli\data
   data: C:\temp\arduino-cli\data
-  downloads: C:\temp\arduino-cli\downloads
+  downloads: C:\temp\arduino-cli\staging
   user: C:\temp\arduino-cli\user
   user: C:\temp\arduino-cli\user
 library:
 library:
   enable_unsafe_install: false
   enable_unsafe_install: false

+ 74 - 57
fap/views/camera_suite_view_camera.c

@@ -8,18 +8,6 @@
 #include "../helpers/camera_suite_speaker.h"
 #include "../helpers/camera_suite_speaker.h"
 #include "../helpers/camera_suite_led.h"
 #include "../helpers/camera_suite_led.h"
 
 
-static CameraSuiteViewCamera* current_instance = NULL;
-
-bool is_inverted = false;
-
-struct CameraSuiteViewCamera {
-    CameraSuiteViewCameraCallback callback;
-    FuriStreamBuffer* rx_stream;
-    FuriThread* worker_thread;
-    View* view;
-    void* context;
-};
-
 void camera_suite_view_camera_set_callback(
 void camera_suite_view_camera_set_callback(
     CameraSuiteViewCamera* instance,
     CameraSuiteViewCamera* instance,
     CameraSuiteViewCameraCallback callback,
     CameraSuiteViewCameraCallback callback,
@@ -33,20 +21,24 @@ void camera_suite_view_camera_set_callback(
 // Function to draw pixels on the canvas based on camera orientation
 // Function to draw pixels on the canvas based on camera orientation
 static void draw_pixel_by_orientation(Canvas* canvas, uint8_t x, uint8_t y, uint8_t orientation) {
 static void draw_pixel_by_orientation(Canvas* canvas, uint8_t x, uint8_t y, uint8_t orientation) {
     switch(orientation) {
     switch(orientation) {
-    case 0: // Camera rotated 0 degrees (right side up, default)
+    default:
+    case 0: { // Camera rotated 0 degrees (right side up, default)
         canvas_draw_dot(canvas, x, y);
         canvas_draw_dot(canvas, x, y);
         break;
         break;
-    case 1: // Camera rotated 90 degrees
+    }
+    case 1: { // Camera rotated 90 degrees
+
         canvas_draw_dot(canvas, y, FRAME_WIDTH - 1 - x);
         canvas_draw_dot(canvas, y, FRAME_WIDTH - 1 - x);
         break;
         break;
-    case 2: // Camera rotated 180 degrees (upside down)
+    }
+    case 2: { // Camera rotated 180 degrees (upside down)
         canvas_draw_dot(canvas, FRAME_WIDTH - 1 - x, FRAME_HEIGHT - 1 - y);
         canvas_draw_dot(canvas, FRAME_WIDTH - 1 - x, FRAME_HEIGHT - 1 - y);
         break;
         break;
-    case 3: // Camera rotated 270 degrees
+    }
+    case 3: { // Camera rotated 270 degrees
         canvas_draw_dot(canvas, FRAME_HEIGHT - 1 - y, x);
         canvas_draw_dot(canvas, FRAME_HEIGHT - 1 - y, x);
         break;
         break;
-    default:
-        break;
+    }
     }
     }
 }
 }
 
 
@@ -59,15 +51,13 @@ static void camera_suite_view_camera_draw(Canvas* canvas, void* _model) {
     // Draw the frame.
     // Draw the frame.
     canvas_draw_frame(canvas, 0, 0, FRAME_WIDTH, FRAME_HEIGHT);
     canvas_draw_frame(canvas, 0, 0, FRAME_WIDTH, FRAME_HEIGHT);
 
 
-    CameraSuite* app = current_instance->context;
-
     for(size_t p = 0; p < FRAME_BUFFER_LENGTH; ++p) {
     for(size_t p = 0; p < FRAME_BUFFER_LENGTH; ++p) {
         uint8_t x = p % ROW_BUFFER_LENGTH; // 0 .. 15
         uint8_t x = p % ROW_BUFFER_LENGTH; // 0 .. 15
         uint8_t y = p / ROW_BUFFER_LENGTH; // 0 .. 63
         uint8_t y = p / ROW_BUFFER_LENGTH; // 0 .. 63
 
 
         for(uint8_t i = 0; i < 8; ++i) {
         for(uint8_t i = 0; i < 8; ++i) {
             if((model->pixels[p] & (1 << (7 - i))) != 0) {
             if((model->pixels[p] & (1 << (7 - i))) != 0) {
-                draw_pixel_by_orientation(canvas, (x * 8) + i, y, app->orientation);
+                draw_pixel_by_orientation(canvas, (x * 8) + i, y, model->orientation);
             }
             }
         }
         }
     }
     }
@@ -127,6 +117,14 @@ static void save_image(void* _model) {
     // Free the file name after use.
     // Free the file name after use.
     furi_string_free(file_name);
     furi_string_free(file_name);
 
 
+    // @todo - Add functionaly for saving images inverted if necessary.
+    // Invert pixel values if necessary.
+    // if(!model->inverted) { }
+
+    for(size_t i = 0; i < FRAME_BUFFER_LENGTH; ++i) {
+        model->pixels[i] = ~model->pixels[i];
+    }
+
     // If the file was opened successfully, write the bitmap header and the
     // If the file was opened successfully, write the bitmap header and the
     // image data.
     // image data.
     if(result) {
     if(result) {
@@ -138,20 +136,13 @@ static void save_image(void* _model) {
 
 
         // Write locally to the Flipper Zero SD card in the DCIM folder.
         // Write locally to the Flipper Zero SD card in the DCIM folder.
         int8_t row_buffer[ROW_BUFFER_LENGTH];
         int8_t row_buffer[ROW_BUFFER_LENGTH];
-        if(is_inverted) {
-            for(size_t i = 0; i < 64; ++i) {
-                for(size_t j = 0; j < ROW_BUFFER_LENGTH; ++j) {
-                    row_buffer[j] = model->pixels[i * ROW_BUFFER_LENGTH + j];
-                }
-                storage_file_write(file, row_buffer, ROW_BUFFER_LENGTH);
-            }
-        } else {
-            for(size_t i = 64; i > 0; --i) {
-                for(size_t j = 0; j < ROW_BUFFER_LENGTH; ++j) {
-                    row_buffer[j] = model->pixels[((i - 1) * ROW_BUFFER_LENGTH) + j];
-                }
-                storage_file_write(file, row_buffer, ROW_BUFFER_LENGTH);
+
+        // @todo - Save image based on orientation.
+        for(size_t i = 64; i > 0; --i) {
+            for(size_t j = 0; j < ROW_BUFFER_LENGTH; ++j) {
+                row_buffer[j] = model->pixels[((i - 1) * ROW_BUFFER_LENGTH) + j];
             }
             }
+            storage_file_write(file, row_buffer, ROW_BUFFER_LENGTH);
         }
         }
     }
     }
 
 
@@ -170,7 +161,9 @@ static void camera_suite_view_camera_model_init(UartDumpModel* const model) {
 
 
 static bool camera_suite_view_camera_input(InputEvent* event, void* context) {
 static bool camera_suite_view_camera_input(InputEvent* event, void* context) {
     furi_assert(context);
     furi_assert(context);
+
     CameraSuiteViewCamera* instance = context;
     CameraSuiteViewCamera* instance = context;
+
     if(event->type == InputTypeRelease) {
     if(event->type == InputTypeRelease) {
         switch(event->key) {
         switch(event->key) {
         default: // Stop all sounds, reset the LED.
         default: // Stop all sounds, reset the LED.
@@ -189,8 +182,8 @@ static bool camera_suite_view_camera_input(InputEvent* event, void* context) {
     } else if(event->type == InputTypePress) {
     } else if(event->type == InputTypePress) {
         uint8_t data[1];
         uint8_t data[1];
         switch(event->key) {
         switch(event->key) {
-        case InputKeyBack:
-            // Stop the camera stream.
+        // Camera: Stop stream.
+        case InputKeyBack: {
             data[0] = 's';
             data[0] = 's';
             // Go back to the main menu.
             // Go back to the main menu.
             with_view_model(
             with_view_model(
@@ -202,25 +195,25 @@ static bool camera_suite_view_camera_input(InputEvent* event, void* context) {
                 },
                 },
                 true);
                 true);
             break;
             break;
-        case InputKeyLeft:
-            // Camera: Toggle invert on the ESP32-CAM.
+        }
+        // Camera: Toggle invert on the ESP32-CAM.
+        case InputKeyLeft: {
             data[0] = '<';
             data[0] = '<';
-            // Toggle invert state locally.
-            is_inverted = !is_inverted;
             with_view_model(
             with_view_model(
                 instance->view,
                 instance->view,
                 UartDumpModel * model,
                 UartDumpModel * model,
                 {
                 {
-                    UNUSED(model);
                     camera_suite_play_happy_bump(instance->context);
                     camera_suite_play_happy_bump(instance->context);
                     camera_suite_play_input_sound(instance->context);
                     camera_suite_play_input_sound(instance->context);
                     camera_suite_led_set_rgb(instance->context, 0, 0, 255);
                     camera_suite_led_set_rgb(instance->context, 0, 0, 255);
+                    model->inverted = !model->inverted;
                     instance->callback(CameraSuiteCustomEventSceneCameraLeft, instance->context);
                     instance->callback(CameraSuiteCustomEventSceneCameraLeft, instance->context);
                 },
                 },
                 true);
                 true);
             break;
             break;
-        case InputKeyRight:
-            // Camera: Enable/disable dithering.
+        }
+        // Camera: Enable/disable dithering.
+        case InputKeyRight: {
             data[0] = '>';
             data[0] = '>';
             with_view_model(
             with_view_model(
                 instance->view,
                 instance->view,
@@ -234,8 +227,9 @@ static bool camera_suite_view_camera_input(InputEvent* event, void* context) {
                 },
                 },
                 true);
                 true);
             break;
             break;
-        case InputKeyUp:
-            // Camera: Increase contrast.
+        }
+        // Camera: Increase contrast.
+        case InputKeyUp: {
             data[0] = 'C';
             data[0] = 'C';
             with_view_model(
             with_view_model(
                 instance->view,
                 instance->view,
@@ -249,8 +243,9 @@ static bool camera_suite_view_camera_input(InputEvent* event, void* context) {
                 },
                 },
                 true);
                 true);
             break;
             break;
-        case InputKeyDown:
-            // Camera: Reduce contrast.
+        }
+        // Camera: Reduce contrast.
+        case InputKeyDown: {
             data[0] = 'c';
             data[0] = 'c';
             with_view_model(
             with_view_model(
                 instance->view,
                 instance->view,
@@ -264,26 +259,35 @@ static bool camera_suite_view_camera_input(InputEvent* event, void* context) {
                 },
                 },
                 true);
                 true);
             break;
             break;
+        }
+        // Camera: Take picture.
         case InputKeyOk: {
         case InputKeyOk: {
-            // Take picture.
+            // Set up data to trigger picture sequence on the ESP32-CAM.
+            data[0] = 'P';
+            // Send `data` to the ESP32-CAM.
+            furi_hal_uart_tx(FuriHalUartIdUSART1, data, 1);
             with_view_model(
             with_view_model(
                 instance->view,
                 instance->view,
                 UartDumpModel * model,
                 UartDumpModel * model,
                 {
                 {
-                    // If flash is enabled, flash the onboard ESP32-CAM LED.
-                    camera_suite_play_happy_bump(instance->context);
+                    camera_suite_play_long_bump(instance->context);
                     camera_suite_play_input_sound(instance->context);
                     camera_suite_play_input_sound(instance->context);
                     camera_suite_led_set_rgb(instance->context, 0, 0, 255);
                     camera_suite_led_set_rgb(instance->context, 0, 0, 255);
+                    // Take a picture if the data is 'P'.
                     save_image(model);
                     save_image(model);
                     instance->callback(CameraSuiteCustomEventSceneCameraOk, instance->context);
                     instance->callback(CameraSuiteCustomEventSceneCameraOk, instance->context);
                 },
                 },
                 true);
                 true);
             return true;
             return true;
         }
         }
+        // Camera: Do nothing.
         case InputKeyMAX:
         case InputKeyMAX:
+        default: {
             break;
             break;
         }
         }
-        // Send `data` to the ESP32-CAM
+        }
+
+        // Send `data` to the ESP32-CAM.
         furi_hal_uart_tx(FuriHalUartIdUSART1, data, 1);
         furi_hal_uart_tx(FuriHalUartIdUSART1, data, 1);
     }
     }
     return true;
     return true;
@@ -300,9 +304,6 @@ static void camera_suite_view_camera_enter(void* context) {
     // Cast `context` to `CameraSuiteViewCamera*` and store it in `instance`.
     // Cast `context` to `CameraSuiteViewCamera*` and store it in `instance`.
     CameraSuiteViewCamera* instance = (CameraSuiteViewCamera*)context;
     CameraSuiteViewCamera* instance = (CameraSuiteViewCamera*)context;
 
 
-    // Assign the current instance to the global variable
-    current_instance = instance;
-
     uint8_t data[1];
     uint8_t data[1];
     data[0] = 'S'; // Uppercase `S` to start the camera
     data[0] = 'S'; // Uppercase `S` to start the camera
 
 
@@ -344,11 +345,15 @@ static void camera_suite_view_camera_enter(void* context) {
 
 
     // Send `data` as the flash bool to the ESP32-CAM
     // Send `data` as the flash bool to the ESP32-CAM
     furi_hal_uart_tx(FuriHalUartIdUSART1, data, 1);
     furi_hal_uart_tx(FuriHalUartIdUSART1, data, 1);
-
+    uint32_t orientation = instanceContext->orientation;
     with_view_model(
     with_view_model(
         instance->view,
         instance->view,
         UartDumpModel * model,
         UartDumpModel * model,
-        { camera_suite_view_camera_model_init(model); },
+        {
+            model->inverted = false;
+            model->orientation = orientation;
+            camera_suite_view_camera_model_init(model);
+        },
         true);
         true);
 }
 }
 
 
@@ -465,7 +470,7 @@ CameraSuiteViewCamera* camera_suite_view_camera_alloc() {
     // Allocate model
     // Allocate model
     view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(UartDumpModel));
     view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(UartDumpModel));
 
 
-    // Set context
+    // Set context for the view
     view_set_context(instance->view, instance);
     view_set_context(instance->view, instance);
 
 
     // Set draw callback
     // Set draw callback
@@ -503,6 +508,18 @@ CameraSuiteViewCamera* camera_suite_view_camera_alloc() {
 void camera_suite_view_camera_free(CameraSuiteViewCamera* instance) {
 void camera_suite_view_camera_free(CameraSuiteViewCamera* instance) {
     furi_assert(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->worker_thread);
+
+    // Free the allocated stream buffer.
+    furi_stream_buffer_free(instance->rx_stream);
+
+    // Re-enable the console.
+    furi_hal_console_enable();
+
     with_view_model(
     with_view_model(
         instance->view, UartDumpModel * model, { UNUSED(model); }, true);
         instance->view, UartDumpModel * model, { UNUSED(model); }, true);
     view_free(instance->view);
     view_free(instance->view);

+ 14 - 6
fap/views/camera_suite_view_camera.h

@@ -41,20 +41,28 @@ typedef enum {
 
 
 #define WORKER_EVENTS_MASK (WorkerEventStop | WorkerEventRx)
 #define WORKER_EVENTS_MASK (WorkerEventStop | WorkerEventRx)
 
 
+// Forward declaration
+typedef void (*CameraSuiteViewCameraCallback)(CameraSuiteCustomEvent event, void* context);
+
+typedef struct CameraSuiteViewCamera {
+    CameraSuiteViewCameraCallback callback;
+    FuriStreamBuffer* rx_stream;
+    FuriThread* worker_thread;
+    View* view;
+    void* context;
+} CameraSuiteViewCamera;
+
 typedef struct UartDumpModel {
 typedef struct UartDumpModel {
     bool initialized;
     bool initialized;
+    bool inverted;
     int rotation_angle;
     int rotation_angle;
+    uint32_t orientation;
     uint8_t pixels[FRAME_BUFFER_LENGTH];
     uint8_t pixels[FRAME_BUFFER_LENGTH];
     uint8_t ringbuffer_index;
     uint8_t ringbuffer_index;
-    uint8_t row_ringbuffer[RING_BUFFER_LENGTH];
     uint8_t row_identifier;
     uint8_t row_identifier;
+    uint8_t row_ringbuffer[RING_BUFFER_LENGTH];
 } UartDumpModel;
 } UartDumpModel;
 
 
-typedef struct CameraSuiteViewCamera CameraSuiteViewCamera;
-
-// Callback
-typedef void (*CameraSuiteViewCameraCallback)(CameraSuiteCustomEvent event, void* context);
-
 // Function Prototypes
 // Function Prototypes
 CameraSuiteViewCamera* camera_suite_view_camera_alloc();
 CameraSuiteViewCamera* camera_suite_view_camera_alloc();
 void camera_suite_view_camera_free(CameraSuiteViewCamera* camera_suite_static);
 void camera_suite_view_camera_free(CameraSuiteViewCamera* camera_suite_static);

+ 19 - 21
firmware/firmware.ino

@@ -100,25 +100,31 @@ void handleSerialInput()
     case '<': // Toggle invert.
     case '<': // Toggle invert.
       invert = !invert;
       invert = !invert;
       break;
       break;
+    case 'b': // Remove brightness.
+      cameraSensor->set_contrast(
+          cameraSensor,
+          cameraSensor->status.brightness - 1);
+      break;
     case 'B': // Add brightness.
     case 'B': // Add brightness.
       cameraSensor->set_contrast(
       cameraSensor->set_contrast(
           cameraSensor,
           cameraSensor,
           cameraSensor->status.brightness + 1);
           cameraSensor->status.brightness + 1);
       break;
       break;
-    case 'b': // Remove brightness.
+    case 'c': // Remove contrast.
       cameraSensor->set_contrast(
       cameraSensor->set_contrast(
           cameraSensor,
           cameraSensor,
-          cameraSensor->status.brightness - 1);
+          cameraSensor->status.contrast - 1);
       break;
       break;
     case 'C': // Add contrast.
     case 'C': // Add contrast.
       cameraSensor->set_contrast(
       cameraSensor->set_contrast(
           cameraSensor,
           cameraSensor,
           cameraSensor->status.contrast + 1);
           cameraSensor->status.contrast + 1);
       break;
       break;
-    case 'c': // Remove contrast.
-      cameraSensor->set_contrast(
-          cameraSensor,
-          cameraSensor->status.contrast - 1);
+    case 'f': // Toggle flash off.
+      isFlashEnabled = false;
+      break;
+    case 'F': // Toggle flash on.
+      isFlashEnabled = true;
       break;
       break;
     case 'j': // Toggle store jpeg to sd card off.
     case 'j': // Toggle store jpeg to sd card off.
       storeJpeg = false;
       storeJpeg = false;
@@ -127,37 +133,29 @@ void handleSerialInput()
       storeJpeg = true;
       storeJpeg = true;
       break;
       break;
     case 'P': // Picture sequence.
     case 'P': // Picture sequence.
-      // Stop the IO stream before taking a picture.
-      stopStream = true;
       if (isFlashEnabled)
       if (isFlashEnabled)
       {
       {
         // Turn on torch.
         // Turn on torch.
         pinMode(FLASH_GPIO_NUM, OUTPUT);
         pinMode(FLASH_GPIO_NUM, OUTPUT);
         digitalWrite(FLASH_GPIO_NUM, HIGH);
         digitalWrite(FLASH_GPIO_NUM, HIGH);
+        // Give some time (500ms) for Flipper to save locally with flash on.
+        delay(500);
+        // Turn off torch.
+        digitalWrite(FLASH_GPIO_NUM, LOW);
       }
       }
 
 
       // @todo - Future feature.
       // @todo - Future feature.
       // if (storeJpeg) { saveJpegPictureToSDCard(); }
       // if (storeJpeg) { saveJpegPictureToSDCard(); }
-
-      // Give some time (100ms) for Flipper to save locally with flash on.
-      delay(100);
-
-      // Turn off torch.
-      pinMode(FLASH_GPIO_NUM, OUTPUT);
-      digitalWrite(FLASH_GPIO_NUM, LOW);
-
-      // Restart the stream after the picture is taken.
-      stopStream = false;
       break;
       break;
     case 'M': // Toggle Mirror.
     case 'M': // Toggle Mirror.
       cameraSensor->set_hmirror(cameraSensor, !cameraSensor->status.hmirror);
       cameraSensor->set_hmirror(cameraSensor, !cameraSensor->status.hmirror);
       break;
       break;
-    case 'S': // Start stream.
-      stopStream = false;
-      break;
     case 's': // Stop stream.
     case 's': // Stop stream.
       stopStream = true;
       stopStream = true;
       break;
       break;
+    case 'S': // Start stream.
+      stopStream = false;
+      break;
     case '0': // Use Floyd Steinberg dithering.
     case '0': // Use Floyd Steinberg dithering.
       ditherAlgorithm = FLOYD_STEINBERG;
       ditherAlgorithm = FLOYD_STEINBERG;
       break;
       break;

+ 5 - 5
firware-flash.bat

@@ -93,10 +93,10 @@ echo Your ESP32-CAM is ready to be flashed. Please follow the instructions below
 :uploadFirmware
 :uploadFirmware
 echo.
 echo.
 echo 1. Ensure IO0 pin on ESP32-CAM is grounded to the proper GND pin.
 echo 1. Ensure IO0 pin on ESP32-CAM is grounded to the proper GND pin.
-echo 2. Hold reset, and plug in your ESP32-CAM; release reset a few seconds later.
-echo 3. As you proceed, release the reset button simultaneously with the next step.
+echo 2. Hold reset, and plug in your ESP32-CAM; hold for a few seconds and release.
+echo 3. Try to time your release simultaneously with continuing to the next step.
 echo 4. ESP32-CAM should now be in flash mode; allow some time for firmware upload.
 echo 4. ESP32-CAM should now be in flash mode; allow some time for firmware upload.
-echo 5. Failure is common; persist and verify all connections if errors persist.
+echo 5. Failure is common; verify all connections if errors persist and try again.
 echo 6. Disconnecting and reconnecting USB between attempts may sometimes work.
 echo 6. Disconnecting and reconnecting USB between attempts may sometimes work.
 echo.
 echo.
 pause
 pause
@@ -115,7 +115,7 @@ if !ERRORLEVEL! EQU 0 (
         goto :uploadLoop
         goto :uploadLoop
     ) else (
     ) else (
         echo.
         echo.
-        set /p UPLOAD_TRY_AGAIN="Upload failed after 3 attempts, don't give up! Would you like to try again? (Y/N): "
+        set /p UPLOAD_TRY_AGAIN="Upload failed after 3 attempts, dont give up friend. Would you like to try again? (Y/N): "
         if /i "!UPLOAD_TRY_AGAIN!"=="Y" (
         if /i "!UPLOAD_TRY_AGAIN!"=="Y" (
             set RETRY_COUNT=1
             set RETRY_COUNT=1
             goto :uploadFirmware
             goto :uploadFirmware
@@ -140,7 +140,7 @@ if /i "!DELETE_TEMP!"=="Y" (
     rmdir /s /q %CLI_TEMP%
     rmdir /s /q %CLI_TEMP%
 )
 )
 echo.
 echo.
-echo Fin. Happy programming friend.
+echo Fin. Happy programming.
 echo.
 echo.
 pause
 pause
 exit /b
 exit /b