Temporarily backport app updates from apps repo
6
.gitmodules
vendored
@@ -26,9 +26,6 @@
|
|||||||
[submodule "lib/cxxheaderparser"]
|
[submodule "lib/cxxheaderparser"]
|
||||||
path = lib/cxxheaderparser
|
path = lib/cxxheaderparser
|
||||||
url = https://github.com/robotpy/cxxheaderparser.git
|
url = https://github.com/robotpy/cxxheaderparser.git
|
||||||
[submodule "applications/external/dap_link/lib/free-dap"]
|
|
||||||
path = applications/external/dap_link/lib/free-dap
|
|
||||||
url = https://github.com/ataradov/free-dap.git
|
|
||||||
[submodule "lib/heatshrink"]
|
[submodule "lib/heatshrink"]
|
||||||
path = lib/heatshrink
|
path = lib/heatshrink
|
||||||
url = https://github.com/flipperdevices/heatshrink.git
|
url = https://github.com/flipperdevices/heatshrink.git
|
||||||
@@ -41,6 +38,3 @@
|
|||||||
[submodule "lib/stm32wb_copro"]
|
[submodule "lib/stm32wb_copro"]
|
||||||
path = lib/stm32wb_copro
|
path = lib/stm32wb_copro
|
||||||
url = https://github.com/flipperdevices/stm32wb_copro.git
|
url = https://github.com/flipperdevices/stm32wb_copro.git
|
||||||
[submodule "applications/external/totp/lib/wolfssl"]
|
|
||||||
path = applications/external/totp/lib/wolfssl
|
|
||||||
url = https://github.com/wolfSSL/wolfssl.git
|
|
||||||
|
|||||||
@@ -7,9 +7,10 @@ App(
|
|||||||
"gui",
|
"gui",
|
||||||
],
|
],
|
||||||
stack_size=1 * 1024,
|
stack_size=1 * 1024,
|
||||||
fap_icon="game_2048.png",
|
order=90,
|
||||||
|
fap_icon="game_2048.png",
|
||||||
fap_category="Games",
|
fap_category="Games",
|
||||||
fap_author="@eugene-kirzhanov",
|
fap_author="@eugene-kirzhanov",
|
||||||
fap_version="1.1",
|
fap_version="1.2",
|
||||||
fap_description="Play the port of the 2048 game on Flipper Zero.",
|
fap_description="Play the port of the 2048 game on Flipper Zero.",
|
||||||
)
|
)
|
||||||
@@ -24,7 +24,8 @@
|
|||||||
#define FRAME_TOP 1
|
#define FRAME_TOP 1
|
||||||
#define FRAME_SIZE 61
|
#define FRAME_SIZE 61
|
||||||
|
|
||||||
#define SAVING_FILENAME APP_DATA_PATH("game_2048.save")
|
#define SAVING_DIRECTORY STORAGE_APP_DATA_PATH_PREFIX
|
||||||
|
#define SAVING_FILENAME SAVING_DIRECTORY "/game_2048.save"
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GameStateMenu,
|
GameStateMenu,
|
||||||
@@ -488,8 +489,8 @@ int32_t game_2048_app() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
view_port_update(view_port);
|
|
||||||
furi_mutex_release(game_state->mutex);
|
furi_mutex_release(game_state->mutex);
|
||||||
|
view_port_update(view_port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 89 B After Width: | Height: | Size: 89 B |
100
applications/external/4inrow/4inrow.c
vendored
@@ -256,65 +256,69 @@ int32_t four_in_row_app(void* p) {
|
|||||||
while(1) {
|
while(1) {
|
||||||
// Выбираем событие из очереди в переменную event (ждем бесконечно долго, если очередь пуста)
|
// Выбираем событие из очереди в переменную event (ждем бесконечно долго, если очередь пуста)
|
||||||
// и проверяем, что у нас получилось это сделать
|
// и проверяем, что у нас получилось это сделать
|
||||||
furi_check(furi_message_queue_get(event_queue, &event, FuriWaitForever) == FuriStatusOk);
|
if(furi_message_queue_get(event_queue, &event, FuriWaitForever) == FuriStatusOk) {
|
||||||
furi_mutex_acquire(fourinrow_state->mutex, FuriWaitForever);
|
if((event.type == InputTypePress) && (event.key == InputKeyBack)) {
|
||||||
// Если нажата кнопка "назад", то выходим из цикла, а следовательно и из приложения
|
|
||||||
if(wincheck() != -1) {
|
|
||||||
notification_message(notification, &end);
|
|
||||||
furi_delay_ms(1000);
|
|
||||||
if(wincheck() == 1) {
|
|
||||||
scoreX++;
|
|
||||||
}
|
|
||||||
if(wincheck() == 2) {
|
|
||||||
scoreO++;
|
|
||||||
}
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(event.type == InputTypePress) {
|
|
||||||
if(event.key == InputKeyOk) {
|
|
||||||
int nh = next_height(cursorx);
|
|
||||||
if(nh != -1) {
|
|
||||||
matrix[nh][cursorx] = player;
|
|
||||||
player = 3 - player;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(event.key == InputKeyUp) {
|
|
||||||
//cursory--;
|
|
||||||
}
|
|
||||||
if(event.key == InputKeyDown) {
|
|
||||||
//cursory++;
|
|
||||||
}
|
|
||||||
if(event.key == InputKeyLeft) {
|
|
||||||
if(cursorx > 0) {
|
|
||||||
cursorx--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(event.key == InputKeyRight) {
|
|
||||||
if(cursorx < 6) {
|
|
||||||
cursorx++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(event.key == InputKeyBack) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
furi_mutex_acquire(fourinrow_state->mutex, FuriWaitForever);
|
||||||
|
if(wincheck() != -1) {
|
||||||
|
notification_message(notification, &end);
|
||||||
|
furi_delay_ms(1000);
|
||||||
|
if(wincheck() == 1) {
|
||||||
|
scoreX++;
|
||||||
|
}
|
||||||
|
if(wincheck() == 2) {
|
||||||
|
scoreO++;
|
||||||
|
}
|
||||||
|
init();
|
||||||
|
furi_mutex_release(fourinrow_state->mutex);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(event.type == InputTypePress) {
|
||||||
|
if(event.key == InputKeyOk) {
|
||||||
|
int nh = next_height(cursorx);
|
||||||
|
if(nh != -1) {
|
||||||
|
matrix[nh][cursorx] = player;
|
||||||
|
player = 3 - player;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(event.key == InputKeyUp) {
|
||||||
|
//cursory--;
|
||||||
|
}
|
||||||
|
if(event.key == InputKeyDown) {
|
||||||
|
//cursory++;
|
||||||
|
}
|
||||||
|
if(event.key == InputKeyLeft) {
|
||||||
|
if(cursorx > 0) {
|
||||||
|
cursorx--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(event.key == InputKeyRight) {
|
||||||
|
if(cursorx < 6) {
|
||||||
|
cursorx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
furi_mutex_release(fourinrow_state->mutex);
|
||||||
}
|
}
|
||||||
view_port_update(view_port);
|
view_port_update(view_port);
|
||||||
furi_mutex_release(fourinrow_state->mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Чистим созданные объекты, связанные с интерфейсом
|
||||||
|
view_port_enabled_set(view_port, false);
|
||||||
|
gui_remove_view_port(gui, view_port);
|
||||||
|
view_port_free(view_port);
|
||||||
|
furi_message_queue_free(event_queue);
|
||||||
|
furi_record_close(RECORD_GUI);
|
||||||
// Clear notification
|
// Clear notification
|
||||||
notification_message_block(notification, &sequence_display_backlight_enforce_auto);
|
notification_message_block(notification, &sequence_display_backlight_enforce_auto);
|
||||||
furi_record_close(RECORD_NOTIFICATION);
|
furi_record_close(RECORD_NOTIFICATION);
|
||||||
|
|
||||||
// Специальная очистка памяти, занимаемой очередью
|
|
||||||
furi_message_queue_free(event_queue);
|
|
||||||
|
|
||||||
// Чистим созданные объекты, связанные с интерфейсом
|
|
||||||
gui_remove_view_port(gui, view_port);
|
|
||||||
view_port_free(view_port);
|
|
||||||
furi_mutex_free(fourinrow_state->mutex);
|
furi_mutex_free(fourinrow_state->mutex);
|
||||||
furi_record_close(RECORD_GUI);
|
|
||||||
free(fourinrow_state);
|
free(fourinrow_state);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
3
applications/external/4inrow/application.fam
vendored
@@ -7,10 +7,11 @@ App(
|
|||||||
"gui",
|
"gui",
|
||||||
],
|
],
|
||||||
stack_size=1 * 1024,
|
stack_size=1 * 1024,
|
||||||
|
order=90,
|
||||||
fap_icon="4inrow_10px.png",
|
fap_icon="4inrow_10px.png",
|
||||||
fap_category="Games",
|
fap_category="Games",
|
||||||
fap_author="leo-need-more-coffee",
|
fap_author="leo-need-more-coffee",
|
||||||
fap_weburl="https://github.com/leo-need-more-coffee/flipperzero-4inrow",
|
fap_weburl="https://github.com/leo-need-more-coffee/flipperzero-4inrow",
|
||||||
fap_version="1.0",
|
fap_version="1.1",
|
||||||
fap_description="4 in row Game",
|
fap_description="4 in row Game",
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
# For details & more options, see documentation/AppManifests.md in firmware repo
|
|
||||||
|
|
||||||
App(
|
|
||||||
appid="wifisniffer", # Must be unique
|
|
||||||
name="[ESP32GPS] Wifi Sniff", # Displayed in menus
|
|
||||||
apptype=FlipperAppType.EXTERNAL,
|
|
||||||
entry_point="wifisniffer_app",
|
|
||||||
stack_size=2 * 1024,
|
|
||||||
fap_category="WiFi",
|
|
||||||
fap_icon="sniff.png", # 10x10 1-bit PNG
|
|
||||||
fap_icon_assets="assets",
|
|
||||||
fap_icon_assets_symbol="wifisniffer",
|
|
||||||
)
|
|
||||||
@@ -7,7 +7,8 @@
|
|||||||
#include "util/vector.h"
|
#include "util/vector.h"
|
||||||
|
|
||||||
#define CALIBRATION_DATA_VER (1)
|
#define CALIBRATION_DATA_VER (1)
|
||||||
#define CALIBRATION_DATA_PATH EXT_PATH("apps_data/air_mouse/calibration.data")
|
#define CALIBRATION_DATA_FILE_NAME "calibration.data"
|
||||||
|
#define CALIBRATION_DATA_PATH EXT_PATH("apps_data/air_mouse/" CALIBRATION_DATA_FILE_NAME)
|
||||||
#define CALIBRATION_DATA_MAGIC (0x23)
|
#define CALIBRATION_DATA_MAGIC (0x23)
|
||||||
|
|
||||||
#define CALIBRATION_DATA_SAVE(x) \
|
#define CALIBRATION_DATA_SAVE(x) \
|
||||||
|
|||||||
@@ -34,4 +34,4 @@ private:
|
|||||||
|
|
||||||
} // namespace cardboard
|
} // namespace cardboard
|
||||||
|
|
||||||
#endif // CARDBOARD_SDK_UTIL_MATRIX_4X4_H_
|
#endif // CARDBOARD_SDK_UTIL_MATRIX4X4_H_
|
||||||
|
|||||||
6
applications/external/asteroids/app.c
vendored
@@ -13,8 +13,7 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <notification/notification.h>
|
#include <notification/notification.h>
|
||||||
#include <notification/notification_messages.h>
|
#include <notification/notification_messages.h>
|
||||||
#include "asteroids_icons.h"
|
#include <asteroids_icons.h>
|
||||||
#include <assets_icons.h>
|
|
||||||
|
|
||||||
#define TAG "Asteroids" // Used for logging
|
#define TAG "Asteroids" // Used for logging
|
||||||
#define DEBUG_MSG 0
|
#define DEBUG_MSG 0
|
||||||
@@ -29,7 +28,8 @@
|
|||||||
#define MAXPOWERUPS 3 /* Max powerups allowed on screen */
|
#define MAXPOWERUPS 3 /* Max powerups allowed on screen */
|
||||||
#define POWERUPSTTL 400 /* Max powerup time to live, in ticks. */
|
#define POWERUPSTTL 400 /* Max powerup time to live, in ticks. */
|
||||||
#define SHIP_HIT_ANIMATION_LEN 15
|
#define SHIP_HIT_ANIMATION_LEN 15
|
||||||
#define SAVING_FILENAME APP_DATA_PATH("game_asteroids.save")
|
#define SAVING_DIRECTORY STORAGE_APP_DATA_PATH_PREFIX
|
||||||
|
#define SAVING_FILENAME SAVING_DIRECTORY "/game_asteroids.save"
|
||||||
#ifndef PI
|
#ifndef PI
|
||||||
#define PI 3.14159265358979f
|
#define PI 3.14159265358979f
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -6,11 +6,12 @@ App(
|
|||||||
cdefines=["APP_ASTEROIDS"],
|
cdefines=["APP_ASTEROIDS"],
|
||||||
requires=["gui"],
|
requires=["gui"],
|
||||||
stack_size=8 * 1024,
|
stack_size=8 * 1024,
|
||||||
|
order=50,
|
||||||
fap_icon="appicon.png",
|
fap_icon="appicon.png",
|
||||||
fap_icon_assets="assets",
|
fap_icon_assets="assets",
|
||||||
fap_category="Games",
|
fap_category="Games",
|
||||||
fap_author="@antirez & @SimplyMinimal",
|
fap_author="@antirez & @SimplyMinimal",
|
||||||
fap_weburl="https://github.com/antirez/flipper-asteroids",
|
fap_weburl="https://github.com/antirez/flipper-asteroids",
|
||||||
fap_version="1.0",
|
fap_version="1.1",
|
||||||
fap_description="Asteroids game",
|
fap_description="Asteroids game",
|
||||||
)
|
)
|
||||||
|
|||||||
13
applications/external/atomicdiceroller/application.fam
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
App(
|
||||||
|
appid="flipper_atomicdiceroller",
|
||||||
|
name="[J305] Atomic Dice Roller",
|
||||||
|
apptype=FlipperAppType.EXTERNAL,
|
||||||
|
entry_point="flipper_atomicdiceroller_app",
|
||||||
|
cdefines=["APP_ATOMICDICEROLLER"],
|
||||||
|
requires=[
|
||||||
|
"gui",
|
||||||
|
],
|
||||||
|
stack_size=2 * 1024,
|
||||||
|
fap_icon="atomicdiceroller.png",
|
||||||
|
fap_category="GPIO",
|
||||||
|
)
|
||||||
BIN
applications/external/atomicdiceroller/atomicdiceroller.png
vendored
Normal file
|
After Width: | Height: | Size: 8.2 KiB |
349
applications/external/atomicdiceroller/flipper_atomicdiceroller.c
vendored
Normal file
@@ -0,0 +1,349 @@
|
|||||||
|
// CC0 1.0 Universal (CC0 1.0)
|
||||||
|
// Public Domain Dedication
|
||||||
|
// https://github.com/nmrr
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <furi.h>
|
||||||
|
#include <gui/gui.h>
|
||||||
|
#include <input/input.h>
|
||||||
|
#include <notification/notification_messages.h>
|
||||||
|
#include <furi_hal_power.h>
|
||||||
|
#include <locale/locale.h>
|
||||||
|
#include <toolbox/crc32_calc.h>
|
||||||
|
#include <lib/toolbox/md5.h>
|
||||||
|
|
||||||
|
#define SCREEN_SIZE_X 128
|
||||||
|
#define SCREEN_SIZE_Y 64
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
EventTypeInput,
|
||||||
|
ClockEventTypeTick,
|
||||||
|
ClockEventTypeTickPause,
|
||||||
|
EventGPIO,
|
||||||
|
} EventType;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
EventType type;
|
||||||
|
InputEvent input;
|
||||||
|
} EventApp;
|
||||||
|
|
||||||
|
#define lineArraySize 128
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
FuriMutex* mutex;
|
||||||
|
uint32_t cps;
|
||||||
|
uint32_t diceAvailiable;
|
||||||
|
uint8_t dice;
|
||||||
|
uint8_t method;
|
||||||
|
uint8_t pause;
|
||||||
|
} mutexStruct;
|
||||||
|
|
||||||
|
static void draw_callback(Canvas* canvas, void* ctx) {
|
||||||
|
mutexStruct* mutexVal = ctx;
|
||||||
|
mutexStruct mutexDraw;
|
||||||
|
furi_mutex_acquire(mutexVal->mutex, FuriWaitForever);
|
||||||
|
memcpy(&mutexDraw, mutexVal, sizeof(mutexStruct));
|
||||||
|
furi_mutex_release(mutexVal->mutex);
|
||||||
|
|
||||||
|
canvas_set_font(canvas, FontPrimary);
|
||||||
|
char buffer[32];
|
||||||
|
snprintf(buffer, sizeof(buffer), "%ld cps", mutexDraw.cps);
|
||||||
|
canvas_draw_str_aligned(canvas, 0, 10, AlignLeft, AlignBottom, buffer);
|
||||||
|
|
||||||
|
snprintf(buffer, sizeof(buffer), "%lu/64", mutexDraw.diceAvailiable);
|
||||||
|
canvas_draw_str_aligned(canvas, SCREEN_SIZE_X, 10, AlignRight, AlignBottom, buffer);
|
||||||
|
|
||||||
|
if(mutexDraw.method == 0)
|
||||||
|
canvas_draw_str_aligned(canvas, 0, 20, AlignLeft, AlignBottom, "Hash: CRC32");
|
||||||
|
else
|
||||||
|
canvas_draw_str_aligned(canvas, 0, 20, AlignLeft, AlignBottom, "Hash: MD5");
|
||||||
|
|
||||||
|
if(mutexDraw.dice != 0 && mutexDraw.pause == 0) {
|
||||||
|
canvas_set_font(canvas, FontBigNumbers);
|
||||||
|
snprintf(buffer, sizeof(buffer), "%u", mutexDraw.dice);
|
||||||
|
canvas_draw_str_aligned(canvas, SCREEN_SIZE_X / 2, 50, AlignCenter, AlignBottom, buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void input_callback(InputEvent* input_event, void* ctx) {
|
||||||
|
furi_assert(ctx);
|
||||||
|
FuriMessageQueue* event_queue = ctx;
|
||||||
|
EventApp event = {.type = EventTypeInput, .input = *input_event};
|
||||||
|
furi_message_queue_put(event_queue, &event, FuriWaitForever);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clock_tick(void* ctx) {
|
||||||
|
furi_assert(ctx);
|
||||||
|
|
||||||
|
FuriMessageQueue* queue = ctx;
|
||||||
|
EventApp event = {.type = ClockEventTypeTick};
|
||||||
|
furi_message_queue_put(queue, &event, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clock_tick_pause(void* ctx) {
|
||||||
|
furi_assert(ctx);
|
||||||
|
|
||||||
|
FuriMessageQueue* queue = ctx;
|
||||||
|
EventApp event = {.type = ClockEventTypeTickPause};
|
||||||
|
furi_message_queue_put(queue, &event, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gpiocallback(void* ctx) {
|
||||||
|
furi_assert(ctx);
|
||||||
|
FuriMessageQueue* queue = ctx;
|
||||||
|
EventApp event = {.type = EventGPIO};
|
||||||
|
furi_message_queue_put(queue, &event, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t flipper_atomicdiceroller_app() {
|
||||||
|
furi_hal_bus_enable(FuriHalBusTIM2);
|
||||||
|
LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP);
|
||||||
|
LL_TIM_SetClockDivision(TIM2, LL_TIM_CLOCKDIVISION_DIV1);
|
||||||
|
LL_TIM_SetPrescaler(TIM2, 0);
|
||||||
|
LL_TIM_SetAutoReload(TIM2, 0xFFFFFFFF);
|
||||||
|
LL_TIM_SetCounter(TIM2, 0);
|
||||||
|
LL_TIM_EnableCounter(TIM2);
|
||||||
|
|
||||||
|
EventApp event;
|
||||||
|
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(EventApp));
|
||||||
|
|
||||||
|
furi_hal_gpio_init(&gpio_ext_pa7, GpioModeInterruptFall, GpioPullUp, GpioSpeedVeryHigh);
|
||||||
|
|
||||||
|
mutexStruct mutexVal;
|
||||||
|
mutexVal.cps = 0;
|
||||||
|
mutexVal.dice = 0;
|
||||||
|
mutexVal.diceAvailiable = 0;
|
||||||
|
mutexVal.method = 0;
|
||||||
|
uint32_t counter = 0;
|
||||||
|
|
||||||
|
mutexVal.mutex = furi_mutex_alloc(FuriMutexTypeNormal);
|
||||||
|
if(!mutexVal.mutex) {
|
||||||
|
furi_message_queue_free(event_queue);
|
||||||
|
return 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
ViewPort* view_port = view_port_alloc();
|
||||||
|
view_port_draw_callback_set(view_port, draw_callback, &mutexVal.mutex);
|
||||||
|
view_port_input_callback_set(view_port, input_callback, event_queue);
|
||||||
|
|
||||||
|
furi_hal_gpio_add_int_callback(&gpio_ext_pa7, gpiocallback, event_queue);
|
||||||
|
|
||||||
|
Gui* gui = furi_record_open(RECORD_GUI);
|
||||||
|
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||||
|
|
||||||
|
FuriTimer* timer = furi_timer_alloc(clock_tick, FuriTimerTypePeriodic, event_queue);
|
||||||
|
furi_timer_start(timer, 1000);
|
||||||
|
|
||||||
|
FuriTimer* timerPause = furi_timer_alloc(clock_tick_pause, FuriTimerTypePeriodic, event_queue);
|
||||||
|
|
||||||
|
// ENABLE 5V pin
|
||||||
|
uint8_t attempts = 0;
|
||||||
|
while(!furi_hal_power_is_otg_enabled() && attempts++ < 5) {
|
||||||
|
furi_hal_power_enable_otg();
|
||||||
|
furi_delay_ms(10);
|
||||||
|
}
|
||||||
|
uint8_t diceBuffer[64];
|
||||||
|
for(uint8_t i = 0; i < 64; i++) diceBuffer[i] = 0;
|
||||||
|
|
||||||
|
uint8_t diceBufferCounter = 0;
|
||||||
|
uint8_t diceBufferPositionWrite = 0;
|
||||||
|
uint8_t diceBufferPositionRead = 0;
|
||||||
|
uint8_t tickCounter = 0;
|
||||||
|
uint32_t CRC32 = 0;
|
||||||
|
uint8_t method = 0;
|
||||||
|
|
||||||
|
// MD5
|
||||||
|
md5_context* md5_ctx = malloc(sizeof(md5_context));
|
||||||
|
uint8_t* hash = malloc(sizeof(uint8_t) * 16);
|
||||||
|
uint8_t* bufferTim2 = malloc(4);
|
||||||
|
md5_starts(md5_ctx);
|
||||||
|
|
||||||
|
uint8_t pause = 0;
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
FuriStatus event_status = furi_message_queue_get(event_queue, &event, FuriWaitForever);
|
||||||
|
|
||||||
|
uint8_t screenRefresh = 0;
|
||||||
|
|
||||||
|
if(event_status == FuriStatusOk) {
|
||||||
|
if(event.type == EventTypeInput) {
|
||||||
|
if(event.input.key == InputKeyBack && event.input.type == InputTypeLong) {
|
||||||
|
break;
|
||||||
|
} else if(pause == 0) {
|
||||||
|
if(event.input.key == InputKeyOk && event.input.type == InputTypeShort) {
|
||||||
|
if(diceBufferCounter > 0) {
|
||||||
|
furi_mutex_acquire(mutexVal.mutex, FuriWaitForever);
|
||||||
|
mutexVal.dice = diceBuffer[diceBufferPositionRead];
|
||||||
|
mutexVal.diceAvailiable = --diceBufferCounter;
|
||||||
|
mutexVal.pause = 1;
|
||||||
|
furi_mutex_release(mutexVal.mutex);
|
||||||
|
|
||||||
|
if(diceBufferPositionRead != 63)
|
||||||
|
diceBufferPositionRead++;
|
||||||
|
else
|
||||||
|
diceBufferPositionRead = 0;
|
||||||
|
|
||||||
|
pause = 1;
|
||||||
|
furi_timer_start(timerPause, 500);
|
||||||
|
screenRefresh = 1;
|
||||||
|
}
|
||||||
|
} else if(event.input.key == InputKeyLeft && event.input.type == InputTypeLong) {
|
||||||
|
if(method == 1) {
|
||||||
|
method = 0;
|
||||||
|
diceBufferPositionWrite = 0;
|
||||||
|
diceBufferPositionRead = 0;
|
||||||
|
diceBufferCounter = 0;
|
||||||
|
CRC32 = 0;
|
||||||
|
tickCounter = 0;
|
||||||
|
furi_mutex_acquire(mutexVal.mutex, FuriWaitForever);
|
||||||
|
mutexVal.method = 0;
|
||||||
|
mutexVal.dice = 0;
|
||||||
|
mutexVal.diceAvailiable = 0;
|
||||||
|
furi_mutex_release(mutexVal.mutex);
|
||||||
|
screenRefresh = 1;
|
||||||
|
}
|
||||||
|
} else if(event.input.key == InputKeyRight && event.input.type == InputTypeLong) {
|
||||||
|
if(method == 0) {
|
||||||
|
method = 1;
|
||||||
|
diceBufferPositionWrite = 0;
|
||||||
|
diceBufferPositionRead = 0;
|
||||||
|
diceBufferCounter = 0;
|
||||||
|
md5_starts(md5_ctx);
|
||||||
|
tickCounter = 0;
|
||||||
|
furi_mutex_acquire(mutexVal.mutex, FuriWaitForever);
|
||||||
|
mutexVal.method = 1;
|
||||||
|
mutexVal.dice = 0;
|
||||||
|
mutexVal.diceAvailiable = 0;
|
||||||
|
furi_mutex_release(mutexVal.mutex);
|
||||||
|
screenRefresh = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(event.type == ClockEventTypeTick) {
|
||||||
|
furi_mutex_acquire(mutexVal.mutex, FuriWaitForever);
|
||||||
|
mutexVal.cps = counter;
|
||||||
|
furi_mutex_release(mutexVal.mutex);
|
||||||
|
|
||||||
|
counter = 0;
|
||||||
|
screenRefresh = 1;
|
||||||
|
} else if(event.type == ClockEventTypeTickPause) {
|
||||||
|
furi_mutex_acquire(mutexVal.mutex, FuriWaitForever);
|
||||||
|
mutexVal.pause = 0;
|
||||||
|
furi_mutex_release(mutexVal.mutex);
|
||||||
|
|
||||||
|
furi_timer_stop(timerPause);
|
||||||
|
|
||||||
|
pause = 0;
|
||||||
|
screenRefresh = 1;
|
||||||
|
} else if(event.type == EventGPIO) {
|
||||||
|
if(diceBufferCounter < 64) {
|
||||||
|
// CRC32
|
||||||
|
if(method == 0) {
|
||||||
|
uint32_t TIM2Tick = TIM2->CNT;
|
||||||
|
bufferTim2[0] = (uint8_t)(TIM2Tick >> 24);
|
||||||
|
bufferTim2[1] = (uint8_t)(TIM2Tick >> 16);
|
||||||
|
bufferTim2[2] = (uint8_t)(TIM2Tick >> 8);
|
||||||
|
bufferTim2[3] = (uint8_t)TIM2Tick;
|
||||||
|
CRC32 = crc32_calc_buffer(CRC32, bufferTim2, 4);
|
||||||
|
tickCounter++;
|
||||||
|
|
||||||
|
if(tickCounter == 8) {
|
||||||
|
uint8_t localDice = CRC32 & 0b111;
|
||||||
|
|
||||||
|
if(localDice == 0 || localDice == 7) {
|
||||||
|
localDice = (diceBuffer[diceBufferPositionRead] >> 3) & 0b111;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(localDice >= 1 && localDice <= 6) {
|
||||||
|
diceBuffer[diceBufferPositionWrite] = localDice;
|
||||||
|
diceBufferCounter++;
|
||||||
|
if(diceBufferPositionWrite != 63)
|
||||||
|
diceBufferPositionWrite++;
|
||||||
|
else
|
||||||
|
diceBufferPositionWrite = 0;
|
||||||
|
|
||||||
|
furi_mutex_acquire(mutexVal.mutex, FuriWaitForever);
|
||||||
|
mutexVal.diceAvailiable = diceBufferCounter;
|
||||||
|
furi_mutex_release(mutexVal.mutex);
|
||||||
|
|
||||||
|
screenRefresh = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
CRC32 = 0;
|
||||||
|
tickCounter = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// MD5
|
||||||
|
else {
|
||||||
|
uint32_t tick = TIM2->CNT;
|
||||||
|
bufferTim2[0] = (uint8_t)(tick >> 24);
|
||||||
|
bufferTim2[1] = (uint8_t)(tick >> 16);
|
||||||
|
bufferTim2[2] = (uint8_t)(tick >> 8);
|
||||||
|
bufferTim2[3] = (uint8_t)tick;
|
||||||
|
md5_update(md5_ctx, bufferTim2, 4);
|
||||||
|
|
||||||
|
tickCounter++;
|
||||||
|
|
||||||
|
if(tickCounter == 32) {
|
||||||
|
md5_finish(md5_ctx, hash);
|
||||||
|
uint8_t localDice = 0;
|
||||||
|
|
||||||
|
for(uint8_t i = 0; i < 16; i++) {
|
||||||
|
localDice = hash[i] & 0b111;
|
||||||
|
if(localDice >= 1 && localDice <= 6) {
|
||||||
|
diceBuffer[diceBufferPositionWrite] = localDice;
|
||||||
|
diceBufferCounter++;
|
||||||
|
if(diceBufferPositionWrite != 63)
|
||||||
|
diceBufferPositionWrite++;
|
||||||
|
else
|
||||||
|
diceBufferPositionWrite = 0;
|
||||||
|
|
||||||
|
furi_mutex_acquire(mutexVal.mutex, FuriWaitForever);
|
||||||
|
mutexVal.diceAvailiable = diceBufferCounter;
|
||||||
|
furi_mutex_release(mutexVal.mutex);
|
||||||
|
|
||||||
|
screenRefresh = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
md5_starts(md5_ctx);
|
||||||
|
tickCounter = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(screenRefresh == 1) view_port_update(view_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
LL_TIM_DisableCounter(TIM2);
|
||||||
|
furi_hal_bus_disable(FuriHalBusTIM2);
|
||||||
|
|
||||||
|
free(md5_ctx);
|
||||||
|
free(bufferTim2);
|
||||||
|
free(hash);
|
||||||
|
|
||||||
|
furi_record_close(RECORD_NOTIFICATION);
|
||||||
|
|
||||||
|
// Disable 5v power
|
||||||
|
if(furi_hal_power_is_otg_enabled()) {
|
||||||
|
furi_hal_power_disable_otg();
|
||||||
|
}
|
||||||
|
|
||||||
|
furi_hal_gpio_disable_int_callback(&gpio_ext_pa7);
|
||||||
|
furi_hal_gpio_remove_int_callback(&gpio_ext_pa7);
|
||||||
|
|
||||||
|
furi_message_queue_free(event_queue);
|
||||||
|
furi_mutex_free(mutexVal.mutex);
|
||||||
|
gui_remove_view_port(gui, view_port);
|
||||||
|
view_port_free(view_port);
|
||||||
|
furi_timer_free(timer);
|
||||||
|
furi_timer_free(timerPause);
|
||||||
|
furi_record_close(RECORD_GUI);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
@@ -1,8 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "helpers/avr_isp_types.h"
|
#include "helpers/avr_isp_types.h"
|
||||||
#include "avr_isp_icons.h"
|
#include <avr_isp_icons.h>
|
||||||
#include <assets_icons.h>
|
|
||||||
|
|
||||||
#include "scenes/avr_isp_scene.h"
|
#include "scenes/avr_isp_scene.h"
|
||||||
#include <gui/gui.h>
|
#include <gui/gui.h>
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
#define AVR_ISP_VERSION_APP "0.1"
|
#define AVR_ISP_VERSION_APP "0.1"
|
||||||
#define AVR_ISP_DEVELOPED "SkorP"
|
#define AVR_ISP_DEVELOPED "SkorP"
|
||||||
#define AVR_ISP_GITHUB "https://github.com/flipperdevices/flipperzero-firmware"
|
#define AVR_ISP_GITHUB "https://github.com/flipperdevices/flipperzero-good-faps"
|
||||||
|
|
||||||
#define AVR_ISP_APP_FILE_VERSION 1
|
#define AVR_ISP_APP_FILE_VERSION 1
|
||||||
#define AVR_ISP_APP_FILE_TYPE "Flipper Dump AVR"
|
#define AVR_ISP_APP_FILE_TYPE "Flipper Dump AVR"
|
||||||
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
@@ -1,6 +1,8 @@
|
|||||||
#include "../avr_isp_app_i.h"
|
#include "../avr_isp_app_i.h"
|
||||||
#include <gui/modules/validators.h>
|
#include <gui/modules/validators.h>
|
||||||
|
|
||||||
|
#define MAX_TEXT_INPUT_LEN 22
|
||||||
|
|
||||||
void avr_isp_scene_input_name_text_callback(void* context) {
|
void avr_isp_scene_input_name_text_callback(void* context) {
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
|
|
||||||
@@ -44,7 +46,7 @@ void avr_isp_scene_input_name_on_enter(void* context) {
|
|||||||
avr_isp_scene_input_name_text_callback,
|
avr_isp_scene_input_name_text_callback,
|
||||||
app,
|
app,
|
||||||
app->file_name_tmp,
|
app->file_name_tmp,
|
||||||
AVR_ISP_MAX_LEN_NAME, // buffer size
|
MAX_TEXT_INPUT_LEN, // buffer size
|
||||||
dev_name_empty);
|
dev_name_empty);
|
||||||
|
|
||||||
ValidatorIsFile* validator_is_file =
|
ValidatorIsFile* validator_is_file =
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
#include "avr_isp_view_chip_detect.h"
|
#include "avr_isp_view_chip_detect.h"
|
||||||
#include "avr_isp_icons.h"
|
#include <avr_isp_icons.h>
|
||||||
#include <assets_icons.h>
|
|
||||||
#include <gui/elements.h>
|
#include <gui/elements.h>
|
||||||
|
|
||||||
#include "../helpers/avr_isp_worker_rw.h"
|
#include "../helpers/avr_isp_worker_rw.h"
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
#include "avr_isp_view_programmer.h"
|
#include "avr_isp_view_programmer.h"
|
||||||
#include "avr_isp_icons.h"
|
#include <avr_isp_icons.h>
|
||||||
#include <assets_icons.h>
|
|
||||||
|
|
||||||
#include "../helpers/avr_isp_worker.h"
|
#include "../helpers/avr_isp_worker.h"
|
||||||
#include <gui/elements.h>
|
#include <gui/elements.h>
|
||||||
@@ -8,7 +8,7 @@ App(
|
|||||||
fap_category="Tools",
|
fap_category="Tools",
|
||||||
fap_icon="images/barcode_10.png",
|
fap_icon="images/barcode_10.png",
|
||||||
fap_icon_assets="images",
|
fap_icon_assets="images",
|
||||||
fap_file_assets="barcode_encoding_files",
|
fap_file_assets="encoding_tables",
|
||||||
fap_author="@Kingal1337",
|
fap_author="@Kingal1337",
|
||||||
fap_weburl="https://github.com/Kingal1337/flipper-barcode-generator",
|
fap_weburl="https://github.com/Kingal1337/flipper-barcode-generator",
|
||||||
fap_version="1.1",
|
fap_version="1.1",
|
||||||
|
|||||||
@@ -3,12 +3,13 @@ App(
|
|||||||
name="BlackJack",
|
name="BlackJack",
|
||||||
apptype=FlipperAppType.EXTERNAL,
|
apptype=FlipperAppType.EXTERNAL,
|
||||||
entry_point="blackjack_app",
|
entry_point="blackjack_app",
|
||||||
requires=["gui", "storage", "canvas"],
|
requires=["gui","storage","canvas"],
|
||||||
stack_size=2 * 1024,
|
stack_size=2 * 1024,
|
||||||
|
order=30,
|
||||||
fap_icon="blackjack_10px.png",
|
fap_icon="blackjack_10px.png",
|
||||||
fap_category="Games",
|
fap_category="Games",
|
||||||
fap_icon_assets="assets",
|
fap_icon_assets="assets",
|
||||||
fap_author="@teeebor",
|
fap_author="@teeebor",
|
||||||
fap_version="1.0",
|
fap_version="1.1",
|
||||||
fap_description="Blackjack Game",
|
fap_description="Blackjack Game",
|
||||||
)
|
)
|
||||||
18
applications/external/blackjack/blackjack.c
vendored
@@ -15,7 +15,6 @@
|
|||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
|
|
||||||
#include "blackjack_icons.h"
|
#include "blackjack_icons.h"
|
||||||
#include <assets_icons.h>
|
|
||||||
|
|
||||||
#define DEALER_MAX 17
|
#define DEALER_MAX 17
|
||||||
|
|
||||||
@@ -34,9 +33,12 @@ static void draw_ui(Canvas* const canvas, const GameState* game_state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void render_callback(Canvas* const canvas, void* ctx) {
|
static void render_callback(Canvas* const canvas, void* ctx) {
|
||||||
furi_assert(ctx);
|
|
||||||
const GameState* game_state = ctx;
|
const GameState* game_state = ctx;
|
||||||
furi_mutex_acquire(game_state->mutex, FuriWaitForever);
|
furi_mutex_acquire(game_state->mutex, 25);
|
||||||
|
|
||||||
|
if(game_state == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
canvas_set_color(canvas, ColorBlack);
|
canvas_set_color(canvas, ColorBlack);
|
||||||
canvas_draw_frame(canvas, 0, 0, 128, 64);
|
canvas_draw_frame(canvas, 0, 0, 128, 64);
|
||||||
@@ -177,6 +179,7 @@ void lose(void* ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void win(void* ctx) {
|
void win(void* ctx) {
|
||||||
|
dolphin_deed(DolphinDeedPluginGameWin);
|
||||||
GameState* game_state = ctx;
|
GameState* game_state = ctx;
|
||||||
game_state->state = GameStatePlay;
|
game_state->state = GameStatePlay;
|
||||||
game_state->player_score += game_state->bet * 2;
|
game_state->player_score += game_state->bet * 2;
|
||||||
@@ -277,7 +280,6 @@ void dealer_tick(GameState* game_state) {
|
|||||||
|
|
||||||
if(dealer_score >= DEALER_MAX) {
|
if(dealer_score >= DEALER_MAX) {
|
||||||
if(dealer_score > 21 || dealer_score < player_score) {
|
if(dealer_score > 21 || dealer_score < player_score) {
|
||||||
dolphin_deed(DolphinDeedPluginGameWin);
|
|
||||||
enqueue(
|
enqueue(
|
||||||
&(game_state->queue_state),
|
&(game_state->queue_state),
|
||||||
game_state,
|
game_state,
|
||||||
@@ -540,7 +542,7 @@ int32_t blackjack_app(void* p) {
|
|||||||
int32_t return_code = 0;
|
int32_t return_code = 0;
|
||||||
|
|
||||||
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(AppEvent));
|
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(AppEvent));
|
||||||
|
dolphin_deed(DolphinDeedPluginGameStart);
|
||||||
GameState* game_state = malloc(sizeof(GameState));
|
GameState* game_state = malloc(sizeof(GameState));
|
||||||
game_state->menu = malloc(sizeof(Menu));
|
game_state->menu = malloc(sizeof(Menu));
|
||||||
game_state->menu->menu_width = 40;
|
game_state->menu->menu_width = 40;
|
||||||
@@ -571,9 +573,6 @@ int32_t blackjack_app(void* p) {
|
|||||||
|
|
||||||
AppEvent event;
|
AppEvent event;
|
||||||
|
|
||||||
// Call dolphin deed on game start
|
|
||||||
dolphin_deed(DolphinDeedPluginGameStart);
|
|
||||||
|
|
||||||
for(bool processing = true; processing;) {
|
for(bool processing = true; processing;) {
|
||||||
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
|
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
|
||||||
furi_mutex_acquire(game_state->mutex, FuriWaitForever);
|
furi_mutex_acquire(game_state->mutex, FuriWaitForever);
|
||||||
@@ -612,8 +611,9 @@ int32_t blackjack_app(void* p) {
|
|||||||
processing = game_state->processing;
|
processing = game_state->processing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
view_port_update(view_port);
|
|
||||||
furi_mutex_release(game_state->mutex);
|
furi_mutex_release(game_state->mutex);
|
||||||
|
view_port_update(view_port);
|
||||||
}
|
}
|
||||||
|
|
||||||
furi_timer_free(timer);
|
furi_timer_free(timer);
|
||||||
|
|||||||
@@ -350,4 +350,4 @@ void add_hand_region(Hand* to, Hand* from) {
|
|||||||
add_to_hand(to, from->cards[i]);
|
add_to_hand(to, from->cards[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
2
applications/external/blackjack/defines.h
vendored
@@ -54,7 +54,6 @@ typedef enum {
|
|||||||
} Direction;
|
} Direction;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
FuriMutex* mutex;
|
|
||||||
Card player_cards[21];
|
Card player_cards[21];
|
||||||
Card dealer_cards[21];
|
Card dealer_cards[21];
|
||||||
uint8_t player_card_count;
|
uint8_t player_card_count;
|
||||||
@@ -74,4 +73,5 @@ typedef struct {
|
|||||||
QueueState queue_state;
|
QueueState queue_state;
|
||||||
Menu* menu;
|
Menu* menu;
|
||||||
unsigned int last_tick;
|
unsigned int last_tick;
|
||||||
|
FuriMutex* mutex;
|
||||||
} GameState;
|
} GameState;
|
||||||
|
|||||||
2
applications/external/blackjack/ui.c
vendored
@@ -81,7 +81,7 @@ void draw_score(Canvas* const canvas, bool top, uint8_t amount) {
|
|||||||
|
|
||||||
void draw_money(Canvas* const canvas, uint32_t score) {
|
void draw_money(Canvas* const canvas, uint32_t score) {
|
||||||
canvas_set_font(canvas, FontSecondary);
|
canvas_set_font(canvas, FontSecondary);
|
||||||
char drawChar[11];
|
char drawChar[10];
|
||||||
uint32_t currAmount = score;
|
uint32_t currAmount = score;
|
||||||
if(currAmount < 1000) {
|
if(currAmount < 1000) {
|
||||||
snprintf(drawChar, sizeof(drawChar), "$%lu", currAmount);
|
snprintf(drawChar, sizeof(drawChar), "$%lu", currAmount);
|
||||||
|
|||||||
2
applications/external/blackjack/util.c
vendored
@@ -121,4 +121,4 @@ Settings load_settings() {
|
|||||||
flipper_format_free(file);
|
flipper_format_free(file);
|
||||||
furi_record_close(RECORD_STORAGE);
|
furi_record_close(RECORD_STORAGE);
|
||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
@@ -7,10 +7,11 @@ App(
|
|||||||
"gui",
|
"gui",
|
||||||
],
|
],
|
||||||
stack_size=1 * 1024,
|
stack_size=1 * 1024,
|
||||||
fap_icon="bomb.png",
|
order=90,
|
||||||
|
fap_icon="bomb.png",
|
||||||
fap_category="Games",
|
fap_category="Games",
|
||||||
fap_icon_assets="assets",
|
fap_icon_assets="assets",
|
||||||
fap_author="@leo-need-more-coffee & @xMasterX",
|
fap_author="@leo-need-more-coffee & @xMasterX",
|
||||||
fap_version="1.0",
|
fap_version="1.1",
|
||||||
fap_description="Bomberduck(Bomberman) Game",
|
fap_description="Bomberduck(Bomberman) Game",
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
#include <notification/notification.h>
|
#include <notification/notification.h>
|
||||||
#include <notification/notification_messages.h>
|
#include <notification/notification_messages.h>
|
||||||
#include "bomberduck_icons.h"
|
#include "bomberduck_icons.h"
|
||||||
#include <assets_icons.h>
|
|
||||||
#include <dolphin/dolphin.h>
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
int max(int a, int b) {
|
int max(int a, int b) {
|
||||||
@@ -626,8 +625,8 @@ int32_t bomberduck_app(void* p) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
view_port_update(view_port);
|
|
||||||
furi_mutex_release(bomber_state->mutex);
|
furi_mutex_release(bomber_state->mutex);
|
||||||
|
view_port_update(view_port);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return to normal backlight settings
|
// Return to normal backlight settings
|
||||||
|
|||||||
@@ -3,14 +3,14 @@ App(
|
|||||||
name="BPM Tapper",
|
name="BPM Tapper",
|
||||||
apptype=FlipperAppType.EXTERNAL,
|
apptype=FlipperAppType.EXTERNAL,
|
||||||
entry_point="bpm_tapper_app",
|
entry_point="bpm_tapper_app",
|
||||||
cdefines=["APP_BPM_TAPPER"],
|
|
||||||
requires=["gui"],
|
requires=["gui"],
|
||||||
stack_size=2 * 1024,
|
stack_size=2 * 1024,
|
||||||
fap_icon="bpm_10px.png",
|
fap_icon="bpm_10px.png",
|
||||||
fap_category="Media",
|
fap_category="Media",
|
||||||
fap_icon_assets="icons",
|
fap_icon_assets="icons",
|
||||||
|
order=15,
|
||||||
fap_author="@panki27",
|
fap_author="@panki27",
|
||||||
fap_weburl="https://github.com/panki27/bpm-tapper",
|
fap_weburl="https://github.com/panki27/bpm-tapper",
|
||||||
fap_version="1.0",
|
fap_version="1.1",
|
||||||
fap_description="Tap center button to measure BPM",
|
fap_description="Tap center button to measure BPM",
|
||||||
)
|
)
|
||||||
|
|||||||
7
applications/external/bpmtapper/bpm.c
vendored
@@ -3,8 +3,10 @@
|
|||||||
#include <dialogs/dialogs.h>
|
#include <dialogs/dialogs.h>
|
||||||
#include <gui/gui.h>
|
#include <gui/gui.h>
|
||||||
#include <input/input.h>
|
#include <input/input.h>
|
||||||
|
#include <core/string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "bpm_tapper_icons.h"
|
#include "bpm_tapper_icons.h"
|
||||||
|
|
||||||
#include <assets_icons.h>
|
#include <assets_icons.h>
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -176,6 +178,7 @@ static void bpm_state_init(BPMTapper* const plugin_state) {
|
|||||||
q = malloc(sizeof(queue));
|
q = malloc(sizeof(queue));
|
||||||
init_queue(q);
|
init_queue(q);
|
||||||
plugin_state->tap_queue = q;
|
plugin_state->tap_queue = q;
|
||||||
|
plugin_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t bpm_tapper_app(void* p) {
|
int32_t bpm_tapper_app(void* p) {
|
||||||
@@ -187,7 +190,6 @@ int32_t bpm_tapper_app(void* p) {
|
|||||||
// setup
|
// setup
|
||||||
bpm_state_init(bpm_state);
|
bpm_state_init(bpm_state);
|
||||||
|
|
||||||
bpm_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
|
|
||||||
if(!bpm_state->mutex) {
|
if(!bpm_state->mutex) {
|
||||||
FURI_LOG_E("BPM-Tapper", "cannot create mutex\r\n");
|
FURI_LOG_E("BPM-Tapper", "cannot create mutex\r\n");
|
||||||
free(bpm_state);
|
free(bpm_state);
|
||||||
@@ -243,8 +245,9 @@ int32_t bpm_tapper_app(void* p) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
view_port_update(view_port);
|
|
||||||
furi_mutex_release(bpm_state->mutex);
|
furi_mutex_release(bpm_state->mutex);
|
||||||
|
view_port_update(view_port);
|
||||||
}
|
}
|
||||||
view_port_enabled_set(view_port, false);
|
view_port_enabled_set(view_port, false);
|
||||||
gui_remove_view_port(gui, view_port);
|
gui_remove_view_port(gui, view_port);
|
||||||
|
|||||||
@@ -13,6 +13,6 @@ App(
|
|||||||
fap_icon_assets="icons",
|
fap_icon_assets="icons",
|
||||||
fap_author="@nymda",
|
fap_author="@nymda",
|
||||||
fap_weburl="https://github.com/nymda/FlipperZeroBrainfuck",
|
fap_weburl="https://github.com/nymda/FlipperZeroBrainfuck",
|
||||||
fap_version="1.0",
|
fap_version="1.1",
|
||||||
fap_description="Brainfuck language interpreter",
|
fap_description="Brainfuck language interpreter",
|
||||||
)
|
)
|
||||||
|
|||||||
3
applications/external/brainfuck/brainfuck.c
vendored
@@ -117,7 +117,6 @@ void brainfuck_free(BFApp* brainfuck) {
|
|||||||
|
|
||||||
void brainfuck_show_loading_popup(void* context, bool show) {
|
void brainfuck_show_loading_popup(void* context, bool show) {
|
||||||
BFApp* brainfuck = context;
|
BFApp* brainfuck = context;
|
||||||
TaskHandle_t timer_task = xTaskGetHandle(configTIMER_SERVICE_TASK_NAME);
|
|
||||||
|
|
||||||
if(show) {
|
if(show) {
|
||||||
// Raise timer priority so that animations can play
|
// Raise timer priority so that animations can play
|
||||||
@@ -146,4 +145,4 @@ int32_t brainfuck_app(void* p) {
|
|||||||
brainfuck_free(brainfuck);
|
brainfuck_free(brainfuck);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -29,8 +29,7 @@ typedef unsigned char byte;
|
|||||||
|
|
||||||
#include <storage/storage.h>
|
#include <storage/storage.h>
|
||||||
#include <lib/toolbox/path.h>
|
#include <lib/toolbox/path.h>
|
||||||
#include "brainfuck_icons.h"
|
#include <brainfuck_icons.h>
|
||||||
#include <assets_icons.h>
|
|
||||||
|
|
||||||
#include <storage/storage.h>
|
#include <storage/storage.h>
|
||||||
#include <stream/stream.h>
|
#include <stream/stream.h>
|
||||||
@@ -39,6 +38,8 @@ typedef unsigned char byte;
|
|||||||
|
|
||||||
#include <notification/notification_messages.h>
|
#include <notification/notification_messages.h>
|
||||||
|
|
||||||
|
#include <assets_icons.h>
|
||||||
|
|
||||||
#define BF_INST_BUFFER_SIZE 2048
|
#define BF_INST_BUFFER_SIZE 2048
|
||||||
#define BF_OUTPUT_SIZE 512
|
#define BF_OUTPUT_SIZE 512
|
||||||
#define BF_STACK_INITIAL_SIZE 128
|
#define BF_STACK_INITIAL_SIZE 128
|
||||||
|
|||||||
@@ -10,8 +10,9 @@ App(
|
|||||||
stack_size=2 * 1024,
|
stack_size=2 * 1024,
|
||||||
fap_icon="caesar_cipher_icon.png",
|
fap_icon="caesar_cipher_icon.png",
|
||||||
fap_category="Tools",
|
fap_category="Tools",
|
||||||
|
order=20,
|
||||||
fap_author="@panki27",
|
fap_author="@panki27",
|
||||||
fap_weburl="https://github.com/panki27/caesar-cipher",
|
fap_weburl="https://github.com/panki27/caesar-cipher",
|
||||||
fap_version="1.0",
|
fap_version="1.1",
|
||||||
fap_description="Encrypt and decrypt text using Caesar Cipher",
|
fap_description="Encrypt and decrypt text using Caesar Cipher",
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,8 +7,10 @@ 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_version="1.3",
|
||||||
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,
|
||||||
requires=["gui", "storage"],
|
requires=["gui", "storage"],
|
||||||
stack_size=8 * 1024,
|
stack_size=8 * 1024,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -44,9 +44,12 @@ CameraSuite* camera_suite_app_alloc() {
|
|||||||
|
|
||||||
// Set defaults, in case no config loaded
|
// Set defaults, in case no config loaded
|
||||||
app->orientation = 0; // Orientation is "portrait", zero degrees by default.
|
app->orientation = 0; // Orientation is "portrait", zero degrees by default.
|
||||||
app->haptic = 1; // Haptic is on by default
|
app->dither = 0; // Dither algorithm is "Floyd Steinberg" by default.
|
||||||
app->speaker = 1; // Speaker is on by default
|
app->flash = 1; // Flash is enabled by default.
|
||||||
app->led = 1; // LED is on 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->speaker = 1; // Speaker is enabled by default
|
||||||
|
app->led = 1; // LED is enabled by default
|
||||||
|
|
||||||
// Load configs
|
// Load configs
|
||||||
camera_suite_read_settings(app);
|
camera_suite_read_settings(app);
|
||||||
|
|||||||
@@ -30,7 +30,10 @@ typedef struct {
|
|||||||
CameraSuiteViewCamera* camera_suite_view_camera;
|
CameraSuiteViewCamera* camera_suite_view_camera;
|
||||||
CameraSuiteViewGuide* camera_suite_view_guide;
|
CameraSuiteViewGuide* camera_suite_view_guide;
|
||||||
uint32_t orientation;
|
uint32_t orientation;
|
||||||
|
uint32_t dither;
|
||||||
|
uint32_t flash;
|
||||||
uint32_t haptic;
|
uint32_t haptic;
|
||||||
|
uint32_t jpeg;
|
||||||
uint32_t speaker;
|
uint32_t speaker;
|
||||||
uint32_t led;
|
uint32_t led;
|
||||||
ButtonMenu* button_menu;
|
ButtonMenu* button_menu;
|
||||||
@@ -51,6 +54,22 @@ typedef enum {
|
|||||||
CameraSuiteOrientation270,
|
CameraSuiteOrientation270,
|
||||||
} CameraSuiteOrientationState;
|
} CameraSuiteOrientationState;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
CameraSuiteDitherFloydSteinberg,
|
||||||
|
CameraSuiteDitherStucki,
|
||||||
|
CameraSuiteDitherJarvisJudiceNinke,
|
||||||
|
} CameraSuiteDitherState;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
CameraSuiteFlashOff,
|
||||||
|
CameraSuiteFlashOn,
|
||||||
|
} CameraSuiteFlashState;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
CameraSuiteJpegOff,
|
||||||
|
CameraSuiteJpegOn,
|
||||||
|
} CameraSuiteJpegState;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
CameraSuiteHapticOff,
|
CameraSuiteHapticOff,
|
||||||
CameraSuiteHapticOn,
|
CameraSuiteHapticOn,
|
||||||
|
|||||||
@@ -51,6 +51,9 @@ void camera_suite_save_settings(void* context) {
|
|||||||
fff_file, BOILERPLATE_SETTINGS_HEADER, BOILERPLATE_SETTINGS_FILE_VERSION);
|
fff_file, BOILERPLATE_SETTINGS_HEADER, BOILERPLATE_SETTINGS_FILE_VERSION);
|
||||||
flipper_format_write_uint32(
|
flipper_format_write_uint32(
|
||||||
fff_file, BOILERPLATE_SETTINGS_KEY_ORIENTATION, &app->orientation, 1);
|
fff_file, BOILERPLATE_SETTINGS_KEY_ORIENTATION, &app->orientation, 1);
|
||||||
|
flipper_format_write_uint32(fff_file, BOILERPLATE_SETTINGS_KEY_DITHER, &app->dither, 1);
|
||||||
|
flipper_format_write_uint32(fff_file, BOILERPLATE_SETTINGS_KEY_FLASH, &app->flash, 1);
|
||||||
|
flipper_format_write_uint32(fff_file, BOILERPLATE_SETTINGS_KEY_JPEG, &app->jpeg, 1);
|
||||||
flipper_format_write_uint32(fff_file, BOILERPLATE_SETTINGS_KEY_HAPTIC, &app->haptic, 1);
|
flipper_format_write_uint32(fff_file, BOILERPLATE_SETTINGS_KEY_HAPTIC, &app->haptic, 1);
|
||||||
flipper_format_write_uint32(fff_file, BOILERPLATE_SETTINGS_KEY_SPEAKER, &app->speaker, 1);
|
flipper_format_write_uint32(fff_file, BOILERPLATE_SETTINGS_KEY_SPEAKER, &app->speaker, 1);
|
||||||
flipper_format_write_uint32(fff_file, BOILERPLATE_SETTINGS_KEY_LED, &app->led, 1);
|
flipper_format_write_uint32(fff_file, BOILERPLATE_SETTINGS_KEY_LED, &app->led, 1);
|
||||||
@@ -100,8 +103,12 @@ void camera_suite_read_settings(void* context) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read settings
|
||||||
flipper_format_read_uint32(
|
flipper_format_read_uint32(
|
||||||
fff_file, BOILERPLATE_SETTINGS_KEY_ORIENTATION, &app->orientation, 1);
|
fff_file, BOILERPLATE_SETTINGS_KEY_ORIENTATION, &app->orientation, 1);
|
||||||
|
flipper_format_read_uint32(fff_file, BOILERPLATE_SETTINGS_KEY_DITHER, &app->dither, 1);
|
||||||
|
flipper_format_read_uint32(fff_file, BOILERPLATE_SETTINGS_KEY_FLASH, &app->flash, 1);
|
||||||
|
flipper_format_read_uint32(fff_file, BOILERPLATE_SETTINGS_KEY_JPEG, &app->jpeg, 1);
|
||||||
flipper_format_read_uint32(fff_file, BOILERPLATE_SETTINGS_KEY_HAPTIC, &app->haptic, 1);
|
flipper_format_read_uint32(fff_file, BOILERPLATE_SETTINGS_KEY_HAPTIC, &app->haptic, 1);
|
||||||
flipper_format_read_uint32(fff_file, BOILERPLATE_SETTINGS_KEY_SPEAKER, &app->speaker, 1);
|
flipper_format_read_uint32(fff_file, BOILERPLATE_SETTINGS_KEY_SPEAKER, &app->speaker, 1);
|
||||||
flipper_format_read_uint32(fff_file, BOILERPLATE_SETTINGS_KEY_LED, &app->led, 1);
|
flipper_format_read_uint32(fff_file, BOILERPLATE_SETTINGS_KEY_LED, &app->led, 1);
|
||||||
|
|||||||
@@ -2,14 +2,21 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <storage/storage.h>
|
#include <storage/storage.h>
|
||||||
#include <flipper_format/flipper_format_i.h>
|
#include <flipper_format/flipper_format_i.h>
|
||||||
|
|
||||||
#include "../camera_suite.h"
|
#include "../camera_suite.h"
|
||||||
|
|
||||||
|
#ifndef CAMERA_SUITE_STORAGE_H
|
||||||
|
#define CAMERA_SUITE_STORAGE_H
|
||||||
|
|
||||||
#define BOILERPLATE_SETTINGS_FILE_VERSION 1
|
#define BOILERPLATE_SETTINGS_FILE_VERSION 1
|
||||||
#define CONFIG_FILE_DIRECTORY_PATH EXT_PATH("apps_data/camera_suite")
|
#define CONFIG_FILE_DIRECTORY_PATH EXT_PATH("apps_data/camera_suite")
|
||||||
#define BOILERPLATE_SETTINGS_SAVE_PATH CONFIG_FILE_DIRECTORY_PATH "/camera_suite.conf"
|
#define BOILERPLATE_SETTINGS_SAVE_PATH CONFIG_FILE_DIRECTORY_PATH "/camera_suite.conf"
|
||||||
#define BOILERPLATE_SETTINGS_SAVE_PATH_TMP BOILERPLATE_SETTINGS_SAVE_PATH ".tmp"
|
#define BOILERPLATE_SETTINGS_SAVE_PATH_TMP BOILERPLATE_SETTINGS_SAVE_PATH ".tmp"
|
||||||
#define BOILERPLATE_SETTINGS_HEADER "Camera Suite Config File"
|
#define BOILERPLATE_SETTINGS_HEADER "Camera Suite Config File"
|
||||||
#define BOILERPLATE_SETTINGS_KEY_ORIENTATION "Orientation"
|
#define BOILERPLATE_SETTINGS_KEY_ORIENTATION "Orientation"
|
||||||
|
#define BOILERPLATE_SETTINGS_KEY_DITHER "Dither"
|
||||||
|
#define BOILERPLATE_SETTINGS_KEY_FLASH "Flash"
|
||||||
|
#define BOILERPLATE_SETTINGS_KEY_JPEG "SaveJPEG"
|
||||||
#define BOILERPLATE_SETTINGS_KEY_HAPTIC "Haptic"
|
#define BOILERPLATE_SETTINGS_KEY_HAPTIC "Haptic"
|
||||||
#define BOILERPLATE_SETTINGS_KEY_LED "Led"
|
#define BOILERPLATE_SETTINGS_KEY_LED "Led"
|
||||||
#define BOILERPLATE_SETTINGS_KEY_SPEAKER "Speaker"
|
#define BOILERPLATE_SETTINGS_KEY_SPEAKER "Speaker"
|
||||||
@@ -18,3 +25,5 @@
|
|||||||
void camera_suite_save_settings(void* context);
|
void camera_suite_save_settings(void* context);
|
||||||
|
|
||||||
void camera_suite_read_settings(void* context);
|
void camera_suite_read_settings(void* context);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -16,6 +16,39 @@ const uint32_t orientation_value[4] = {
|
|||||||
CameraSuiteOrientation270,
|
CameraSuiteOrientation270,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Possible dithering types for the camera.
|
||||||
|
const char* const dither_text[28] = {
|
||||||
|
"Floyd-Steinberg",
|
||||||
|
"Stucki",
|
||||||
|
"Jarvis-Judice-Ninke",
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint32_t dither_value[4] = {
|
||||||
|
CameraSuiteDitherFloydSteinberg,
|
||||||
|
CameraSuiteDitherStucki,
|
||||||
|
CameraSuiteDitherJarvisJudiceNinke,
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* const flash_text[2] = {
|
||||||
|
"OFF",
|
||||||
|
"ON",
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint32_t flash_value[2] = {
|
||||||
|
CameraSuiteFlashOff,
|
||||||
|
CameraSuiteFlashOn,
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* const jpeg_text[2] = {
|
||||||
|
"OFF",
|
||||||
|
"ON",
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint32_t jpeg_value[2] = {
|
||||||
|
CameraSuiteJpegOff,
|
||||||
|
CameraSuiteJpegOn,
|
||||||
|
};
|
||||||
|
|
||||||
const char* const haptic_text[2] = {
|
const char* const haptic_text[2] = {
|
||||||
"OFF",
|
"OFF",
|
||||||
"ON",
|
"ON",
|
||||||
@@ -54,6 +87,30 @@ 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) {
|
||||||
|
CameraSuite* app = variable_item_get_context(item);
|
||||||
|
uint8_t index = variable_item_get_current_value_index(item);
|
||||||
|
|
||||||
|
variable_item_set_current_value_text(item, dither_text[index]);
|
||||||
|
app->dither = dither_value[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void camera_suite_scene_settings_set_flash(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, flash_text[index]);
|
||||||
|
app->flash = flash_value[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void camera_suite_scene_settings_set_jpeg(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, jpeg_text[index]);
|
||||||
|
app->jpeg = jpeg_value[index];
|
||||||
|
}
|
||||||
|
|
||||||
static void camera_suite_scene_settings_set_haptic(VariableItem* item) {
|
static void camera_suite_scene_settings_set_haptic(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);
|
||||||
@@ -97,6 +154,38 @@ void camera_suite_scene_settings_on_enter(void* context) {
|
|||||||
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, orientation_text[value_index]);
|
variable_item_set_current_value_text(item, orientation_text[value_index]);
|
||||||
|
|
||||||
|
// Camera Dither Type
|
||||||
|
item = variable_item_list_add(
|
||||||
|
app->variable_item_list,
|
||||||
|
"Dithering Type:",
|
||||||
|
3,
|
||||||
|
camera_suite_scene_settings_set_camera_dither,
|
||||||
|
app);
|
||||||
|
value_index = value_index_uint32(app->dither, dither_value, 3);
|
||||||
|
variable_item_set_current_value_index(item, value_index);
|
||||||
|
variable_item_set_current_value_text(item, dither_text[value_index]);
|
||||||
|
|
||||||
|
// Flash ON/OFF
|
||||||
|
item = variable_item_list_add(
|
||||||
|
app->variable_item_list, "Flash:", 2, camera_suite_scene_settings_set_flash, app);
|
||||||
|
value_index = value_index_uint32(app->flash, flash_value, 2);
|
||||||
|
variable_item_set_current_value_index(item, value_index);
|
||||||
|
variable_item_set_current_value_text(item, flash_text[value_index]);
|
||||||
|
|
||||||
|
// @todo - Save picture to ESP32-CAM sd-card instead of Flipper Zero
|
||||||
|
// sd-card. This hides the setting for it, for now.
|
||||||
|
// Save JPEG to ESP32-CAM sd-card instead of Flipper Zero sd-card ON/OFF
|
||||||
|
// item = variable_item_list_add(
|
||||||
|
// app->variable_item_list,
|
||||||
|
// "Save JPEG to ext sdcard:",
|
||||||
|
// 2,
|
||||||
|
// camera_suite_scene_settings_set_jpeg,
|
||||||
|
// app);
|
||||||
|
// value_index = value_index_uint32(app->jpeg, jpeg_value, 2);
|
||||||
|
// variable_item_set_current_value_index(item, value_index);
|
||||||
|
// variable_item_set_current_value_text(item, jpeg_text[value_index]);
|
||||||
|
UNUSED(camera_suite_scene_settings_set_jpeg);
|
||||||
|
|
||||||
// Haptic FX ON/OFF
|
// Haptic FX ON/OFF
|
||||||
item = variable_item_list_add(
|
item = variable_item_list_add(
|
||||||
app->variable_item_list, "Haptic FX:", 2, camera_suite_scene_settings_set_haptic, app);
|
app->variable_item_list, "Haptic FX:", 2, camera_suite_scene_settings_set_haptic, app);
|
||||||
|
|||||||
@@ -8,48 +8,39 @@
|
|||||||
#include "../helpers/camera_suite_speaker.h"
|
#include "../helpers/camera_suite_speaker.h"
|
||||||
#include "../helpers/camera_suite_led.h"
|
#include "../helpers/camera_suite_led.h"
|
||||||
|
|
||||||
static CameraSuiteViewCamera* current_instance = NULL;
|
|
||||||
|
|
||||||
struct CameraSuiteViewCamera {
|
|
||||||
CameraSuiteViewCameraCallback callback;
|
|
||||||
FuriStreamBuffer* rx_stream;
|
|
||||||
FuriThread* worker_thread;
|
|
||||||
View* view;
|
|
||||||
void* context;
|
|
||||||
};
|
|
||||||
|
|
||||||
void camera_suite_view_camera_set_callback(
|
|
||||||
CameraSuiteViewCamera* instance,
|
|
||||||
CameraSuiteViewCameraCallback callback,
|
|
||||||
void* context) {
|
|
||||||
furi_assert(instance);
|
|
||||||
furi_assert(callback);
|
|
||||||
instance->callback = callback;
|
|
||||||
instance->context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to draw pixels on the canvas based on camera orientation
|
|
||||||
static void draw_pixel_by_orientation(Canvas* canvas, uint8_t x, uint8_t y, uint8_t orientation) {
|
static void draw_pixel_by_orientation(Canvas* canvas, uint8_t x, uint8_t y, uint8_t orientation) {
|
||||||
|
furi_assert(canvas);
|
||||||
|
furi_assert(x);
|
||||||
|
furi_assert(y);
|
||||||
|
furi_assert(orientation);
|
||||||
|
|
||||||
switch(orientation) {
|
switch(orientation) {
|
||||||
case 0: // Camera rotated 0 degrees (right side up, default)
|
default:
|
||||||
|
case 0: { // Camera rotated 0 degrees (right side up, default)
|
||||||
canvas_draw_dot(canvas, x, y);
|
canvas_draw_dot(canvas, x, y);
|
||||||
break;
|
break;
|
||||||
case 1: // Camera rotated 90 degrees
|
}
|
||||||
|
case 1: { // Camera rotated 90 degrees
|
||||||
|
|
||||||
canvas_draw_dot(canvas, y, FRAME_WIDTH - 1 - x);
|
canvas_draw_dot(canvas, y, FRAME_WIDTH - 1 - x);
|
||||||
break;
|
break;
|
||||||
case 2: // Camera rotated 180 degrees (upside down)
|
}
|
||||||
|
case 2: { // Camera rotated 180 degrees (upside down)
|
||||||
canvas_draw_dot(canvas, FRAME_WIDTH - 1 - x, FRAME_HEIGHT - 1 - y);
|
canvas_draw_dot(canvas, FRAME_WIDTH - 1 - x, FRAME_HEIGHT - 1 - y);
|
||||||
break;
|
break;
|
||||||
case 3: // Camera rotated 270 degrees
|
}
|
||||||
|
case 3: { // Camera rotated 270 degrees
|
||||||
canvas_draw_dot(canvas, FRAME_HEIGHT - 1 - y, x);
|
canvas_draw_dot(canvas, FRAME_HEIGHT - 1 - y, x);
|
||||||
break;
|
break;
|
||||||
default:
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void camera_suite_view_camera_draw(Canvas* canvas, void* _model) {
|
static void camera_suite_view_camera_draw(Canvas* canvas, void* model) {
|
||||||
UartDumpModel* model = _model;
|
furi_assert(canvas);
|
||||||
|
furi_assert(model);
|
||||||
|
|
||||||
|
UartDumpModel* uartDumpModel = model;
|
||||||
|
|
||||||
// Clear the screen.
|
// Clear the screen.
|
||||||
canvas_set_color(canvas, ColorBlack);
|
canvas_set_color(canvas, ColorBlack);
|
||||||
@@ -57,21 +48,19 @@ static void camera_suite_view_camera_draw(Canvas* canvas, void* _model) {
|
|||||||
// Draw the frame.
|
// Draw the frame.
|
||||||
canvas_draw_frame(canvas, 0, 0, FRAME_WIDTH, FRAME_HEIGHT);
|
canvas_draw_frame(canvas, 0, 0, FRAME_WIDTH, FRAME_HEIGHT);
|
||||||
|
|
||||||
CameraSuite* app = current_instance->context;
|
|
||||||
|
|
||||||
for(size_t p = 0; p < FRAME_BUFFER_LENGTH; ++p) {
|
for(size_t p = 0; p < FRAME_BUFFER_LENGTH; ++p) {
|
||||||
uint8_t x = p % ROW_BUFFER_LENGTH; // 0 .. 15
|
uint8_t x = p % ROW_BUFFER_LENGTH; // 0 .. 15
|
||||||
uint8_t y = p / ROW_BUFFER_LENGTH; // 0 .. 63
|
uint8_t y = p / ROW_BUFFER_LENGTH; // 0 .. 63
|
||||||
|
|
||||||
for(uint8_t i = 0; i < 8; ++i) {
|
for(uint8_t i = 0; i < 8; ++i) {
|
||||||
if((model->pixels[p] & (1 << (7 - i))) != 0) {
|
if((uartDumpModel->pixels[p] & (1 << (7 - i))) != 0) {
|
||||||
draw_pixel_by_orientation(canvas, (x * 8) + i, y, app->orientation);
|
draw_pixel_by_orientation(canvas, (x * 8) + i, y, uartDumpModel->orientation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw the guide if the camera is not initialized.
|
// Draw the guide if the camera is not initialized.
|
||||||
if(!model->initialized) {
|
if(!uartDumpModel->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");
|
||||||
@@ -82,15 +71,106 @@ static void camera_suite_view_camera_draw(Canvas* canvas, void* _model) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void camera_suite_view_camera_model_init(UartDumpModel* const model) {
|
static void save_image(void* model) {
|
||||||
|
furi_assert(model);
|
||||||
|
|
||||||
|
UartDumpModel* uartDumpModel = model;
|
||||||
|
|
||||||
|
// This pointer is used to access the storage.
|
||||||
|
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||||
|
|
||||||
|
// This pointer is used to access the filesystem.
|
||||||
|
File* file = storage_file_alloc(storage);
|
||||||
|
|
||||||
|
// Store path in local variable.
|
||||||
|
const char* folderName = EXT_PATH("DCIM");
|
||||||
|
|
||||||
|
// Create the folder name for the image file if it does not exist.
|
||||||
|
if(storage_common_stat(storage, folderName, NULL) == FSE_NOT_EXIST) {
|
||||||
|
storage_simply_mkdir(storage, folderName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This pointer is used to access the file name.
|
||||||
|
FuriString* file_name = furi_string_alloc();
|
||||||
|
|
||||||
|
// Get the current date and time.
|
||||||
|
FuriHalRtcDateTime datetime = {0};
|
||||||
|
furi_hal_rtc_get_datetime(&datetime);
|
||||||
|
|
||||||
|
// Create the file name.
|
||||||
|
furi_string_printf(
|
||||||
|
file_name,
|
||||||
|
EXT_PATH("DCIM/%.4d%.2d%.2d-%.2d%.2d%.2d.bmp"),
|
||||||
|
datetime.year,
|
||||||
|
datetime.month,
|
||||||
|
datetime.day,
|
||||||
|
datetime.hour,
|
||||||
|
datetime.minute,
|
||||||
|
datetime.second);
|
||||||
|
|
||||||
|
// Open the file for writing. If the file does not exist (it shouldn't),
|
||||||
|
// create it.
|
||||||
|
bool result =
|
||||||
|
storage_file_open(file, furi_string_get_cstr(file_name), FSAM_WRITE, FSOM_OPEN_ALWAYS);
|
||||||
|
|
||||||
|
// Free the file name after use.
|
||||||
|
furi_string_free(file_name);
|
||||||
|
|
||||||
|
if(!uartDumpModel->inverted) {
|
||||||
|
for(size_t i = 0; i < FRAME_BUFFER_LENGTH; ++i) {
|
||||||
|
uartDumpModel->pixels[i] = ~uartDumpModel->pixels[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the file was opened successfully, write the bitmap header and the
|
||||||
|
// image data.
|
||||||
|
if(result) {
|
||||||
|
// Write BMP Header
|
||||||
|
storage_file_write(file, bitmap_header, BITMAP_HEADER_LENGTH);
|
||||||
|
|
||||||
|
// @todo - Add a function for saving the image directly from the
|
||||||
|
// ESP32-CAM to the Flipper Zero SD card.
|
||||||
|
|
||||||
|
// Write locally to the Flipper Zero SD card in the DCIM folder.
|
||||||
|
int8_t row_buffer[ROW_BUFFER_LENGTH];
|
||||||
|
|
||||||
|
// @todo - Save image based on orientation.
|
||||||
|
for(size_t i = 64; i > 0; --i) {
|
||||||
|
for(size_t j = 0; j < ROW_BUFFER_LENGTH; ++j) {
|
||||||
|
row_buffer[j] = uartDumpModel->pixels[((i - 1) * ROW_BUFFER_LENGTH) + j];
|
||||||
|
}
|
||||||
|
storage_file_write(file, row_buffer, ROW_BUFFER_LENGTH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the file.
|
||||||
|
storage_file_close(file);
|
||||||
|
|
||||||
|
// Free up memory.
|
||||||
|
storage_file_free(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
camera_suite_view_camera_model_init(UartDumpModel* const model, CameraSuite* instance_context) {
|
||||||
|
furi_assert(model);
|
||||||
|
furi_assert(instance_context);
|
||||||
|
|
||||||
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) {
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
|
furi_assert(event);
|
||||||
|
|
||||||
CameraSuiteViewCamera* instance = context;
|
CameraSuiteViewCamera* instance = context;
|
||||||
|
|
||||||
if(event->type == InputTypeRelease) {
|
if(event->type == InputTypeRelease) {
|
||||||
switch(event->key) {
|
switch(event->key) {
|
||||||
default: // Stop all sounds, reset the LED.
|
default: // Stop all sounds, reset the LED.
|
||||||
@@ -106,13 +186,18 @@ static bool camera_suite_view_camera_input(InputEvent* event, void* context) {
|
|||||||
true);
|
true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Send `data` to the ESP32-CAM
|
|
||||||
} else if(event->type == InputTypePress) {
|
} else if(event->type == InputTypePress) {
|
||||||
uint8_t data[1];
|
uint8_t data[1] = {'X'};
|
||||||
switch(event->key) {
|
switch(event->key) {
|
||||||
case InputKeyBack:
|
// Camera: Stop stream.
|
||||||
// Stop the camera stream.
|
case InputKeyBack: {
|
||||||
data[0] = 's';
|
// 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.
|
// Go back to the main menu.
|
||||||
with_view_model(
|
with_view_model(
|
||||||
instance->view,
|
instance->view,
|
||||||
@@ -123,9 +208,9 @@ static bool camera_suite_view_camera_input(InputEvent* event, void* context) {
|
|||||||
},
|
},
|
||||||
true);
|
true);
|
||||||
break;
|
break;
|
||||||
case InputKeyLeft:
|
}
|
||||||
// Camera: Invert.
|
// Camera: Toggle invert on the ESP32-CAM.
|
||||||
data[0] = '<';
|
case InputKeyLeft: {
|
||||||
with_view_model(
|
with_view_model(
|
||||||
instance->view,
|
instance->view,
|
||||||
UartDumpModel * model,
|
UartDumpModel * model,
|
||||||
@@ -134,12 +219,20 @@ static bool camera_suite_view_camera_input(InputEvent* event, void* context) {
|
|||||||
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;
|
||||||
|
} else {
|
||||||
|
data[0] = 'I';
|
||||||
|
model->inverted = true;
|
||||||
|
}
|
||||||
instance->callback(CameraSuiteCustomEventSceneCameraLeft, instance->context);
|
instance->callback(CameraSuiteCustomEventSceneCameraLeft, instance->context);
|
||||||
},
|
},
|
||||||
true);
|
true);
|
||||||
break;
|
break;
|
||||||
case InputKeyRight:
|
}
|
||||||
// Camera: Enable/disable dithering.
|
// Camera: Enable/disable dithering.
|
||||||
|
case InputKeyRight: {
|
||||||
data[0] = '>';
|
data[0] = '>';
|
||||||
with_view_model(
|
with_view_model(
|
||||||
instance->view,
|
instance->view,
|
||||||
@@ -153,8 +246,9 @@ static bool camera_suite_view_camera_input(InputEvent* event, void* context) {
|
|||||||
},
|
},
|
||||||
true);
|
true);
|
||||||
break;
|
break;
|
||||||
case InputKeyUp:
|
}
|
||||||
// Camera: Increase contrast.
|
// Camera: Increase contrast.
|
||||||
|
case InputKeyUp: {
|
||||||
data[0] = 'C';
|
data[0] = 'C';
|
||||||
with_view_model(
|
with_view_model(
|
||||||
instance->view,
|
instance->view,
|
||||||
@@ -168,8 +262,9 @@ static bool camera_suite_view_camera_input(InputEvent* event, void* context) {
|
|||||||
},
|
},
|
||||||
true);
|
true);
|
||||||
break;
|
break;
|
||||||
case InputKeyDown:
|
}
|
||||||
// Camera: Reduce contrast.
|
// Camera: Reduce contrast.
|
||||||
|
case InputKeyDown: {
|
||||||
data[0] = 'c';
|
data[0] = 'c';
|
||||||
with_view_model(
|
with_view_model(
|
||||||
instance->view,
|
instance->view,
|
||||||
@@ -183,58 +278,113 @@ static bool camera_suite_view_camera_input(InputEvent* event, void* context) {
|
|||||||
},
|
},
|
||||||
true);
|
true);
|
||||||
break;
|
break;
|
||||||
case InputKeyOk:
|
}
|
||||||
// Switch dithering types.
|
// Camera: Take picture.
|
||||||
data[0] = 'D';
|
case InputKeyOk: {
|
||||||
with_view_model(
|
with_view_model(
|
||||||
instance->view,
|
instance->view,
|
||||||
UartDumpModel * model,
|
UartDumpModel * model,
|
||||||
{
|
{
|
||||||
UNUSED(model);
|
camera_suite_play_long_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);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Take a picture.
|
||||||
|
save_image(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: {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Send `data` to the ESP32-CAM
|
}
|
||||||
furi_hal_uart_tx(UART_CH, data, 1);
|
|
||||||
|
if(data[0] != 'X') {
|
||||||
|
// Send `data` to the ESP32-CAM.
|
||||||
|
furi_hal_uart_tx(UART_CH, data, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void camera_suite_view_camera_exit(void* context) {
|
static void camera_suite_view_camera_exit(void* context) {
|
||||||
furi_assert(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);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void camera_suite_view_camera_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);
|
furi_assert(context);
|
||||||
|
|
||||||
// Cast `context` to `CameraSuiteViewCamera*` and store it in `instance`.
|
// Get the camera suite instance context.
|
||||||
CameraSuiteViewCamera* instance = (CameraSuiteViewCamera*)context;
|
CameraSuiteViewCamera* instance = (CameraSuiteViewCamera*)context;
|
||||||
|
|
||||||
// Assign the current instance to the global variable
|
// Get the camera suite instance context.
|
||||||
current_instance = instance;
|
CameraSuite* instance_context = instance->context;
|
||||||
|
|
||||||
uint8_t data[1];
|
// Start camera stream.
|
||||||
data[0] = 'S'; // Uppercase `S` to start the camera
|
uint8_t start_camera = 'S';
|
||||||
// Send `data` to the ESP32-CAM
|
furi_hal_uart_tx(UART_CH, &start_camera, 1);
|
||||||
furi_hal_uart_tx(UART_CH, data, 1);
|
furi_delay_ms(75);
|
||||||
|
|
||||||
|
// Get/set dither type.
|
||||||
|
uint8_t dither_type = instance_context->dither;
|
||||||
|
furi_hal_uart_tx(UART_CH, &dither_type, 1);
|
||||||
|
furi_delay_ms(75);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
uint8_t flash_state = instance_context->flash ? 'F' : 'f';
|
||||||
|
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);
|
||||||
|
|
||||||
with_view_model(
|
with_view_model(
|
||||||
instance->view,
|
instance->view,
|
||||||
UartDumpModel * model,
|
UartDumpModel * model,
|
||||||
{ camera_suite_view_camera_model_init(model); },
|
{ camera_suite_view_camera_model_init(model, instance_context); },
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void camera_on_irq_cb(UartIrqEvent uartIrqEvent, uint8_t data, void* context) {
|
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(uartIrqEvent);
|
||||||
|
furi_assert(data);
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
|
|
||||||
// Cast `context` to `CameraSuiteViewCamera*` and store it in `instance`.
|
// Cast `context` to `CameraSuiteViewCamera*` and store it in `instance`.
|
||||||
@@ -248,47 +398,57 @@ static void camera_on_irq_cb(UartIrqEvent uartIrqEvent, uint8_t data, void* cont
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void process_ringbuffer(UartDumpModel* model, uint8_t byte) {
|
static void process_ringbuffer(UartDumpModel* model, uint8_t const byte) {
|
||||||
// First char has to be 'Y' in the buffer.
|
furi_assert(model);
|
||||||
if(model->ringbuffer_index == 0 && byte != 'Y') {
|
furi_assert(byte);
|
||||||
|
|
||||||
|
// The first HEADER_LENGTH bytes are reserved for header information.
|
||||||
|
if(model->ringbuffer_index < HEADER_LENGTH) {
|
||||||
|
// Validate the start of row characters 'Y' and ':'.
|
||||||
|
if(model->ringbuffer_index == 0 && byte != 'Y') {
|
||||||
|
// Incorrect start of frame; reset.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(model->ringbuffer_index == 1 && byte != ':') {
|
||||||
|
// Incorrect start of frame; reset.
|
||||||
|
model->ringbuffer_index = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(model->ringbuffer_index == 2) {
|
||||||
|
// Assign the third byte as the row identifier.
|
||||||
|
model->row_identifier = byte;
|
||||||
|
}
|
||||||
|
model->ringbuffer_index++; // Increment index for the next byte.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Second char has to be ':' in the buffer or reset.
|
// Store pixel value directly after the header.
|
||||||
if(model->ringbuffer_index == 1 && byte != ':') {
|
model->row_ringbuffer[model->ringbuffer_index - HEADER_LENGTH] = byte;
|
||||||
model->ringbuffer_index = 0;
|
model->ringbuffer_index++; // Increment index for the next byte.
|
||||||
process_ringbuffer(model, byte);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assign current byte to the ringbuffer.
|
// Check whether the ring buffer is filled.
|
||||||
model->row_ringbuffer[model->ringbuffer_index] = byte;
|
if(model->ringbuffer_index >= RING_BUFFER_LENGTH) {
|
||||||
// Increment the ringbuffer index.
|
model->ringbuffer_index = 0; // Reset the ring buffer index.
|
||||||
++model->ringbuffer_index;
|
model->initialized = true; // Set the connection as successfully established.
|
||||||
|
|
||||||
// Let's wait 'till the buffer fills.
|
// Compute the starting index for the row in the pixel buffer.
|
||||||
if(model->ringbuffer_index < RING_BUFFER_LENGTH) {
|
size_t row_start_index = model->row_identifier * ROW_BUFFER_LENGTH;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Flush the ringbuffer to the framebuffer.
|
// Ensure the row start index is within the valid range.
|
||||||
model->ringbuffer_index = 0; // Reset the ringbuffer
|
if(row_start_index > LAST_ROW_INDEX) {
|
||||||
model->initialized = true; // Established the connection successfully.
|
row_start_index = 0; // Reset to a safe value in case of an overflow.
|
||||||
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
|
// Flush the contents of the ring buffer to the pixel buffer.
|
||||||
row_start_index = 0;
|
for(size_t i = 0; i < ROW_BUFFER_LENGTH; ++i) {
|
||||||
}
|
model->pixels[row_start_index + i] = model->row_ringbuffer[i];
|
||||||
|
}
|
||||||
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) {
|
static int32_t camera_worker(void* context) {
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
|
|
||||||
CameraSuiteViewCamera* instance = context;
|
CameraSuiteViewCamera* instance = context;
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
@@ -328,36 +488,49 @@ static int32_t camera_worker(void* context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CameraSuiteViewCamera* camera_suite_view_camera_alloc() {
|
CameraSuiteViewCamera* camera_suite_view_camera_alloc() {
|
||||||
|
// Allocate memory for the instance
|
||||||
CameraSuiteViewCamera* instance = malloc(sizeof(CameraSuiteViewCamera));
|
CameraSuiteViewCamera* instance = malloc(sizeof(CameraSuiteViewCamera));
|
||||||
|
|
||||||
|
// Allocate the view object
|
||||||
instance->view = view_alloc();
|
instance->view = view_alloc();
|
||||||
|
|
||||||
|
// Allocate a stream buffer
|
||||||
instance->rx_stream = furi_stream_buffer_alloc(2048, 1);
|
instance->rx_stream = furi_stream_buffer_alloc(2048, 1);
|
||||||
|
|
||||||
// Set up views
|
// Allocate model
|
||||||
view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(UartDumpModel));
|
view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(UartDumpModel));
|
||||||
view_set_context(instance->view, instance); // furi_assert crashes in events without this
|
|
||||||
|
// Set context for the view
|
||||||
|
view_set_context(instance->view, instance);
|
||||||
|
|
||||||
|
// Set draw callback
|
||||||
view_set_draw_callback(instance->view, (ViewDrawCallback)camera_suite_view_camera_draw);
|
view_set_draw_callback(instance->view, (ViewDrawCallback)camera_suite_view_camera_draw);
|
||||||
|
|
||||||
|
// Set input callback
|
||||||
view_set_input_callback(instance->view, camera_suite_view_camera_input);
|
view_set_input_callback(instance->view, camera_suite_view_camera_input);
|
||||||
|
|
||||||
|
// Set enter callback
|
||||||
view_set_enter_callback(instance->view, camera_suite_view_camera_enter);
|
view_set_enter_callback(instance->view, camera_suite_view_camera_enter);
|
||||||
|
|
||||||
|
// Set exit callback
|
||||||
view_set_exit_callback(instance->view, camera_suite_view_camera_exit);
|
view_set_exit_callback(instance->view, camera_suite_view_camera_exit);
|
||||||
|
|
||||||
with_view_model(
|
// Allocate a thread for this camera to run on.
|
||||||
instance->view,
|
FuriThread* thread = furi_thread_alloc_ex("UsbUartWorker", 2048, camera_worker, instance);
|
||||||
UartDumpModel * model,
|
instance->worker_thread = thread;
|
||||||
{ camera_suite_view_camera_model_init(model); },
|
|
||||||
true);
|
|
||||||
|
|
||||||
instance->worker_thread = furi_thread_alloc_ex("UsbUartWorker", 2048, camera_worker, instance);
|
|
||||||
furi_thread_start(instance->worker_thread);
|
furi_thread_start(instance->worker_thread);
|
||||||
|
|
||||||
// Enable uart listener
|
// Enable uart listener
|
||||||
if(UART_CH == FuriHalUartIdUSART1) {
|
if(UART_CH == UART_CH) {
|
||||||
furi_hal_console_disable();
|
furi_hal_console_disable();
|
||||||
} else if(UART_CH == FuriHalUartIdLPUART1) {
|
} else if(UART_CH == FuriHalUartIdLPUART1) {
|
||||||
furi_hal_uart_init(UART_CH, 230400);
|
furi_hal_uart_init(UART_CH, 230400);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 115200 is the default baud rate for the ESP32-CAM.
|
||||||
furi_hal_uart_set_br(UART_CH, 230400);
|
furi_hal_uart_set_br(UART_CH, 230400);
|
||||||
|
|
||||||
|
// Enable UART1 and set the IRQ callback.
|
||||||
furi_hal_uart_set_irq_cb(UART_CH, camera_on_irq_cb, instance);
|
furi_hal_uart_set_irq_cb(UART_CH, camera_on_irq_cb, instance);
|
||||||
|
|
||||||
return instance;
|
return instance;
|
||||||
@@ -366,21 +539,39 @@ CameraSuiteViewCamera* camera_suite_view_camera_alloc() {
|
|||||||
void camera_suite_view_camera_free(CameraSuiteViewCamera* instance) {
|
void camera_suite_view_camera_free(CameraSuiteViewCamera* instance) {
|
||||||
furi_assert(instance);
|
furi_assert(instance);
|
||||||
|
|
||||||
with_view_model(
|
// Remove the IRQ callback.
|
||||||
instance->view, UartDumpModel * model, { UNUSED(model); }, true);
|
|
||||||
view_free(instance->view);
|
|
||||||
free(instance);
|
|
||||||
|
|
||||||
furi_hal_uart_set_irq_cb(UART_CH, NULL, NULL);
|
furi_hal_uart_set_irq_cb(UART_CH, NULL, NULL);
|
||||||
|
|
||||||
|
// Free the worker thread.
|
||||||
|
furi_thread_free(instance->worker_thread);
|
||||||
|
|
||||||
|
// Free the allocated stream buffer.
|
||||||
|
furi_stream_buffer_free(instance->rx_stream);
|
||||||
|
|
||||||
|
// Re-enable the console.
|
||||||
if(UART_CH == FuriHalUartIdLPUART1) {
|
if(UART_CH == FuriHalUartIdLPUART1) {
|
||||||
furi_hal_uart_deinit(UART_CH);
|
furi_hal_uart_deinit(UART_CH);
|
||||||
} else {
|
} else {
|
||||||
furi_hal_console_enable();
|
furi_hal_console_enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
with_view_model(
|
||||||
|
instance->view, UartDumpModel * model, { UNUSED(model); }, true);
|
||||||
|
view_free(instance->view);
|
||||||
|
free(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
View* camera_suite_view_camera_get_view(CameraSuiteViewCamera* instance) {
|
View* camera_suite_view_camera_get_view(CameraSuiteViewCamera* instance) {
|
||||||
furi_assert(instance);
|
furi_assert(instance);
|
||||||
return instance->view;
|
return instance->view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void camera_suite_view_camera_set_callback(
|
||||||
|
CameraSuiteViewCamera* instance,
|
||||||
|
CameraSuiteViewCameraCallback callback,
|
||||||
|
void* context) {
|
||||||
|
furi_assert(instance);
|
||||||
|
furi_assert(callback);
|
||||||
|
instance->callback = callback;
|
||||||
|
instance->context = context;
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
#include "../helpers/camera_suite_custom_event.h"
|
#include "../helpers/camera_suite_custom_event.h"
|
||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include <furi_hal.h>
|
#include <furi_hal.h>
|
||||||
@@ -19,48 +21,60 @@
|
|||||||
#define UART_CH \
|
#define UART_CH \
|
||||||
(xtreme_settings.uart_esp_channel == UARTDefault ? FuriHalUartIdUSART1 : FuriHalUartIdLPUART1)
|
(xtreme_settings.uart_esp_channel == UARTDefault ? FuriHalUartIdUSART1 : FuriHalUartIdLPUART1)
|
||||||
|
|
||||||
#pragma once
|
#define BITMAP_HEADER_LENGTH 62
|
||||||
|
|
||||||
#define FRAME_WIDTH 128
|
|
||||||
#define FRAME_HEIGHT 64
|
|
||||||
#define FRAME_BIT_DEPTH 1
|
#define FRAME_BIT_DEPTH 1
|
||||||
#define FRAME_BUFFER_LENGTH 1024
|
#define FRAME_BUFFER_LENGTH 1024
|
||||||
#define ROW_BUFFER_LENGTH 16
|
#define FRAME_HEIGHT 64
|
||||||
#define RING_BUFFER_LENGTH 19
|
#define FRAME_WIDTH 128
|
||||||
|
#define HEADER_LENGTH 3 // 'Y', ':', and row identifier
|
||||||
#define LAST_ROW_INDEX 1008
|
#define LAST_ROW_INDEX 1008
|
||||||
|
#define RING_BUFFER_LENGTH 19
|
||||||
|
#define ROW_BUFFER_LENGTH 16
|
||||||
|
|
||||||
|
static const unsigned char bitmap_header[BITMAP_HEADER_LENGTH] = {
|
||||||
|
0x42, 0x4D, 0x3E, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x28, 0x00,
|
||||||
|
0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00};
|
||||||
|
|
||||||
extern const Icon I_DolphinCommon_56x48;
|
extern const Icon I_DolphinCommon_56x48;
|
||||||
|
|
||||||
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 CameraSuiteViewCamera CameraSuiteViewCamera;
|
|
||||||
|
|
||||||
typedef void (*CameraSuiteViewCameraCallback)(CameraSuiteCustomEvent event, void* context);
|
|
||||||
|
|
||||||
void camera_suite_view_camera_set_callback(
|
|
||||||
CameraSuiteViewCamera* camera_suite_view_camera,
|
|
||||||
CameraSuiteViewCameraCallback callback,
|
|
||||||
void* context);
|
|
||||||
|
|
||||||
CameraSuiteViewCamera* camera_suite_view_camera_alloc();
|
|
||||||
|
|
||||||
void camera_suite_view_camera_free(CameraSuiteViewCamera* camera_suite_static);
|
|
||||||
|
|
||||||
View* camera_suite_view_camera_get_view(CameraSuiteViewCamera* camera_suite_static);
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
// Reserved for StreamBuffer internal event
|
WorkerEventReserved = (1 << 0), // Reserved for StreamBuffer internal event
|
||||||
WorkerEventReserved = (1 << 0),
|
|
||||||
WorkerEventStop = (1 << 1),
|
WorkerEventStop = (1 << 1),
|
||||||
WorkerEventRx = (1 << 2),
|
WorkerEventRx = (1 << 2),
|
||||||
} WorkerEventFlags;
|
} WorkerEventFlags;
|
||||||
|
|
||||||
#define WORKER_EVENTS_MASK (WorkerEventStop | WorkerEventRx)
|
#define WORKER_EVENTS_MASK (WorkerEventStop | WorkerEventRx)
|
||||||
|
|
||||||
|
// Forward declaration
|
||||||
|
typedef void (*CameraSuiteViewCameraCallback)(CameraSuiteCustomEvent event, void* context);
|
||||||
|
|
||||||
|
typedef struct CameraSuiteViewCamera {
|
||||||
|
CameraSuiteViewCameraCallback callback;
|
||||||
|
FuriStreamBuffer* rx_stream;
|
||||||
|
FuriThread* worker_thread;
|
||||||
|
NotificationApp* notification;
|
||||||
|
View* view;
|
||||||
|
void* context;
|
||||||
|
} CameraSuiteViewCamera;
|
||||||
|
|
||||||
|
typedef struct UartDumpModel {
|
||||||
|
bool flash;
|
||||||
|
bool initialized;
|
||||||
|
bool inverted;
|
||||||
|
int rotation_angle;
|
||||||
|
uint32_t orientation;
|
||||||
|
uint8_t pixels[FRAME_BUFFER_LENGTH];
|
||||||
|
uint8_t ringbuffer_index;
|
||||||
|
uint8_t row_identifier;
|
||||||
|
uint8_t row_ringbuffer[RING_BUFFER_LENGTH];
|
||||||
|
} UartDumpModel;
|
||||||
|
|
||||||
|
// Function Prototypes
|
||||||
|
CameraSuiteViewCamera* camera_suite_view_camera_alloc();
|
||||||
|
View* camera_suite_view_camera_get_view(CameraSuiteViewCamera* camera_suite_static);
|
||||||
|
void camera_suite_view_camera_free(CameraSuiteViewCamera* camera_suite_static);
|
||||||
|
void camera_suite_view_camera_set_callback(
|
||||||
|
CameraSuiteViewCamera* camera_suite_view_camera,
|
||||||
|
CameraSuiteViewCameraCallback callback,
|
||||||
|
void* context);
|
||||||
|
|||||||
@@ -32,12 +32,11 @@ void camera_suite_view_guide_draw(Canvas* canvas, CameraSuiteViewGuideModel* mod
|
|||||||
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, "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");
|
||||||
canvas_draw_str_aligned(canvas, 0, 32, AlignLeft, AlignTop, "Up = Contrast Up");
|
canvas_draw_str_aligned(canvas, 0, 32, AlignLeft, AlignTop, "Up = Contrast up");
|
||||||
canvas_draw_str_aligned(canvas, 0, 42, AlignLeft, AlignTop, "Down = Contrast Down");
|
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 = Take picture");
|
||||||
canvas_draw_str_aligned(canvas, 0, 52, AlignLeft, AlignTop, "Center = Toggle Dither Type");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void camera_suite_view_guide_model_init(CameraSuiteViewGuideModel* const model) {
|
static void camera_suite_view_guide_model_init(CameraSuiteViewGuideModel* const model) {
|
||||||
|
|||||||
1
applications/external/chess/application.fam
vendored
@@ -7,6 +7,7 @@ App(
|
|||||||
"gui",
|
"gui",
|
||||||
],
|
],
|
||||||
stack_size=4 * 1024,
|
stack_size=4 * 1024,
|
||||||
|
order=10,
|
||||||
fap_icon="flipchess_10px.png",
|
fap_icon="flipchess_10px.png",
|
||||||
fap_icon_assets="icons",
|
fap_icon_assets="icons",
|
||||||
fap_icon_assets_symbol="flipchess",
|
fap_icon_assets_symbol="flipchess",
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <input/input.h>
|
#include <input/input.h>
|
||||||
#include <gui/elements.h>
|
#include <gui/elements.h>
|
||||||
#include "flipchess_icons.h"
|
#include "flipchess_icons.h"
|
||||||
|
|
||||||
#include <assets_icons.h>
|
#include <assets_icons.h>
|
||||||
|
|
||||||
struct FlipChessStartscreen {
|
struct FlipChessStartscreen {
|
||||||
|
|||||||