Merge pull request #562 from CodyTolene/ct/camera-suite-update

Update '[ESP32] Camera Suite' to v1.1.0
This commit is contained in:
MMX 2023-07-29 04:15:21 +03:00 committed by GitHub
commit 03b950999c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 176 additions and 502 deletions

View file

@ -1,9 +1,9 @@
App(
appid="camerasuite",
appid="camera_suite",
apptype=FlipperAppType.EXTERNAL,
cdefines=["APP_CAMERA_SUITE"],
entry_point="camera_suite_app",
fap_author="Cody Tolene",
fap_author="@CodyTolene @Z4urce @leedave",
fap_category="GPIO",
fap_description="A camera suite application for the Flipper Zero ESP32-CAM module.",
fap_icon="icons/camera_suite.png",

View file

@ -13,7 +13,7 @@ void camera_suite_tick_event_callback(void* context) {
scene_manager_handle_tick_event(app->scene_manager);
}
//leave app if back button pressed
// Leave app if back button pressed.
bool camera_suite_navigation_event_callback(void* context) {
furi_assert(context);
CameraSuite* app = context;
@ -25,10 +25,10 @@ CameraSuite* camera_suite_app_alloc() {
app->gui = furi_record_open(RECORD_GUI);
app->notification = furi_record_open(RECORD_NOTIFICATION);
//Turn backlight on, believe me this makes testing your app easier
// Turn backlight on.
notification_message(app->notification, &sequence_display_backlight_on);
//Scene additions
// Scene additions
app->view_dispatcher = view_dispatcher_alloc();
view_dispatcher_enable_queue(app->view_dispatcher);
@ -60,17 +60,11 @@ CameraSuite* camera_suite_app_alloc() {
CameraSuiteViewIdStartscreen,
camera_suite_view_start_get_view(app->camera_suite_view_start));
app->camera_suite_view_style_1 = camera_suite_view_style_1_alloc();
app->camera_suite_view_camera = camera_suite_view_camera_alloc();
view_dispatcher_add_view(
app->view_dispatcher,
CameraSuiteViewIdScene1,
camera_suite_view_style_1_get_view(app->camera_suite_view_style_1));
app->camera_suite_view_style_2 = camera_suite_view_style_2_alloc();
view_dispatcher_add_view(
app->view_dispatcher,
CameraSuiteViewIdScene2,
camera_suite_view_style_2_get_view(app->camera_suite_view_style_2));
CameraSuiteViewIdCamera,
camera_suite_view_camera_get_view(app->camera_suite_view_camera));
app->camera_suite_view_guide = camera_suite_view_guide_alloc();
view_dispatcher_add_view(
@ -98,9 +92,9 @@ void camera_suite_app_free(CameraSuite* app) {
scene_manager_free(app->scene_manager);
// View Dispatcher
view_dispatcher_remove_view(app->view_dispatcher, CameraSuiteViewIdStartscreen);
view_dispatcher_remove_view(app->view_dispatcher, CameraSuiteViewIdMenu);
view_dispatcher_remove_view(app->view_dispatcher, CameraSuiteViewIdScene1);
view_dispatcher_remove_view(app->view_dispatcher, CameraSuiteViewIdScene2);
view_dispatcher_remove_view(app->view_dispatcher, CameraSuiteViewIdCamera);
view_dispatcher_remove_view(app->view_dispatcher, CameraSuiteViewIdGuide);
view_dispatcher_remove_view(app->view_dispatcher, CameraSuiteViewIdSettings);
submenu_free(app->submenu);
@ -110,8 +104,7 @@ void camera_suite_app_free(CameraSuite* app) {
// Free remaining resources
camera_suite_view_start_free(app->camera_suite_view_start);
camera_suite_view_style_1_free(app->camera_suite_view_style_1);
camera_suite_view_style_2_free(app->camera_suite_view_style_2);
camera_suite_view_camera_free(app->camera_suite_view_camera);
camera_suite_view_guide_free(app->camera_suite_view_guide);
button_menu_free(app->button_menu);
variable_item_list_free(app->variable_item_list);

View file

@ -4,9 +4,7 @@
#include "scenes/camera_suite_scene.h"
#include "views/camera_suite_view_guide.h"
#include "views/camera_suite_view_start.h"
#include "views/camera_suite_view_style_1.h"
#include "views/camera_suite_view_style_2.h"
#include <assets_icons.h>
#include "views/camera_suite_view_camera.h"
#include <furi.h>
#include <furi_hal.h>
#include <gui/gui.h>
@ -29,8 +27,7 @@ typedef struct {
SceneManager* scene_manager;
VariableItemList* variable_item_list;
CameraSuiteViewStart* camera_suite_view_start;
CameraSuiteViewStyle1* camera_suite_view_style_1;
CameraSuiteViewStyle2* camera_suite_view_style_2;
CameraSuiteViewCamera* camera_suite_view_camera;
CameraSuiteViewGuide* camera_suite_view_guide;
uint32_t orientation;
uint32_t haptic;
@ -42,8 +39,7 @@ typedef struct {
typedef enum {
CameraSuiteViewIdStartscreen,
CameraSuiteViewIdMenu,
CameraSuiteViewIdScene1,
CameraSuiteViewIdScene2,
CameraSuiteViewIdCamera,
CameraSuiteViewIdGuide,
CameraSuiteViewIdSettings,
} CameraSuiteViewId;

View file

@ -0,0 +1,20 @@
## v1.1
- Support and picture stabilization for all camera orientations (0°, 90°, 180°, 270°).
- Rename "Scene 1" to "Camera". No UX changes, strictly internal.
- Clean up unused "Scene 2". This was inaccessible to users previously and unused.
- Add new dithering variations (needs new module firmware, see https://github.com/CodyTolene/Flipper-Zero-Camera-Suite#firmware-installation):
- Add `Jarvis Judice` Ninke Dithering option
- Add `Stucki` dithering option.
- Add ability to toggle dithering options from default `Floyd-Steinberg` and back.
- 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
- 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
- Repurpose and build upon the "[ESP32] Camera" software into the new "[ESP32] Camera Suite" application with new purpose:
- Adding more scene for a guide.
- Adding more scene for saveable settings.
- Add ability to rotate the camera orientation.

View file

@ -0,0 +1,35 @@
## Flipper Zero - Camera Suite
Software to run an ESP32-CAM module on your Flipper Zero device.
## Software Guide <a name="software-guide"></a>
### Flipper Zero button mappings:
🔼 = Contrast Up
🔽 = Contrast Down
◀️ = Toggle invert.
▶️ = Toggle dithering on/off.
⚪ = Cycle FloydSteinberg/Jarvis-Judice-Ninke/Stucki dithering types.
↩️ = Go back.
### Camera Suite settings:
**Orientation** = Rotate the camera image 90 degrees counter-clockwise starting at zero by default (0, 90, 180, 270). This is useful if you have your camera module mounted in a different orientation than the default.
**Haptic FX** = Toggle haptic feedback on/off.
**Sound FX** = Toggle sound effects on/off.
**LED FX** = Toggle LED effects on/off.
## Links
Full setup, wiring guide, etc. in the main project README here: https://github.com/CodyTolene/Flipper-Zero-Camera-Suite
A firmware is needed for the ESP32-CAM module, see here for more information: https://github.com/CodyTolene/Flipper-Zero-Camera-Suite#firmware-installation

View file

@ -8,20 +8,13 @@ typedef enum {
CameraSuiteCustomEventStartRight,
CameraSuiteCustomEventStartOk,
CameraSuiteCustomEventStartBack,
// Scene events: Camera style 1
CameraSuiteCustomEventSceneStyle1Up,
CameraSuiteCustomEventSceneStyle1Down,
CameraSuiteCustomEventSceneStyle1Left,
CameraSuiteCustomEventSceneStyle1Right,
CameraSuiteCustomEventSceneStyle1Ok,
CameraSuiteCustomEventSceneStyle1Back,
// Scene events: Camera style 2
CameraSuiteCustomEventSceneStyle2Up,
CameraSuiteCustomEventSceneStyle2Down,
CameraSuiteCustomEventSceneStyle2Left,
CameraSuiteCustomEventSceneStyle2Right,
CameraSuiteCustomEventSceneStyle2Ok,
CameraSuiteCustomEventSceneStyle2Back,
// Scene events: Camera
CameraSuiteCustomEventSceneCameraUp,
CameraSuiteCustomEventSceneCameraDown,
CameraSuiteCustomEventSceneCameraLeft,
CameraSuiteCustomEventSceneCameraRight,
CameraSuiteCustomEventSceneCameraOk,
CameraSuiteCustomEventSceneCameraBack,
// Scene events: Guide
CameraSuiteCustomEventSceneGuideUp,
CameraSuiteCustomEventSceneGuideDown,

View file

@ -1,35 +1,35 @@
#include "../camera_suite.h"
#include "../helpers/camera_suite_custom_event.h"
#include "../views/camera_suite_view_style_1.h"
#include "../views/camera_suite_view_camera.h"
static void camera_suite_view_style_1_callback(CameraSuiteCustomEvent event, void* context) {
void camera_suite_view_camera_callback(CameraSuiteCustomEvent event, void* context) {
furi_assert(context);
CameraSuite* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, event);
}
void camera_suite_scene_style_1_on_enter(void* context) {
void camera_suite_scene_camera_on_enter(void* context) {
furi_assert(context);
CameraSuite* app = context;
camera_suite_view_style_1_set_callback(
app->camera_suite_view_style_1, camera_suite_view_style_1_callback, app);
view_dispatcher_switch_to_view(app->view_dispatcher, CameraSuiteViewIdScene1);
camera_suite_view_camera_set_callback(
app->camera_suite_view_camera, camera_suite_view_camera_callback, app);
view_dispatcher_switch_to_view(app->view_dispatcher, CameraSuiteViewIdCamera);
}
bool camera_suite_scene_style_1_on_event(void* context, SceneManagerEvent event) {
bool camera_suite_scene_camera_on_event(void* context, SceneManagerEvent event) {
CameraSuite* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
switch(event.event) {
case CameraSuiteCustomEventSceneStyle1Left:
case CameraSuiteCustomEventSceneStyle1Right:
case CameraSuiteCustomEventSceneStyle1Up:
case CameraSuiteCustomEventSceneStyle1Down:
case CameraSuiteCustomEventSceneStyle1Ok:
case CameraSuiteCustomEventSceneCameraLeft:
case CameraSuiteCustomEventSceneCameraRight:
case CameraSuiteCustomEventSceneCameraUp:
case CameraSuiteCustomEventSceneCameraDown:
case CameraSuiteCustomEventSceneCameraOk:
// Do nothing.
break;
case CameraSuiteCustomEventSceneStyle1Back:
case CameraSuiteCustomEventSceneCameraBack:
notification_message(app->notification, &sequence_reset_red);
notification_message(app->notification, &sequence_reset_green);
notification_message(app->notification, &sequence_reset_blue);
@ -46,7 +46,7 @@ bool camera_suite_scene_style_1_on_event(void* context, SceneManagerEvent event)
return consumed;
}
void camera_suite_scene_style_1_on_exit(void* context) {
void camera_suite_scene_camera_on_exit(void* context) {
CameraSuite* app = context;
UNUSED(app);
}

View file

@ -1,6 +1,5 @@
ADD_SCENE(camera_suite, start, Start)
ADD_SCENE(camera_suite, menu, Menu)
ADD_SCENE(camera_suite, style_1, Style_1)
ADD_SCENE(camera_suite, style_2, Style_2)
ADD_SCENE(camera_suite, camera, Camera)
ADD_SCENE(camera_suite, guide, Guide)
ADD_SCENE(camera_suite, settings, Settings)

View file

@ -1,10 +1,8 @@
#include "../camera_suite.h"
enum SubmenuIndex {
/** Atkinson Dithering Algorithm. */
SubmenuIndexSceneStyle1 = 10,
/** Floyd-Steinberg Dithering Algorithm. */
SubmenuIndexSceneStyle2,
/** Camera. */
SubmenuIndexSceneCamera = 10,
/** Guide/how-to. */
SubmenuIndexGuide,
/** Settings menu. */
@ -22,16 +20,9 @@ void camera_suite_scene_menu_on_enter(void* context) {
submenu_add_item(
app->submenu,
"Open Camera",
SubmenuIndexSceneStyle1,
SubmenuIndexSceneCamera,
camera_suite_scene_menu_submenu_callback,
app);
// Staged view for the future.
// submenu_add_item(
// app->submenu,
// "Test",
// SubmenuIndexSceneStyle2,
// camera_suite_scene_menu_submenu_callback,
// app);
submenu_add_item(
app->submenu, "Guide", SubmenuIndexGuide, camera_suite_scene_menu_submenu_callback, app);
submenu_add_item(
@ -56,15 +47,10 @@ bool camera_suite_scene_menu_on_event(void* context, SceneManagerEvent event) {
view_dispatcher_stop(app->view_dispatcher);
return true;
} else if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexSceneStyle1) {
if(event.event == SubmenuIndexSceneCamera) {
scene_manager_set_scene_state(
app->scene_manager, CameraSuiteSceneMenu, SubmenuIndexSceneStyle1);
scene_manager_next_scene(app->scene_manager, CameraSuiteSceneStyle_1);
return true;
} else if(event.event == SubmenuIndexSceneStyle2) {
scene_manager_set_scene_state(
app->scene_manager, CameraSuiteSceneMenu, SubmenuIndexSceneStyle2);
scene_manager_next_scene(app->scene_manager, CameraSuiteSceneStyle_2);
app->scene_manager, CameraSuiteSceneMenu, SubmenuIndexSceneCamera);
scene_manager_next_scene(app->scene_manager, CameraSuiteSceneCamera);
return true;
} else if(event.event == SubmenuIndexGuide) {
scene_manager_set_scene_state(

View file

@ -24,9 +24,9 @@ bool camera_suite_scene_start_on_event(void* context, SceneManagerEvent event) {
switch(event.event) {
case CameraSuiteCustomEventStartLeft:
case CameraSuiteCustomEventStartRight:
break;
case CameraSuiteCustomEventStartUp:
case CameraSuiteCustomEventStartDown:
// Do nothing.
break;
case CameraSuiteCustomEventStartOk:
scene_manager_next_scene(app->scene_manager, CameraSuiteSceneMenu);

View file

@ -1,54 +0,0 @@
#include "../camera_suite.h"
#include "../helpers/camera_suite_custom_event.h"
#include "../helpers/camera_suite_haptic.h"
#include "../helpers/camera_suite_led.h"
#include "../views/camera_suite_view_style_2.h"
void camera_suite_view_style_2_callback(CameraSuiteCustomEvent event, void* context) {
furi_assert(context);
CameraSuite* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, event);
}
void camera_suite_scene_style_2_on_enter(void* context) {
furi_assert(context);
CameraSuite* app = context;
camera_suite_view_style_2_set_callback(
app->camera_suite_view_style_2, camera_suite_view_style_2_callback, app);
view_dispatcher_switch_to_view(app->view_dispatcher, CameraSuiteViewIdScene2);
}
bool camera_suite_scene_style_2_on_event(void* context, SceneManagerEvent event) {
CameraSuite* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
switch(event.event) {
case CameraSuiteCustomEventSceneStyle2Left:
case CameraSuiteCustomEventSceneStyle2Right:
case CameraSuiteCustomEventSceneStyle2Up:
case CameraSuiteCustomEventSceneStyle2Down:
case CameraSuiteCustomEventSceneStyle2Ok:
// Do nothing.
break;
case CameraSuiteCustomEventSceneStyle2Back:
notification_message(app->notification, &sequence_reset_red);
notification_message(app->notification, &sequence_reset_green);
notification_message(app->notification, &sequence_reset_blue);
if(!scene_manager_search_and_switch_to_previous_scene(
app->scene_manager, CameraSuiteSceneMenu)) {
scene_manager_stop(app->scene_manager);
view_dispatcher_stop(app->view_dispatcher);
}
consumed = true;
break;
}
}
return consumed;
}
void camera_suite_scene_style_2_on_exit(void* context) {
CameraSuite* app = context;
UNUSED(app);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -8,23 +8,19 @@
#include "../helpers/camera_suite_speaker.h"
#include "../helpers/camera_suite_led.h"
static CameraSuiteViewStyle1* current_instance = NULL;
// Dithering type:
// 0 = Floyd Steinberg (default)
// 1 = Atkinson
static int current_dithering = 0;
static CameraSuiteViewCamera* current_instance = NULL;
struct CameraSuiteViewStyle1 {
CameraSuiteViewStyle1Callback callback;
struct CameraSuiteViewCamera {
CameraSuiteViewCameraCallback callback;
FuriStreamBuffer* rx_stream;
FuriThread* worker_thread;
View* view;
void* context;
};
void camera_suite_view_style_1_set_callback(
CameraSuiteViewStyle1* instance,
CameraSuiteViewStyle1Callback callback,
void camera_suite_view_camera_set_callback(
CameraSuiteViewCamera* instance,
CameraSuiteViewCameraCallback callback,
void* context) {
furi_assert(instance);
furi_assert(callback);
@ -32,7 +28,29 @@ void camera_suite_view_style_1_set_callback(
instance->context = context;
}
static void camera_suite_view_style_1_draw(Canvas* canvas, UartDumpModel* model) {
// 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) {
switch(orientation) {
case 0: // Camera rotated 0 degrees (right side up, default)
canvas_draw_dot(canvas, x, y);
break;
case 1: // Camera rotated 90 degrees
canvas_draw_dot(canvas, y, FRAME_WIDTH - 1 - x);
break;
case 2: // Camera rotated 180 degrees (upside down)
canvas_draw_dot(canvas, FRAME_WIDTH - 1 - x, FRAME_HEIGHT - 1 - y);
break;
case 3: // Camera rotated 270 degrees
canvas_draw_dot(canvas, FRAME_HEIGHT - 1 - y, x);
break;
default:
break;
}
}
static void camera_suite_view_camera_draw(Canvas* canvas, void* _model) {
UartDumpModel* model = _model;
// Clear the screen.
canvas_set_color(canvas, ColorBlack);
@ -41,60 +59,17 @@ static void camera_suite_view_style_1_draw(Canvas* canvas, UartDumpModel* model)
CameraSuite* app = current_instance->context;
// Draw the pixels with rotation.
for(size_t p = 0; p < FRAME_BUFFER_LENGTH; ++p) {
uint8_t x = p % ROW_BUFFER_LENGTH; // 0 .. 15
uint8_t y = p / ROW_BUFFER_LENGTH; // 0 .. 63
// Apply rotation
int16_t rotated_x, rotated_y;
switch(app->orientation) {
case 1: // 90 degrees
rotated_x = y;
rotated_y = FRAME_WIDTH - 1 - x;
break;
case 2: // 180 degrees
rotated_x = FRAME_WIDTH - 1 - x;
rotated_y = FRAME_HEIGHT - 1 - y;
break;
case 3: // 270 degrees
rotated_x = FRAME_HEIGHT - 1 - y;
rotated_y = x;
break;
case 0: // 0 degrees
default:
rotated_x = x;
rotated_y = y;
break;
}
for(uint8_t i = 0; i < 8; ++i) {
if((model->pixels[p] & (1 << i)) != 0) {
// Adjust the coordinates based on the new screen dimensions
uint16_t screen_x, screen_y;
switch(app->orientation) {
case 1: // 90 degrees
screen_x = rotated_x;
screen_y = FRAME_HEIGHT - 8 + (rotated_y * 8) + i;
break;
case 2: // 180 degrees
screen_x = FRAME_WIDTH - 8 + (rotated_x * 8) + i;
screen_y = FRAME_HEIGHT - 1 - rotated_y;
break;
case 3: // 270 degrees
screen_x = FRAME_WIDTH - 1 - rotated_x;
screen_y = rotated_y * 8 + i;
break;
case 0: // 0 degrees
default:
screen_x = rotated_x * 8 + i;
screen_y = rotated_y;
break;
}
canvas_draw_dot(canvas, screen_x, screen_y);
if((model->pixels[p] & (1 << (7 - i))) != 0) {
draw_pixel_by_orientation(canvas, (x * 8) + i, y, app->orientation);
}
}
}
// Draw the guide if the camera is not initialized.
if(!model->initialized) {
canvas_draw_icon(canvas, 74, 16, &I_DolphinCommon_56x48);
@ -107,15 +82,15 @@ static void camera_suite_view_style_1_draw(Canvas* canvas, UartDumpModel* model)
}
}
static void camera_suite_view_style_1_model_init(UartDumpModel* const model) {
static void camera_suite_view_camera_model_init(UartDumpModel* const model) {
for(size_t i = 0; i < FRAME_BUFFER_LENGTH; i++) {
model->pixels[i] = 0;
}
}
static bool camera_suite_view_style_1_input(InputEvent* event, void* context) {
static bool camera_suite_view_camera_input(InputEvent* event, void* context) {
furi_assert(context);
CameraSuiteViewStyle1* instance = context;
CameraSuiteViewCamera* instance = context;
if(event->type == InputTypeRelease) {
switch(event->key) {
default: // Stop all sounds, reset the LED.
@ -144,7 +119,7 @@ static bool camera_suite_view_style_1_input(InputEvent* event, void* context) {
UartDumpModel * model,
{
UNUSED(model);
instance->callback(CameraSuiteCustomEventSceneStyle1Back, instance->context);
instance->callback(CameraSuiteCustomEventSceneCameraBack, instance->context);
},
true);
break;
@ -159,7 +134,7 @@ static bool camera_suite_view_style_1_input(InputEvent* event, void* context) {
camera_suite_play_happy_bump(instance->context);
camera_suite_play_input_sound(instance->context);
camera_suite_led_set_rgb(instance->context, 0, 0, 255);
instance->callback(CameraSuiteCustomEventSceneStyle1Left, instance->context);
instance->callback(CameraSuiteCustomEventSceneCameraLeft, instance->context);
},
true);
break;
@ -174,7 +149,7 @@ static bool camera_suite_view_style_1_input(InputEvent* event, void* context) {
camera_suite_play_happy_bump(instance->context);
camera_suite_play_input_sound(instance->context);
camera_suite_led_set_rgb(instance->context, 0, 0, 255);
instance->callback(CameraSuiteCustomEventSceneStyle1Right, instance->context);
instance->callback(CameraSuiteCustomEventSceneCameraRight, instance->context);
},
true);
break;
@ -189,7 +164,7 @@ static bool camera_suite_view_style_1_input(InputEvent* event, void* context) {
camera_suite_play_happy_bump(instance->context);
camera_suite_play_input_sound(instance->context);
camera_suite_led_set_rgb(instance->context, 0, 0, 255);
instance->callback(CameraSuiteCustomEventSceneStyle1Up, instance->context);
instance->callback(CameraSuiteCustomEventSceneCameraUp, instance->context);
},
true);
break;
@ -204,18 +179,13 @@ static bool camera_suite_view_style_1_input(InputEvent* event, void* context) {
camera_suite_play_happy_bump(instance->context);
camera_suite_play_input_sound(instance->context);
camera_suite_led_set_rgb(instance->context, 0, 0, 255);
instance->callback(CameraSuiteCustomEventSceneStyle1Down, instance->context);
instance->callback(CameraSuiteCustomEventSceneCameraDown, instance->context);
},
true);
break;
case InputKeyOk:
if(current_dithering == 0) {
data[0] = 'd'; // Update to Floyd Steinberg dithering.
current_dithering = 1;
} else {
data[0] = 'D'; // Update to Atkinson dithering.
current_dithering = 0;
}
// Switch dithering types.
data[0] = 'D';
with_view_model(
instance->view,
UartDumpModel * model,
@ -224,7 +194,7 @@ static bool camera_suite_view_style_1_input(InputEvent* event, void* context) {
camera_suite_play_happy_bump(instance->context);
camera_suite_play_input_sound(instance->context);
camera_suite_led_set_rgb(instance->context, 0, 0, 255);
instance->callback(CameraSuiteCustomEventSceneStyle1Ok, instance->context);
instance->callback(CameraSuiteCustomEventSceneCameraOk, instance->context);
},
true);
break;
@ -237,16 +207,16 @@ static bool camera_suite_view_style_1_input(InputEvent* event, void* context) {
return true;
}
static void camera_suite_view_style_1_exit(void* context) {
static void camera_suite_view_camera_exit(void* context) {
furi_assert(context);
}
static void camera_suite_view_style_1_enter(void* context) {
static void camera_suite_view_camera_enter(void* context) {
// Check `context` for null. If it is null, abort program, else continue.
furi_assert(context);
// Cast `context` to `CameraSuiteViewStyle1*` and store it in `instance`.
CameraSuiteViewStyle1* instance = (CameraSuiteViewStyle1*)context;
// Cast `context` to `CameraSuiteViewCamera*` and store it in `instance`.
CameraSuiteViewCamera* instance = (CameraSuiteViewCamera*)context;
// Assign the current instance to the global variable
current_instance = instance;
@ -259,7 +229,7 @@ static void camera_suite_view_style_1_enter(void* context) {
with_view_model(
instance->view,
UartDumpModel * model,
{ camera_suite_view_style_1_model_init(model); },
{ camera_suite_view_camera_model_init(model); },
true);
}
@ -267,8 +237,8 @@ static void camera_on_irq_cb(UartIrqEvent uartIrqEvent, uint8_t data, void* cont
// Check `context` for null. If it is null, abort program, else continue.
furi_assert(context);
// Cast `context` to `CameraSuiteViewStyle1*` and store it in `instance`.
CameraSuiteViewStyle1* instance = context;
// Cast `context` to `CameraSuiteViewCamera*` and store it in `instance`.
CameraSuiteViewCamera* instance = context;
// If `uartIrqEvent` is `UartIrqEventRXNE`, send the data to the
// `rx_stream` and set the `WorkerEventRx` flag.
@ -319,7 +289,7 @@ static void process_ringbuffer(UartDumpModel* model, uint8_t byte) {
static int32_t camera_worker(void* context) {
furi_assert(context);
CameraSuiteViewStyle1* instance = context;
CameraSuiteViewCamera* instance = context;
while(1) {
uint32_t events =
@ -348,14 +318,17 @@ static int32_t camera_worker(void* context) {
false);
}
} while(length > 0);
with_view_model(
instance->view, UartDumpModel * model, { UNUSED(model); }, true);
}
}
return 0;
}
CameraSuiteViewStyle1* camera_suite_view_style_1_alloc() {
CameraSuiteViewStyle1* instance = malloc(sizeof(CameraSuiteViewStyle1));
CameraSuiteViewCamera* camera_suite_view_camera_alloc() {
CameraSuiteViewCamera* instance = malloc(sizeof(CameraSuiteViewCamera));
instance->view = view_alloc();
@ -364,15 +337,15 @@ CameraSuiteViewStyle1* camera_suite_view_style_1_alloc() {
// Set up views
view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(UartDumpModel));
view_set_context(instance->view, instance); // furi_assert crashes in events without this
view_set_draw_callback(instance->view, (ViewDrawCallback)camera_suite_view_style_1_draw);
view_set_input_callback(instance->view, camera_suite_view_style_1_input);
view_set_enter_callback(instance->view, camera_suite_view_style_1_enter);
view_set_exit_callback(instance->view, camera_suite_view_style_1_exit);
view_set_draw_callback(instance->view, (ViewDrawCallback)camera_suite_view_camera_draw);
view_set_input_callback(instance->view, camera_suite_view_camera_input);
view_set_enter_callback(instance->view, camera_suite_view_camera_enter);
view_set_exit_callback(instance->view, camera_suite_view_camera_exit);
with_view_model(
instance->view,
UartDumpModel * model,
{ camera_suite_view_style_1_model_init(model); },
{ camera_suite_view_camera_model_init(model); },
true);
instance->worker_thread = furi_thread_alloc_ex("UsbUartWorker", 2048, camera_worker, instance);
@ -386,7 +359,7 @@ CameraSuiteViewStyle1* camera_suite_view_style_1_alloc() {
return instance;
}
void camera_suite_view_style_1_free(CameraSuiteViewStyle1* instance) {
void camera_suite_view_camera_free(CameraSuiteViewCamera* instance) {
furi_assert(instance);
with_view_model(
@ -395,7 +368,7 @@ void camera_suite_view_style_1_free(CameraSuiteViewStyle1* instance) {
free(instance);
}
View* camera_suite_view_style_1_get_view(CameraSuiteViewStyle1* instance) {
View* camera_suite_view_camera_get_view(CameraSuiteViewCamera* instance) {
furi_assert(instance);
return instance->view;
}
}

View file

@ -19,11 +19,12 @@
#define FRAME_WIDTH 128
#define FRAME_HEIGHT 64
#define FRAME_BIT_DEPTH 1
#define FRAME_BUFFER_LENGTH \
(FRAME_WIDTH * FRAME_HEIGHT * FRAME_BIT_DEPTH / 8) // 128*64*1 / 8 = 1024
#define ROW_BUFFER_LENGTH (FRAME_WIDTH / 8) // 128/8 = 16
#define RING_BUFFER_LENGTH (ROW_BUFFER_LENGTH + 3) // ROW_BUFFER_LENGTH + Header => 16 + 3 = 19
#define LAST_ROW_INDEX (FRAME_BUFFER_LENGTH - ROW_BUFFER_LENGTH) // 1024 - 16 = 1008
#define FRAME_BUFFER_LENGTH 1024
#define ROW_BUFFER_LENGTH 16
#define RING_BUFFER_LENGTH 19
#define LAST_ROW_INDEX 1008
extern const Icon I_DolphinCommon_56x48;
typedef struct UartDumpModel UartDumpModel;
@ -35,20 +36,20 @@ struct UartDumpModel {
uint8_t row_ringbuffer[RING_BUFFER_LENGTH];
};
typedef struct CameraSuiteViewStyle1 CameraSuiteViewStyle1;
typedef struct CameraSuiteViewCamera CameraSuiteViewCamera;
typedef void (*CameraSuiteViewStyle1Callback)(CameraSuiteCustomEvent event, void* context);
typedef void (*CameraSuiteViewCameraCallback)(CameraSuiteCustomEvent event, void* context);
void camera_suite_view_style_1_set_callback(
CameraSuiteViewStyle1* camera_suite_view_style_1,
CameraSuiteViewStyle1Callback callback,
void camera_suite_view_camera_set_callback(
CameraSuiteViewCamera* camera_suite_view_camera,
CameraSuiteViewCameraCallback callback,
void* context);
CameraSuiteViewStyle1* camera_suite_view_style_1_alloc();
CameraSuiteViewCamera* camera_suite_view_camera_alloc();
void camera_suite_view_style_1_free(CameraSuiteViewStyle1* camera_suite_static);
void camera_suite_view_camera_free(CameraSuiteViewCamera* camera_suite_static);
View* camera_suite_view_style_1_get_view(CameraSuiteViewStyle1* camera_suite_static);
View* camera_suite_view_camera_get_view(CameraSuiteViewCamera* camera_suite_static);
typedef enum {
// Reserved for StreamBuffer internal event

View file

@ -1,249 +0,0 @@
#include "../camera_suite.h"
#include <furi.h>
#include <furi_hal.h>
#include <input/input.h>
#include <gui/elements.h>
#include <dolphin/dolphin.h>
#include "../helpers/camera_suite_haptic.h"
#include "../helpers/camera_suite_speaker.h"
#include "../helpers/camera_suite_led.h"
struct CameraSuiteViewStyle2 {
View* view;
CameraSuiteViewStyle2Callback callback;
void* context;
};
typedef struct {
int screen_text;
} CameraSuiteViewStyle2Model;
char buttonText[11][14] = {
"",
"Press Up",
"Press Down",
"Press Left",
"Press Right",
"Press Ok",
"Release Up",
"Release Down",
"Release Left",
"Release Right",
"Release Ok",
};
void camera_suite_view_style_2_set_callback(
CameraSuiteViewStyle2* instance,
CameraSuiteViewStyle2Callback callback,
void* context) {
furi_assert(instance);
furi_assert(callback);
instance->callback = callback;
instance->context = context;
}
void camera_suite_view_style_2_draw(Canvas* canvas, CameraSuiteViewStyle2Model* model) {
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 0, 10, AlignLeft, AlignTop, "Scene 2: Input Examples");
canvas_set_font(canvas, FontSecondary);
char* strInput = malloc(15);
strcpy(strInput, buttonText[model->screen_text]);
canvas_draw_str_aligned(canvas, 0, 22, AlignLeft, AlignTop, strInput);
free(strInput);
}
static void camera_suite_view_style_2_model_init(CameraSuiteViewStyle2Model* const model) {
model->screen_text = 0;
}
bool camera_suite_view_style_2_input(InputEvent* event, void* context) {
furi_assert(context);
CameraSuiteViewStyle2* instance = context;
if(event->type == InputTypeRelease) {
switch(event->key) {
case InputKeyBack:
with_view_model(
instance->view,
CameraSuiteViewStyle2Model * model,
{
UNUSED(model);
camera_suite_stop_all_sound(instance->context);
instance->callback(CameraSuiteCustomEventSceneStyle2Back, instance->context);
camera_suite_play_long_bump(instance->context);
},
true);
break;
case InputKeyUp:
with_view_model(
instance->view,
CameraSuiteViewStyle2Model * model,
{
model->screen_text = 6;
camera_suite_play_bad_bump(instance->context);
camera_suite_stop_all_sound(instance->context);
camera_suite_led_set_rgb(instance->context, 255, 0, 255);
},
true);
break;
case InputKeyDown:
with_view_model(
instance->view,
CameraSuiteViewStyle2Model * model,
{
model->screen_text = 7;
camera_suite_play_bad_bump(instance->context);
camera_suite_stop_all_sound(instance->context);
camera_suite_led_set_rgb(instance->context, 255, 255, 0);
},
true);
break;
case InputKeyLeft:
with_view_model(
instance->view,
CameraSuiteViewStyle2Model * model,
{
model->screen_text = 8;
camera_suite_play_bad_bump(instance->context);
camera_suite_stop_all_sound(instance->context);
camera_suite_led_set_rgb(instance->context, 0, 255, 255);
},
true);
break;
case InputKeyRight:
with_view_model(
instance->view,
CameraSuiteViewStyle2Model * model,
{
model->screen_text = 9;
camera_suite_play_bad_bump(instance->context);
camera_suite_stop_all_sound(instance->context);
camera_suite_led_set_rgb(instance->context, 255, 0, 0);
},
true);
break;
case InputKeyOk:
with_view_model(
instance->view,
CameraSuiteViewStyle2Model * model,
{
model->screen_text = 10;
camera_suite_play_bad_bump(instance->context);
camera_suite_stop_all_sound(instance->context);
camera_suite_led_set_rgb(instance->context, 255, 255, 255);
},
true);
break;
case InputKeyMAX:
break;
}
} else if(event->type == InputTypePress) {
switch(event->key) {
case InputKeyUp:
with_view_model(
instance->view,
CameraSuiteViewStyle2Model * model,
{
model->screen_text = 1;
camera_suite_play_happy_bump(instance->context);
camera_suite_play_input_sound(instance->context);
},
true);
break;
case InputKeyDown:
with_view_model(
instance->view,
CameraSuiteViewStyle2Model * model,
{
model->screen_text = 2;
camera_suite_play_happy_bump(instance->context);
camera_suite_play_input_sound(instance->context);
},
true);
break;
case InputKeyLeft:
with_view_model(
instance->view,
CameraSuiteViewStyle2Model * model,
{
model->screen_text = 3;
camera_suite_play_happy_bump(instance->context);
camera_suite_play_input_sound(instance->context);
},
true);
break;
case InputKeyRight:
with_view_model(
instance->view,
CameraSuiteViewStyle2Model * model,
{
model->screen_text = 4;
camera_suite_play_happy_bump(instance->context);
camera_suite_play_input_sound(instance->context);
},
true);
break;
case InputKeyOk:
with_view_model(
instance->view,
CameraSuiteViewStyle2Model * model,
{
model->screen_text = 5;
camera_suite_play_happy_bump(instance->context);
camera_suite_play_input_sound(instance->context);
},
true);
break;
case InputKeyBack:
case InputKeyMAX:
break;
}
}
return true;
}
void camera_suite_view_style_2_exit(void* context) {
furi_assert(context);
CameraSuite* app = context;
camera_suite_stop_all_sound(app);
//camera_suite_led_reset(app);
}
void camera_suite_view_style_2_enter(void* context) {
furi_assert(context);
dolphin_deed(DolphinDeedPluginStart);
}
CameraSuiteViewStyle2* camera_suite_view_style_2_alloc() {
CameraSuiteViewStyle2* instance = malloc(sizeof(CameraSuiteViewStyle2));
instance->view = view_alloc();
view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(CameraSuiteViewStyle2Model));
view_set_context(instance->view, instance);
view_set_draw_callback(instance->view, (ViewDrawCallback)camera_suite_view_style_2_draw);
view_set_input_callback(instance->view, camera_suite_view_style_2_input);
//view_set_enter_callback(instance->view, camera_suite_view_style_2_enter);
view_set_exit_callback(instance->view, camera_suite_view_style_2_exit);
with_view_model(
instance->view,
CameraSuiteViewStyle2Model * model,
{ camera_suite_view_style_2_model_init(model); },
true);
return instance;
}
void camera_suite_view_style_2_free(CameraSuiteViewStyle2* instance) {
furi_assert(instance);
view_free(instance->view);
free(instance);
}
View* camera_suite_view_style_2_get_view(CameraSuiteViewStyle2* instance) {
furi_assert(instance);
return instance->view;
}

View file

@ -1,19 +0,0 @@
#pragma once
#include <gui/view.h>
#include "../helpers/camera_suite_custom_event.h"
typedef struct CameraSuiteViewStyle2 CameraSuiteViewStyle2;
typedef void (*CameraSuiteViewStyle2Callback)(CameraSuiteCustomEvent event, void* context);
void camera_suite_view_style_2_set_callback(
CameraSuiteViewStyle2* instance,
CameraSuiteViewStyle2Callback callback,
void* context);
CameraSuiteViewStyle2* camera_suite_view_style_2_alloc();
void camera_suite_view_style_2_free(CameraSuiteViewStyle2* camera_suite_static);
View* camera_suite_view_style_2_get_view(CameraSuiteViewStyle2* boilerpate_static);