Add Camera Suite GPIO application for the ESP32-CAM module.

This commit is contained in:
Cody Tolene
2023-07-11 00:06:55 -05:00
parent e7439272e6
commit 978fecf242
30 changed files with 2061 additions and 0 deletions

View File

@@ -0,0 +1,120 @@
#include "../camera-suite.h"
#include <furi.h>
#include <furi_hal.h>
#include <input/input.h>
#include <gui/elements.h>
#include <dolphin/dolphin.h>
struct CameraSuiteViewGuide {
View* view;
CameraSuiteViewGuideCallback callback;
void* context;
};
typedef struct {
int some_value;
} CameraSuiteViewGuideModel;
void camera_suite_view_guide_set_callback(
CameraSuiteViewGuide* instance,
CameraSuiteViewGuideCallback callback,
void* context) {
furi_assert(instance);
furi_assert(callback);
instance->callback = callback;
instance->context = context;
}
void camera_suite_view_guide_draw(Canvas* canvas, CameraSuiteViewGuideModel* model) {
UNUSED(model);
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 0, 0, AlignLeft, AlignTop, "Guide");
canvas_set_font(canvas, FontSecondary);
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, 32, AlignLeft, AlignTop, "Up = Contrast Up");
canvas_draw_str_aligned(canvas, 0, 42, AlignLeft, AlignTop, "Down = Contrast Down");
// TODO: Possibly update to take picture instead.
canvas_draw_str_aligned(canvas, 0, 52, AlignLeft, AlignTop, "Center = Toggle Dither Type");
}
static void camera_suite_view_guide_model_init(CameraSuiteViewGuideModel* const model) {
model->some_value = 1;
}
bool camera_suite_view_guide_input(InputEvent* event, void* context) {
furi_assert(context);
CameraSuiteViewGuide* instance = context;
if(event->type == InputTypeRelease) {
switch(event->key) {
case InputKeyBack:
with_view_model(
instance->view,
CameraSuiteViewGuideModel * model,
{
UNUSED(model);
instance->callback(CameraSuiteCustomEventSceneGuideBack, instance->context);
},
true);
break;
case InputKeyLeft:
case InputKeyRight:
case InputKeyUp:
case InputKeyDown:
case InputKeyOk:
case InputKeyMAX:
// Do nothing.
break;
}
}
return true;
}
void camera_suite_view_guide_exit(void* context) {
furi_assert(context);
}
void camera_suite_view_guide_enter(void* context) {
furi_assert(context);
CameraSuiteViewGuide* instance = (CameraSuiteViewGuide*)context;
with_view_model(
instance->view,
CameraSuiteViewGuideModel * model,
{ camera_suite_view_guide_model_init(model); },
true);
}
CameraSuiteViewGuide* camera_suite_view_guide_alloc() {
CameraSuiteViewGuide* instance = malloc(sizeof(CameraSuiteViewGuide));
instance->view = view_alloc();
view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(CameraSuiteViewGuideModel));
view_set_context(instance->view, instance); // furi_assert crashes in events without this
view_set_draw_callback(instance->view, (ViewDrawCallback)camera_suite_view_guide_draw);
view_set_input_callback(instance->view, camera_suite_view_guide_input);
view_set_enter_callback(instance->view, camera_suite_view_guide_enter);
view_set_exit_callback(instance->view, camera_suite_view_guide_exit);
with_view_model(
instance->view,
CameraSuiteViewGuideModel * model,
{ camera_suite_view_guide_model_init(model); },
true);
return instance;
}
void camera_suite_view_guide_free(CameraSuiteViewGuide* instance) {
furi_assert(instance);
with_view_model(
instance->view, CameraSuiteViewGuideModel * model, { UNUSED(model); }, true);
view_free(instance->view);
free(instance);
}
View* camera_suite_view_guide_get_view(CameraSuiteViewGuide* instance) {
furi_assert(instance);
return instance->view;
}

View File

@@ -0,0 +1,19 @@
#pragma once
#include <gui/view.h>
#include "../helpers/camera_suite_custom_event.h"
typedef struct CameraSuiteViewGuide CameraSuiteViewGuide;
typedef void (*CameraSuiteViewGuideCallback)(CameraSuiteCustomEvent event, void* context);
void camera_suite_view_guide_set_callback(
CameraSuiteViewGuide* camera_suite_view_guide,
CameraSuiteViewGuideCallback callback,
void* context);
View* camera_suite_view_guide_get_view(CameraSuiteViewGuide* camera_suite_static);
CameraSuiteViewGuide* camera_suite_view_guide_alloc();
void camera_suite_view_guide_free(CameraSuiteViewGuide* camera_suite_static);

