MX 1 год назад
Родитель
Сommit
03f9ea1ea0

+ 1 - 3
application.fam

@@ -7,9 +7,7 @@ App(
     fap_category="GPIO",
     fap_category="GPIO",
     fap_description="A camera suite application for the Flipper Zero ESP32-CAM module.",
     fap_description="A camera suite application for the Flipper Zero ESP32-CAM module.",
     fap_icon="icons/camera_suite.png",
     fap_icon="icons/camera_suite.png",
-    fap_icon_assets="assets",
-    fap_libs=["assets"],
-    fap_version="1.4",
+    fap_version="1.7",
     fap_weburl="https://github.com/CodyTolene/Flipper-Zero-Cam",
     fap_weburl="https://github.com/CodyTolene/Flipper-Zero-Cam",
     name="[ESP32] Camera Suite",
     name="[ESP32] Camera Suite",
     order=1,
     order=1,

+ 0 - 0
assets/.gitkeep


BIN
assets/DolphinCommon_56x48.png


+ 15 - 7
camera_suite.c

@@ -43,16 +43,18 @@ CameraSuite* camera_suite_app_alloc() {
         app->view_dispatcher, camera_suite_custom_event_callback);
         app->view_dispatcher, camera_suite_custom_event_callback);
     app->submenu = submenu_alloc();
     app->submenu = submenu_alloc();
 
 
-    // Set defaults, in case no config loaded
-    app->orientation = 0; // Orientation is "portrait", zero degrees by default.
-    app->dither = 0; // Dither algorithm is "Floyd Steinberg" by default.
-    app->flash = 1; // Flash is enabled by default.
+    // Set app default settings values.
     app->haptic = 1; // Haptic is enabled by default
     app->haptic = 1; // Haptic is enabled by default
     app->jpeg = 0; // Save JPEG to ESP32-CAM sd-card is disabled by default.
     app->jpeg = 0; // Save JPEG to ESP32-CAM sd-card is disabled by default.
     app->speaker = 1; // Speaker is enabled by default
     app->speaker = 1; // Speaker is enabled by default
     app->led = 1; // LED is enabled by default
     app->led = 1; // LED is enabled by default
 
 
