diff options
author | Vadim Kaushan <admin@disasm.info> | 2020-10-26 12:26:15 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-10-26 12:26:15 +0300 |
commit | bb68fca20b98eff37ed32001735d0a58c6a427d0 (patch) | |
tree | 3158471f0a6601cb65f1f9f51270ab8d93d5bf48 /applications | |
parent | 69d97afea8bbe2c2d6cc8f86399566a70c65c0ed (diff) |
Implement ValueManager and ValueComposer (#183)
* Fix ValueManager implementation
* Implement ValueComposer
* Add constructor for ValueManager
* Add value-expanders.h to flipper_v2.h set
* Move COPY_COMPOSE body into a .c file
* Add test for ValueManager
* Add destructors for ValueMutex, ValueManager and ValueComposer
* Use destructors in tests
* Move composition logic into perform_compose()
* Add docs for perform_compose()
* Add test for ValueComposer
* Replace atomic_bool with bool as g++ compiler doesn't support C11 atomics
* Add Event type
* Add semaphore support to the local target
* Add test for Event
* Update input records and relevant examples
* Rename Event to AppEvent in the cc1101-workaround example
* Rename Event to AppEvent in the irda example
* Use Event in ValueComposer to wait for update request
* Add perform_compose_internal() function
* fix Event/AppEvent
Co-authored-by: aanper <mail@s3f.ru>
Diffstat (limited to 'applications')
-rw-r--r-- | applications/applications.mk | 2 | ||||
-rw-r--r-- | applications/backlight-control/backlight-control.c | 8 | ||||
-rw-r--r-- | applications/cc1101-workaround/cc1101-workaround.cpp | 8 | ||||
-rw-r--r-- | applications/examples/fatfs_list.c | 12 | ||||
-rw-r--r-- | applications/examples/input_dump.c | 17 | ||||
-rw-r--r-- | applications/gui/gui_event.c | 11 | ||||
-rw-r--r-- | applications/input/input.c | 49 | ||||
-rw-r--r-- | applications/irda/irda.c | 22 | ||||
-rw-r--r-- | applications/tests/furi_event_test.c | 30 | ||||
-rw-r--r-- | applications/tests/furi_value_expanders_test.c | 145 | ||||
-rw-r--r-- | applications/tests/furi_valuemutex_test.c | 4 | ||||
-rw-r--r-- | applications/tests/minunit_test.c | 14 |
12 files changed, 259 insertions, 63 deletions
diff --git a/applications/applications.mk b/applications/applications.mk index f527dd89..2dd264cd 100644 --- a/applications/applications.mk +++ b/applications/applications.mk @@ -49,6 +49,8 @@ C_SOURCES += $(APP_DIR)/tests/minunit_test.c C_SOURCES += $(APP_DIR)/tests/furi_valuemutex_test.c C_SOURCES += $(APP_DIR)/tests/furi_pubsub_test.c C_SOURCES += $(APP_DIR)/tests/furi_memmgr_test.c +C_SOURCES += $(APP_DIR)/tests/furi_value_expanders_test.c +C_SOURCES += $(APP_DIR)/tests/furi_event_test.c endif APP_EXAMPLE_BLINK ?= 0 diff --git a/applications/backlight-control/backlight-control.c b/applications/backlight-control/backlight-control.c index ef22f3df..014f2f13 100644 --- a/applications/backlight-control/backlight-control.c +++ b/applications/backlight-control/backlight-control.c @@ -1,6 +1,6 @@ -#include "flipper.h" +#include "flipper_v2.h" -static void event_cb(const void* value, size_t size, void* ctx) { +static void event_cb(const void* value, void* ctx) { xSemaphoreGive((SemaphoreHandle_t*)ctx); } @@ -14,7 +14,9 @@ void backlight_control(void* p) { SemaphoreHandle_t update = xSemaphoreCreateCountingStatic(255, 0, &event_descriptor); // open record - furi_open_deprecated("input_events", false, false, event_cb, NULL, (void*)update); + PubSub* event_record = furi_open("input_events"); + assert(event_record != NULL); + subscribe_pubsub(event_record, event_cb, (void*)update); // we ready to work furiac_ready(); diff --git a/applications/cc1101-workaround/cc1101-workaround.cpp b/applications/cc1101-workaround/cc1101-workaround.cpp index ecac480a..34fb4814 100644 --- a/applications/cc1101-workaround/cc1101-workaround.cpp +++ b/applications/cc1101-workaround/cc1101-workaround.cpp @@ -115,7 +115,7 @@ typedef struct { InputEvent input; } value; EventType type; -} Event; +} AppEvent; typedef enum { ModeRx, ModeTx } Mode; @@ -195,14 +195,14 @@ static void render_callback(CanvasApi* canvas, void* ctx) { static void input_callback(InputEvent* input_event, void* ctx) { osMessageQueueId_t event_queue = (QueueHandle_t)ctx; - Event event; + AppEvent event; event.type = EventTypeKey; event.value.input = *input_event; osMessageQueuePut(event_queue, &event, 0, 0); } extern "C" void cc1101_workaround(void* p) { - osMessageQueueId_t event_queue = osMessageQueueNew(1, sizeof(Event), NULL); + osMessageQueueId_t event_queue = osMessageQueueNew(1, sizeof(AppEvent), NULL); assert(event_queue); State _state; @@ -266,7 +266,7 @@ extern "C" void cc1101_workaround(void* p) { const int16_t RSSI_THRESHOLD = -89; - Event event; + AppEvent event; while(1) { osStatus_t event_status = osMessageQueueGet(event_queue, &event, NULL, 150); State* state = (State*)acquire_mutex_block(&state_mutex); diff --git a/applications/examples/fatfs_list.c b/applications/examples/fatfs_list.c index 58e6730c..de24124c 100644 --- a/applications/examples/fatfs_list.c +++ b/applications/examples/fatfs_list.c @@ -1,6 +1,6 @@ #include "u8g2/u8g2.h" #include "fatfs/ff.h" -#include "flipper.h" +#include "flipper_v2.h" #include <stdio.h> // TODO currently we have small stack, so it will be static @@ -26,7 +26,7 @@ typedef struct { AppEventType type; } AppEvent; -static void event_cb(const void* value, size_t size, void* ctx) { +static void event_cb(const void* value, void* ctx) { QueueHandle_t event_queue = (QueueHandle_t)ctx; AppEvent event; @@ -56,9 +56,13 @@ void fatfs_list(void* p) { furiac_exit(NULL); } - FuriRecordSubscriber* event_record = - furi_open_deprecated("input_events", false, false, event_cb, NULL, event_queue); + PubSub* event_record = furi_open("input_events"); if(event_record == NULL) { + fuprintf(furi_log, "[widget][fatfs_list] cannot open input_events record\n"); + furiac_exit(NULL); + } + PubSubItem* subscription = subscribe_pubsub(event_record, event_cb, event_queue); + if(subscription == NULL) { fuprintf(furi_log, "[widget][fatfs_list] cannot register input_events callback\n"); furiac_exit(NULL); } diff --git a/applications/examples/input_dump.c b/applications/examples/input_dump.c index 9f8d3f67..1ab70c32 100644 --- a/applications/examples/input_dump.c +++ b/applications/examples/input_dump.c @@ -1,13 +1,13 @@ -#include "flipper.h" +#include "flipper_v2.h" #include <stdio.h> -static void state_cb(const void* value, size_t size, void* ctx) { +static void state_cb(const void* value, void* ctx) { const InputState* state = value; printf("state: %02x\n", *state); } -static void event_cb(const void* value, size_t size, void* ctx) { +static void event_cb(const void* value, void* ctx) { const InputEvent* event = value; printf("event: %02x %s\n", event->input, event->state ? "pressed" : "released"); @@ -15,10 +15,13 @@ static void event_cb(const void* value, size_t size, void* ctx) { void application_input_dump(void* p) { // open record - FuriRecordSubscriber* state_record = - furi_open_deprecated("input_state", false, false, state_cb, NULL, NULL); - FuriRecordSubscriber* event_record = - furi_open_deprecated("input_events", false, false, event_cb, NULL, NULL); + ValueManager* state_record = furi_open("input_state"); + assert(state_record != NULL); + subscribe_pubsub(&state_record->pubsub, state_cb, NULL); + + PubSub* event_record = furi_open("input_events"); + assert(event_record != NULL); + subscribe_pubsub(event_record, event_cb, NULL); for(;;) { delay(100); diff --git a/applications/gui/gui_event.c b/applications/gui/gui_event.c index 7c727206..b9dfffc9 100644 --- a/applications/gui/gui_event.c +++ b/applications/gui/gui_event.c @@ -1,17 +1,17 @@ #include "gui_event.h" -#include <flipper.h> +#include <flipper_v2.h> #include <assert.h> #define GUI_EVENT_MQUEUE_SIZE 8 struct GuiEvent { - FuriRecordSubscriber* input_event_record; + PubSub* input_event_record; osMessageQueueId_t mqueue; osMutexId_t lock_mutex; }; -void gui_event_input_events_callback(const void* value, size_t size, void* ctx) { +void gui_event_input_events_callback(const void* value, void* ctx) { assert(ctx); GuiEvent* gui_event = ctx; @@ -29,9 +29,10 @@ GuiEvent* gui_event_alloc() { assert(gui_event->mqueue); // Input - gui_event->input_event_record = furi_open_deprecated( - "input_events", false, false, gui_event_input_events_callback, NULL, gui_event); + gui_event->input_event_record = furi_open("input_events"); assert(gui_event->input_event_record != NULL); + subscribe_pubsub(gui_event->input_event_record, gui_event_input_events_callback, gui_event); + // Lock mutex gui_event->lock_mutex = osMutexNew(NULL); assert(gui_event->lock_mutex); diff --git a/applications/input/input.c b/applications/input/input.c index eec75eb1..612abcbc 100644 --- a/applications/input/input.c +++ b/applications/input/input.c @@ -1,46 +1,44 @@ #include <input/input.h> #include <input_priv.h> #include <stdio.h> -#include <flipper.h> +#include <flipper_v2.h> #ifdef APP_NFC void st25r3916Isr(void); #endif static volatile bool initialized = false; -static SemaphoreHandle_t event; +static ValueManager input_state_record; +static PubSub input_events_record; +static Event event; static InputState input_state = { false, }; void input_task(void* p) { uint32_t state_bits = 0; - StaticSemaphore_t event_semaphore; uint8_t debounce_counters[INPUT_COUNT]; - event = xSemaphoreCreateCountingStatic(1, 0, &event_semaphore); - - if(!furi_create_deprecated("input_state", (void*)&input_state, sizeof(input_state))) { - printf("[input_task] cannot create the input_state record\n"); + if(!init_managed(&input_state_record, &input_state, sizeof(input_state))) { + printf("[input_task] cannot initialize ValueManager for input_state\n"); furiac_exit(NULL); } - - FuriRecordSubscriber* input_state_record = - furi_open_deprecated("input_state", false, false, NULL, NULL, NULL); - if(input_state_record == NULL) { - printf("[input_task] cannot open the input_state record\n"); + if(!init_pubsub(&input_events_record)) { + printf("[input_task] cannot initialize PubSub for input_events\n"); + furiac_exit(NULL); + } + if(!init_event(&event)) { + printf("[input_task] cannot initialize Event\n"); furiac_exit(NULL); } - if(!furi_create_deprecated("input_events", NULL, 0)) { - printf("[input_task] cannot create the input_events record\n"); + if(!furi_create("input_state", &input_state_record)) { + printf("[input_task] cannot create the input_state record\n"); furiac_exit(NULL); } - FuriRecordSubscriber* input_events_record = - furi_open_deprecated("input_events", false, false, NULL, NULL, NULL); - if(input_events_record == NULL) { - printf("[input_task] cannot open the input_events record\n"); + if(!furi_create("input_events", &input_events_record)) { + printf("[input_task] cannot create the input_events record\n"); furiac_exit(NULL); } @@ -82,7 +80,7 @@ void input_task(void* p) { if(changed_bits != 0) { // printf("[input] %02x -> %02x\n", state_bits, new_state_bits); InputState new_state = _BITS2STATE(new_state_bits); - furi_write(input_state_record, &new_state, sizeof(new_state)); + write_managed(&input_state_record, &new_state, sizeof(new_state), osWaitForever); state_bits = new_state_bits; @@ -90,13 +88,13 @@ void input_task(void* p) { if((changed_bits & (1 << i)) != 0) { bool state = (new_state_bits & (1 << i)) != 0; InputEvent event = {i, state}; - furi_write(input_events_record, &event, sizeof(event)); + notify_pubsub(&input_events_record, &event); } } } // Sleep: wait for event - xSemaphoreTake(event, portMAX_DELAY); + wait_event(&event); } else { osDelay(1); } @@ -113,12 +111,5 @@ void HAL_GPIO_EXTI_Callback(uint16_t pin) { if(!initialized) return; - BaseType_t task_woken = pdFALSE; - - // Ignore the result, as we do not care about repeated event during event processing. - xSemaphoreGiveFromISR(event, &task_woken); - - if(task_woken) { - portYIELD_FROM_ISR(task_woken); - } + signal_event(&event); } diff --git a/applications/irda/irda.c b/applications/irda/irda.c index a6e79207..7e6c3ce8 100644 --- a/applications/irda/irda.c +++ b/applications/irda/irda.c @@ -14,7 +14,7 @@ typedef struct { InputEvent input; } value; EventType type; -} Event; +} AppEvent; typedef struct { uint8_t mode_id; @@ -24,15 +24,15 @@ typedef struct { uint8_t samsung_packet_id; } State; -typedef void (*ModeInput)(Event*, State*); +typedef void (*ModeInput)(AppEvent*, State*); typedef void (*ModeRender)(CanvasApi*, State*); -void input_carrier(Event* event, State* state); +void input_carrier(AppEvent* event, State* state); void render_carrier(CanvasApi* canvas, State* state); -void input_nec(Event* event, State* state); +void input_nec(AppEvent* event, State* state); void render_nec(CanvasApi* canvas, State* state); void render_carrier(CanvasApi* canvas, State* state); -void input_samsung(Event* event, State* state); +void input_samsung(AppEvent* event, State* state); void render_samsung(CanvasApi* canvas, State* state); typedef struct { @@ -120,7 +120,7 @@ void render_samsung(CanvasApi* canvas, State* state) { } } -void input_carrier(Event* event, State* state) { +void input_carrier(AppEvent* event, State* state) { if(event->value.input.input == InputOk) { if(event->value.input.state) { hal_pwm_set( @@ -151,7 +151,7 @@ void input_carrier(Event* event, State* state) { } } -void input_nec(Event* event, State* state) { +void input_nec(AppEvent* event, State* state) { uint8_t packets_count = sizeof(nec_packets) / sizeof(nec_packets[0]); if(event->value.input.input == InputOk) { @@ -180,7 +180,7 @@ void input_nec(Event* event, State* state) { } } -void input_samsung(Event* event, State* state) { +void input_samsung(AppEvent* event, State* state) { uint8_t packets_count = sizeof(samsung_packets) / sizeof(samsung_packets[0]); if(event->value.input.input == InputOk) { @@ -226,14 +226,14 @@ static void render_callback(CanvasApi* canvas, void* ctx) { static void input_callback(InputEvent* input_event, void* ctx) { osMessageQueueId_t event_queue = (QueueHandle_t)ctx; - Event event; + AppEvent event; event.type = EventTypeKey; event.value.input = *input_event; osMessageQueuePut(event_queue, &event, 0, 0); } void irda(void* p) { - osMessageQueueId_t event_queue = osMessageQueueNew(1, sizeof(Event), NULL); + osMessageQueueId_t event_queue = osMessageQueueNew(1, sizeof(AppEvent), NULL); State _state; uint8_t mode_count = sizeof(modes) / sizeof(modes[0]); @@ -264,7 +264,7 @@ void irda(void* p) { } gui->add_widget(gui, widget, WidgetLayerFullscreen); - Event event; + AppEvent event; while(1) { osStatus_t event_status = osMessageQueueGet(event_queue, &event, NULL, osWaitForever); State* state = (State*)acquire_mutex_block(&state_mutex); diff --git a/applications/tests/furi_event_test.c b/applications/tests/furi_event_test.c new file mode 100644 index 00000000..f6b9a5e0 --- /dev/null +++ b/applications/tests/furi_event_test.c @@ -0,0 +1,30 @@ +#include "flipper_v2.h" +#include "minunit.h" + +static void furi_concurent_app(void* p) { + Event* event = p; + + signal_event(event); + + furiac_exit(NULL); +} + +void test_furi_event() { + Event event; + + mu_check(init_event(&event)); + + // The event should not be signalled right after creation + mu_check(!wait_event_with_timeout(&event, 100)); + + // Create second app + FuriApp* second_app = furiac_start(furi_concurent_app, "furi concurent app", (void*)&event); + + // The event should be signalled now + mu_check(wait_event_with_timeout(&event, 100)); + + // The event should not be signalled once it's processed + mu_check(!wait_event_with_timeout(&event, 100)); + + mu_check(delete_event(&event)); +} diff --git a/applications/tests/furi_value_expanders_test.c b/applications/tests/furi_value_expanders_test.c new file mode 100644 index 00000000..8a795a4e --- /dev/null +++ b/applications/tests/furi_value_expanders_test.c @@ -0,0 +1,145 @@ +#include "flipper_v2.h" +#include "minunit.h" +#include <stdint.h> + +typedef struct { + uint8_t red; + uint8_t green; + uint8_t blue; +} Rgb; + +static uint32_t rgb_final_state; + +static void rgb_clear(void* ctx, void* state) { + Rgb* rgb = state; + rgb->red = 0; + rgb->green = 0; + rgb->blue = 0; +} + +static void rgb_commit(void* ctx, void* state) { + Rgb* rgb = state; + rgb_final_state = ((uint32_t)rgb->red) | (((uint32_t)rgb->green) << 8) | + (((uint32_t)rgb->blue) << 16); +} + +static void set_red_composer(void* ctx, void* state) { + Rgb* rgb = state; + uint8_t* red = ctx; + + rgb->red = *red; +} + +void test_furi_value_composer() { + Rgb rgb = {0, 0, 0}; + ValueComposer composer; + Rgb layer1_rgb = {0, 0, 0}; + ValueMutex layer1_mutex; + uint8_t layer2_red = 0; + + rgb_final_state = 0xdeadbeef; + + mu_check(init_composer(&composer, &rgb)); + + mu_check(init_mutex(&layer1_mutex, &layer1_rgb, sizeof(layer1_rgb))); + + perform_compose(&composer, rgb_clear, rgb_commit, NULL); + mu_assert_int_eq(0xdeadbeef, rgb_final_state); + + ValueComposerHandle* layer1_handle = + add_compose_layer(&composer, COPY_COMPOSE, &layer1_mutex, UiLayerNotify); + mu_assert_pointers_not_eq(layer1_handle, NULL); + + // RGB state should be updated with the layer1 state + perform_compose(&composer, rgb_clear, rgb_commit, NULL); + mu_assert_int_eq(0x000000, rgb_final_state); + + layer2_red = 0xcc; + ValueComposerHandle* layer2_handle = + add_compose_layer(&composer, set_red_composer, &layer2_red, UiLayerAboveNotify); + mu_assert_pointers_not_eq(layer2_handle, NULL); + + // RGB state should be updated with the layer1 and layer2 state, in order + perform_compose(&composer, rgb_clear, rgb_commit, NULL); + mu_assert_int_eq(0x0000cc, rgb_final_state); + + // Change layer1 state + Rgb* state = acquire_mutex(&layer1_mutex, 0); + mu_assert_pointers_not_eq(state, NULL); + state->red = 0x12; + state->green = 0x34; + state->blue = 0x56; + release_mutex(&layer1_mutex, state); + + // Nothing should happen, we need to trigger composition request first + perform_compose(&composer, rgb_clear, rgb_commit, NULL); + mu_assert_int_eq(0x0000cc, rgb_final_state); + + request_compose(layer1_handle); + + perform_compose(&composer, rgb_clear, rgb_commit, NULL); + mu_assert_int_eq(0x5634cc, rgb_final_state); + + // Change layer2 state + layer2_red = 0xff; + + // Nothing should happen, we need to trigger composition request first + perform_compose(&composer, rgb_clear, rgb_commit, NULL); + mu_assert_int_eq(0x5634cc, rgb_final_state); + + request_compose(layer2_handle); + + perform_compose(&composer, rgb_clear, rgb_commit, NULL); + mu_assert_int_eq(0x5634ff, rgb_final_state); + + // Remove layer1 + mu_check(remove_compose_layer(layer1_handle)); + + perform_compose(&composer, rgb_clear, rgb_commit, NULL); + mu_assert_int_eq(0x0000ff, rgb_final_state); + + // Remove layer2 + mu_check(remove_compose_layer(layer2_handle)); + + perform_compose(&composer, rgb_clear, rgb_commit, NULL); + mu_assert_int_eq(0x000000, rgb_final_state); + + mu_check(delete_composer(&composer)); +} + +static const uint32_t notify_value_0 = 0x12345678; +static const uint32_t notify_value_1 = 0x11223344; + +static uint32_t pubsub_value = 0; + +void test_value_manager_handler(void* arg, void* ctx) { + pubsub_value = *(uint32_t*)arg; +} + +void test_furi_value_manager() { + uint32_t value = 0; + ValueManager managed; + + mu_check(init_managed(&managed, &value, sizeof(value))); + + pubsub_value = 0; + + PubSubItem* test_pubsub_item; + test_pubsub_item = subscribe_pubsub(&managed.pubsub, test_value_manager_handler, 0); + mu_assert_pointers_not_eq(test_pubsub_item, NULL); + + mu_check(write_managed(&managed, (void*)¬ify_value_0, sizeof(notify_value_0), 100)); + + mu_assert_int_eq(pubsub_value, notify_value_0); + + uint32_t* ptr = acquire_mutex(&managed.value, 100); + mu_assert_pointers_not_eq(ptr, NULL); + + *ptr = notify_value_1; + + mu_check(commit_managed(&managed, ptr)); + + mu_assert_int_eq(pubsub_value, notify_value_1); + + mu_check(delete_managed(&managed)); +} diff --git a/applications/tests/furi_valuemutex_test.c b/applications/tests/furi_valuemutex_test.c index 6279d188..88bd6673 100644 --- a/applications/tests/furi_valuemutex_test.c +++ b/applications/tests/furi_valuemutex_test.c @@ -37,6 +37,8 @@ void test_furi_valuemutex() { //acquire mutex blocking case //write mutex blocking case //read mutex blocking case + + mu_check(delete_mutex(&valuemutex)); } /* @@ -119,4 +121,6 @@ void test_furi_concurrent_access() { mu_assert_pointers_eq(second_app->handler, NULL); mu_assert_int_eq(value.a, value.b); + + mu_check(delete_mutex(&mutex)); }
\ No newline at end of file diff --git a/applications/tests/minunit_test.c b/applications/tests/minunit_test.c index 472dfa7d..9d6a93f4 100644 --- a/applications/tests/minunit_test.c +++ b/applications/tests/minunit_test.c @@ -12,6 +12,9 @@ void test_furi_create_open(); void test_furi_valuemutex(); void test_furi_concurrent_access(); void test_furi_pubsub(); +void test_furi_value_composer(); +void test_furi_value_manager(); +void test_furi_event(); void test_furi_memmgr(); @@ -60,6 +63,15 @@ MU_TEST(mu_test_furi_memmgr) { test_furi_memmgr(); } +MU_TEST(mu_test_furi_value_expanders) { + test_furi_value_composer(); + test_furi_value_manager(); +} + +MU_TEST(mu_test_furi_event) { + test_furi_event(); +} + MU_TEST_SUITE(test_suite) { MU_SUITE_CONFIGURE(&test_setup, &test_teardown); @@ -72,6 +84,8 @@ MU_TEST_SUITE(test_suite) { MU_RUN_TEST(mu_test_furi_valuemutex); MU_RUN_TEST(mu_test_furi_concurrent_access); MU_RUN_TEST(mu_test_furi_pubsub); + MU_RUN_TEST(mu_test_furi_value_expanders); + MU_RUN_TEST(mu_test_furi_event); MU_RUN_TEST(mu_test_furi_memmgr); } |