View File

@@ -0,0 +1,126 @@
#include "../camera-suite.h"
#include <furi.h>
#include <furi_hal.h>
#include <input/input.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(
CameraSuiteViewStart* instance,
CameraSuiteViewStartCallback callback,
void* context) {
furi_assert(instance);
furi_assert(callback);
instance->callback = callback;
instance->context = context;
}
void camera_suite_view_start_draw(Canvas* canvas, CameraSuiteViewStartModel* model) {
UNUSED(model);
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 64, 10, AlignCenter, AlignTop, "Camera Suite");
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");
}
static void camera_suite_view_start_model_init(CameraSuiteViewStartModel* const model) {
model->some_value = 1;
}
bool camera_suite_view_start_input(InputEvent* event, void* context) {
furi_assert(context);
CameraSuiteViewStart* instance = context;
if(event->type == InputTypeRelease) {
switch(event->key) {
case InputKeyBack:
// Exit application.
with_view_model(
instance->view,
CameraSuiteViewStartModel * model,
{
UNUSED(model);
instance->callback(CameraSuiteCustomEventStartBack, instance->context);
},
true);
break;
case InputKeyOk:
// Start the application.
with_view_model(
instance->view,
CameraSuiteViewStartModel * model,
{
UNUSED(model);
instance->callback(CameraSuiteCustomEventStartOk, instance->context);
},
true);
break;
case InputKeyMAX:
case InputKeyLeft:
case InputKeyRight:
case InputKeyUp:
case InputKeyDown:
// Do nothing.
break;
}
}
return true;
}
void camera_suite_view_start_exit(void* context) {
furi_assert(context);
}
void camera_suite_view_start_enter(void* context) {
furi_assert(context);
CameraSuiteViewStart* instance = (CameraSuiteViewStart*)context;
with_view_model(
instance->view,
CameraSuiteViewStartModel * model,
{ camera_suite_view_start_model_init(model); },
true);
}
CameraSuiteViewStart* camera_suite_view_start_alloc() {
CameraSuiteViewStart* instance = malloc(sizeof(CameraSuiteViewStart));
instance->view = view_alloc();
view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(CameraSuiteViewStartModel));
// furi_assert crashes in events without this
view_set_context(instance->view, instance);
view_set_draw_callback(instance->view, (ViewDrawCallback)camera_suite_view_start_draw);
view_set_input_callback(instance->view, camera_suite_view_start_input);
with_view_model(
instance->view,
CameraSuiteViewStartModel * model,
{ camera_suite_view_start_model_init(model); },
true);
return instance;
}
void camera_suite_view_start_free(CameraSuiteViewStart* instance) {
furi_assert(instance);
with_view_model(
instance->view, CameraSuiteViewStartModel * model, { UNUSED(model); }, true);
view_free(instance->view);
free(instance);
}
View* camera_suite_view_start_get_view(CameraSuiteViewStart* instance) {
furi_assert(instance);
return instance->view;
}

View File

@@ -0,0 +1,19 @@
#pragma once
#include <gui/view.h>
#include "../helpers/camera_suite_custom_event.h"
typedef struct CameraSuiteViewStart CameraSuiteViewStart;
typedef void (*CameraSuiteViewStartCallback)(CameraSuiteCustomEvent event, void* context);
void camera_suite_view_start_set_callback(
CameraSuiteViewStart* camera_suite_view_start,
CameraSuiteViewStartCallback callback,
void* context);
View* camera_suite_view_start_get_view(CameraSuiteViewStart* camera_suite_static);
CameraSuiteViewStart* camera_suite_view_start_alloc();
void camera_suite_view_start_free(CameraSuiteViewStart* camera_suite_static);

View File

