From a96f23af9b6847c27b544bbe955f2b19ad09da7c Mon Sep 17 00:00:00 2001 From: DrZlo13 Date: Thu, 19 Nov 2020 15:25:32 +0300 Subject: [PATCH] fix multithread logic in template app, update gpio HAL (#250) * fix multithread logic * more buffer for dallas id string * update apps to use new logic * delay_us small speedup * add consant qualifier to gpio records and some core api * fix some apps to use simpler method of getting gpio record * fix ibutton app, stupid stack problem --- .../backlight-control/backlight-control.c | 5 +- applications/examples/blink.c | 19 ++++---- applications/ibutton/ibutton.cpp | 16 ++----- applications/ibutton/ibutton.h | 6 +-- .../ibutton/ibutton_mode_dallas_emulate.h | 9 ++-- .../ibutton/ibutton_mode_dallas_read.h | 9 ++-- applications/ibutton/one_wire_gpio.h | 6 +-- applications/ibutton/one_wire_slave_gpio.h | 6 +-- applications/irda/irda.c | 5 +- applications/sd-card-test/sd-card-test.cpp | 2 + applications/sd-nfc/sdnfc.cpp | 2 + core/api-basic/valuemutex.c | 2 +- core/api-basic/valuemutex.h | 2 +- core/api-hal/api-gpio.c | 10 ++-- core/api-hal/api-gpio.h | 10 ++-- firmware/targets/f2/api-hal/api-hal-gpio.c | 6 ++- firmware/targets/f2/api-hal/api-hal-gpio.h | 8 +++- firmware/targets/f3/api-hal/api-hal-delay.c | 5 +- firmware/targets/f3/api-hal/api-hal-gpio.c | 11 +++-- firmware/targets/f3/api-hal/api-hal-gpio.h | 8 +++- firmware/targets/local/api-hal/api-hal-gpio.c | 12 +++-- firmware/targets/local/api-hal/api-hal-gpio.h | 8 +++- lib/app-template/app-template.cpp | 12 ++++- lib/app-template/app-template.h | 46 +++++++++++-------- 24 files changed, 137 insertions(+), 88 deletions(-) diff --git a/applications/backlight-control/backlight-control.c b/applications/backlight-control/backlight-control.c index 16810c45..a640b5aa 100644 --- a/applications/backlight-control/backlight-control.c +++ b/applications/backlight-control/backlight-control.c @@ -7,11 +7,8 @@ static void event_cb(const void* value, void* ctx) { const uint32_t BACKLIGHT_TIME = 10000; void backlight_control(void* p) { - // create pin - GpioPin backlight = backlight_gpio; - // TODO open record - GpioPin* backlight_record = &backlight; + const GpioPin* backlight_record = &backlight_gpio; // configure pin gpio_init(backlight_record, GpioModeOutputPushPull); diff --git a/applications/examples/blink.c b/applications/examples/blink.c index d44d130e..cf5718ce 100644 --- a/applications/examples/blink.c +++ b/applications/examples/blink.c @@ -1,21 +1,22 @@ #include "flipper_v2.h" -void rgb_set(bool r, bool g, bool b, GpioPin* led_r, GpioPin* led_g, GpioPin* led_b) { +void rgb_set( + bool r, + bool g, + bool b, + const GpioPin* led_r, + const GpioPin* led_g, + const GpioPin* led_b) { gpio_write(led_r, !r); gpio_write(led_g, !g); gpio_write(led_b, !b); } void application_blink(void* p) { - // create pin - GpioPin led_r = led_gpio[0]; - GpioPin led_g = led_gpio[1]; - GpioPin led_b = led_gpio[2]; - // TODO open record - GpioPin* led_r_record = &led_r; - GpioPin* led_g_record = &led_g; - GpioPin* led_b_record = &led_b; + const GpioPin* led_r_record = &led_gpio[0]; + const GpioPin* led_g_record = &led_gpio[1]; + const GpioPin* led_b_record = &led_gpio[2]; // configure pin gpio_init(led_r_record, GpioModeOutputOpenDrain); diff --git a/applications/ibutton/ibutton.cpp b/applications/ibutton/ibutton.cpp index 104d4d24..94023e57 100644 --- a/applications/ibutton/ibutton.cpp +++ b/applications/ibutton/ibutton.cpp @@ -4,25 +4,21 @@ // start app void AppiButton::run() { - acquire_state(); mode[0] = new AppiButtonModeDallasRead(this); mode[1] = new AppiButtonModeDallasEmulate(this); - release_state(); switch_to_mode(0); - // create pin - GpioPin red_led = led_gpio[0]; - GpioPin green_led = led_gpio[1]; - // TODO open record - red_led_record = &red_led; - green_led_record = &green_led; + red_led_record = &led_gpio[0]; + green_led_record = &led_gpio[1]; // configure pin gpio_init(red_led_record, GpioModeOutputOpenDrain); gpio_init(green_led_record, GpioModeOutputOpenDrain); + app_ready(); + AppiButtonEvent event; while(1) { if(get_event(&event, 100)) { @@ -61,9 +57,7 @@ void AppiButton::render(CanvasApi* canvas) { canvas->set_font(canvas, FontPrimary); canvas->draw_str(canvas, 2, 12, "iButton"); - if(mode[state.mode_index] != NULL) { - mode[state.mode_index]->render(canvas, &state); - } + mode[state.mode_index]->render(canvas, &state); } void AppiButton::blink_red() { diff --git a/applications/ibutton/ibutton.h b/applications/ibutton/ibutton.h index bd44ad5e..a99fc186 100644 --- a/applications/ibutton/ibutton.h +++ b/applications/ibutton/ibutton.h @@ -38,11 +38,11 @@ public: // with template variables class AppiButton : public AppTemplate { public: - GpioPin* red_led_record; - GpioPin* green_led_record; + const GpioPin* red_led_record; + const GpioPin* green_led_record; static const uint8_t modes_count = 2; - AppTemplateMode* mode[modes_count] = {NULL, NULL}; + AppTemplateMode* mode[modes_count]; void run(); void render(CanvasApi* canvas); diff --git a/applications/ibutton/ibutton_mode_dallas_emulate.h b/applications/ibutton/ibutton_mode_dallas_emulate.h index 391c9530..0ed18546 100644 --- a/applications/ibutton/ibutton_mode_dallas_emulate.h +++ b/applications/ibutton/ibutton_mode_dallas_emulate.h @@ -17,8 +17,7 @@ public: app = parent_app; // TODO open record - GpioPin one_wire_pin = ibutton_gpio; - GpioPin* one_wire_pin_record = &one_wire_pin; + const GpioPin* one_wire_pin_record = &ibutton_gpio; onewire_slave = new OneWireGpioSlave(one_wire_pin_record); }; }; @@ -39,9 +38,11 @@ void AppiButtonModeDallasEmulate::render(CanvasApi* canvas, AppiButtonState* sta canvas->draw_str(canvas, 2, 25, "< dallas emulate"); canvas->draw_str(canvas, 2, 37, "unimplemented"); { - char buf[24]; - sprintf( + const uint8_t buffer_size = 32; + char buf[buffer_size]; + snprintf( buf, + buffer_size, "%x:%x:%x:%x:%x:%x:%x:%x", state->dallas_address[0], state->dallas_address[1], diff --git a/applications/ibutton/ibutton_mode_dallas_read.h b/applications/ibutton/ibutton_mode_dallas_read.h index f22fa134..639d7df3 100644 --- a/applications/ibutton/ibutton_mode_dallas_read.h +++ b/applications/ibutton/ibutton_mode_dallas_read.h @@ -17,8 +17,7 @@ public: app = parent_app; // TODO open record - GpioPin one_wire_pin = ibutton_gpio; - GpioPin* one_wire_pin_record = &one_wire_pin; + const GpioPin* one_wire_pin_record = &ibutton_gpio; onewire = new OneWireGpio(one_wire_pin_record); }; @@ -68,9 +67,11 @@ void AppiButtonModeDallasRead::render(CanvasApi* canvas, AppiButtonState* state) canvas->draw_str(canvas, 2, 25, "dallas read >"); canvas->draw_str(canvas, 2, 37, "touch me, iButton"); { - char buf[24]; - sprintf( + const uint8_t buffer_size = 32; + char buf[buffer_size]; + snprintf( buf, + buffer_size, "%x:%x:%x:%x:%x:%x:%x:%x", state->dallas_address[0], state->dallas_address[1], diff --git a/applications/ibutton/one_wire_gpio.h b/applications/ibutton/one_wire_gpio.h index a99bbb02..6d9818d6 100644 --- a/applications/ibutton/one_wire_gpio.h +++ b/applications/ibutton/one_wire_gpio.h @@ -5,10 +5,10 @@ class OneWireGpio { private: - GpioPin* gpio; + const GpioPin* gpio; public: - OneWireGpio(GpioPin* one_wire_gpio); + OneWireGpio(const GpioPin* one_wire_gpio); ~OneWireGpio(); bool reset(void); bool read_bit(void); @@ -20,7 +20,7 @@ public: void stop(void); }; -OneWireGpio::OneWireGpio(GpioPin* one_wire_gpio) { +OneWireGpio::OneWireGpio(const GpioPin* one_wire_gpio) { gpio = one_wire_gpio; } diff --git a/applications/ibutton/one_wire_slave_gpio.h b/applications/ibutton/one_wire_slave_gpio.h index cf6cbdd9..f6d11e3f 100644 --- a/applications/ibutton/one_wire_slave_gpio.h +++ b/applications/ibutton/one_wire_slave_gpio.h @@ -5,10 +5,10 @@ class OneWireGpioSlave { private: - GpioPin* gpio; + const GpioPin* gpio; public: - OneWireGpioSlave(GpioPin* one_wire_gpio); + OneWireGpioSlave(const GpioPin* one_wire_gpio); ~OneWireGpioSlave(); void start(void); void stop(void); @@ -25,7 +25,7 @@ public: OneWiteTimeType wait_while_gpio(volatile OneWiteTimeType retries, const bool pin_value); }; -OneWireGpioSlave::OneWireGpioSlave(GpioPin* one_wire_gpio) { +OneWireGpioSlave::OneWireGpioSlave(const GpioPin* one_wire_gpio) { gpio = one_wire_gpio; } diff --git a/applications/irda/irda.c b/applications/irda/irda.c index 31a1a7f2..08043e34 100644 --- a/applications/irda/irda.c +++ b/applications/irda/irda.c @@ -264,11 +264,8 @@ void irda(void* p) { gui->add_widget(gui, widget, GuiLayerFullscreen); // Red LED - // create pin - GpioPin led = led_gpio[0]; - // TODO open record - GpioPin* led_record = &led; + const GpioPin* led_record = &led_gpio[0]; // configure pin gpio_init(led_record, GpioModeOutputOpenDrain); diff --git a/applications/sd-card-test/sd-card-test.cpp b/applications/sd-card-test/sd-card-test.cpp index 1fd74030..d1b2d3be 100644 --- a/applications/sd-card-test/sd-card-test.cpp +++ b/applications/sd-card-test/sd-card-test.cpp @@ -95,6 +95,8 @@ void SdTest::run() { gpio_init(red_led_record, GpioModeOutputOpenDrain); gpio_init(green_led_record, GpioModeOutputOpenDrain); + app_ready(); + detect_sd_card(); show_warning(); init_sd_card(); diff --git a/applications/sd-nfc/sdnfc.cpp b/applications/sd-nfc/sdnfc.cpp index b8a2ad3c..7705c067 100644 --- a/applications/sd-nfc/sdnfc.cpp +++ b/applications/sd-nfc/sdnfc.cpp @@ -77,6 +77,8 @@ void AppSdNFC::run() { gpio_init(red_led_record, GpioModeOutputOpenDrain); gpio_init(green_led_record, GpioModeOutputOpenDrain); + app_ready(); + uint8_t rfal_result = rfalNfcInitialize(); if(rfal_result) { set_text("rfal init fail"); diff --git a/core/api-basic/valuemutex.c b/core/api-basic/valuemutex.c index eb6c20bf..7679ff9b 100644 --- a/core/api-basic/valuemutex.c +++ b/core/api-basic/valuemutex.c @@ -33,7 +33,7 @@ void* acquire_mutex(ValueMutex* valuemutex, uint32_t timeout) { } } -bool release_mutex(ValueMutex* valuemutex, void* value) { +bool release_mutex(ValueMutex* valuemutex, const void* value) { if(value != valuemutex->value) return false; if(osMutexRelease(valuemutex->mutex) != osOK) return false; diff --git a/core/api-basic/valuemutex.h b/core/api-basic/valuemutex.h index 986e936a..46084176 100644 --- a/core/api-basic/valuemutex.h +++ b/core/api-basic/valuemutex.h @@ -58,7 +58,7 @@ static inline void* acquire_mutex_block(ValueMutex* valuemutex) { Release mutex after end of work with data. Call `release_mutex` and pass ValueData instance and pointer to data. */ -bool release_mutex(ValueMutex* valuemutex, void* value); +bool release_mutex(ValueMutex* valuemutex, const void* value); /* Instead of take-access-give sequence you can use `read_mutex` and `write_mutex` functions. diff --git a/core/api-hal/api-gpio.c b/core/api-hal/api-gpio.c index 74e2adeb..f1206025 100644 --- a/core/api-hal/api-gpio.c +++ b/core/api-hal/api-gpio.c @@ -9,7 +9,7 @@ bool gpio_api_init(void) { } // init GPIO -void gpio_init(GpioPin* gpio, GpioMode mode) { +void gpio_init(const GpioPin* gpio, const GpioMode mode) { if(osMutexAcquire(gpioInitMutex, osWaitForever) == osOK) { hal_gpio_init(gpio, mode, GpioPullNo, GpioSpeedLow); osMutexRelease(gpioInitMutex); @@ -17,13 +17,17 @@ void gpio_init(GpioPin* gpio, GpioMode mode) { } // init GPIO, extended version -void gpio_init_ex(GpioPin* gpio, GpioMode mode, GpioPull pull, GpioSpeed speed) { +void gpio_init_ex( + const GpioPin* gpio, + const GpioMode mode, + const GpioPull pull, + const GpioSpeed speed) { hal_gpio_init(gpio, mode, pull, speed); } // put GPIO to Z-state void gpio_disable(GpioDisableRecord* gpio_record) { - GpioPin* gpio_pin = acquire_mutex(gpio_record->gpio_mutex, 0); + const GpioPin* gpio_pin = acquire_mutex(gpio_record->gpio_mutex, 0); if(gpio_pin == NULL) { gpio_pin = gpio_record->gpio; } diff --git a/core/api-hal/api-gpio.h b/core/api-hal/api-gpio.h index 6c424f0b..116c6ffb 100644 --- a/core/api-hal/api-gpio.h +++ b/core/api-hal/api-gpio.h @@ -12,13 +12,17 @@ typedef struct { bool gpio_api_init(); // init GPIO -void gpio_init(GpioPin* gpio, GpioMode mode); +void gpio_init(const GpioPin* gpio, const GpioMode mode); // init GPIO, extended version -void gpio_init_ex(GpioPin* gpio, GpioMode mode, GpioPull pull, GpioSpeed speed); +void gpio_init_ex( + const GpioPin* gpio, + const GpioMode mode, + const GpioPull pull, + const GpioSpeed speed); // write value to GPIO, false = LOW, true = HIGH -static inline void gpio_write(GpioPin* gpio, bool state) { +static inline void gpio_write(const GpioPin* gpio, const bool state) { hal_gpio_write(gpio, state); } diff --git a/firmware/targets/f2/api-hal/api-hal-gpio.c b/firmware/targets/f2/api-hal/api-hal-gpio.c index 91eeef25..d2c4d7cd 100644 --- a/firmware/targets/f2/api-hal/api-hal-gpio.c +++ b/firmware/targets/f2/api-hal/api-hal-gpio.c @@ -1,7 +1,11 @@ #include "api-hal-gpio.h" // init GPIO -void hal_gpio_init(GpioPin* gpio, GpioMode mode, GpioPull pull, GpioSpeed speed) { +void hal_gpio_init( + const GpioPin* gpio, + const GpioMode mode, + const GpioPull pull, + const GpioSpeed speed) { // TODO: Alternate Functions GPIO_InitTypeDef GPIO_InitStruct = {0}; diff --git a/firmware/targets/f2/api-hal/api-hal-gpio.h b/firmware/targets/f2/api-hal/api-hal-gpio.h index f1b77711..9413025c 100644 --- a/firmware/targets/f2/api-hal/api-hal-gpio.h +++ b/firmware/targets/f2/api-hal/api-hal-gpio.h @@ -39,10 +39,14 @@ typedef struct { } GpioPin; // init GPIO -void hal_gpio_init(GpioPin* gpio, GpioMode mode, GpioPull pull, GpioSpeed speed); +void hal_gpio_init( + const GpioPin* gpio, + const GpioMode mode, + const GpioPull pull, + const GpioSpeed speed); // write value to GPIO, false = LOW, true = HIGH -static inline void hal_gpio_write(GpioPin* gpio, bool state) { +static inline void hal_gpio_write(const GpioPin* gpio, const bool state) { // writing to BSSR is an atomic operation if(state == true) { gpio->port->BSRR = gpio->pin; diff --git a/firmware/targets/f3/api-hal/api-hal-delay.c b/firmware/targets/f3/api-hal/api-hal-delay.c index bda9cace..07e0b2cc 100644 --- a/firmware/targets/f3/api-hal/api-hal-delay.c +++ b/firmware/targets/f3/api-hal/api-hal-delay.c @@ -2,15 +2,18 @@ #include "assert.h" #include "cmsis_os2.h" +static uint32_t clk_per_microsecond; + void delay_us_init_DWT(void) { CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; DWT->CYCCNT = 0U; + clk_per_microsecond = SystemCoreClock / 1000000.0f; } void delay_us(float microseconds) { uint32_t start = DWT->CYCCNT; - uint32_t time_ticks = microseconds * (SystemCoreClock / 1000000.0f); + uint32_t time_ticks = microseconds * clk_per_microsecond; while((DWT->CYCCNT - start) < time_ticks) { }; } diff --git a/firmware/targets/f3/api-hal/api-hal-gpio.c b/firmware/targets/f3/api-hal/api-hal-gpio.c index a3bfd0e5..17cbc962 100644 --- a/firmware/targets/f3/api-hal/api-hal-gpio.c +++ b/firmware/targets/f3/api-hal/api-hal-gpio.c @@ -2,7 +2,11 @@ #include "api-hal-resources.h" // init GPIO -void hal_gpio_init(GpioPin* gpio, GpioMode mode, GpioPull pull, GpioSpeed speed) { +void hal_gpio_init( + const GpioPin* gpio, + const GpioMode mode, + const GpioPull pull, + const GpioSpeed speed) { // TODO: Alternate Functions GPIO_InitTypeDef GPIO_InitStruct = {0}; @@ -16,10 +20,9 @@ void hal_gpio_init(GpioPin* gpio, GpioMode mode, GpioPull pull, GpioSpeed speed) bool hal_gpio_read_sd_detect(void) { bool result = false; - // create pin - GpioPin sd_cs_pin = sd_cs_gpio; + // TODO open record - GpioPin* sd_cs_record = &sd_cs_pin; + const GpioPin* sd_cs_record = &sd_cs_gpio; // configure pin as input gpio_init_ex(sd_cs_record, GpioModeInput, GpioPullUp, GpioSpeedVeryHigh); diff --git a/firmware/targets/f3/api-hal/api-hal-gpio.h b/firmware/targets/f3/api-hal/api-hal-gpio.h index f1b77711..9413025c 100644 --- a/firmware/targets/f3/api-hal/api-hal-gpio.h +++ b/firmware/targets/f3/api-hal/api-hal-gpio.h @@ -39,10 +39,14 @@ typedef struct { } GpioPin; // init GPIO -void hal_gpio_init(GpioPin* gpio, GpioMode mode, GpioPull pull, GpioSpeed speed); +void hal_gpio_init( + const GpioPin* gpio, + const GpioMode mode, + const GpioPull pull, + const GpioSpeed speed); // write value to GPIO, false = LOW, true = HIGH -static inline void hal_gpio_write(GpioPin* gpio, bool state) { +static inline void hal_gpio_write(const GpioPin* gpio, const bool state) { // writing to BSSR is an atomic operation if(state == true) { gpio->port->BSRR = gpio->pin; diff --git a/firmware/targets/local/api-hal/api-hal-gpio.c b/firmware/targets/local/api-hal/api-hal-gpio.c index 69e8e4f8..574b28a3 100644 --- a/firmware/targets/local/api-hal/api-hal-gpio.c +++ b/firmware/targets/local/api-hal/api-hal-gpio.c @@ -2,7 +2,11 @@ #include // init GPIO -void hal_gpio_init(GpioPin* gpio, GpioMode mode, GpioPull pull, GpioSpeed speed){ +void hal_gpio_init( + const GpioPin* gpio, + const GpioMode mode, + const GpioPull pull, + const GpioSpeed speed) { // TODO more mode if(gpio->pin != 0) { switch(mode) { @@ -17,7 +21,7 @@ void hal_gpio_init(GpioPin* gpio, GpioMode mode, GpioPull pull, GpioSpeed speed) case GpioModeOutputOpenDrain: printf("[GPIO] %s%d open drain\n", gpio->port, gpio->pin); break; - + default: printf("[GPIO] %s%d mode %d unsupported\n", gpio->port, gpio->pin, mode); break; @@ -28,7 +32,7 @@ void hal_gpio_init(GpioPin* gpio, GpioMode mode, GpioPull pull, GpioSpeed speed) } // write value to GPIO, false = LOW, true = HIGH -void hal_gpio_write(GpioPin* gpio, bool state){ +void hal_gpio_write(const GpioPin* gpio, const bool state) { if(gpio->pin != 0) { if(state) { printf("[GPIO] %s%d on\n", gpio->port, gpio->pin); @@ -41,7 +45,7 @@ void hal_gpio_write(GpioPin* gpio, bool state){ } // read value from GPIO, false = LOW, true = HIGH -bool hal_gpio_read(const GpioPin* gpio){ +bool hal_gpio_read(const GpioPin* gpio) { // TODO emulate pin state? return false; } diff --git a/firmware/targets/local/api-hal/api-hal-gpio.h b/firmware/targets/local/api-hal/api-hal-gpio.h index 75872856..10097b5a 100644 --- a/firmware/targets/local/api-hal/api-hal-gpio.h +++ b/firmware/targets/local/api-hal/api-hal-gpio.h @@ -40,10 +40,14 @@ typedef struct { } GpioPin; // init GPIO -void hal_gpio_init(GpioPin* gpio, GpioMode mode, GpioPull pull, GpioSpeed speed); +void hal_gpio_init( + const GpioPin* gpio, + const GpioMode mode, + const GpioPull pull, + const GpioSpeed speed); // write value to GPIO, false = LOW, true = HIGH -void hal_gpio_write(GpioPin* gpio, bool state); +void hal_gpio_write(const GpioPin* gpio, const bool state); // read value from GPIO, false = LOW, true = HIGH bool hal_gpio_read(const GpioPin* gpio); \ No newline at end of file diff --git a/lib/app-template/app-template.cpp b/lib/app-template/app-template.cpp index 39fe1a9b..cf614f7f 100644 --- a/lib/app-template/app-template.cpp +++ b/lib/app-template/app-template.cpp @@ -21,7 +21,7 @@ public: // state initializer AppExampleState() { - example_data = 12; + example_data = 0; } }; @@ -51,6 +51,16 @@ public: // start app void AppExample::run() { + // here we dont need to acquire or release state + // because before we call app_ready our application is "single threaded" + state.example_data = 12; + + // signal that we ready to render and ipc + app_ready(); + + // from here, any data that pass in render function must be guarded + // by calling acquire_state and release_state + AppExampleEvent event; while(1) { if(get_event(&event, 1000)) { diff --git a/lib/app-template/app-template.h b/lib/app-template/app-template.h index 36937b2d..570c9e53 100644 --- a/lib/app-template/app-template.h +++ b/lib/app-template/app-template.h @@ -6,20 +6,21 @@ // simple app class with template variables template class AppTemplate { public: - AppTemplate(); - ~AppTemplate(); - void input_callback(InputEvent* input_event, void* ctx); - void draw_callback(CanvasApi* canvas, void* ctx); - virtual void render(CanvasApi* canvas) = 0; Widget* widget; osMessageQueueId_t event_queue; TState state; ValueMutex state_mutex; GuiApi* gui; + AppTemplate(); + ~AppTemplate(); + void input_callback(InputEvent* input_event, void* ctx); + void draw_callback(CanvasApi* canvas, void* ctx); + virtual void render(CanvasApi* canvas) = 0; void acquire_state(void); void release_state(void); bool get_event(TEvent* event, uint32_t timeout); + void app_ready(void); void exit(void); void update_gui(void); }; @@ -35,24 +36,15 @@ template AppTemplate::AppTemplate() furiac_exit(NULL); } - // allocate widget - widget = widget_alloc(); - - // connect widget with input callback - auto input_cb_ref = cbc::obtain_connector(this, &AppTemplate::input_callback); - widget_input_callback_set(widget, input_cb_ref, this); - - // connect widget with draw callback - auto draw_cb_ref = cbc::obtain_connector(this, &AppTemplate::draw_callback); - widget_draw_callback_set(widget, draw_cb_ref, this); - - // open gui and add widget + // open gui gui = (GuiApi*)furi_open("gui"); if(gui == NULL) { printf("gui is not available\n"); furiac_exit(NULL); } - gui->add_widget(gui, widget, GuiLayerFullscreen); + + // allocate widget + widget = widget_alloc(); } template AppTemplate::~AppTemplate() { @@ -96,6 +88,24 @@ bool AppTemplate::get_event(TEvent* event, uint32_t timeout) { return (event_status == osOK); } +// signal that app is ready, and we can render something +// also unblock dependent tasks +template void AppTemplate::app_ready(void) { + // connect widget with input callback + auto input_cb_ref = cbc::obtain_connector(this, &AppTemplate::input_callback); + widget_input_callback_set(widget, input_cb_ref, this); + + // connect widget with draw callback + auto draw_cb_ref = cbc::obtain_connector(this, &AppTemplate::draw_callback); + widget_draw_callback_set(widget, draw_cb_ref, this); + + // add widget + gui->add_widget(gui, widget, GuiLayerFullscreen); + + // signal that our app ready to work + furiac_ready(); +} + template void AppTemplate::exit(void) { // TODO remove all widgets create by app widget_enabled_set(widget, false);