|
@@ -60,7 +60,7 @@ static void camera_suite_view_camera_draw(Canvas* canvas, void* model) {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Draw the guide if the camera is not initialized.
|
|
// Draw the guide if the camera is not initialized.
|
|
|
- if(!uartDumpModel->initialized) {
|
|
|
|
|
|
|
+ if(!uartDumpModel->is_initialized) {
|
|
|
canvas_draw_icon(canvas, 74, 16, &I_DolphinCommon_56x48);
|
|
canvas_draw_icon(canvas, 74, 16, &I_DolphinCommon_56x48);
|
|
|
canvas_set_font(canvas, FontSecondary);
|
|
canvas_set_font(canvas, FontSecondary);
|
|
|
canvas_draw_str(canvas, 8, 12, "Connect the ESP32-CAM");
|
|
canvas_draw_str(canvas, 8, 12, "Connect the ESP32-CAM");
|
|
@@ -71,7 +71,7 @@ static void camera_suite_view_camera_draw(Canvas* canvas, void* model) {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static void save_image(void* model) {
|
|
|
|
|
|
|
+static void save_image_to_flipper_sd_card(void* model) {
|
|
|
furi_assert(model);
|
|
furi_assert(model);
|
|
|
|
|
|
|
|
UartDumpModel* uartDumpModel = model;
|
|
UartDumpModel* uartDumpModel = model;
|
|
@@ -116,7 +116,7 @@ static void save_image(void* model) {
|
|
|
// Free the file name after use.
|
|
// Free the file name after use.
|
|
|
furi_string_free(file_name);
|
|
furi_string_free(file_name);
|
|
|
|
|
|
|
|
- if(!uartDumpModel->inverted) {
|
|
|
|
|
|
|
+ if(!uartDumpModel->is_inverted) {
|
|
|
for(size_t i = 0; i < FRAME_BUFFER_LENGTH; ++i) {
|
|
for(size_t i = 0; i < FRAME_BUFFER_LENGTH; ++i) {
|
|
|
uartDumpModel->pixels[i] = ~uartDumpModel->pixels[i];
|
|
uartDumpModel->pixels[i] = ~uartDumpModel->pixels[i];
|
|
|
}
|
|
}
|
|
@@ -155,14 +155,14 @@ static void
|
|
|
furi_assert(model);
|
|
furi_assert(model);
|
|
|
furi_assert(instance_context);
|
|
furi_assert(instance_context);
|
|
|
|
|
|
|
|
|
|
+ model->is_dithering_enabled = true;
|
|
|
|
|
+ model->is_inverted = false;
|
|
|
|
|
+ uint32_t orientation = instance_context->orientation;
|
|
|
|
|
+ model->orientation = orientation;
|
|
|
|
|
+
|
|
|
for(size_t i = 0; i < FRAME_BUFFER_LENGTH; i++) {
|
|
for(size_t i = 0; i < FRAME_BUFFER_LENGTH; i++) {
|
|
|
model->pixels[i] = 0;
|
|
model->pixels[i] = 0;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- uint32_t orientation = instance_context->orientation;
|
|
|
|
|
- model->flash = instance_context->flash;
|
|
|
|
|
- model->inverted = false;
|
|
|
|
|
- model->orientation = orientation;
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static bool camera_suite_view_camera_input(InputEvent* event, void* context) {
|
|
static bool camera_suite_view_camera_input(InputEvent* event, void* context) {
|
|
@@ -187,157 +187,156 @@ static bool camera_suite_view_camera_input(InputEvent* event, void* context) {
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
} else if(event->type == InputTypePress) {
|
|
} else if(event->type == InputTypePress) {
|
|
|
- uint8_t data[1] = {'X'};
|
|
|
|
|
switch(event->key) {
|
|
switch(event->key) {
|
|
|
- // Camera: Stop stream.
|
|
|
|
|
case InputKeyBack: {
|
|
case InputKeyBack: {
|
|
|
- // Set the camera flash to off.
|
|
|
|
|
- uint8_t flash_off = 'f';
|
|
|
|
|
- furi_hal_uart_tx(UART_CH, &flash_off, 1);
|
|
|
|
|
- furi_delay_ms(50);
|
|
|
|
|
- // Stop camera stream.
|
|
|
|
|
- uint8_t stop_camera = 's';
|
|
|
|
|
- furi_hal_uart_tx(UART_CH, &stop_camera, 1);
|
|
|
|
|
- // Go back to the main menu.
|
|
|
|
|
with_view_model(
|
|
with_view_model(
|
|
|
instance->view,
|
|
instance->view,
|
|
|
UartDumpModel * model,
|
|
UartDumpModel * model,
|
|
|
{
|
|
{
|
|
|
UNUSED(model);
|
|
UNUSED(model);
|
|
|
|
|
+
|
|
|
|
|
+ // Stop camera stream.
|
|
|
|
|
+ furi_hal_uart_tx(UART_CH, (uint8_t[]){'s'}, 1);
|
|
|
|
|
+ furi_delay_ms(50);
|
|
|
|
|
+
|
|
|
|
|
+ // Go back to the main menu.
|
|
|
instance->callback(CameraSuiteCustomEventSceneCameraBack, instance->context);
|
|
instance->callback(CameraSuiteCustomEventSceneCameraBack, instance->context);
|
|
|
},
|
|
},
|
|
|
true);
|
|
true);
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
- // Camera: Toggle invert on the ESP32-CAM.
|
|
|
|
|
case InputKeyLeft: {
|
|
case InputKeyLeft: {
|
|
|
with_view_model(
|
|
with_view_model(
|
|
|
instance->view,
|
|
instance->view,
|
|
|
UartDumpModel * model,
|
|
UartDumpModel * model,
|
|
|
{
|
|
{
|
|
|
- UNUSED(model);
|
|
|
|
|
|
|
+ // Play sound.
|
|
|
camera_suite_play_happy_bump(instance->context);
|
|
camera_suite_play_happy_bump(instance->context);
|
|
|
camera_suite_play_input_sound(instance->context);
|
|
camera_suite_play_input_sound(instance->context);
|
|
|
camera_suite_led_set_rgb(instance->context, 0, 0, 255);
|
|
camera_suite_led_set_rgb(instance->context, 0, 0, 255);
|
|
|
- if(model->inverted) {
|
|
|
|
|
- data[0] = 'i';
|
|
|
|
|
- model->inverted = false;
|
|
|
|
|
|
|
+
|
|
|
|
|
+ if(model->is_inverted) {
|
|
|
|
|
+ // Camera: Set invert to false on the ESP32-CAM.
|
|
|
|
|
+ furi_hal_uart_tx(UART_CH, (uint8_t[]){'i'}, 1);
|
|
|
|
|
+ furi_delay_ms(50);
|
|
|
|
|
+
|
|
|
|
|
+ model->is_inverted = false;
|
|
|
} else {
|
|
} else {
|
|
|
- data[0] = 'I';
|
|
|
|
|
- model->inverted = true;
|
|
|
|
|
|
|
+ // Camera: Set invert to true on the ESP32-CAM.
|
|
|
|
|
+ furi_hal_uart_tx(UART_CH, (uint8_t[]){'I'}, 1);
|
|
|
|
|
+ furi_delay_ms(50);
|
|
|
|
|
+
|
|
|
|
|
+ model->is_inverted = true;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
instance->callback(CameraSuiteCustomEventSceneCameraLeft, instance->context);
|
|
instance->callback(CameraSuiteCustomEventSceneCameraLeft, instance->context);
|
|
|
},
|
|
},
|
|
|
true);
|
|
true);
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
- // Camera: Enable/disable dithering.
|
|
|
|
|
case InputKeyRight: {
|
|
case InputKeyRight: {
|
|
|
- data[0] = '>';
|
|
|
|
|
with_view_model(
|
|
with_view_model(
|
|
|
instance->view,
|
|
instance->view,
|
|
|
UartDumpModel * model,
|
|
UartDumpModel * model,
|
|
|
{
|
|
{
|
|
|
- UNUSED(model);
|
|
|
|
|
|
|
+ // Play sound.
|
|
|
camera_suite_play_happy_bump(instance->context);
|
|
camera_suite_play_happy_bump(instance->context);
|
|
|
camera_suite_play_input_sound(instance->context);
|
|
camera_suite_play_input_sound(instance->context);
|
|
|
camera_suite_led_set_rgb(instance->context, 0, 0, 255);
|
|
camera_suite_led_set_rgb(instance->context, 0, 0, 255);
|
|
|
|
|
+
|
|
|
|
|
+ if(model->is_dithering_enabled) {
|
|
|
|
|
+ // Camera: Disable dithering.
|
|
|
|
|
+ furi_hal_uart_tx(UART_CH, (uint8_t[]){'d'}, 1);
|
|
|
|
|
+ furi_delay_ms(50);
|
|
|
|
|
+
|
|
|
|
|
+ model->is_dithering_enabled = false;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // Camera: Enable dithering.
|
|
|
|
|
+ furi_hal_uart_tx(UART_CH, (uint8_t[]){'D'}, 1);
|
|
|
|
|
+ furi_delay_ms(50);
|
|
|
|
|
+
|
|
|
|
|
+ model->is_dithering_enabled = true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
instance->callback(CameraSuiteCustomEventSceneCameraRight, instance->context);
|
|
instance->callback(CameraSuiteCustomEventSceneCameraRight, instance->context);
|
|
|
},
|
|
},
|
|
|
true);
|
|
true);
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
- // Camera: Increase contrast.
|
|
|
|
|
case InputKeyUp: {
|
|
case InputKeyUp: {
|
|
|
- data[0] = 'C';
|
|
|
|
|
with_view_model(
|
|
with_view_model(
|
|
|
instance->view,
|
|
instance->view,
|
|
|
UartDumpModel * model,
|
|
UartDumpModel * model,
|
|
|
{
|
|
{
|
|
|
UNUSED(model);
|
|
UNUSED(model);
|
|
|
|
|
+
|
|
|
|
|
+ // Play sound.
|
|
|
camera_suite_play_happy_bump(instance->context);
|
|
camera_suite_play_happy_bump(instance->context);
|
|
|
camera_suite_play_input_sound(instance->context);
|
|
camera_suite_play_input_sound(instance->context);
|
|
|
camera_suite_led_set_rgb(instance->context, 0, 0, 255);
|
|
camera_suite_led_set_rgb(instance->context, 0, 0, 255);
|
|
|
|
|
+
|
|
|
|
|
+ // Camera: Increase contrast.
|
|
|
|
|
+ furi_hal_uart_tx(UART_CH, (uint8_t[]){'C'}, 1);
|
|
|
|
|
+ furi_delay_ms(50);
|
|
|
|
|
+
|
|
|
instance->callback(CameraSuiteCustomEventSceneCameraUp, instance->context);
|
|
instance->callback(CameraSuiteCustomEventSceneCameraUp, instance->context);
|
|
|
},
|
|
},
|
|
|
true);
|
|
true);
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
- // Camera: Reduce contrast.
|
|
|
|
|
case InputKeyDown: {
|
|
case InputKeyDown: {
|
|
|
- data[0] = 'c';
|
|
|
|
|
with_view_model(
|
|
with_view_model(
|
|
|
instance->view,
|
|
instance->view,
|
|
|
UartDumpModel * model,
|
|
UartDumpModel * model,
|
|
|
{
|
|
{
|
|
|
UNUSED(model);
|
|
UNUSED(model);
|
|
|
|
|
+
|
|
|
|
|
+ // Play sound.
|
|
|
camera_suite_play_happy_bump(instance->context);
|
|
camera_suite_play_happy_bump(instance->context);
|
|
|
camera_suite_play_input_sound(instance->context);
|
|
camera_suite_play_input_sound(instance->context);
|
|
|
camera_suite_led_set_rgb(instance->context, 0, 0, 255);
|
|
camera_suite_led_set_rgb(instance->context, 0, 0, 255);
|
|
|
|
|
+
|
|
|
|
|
+ // Camera: Reduce contrast.
|
|
|
|
|
+ furi_hal_uart_tx(UART_CH, (uint8_t[]){'c'}, 1);
|
|
|
|
|
+ furi_delay_ms(50);
|
|
|
|
|
+
|
|
|
instance->callback(CameraSuiteCustomEventSceneCameraDown, instance->context);
|
|
instance->callback(CameraSuiteCustomEventSceneCameraDown, instance->context);
|
|
|
},
|
|
},
|
|
|
true);
|
|
true);
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
- // Camera: Take picture.
|
|
|
|
|
case InputKeyOk: {
|
|
case InputKeyOk: {
|
|
|
with_view_model(
|
|
with_view_model(
|
|
|
instance->view,
|
|
instance->view,
|
|
|
UartDumpModel * model,
|
|
UartDumpModel * model,
|
|
|
{
|
|
{
|
|
|
|
|
+ // Play sound.
|
|
|
camera_suite_play_long_bump(instance->context);
|
|
camera_suite_play_long_bump(instance->context);
|
|
|
camera_suite_play_input_sound(instance->context);
|
|
camera_suite_play_input_sound(instance->context);
|
|
|
camera_suite_led_set_rgb(instance->context, 0, 0, 255);
|
|
camera_suite_led_set_rgb(instance->context, 0, 0, 255);
|
|
|
|
|
|
|
|
- // Save picture directly to ESP32-CAM.
|
|
|
|
|
- // @todo - Add this functionality.
|
|
|
|
|
- // data[0] = 'P';
|
|
|
|
|
- // furi_hal_uart_tx(UART_CH, data, 1);
|
|
|
|
|
-
|
|
|
|
|
- // if(model->flash) {
|
|
|
|
|
- // data[0] = 'F';
|
|
|
|
|
- // furi_hal_uart_tx(UART_CH, data, 1);
|
|
|
|
|
- // furi_delay_ms(50);
|
|
|
|
|
- // }
|
|
|
|
|
|
|
+ // @todo - Save picture directly to ESP32-CAM.
|
|
|
|
|
+ // furi_hal_uart_tx(UART_CH, (uint8_t[]){'P'}, 1);
|
|
|
|
|
|
|
|
- // Take a picture.
|
|
|
|
|
- save_image(model);
|
|
|
|
|
|
|
+ // Save currently displayed image to the Flipper Zero SD card.
|
|
|
|
|
+ save_image_to_flipper_sd_card(model);
|
|
|
|
|
|
|
|
- // if(model->flash) {
|
|
|
|
|
- // data[0] = 'f';
|
|
|
|
|
- // }
|
|
|
|
|
instance->callback(CameraSuiteCustomEventSceneCameraOk, instance->context);
|
|
instance->callback(CameraSuiteCustomEventSceneCameraOk, instance->context);
|
|
|
},
|
|
},
|
|
|
true);
|
|
true);
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
- // Camera: Do nothing.
|
|
|
|
|
case InputKeyMAX:
|
|
case InputKeyMAX:
|
|
|
default: {
|
|
default: {
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- if(data[0] != 'X') {
|
|
|
|
|
- // Send `data` to the ESP32-CAM.
|
|
|
|
|
- furi_hal_uart_tx(UART_CH, data, 1);
|
|
|
|
|
- }
|
|
|
|
|
}
|
|
}
|
|
|
- return true;
|
|
|
|
|
|
|
+ return false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void camera_suite_view_camera_exit(void* context) {
|
|
static void camera_suite_view_camera_exit(void* context) {
|
|
|
- UNUSED(context);
|
|
|
|
|
-
|
|
|
|
|
- // Set the camera flash to off.
|
|
|
|
|
- uint8_t flash_off = 'f';
|
|
|
|
|
- furi_hal_uart_tx(UART_CH, &flash_off, 1);
|
|
|
|
|
- furi_delay_ms(50);
|
|
|
|
|
-
|
|
|
|
|
- // Stop camera stream.
|
|
|
|
|
- uint8_t stop_camera = 's';
|
|
|
|
|
- furi_hal_uart_tx(UART_CH, &stop_camera, 1);
|
|
|
|
|
- furi_delay_ms(50);
|
|
|
|
|
|
|
+ furi_assert(context);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void camera_suite_view_camera_enter(void* context) {
|
|
static void camera_suite_view_camera_enter(void* context) {
|
|
@@ -350,30 +349,23 @@ static void camera_suite_view_camera_enter(void* context) {
|
|
|
CameraSuite* instance_context = instance->context;
|
|
CameraSuite* instance_context = instance->context;
|
|
|
|
|
|
|
|
// Start camera stream.
|
|
// Start camera stream.
|
|
|
- uint8_t start_camera = 'S';
|
|
|
|
|
- furi_hal_uart_tx(UART_CH, &start_camera, 1);
|
|
|
|
|
- furi_delay_ms(75);
|
|
|
|
|
|
|
+ furi_hal_uart_tx(UART_CH, (uint8_t[]){'S'}, 1);
|
|
|
|
|
+ furi_delay_ms(50);
|
|
|
|
|
|
|
|
// Get/set dither type.
|
|
// Get/set dither type.
|
|
|
uint8_t dither_type = instance_context->dither;
|
|
uint8_t dither_type = instance_context->dither;
|
|
|
furi_hal_uart_tx(UART_CH, &dither_type, 1);
|
|
furi_hal_uart_tx(UART_CH, &dither_type, 1);
|
|
|
- furi_delay_ms(75);
|
|
|
|
|
|
|
+ furi_delay_ms(50);
|
|
|
|
|
|
|
|
// Make sure the camera is not inverted.
|
|
// Make sure the camera is not inverted.
|
|
|
- uint8_t invert_camera = 'i';
|
|
|
|
|
- furi_hal_uart_tx(UART_CH, &invert_camera, 1);
|
|
|
|
|
- furi_delay_ms(75);
|
|
|
|
|
|
|
+ furi_hal_uart_tx(UART_CH, (uint8_t[]){'i'}, 1);
|
|
|
|
|
+ furi_delay_ms(50);
|
|
|
|
|
|
|
|
- // Toggle flash on or off based on the current state. This will keep the
|
|
|
|
|
- // flash on initially. However we're toggling it for now on input.
|
|
|
|
|
|
|
+ // Toggle flash on or off based on the current state. If the user has this
|
|
|
|
|
+ // on the flash will stay on the entire time the user is in the camera view.
|
|
|
uint8_t flash_state = instance_context->flash ? 'F' : 'f';
|
|
uint8_t flash_state = instance_context->flash ? 'F' : 'f';
|
|
|
furi_hal_uart_tx(UART_CH, &flash_state, 1);
|
|
furi_hal_uart_tx(UART_CH, &flash_state, 1);
|
|
|
- furi_delay_ms(75);
|
|
|
|
|
-
|
|
|
|
|
- // Make sure we start with the flash off.
|
|
|
|
|
- // uint8_t flash_state = 'f';
|
|
|
|
|
- // furi_hal_uart_tx(UART_CH, &flash_state, 1);
|
|
|
|
|
- // furi_delay_ms(75);
|
|
|
|
|
|
|
+ furi_delay_ms(50);
|
|
|
|
|
|
|
|
with_view_model(
|
|
with_view_model(
|
|
|
instance->view,
|
|
instance->view,
|
|
@@ -429,7 +421,7 @@ static void process_ringbuffer(UartDumpModel* model, uint8_t const byte) {
|
|
|
// Check whether the ring buffer is filled.
|
|
// Check whether the ring buffer is filled.
|
|
|
if(model->ringbuffer_index >= RING_BUFFER_LENGTH) {
|
|
if(model->ringbuffer_index >= RING_BUFFER_LENGTH) {
|
|
|
model->ringbuffer_index = 0; // Reset the ring buffer index.
|
|
model->ringbuffer_index = 0; // Reset the ring buffer index.
|
|
|
- model->initialized = true; // Set the connection as successfully established.
|
|
|
|
|
|
|
+ model->is_initialized = true; // Set the connection as successfully established.
|
|
|
|
|
|
|
|
// Compute the starting index for the row in the pixel buffer.
|
|
// Compute the starting index for the row in the pixel buffer.
|
|
|
size_t row_start_index = model->row_identifier * ROW_BUFFER_LENGTH;
|
|
size_t row_start_index = model->row_identifier * ROW_BUFFER_LENGTH;
|