@@ -0,0 +1,401 @@
#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"
static CameraSuiteViewStyle1* current_instance = NULL;
// Dithering type:
// 0 = Floyd Steinberg (default)
// 1 = Atkinson
static int current_dithering = 0;
struct CameraSuiteViewStyle1 {
CameraSuiteViewStyle1Callback callback;
FuriStreamBuffer* rx_stream;
FuriThread* worker_thread;
View* view;
void* context;
};
void camera_suite_view_style_1_set_callback(
CameraSuiteViewStyle1* instance,
CameraSuiteViewStyle1Callback callback,
void* context) {
furi_assert(instance);
furi_assert(callback);
instance->callback = callback;
instance->context = context;
}
static void camera_suite_view_style_1_draw(Canvas* canvas, UartDumpModel* model) {
// Clear the screen.
canvas_set_color(canvas, ColorBlack);
// Draw the frame.
canvas_draw_frame(canvas, 0, 0, FRAME_WIDTH, FRAME_HEIGHT);
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);
}
}
}
// Draw the guide if the camera is not initialized.
if(!model->initialized) {
canvas_draw_icon(canvas, 74, 16, &I_DolphinCommon_56x48);
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");
}
}
static void camera_suite_view_style_1_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) {
furi_assert(context);
CameraSuiteViewStyle1* instance = context;
if(event->type == InputTypeRelease) {
switch(event->key) {
default: // Stop all sounds, reset the LED.
with_view_model(
instance->view,
UartDumpModel * model,
{
UNUSED(model);
camera_suite_play_bad_bump(instance->context);
camera_suite_stop_all_sound(instance->context);
camera_suite_led_set_rgb(instance->context, 0, 0, 0);
},
true);
break;
}
// Send `data` to the ESP32-CAM
} else if(event->type == InputTypePress) {
uint8_t data[1];
switch(event->key) {
case InputKeyBack:
// Stop the camera stream.
data[0] = 's';
// Go back to the main menu.
with_view_model(
instance->view,
UartDumpModel * model,
{
UNUSED(model);
instance->callback(CameraSuiteCustomEventSceneStyle1Back, instance->context);
},
true);
break;
case InputKeyLeft:
// Camera: Invert.
data[0] = '<';
with_view_model(
instance->view,
UartDumpModel * model,
{
UNUSED(model);
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);
},
true);
break;
case InputKeyRight:
// Camera: Enable/disable dithering.
data[0] = '>';
with_view_model(
instance->view,
UartDumpModel * model,
{
UNUSED(model);
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);
},
true);
break;
case InputKeyUp:
// Camera: Increase contrast.
data[0] = 'C';
with_view_model(
instance->view,
UartDumpModel * model,
{
UNUSED(model);
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);
},
true);
break;
case InputKeyDown:
// Camera: Reduce contrast.
data[0] = 'c';
with_view_model(
instance->view,
UartDumpModel * model,
{
UNUSED(model);
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);
},
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;
}
with_view_model(
instance->view,
UartDumpModel * model,
{
UNUSED(model);
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);
},
true);
break;
case InputKeyMAX:
break;
}
// Send `data` to the ESP32-CAM
furi_hal_uart_tx(FuriHalUartIdUSART1, data, 1);
}
return true;
}
static void camera_suite_view_style_1_exit(void* context) {
furi_assert(context);
}
static void camera_suite_view_style_1_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;
// Assign the current instance to the global variable
current_instance = instance;
uint8_t data[1];
data[0] = 'S'; // Uppercase `S` to start the camera
// Send `data` to the ESP32-CAM
furi_hal_uart_tx(FuriHalUartIdUSART1, data, 1);
with_view_model(
instance->view,
UartDumpModel * model,
{ camera_suite_view_style_1_model_init(model); },
true);
}
static void camera_on_irq_cb(UartIrqEvent uartIrqEvent, uint8_t data, 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 = context;
// If `uartIrqEvent` is `UartIrqEventRXNE`, send the data to the
// `rx_stream` and set the `WorkerEventRx` flag.
if(uartIrqEvent == UartIrqEventRXNE) {
furi_stream_buffer_send(instance->rx_stream, &data, 1, 0);
furi_thread_flags_set(furi_thread_get_id(instance->worker_thread), WorkerEventRx);
}
}
static void process_ringbuffer(UartDumpModel* model, uint8_t byte) {
// First char has to be 'Y' in the buffer.
if(model->ringbuffer_index == 0 && byte != 'Y') {
return;
}
// Second char has to be ':' in the buffer or reset.
if(model->ringbuffer_index == 1 && byte != ':') {
model->ringbuffer_index = 0;
process_ringbuffer(model, byte);
return;
}
// Assign current byte to the ringbuffer.
model->row_ringbuffer[model->ringbuffer_index] = byte;
// Increment the ringbuffer index.
++model->ringbuffer_index;
// Let's wait 'till the buffer fills.
if(model->ringbuffer_index < RING_BUFFER_LENGTH) {
return;
}
// Flush the ringbuffer to the framebuffer.
model->ringbuffer_index = 0; // Reset the ringbuffer
model->initialized = true; // Established the connection successfully.
size_t row_start_index =
model->row_ringbuffer[2] * ROW_BUFFER_LENGTH; // Third char will determine the row number
if(row_start_index > LAST_ROW_INDEX) { // Failsafe
row_start_index = 0;
}
for(size_t i = 0; i < ROW_BUFFER_LENGTH; ++i) {
model->pixels[row_start_index + i] =
model->row_ringbuffer[i + 3]; // Writing the remaining 16 bytes into the frame buffer
}
}
static int32_t camera_worker(void* context) {
furi_assert(context);
CameraSuiteViewStyle1* instance = context;
while(1) {
uint32_t events =
furi_thread_flags_wait(WORKER_EVENTS_MASK, FuriFlagWaitAny, FuriWaitForever);
furi_check((events & FuriFlagError) == 0);
if(events & WorkerEventStop) {
break;
} else if(events & WorkerEventRx) {
size_t length = 0;
do {
size_t intended_data_size = 64;
uint8_t data[intended_data_size];
length =
furi_stream_buffer_receive(instance->rx_stream, data, intended_data_size, 0);
if(length > 0) {
with_view_model(
instance->view,
UartDumpModel * model,
{
for(size_t i = 0; i < length; i++) {
process_ringbuffer(model, data[i]);
}
},
false);
}
} while(length > 0);
}
}
return 0;
}
CameraSuiteViewStyle1* camera_suite_view_style_1_alloc() {
CameraSuiteViewStyle1* instance = malloc(sizeof(CameraSuiteViewStyle1));
instance->view = view_alloc();
instance->rx_stream = furi_stream_buffer_alloc(2048, 1);
// 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);
with_view_model(
instance->view,
UartDumpModel * model,
{ camera_suite_view_style_1_model_init(model); },
true);
instance->worker_thread = furi_thread_alloc_ex("UsbUartWorker", 2048, camera_worker, instance);
furi_thread_start(instance->worker_thread);
// Enable uart listener
furi_hal_console_disable();
furi_hal_uart_set_br(FuriHalUartIdUSART1, 230400);
furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, camera_on_irq_cb, instance);
return instance;
}
void camera_suite_view_style_1_free(CameraSuiteViewStyle1* instance) {
furi_assert(instance);
with_view_model(
instance->view, UartDumpModel * model, { UNUSED(model); }, true);
view_free(instance->view);
free(instance);
}
View* camera_suite_view_style_1_get_view(CameraSuiteViewStyle1* instance) {
furi_assert(instance);
return instance->view;
}