-    // Load configs
+    // Set cam default settings values.
+    app->orientation = 0; // Orientation is "portrait", zero degrees by default.
+    app->dither = 0; // Dither algorithm is "Floyd Steinberg" by default.
+    app->flash = 1; // Flash is enabled by default.
+
+    // Load configs if available (overrides defaults).
     camera_suite_read_settings(app);
     camera_suite_read_settings(app);
 
 
     view_dispatcher_add_view(
     view_dispatcher_add_view(
@@ -81,7 +83,11 @@ CameraSuite* camera_suite_app_alloc() {
     app->variable_item_list = variable_item_list_alloc();
     app->variable_item_list = variable_item_list_alloc();
     view_dispatcher_add_view(
     view_dispatcher_add_view(
         app->view_dispatcher,
         app->view_dispatcher,
-        CameraSuiteViewIdSettings,
+        CameraSuiteViewIdAppSettings,
+        variable_item_list_get_view(app->variable_item_list));
+    view_dispatcher_add_view(
+        app->view_dispatcher,
+        CameraSuiteViewIdCamSettings,
         variable_item_list_get_view(app->variable_item_list));
         variable_item_list_get_view(app->variable_item_list));
 
 
     //End Scene Additions
     //End Scene Additions
@@ -100,7 +106,8 @@ void camera_suite_app_free(CameraSuite* app) {
     view_dispatcher_remove_view(app->view_dispatcher, CameraSuiteViewIdMenu);
     view_dispatcher_remove_view(app->view_dispatcher, CameraSuiteViewIdMenu);
     view_dispatcher_remove_view(app->view_dispatcher, CameraSuiteViewIdCamera);
     view_dispatcher_remove_view(app->view_dispatcher, CameraSuiteViewIdCamera);
     view_dispatcher_remove_view(app->view_dispatcher, CameraSuiteViewIdGuide);
     view_dispatcher_remove_view(app->view_dispatcher, CameraSuiteViewIdGuide);
-    view_dispatcher_remove_view(app->view_dispatcher, CameraSuiteViewIdSettings);
+    view_dispatcher_remove_view(app->view_dispatcher, CameraSuiteViewIdAppSettings);
+    view_dispatcher_remove_view(app->view_dispatcher, CameraSuiteViewIdCamSettings);
     submenu_free(app->submenu);
     submenu_free(app->submenu);
 
 
     view_dispatcher_free(app->view_dispatcher);
     view_dispatcher_free(app->view_dispatcher);
@@ -110,6 +117,7 @@ void camera_suite_app_free(CameraSuite* app) {
     camera_suite_view_start_free(app->camera_suite_view_start);
     camera_suite_view_start_free(app->camera_suite_view_start);
     camera_suite_view_camera_free(app->camera_suite_view_camera);
     camera_suite_view_camera_free(app->camera_suite_view_camera);
     camera_suite_view_guide_free(app->camera_suite_view_guide);
     camera_suite_view_guide_free(app->camera_suite_view_guide);
+
     button_menu_free(app->button_menu);
     button_menu_free(app->button_menu);
     variable_item_list_free(app->variable_item_list);
     variable_item_list_free(app->variable_item_list);
 
 

+ 2 - 1
camera_suite.h

@@ -45,7 +45,8 @@ typedef enum {
     CameraSuiteViewIdMenu,
     CameraSuiteViewIdMenu,
     CameraSuiteViewIdCamera,
     CameraSuiteViewIdCamera,
     CameraSuiteViewIdGuide,
     CameraSuiteViewIdGuide,
-    CameraSuiteViewIdSettings,
+    CameraSuiteViewIdAppSettings,
+    CameraSuiteViewIdCamSettings,
 } CameraSuiteViewId;
 } CameraSuiteViewId;
 
 
 typedef enum {
 typedef enum {

+ 27 - 10
docs/CHANGELOG.md

@@ -1,8 +1,28 @@
-## Roadmap
+# Roadmap
 
 
 - Store images to onboard ESP32-CAM SD card (partially completed, #24).
 - Store images to onboard ESP32-CAM SD card (partially completed, #24).
 - Camera preview GUI overlay (#21).
 - Camera preview GUI overlay (#21).
 - Full screen 90 degree and 270 degree fill (#6).
 - Full screen 90 degree and 270 degree fill (#6).
+- WiFi streaming/connection support (#35).
+
+## v1.7
+
+- Add support for new Flipper Zero Firmware UART updates.
+- Remove staged WiFi streaming/connection support for now. Until I can fully test.
+
+## v1.6
+
+- Add new splash/start screen.
+- Add new module not connected notification + pinout guide in-app.
+- Update README with a new "Special Thanks" section.
+- Update README "Contributions" section regarding firmware development.
+- Separate settings into two views: app and cam settings.
+- General code improvements and cleanup.
+- Stage new scene for WiFi streaming/connection support (#35).
+
+## v1.5
+
+- Remove usage of image no longer found in the Flipper Zero firmware build.
 
 
 ## v1.4
 ## v1.4
 
 
@@ -12,9 +32,6 @@
 - Improve Firmware flashing utility code.
 - Improve Firmware flashing utility code.
 - Improve GitHub actions code.
 - Improve GitHub actions code.
 - Look to mitigate issue "Mirrored Image" #27.
 - Look to mitigate issue "Mirrored Image" #27.
-
-## v1.3.1 (patch)
-
 - Addressed new linting issue with "ufbt" tools.
 - Addressed new linting issue with "ufbt" tools.
 
 
 ## v1.3
 ## v1.3
@@ -36,25 +53,25 @@
 - Update documentation to reflect changes.
 - Update documentation to reflect changes.
 - Update firmware with new dithering options set.
 - Update firmware with new dithering options set.
 - Update firmware with new flash support.
 - Update firmware with new flash support.
-- Update repo to reflect https://github.com/CodyTolene/Flipper-Zero-Development-Toolkit for easier tooling.
+- Update repo to reflect <https://github.com/CodyTolene/Flipper-Zero-Development-Toolkit> for easier tooling.
 
 
 ## v1.1
 ## v1.1
 
 
 - Support and picture stabilization for all camera orientations (0 degree, 90 degree, 180 degree, and 270 degree).
 - Support and picture stabilization for all camera orientations (0 degree, 90 degree, 180 degree, and 270 degree).
 - Rename "Scene 1" to "Camera". No UX changes there.
 - Rename "Scene 1" to "Camera". No UX changes there.
 - Clean up unused "Scene 2". This was inaccessible to users previously and unused.
 - Clean up unused "Scene 2". This was inaccessible to users previously and unused.
-- Add new dithering variations (requires the latest firmware installation, see here for the installation guide https://github.com/CodyTolene/Flipper-Zero-Camera-Suite#firmware-installation):
+- Add new dithering variations (requires the latest firmware installation, see here for the installation guide <https://github.com/CodyTolene/Flipper-Zero-Camera-Suite#firmware-installation>):
   - "Jarvis Judice Ninke" dithering option
   - "Jarvis Judice Ninke" dithering option
   - "Stucki" dithering option.
   - "Stucki" dithering option.
   - "Floyd-Steinberg" dithering option.
   - "Floyd-Steinberg" dithering option.
   - Cycle through the dithering options with the center button on the Flipper Zero.
   - Cycle through the dithering options with the center button on the Flipper Zero.
-- Resolves issue https://github.com/CodyTolene/Flipper-Zero-Camera-Suite/issues/7
-- Resolves issue https://github.com/CodyTolene/Flipper-Zero-Camera-Suite/pull/17
+- Resolves issue <https://github.com/CodyTolene/Flipper-Zero-Camera-Suite/issues/7>
+- Resolves issue <https://github.com/CodyTolene/Flipper-Zero-Camera-Suite/pull/17>
 
 
 ## v1.0
 ## v1.0
 
 
-- Builds upon Z4urce's software found here (updated 6 months ago): https://github.com/Z4urce/flipperzero-camera
-- Utilizes the superb C boilerplate examples laid out by leedave (updated last month): https://github.com/leedave/flipper-zero-fap-boilerplate
+- Builds upon Z4urce's software found here (updated 6 months ago): <https://github.com/Z4urce/flipperzero-camera>
+- Utilizes the superb C boilerplate examples laid out by leedave (updated last month): <https://github.com/leedave/flipper-zero-fap-boilerplate>
 - Builds upon the "Camera" software into the new "Camera Suite" application with new usage:
 - Builds upon the "Camera" software into the new "Camera Suite" application with new usage:
   - Add a scene for a guide.
   - Add a scene for a guide.
   - Add a scene for settings.
   - Add a scene for settings.

+ 5 - 5
docs/README.md

@@ -10,9 +10,9 @@ Firmware is needed for the ESP32-CAM module, see here for more information: http
 
 
 Button mappings:
 Button mappings:
 
 
-**Up** = Contrast Up
+**Up** = Contrast Up.
 
 
-**Down** = Contrast Down
+**Down** = Contrast Down.
 
 
 **Left** = Toggle invert.
 **Left** = Toggle invert.
 
 
@@ -30,8 +30,8 @@ Settings:
 
 
 **Dithering Type** Change between the Cycle Floyd–Steinberg, Jarvis-Judice-Ninke, and Stucki dithering types.
 **Dithering Type** Change between the Cycle Floyd–Steinberg, Jarvis-Judice-Ninke, and Stucki dithering types.
 
 
-**Haptic FX** = Toggle haptic feedback on/off.
+**Haptic Effects** = Toggle haptic feedback on/off.
 
 
-**Sound FX** = Toggle sound effects on/off.
+**Sound Effects** = Toggle sound effects on/off.
 
 
-**LED FX** = Toggle LED effects on/off.
+**LED Effects** = Toggle LED effects on/off.

+ 111 - 0
scenes/camera_suite_scene_app_settings.c

@@ -0,0 +1,111 @@
+#include "../camera_suite.h"
+#include <lib/toolbox/value_index.h>
+
+const char* const haptic_text[2] = {
+    "OFF",
+    "ON",
+};
+
+const uint32_t haptic_value[2] = {
+    CameraSuiteHapticOff,
+    CameraSuiteHapticOn,
+};
+
+const char* const speaker_text[2] = {
+    "OFF",
+    "ON",
+};
+
+const uint32_t speaker_value[2] = {
+    CameraSuiteSpeakerOff,
+    CameraSuiteSpeakerOn,
+};
+
+const char* const led_text[2] = {
+    "OFF",
+    "ON",
+};
+
+const uint32_t led_value[2] = {
+    CameraSuiteLedOff,
+    CameraSuiteLedOn,
+};
+
+static void camera_suite_scene_app_settings_set_haptic(VariableItem* item) {
+    CameraSuite* app = variable_item_get_context(item);
+    uint8_t index = variable_item_get_current_value_index(item);
+
+    variable_item_set_current_value_text(item, haptic_text[index]);
+    app->haptic = haptic_value[index];
+}
+
+static void camera_suite_scene_app_settings_set_speaker(VariableItem* item) {
+    CameraSuite* app = variable_item_get_context(item);
+    uint8_t index = variable_item_get_current_value_index(item);
+    variable_item_set_current_value_text(item, speaker_text[index]);
+    app->speaker = speaker_value[index];
+}
+
+static void camera_suite_scene_app_settings_set_led(VariableItem* item) {
+    CameraSuite* app = variable_item_get_context(item);
+    uint8_t index = variable_item_get_current_value_index(item);
+    variable_item_set_current_value_text(item, led_text[index]);
+    app->led = led_value[index];
+}
+
+void camera_suite_scene_app_settings_submenu_callback(void* context, uint32_t index) {
+    CameraSuite* app = context;
+    view_dispatcher_send_custom_event(app->view_dispatcher, index);
+}
+
+void camera_suite_scene_app_settings_on_enter(void* context) {
+    CameraSuite* app = context;
+    VariableItem* item;
+    uint8_t value_index;
+
+    // Haptic Effects ON/OFF
+    item = variable_item_list_add(
+        app->variable_item_list,
+        "Haptic Effects:",
+        2,
+        camera_suite_scene_app_settings_set_haptic,
+        app);
+    value_index = value_index_uint32(app->haptic, haptic_value, 2);
+    variable_item_set_current_value_index(item, value_index);
+    variable_item_set_current_value_text(item, haptic_text[value_index]);
+
+    // Sound Effects ON/OFF
+    item = variable_item_list_add(
+        app->variable_item_list,
+        "Sound Effects:",
+        2,
+        camera_suite_scene_app_settings_set_speaker,
+        app);
+    value_index = value_index_uint32(app->speaker, speaker_value, 2);
+    variable_item_set_current_value_index(item, value_index);
+    variable_item_set_current_value_text(item, speaker_text[value_index]);
+
+    // LED Effects ON/OFF
+    item = variable_item_list_add(
+        app->variable_item_list, "LED Effects:", 2, camera_suite_scene_app_settings_set_led, app);
+    value_index = value_index_uint32(app->led, led_value, 2);
+    variable_item_set_current_value_index(item, value_index);
+    variable_item_set_current_value_text(item, led_text[value_index]);
+
+    view_dispatcher_switch_to_view(app->view_dispatcher, CameraSuiteViewIdAppSettings);
+}
+
+bool camera_suite_scene_app_settings_on_event(void* context, SceneManagerEvent event) {
+    CameraSuite* app = context;
+    UNUSED(app);
+    bool consumed = false;
+    if(event.type == SceneManagerEventTypeCustom) {
+    }
+    return consumed;
+}
+
+void camera_suite_scene_app_settings_on_exit(void* context) {
+    CameraSuite* app = context;
+    variable_item_list_set_selected_item(app->variable_item_list, 0);
+    variable_item_list_reset(app->variable_item_list);
+}

+ 15 - 88
scenes/camera_suite_scene_settings.c → scenes/camera_suite_scene_cam_settings.c

@@ -49,37 +49,7 @@ const uint32_t jpeg_value[2] = {
     CameraSuiteJpegOn,
     CameraSuiteJpegOn,
 };
 };
 
 
-const char* const haptic_text[2] = {
-    "OFF",
-    "ON",
-};
-
-const uint32_t haptic_value[2] = {
-    CameraSuiteHapticOff,
-    CameraSuiteHapticOn,
-};
-
-const char* const speaker_text[2] = {
-    "OFF",
-    "ON",
-};
-
-const uint32_t speaker_value[2] = {
-    CameraSuiteSpeakerOff,
-    CameraSuiteSpeakerOn,
-};
-
-const char* const led_text[2] = {
-    "OFF",
-    "ON",
-};
-
-const uint32_t led_value[2] = {
-    CameraSuiteLedOff,
-    CameraSuiteLedOn,
-};
-
-static void camera_suite_scene_settings_set_camera_orientation(VariableItem* item) {
+static void camera_suite_scene_cam_settings_set_camera_orientation(VariableItem* item) {
     CameraSuite* app = variable_item_get_context(item);
     CameraSuite* app = variable_item_get_context(item);
     uint8_t index = variable_item_get_current_value_index(item);
     uint8_t index = variable_item_get_current_value_index(item);
 
 
@@ -87,7 +57,7 @@ static void camera_suite_scene_settings_set_camera_orientation(VariableItem* ite
     app->orientation = orientation_value[index];
     app->orientation = orientation_value[index];
 }
 }
 
 
-static void camera_suite_scene_settings_set_camera_dither(VariableItem* item) {
+static void camera_suite_scene_cam_settings_set_camera_dither(VariableItem* item) {
     CameraSuite* app = variable_item_get_context(item);
     CameraSuite* app = variable_item_get_context(item);
     uint8_t index = variable_item_get_current_value_index(item);
     uint8_t index = variable_item_get_current_value_index(item);
 
 
@@ -95,7 +65,7 @@ static void camera_suite_scene_settings_set_camera_dither(VariableItem* item) {
     app->dither = dither_value[index];
     app->dither = dither_value[index];
 }
 }
 
 
-static void camera_suite_scene_settings_set_flash(VariableItem* item) {
+static void camera_suite_scene_cam_settings_set_flash(VariableItem* item) {
     CameraSuite* app = variable_item_get_context(item);
     CameraSuite* app = variable_item_get_context(item);
     uint8_t index = variable_item_get_current_value_index(item);
     uint8_t index = variable_item_get_current_value_index(item);
 
 
@@ -103,7 +73,7 @@ static void camera_suite_scene_settings_set_flash(VariableItem* item) {
     app->flash = flash_value[index];
     app->flash = flash_value[index];
 }
 }
 
 
-static void camera_suite_scene_settings_set_jpeg(VariableItem* item) {
+static void camera_suite_scene_cam_settings_set_jpeg(VariableItem* item) {
     CameraSuite* app = variable_item_get_context(item);
     CameraSuite* app = variable_item_get_context(item);
     uint8_t index = variable_item_get_current_value_index(item);
     uint8_t index = variable_item_get_current_value_index(item);
 
 
@@ -111,34 +81,12 @@ static void camera_suite_scene_settings_set_jpeg(VariableItem* item) {
     app->jpeg = jpeg_value[index];
     app->jpeg = jpeg_value[index];
 }
 }
 
 
-static void camera_suite_scene_settings_set_haptic(VariableItem* item) {
-    CameraSuite* app = variable_item_get_context(item);
-    uint8_t index = variable_item_get_current_value_index(item);
-
-    variable_item_set_current_value_text(item, haptic_text[index]);
-    app->haptic = haptic_value[index];
-}
-
-static void camera_suite_scene_settings_set_speaker(VariableItem* item) {
-    CameraSuite* app = variable_item_get_context(item);
-    uint8_t index = variable_item_get_current_value_index(item);
-    variable_item_set_current_value_text(item, speaker_text[index]);
-    app->speaker = speaker_value[index];
-}
-
-static void camera_suite_scene_settings_set_led(VariableItem* item) {
-    CameraSuite* app = variable_item_get_context(item);
-    uint8_t index = variable_item_get_current_value_index(item);
-    variable_item_set_current_value_text(item, led_text[index]);
-    app->led = led_value[index];
-}
-
-void camera_suite_scene_settings_submenu_callback(void* context, uint32_t index) {
+void camera_suite_scene_cam_settings_submenu_callback(void* context, uint32_t index) {
     CameraSuite* app = context;
     CameraSuite* app = context;
     view_dispatcher_send_custom_event(app->view_dispatcher, index);
     view_dispatcher_send_custom_event(app->view_dispatcher, index);
 }
 }
 
 
-void camera_suite_scene_settings_on_enter(void* context) {
+void camera_suite_scene_cam_settings_on_enter(void* context) {
     CameraSuite* app = context;
     CameraSuite* app = context;
     VariableItem* item;
     VariableItem* item;
     uint8_t value_index;
     uint8_t value_index;
@@ -148,7 +96,7 @@ void camera_suite_scene_settings_on_enter(void* context) {
         app->variable_item_list,
         app->variable_item_list,
         "Orientation:",
         "Orientation:",
         4,
         4,
-        camera_suite_scene_settings_set_camera_orientation,
+        camera_suite_scene_cam_settings_set_camera_orientation,
         app);
         app);
     value_index = value_index_uint32(app->orientation, orientation_value, 4);
     value_index = value_index_uint32(app->orientation, orientation_value, 4);
     variable_item_set_current_value_index(item, value_index);
     variable_item_set_current_value_index(item, value_index);
@@ -159,7 +107,7 @@ void camera_suite_scene_settings_on_enter(void* context) {
         app->variable_item_list,
         app->variable_item_list,
         "Dithering Type:",
         "Dithering Type:",
         3,
         3,
-        camera_suite_scene_settings_set_camera_dither,
+        camera_suite_scene_cam_settings_set_camera_dither,
         app);
         app);
     value_index = value_index_uint32(app->dither, dither_value, 3);
     value_index = value_index_uint32(app->dither, dither_value, 3);
     variable_item_set_current_value_index(item, value_index);
     variable_item_set_current_value_index(item, value_index);
@@ -167,7 +115,7 @@ void camera_suite_scene_settings_on_enter(void* context) {
 
 
     // Flash ON/OFF
     // Flash ON/OFF
     item = variable_item_list_add(
     item = variable_item_list_add(
-        app->variable_item_list, "Flash:", 2, camera_suite_scene_settings_set_flash, app);
+        app->variable_item_list, "Flash:", 2, camera_suite_scene_cam_settings_set_flash, app);
     value_index = value_index_uint32(app->flash, flash_value, 2);
     value_index = value_index_uint32(app->flash, flash_value, 2);
     variable_item_set_current_value_index(item, value_index);
     variable_item_set_current_value_index(item, value_index);
     variable_item_set_current_value_text(item, flash_text[value_index]);
     variable_item_set_current_value_text(item, flash_text[value_index]);
@@ -179,38 +127,17 @@ void camera_suite_scene_settings_on_enter(void* context) {
     //     app->variable_item_list,
     //     app->variable_item_list,
     //     "Save JPEG to ext sdcard:",
     //     "Save JPEG to ext sdcard:",
     //     2,
     //     2,
-    //     camera_suite_scene_settings_set_jpeg,
+    //     camera_suite_scene_cam_settings_set_jpeg,
     //     app);
     //     app);
     // value_index = value_index_uint32(app->jpeg, jpeg_value, 2);
     // value_index = value_index_uint32(app->jpeg, jpeg_value, 2);
     // variable_item_set_current_value_index(item, value_index);
     // variable_item_set_current_value_index(item, value_index);
     // variable_item_set_current_value_text(item, jpeg_text[value_index]);
     // variable_item_set_current_value_text(item, jpeg_text[value_index]);
-    UNUSED(camera_suite_scene_settings_set_jpeg);
+    UNUSED(camera_suite_scene_cam_settings_set_jpeg);
 
 
-    // Haptic FX ON/OFF
-    item = variable_item_list_add(
-        app->variable_item_list, "Haptic FX:", 2, camera_suite_scene_settings_set_haptic, app);
-    value_index = value_index_uint32(app->haptic, haptic_value, 2);
-    variable_item_set_current_value_index(item, value_index);
-    variable_item_set_current_value_text(item, haptic_text[value_index]);
-
-    // Sound FX ON/OFF
-    item = variable_item_list_add(
-        app->variable_item_list, "Sound FX:", 2, camera_suite_scene_settings_set_speaker, app);
-    value_index = value_index_uint32(app->speaker, speaker_value, 2);
-    variable_item_set_current_value_index(item, value_index);
-    variable_item_set_current_value_text(item, speaker_text[value_index]);
-
-    // LED FX ON/OFF
-    item = variable_item_list_add(
-        app->variable_item_list, "LED FX:", 2, camera_suite_scene_settings_set_led, app);
-    value_index = value_index_uint32(app->led, led_value, 2);
-    variable_item_set_current_value_index(item, value_index);
-    variable_item_set_current_value_text(item, led_text[value_index]);
-
-    view_dispatcher_switch_to_view(app->view_dispatcher, CameraSuiteViewIdSettings);
+    view_dispatcher_switch_to_view(app->view_dispatcher, CameraSuiteViewIdCamSettings);
 }
 }
 
 
-bool camera_suite_scene_settings_on_event(void* context, SceneManagerEvent event) {
+bool camera_suite_scene_cam_settings_on_event(void* context, SceneManagerEvent event) {
     CameraSuite* app = context;
     CameraSuite* app = context;
     UNUSED(app);
     UNUSED(app);
     bool consumed = false;
     bool consumed = false;
@@ -219,8 +146,8 @@ bool camera_suite_scene_settings_on_event(void* context, SceneManagerEvent event
     return consumed;
     return consumed;
 }
 }
 
 
-void camera_suite_scene_settings_on_exit(void* context) {
+void camera_suite_scene_cam_settings_on_exit(void* context) {
     CameraSuite* app = context;
     CameraSuite* app = context;
     variable_item_list_set_selected_item(app->variable_item_list, 0);
     variable_item_list_set_selected_item(app->variable_item_list, 0);
     variable_item_list_reset(app->variable_item_list);
     variable_item_list_reset(app->variable_item_list);
-}
+}

+ 2 - 1
scenes/camera_suite_scene_config.h

@@ -2,4 +2,5 @@ ADD_SCENE(camera_suite, start, Start)
 ADD_SCENE(camera_suite, menu, Menu)
 ADD_SCENE(camera_suite, menu, Menu)
 ADD_SCENE(camera_suite, camera, Camera)
 ADD_SCENE(camera_suite, camera, Camera)
 ADD_SCENE(camera_suite, guide, Guide)
 ADD_SCENE(camera_suite, guide, Guide)
-ADD_SCENE(camera_suite, settings, Settings)
+ADD_SCENE(camera_suite, app_settings, AppSettings)
+ADD_SCENE(camera_suite, cam_settings, CamSettings)

+ 31 - 11
scenes/camera_suite_scene_menu.c

@@ -3,10 +3,12 @@
 enum SubmenuIndex {
 enum SubmenuIndex {
     /** Camera. */
     /** Camera. */
     SubmenuIndexSceneCamera = 10,
     SubmenuIndexSceneCamera = 10,
+    /** Cam settings menu. */
+    SubmenuIndexCamSettings,
+    /** App settings menu. */
+    SubmenuIndexAppSettings,
     /** Guide/how-to. */
     /** Guide/how-to. */
     SubmenuIndexGuide,
     SubmenuIndexGuide,
-    /** Settings menu. */
-    SubmenuIndexSettings,
 };
 };
 
 
 void camera_suite_scene_menu_submenu_callback(void* context, uint32_t index) {
 void camera_suite_scene_menu_submenu_callback(void* context, uint32_t index) {
@@ -19,16 +21,29 @@ void camera_suite_scene_menu_on_enter(void* context) {
 
 
     submenu_add_item(
     submenu_add_item(
         app->submenu,
         app->submenu,
-        "Open Camera",
+        "Stream Camera to Screen",
         SubmenuIndexSceneCamera,
         SubmenuIndexSceneCamera,
         camera_suite_scene_menu_submenu_callback,
         camera_suite_scene_menu_submenu_callback,
         app);
         app);
+
+    submenu_add_item(
+        app->submenu,
+        "Camera Settings",
+        SubmenuIndexCamSettings,
+        camera_suite_scene_menu_submenu_callback,
+        app);
+
     submenu_add_item(
     submenu_add_item(
-        app->submenu, "Guide", SubmenuIndexGuide, camera_suite_scene_menu_submenu_callback, app);
+        app->submenu,
+        "Application Settings",
+        SubmenuIndexAppSettings,
+        camera_suite_scene_menu_submenu_callback,
+        app);
+
     submenu_add_item(
     submenu_add_item(
         app->submenu,
         app->submenu,
-        "Settings",
-        SubmenuIndexSettings,
+        "Camera Suite Guide",
+        SubmenuIndexGuide,
         camera_suite_scene_menu_submenu_callback,
         camera_suite_scene_menu_submenu_callback,
         app);
         app);
 
 
@@ -52,16 +67,21 @@ bool camera_suite_scene_menu_on_event(void* context, SceneManagerEvent event) {
                 app->scene_manager, CameraSuiteSceneMenu, SubmenuIndexSceneCamera);
                 app->scene_manager, CameraSuiteSceneMenu, SubmenuIndexSceneCamera);
             scene_manager_next_scene(app->scene_manager, CameraSuiteSceneCamera);
             scene_manager_next_scene(app->scene_manager, CameraSuiteSceneCamera);
             return true;
             return true;
+        } else if(event.event == SubmenuIndexAppSettings) {
+            scene_manager_set_scene_state(
+                app->scene_manager, CameraSuiteSceneMenu, SubmenuIndexAppSettings);
+            scene_manager_next_scene(app->scene_manager, CameraSuiteSceneAppSettings);
+            return true;
+        } else if(event.event == SubmenuIndexCamSettings) {
+            scene_manager_set_scene_state(
+                app->scene_manager, CameraSuiteSceneMenu, SubmenuIndexCamSettings);
+            scene_manager_next_scene(app->scene_manager, CameraSuiteSceneCamSettings);
+            return true;
         } else if(event.event == SubmenuIndexGuide) {
         } else if(event.event == SubmenuIndexGuide) {
             scene_manager_set_scene_state(
             scene_manager_set_scene_state(
                 app->scene_manager, CameraSuiteSceneMenu, SubmenuIndexGuide);
                 app->scene_manager, CameraSuiteSceneMenu, SubmenuIndexGuide);
             scene_manager_next_scene(app->scene_manager, CameraSuiteSceneGuide);
             scene_manager_next_scene(app->scene_manager, CameraSuiteSceneGuide);
             return true;
             return true;
-        } else if(event.event == SubmenuIndexSettings) {
-            scene_manager_set_scene_state(
-                app->scene_manager, CameraSuiteSceneMenu, SubmenuIndexSettings);
-            scene_manager_next_scene(app->scene_manager, CameraSuiteSceneSettings);
-            return true;
         }
         }
     }
     }
     return false;
     return false;

BIN
screenshots/camera.png


BIN
screenshots/guide.png


BIN
screenshots/guide_connect.png


BIN
screenshots/main_menu.png


BIN
screenshots/settings.png


BIN
screenshots/settings_app.png


BIN
screenshots/settings_camera.png


BIN
screenshots/start_screen.png


+ 136 - 29
views/camera_suite_view_camera.c

@@ -59,15 +59,100 @@ static void camera_suite_view_camera_draw(Canvas* canvas, void* model) {
         }
         }
     }
     }
 
 
-    // Draw the guide if the camera is not initialized.
+    // Draw the pinout guide if the camera is not initialized.
     if(!uartDumpModel->is_initialized) {
     if(!uartDumpModel->is_initialized) {
-        canvas_draw_icon(canvas, 74, 16, &I_DolphinCommon_56x48);
+        // Clear the screen.
+        canvas_clear(canvas);
+
+        // Draw the ESP32-CAM module.
+        canvas_set_font(canvas, FontSecondary);
+        canvas_draw_str(canvas, 47, 50, "ESP32");
+        canvas_set_font(canvas, FontSecondary);
+        canvas_draw_str(canvas, 52, 58, "CAM");
+        canvas_draw_dot(canvas, 84, 3);
+        canvas_draw_box(canvas, 50, 35, 23, 7);
+        canvas_draw_circle(canvas, 42, 12, 1);
+        canvas_draw_circle(canvas, 42, 16, 1);
+        canvas_draw_circle(canvas, 42, 20, 1);
+        canvas_draw_circle(canvas, 42, 24, 1);
+        canvas_draw_circle(canvas, 42, 28, 1);
+        canvas_draw_circle(canvas, 42, 32, 1);
+        canvas_draw_circle(canvas, 42, 36, 1);
+        canvas_draw_circle(canvas, 42, 8, 1);
+        canvas_draw_circle(canvas, 59, 15, 1);
+        canvas_draw_circle(canvas, 61, 17, 5);
+        canvas_draw_circle(canvas, 61, 17, 9);
+        canvas_draw_circle(canvas, 80, 12, 1);
+        canvas_draw_circle(canvas, 80, 16, 1);
+        canvas_draw_circle(canvas, 80, 20, 1);
+        canvas_draw_circle(canvas, 80, 24, 1);
+        canvas_draw_circle(canvas, 80, 28, 1);
+        canvas_draw_circle(canvas, 80, 32, 1);
+        canvas_draw_circle(canvas, 80, 36, 1);
+        canvas_draw_circle(canvas, 80, 42, 1);
+        canvas_draw_circle(canvas, 80, 8, 1);
+        canvas_draw_line(canvas, 38, 4, 38, 58);
+        canvas_draw_line(canvas, 39, 3, 83, 3);
+        canvas_draw_line(canvas, 40, 2, 84, 2);
+        canvas_draw_line(canvas, 48, 4, 74, 4);
+        canvas_draw_line(canvas, 48, 5, 48, 26);
+        canvas_draw_line(canvas, 55, 27, 49, 27);
+        canvas_draw_line(canvas, 56, 25, 56, 36);
+        canvas_draw_line(canvas, 64, 21, 63, 21);
+        canvas_draw_line(canvas, 65, 15, 65, 17);
+        canvas_draw_line(canvas, 66, 15, 64, 18);
+        canvas_draw_line(canvas, 66, 16, 64, 19);
+        canvas_draw_line(canvas, 66, 18, 60, 21);
+        canvas_draw_line(canvas, 66, 19, 61, 21);
+        canvas_draw_line(canvas, 66, 25, 66, 36);
+        canvas_draw_line(canvas, 73, 27, 67, 27);
+        canvas_draw_line(canvas, 74, 5, 74, 26);
+        canvas_draw_line(canvas, 75, 4, 75, 25);
+        canvas_draw_line(canvas, 83, 59, 39, 59);
+        canvas_draw_line(canvas, 84, 4, 84, 58);
+        canvas_draw_line(canvas, 85, 2, 85, 57);
+        canvas_draw_frame(canvas, 78, 40, 5, 5);
+
+        // Draw the pinout lines.
+        canvas_draw_line(canvas, 39, 8, 21, 8);
+        canvas_draw_line(canvas, 87, 24, 83, 24);
+        canvas_draw_line(canvas, 87, 32, 83, 32);
+        canvas_draw_line(canvas, 88, 23, 88, 13);
+        canvas_draw_line(canvas, 88, 33, 88, 43);
+        canvas_draw_line(canvas, 89, 12, 126, 12);
+        canvas_draw_line(canvas, 126, 28, 83, 28);
+        canvas_draw_line(canvas, 126, 44, 89, 44);
+
+        // Draw the pinout labels.
+        canvas_set_font(canvas, FontSecondary);
+        canvas_draw_str(canvas, 91, 11, "VCC-3V");
+        canvas_set_font(canvas, FontSecondary);
+        canvas_draw_str(canvas, 91, 27, "U0R-TX");
+        canvas_set_font(canvas, FontSecondary);
+        canvas_draw_str(canvas, 91, 43, "U0T-RX");
+        canvas_set_font(canvas, FontSecondary);
+        canvas_draw_str(canvas, 2, 12, "GND");
+        canvas_set_font(canvas, FontSecondary);
+        canvas_draw_str(canvas, 12, 21, "-GND");
+
+        // Draw the "Please Connect Module!" text.
+        canvas_set_font(canvas, FontSecondary);
+        canvas_draw_str(canvas, 2, 40, "Please");
         canvas_set_font(canvas, FontSecondary);
         canvas_set_font(canvas, FontSecondary);
-        canvas_draw_str(canvas, 8, 12, "Connect the ESP32-CAM");
-        canvas_draw_str(canvas, 20, 24, "VCC - 3V3");
-        canvas_draw_str(canvas, 20, 34, "GND - GND");
-        canvas_draw_str(canvas, 20, 44, "U0R - TX");
-        canvas_draw_str(canvas, 20, 54, "U0T - RX");
+        canvas_draw_str(canvas, 2, 49, "Connect");
+        canvas_set_font(canvas, FontSecondary);
+        canvas_draw_str(canvas, 2, 58, "Module!");
+
+        // Draw the "Back" text and button logo.
+        canvas_set_font(canvas, FontSecondary);
+        canvas_draw_str(canvas, 92, 57, "Back");
+        canvas_draw_line(canvas, 116, 49, 116, 53);
+        canvas_draw_line(canvas, 115, 50, 115, 52);
+        canvas_draw_dot(canvas, 114, 51);
+        canvas_draw_line(canvas, 117, 51, 121, 51);
+        canvas_draw_line(canvas, 122, 52, 123, 53);
+        canvas_draw_line(canvas, 123, 54, 122, 55);
+        canvas_draw_line(canvas, 121, 56, 117, 56);
     }
     }
 }
 }
 
 
@@ -94,10 +179,20 @@ static void save_image_to_flipper_sd_card(void* model) {
     FuriString* file_name = furi_string_alloc();
     FuriString* file_name = furi_string_alloc();
 
 
     // Get the current date and time.
     // Get the current date and time.
+
+    // Not supported in "Release" F0 build.
+    // TODO: Remove when DateTime is supported in "Release" F0 build.
+    // FuriHalRtcDateTime datetime = {0};
+
+    // Only supported in "RC" & "Dev" builds.
+    // TODO: Uncomment when DateTime is supported in "Release" F0 build.
     DateTime datetime = {0};
     DateTime datetime = {0};
+
+    // TODO: Uncomment when DateTime is supported in "Release" F0 build.
     furi_hal_rtc_get_datetime(&datetime);
     furi_hal_rtc_get_datetime(&datetime);
 
 
-    // Create the file name.
+    // Create the file name using DateTime.
+    // TODO: Uncomment when DateTime is supported in "Release" F0 build.
     furi_string_printf(
     furi_string_printf(
         file_name,
         file_name,
         EXT_PATH("DCIM/%.4d%.2d%.2d-%.2d%.2d%.2d.bmp"),
         EXT_PATH("DCIM/%.4d%.2d%.2d-%.2d%.2d%.2d.bmp"),
@@ -108,6 +203,10 @@ static void save_image_to_flipper_sd_card(void* model) {
         datetime.minute,
         datetime.minute,
         datetime.second);
         datetime.second);
 
 
+    // Just use a random number for now instead of DateTime.
+    // int random_number = rand();
+    // furi_string_printf(file_name, EXT_PATH("DCIM/%d.bmp"), random_number);
+
     // Open the file for writing. If the file does not exist (it shouldn't),
     // Open the file for writing. If the file does not exist (it shouldn't),
     // create it.
     // create it.
     bool result =
     bool result =
@@ -332,6 +431,7 @@ static bool camera_suite_view_camera_input(InputEvent* event, void* context) {
         }
         }
         }
         }
     }
     }
+
     return false;
     return false;
 }
 }
 
 
@@ -382,12 +482,10 @@ static void
     // Cast `context` to `CameraSuiteViewCamera*` and store it in `instance`.
     // Cast `context` to `CameraSuiteViewCamera*` and store it in `instance`.
     CameraSuiteViewCamera* instance = context;
     CameraSuiteViewCamera* instance = context;
 
 
-    // If `uartIrqEvent` is `UartIrqEventRXNE`, send the data to the
-    // `rx_stream` and set the `WorkerEventRx` flag.
     if(event == FuriHalSerialRxEventData) {
     if(event == FuriHalSerialRxEventData) {
         uint8_t data = furi_hal_serial_async_rx(handle);
         uint8_t data = furi_hal_serial_async_rx(handle);
-        furi_stream_buffer_send(instance->rx_stream, &data, 1, 0);
-        furi_thread_flags_set(furi_thread_get_id(instance->worker_thread), WorkerEventRx);
+        furi_stream_buffer_send(instance->camera_rx_stream, &data, 1, 0);
+        furi_thread_flags_set(furi_thread_get_id(instance->camera_worker_thread), WorkerEventRx);
     }
     }
 }
 }
 
 
@@ -439,31 +537,39 @@ static void process_ringbuffer(UartDumpModel* model, uint8_t const byte) {
     }
     }
 }
 }
 
 
-static int32_t camera_worker(void* context) {
+static int32_t camera_suite_camera_worker(void* context) {
     furi_assert(context);
     furi_assert(context);
 
 
     CameraSuiteViewCamera* instance = context;
     CameraSuiteViewCamera* instance = context;
 
 
     while(1) {
     while(1) {
+        // Wait for any event on the worker thread.
         uint32_t events =
         uint32_t events =
-            furi_thread_flags_wait(WORKER_EVENTS_MASK, FuriFlagWaitAny, FuriWaitForever);
+            furi_thread_flags_wait(CAMERA_WORKER_EVENTS_MASK, FuriFlagWaitAny, FuriWaitForever);
+
+        // Check if an error occurred.
         furi_check((events & FuriFlagError) == 0);
         furi_check((events & FuriFlagError) == 0);
 
 
+        // Check if the thread should stop.
         if(events & WorkerEventStop) {
         if(events & WorkerEventStop) {
             break;
             break;
         } else if(events & WorkerEventRx) {
         } else if(events & WorkerEventRx) {
             size_t length = 0;
             size_t length = 0;
+            // Read all available data from the stream buffer.
             do {
             do {
-                size_t intended_data_size = 64;
-                uint8_t data[intended_data_size];
+                // Read up to 64 bytes from the stream buffer.
+                size_t buffer_size = 64;
+                // Allocate a buffer for the data.
+                uint8_t data[buffer_size];
+                // Read the data from the stream buffer.
                 length =
                 length =
-                    furi_stream_buffer_receive(instance->rx_stream, data, intended_data_size, 0);
-
+                    furi_stream_buffer_receive(instance->camera_rx_stream, data, buffer_size, 0);
                 if(length > 0) {
                 if(length > 0) {
                     with_view_model(
                     with_view_model(
                         instance->view,
                         instance->view,
                         UartDumpModel * model,
                         UartDumpModel * model,
                         {
                         {
+                            // Process the data.
                             for(size_t i = 0; i < length; i++) {
                             for(size_t i = 0; i < length; i++) {
                                 process_ringbuffer(model, data[i]);
                                 process_ringbuffer(model, data[i]);
                             }
                             }
@@ -488,7 +594,7 @@ CameraSuiteViewCamera* camera_suite_view_camera_alloc() {
     instance->view = view_alloc();
     instance->view = view_alloc();
 
 
     // Allocate a stream buffer
     // Allocate a stream buffer
-    instance->rx_stream = furi_stream_buffer_alloc(2048, 1);
+    instance->camera_rx_stream = furi_stream_buffer_alloc(2048, 1);
 
 
     // Allocate model
     // Allocate model
     view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(UartDumpModel));
     view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(UartDumpModel));
@@ -509,16 +615,17 @@ CameraSuiteViewCamera* camera_suite_view_camera_alloc() {
     view_set_exit_callback(instance->view, camera_suite_view_camera_exit);
     view_set_exit_callback(instance->view, camera_suite_view_camera_exit);
 
 
     // Allocate a thread for this camera to run on.
     // Allocate a thread for this camera to run on.
-    FuriThread* thread = furi_thread_alloc_ex("UsbUartWorker", 2048, camera_worker, instance);
-    instance->worker_thread = thread;
-    furi_thread_start(instance->worker_thread);
+    FuriThread* thread = furi_thread_alloc_ex(
+        "Camera_Suite_Camera_Rx_Thread", 2048, camera_suite_camera_worker, instance);
+    instance->camera_worker_thread = thread;
+    furi_thread_start(instance->camera_worker_thread);
 
 
-    // 115200 is the default baud rate for the ESP32-CAM.
+    // Allocate the serial handle for the camera.
     instance->serial_handle = furi_hal_serial_control_acquire(UART_CH);
     instance->serial_handle = furi_hal_serial_control_acquire(UART_CH);
     furi_check(instance->serial_handle);
     furi_check(instance->serial_handle);
     furi_hal_serial_init(instance->serial_handle, 230400);
     furi_hal_serial_init(instance->serial_handle, 230400);
 
 
-    // Enable UART1 and set the IRQ callback.
+    // Start the asynchronous receive.
     furi_hal_serial_async_rx_start(instance->serial_handle, camera_on_irq_cb, instance, false);
     furi_hal_serial_async_rx_start(instance->serial_handle, camera_on_irq_cb, instance, false);
 
 
     return instance;
     return instance;
@@ -528,14 +635,14 @@ void camera_suite_view_camera_free(CameraSuiteViewCamera* instance) {
     furi_assert(instance);
     furi_assert(instance);
 
 
     // Free the worker thread.
     // Free the worker thread.
-    furi_thread_flags_set(furi_thread_get_id(instance->worker_thread), WorkerEventStop);
-    furi_thread_join(instance->worker_thread);
-    furi_thread_free(instance->worker_thread);
+    furi_thread_flags_set(furi_thread_get_id(instance->camera_worker_thread), WorkerEventStop);
+    furi_thread_join(instance->camera_worker_thread);
+    furi_thread_free(instance->camera_worker_thread);
 
 
     // Free the allocated stream buffer.
     // Free the allocated stream buffer.
-    furi_stream_buffer_free(instance->rx_stream);
+    furi_stream_buffer_free(instance->camera_rx_stream);
 
 
-    // Re-enable the console.
+    // Deinitialize the serial handle and release the control.
     furi_hal_serial_deinit(instance->serial_handle);
     furi_hal_serial_deinit(instance->serial_handle);
     furi_hal_serial_control_release(instance->serial_handle);
     furi_hal_serial_control_release(instance->serial_handle);
 
 

+ 3 - 5
views/camera_suite_view_camera.h

@@ -17,8 +17,6 @@
 
 
 #include "../helpers/camera_suite_custom_event.h"
 #include "../helpers/camera_suite_custom_event.h"
 
 
-#include <camera_suite_icons.h>
-
 #define UART_CH (FuriHalSerialIdUsart)
 #define UART_CH (FuriHalSerialIdUsart)
 
 
 #define BITMAP_HEADER_LENGTH 62
 #define BITMAP_HEADER_LENGTH 62
@@ -43,16 +41,16 @@ typedef enum {
     WorkerEventRx = (1 << 2),
     WorkerEventRx = (1 << 2),
 } WorkerEventFlags;
 } WorkerEventFlags;
 
 
-#define WORKER_EVENTS_MASK (WorkerEventStop | WorkerEventRx)
+#define CAMERA_WORKER_EVENTS_MASK (WorkerEventStop | WorkerEventRx)
 
 
 // Forward declaration
 // Forward declaration
 typedef void (*CameraSuiteViewCameraCallback)(CameraSuiteCustomEvent event, void* context);
 typedef void (*CameraSuiteViewCameraCallback)(CameraSuiteCustomEvent event, void* context);
 
 
 typedef struct CameraSuiteViewCamera {
 typedef struct CameraSuiteViewCamera {
     CameraSuiteViewCameraCallback callback;
     CameraSuiteViewCameraCallback callback;
-    FuriStreamBuffer* rx_stream;
+    FuriStreamBuffer* camera_rx_stream;
     FuriHalSerialHandle* serial_handle;
     FuriHalSerialHandle* serial_handle;
-    FuriThread* worker_thread;
+    FuriThread* camera_worker_thread;
     NotificationApp* notification;
     NotificationApp* notification;
     View* view;
     View* view;
     void* context;
     void* context;

+ 2 - 1
views/camera_suite_view_guide.c

@@ -30,7 +30,7 @@ void camera_suite_view_guide_draw(Canvas* canvas, CameraSuiteViewGuideModel* mod
     canvas_clear(canvas);
     canvas_clear(canvas);
     canvas_set_color(canvas, ColorBlack);
     canvas_set_color(canvas, ColorBlack);
     canvas_set_font(canvas, FontPrimary);
     canvas_set_font(canvas, FontPrimary);
-    canvas_draw_str_aligned(canvas, 0, 0, AlignLeft, AlignTop, "Guide");
+    canvas_draw_str_aligned(canvas, 0, 0, AlignLeft, AlignTop, "Camera Suite Guide");
     canvas_set_font(canvas, FontSecondary);
     canvas_set_font(canvas, FontSecondary);
     canvas_draw_str_aligned(canvas, 0, 12, AlignLeft, AlignTop, "Left = Toggle invert");
     canvas_draw_str_aligned(canvas, 0, 12, AlignLeft, AlignTop, "Left = Toggle invert");
     canvas_draw_str_aligned(canvas, 0, 22, AlignLeft, AlignTop, "Right = Toggle dithering");
     canvas_draw_str_aligned(canvas, 0, 22, AlignLeft, AlignTop, "Right = Toggle dithering");
@@ -54,6 +54,7 @@ bool camera_suite_view_guide_input(InputEvent* event, void* context) {
                 CameraSuiteViewGuideModel * model,
                 CameraSuiteViewGuideModel * model,
                 {
                 {
                     UNUSED(model);
                     UNUSED(model);
+                    // Go back to the main menu.
                     instance->callback(CameraSuiteCustomEventSceneGuideBack, instance->context);
                     instance->callback(CameraSuiteCustomEventSceneGuideBack, instance->context);
                 },
                 },
                 true);
                 true);

+ 92 - 17
views/camera_suite_view_start.c

@@ -4,16 +4,6 @@
 #include <input/input.h>
 #include <input/input.h>
 #include <gui/elements.h>
 #include <gui/elements.h>
 
 
-struct CameraSuiteViewStart {
-    View* view;
-    CameraSuiteViewStartCallback callback;
-    void* context;
-};
-
-typedef struct {
-    int some_value;
-} CameraSuiteViewStartModel;
-
 void camera_suite_view_start_set_callback(
 void camera_suite_view_start_set_callback(
     CameraSuiteViewStart* instance,
     CameraSuiteViewStart* instance,
     CameraSuiteViewStartCallback callback,
     CameraSuiteViewStartCallback callback,
@@ -27,13 +17,88 @@ void camera_suite_view_start_set_callback(
 void camera_suite_view_start_draw(Canvas* canvas, CameraSuiteViewStartModel* model) {
 void camera_suite_view_start_draw(Canvas* canvas, CameraSuiteViewStartModel* model) {
     UNUSED(model);
     UNUSED(model);
     canvas_clear(canvas);
     canvas_clear(canvas);
-    canvas_set_color(canvas, ColorBlack);
-    canvas_set_font(canvas, FontPrimary);
-    canvas_draw_str_aligned(canvas, 64, 10, AlignCenter, AlignTop, "Camera Suite");
+
+    // Draw Camera Suite logo.
+    canvas_draw_circle(canvas, 82, 28, 1);
+    canvas_draw_circle(canvas, 85, 29, 11);
+    canvas_draw_circle(canvas, 85, 29, 6);
+    canvas_draw_circle(canvas, 85, 29, 9);
+    canvas_draw_circle(canvas, 104, 17, 1);
+    canvas_draw_line(canvas, 70, 14, 108, 14);
+    canvas_draw_line(canvas, 70, 14, 74, 10);
+    canvas_draw_line(canvas, 70, 15, 70, 37);
+    canvas_draw_line(canvas, 70, 32, 74, 32);
+    canvas_draw_line(canvas, 75, 9, 82, 9);
+    canvas_draw_line(canvas, 78, 37, 70, 37);
+    canvas_draw_line(canvas, 79, 20, 70, 20);
+    canvas_draw_line(canvas, 81, 18, 85, 14);
+    canvas_draw_line(canvas, 82, 14, 82, 8);
+    canvas_draw_line(canvas, 82, 8, 86, 4);
+    canvas_draw_line(canvas, 82, 8, 95, 8);
+    canvas_draw_line(canvas, 83, 14, 85, 11);
+    canvas_draw_line(canvas, 84, 15, 92, 15);
+    canvas_draw_line(canvas, 86, 11, 92, 11);
+    canvas_draw_line(canvas, 86, 23, 84, 24);
+    canvas_draw_line(canvas, 86, 24, 82, 24);
+    canvas_draw_line(canvas, 86, 25, 89, 27);
+    canvas_draw_line(canvas, 86, 4, 98, 4);
+    canvas_draw_line(canvas, 87, 24, 91, 28);
+    canvas_draw_line(canvas, 87, 26, 89, 28);
+    canvas_draw_line(canvas, 88, 26, 84, 25);
+    canvas_draw_line(canvas, 88, 26, 86, 24);
+    canvas_draw_line(canvas, 88, 28, 89, 31);
+    canvas_draw_line(canvas, 89, 28, 89, 30);
+    canvas_draw_line(canvas, 90, 28, 90, 31);
+    canvas_draw_line(canvas, 90, 30, 89, 33);
+    canvas_draw_line(canvas, 92, 11, 93, 14);
+    canvas_draw_line(canvas, 93, 16, 97, 18);
+    canvas_draw_line(canvas, 94, 8, 98, 4);
+    canvas_draw_line(canvas, 95, 9, 95, 14);
+    canvas_draw_line(canvas, 96, 32, 107, 32);
+    canvas_draw_line(canvas, 98, 19, 100, 22);
+    canvas_draw_line(canvas, 98, 5, 98, 9);
+    canvas_draw_line(canvas, 98, 9, 111, 9);
+    canvas_draw_line(canvas, 98, 9, 96, 14);
+    canvas_draw_line(canvas, 99, 20, 108, 20);
+    canvas_draw_line(canvas, 100, 23, 100, 27);
+    canvas_draw_line(canvas, 100, 28, 93, 36);
+    canvas_draw_line(canvas, 102, 23, 104, 23);
+    canvas_draw_line(canvas, 104, 23, 106, 28);
+    canvas_draw_line(canvas, 104, 24, 102, 28);
+    canvas_draw_line(canvas, 107, 14, 112, 9);
+    canvas_draw_line(canvas, 107, 28, 108, 27);
+    canvas_draw_line(canvas, 107, 37, 92, 37);
+    canvas_draw_line(canvas, 108, 15, 108, 37);
+    canvas_draw_line(canvas, 108, 20, 112, 16);
+    canvas_draw_line(canvas, 108, 32, 112, 28);
+    canvas_draw_line(canvas, 108, 37, 112, 33);
+    canvas_draw_line(canvas, 112, 10, 112, 33);
+
+    // Draw "Start" button.
     canvas_set_font(canvas, FontSecondary);
     canvas_set_font(canvas, FontSecondary);
-    canvas_draw_str_aligned(canvas, 64, 22, AlignCenter, AlignTop, "Flipper Zero");
-    canvas_draw_str_aligned(canvas, 64, 32, AlignCenter, AlignTop, "ESP32 CAM");
-    elements_button_center(canvas, "Start");
+    canvas_draw_str(canvas, 46, 57, "Start");
+    canvas_draw_circle(canvas, 75, 53, 2);
+    canvas_draw_dot(canvas, 72, 50);
+    canvas_draw_dot(canvas, 72, 56);
+    canvas_draw_dot(canvas, 78, 50);
+    canvas_draw_dot(canvas, 78, 56);
+    canvas_draw_line(canvas, 43, 47, 43, 59);
+    canvas_draw_line(canvas, 44, 46, 81, 46);
+    canvas_draw_line(canvas, 44, 60, 81, 60);
+    canvas_draw_line(canvas, 71, 51, 71, 55);
+    canvas_draw_line(canvas, 73, 49, 77, 49);
+    canvas_draw_line(canvas, 73, 57, 77, 57);
+    canvas_draw_line(canvas, 74, 52, 76, 52);
+    canvas_draw_line(canvas, 74, 53, 76, 53);
+    canvas_draw_line(canvas, 74, 54, 77, 54);
+    canvas_draw_line(canvas, 79, 51, 79, 55);
+    canvas_draw_line(canvas, 82, 47, 82, 59);
+
+    // Draw "Camera Suite" text.
+    canvas_set_font(canvas, FontPrimary);
+    canvas_draw_str(canvas, 16, 23, "Camera");
+    canvas_set_font(canvas, FontPrimary);
+    canvas_draw_str(canvas, 23, 35, "Suite");
 }
 }
 
 
 static void camera_suite_view_start_model_init(CameraSuiteViewStartModel* const model) {
 static void camera_suite_view_start_model_init(CameraSuiteViewStartModel* const model) {
@@ -94,12 +159,22 @@ void camera_suite_view_start_enter(void* context) {
 }
 }
 
 
 CameraSuiteViewStart* camera_suite_view_start_alloc() {
 CameraSuiteViewStart* camera_suite_view_start_alloc() {
+    // Allocate memory for the instance
     CameraSuiteViewStart* instance = malloc(sizeof(CameraSuiteViewStart));
     CameraSuiteViewStart* instance = malloc(sizeof(CameraSuiteViewStart));
+
+    // Allocate the view object
     instance->view = view_alloc();
     instance->view = view_alloc();
+
+    // Allocate model
     view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(CameraSuiteViewStartModel));
     view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(CameraSuiteViewStartModel));
-    // furi_assert crashes in events without this
+
+    // Set context for the view (furi_assert crashes in events without this)
     view_set_context(instance->view, instance);
     view_set_context(instance->view, instance);
+
+    // Set draw callback
     view_set_draw_callback(instance->view, (ViewDrawCallback)camera_suite_view_start_draw);
     view_set_draw_callback(instance->view, (ViewDrawCallback)camera_suite_view_start_draw);
+
+    // Set input callback
     view_set_input_callback(instance->view, camera_suite_view_start_input);
     view_set_input_callback(instance->view, camera_suite_view_start_input);
 
 
     with_view_model(
     with_view_model(

+ 11 - 3
views/camera_suite_view_start.h

@@ -3,10 +3,18 @@
 #include <gui/view.h>
 #include <gui/view.h>
 #include "../helpers/camera_suite_custom_event.h"
 #include "../helpers/camera_suite_custom_event.h"
 
 
-typedef struct CameraSuiteViewStart CameraSuiteViewStart;
-
 typedef void (*CameraSuiteViewStartCallback)(CameraSuiteCustomEvent event, void* context);
 typedef void (*CameraSuiteViewStartCallback)(CameraSuiteCustomEvent event, void* context);
 
 
+typedef struct CameraSuiteViewStart {
+    View* view;
+    CameraSuiteViewStartCallback callback;
+    void* context;
+} CameraSuiteViewStart;
+
+typedef struct {
+    int some_value;
+} CameraSuiteViewStartModel;
+
 void camera_suite_view_start_set_callback(
 void camera_suite_view_start_set_callback(
     CameraSuiteViewStart* camera_suite_view_start,
     CameraSuiteViewStart* camera_suite_view_start,
     CameraSuiteViewStartCallback callback,
     CameraSuiteViewStartCallback callback,
@@ -16,4 +24,4 @@ View* camera_suite_view_start_get_view(CameraSuiteViewStart* camera_suite_static
 
 
 CameraSuiteViewStart* camera_suite_view_start_alloc();
 CameraSuiteViewStart* camera_suite_view_start_alloc();
 
 
-void camera_suite_view_start_free(CameraSuiteViewStart* camera_suite_static);
+void camera_suite_view_start_free(CameraSuiteViewStart* camera_suite_static);