Просмотр исходного кода

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
DrZlo13 5 лет назад
Родитель
Сommit
a96f23af9b

+ 1 - 4
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);

+ 10 - 9
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);

+ 5 - 11
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() {

+ 3 - 3
applications/ibutton/ibutton.h

@@ -38,11 +38,11 @@ public:
 // with template variables <state, events>
 class AppiButton : public AppTemplate<AppiButtonState, AppiButtonEvent> {
 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<AppiButtonState, AppiButtonEvent>* mode[modes_count] = {NULL, NULL};
+    AppTemplateMode<AppiButtonState, AppiButtonEvent>* mode[modes_count];
 
     void run();
     void render(CanvasApi* canvas);

+ 5 - 4
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],

+ 5 - 4
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],

+ 3 - 3
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;
 }
 

+ 3 - 3
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;
 }
 

+ 1 - 4
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);

+ 2 - 0
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();

+ 2 - 0
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");

+ 1 - 1
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;

+ 1 - 1
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.

+ 7 - 3
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;
     }

+ 7 - 3
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);
 }
 

+ 5 - 1
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};
 

+ 6 - 2
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;

+ 4 - 1
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) {
     };
 }

+ 7 - 4
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);

+ 6 - 2
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;

+ 8 - 4
firmware/targets/local/api-hal/api-hal-gpio.c

@@ -2,7 +2,11 @@
 #include <stdio.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 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;
 }

+ 6 - 2
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);

+ 11 - 1
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)) {

+ 28 - 18
lib/app-template/app-template.h

@@ -6,20 +6,21 @@
 // simple app class with template variables <state, events>
 template <class TState, class TEvent> 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 <class TState, class TEvent> AppTemplate<TState, TEvent>::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 <class TState, class TEvent> AppTemplate<TState, TEvent>::~AppTemplate() {
@@ -96,6 +88,24 @@ bool AppTemplate<TState, TEvent>::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 <class TState, class TEvent> void AppTemplate<TState, TEvent>::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 <class TState, class TEvent> void AppTemplate<TState, TEvent>::exit(void) {
     // TODO remove all widgets create by app
     widget_enabled_set(widget, false);