View File

@@ -0,0 +1,60 @@
#include "../helpers/camera_suite_custom_event.h"
#include <furi.h>
#include <furi_hal.h>
#include <furi_hal_console.h>
#include <furi_hal_uart.h>
#include <gui/elements.h>
#include <gui/gui.h>
#include <gui/icon_i.h>
#include <gui/modules/dialog_ex.h>
#include <gui/view.h>
#include <gui/view_dispatcher.h>
#include <notification/notification.h>
#include <notification/notification_messages.h>
#include <storage/filesystem_api_defines.h>
#include <storage/storage.h>
#pragma once
#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
typedef struct UartDumpModel UartDumpModel;
struct UartDumpModel {
bool initialized;
int rotation_angle;
uint8_t pixels[FRAME_BUFFER_LENGTH];
uint8_t ringbuffer_index;
uint8_t row_ringbuffer[RING_BUFFER_LENGTH];
};
typedef struct CameraSuiteViewStyle1 CameraSuiteViewStyle1;
typedef void (*CameraSuiteViewStyle1Callback)(CameraSuiteCustomEvent event, void* context);
void camera_suite_view_style_1_set_callback(
CameraSuiteViewStyle1* camera_suite_view_style_1,
CameraSuiteViewStyle1Callback callback,
void* context);
CameraSuiteViewStyle1* camera_suite_view_style_1_alloc();
void camera_suite_view_style_1_free(CameraSuiteViewStyle1* camera_suite_static);
View* camera_suite_view_style_1_get_view(CameraSuiteViewStyle1* camera_suite_static);
typedef enum {
// Reserved for StreamBuffer internal event
WorkerEventReserved = (1 << 0),
WorkerEventStop = (1 << 1),
WorkerEventRx = (1 << 2),
} WorkerEventFlags;
#define WORKER_EVENTS_MASK (WorkerEventStop | WorkerEventRx)

View File

@@ -0,0 +1,249 @@
#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

@@ -0,0 +1,19 @@
#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);