diff --git a/applications/applications.mk b/applications/applications.mk index 9991b367..188a2abe 100644 --- a/applications/applications.mk +++ b/applications/applications.mk @@ -5,7 +5,7 @@ CFLAGS += -I$(APP_DIR) APP_RELEASE ?= 0 ifeq ($(APP_RELEASE), 1) -APP_DISPLAY = 1 +APP_GUI = 1 APP_INPUT = 1 APP_MENU = 1 endif @@ -81,9 +81,9 @@ endif # device drivers APP_GUI ?= 0 ifeq ($(APP_GUI), 1) -APP_DISPLAY = 1 CFLAGS += -DAPP_GUI C_SOURCES += $(wildcard $(APP_DIR)/gui/*.c) +C_SOURCES += $(wildcard $(APP_DIR)/backlight-control/*.c) endif ifeq ($(APP_DISPLAY), 1) diff --git a/applications/backlight-control/backlight-control.c b/applications/backlight-control/backlight-control.c new file mode 100644 index 00000000..ef22f3df --- /dev/null +++ b/applications/backlight-control/backlight-control.c @@ -0,0 +1,30 @@ +#include "flipper.h" + +static void event_cb(const void* value, size_t size, void* ctx) { + xSemaphoreGive((SemaphoreHandle_t*)ctx); +} + +const uint32_t BACKLIGHT_TIME = 10000; + +void backlight_control(void* p) { + // TODO use FURI + HAL_GPIO_WritePin(DISPLAY_BACKLIGHT_GPIO_Port, DISPLAY_BACKLIGHT_Pin, GPIO_PIN_SET); + + StaticSemaphore_t event_descriptor; + SemaphoreHandle_t update = xSemaphoreCreateCountingStatic(255, 0, &event_descriptor); + + // open record + furi_open_deprecated("input_events", false, false, event_cb, NULL, (void*)update); + + // we ready to work + furiac_ready(); + + while(1) { + // wait for event + if(xSemaphoreTake(update, BACKLIGHT_TIME) == pdTRUE) { + HAL_GPIO_WritePin(DISPLAY_BACKLIGHT_GPIO_Port, DISPLAY_BACKLIGHT_Pin, GPIO_PIN_SET); + } else { + HAL_GPIO_WritePin(DISPLAY_BACKLIGHT_GPIO_Port, DISPLAY_BACKLIGHT_Pin, GPIO_PIN_RESET); + } + } +} \ No newline at end of file diff --git a/applications/gui/canvas.c b/applications/gui/canvas.c index 6f137284..842397bd 100644 --- a/applications/gui/canvas.c +++ b/applications/gui/canvas.c @@ -3,77 +3,117 @@ #include #include -#include -struct Canvas { - FuriRecordSubscriber* fb_record; - u8g2_t* fb; +typedef struct { + CanvasApi api; + + u8g2_t fb; uint8_t offset_x; uint8_t offset_y; uint8_t width; uint8_t height; -}; +} Canvas; -Canvas* canvas_alloc() { +uint8_t canvas_width(CanvasApi* api); +uint8_t canvas_height(CanvasApi* api); +void canvas_clear(CanvasApi* api); +void canvas_color_set(CanvasApi* api, uint8_t color); +void canvas_font_set(CanvasApi* api, Font font); +void canvas_str_draw(CanvasApi* api, uint8_t x, uint8_t y, const char* str); + +uint8_t u8g2_gpio_and_delay_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr); +uint8_t u8x8_hw_spi_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr); + +CanvasApi* canvas_api_init() { Canvas* canvas = furi_alloc(sizeof(Canvas)); - canvas->fb_record = furi_open_deprecated("u8g2_fb", false, false, NULL, NULL, NULL); - assert(canvas->fb_record); - return canvas; + + u8g2_Setup_st7565_erc12864_alt_f( + &canvas->fb, U8G2_R0, u8x8_hw_spi_stm32, u8g2_gpio_and_delay_stm32); + + // send init sequence to the display, display is in sleep mode after this + u8g2_InitDisplay(&canvas->fb); + u8g2_SetContrast(&canvas->fb, 36); + + u8g2_SetPowerSave(&canvas->fb, 0); // wake up display + u8g2_SendBuffer(&canvas->fb); + + canvas->api.width = canvas_width; + canvas->api.height = canvas_height; + canvas->api.clear = canvas_clear; + canvas->api.set_color = canvas_color_set; + canvas->api.set_font = canvas_font_set; + canvas->api.draw_str = canvas_str_draw; + + return (CanvasApi*)canvas; } -void canvas_free(Canvas* canvas) { - assert(canvas); - free(canvas); +void canvas_api_free(CanvasApi* api) { + assert(api); + free(api); } -void canvas_commit(Canvas* canvas) { - assert(canvas); - if(canvas->fb) { - furi_commit(canvas->fb_record); - canvas->fb = NULL; - } +void canvas_commit(CanvasApi* api) { + assert(api); + Canvas* canvas = (Canvas*)api; + u8g2_SetPowerSave(&canvas->fb, 0); // wake up display + u8g2_SendBuffer(&canvas->fb); } void canvas_frame_set( - Canvas* canvas, + CanvasApi* api, uint8_t offset_x, uint8_t offset_y, uint8_t width, uint8_t height) { - assert(canvas); + assert(api); + Canvas* canvas = (Canvas*)api; canvas->offset_x = offset_x; canvas->offset_y = offset_y; canvas->width = width; canvas->height = height; } -u8g2_t* canvas_fb(Canvas* canvas) { - if(!canvas->fb) { - canvas->fb = furi_take(canvas->fb_record); - assert(canvas->fb); +uint8_t canvas_width(CanvasApi* api) { + assert(api); + Canvas* canvas = (Canvas*)api; + return canvas->width; +} + +uint8_t canvas_height(CanvasApi* api) { + assert(api); + Canvas* canvas = (Canvas*)api; + return canvas->height; +} + +void canvas_clear(CanvasApi* api) { + assert(api); + Canvas* canvas = (Canvas*)api; + u8g2_ClearBuffer(&canvas->fb); +} + +void canvas_color_set(CanvasApi* api, Color color) { + assert(api); + Canvas* canvas = (Canvas*)api; + u8g2_SetDrawColor(&canvas->fb, color); +} + +void canvas_font_set(CanvasApi* api, Font font) { + assert(api); + Canvas* canvas = (Canvas*)api; + u8g2_SetFontMode(&canvas->fb, 1); + if(font == FontPrimary) { + u8g2_SetFont(&canvas->fb, u8g2_font_Born2bSportyV2_tr); + } else if(font == FontSecondary) { + u8g2_SetFont(&canvas->fb, u8g2_font_HelvetiPixel_tr); + } else { + assert(0); } - return canvas->fb; } -void canvas_clear(Canvas* canvas) { - u8g2_t* fb = canvas_fb(canvas); - u8g2_ClearBuffer(fb); -} - -void canvas_color_set(Canvas* canvas, uint8_t color) { - u8g2_t* fb = canvas_fb(canvas); - u8g2_SetDrawColor(fb, 1); -} - -void canvas_font_set(Canvas* canvas, font_t font) { - u8g2_t* fb = canvas_fb(canvas); - u8g2_SetFontMode(fb, 1); - u8g2_SetFont(fb, font); -} - -void canvas_str_draw(Canvas* canvas, uint8_t x, uint8_t y, const char* str) { +void canvas_str_draw(CanvasApi* api, uint8_t x, uint8_t y, const char* str) { + assert(api); + Canvas* canvas = (Canvas*)api; x += canvas->offset_x; y += canvas->offset_y; - u8g2_t* fb = canvas_fb(canvas); - u8g2_DrawStr(fb, x, y, str); + u8g2_DrawStr(&canvas->fb, x, y, str); } diff --git a/applications/gui/canvas.h b/applications/gui/canvas.h index 3b0f547e..237a75de 100644 --- a/applications/gui/canvas.h +++ b/applications/gui/canvas.h @@ -3,22 +3,25 @@ #include #include -#define COLOR_WHITE 0x00 -#define COLOR_BLACK 0x01 +typedef enum { + ColorWhite = 0x00, + ColorBlack = 0x01, +} Color; -#define CANVAS_FONT_PRIMARY u8g2_font_Born2bSportyV2_tr -#define CANVAS_FONT_SECONDARY u8g2_font_HelvetiPixel_tr +typedef enum { + FontPrimary = 0x00, + FontSecondary = 0x01, +} Font; -typedef struct Canvas Canvas; -typedef const uint8_t* font_t; +typedef struct CanvasApi CanvasApi; +struct CanvasApi { + uint8_t (*width)(CanvasApi* canvas); + uint8_t (*height)(CanvasApi* canvas); -uint8_t canvas_width(Canvas* canvas); -uint8_t canvas_height(Canvas* canvas); + void (*clear)(CanvasApi* canvas); -void canvas_clear(Canvas* canvas); + void (*set_color)(CanvasApi* canvas, Color color); + void (*set_font)(CanvasApi* canvas, Font font); -void canvas_color_set(Canvas* canvas, uint8_t color); - -void canvas_font_set(Canvas* canvas, font_t font); - -void canvas_str_draw(Canvas* canvas, uint8_t x, uint8_t y, const char* str); + void (*draw_str)(CanvasApi* canvas, uint8_t x, uint8_t y, const char* str); +}; diff --git a/applications/gui/canvas_i.h b/applications/gui/canvas_i.h index c24b2102..7337db00 100644 --- a/applications/gui/canvas_i.h +++ b/applications/gui/canvas_i.h @@ -1,13 +1,13 @@ #pragma once -Canvas* canvas_alloc(); +CanvasApi* canvas_api_init(); -void canvas_free(Canvas* canvas); +void canvas_api_free(CanvasApi* api); -void canvas_commit(Canvas* canvas); +void canvas_commit(CanvasApi* api); void canvas_frame_set( - Canvas* canvas, + CanvasApi* api, uint8_t offset_x, uint8_t offset_y, uint8_t width, diff --git a/applications/gui/gui.c b/applications/gui/gui.c index ecc314d7..38243562 100644 --- a/applications/gui/gui.c +++ b/applications/gui/gui.c @@ -2,6 +2,7 @@ #include "gui_i.h" #include +#include #include #include @@ -13,67 +14,55 @@ ARRAY_DEF(WidgetArray, Widget*, M_PTR_OPLIST); -struct GUI { - GUIEvent* event; - Canvas* canvas; +struct Gui { + GuiApi api; + GuiEvent* event; + CanvasApi* canvas_api; WidgetArray_t widgets_status_bar; WidgetArray_t widgets; WidgetArray_t widgets_fs; WidgetArray_t widgets_dialog; }; -void gui_widget_status_bar_add(GUI* gui, Widget* widget) { - assert(gui); +void gui_add_widget(GuiApi* gui_api, Widget* widget, WidgetLayer layer) { + assert(gui_api); assert(widget); + Gui* gui = (Gui*)gui_api; + + // TODO add mutex on widget array + WidgetArray_t* widget_array = NULL; + + switch(layer) { + case WidgetLayerStatusBar: + widget_array = &gui->widgets_status_bar; + break; + case WidgetLayerMain: + widget_array = &gui->widgets; + break; + case WidgetLayerFullscreen: + widget_array = &gui->widgets_fs; + break; + case WidgetLayerDialog: + widget_array = &gui->widgets_dialog; + break; + default: + break; + } + + assert(widget_array); gui_event_lock(gui->event); - WidgetArray_push_back(gui->widgets_status_bar, widget); + WidgetArray_push_back(*widget_array, widget); widget_gui_set(widget, gui); gui_event_unlock(gui->event); gui_update(gui); } -void gui_widget_add(GUI* gui, Widget* widget) { +void gui_update(Gui* gui) { assert(gui); - assert(widget); - - gui_event_lock(gui->event); - WidgetArray_push_back(gui->widgets, widget); - widget_gui_set(widget, gui); - gui_event_unlock(gui->event); - - gui_update(gui); -} - -void gui_widget_fs_add(GUI* gui, Widget* widget) { - assert(gui); - assert(widget); - - gui_event_lock(gui->event); - WidgetArray_push_back(gui->widgets_fs, widget); - widget_gui_set(widget, gui); - gui_event_unlock(gui->event); - - gui_update(gui); -} - -void gui_widget_dialog_add(GUI* gui, Widget* widget) { - assert(gui); - assert(widget); - - gui_event_lock(gui->event); - WidgetArray_push_back(gui->widgets_dialog, widget); - widget_gui_set(widget, gui); - gui_event_unlock(gui->event); - - gui_update(gui); -} - -void gui_update(GUI* gui) { - assert(gui); - GUIMessage message; - message.type = GUIMessageTypeRedraw; + GuiMessage message; + message.type = GuiMessageTypeRedraw; gui_event_messsage_send(gui->event, &message); } @@ -88,36 +77,36 @@ Widget* gui_widget_find_enabled(WidgetArray_t array) { return NULL; } -bool gui_redraw_fs(GUI* gui) { - canvas_frame_set(gui->canvas, 0, 0, 128, 64); +bool gui_redraw_fs(Gui* gui) { + canvas_frame_set(gui->canvas_api, 0, 0, 128, 64); Widget* widget = gui_widget_find_enabled(gui->widgets_fs); if(widget) { - widget_draw(widget, gui->canvas); + widget_draw(widget, gui->canvas_api); return true; } else { return false; } } -void gui_redraw_status_bar(GUI* gui) { - canvas_frame_set(gui->canvas, 0, 0, 128, 64); +void gui_redraw_status_bar(Gui* gui) { + canvas_frame_set(gui->canvas_api, 0, 0, 128, 64); Widget* widget = gui_widget_find_enabled(gui->widgets_status_bar); - if(widget) widget_draw(widget, gui->canvas); + if(widget) widget_draw(widget, gui->canvas_api); } -void gui_redraw_normal(GUI* gui) { - canvas_frame_set(gui->canvas, 0, 9, 128, 55); +void gui_redraw_normal(Gui* gui) { + canvas_frame_set(gui->canvas_api, 0, 9, 128, 55); Widget* widget = gui_widget_find_enabled(gui->widgets); - if(widget) widget_draw(widget, gui->canvas); + if(widget) widget_draw(widget, gui->canvas_api); } -void gui_redraw_dialogs(GUI* gui) { - canvas_frame_set(gui->canvas, 10, 20, 118, 44); +void gui_redraw_dialogs(Gui* gui) { + canvas_frame_set(gui->canvas_api, 10, 20, 118, 44); Widget* widget = gui_widget_find_enabled(gui->widgets_dialog); - if(widget) widget_draw(widget, gui->canvas); + if(widget) widget_draw(widget, gui->canvas_api); } -void gui_redraw(GUI* gui) { +void gui_redraw(Gui* gui) { assert(gui); if(!gui_redraw_fs(gui)) { @@ -126,10 +115,10 @@ void gui_redraw(GUI* gui) { } gui_redraw_dialogs(gui); - canvas_commit(gui->canvas); + canvas_commit(gui->canvas_api); } -void gui_input(GUI* gui, InputEvent* input_event) { +void gui_input(Gui* gui, InputEvent* input_event) { assert(gui); Widget* widget = gui_widget_find_enabled(gui->widgets_dialog); @@ -141,35 +130,42 @@ void gui_input(GUI* gui, InputEvent* input_event) { } } -GUI* gui_alloc() { - GUI* gui = furi_alloc(sizeof(GUI)); +Gui* gui_alloc() { + Gui* gui = furi_alloc(sizeof(Gui)); + // Initialize widget arrays WidgetArray_init(gui->widgets_status_bar); WidgetArray_init(gui->widgets); WidgetArray_init(gui->widgets_fs); WidgetArray_init(gui->widgets_dialog); + // Event dispatcher gui->event = gui_event_alloc(); - // Drawing canvas - gui->canvas = canvas_alloc(); + + // Drawing canvas api + gui->canvas_api = canvas_api_init(); + + gui->api.add_widget = gui_add_widget; return gui; } void gui_task(void* p) { - GUI* gui = gui_alloc(); + Gui* gui = gui_alloc(); // Create FURI record - if(!furi_create_deprecated("gui", gui, sizeof(gui))) { + if(!furi_create("gui", gui)) { printf("[gui_task] cannot create the gui record\n"); furiac_exit(NULL); } + furiac_ready(); + // Forever dispatch while(1) { - GUIMessage message = gui_event_message_next(gui->event); - if(message.type == GUIMessageTypeRedraw) { + GuiMessage message = gui_event_message_next(gui->event); + if(message.type == GuiMessageTypeRedraw) { gui_redraw(gui); - } else if(message.type == GUIMessageTypeInput) { + } else if(message.type == GuiMessageTypeInput) { gui_input(gui, &message.input); } } diff --git a/applications/gui/gui.h b/applications/gui/gui.h index a95b802c..8db1cc20 100644 --- a/applications/gui/gui.h +++ b/applications/gui/gui.h @@ -1,12 +1,18 @@ #pragma once +#include "widget.h" +#include "canvas.h" + +typedef enum { + WidgetLayerStatusBar, + WidgetLayerMain, + WidgetLayerFullscreen, + WidgetLayerDialog +} WidgetLayer; + typedef struct Widget Widget; -typedef struct GUI GUI; -void gui_widget_status_bar_add(GUI* gui, Widget* widget); - -void gui_widget_add(GUI* gui, Widget* widget); - -void gui_widget_fs_add(GUI* gui, Widget* widget); - -void gui_widget_dialog_add(GUI* gui, Widget* widget); +typedef struct GuiApi GuiApi; +struct GuiApi { + void (*add_widget)(GuiApi* gui_api, Widget* widget, WidgetLayer layer); +}; diff --git a/applications/gui/gui_event.c b/applications/gui/gui_event.c index a2ee801b..44b4d5fc 100644 --- a/applications/gui/gui_event.c +++ b/applications/gui/gui_event.c @@ -5,7 +5,7 @@ #define GUI_EVENT_MQUEUE_SIZE 8 -struct GUIEvent { +struct GuiEvent { FuriRecordSubscriber* input_event_record; osMessageQueueId_t mqueue; osMutexId_t lock_mutex; @@ -13,19 +13,19 @@ struct GUIEvent { void gui_event_input_events_callback(const void* value, size_t size, void* ctx) { assert(ctx); - GUIEvent* gui_event = ctx; + GuiEvent* gui_event = ctx; - GUIMessage message; - message.type = GUIMessageTypeInput; + GuiMessage message; + message.type = GuiMessageTypeInput; message.input = *(InputEvent*)value; - osMessageQueuePut(gui_event->mqueue, &message, 0, 0); + osMessageQueuePut(gui_event->mqueue, &message, 0, osWaitForever); } -GUIEvent* gui_event_alloc() { - GUIEvent* gui_event = furi_alloc(sizeof(GUIEvent)); +GuiEvent* gui_event_alloc() { + GuiEvent* gui_event = furi_alloc(sizeof(GuiEvent)); // Allocate message que - gui_event->mqueue = osMessageQueueNew(GUI_EVENT_MQUEUE_SIZE, sizeof(GUIMessage), NULL); + gui_event->mqueue = osMessageQueueNew(GUI_EVENT_MQUEUE_SIZE, sizeof(GuiMessage), NULL); assert(gui_event->mqueue); // Input @@ -40,35 +40,34 @@ GUIEvent* gui_event_alloc() { return gui_event; } -void gui_event_free(GUIEvent* gui_event) { +void gui_event_free(GuiEvent* gui_event) { assert(gui_event); gui_event_unlock(gui_event); assert(osMessageQueueDelete(gui_event->mqueue) == osOK); free(gui_event); } -void gui_event_lock(GUIEvent* gui_event) { +void gui_event_lock(GuiEvent* gui_event) { assert(gui_event); assert(osMutexAcquire(gui_event->lock_mutex, osWaitForever) == osOK); } -void gui_event_unlock(GUIEvent* gui_event) { +void gui_event_unlock(GuiEvent* gui_event) { assert(gui_event); assert(osMutexRelease(gui_event->lock_mutex) == osOK); } -void gui_event_messsage_send(GUIEvent* gui_event, GUIMessage* message) { +void gui_event_messsage_send(GuiEvent* gui_event, GuiMessage* message) { assert(gui_event); assert(message); osMessageQueuePut(gui_event->mqueue, message, 0, 0); } -GUIMessage gui_event_message_next(GUIEvent* gui_event) { +GuiMessage gui_event_message_next(GuiEvent* gui_event) { assert(gui_event); - GUIMessage message; + GuiMessage message; gui_event_unlock(gui_event); - while(osMessageQueueGet(gui_event->mqueue, &message, NULL, osWaitForever) != osOK) { - }; + assert(osMessageQueueGet(gui_event->mqueue, &message, NULL, osWaitForever) == osOK); gui_event_lock(gui_event); return message; } diff --git a/applications/gui/gui_event.h b/applications/gui/gui_event.h index c3a47e45..89ba4ee2 100644 --- a/applications/gui/gui_event.h +++ b/applications/gui/gui_event.h @@ -4,26 +4,26 @@ #include typedef enum { - GUIMessageTypeRedraw = 0x00, - GUIMessageTypeInput = 0x01, -} GUIMessageType; + GuiMessageTypeRedraw = 0x00, + GuiMessageTypeInput = 0x01, +} GuiMessageType; typedef struct { - GUIMessageType type; + GuiMessageType type; InputEvent input; void* data; -} GUIMessage; +} GuiMessage; -typedef struct GUIEvent GUIEvent; +typedef struct GuiEvent GuiEvent; -GUIEvent* gui_event_alloc(); +GuiEvent* gui_event_alloc(); -void gui_event_free(GUIEvent* gui_event); +void gui_event_free(GuiEvent* gui_event); -void gui_event_lock(GUIEvent* gui_event); +void gui_event_lock(GuiEvent* gui_event); -void gui_event_unlock(GUIEvent* gui_event); +void gui_event_unlock(GuiEvent* gui_event); -void gui_event_messsage_send(GUIEvent* gui_event, GUIMessage* message); +void gui_event_messsage_send(GuiEvent* gui_event, GuiMessage* message); -GUIMessage gui_event_message_next(GUIEvent* gui_event); +GuiMessage gui_event_message_next(GuiEvent* gui_event); diff --git a/applications/gui/gui_i.h b/applications/gui/gui_i.h index e12970fc..a64874c1 100644 --- a/applications/gui/gui_i.h +++ b/applications/gui/gui_i.h @@ -1,3 +1,5 @@ #pragma once -void gui_update(GUI* gui); +typedef struct Gui Gui; + +void gui_update(Gui* gui); diff --git a/applications/gui/u8g2_periphery.c b/applications/gui/u8g2_periphery.c new file mode 100644 index 00000000..db12c506 --- /dev/null +++ b/applications/gui/u8g2_periphery.c @@ -0,0 +1,114 @@ +#include "u8g2/u8g2.h" +#include "flipper.h" + +extern SPI_HandleTypeDef hspi1; + +// TODO: fix log +#ifdef DEBUG +#undef DEBUG +#endif + +uint8_t u8g2_gpio_and_delay_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr) { + switch(msg) { + //Initialize SPI peripheral + case U8X8_MSG_GPIO_AND_DELAY_INIT: + /* HAL initialization contains all what we need so we can skip this part. */ + break; + + //Function which implements a delay, arg_int contains the amount of ms + case U8X8_MSG_DELAY_MILLI: + osDelay(arg_int); + break; + + //Function which delays 10us + case U8X8_MSG_DELAY_10MICRO: + delay_us(10); + break; + + //Function which delays 100ns + case U8X8_MSG_DELAY_100NANO: + asm("nop"); + break; + + // Function to define the logic level of the RESET line + case U8X8_MSG_GPIO_RESET: +#ifdef DEBUG + fuprintf(log, "[u8g2] rst %d\n", arg_int); +#endif + + // TODO change it to FuriRecord pin + HAL_GPIO_WritePin( + DISPLAY_RST_GPIO_Port, DISPLAY_RST_Pin, arg_int ? GPIO_PIN_SET : GPIO_PIN_RESET); + break; + + default: +#ifdef DEBUG + fufuprintf(log, "[u8g2] unknown io %d\n", msg); +#endif + + return 0; //A message was received which is not implemented, return 0 to indicate an error + } + + return 1; // command processed successfully. +} + +uint8_t u8x8_hw_spi_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr) { + switch(msg) { + case U8X8_MSG_BYTE_SEND: +#ifdef DEBUG + fuprintf(log, "[u8g2] send %d bytes %02X\n", arg_int, ((uint8_t*)arg_ptr)[0]); +#endif + + // TODO change it to FuriRecord SPI + HAL_SPI_Transmit(&hspi1, (uint8_t*)arg_ptr, arg_int, 10000); + break; + + case U8X8_MSG_BYTE_SET_DC: +#ifdef DEBUG + fuprintf(log, "[u8g2] dc %d\n", arg_int); +#endif + + // TODO change it to FuriRecord pin + HAL_GPIO_WritePin( + DISPLAY_DI_GPIO_Port, DISPLAY_DI_Pin, arg_int ? GPIO_PIN_SET : GPIO_PIN_RESET); + break; + + case U8X8_MSG_BYTE_INIT: +#ifdef DEBUG + fuprintf(log, "[u8g2] init\n"); +#endif + + // TODO change it to FuriRecord pin + HAL_GPIO_WritePin(DISPLAY_CS_GPIO_Port, DISPLAY_CS_Pin, GPIO_PIN_RESET); + break; + + case U8X8_MSG_BYTE_START_TRANSFER: +#ifdef DEBUG + fuprintf(log, "[u8g2] start\n"); +#endif + + // TODO change it to FuriRecord pin + HAL_GPIO_WritePin(DISPLAY_CS_GPIO_Port, DISPLAY_CS_Pin, GPIO_PIN_RESET); + asm("nop"); + break; + + case U8X8_MSG_BYTE_END_TRANSFER: +#ifdef DEBUG + fuprintf(log, "[u8g2] end\n"); +#endif + + asm("nop"); + // TODO change it to FuriRecord pin + HAL_GPIO_WritePin(DISPLAY_CS_GPIO_Port, DISPLAY_CS_Pin, GPIO_PIN_SET); + break; + + default: +#ifdef DEBUG + fuprintf(log, "[u8g2] unknown xfer %d\n", msg); +#endif + + return 0; + } + + return 1; +} diff --git a/applications/gui/widget.c b/applications/gui/widget.c index bff2a4b9..4b22679d 100644 --- a/applications/gui/widget.c +++ b/applications/gui/widget.c @@ -7,8 +7,10 @@ #include "gui.h" #include "gui_i.h" +// TODO add mutex to widget ops + struct Widget { - void* gui; + Gui* gui; bool is_enabled; WidgetDrawCallback draw_callback; void* draw_callback_context; @@ -56,18 +58,20 @@ void widget_update(Widget* widget) { if(widget->gui) gui_update(widget->gui); } -void widget_gui_set(Widget* widget, GUI* gui) { +void widget_gui_set(Widget* widget, Gui* gui) { assert(widget); assert(gui); widget->gui = gui; } -void widget_draw(Widget* widget, Canvas* canvas) { +void widget_draw(Widget* widget, CanvasApi* canvas_api) { assert(widget); - assert(canvas); + assert(canvas_api); assert(widget->gui); - if(widget->draw_callback) widget->draw_callback(canvas, widget->draw_callback_context); + if(widget->draw_callback) { + widget->draw_callback(canvas_api, widget->draw_callback_context); + } } void widget_input(Widget* widget, InputEvent* event) { diff --git a/applications/gui/widget.h b/applications/gui/widget.h index b29ade45..83f7d497 100644 --- a/applications/gui/widget.h +++ b/applications/gui/widget.h @@ -1,12 +1,11 @@ #pragma once #include +#include "canvas.h" -typedef struct GUI GUI; -typedef struct Canvas Canvas; typedef struct Widget Widget; -typedef void (*WidgetDrawCallback)(Canvas* canvas, void* context); +typedef void (*WidgetDrawCallback)(CanvasApi* api, void* context); typedef void (*WidgetInputCallback)(InputEvent* event, void* context); Widget* widget_alloc(); diff --git a/applications/gui/widget_i.h b/applications/gui/widget_i.h index 5c1af22d..b3d481e9 100644 --- a/applications/gui/widget_i.h +++ b/applications/gui/widget_i.h @@ -1,7 +1,9 @@ #pragma once -void widget_gui_set(Widget* widget, GUI* gui); +#include "gui_i.h" -void widget_draw(Widget* widget, Canvas* canvas); +void widget_gui_set(Widget* widget, Gui* gui); + +void widget_draw(Widget* widget, CanvasApi* canvas_api); void widget_input(Widget* widget, InputEvent* event); diff --git a/applications/menu/menu.c b/applications/menu/menu.c index 8cafe6a4..a0261bf5 100644 --- a/applications/menu/menu.c +++ b/applications/menu/menu.c @@ -4,18 +4,18 @@ #include #include +#include #include -#include -#include #include "menu_event.h" #include "menu_item.h" struct Menu { MenuEvent* event; + // GUI - FuriRecordSubscriber* gui_record; Widget* widget; + // State MenuItem* root; MenuItem* settings; @@ -23,9 +23,9 @@ struct Menu { uint32_t position; }; -void menu_widget_callback(Canvas* canvas, void* context); +void menu_widget_callback(CanvasApi* canvas, void* context); -Menu* menu_alloc() { +Menu* menu_init() { Menu* menu = furi_alloc(sizeof(Menu)); // Event dispatcher @@ -37,8 +37,9 @@ Menu* menu_alloc() { widget_input_callback_set(menu->widget, menu_event_input_callback, menu->event); // Open GUI and register fullscreen widget - menu->gui_record = furi_open_deprecated("gui", false, false, NULL, NULL, NULL); - assert(menu->gui_record); + GuiApi* gui = furi_open("gui"); + assert(gui); + gui->add_widget(gui, menu->widget, WidgetLayerFullscreen); return menu; } @@ -48,22 +49,21 @@ void menu_build_main(Menu* menu) { // Root point menu->root = menu_item_alloc_menu(NULL, NULL); - menu_item_add(menu, menu_item_alloc_function("Sub 1 gHz", NULL, NULL)); - menu_item_add(menu, menu_item_alloc_function("125 kHz RFID", NULL, NULL)); - menu_item_add(menu, menu_item_alloc_function("Infrared", NULL, NULL)); - menu_item_add(menu, menu_item_alloc_function("I-Button", NULL, NULL)); - menu_item_add(menu, menu_item_alloc_function("USB", NULL, NULL)); - menu_item_add(menu, menu_item_alloc_function("Bluetooth", NULL, NULL)); - menu_item_add(menu, menu_item_alloc_function("GPIO / HW", NULL, NULL)); - menu_item_add(menu, menu_item_alloc_function("NFC", NULL, NULL)); - menu_item_add(menu, menu_item_alloc_function("U2F", NULL, NULL)); - menu_item_add(menu, menu_item_alloc_function("Tamagotchi", NULL, NULL)); - menu_item_add(menu, menu_item_alloc_function("Plugins", NULL, NULL)); + menu_item_add(menu, menu_item_alloc_function("Sub 1 gHz", NULL, NULL, NULL)); + menu_item_add(menu, menu_item_alloc_function("125 kHz RFID", NULL, NULL, NULL)); + menu_item_add(menu, menu_item_alloc_function("Infrared", NULL, NULL, NULL)); + menu_item_add(menu, menu_item_alloc_function("I-Button", NULL, NULL, NULL)); + menu_item_add(menu, menu_item_alloc_function("USB", NULL, NULL, NULL)); + menu_item_add(menu, menu_item_alloc_function("Bluetooth", NULL, NULL, NULL)); + menu_item_add(menu, menu_item_alloc_function("GPIO / HW", NULL, NULL, NULL)); + menu_item_add(menu, menu_item_alloc_function("U2F", NULL, NULL, NULL)); + menu_item_add(menu, menu_item_alloc_function("Tamagotchi", NULL, NULL, NULL)); + menu_item_add(menu, menu_item_alloc_function("Plugins", NULL, NULL, NULL)); menu->settings = menu_item_alloc_menu("Setting", NULL); - menu_item_subitem_add(menu->settings, menu_item_alloc_function("one", NULL, NULL)); - menu_item_subitem_add(menu->settings, menu_item_alloc_function("two", NULL, NULL)); - menu_item_subitem_add(menu->settings, menu_item_alloc_function("three", NULL, NULL)); + menu_item_subitem_add(menu->settings, menu_item_alloc_function("one", NULL, NULL, NULL)); + menu_item_subitem_add(menu->settings, menu_item_alloc_function("two", NULL, NULL, NULL)); + menu_item_subitem_add(menu->settings, menu_item_alloc_function("three", NULL, NULL, NULL)); menu_item_add(menu, menu->settings); } @@ -76,7 +76,7 @@ void menu_settings_item_add(Menu* menu, MenuItem* item) { menu_item_subitem_add(menu->settings, item); } -void menu_widget_callback(Canvas* canvas, void* context) { +void menu_widget_callback(CanvasApi* canvas, void* context) { assert(canvas); assert(context); @@ -85,20 +85,20 @@ void menu_widget_callback(Canvas* canvas, void* context) { menu_event_lock(menu->event); if(!menu->current) { - canvas_clear(canvas); - canvas_color_set(canvas, COLOR_BLACK); - canvas_font_set(canvas, CANVAS_FONT_PRIMARY); - canvas_str_draw(canvas, 2, 32, "Idle Screen"); + canvas->clear(canvas); + canvas->set_color(canvas, ColorBlack); + canvas->set_font(canvas, FontPrimary); + canvas->draw_str(canvas, 2, 32, "Idle Screen"); } else { MenuItemArray_t* items = menu_item_get_subitems(menu->current); - canvas_clear(canvas); - canvas_color_set(canvas, COLOR_BLACK); - canvas_font_set(canvas, CANVAS_FONT_SECONDARY); + canvas->clear(canvas); + canvas->set_color(canvas, ColorBlack); + canvas->set_font(canvas, FontSecondary); for(size_t i = 0; i < 5; i++) { size_t shift_position = i + menu->position + MenuItemArray_size(*items) - 2; shift_position = shift_position % (MenuItemArray_size(*items)); MenuItem* item = *MenuItemArray_get(*items, shift_position); - canvas_str_draw(canvas, 2, 12 * (i + 1), menu_item_get_label(item)); + canvas->draw_str(canvas, 2, 12 * (i + 1), menu_item_get_label(item)); } } @@ -148,8 +148,7 @@ void menu_ok(Menu* menu) { menu->position = 0; menu_update(menu); } else if(type == MenuItemTypeFunction) { - MenuItemCallback function = menu_item_get_function(item); - if(function) function(); + menu_item_function_call(item); } } @@ -173,19 +172,14 @@ void menu_exit(Menu* menu) { } void menu_task(void* p) { - Menu* menu = menu_alloc(); + Menu* menu = menu_init(); menu_build_main(menu); - // Register widget - GUI* gui = furi_take(menu->gui_record); - assert(gui); - gui_widget_fs_add(gui, menu->widget); - furi_commit(menu->gui_record); - if(!furi_create_deprecated("menu", menu, sizeof(menu))) { printf("[menu_task] cannot create the menu record\n"); furiac_exit(NULL); } + furiac_ready(); while(1) { diff --git a/applications/menu/menu_event.c b/applications/menu/menu_event.c index 82b32f8f..bd479972 100644 --- a/applications/menu/menu_event.c +++ b/applications/menu/menu_event.c @@ -19,7 +19,7 @@ void MenuEventimeout_callback(void* arg) { MenuEvent* menu_event = arg; MenuMessage message; message.type = MenuMessageTypeIdle; - osMessageQueuePut(menu_event->mqueue, &message, 0, 0); + osMessageQueuePut(menu_event->mqueue, &message, 0, osWaitForever); } MenuEvent* menu_event_alloc() { @@ -92,5 +92,5 @@ void menu_event_input_callback(InputEvent* input_event, void* context) { message.type = MenuMessageTypeUnknown; } - osMessageQueuePut(menu_event->mqueue, &message, 0, 0); + osMessageQueuePut(menu_event->mqueue, &message, 0, osWaitForever); } diff --git a/applications/menu/menu_item.c b/applications/menu/menu_item.c index 57072bc2..87c081c1 100644 --- a/applications/menu/menu_item.c +++ b/applications/menu/menu_item.c @@ -10,6 +10,8 @@ struct MenuItem { void* icon; MenuItem* parent; void* data; + MenuItemCallback callback; + void* callback_context; }; MenuItem* menu_item_alloc() { @@ -31,27 +33,35 @@ MenuItem* menu_item_alloc_menu(const char* label, void* icon) { return menu_item; } -MenuItem* menu_item_alloc_function(const char* label, void* icon, MenuItemCallback function) { +MenuItem* +menu_item_alloc_function(const char* label, void* icon, MenuItemCallback callback, void* context) { MenuItem* menu_item = menu_item_alloc(); menu_item->type = MenuItemTypeFunction; menu_item->label = label; menu_item->icon = icon; - menu_item->data = function; + menu_item->callback = callback; + menu_item->callback_context = context; return menu_item; } void menu_item_release(MenuItem* menu_item) { - if(menu_item->type == MenuItemTypeMenu) free(menu_item->data); + assert(menu_item); + if(menu_item->type == MenuItemTypeMenu) { + //TODO: iterate and release + free(menu_item->data); + } free(menu_item); } MenuItem* menu_item_get_parent(MenuItem* menu_item) { + assert(menu_item); return menu_item->parent; } void menu_item_subitem_add(MenuItem* menu_item, MenuItem* sub_item) { + assert(menu_item); assert(menu_item->type == MenuItemTypeMenu); MenuItemArray_t* items = menu_item->data; sub_item->parent = menu_item; @@ -59,31 +69,39 @@ void menu_item_subitem_add(MenuItem* menu_item, MenuItem* sub_item) { } uint8_t menu_item_get_type(MenuItem* menu_item) { + assert(menu_item); return menu_item->type; } void menu_item_set_label(MenuItem* menu_item, const char* label) { + assert(menu_item); menu_item->label = label; } const char* menu_item_get_label(MenuItem* menu_item) { + assert(menu_item); return menu_item->label; } void menu_item_set_icon(MenuItem* menu_item, void* icon) { + assert(menu_item); menu_item->icon = icon; } void* menu_item_get_icon(MenuItem* menu_item) { + assert(menu_item); return menu_item->icon; } MenuItemArray_t* menu_item_get_subitems(MenuItem* menu_item) { + assert(menu_item); assert(menu_item->type == MenuItemTypeMenu); return menu_item->data; } -MenuItemCallback menu_item_get_function(MenuItem* menu_item) { +void menu_item_function_call(MenuItem* menu_item) { + assert(menu_item); assert(menu_item->type == MenuItemTypeFunction); - return menu_item->data; + + if(menu_item->callback) menu_item->callback(menu_item->callback_context); } diff --git a/applications/menu/menu_item.h b/applications/menu/menu_item.h index 57b81124..06838d6e 100644 --- a/applications/menu/menu_item.h +++ b/applications/menu/menu_item.h @@ -9,13 +9,14 @@ typedef enum { } MenuItemType; typedef struct MenuItem MenuItem; -typedef void (*MenuItemCallback)(); +typedef void (*MenuItemCallback)(void* context); ARRAY_DEF(MenuItemArray, MenuItem*, M_PTR_OPLIST); MenuItem* menu_item_alloc_menu(const char* label, void* icon); -MenuItem* menu_item_alloc_function(const char* label, void* icon, MenuItemCallback function); +MenuItem* +menu_item_alloc_function(const char* label, void* icon, MenuItemCallback callback, void* context); void menu_item_release(MenuItem* menu_item); @@ -33,4 +34,4 @@ void* menu_item_get_icon(MenuItem* menu_item); MenuItemArray_t* menu_item_get_subitems(MenuItem* menu_item); -MenuItemCallback menu_item_get_function(MenuItem* menu_item); +void menu_item_function_call(MenuItem* menu_item); diff --git a/applications/startup.h b/applications/startup.h index 2f96ce08..847009dc 100644 --- a/applications/startup.h +++ b/applications/startup.h @@ -26,6 +26,7 @@ void coreglitch_demo_0(void* p); void u8g2_qrcode(void* p); void fatfs_list(void* p); void gui_task(void* p); +void backlight_control(void* p); const FlipperStartupApp FLIPPER_STARTUP[] = { #ifdef APP_DISPLAY @@ -37,7 +38,8 @@ const FlipperStartupApp FLIPPER_STARTUP[] = { #endif #ifdef APP_GUI - {.app = gui_task, .name = "gui_task", .libs = {1, FURI_LIB{"display_u8g2"}}}, + {.app = backlight_control, .name = "backlight_control", .libs = {1, FURI_LIB{"input_task"}}}, + {.app = gui_task, .name = "gui_task", .libs = {0}}, #endif #ifdef APP_MENU