[Fl-3147] Remove ValueMutex (#2467)
* Move keypad_test to furi_mutex * Move text_box_test to furi_mutex * Move snake_game to furi_mutex * Remove ValueMutex completely * Snake Game: simplify code and fix PVS warning * F18: sync API symbols Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									eefca9f498
								
							
						
					
					
						commit
						9819306731
					
				| @ -11,6 +11,7 @@ typedef struct { | |||||||
|     uint16_t left; |     uint16_t left; | ||||||
|     uint16_t right; |     uint16_t right; | ||||||
|     uint16_t ok; |     uint16_t ok; | ||||||
|  |     FuriMutex* mutex; | ||||||
| } KeypadTestState; | } KeypadTestState; | ||||||
| 
 | 
 | ||||||
| static void keypad_test_reset_state(KeypadTestState* state) { | static void keypad_test_reset_state(KeypadTestState* state) { | ||||||
| @ -22,7 +23,8 @@ static void keypad_test_reset_state(KeypadTestState* state) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void keypad_test_render_callback(Canvas* canvas, void* ctx) { | static void keypad_test_render_callback(Canvas* canvas, void* ctx) { | ||||||
|     KeypadTestState* state = (KeypadTestState*)acquire_mutex((ValueMutex*)ctx, 25); |     KeypadTestState* state = ctx; | ||||||
|  |     furi_mutex_acquire(state->mutex, FuriWaitForever); | ||||||
|     canvas_clear(canvas); |     canvas_clear(canvas); | ||||||
|     char strings[5][20]; |     char strings[5][20]; | ||||||
| 
 | 
 | ||||||
| @ -51,7 +53,7 @@ static void keypad_test_render_callback(Canvas* canvas, void* ctx) { | |||||||
| 
 | 
 | ||||||
|     canvas_draw_str(canvas, 10, 63, "[back] - reset, hold to exit"); |     canvas_draw_str(canvas, 10, 63, "[back] - reset, hold to exit"); | ||||||
| 
 | 
 | ||||||
|     release_mutex((ValueMutex*)ctx, state); |     furi_mutex_release(state->mutex); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void keypad_test_input_callback(InputEvent* input_event, void* ctx) { | static void keypad_test_input_callback(InputEvent* input_event, void* ctx) { | ||||||
| @ -64,17 +66,17 @@ int32_t keypad_test_app(void* p) { | |||||||
|     FuriMessageQueue* event_queue = furi_message_queue_alloc(32, sizeof(InputEvent)); |     FuriMessageQueue* event_queue = furi_message_queue_alloc(32, sizeof(InputEvent)); | ||||||
|     furi_check(event_queue); |     furi_check(event_queue); | ||||||
| 
 | 
 | ||||||
|     KeypadTestState _state = {{false, false, false, false, false}, 0, 0, 0, 0, 0}; |     KeypadTestState state = {{false, false, false, false, false}, 0, 0, 0, 0, 0, NULL}; | ||||||
|  |     state.mutex = furi_mutex_alloc(FuriMutexTypeNormal); | ||||||
| 
 | 
 | ||||||
|     ValueMutex state_mutex; |     if(!state.mutex) { | ||||||
|     if(!init_mutex(&state_mutex, &_state, sizeof(KeypadTestState))) { |  | ||||||
|         FURI_LOG_E(TAG, "cannot create mutex"); |         FURI_LOG_E(TAG, "cannot create mutex"); | ||||||
|         return 0; |         return 0; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     ViewPort* view_port = view_port_alloc(); |     ViewPort* view_port = view_port_alloc(); | ||||||
| 
 | 
 | ||||||
|     view_port_draw_callback_set(view_port, keypad_test_render_callback, &state_mutex); |     view_port_draw_callback_set(view_port, keypad_test_render_callback, &state); | ||||||
|     view_port_input_callback_set(view_port, keypad_test_input_callback, event_queue); |     view_port_input_callback_set(view_port, keypad_test_input_callback, event_queue); | ||||||
| 
 | 
 | ||||||
|     // Open GUI and register view_port
 |     // Open GUI and register view_port
 | ||||||
| @ -83,7 +85,7 @@ int32_t keypad_test_app(void* p) { | |||||||
| 
 | 
 | ||||||
|     InputEvent event; |     InputEvent event; | ||||||
|     while(furi_message_queue_get(event_queue, &event, FuriWaitForever) == FuriStatusOk) { |     while(furi_message_queue_get(event_queue, &event, FuriWaitForever) == FuriStatusOk) { | ||||||
|         KeypadTestState* state = (KeypadTestState*)acquire_mutex_block(&state_mutex); |         furi_mutex_acquire(state.mutex, FuriWaitForever); | ||||||
|         FURI_LOG_I( |         FURI_LOG_I( | ||||||
|             TAG, |             TAG, | ||||||
|             "key: %s type: %s", |             "key: %s type: %s", | ||||||
| @ -92,54 +94,54 @@ int32_t keypad_test_app(void* p) { | |||||||
| 
 | 
 | ||||||
|         if(event.key == InputKeyRight) { |         if(event.key == InputKeyRight) { | ||||||
|             if(event.type == InputTypePress) { |             if(event.type == InputTypePress) { | ||||||
|                 state->press[0] = true; |                 state.press[0] = true; | ||||||
|             } else if(event.type == InputTypeRelease) { |             } else if(event.type == InputTypeRelease) { | ||||||
|                 state->press[0] = false; |                 state.press[0] = false; | ||||||
|             } else if(event.type == InputTypeShort) { |             } else if(event.type == InputTypeShort) { | ||||||
|                 ++state->right; |                 ++state.right; | ||||||
|             } |             } | ||||||
|         } else if(event.key == InputKeyLeft) { |         } else if(event.key == InputKeyLeft) { | ||||||
|             if(event.type == InputTypePress) { |             if(event.type == InputTypePress) { | ||||||
|                 state->press[1] = true; |                 state.press[1] = true; | ||||||
|             } else if(event.type == InputTypeRelease) { |             } else if(event.type == InputTypeRelease) { | ||||||
|                 state->press[1] = false; |                 state.press[1] = false; | ||||||
|             } else if(event.type == InputTypeShort) { |             } else if(event.type == InputTypeShort) { | ||||||
|                 ++state->left; |                 ++state.left; | ||||||
|             } |             } | ||||||
|         } else if(event.key == InputKeyUp) { |         } else if(event.key == InputKeyUp) { | ||||||
|             if(event.type == InputTypePress) { |             if(event.type == InputTypePress) { | ||||||
|                 state->press[2] = true; |                 state.press[2] = true; | ||||||
|             } else if(event.type == InputTypeRelease) { |             } else if(event.type == InputTypeRelease) { | ||||||
|                 state->press[2] = false; |                 state.press[2] = false; | ||||||
|             } else if(event.type == InputTypeShort) { |             } else if(event.type == InputTypeShort) { | ||||||
|                 ++state->up; |                 ++state.up; | ||||||
|             } |             } | ||||||
|         } else if(event.key == InputKeyDown) { |         } else if(event.key == InputKeyDown) { | ||||||
|             if(event.type == InputTypePress) { |             if(event.type == InputTypePress) { | ||||||
|                 state->press[3] = true; |                 state.press[3] = true; | ||||||
|             } else if(event.type == InputTypeRelease) { |             } else if(event.type == InputTypeRelease) { | ||||||
|                 state->press[3] = false; |                 state.press[3] = false; | ||||||
|             } else if(event.type == InputTypeShort) { |             } else if(event.type == InputTypeShort) { | ||||||
|                 ++state->down; |                 ++state.down; | ||||||
|             } |             } | ||||||
|         } else if(event.key == InputKeyOk) { |         } else if(event.key == InputKeyOk) { | ||||||
|             if(event.type == InputTypePress) { |             if(event.type == InputTypePress) { | ||||||
|                 state->press[4] = true; |                 state.press[4] = true; | ||||||
|             } else if(event.type == InputTypeRelease) { |             } else if(event.type == InputTypeRelease) { | ||||||
|                 state->press[4] = false; |                 state.press[4] = false; | ||||||
|             } else if(event.type == InputTypeShort) { |             } else if(event.type == InputTypeShort) { | ||||||
|                 ++state->ok; |                 ++state.ok; | ||||||
|             } |             } | ||||||
|         } else if(event.key == InputKeyBack) { |         } else if(event.key == InputKeyBack) { | ||||||
|             if(event.type == InputTypeLong) { |             if(event.type == InputTypeLong) { | ||||||
|                 release_mutex(&state_mutex, state); |                 furi_mutex_release(state.mutex); | ||||||
|                 break; |                 break; | ||||||
|             } else if(event.type == InputTypeShort) { |             } else if(event.type == InputTypeShort) { | ||||||
|                 keypad_test_reset_state(state); |                 keypad_test_reset_state(&state); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         release_mutex(&state_mutex, state); |         furi_mutex_release(state.mutex); | ||||||
|         view_port_update(view_port); |         view_port_update(view_port); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -147,7 +149,7 @@ int32_t keypad_test_app(void* p) { | |||||||
|     gui_remove_view_port(gui, view_port); |     gui_remove_view_port(gui, view_port); | ||||||
|     view_port_free(view_port); |     view_port_free(view_port); | ||||||
|     furi_message_queue_free(event_queue); |     furi_message_queue_free(event_queue); | ||||||
|     delete_mutex(&state_mutex); |     furi_mutex_free(state.mutex); | ||||||
| 
 | 
 | ||||||
|     furi_record_close(RECORD_GUI); |     furi_record_close(RECORD_GUI); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -53,15 +53,17 @@ static void (*text_box_test_render[])(Canvas* canvas) = { | |||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     uint32_t idx; |     uint32_t idx; | ||||||
|  |     FuriMutex* mutex; | ||||||
| } TextBoxTestState; | } TextBoxTestState; | ||||||
| 
 | 
 | ||||||
| static void text_box_test_render_callback(Canvas* canvas, void* ctx) { | static void text_box_test_render_callback(Canvas* canvas, void* ctx) { | ||||||
|     TextBoxTestState* state = acquire_mutex((ValueMutex*)ctx, 25); |     TextBoxTestState* state = ctx; | ||||||
|  |     furi_mutex_acquire(state->mutex, FuriWaitForever); | ||||||
|     canvas_clear(canvas); |     canvas_clear(canvas); | ||||||
| 
 | 
 | ||||||
|     text_box_test_render[state->idx](canvas); |     text_box_test_render[state->idx](canvas); | ||||||
| 
 | 
 | ||||||
|     release_mutex((ValueMutex*)ctx, state); |     furi_mutex_release(state->mutex); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void text_box_test_input_callback(InputEvent* input_event, void* ctx) { | static void text_box_test_input_callback(InputEvent* input_event, void* ctx) { | ||||||
| @ -74,17 +76,17 @@ int32_t text_box_test_app(void* p) { | |||||||
|     FuriMessageQueue* event_queue = furi_message_queue_alloc(32, sizeof(InputEvent)); |     FuriMessageQueue* event_queue = furi_message_queue_alloc(32, sizeof(InputEvent)); | ||||||
|     furi_check(event_queue); |     furi_check(event_queue); | ||||||
| 
 | 
 | ||||||
|     TextBoxTestState _state = {.idx = 0}; |     TextBoxTestState state = {.idx = 0, .mutex = NULL}; | ||||||
|  |     state.mutex = furi_mutex_alloc(FuriMutexTypeNormal); | ||||||
| 
 | 
 | ||||||
|     ValueMutex state_mutex; |     if(!state.mutex) { | ||||||
|     if(!init_mutex(&state_mutex, &_state, sizeof(TextBoxTestState))) { |  | ||||||
|         FURI_LOG_E(TAG, "Cannot create mutex"); |         FURI_LOG_E(TAG, "Cannot create mutex"); | ||||||
|         return 0; |         return 0; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     ViewPort* view_port = view_port_alloc(); |     ViewPort* view_port = view_port_alloc(); | ||||||
| 
 | 
 | ||||||
|     view_port_draw_callback_set(view_port, text_box_test_render_callback, &state_mutex); |     view_port_draw_callback_set(view_port, text_box_test_render_callback, &state); | ||||||
|     view_port_input_callback_set(view_port, text_box_test_input_callback, event_queue); |     view_port_input_callback_set(view_port, text_box_test_input_callback, event_queue); | ||||||
| 
 | 
 | ||||||
|     // Open GUI and register view_port
 |     // Open GUI and register view_port
 | ||||||
| @ -94,24 +96,24 @@ int32_t text_box_test_app(void* p) { | |||||||
|     uint32_t test_renders_num = COUNT_OF(text_box_test_render); |     uint32_t test_renders_num = COUNT_OF(text_box_test_render); | ||||||
|     InputEvent event; |     InputEvent event; | ||||||
|     while(furi_message_queue_get(event_queue, &event, FuriWaitForever) == FuriStatusOk) { |     while(furi_message_queue_get(event_queue, &event, FuriWaitForever) == FuriStatusOk) { | ||||||
|         TextBoxTestState* state = acquire_mutex_block(&state_mutex); |         furi_mutex_acquire(state.mutex, FuriWaitForever); | ||||||
| 
 | 
 | ||||||
|         if(event.type == InputTypeShort) { |         if(event.type == InputTypeShort) { | ||||||
|             if(event.key == InputKeyRight) { |             if(event.key == InputKeyRight) { | ||||||
|                 if(state->idx < test_renders_num - 1) { |                 if(state.idx < test_renders_num - 1) { | ||||||
|                     state->idx++; |                     state.idx++; | ||||||
|                 } |                 } | ||||||
|             } else if(event.key == InputKeyLeft) { |             } else if(event.key == InputKeyLeft) { | ||||||
|                 if(state->idx > 0) { |                 if(state.idx > 0) { | ||||||
|                     state->idx--; |                     state.idx--; | ||||||
|                 } |                 } | ||||||
|             } else if(event.key == InputKeyBack) { |             } else if(event.key == InputKeyBack) { | ||||||
|                 release_mutex(&state_mutex, state); |                 furi_mutex_release(state.mutex); | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         release_mutex(&state_mutex, state); |         furi_mutex_release(state.mutex); | ||||||
|         view_port_update(view_port); |         view_port_update(view_port); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -119,7 +121,7 @@ int32_t text_box_test_app(void* p) { | |||||||
|     gui_remove_view_port(gui, view_port); |     gui_remove_view_port(gui, view_port); | ||||||
|     view_port_free(view_port); |     view_port_free(view_port); | ||||||
|     furi_message_queue_free(event_queue); |     furi_message_queue_free(event_queue); | ||||||
|     delete_mutex(&state_mutex); |     furi_mutex_free(state.mutex); | ||||||
| 
 | 
 | ||||||
|     furi_record_close(RECORD_GUI); |     furi_record_close(RECORD_GUI); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -5,7 +5,6 @@ | |||||||
| 
 | 
 | ||||||
| // v2 tests
 | // v2 tests
 | ||||||
| void test_furi_create_open(); | void test_furi_create_open(); | ||||||
| void test_furi_valuemutex(); |  | ||||||
| void test_furi_concurrent_access(); | void test_furi_concurrent_access(); | ||||||
| void test_furi_pubsub(); | void test_furi_pubsub(); | ||||||
| 
 | 
 | ||||||
| @ -30,10 +29,6 @@ MU_TEST(mu_test_furi_create_open) { | |||||||
|     test_furi_create_open(); |     test_furi_create_open(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| MU_TEST(mu_test_furi_valuemutex) { |  | ||||||
|     test_furi_valuemutex(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| MU_TEST(mu_test_furi_pubsub) { | MU_TEST(mu_test_furi_pubsub) { | ||||||
|     test_furi_pubsub(); |     test_furi_pubsub(); | ||||||
| } | } | ||||||
| @ -51,7 +46,6 @@ MU_TEST_SUITE(test_suite) { | |||||||
| 
 | 
 | ||||||
|     // v2 tests
 |     // v2 tests
 | ||||||
|     MU_RUN_TEST(mu_test_furi_create_open); |     MU_RUN_TEST(mu_test_furi_create_open); | ||||||
|     MU_RUN_TEST(mu_test_furi_valuemutex); |  | ||||||
|     MU_RUN_TEST(mu_test_furi_pubsub); |     MU_RUN_TEST(mu_test_furi_pubsub); | ||||||
|     MU_RUN_TEST(mu_test_furi_memmgr); |     MU_RUN_TEST(mu_test_furi_memmgr); | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,41 +0,0 @@ | |||||||
| #include <stdio.h> |  | ||||||
| #include <string.h> |  | ||||||
| #include <furi.h> |  | ||||||
| 
 |  | ||||||
| #include "../minunit.h" |  | ||||||
| 
 |  | ||||||
| void test_furi_valuemutex() { |  | ||||||
|     const int init_value = 0xdeadbeef; |  | ||||||
|     const int changed_value = 0x12345678; |  | ||||||
| 
 |  | ||||||
|     int value = init_value; |  | ||||||
|     bool result; |  | ||||||
|     ValueMutex valuemutex; |  | ||||||
| 
 |  | ||||||
|     // init mutex case
 |  | ||||||
|     result = init_mutex(&valuemutex, &value, sizeof(value)); |  | ||||||
|     mu_assert(result, "init mutex failed"); |  | ||||||
| 
 |  | ||||||
|     // acquire mutex case
 |  | ||||||
|     int* value_pointer = acquire_mutex(&valuemutex, 100); |  | ||||||
|     mu_assert_pointers_eq(value_pointer, &value); |  | ||||||
| 
 |  | ||||||
|     // second acquire mutex case
 |  | ||||||
|     int* value_pointer_second = acquire_mutex(&valuemutex, 100); |  | ||||||
|     mu_assert_pointers_eq(value_pointer_second, NULL); |  | ||||||
| 
 |  | ||||||
|     // change value case
 |  | ||||||
|     *value_pointer = changed_value; |  | ||||||
|     mu_assert_int_eq(value, changed_value); |  | ||||||
| 
 |  | ||||||
|     // release mutex case
 |  | ||||||
|     result = release_mutex(&valuemutex, &value); |  | ||||||
|     mu_assert(result, "release mutex failed"); |  | ||||||
| 
 |  | ||||||
|     // TODO
 |  | ||||||
|     //acquire mutex blocking case
 |  | ||||||
|     //write mutex blocking case
 |  | ||||||
|     //read mutex blocking case
 |  | ||||||
| 
 |  | ||||||
|     mu_check(delete_mutex(&valuemutex)); |  | ||||||
| } |  | ||||||
| @ -50,6 +50,7 @@ typedef struct { | |||||||
|     Direction nextMovement; // if backward of currentMovement, ignore
 |     Direction nextMovement; // if backward of currentMovement, ignore
 | ||||||
|     Point fruit; |     Point fruit; | ||||||
|     GameState state; |     GameState state; | ||||||
|  |     FuriMutex* mutex; | ||||||
| } SnakeState; | } SnakeState; | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
| @ -92,12 +93,10 @@ const NotificationSequence sequence_eat = { | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static void snake_game_render_callback(Canvas* const canvas, void* ctx) { | static void snake_game_render_callback(Canvas* const canvas, void* ctx) { | ||||||
|     const SnakeState* snake_state = acquire_mutex((ValueMutex*)ctx, 25); |     furi_assert(ctx); | ||||||
|     if(snake_state == NULL) { |     const SnakeState* snake_state = ctx; | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     // Before the function is called, the state is set with the canvas_reset(canvas)
 |     furi_mutex_acquire(snake_state->mutex, FuriWaitForever); | ||||||
| 
 | 
 | ||||||
|     // Frame
 |     // Frame
 | ||||||
|     canvas_draw_frame(canvas, 0, 0, 128, 64); |     canvas_draw_frame(canvas, 0, 0, 128, 64); | ||||||
| @ -134,7 +133,7 @@ static void snake_game_render_callback(Canvas* const canvas, void* ctx) { | |||||||
|         canvas_draw_str_aligned(canvas, 64, 41, AlignCenter, AlignBottom, buffer); |         canvas_draw_str_aligned(canvas, 64, 41, AlignCenter, AlignBottom, buffer); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     release_mutex((ValueMutex*)ctx, snake_state); |     furi_mutex_release(snake_state->mutex); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void snake_game_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { | static void snake_game_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { | ||||||
| @ -324,15 +323,16 @@ int32_t snake_game_app(void* p) { | |||||||
|     SnakeState* snake_state = malloc(sizeof(SnakeState)); |     SnakeState* snake_state = malloc(sizeof(SnakeState)); | ||||||
|     snake_game_init_game(snake_state); |     snake_game_init_game(snake_state); | ||||||
| 
 | 
 | ||||||
|     ValueMutex state_mutex; |     snake_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); | ||||||
|     if(!init_mutex(&state_mutex, snake_state, sizeof(SnakeState))) { | 
 | ||||||
|  |     if(!snake_state->mutex) { | ||||||
|         FURI_LOG_E("SnakeGame", "cannot create mutex\r\n"); |         FURI_LOG_E("SnakeGame", "cannot create mutex\r\n"); | ||||||
|         free(snake_state); |         free(snake_state); | ||||||
|         return 255; |         return 255; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     ViewPort* view_port = view_port_alloc(); |     ViewPort* view_port = view_port_alloc(); | ||||||
|     view_port_draw_callback_set(view_port, snake_game_render_callback, &state_mutex); |     view_port_draw_callback_set(view_port, snake_game_render_callback, snake_state); | ||||||
|     view_port_input_callback_set(view_port, snake_game_input_callback, event_queue); |     view_port_input_callback_set(view_port, snake_game_input_callback, event_queue); | ||||||
| 
 | 
 | ||||||
|     FuriTimer* timer = |     FuriTimer* timer = | ||||||
| @ -352,7 +352,7 @@ int32_t snake_game_app(void* p) { | |||||||
|     for(bool processing = true; processing;) { |     for(bool processing = true; processing;) { | ||||||
|         FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); |         FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); | ||||||
| 
 | 
 | ||||||
|         SnakeState* snake_state = (SnakeState*)acquire_mutex_block(&state_mutex); |         furi_mutex_acquire(snake_state->mutex, FuriWaitForever); | ||||||
| 
 | 
 | ||||||
|         if(event_status == FuriStatusOk) { |         if(event_status == FuriStatusOk) { | ||||||
|             // press events
 |             // press events
 | ||||||
| @ -391,7 +391,7 @@ int32_t snake_game_app(void* p) { | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         view_port_update(view_port); |         view_port_update(view_port); | ||||||
|         release_mutex(&state_mutex, snake_state); |         furi_mutex_release(snake_state->mutex); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Return backlight to normal state
 |     // Return backlight to normal state
 | ||||||
| @ -404,7 +404,7 @@ int32_t snake_game_app(void* p) { | |||||||
|     furi_record_close(RECORD_NOTIFICATION); |     furi_record_close(RECORD_NOTIFICATION); | ||||||
|     view_port_free(view_port); |     view_port_free(view_port); | ||||||
|     furi_message_queue_free(event_queue); |     furi_message_queue_free(event_queue); | ||||||
|     delete_mutex(&state_mutex); |     furi_mutex_free(snake_state->mutex); | ||||||
|     free(snake_state); |     free(snake_state); | ||||||
| 
 | 
 | ||||||
|     return 0; |     return 0; | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| entry,status,name,type,params | entry,status,name,type,params | ||||||
| Version,+,17.0,, | Version,+,18.0,, | ||||||
| Header,+,applications/services/bt/bt_service/bt.h,, | Header,+,applications/services/bt/bt_service/bt.h,, | ||||||
| Header,+,applications/services/cli/cli.h,, | Header,+,applications/services/cli/cli.h,, | ||||||
| Header,+,applications/services/cli/cli_vcp.h,, | Header,+,applications/services/cli/cli_vcp.h,, | ||||||
| @ -156,6 +156,7 @@ Header,+,lib/toolbox/manchester_decoder.h,, | |||||||
| Header,+,lib/toolbox/manchester_encoder.h,, | Header,+,lib/toolbox/manchester_encoder.h,, | ||||||
| Header,+,lib/toolbox/md5.h,, | Header,+,lib/toolbox/md5.h,, | ||||||
| Header,+,lib/toolbox/path.h,, | Header,+,lib/toolbox/path.h,, | ||||||
|  | Header,+,lib/toolbox/pretty_format.h,, | ||||||
| Header,+,lib/toolbox/protocols/protocol_dict.h,, | Header,+,lib/toolbox/protocols/protocol_dict.h,, | ||||||
| Header,+,lib/toolbox/random_name.h,, | Header,+,lib/toolbox/random_name.h,, | ||||||
| Header,+,lib/toolbox/saved_struct.h,, | Header,+,lib/toolbox/saved_struct.h,, | ||||||
| @ -439,7 +440,6 @@ Function,-,_wctomb_r,int,"_reent*, char*, wchar_t, _mbstate_t*" | |||||||
| Function,-,a64l,long,const char* | Function,-,a64l,long,const char* | ||||||
| Function,+,abort,void, | Function,+,abort,void, | ||||||
| Function,-,abs,int,int | Function,-,abs,int,int | ||||||
| Function,+,acquire_mutex,void*,"ValueMutex*, uint32_t" |  | ||||||
| Function,-,aligned_alloc,void*,"size_t, size_t" | Function,-,aligned_alloc,void*,"size_t, size_t" | ||||||
| Function,+,aligned_free,void,void* | Function,+,aligned_free,void,void* | ||||||
| Function,+,aligned_malloc,void*,"size_t, size_t" | Function,+,aligned_malloc,void*,"size_t, size_t" | ||||||
| @ -573,7 +573,6 @@ Function,-,ctermid,char*,char* | |||||||
| Function,-,ctime,char*,const time_t* | Function,-,ctime,char*,const time_t* | ||||||
| Function,-,ctime_r,char*,"const time_t*, char*" | Function,-,ctime_r,char*,"const time_t*, char*" | ||||||
| Function,-,cuserid,char*,char* | Function,-,cuserid,char*,char* | ||||||
| Function,+,delete_mutex,_Bool,ValueMutex* |  | ||||||
| Function,+,dialog_ex_alloc,DialogEx*, | Function,+,dialog_ex_alloc,DialogEx*, | ||||||
| Function,+,dialog_ex_disable_extended_events,void,DialogEx* | Function,+,dialog_ex_disable_extended_events,void,DialogEx* | ||||||
| Function,+,dialog_ex_enable_extended_events,void,DialogEx* | Function,+,dialog_ex_enable_extended_events,void,DialogEx* | ||||||
| @ -684,6 +683,7 @@ Function,+,file_browser_worker_set_folder_callback,void,"BrowserWorker*, Browser | |||||||
| Function,+,file_browser_worker_set_item_callback,void,"BrowserWorker*, BrowserWorkerListItemCallback" | Function,+,file_browser_worker_set_item_callback,void,"BrowserWorker*, BrowserWorkerListItemCallback" | ||||||
| Function,+,file_browser_worker_set_list_callback,void,"BrowserWorker*, BrowserWorkerListLoadCallback" | Function,+,file_browser_worker_set_list_callback,void,"BrowserWorker*, BrowserWorkerListLoadCallback" | ||||||
| Function,+,file_browser_worker_set_long_load_callback,void,"BrowserWorker*, BrowserWorkerLongLoadCallback" | Function,+,file_browser_worker_set_long_load_callback,void,"BrowserWorker*, BrowserWorkerLongLoadCallback" | ||||||
|  | Function,+,file_info_is_dir,_Bool,const FileInfo* | ||||||
| Function,+,file_stream_alloc,Stream*,Storage* | Function,+,file_stream_alloc,Stream*,Storage* | ||||||
| Function,+,file_stream_close,_Bool,Stream* | Function,+,file_stream_close,_Bool,Stream* | ||||||
| Function,+,file_stream_get_error,FS_Error,Stream* | Function,+,file_stream_get_error,FS_Error,Stream* | ||||||
| @ -707,6 +707,7 @@ Function,-,flipper_application_preload_status_to_string,const char*,FlipperAppli | |||||||
| Function,+,flipper_application_spawn,FuriThread*,"FlipperApplication*, void*" | Function,+,flipper_application_spawn,FuriThread*,"FlipperApplication*, void*" | ||||||
| Function,+,flipper_format_buffered_file_alloc,FlipperFormat*,Storage* | Function,+,flipper_format_buffered_file_alloc,FlipperFormat*,Storage* | ||||||
| Function,+,flipper_format_buffered_file_close,_Bool,FlipperFormat* | Function,+,flipper_format_buffered_file_close,_Bool,FlipperFormat* | ||||||
|  | Function,+,flipper_format_buffered_file_open_always,_Bool,"FlipperFormat*, const char*" | ||||||
| Function,+,flipper_format_buffered_file_open_existing,_Bool,"FlipperFormat*, const char*" | Function,+,flipper_format_buffered_file_open_existing,_Bool,"FlipperFormat*, const char*" | ||||||
| Function,+,flipper_format_delete_key,_Bool,"FlipperFormat*, const char*" | Function,+,flipper_format_delete_key,_Bool,"FlipperFormat*, const char*" | ||||||
| Function,+,flipper_format_file_alloc,FlipperFormat*,Storage* | Function,+,flipper_format_file_alloc,FlipperFormat*,Storage* | ||||||
| @ -1234,6 +1235,7 @@ Function,+,furi_thread_flags_get,uint32_t, | |||||||
| Function,+,furi_thread_flags_set,uint32_t,"FuriThreadId, uint32_t" | Function,+,furi_thread_flags_set,uint32_t,"FuriThreadId, uint32_t" | ||||||
| Function,+,furi_thread_flags_wait,uint32_t,"uint32_t, uint32_t, uint32_t" | Function,+,furi_thread_flags_wait,uint32_t,"uint32_t, uint32_t, uint32_t" | ||||||
| Function,+,furi_thread_free,void,FuriThread* | Function,+,furi_thread_free,void,FuriThread* | ||||||
|  | Function,+,furi_thread_get_appid,const char*,FuriThreadId | ||||||
| Function,+,furi_thread_get_current,FuriThread*, | Function,+,furi_thread_get_current,FuriThread*, | ||||||
| Function,+,furi_thread_get_current_id,FuriThreadId, | Function,+,furi_thread_get_current_id,FuriThreadId, | ||||||
| Function,+,furi_thread_get_current_priority,FuriThreadPriority, | Function,+,furi_thread_get_current_priority,FuriThreadPriority, | ||||||
| @ -1248,6 +1250,7 @@ Function,+,furi_thread_is_suspended,_Bool,FuriThreadId | |||||||
| Function,+,furi_thread_join,_Bool,FuriThread* | Function,+,furi_thread_join,_Bool,FuriThread* | ||||||
| Function,+,furi_thread_mark_as_service,void,FuriThread* | Function,+,furi_thread_mark_as_service,void,FuriThread* | ||||||
| Function,+,furi_thread_resume,void,FuriThreadId | Function,+,furi_thread_resume,void,FuriThreadId | ||||||
|  | Function,+,furi_thread_set_appid,void,"FuriThread*, const char*" | ||||||
| Function,+,furi_thread_set_callback,void,"FuriThread*, FuriThreadCallback" | Function,+,furi_thread_set_callback,void,"FuriThread*, FuriThreadCallback" | ||||||
| Function,+,furi_thread_set_context,void,"FuriThread*, void*" | Function,+,furi_thread_set_context,void,"FuriThread*, void*" | ||||||
| Function,+,furi_thread_set_current_priority,void,FuriThreadPriority | Function,+,furi_thread_set_current_priority,void,FuriThreadPriority | ||||||
| @ -1312,7 +1315,6 @@ Function,+,icon_get_data,const uint8_t*,const Icon* | |||||||
| Function,+,icon_get_height,uint8_t,const Icon* | Function,+,icon_get_height,uint8_t,const Icon* | ||||||
| Function,+,icon_get_width,uint8_t,const Icon* | Function,+,icon_get_width,uint8_t,const Icon* | ||||||
| Function,-,index,char*,"const char*, int" | Function,-,index,char*,"const char*, int" | ||||||
| Function,+,init_mutex,_Bool,"ValueMutex*, void*, size_t" |  | ||||||
| Function,-,initstate,char*,"unsigned, char*, size_t" | Function,-,initstate,char*,"unsigned, char*, size_t" | ||||||
| Function,+,input_get_key_name,const char*,InputKey | Function,+,input_get_key_name,const char*,InputKey | ||||||
| Function,+,input_get_type_name,const char*,InputType | Function,+,input_get_type_name,const char*,InputType | ||||||
| @ -1491,6 +1493,7 @@ Function,+,power_get_pubsub,FuriPubSub*,Power* | |||||||
| Function,+,power_is_battery_healthy,_Bool,Power* | Function,+,power_is_battery_healthy,_Bool,Power* | ||||||
| Function,+,power_off,void,Power* | Function,+,power_off,void,Power* | ||||||
| Function,+,power_reboot,void,PowerBootMode | Function,+,power_reboot,void,PowerBootMode | ||||||
|  | Function,+,pretty_format_bytes_hex_canonical,void,"FuriString*, size_t, const char*, const uint8_t*, size_t" | ||||||
| Function,-,printf,int,"const char*, ..." | Function,-,printf,int,"const char*, ..." | ||||||
| Function,+,property_value_out,void,"PropertyValueContext*, const char*, unsigned int, ..." | Function,+,property_value_out,void,"PropertyValueContext*, const char*, unsigned int, ..." | ||||||
| Function,+,protocol_dict_alloc,ProtocolDict*,"const ProtocolBase**, size_t" | Function,+,protocol_dict_alloc,ProtocolDict*,"const ProtocolBase**, size_t" | ||||||
| @ -1534,12 +1537,10 @@ Function,+,rand,int, | |||||||
| Function,-,rand_r,int,unsigned* | Function,-,rand_r,int,unsigned* | ||||||
| Function,+,random,long, | Function,+,random,long, | ||||||
| Function,-,rawmemchr,void*,"const void*, int" | Function,-,rawmemchr,void*,"const void*, int" | ||||||
| Function,-,read_mutex,_Bool,"ValueMutex*, void*, size_t, uint32_t" |  | ||||||
| Function,+,realloc,void*,"void*, size_t" | Function,+,realloc,void*,"void*, size_t" | ||||||
| Function,-,reallocarray,void*,"void*, size_t, size_t" | Function,-,reallocarray,void*,"void*, size_t, size_t" | ||||||
| Function,-,reallocf,void*,"void*, size_t" | Function,-,reallocf,void*,"void*, size_t" | ||||||
| Function,-,realpath,char*,"const char*, char*" | Function,-,realpath,char*,"const char*, char*" | ||||||
| Function,+,release_mutex,_Bool,"ValueMutex*, const void*" |  | ||||||
| Function,-,remove,int,const char* | Function,-,remove,int,const char* | ||||||
| Function,-,rename,int,"const char*, const char*" | Function,-,rename,int,"const char*, const char*" | ||||||
| Function,-,renameat,int,"int, const char*, int, const char*" | Function,-,renameat,int,"int, const char*, int, const char*" | ||||||
| @ -1617,14 +1618,18 @@ Function,-,srand48,void,long | |||||||
| Function,-,srandom,void,unsigned | Function,-,srandom,void,unsigned | ||||||
| Function,+,sscanf,int,"const char*, const char*, ..." | Function,+,sscanf,int,"const char*, const char*, ..." | ||||||
| Function,+,storage_common_copy,FS_Error,"Storage*, const char*, const char*" | Function,+,storage_common_copy,FS_Error,"Storage*, const char*, const char*" | ||||||
|  | Function,+,storage_common_exists,_Bool,"Storage*, const char*" | ||||||
| Function,+,storage_common_fs_info,FS_Error,"Storage*, const char*, uint64_t*, uint64_t*" | Function,+,storage_common_fs_info,FS_Error,"Storage*, const char*, uint64_t*, uint64_t*" | ||||||
| Function,+,storage_common_merge,FS_Error,"Storage*, const char*, const char*" | Function,+,storage_common_merge,FS_Error,"Storage*, const char*, const char*" | ||||||
|  | Function,+,storage_common_migrate,FS_Error,"Storage*, const char*, const char*" | ||||||
| Function,+,storage_common_mkdir,FS_Error,"Storage*, const char*" | Function,+,storage_common_mkdir,FS_Error,"Storage*, const char*" | ||||||
| Function,+,storage_common_remove,FS_Error,"Storage*, const char*" | Function,+,storage_common_remove,FS_Error,"Storage*, const char*" | ||||||
| Function,+,storage_common_rename,FS_Error,"Storage*, const char*, const char*" | Function,+,storage_common_rename,FS_Error,"Storage*, const char*, const char*" | ||||||
|  | Function,+,storage_common_resolve_path_and_ensure_app_directory,void,"Storage*, FuriString*" | ||||||
| Function,+,storage_common_stat,FS_Error,"Storage*, const char*, FileInfo*" | Function,+,storage_common_stat,FS_Error,"Storage*, const char*, FileInfo*" | ||||||
| Function,+,storage_common_timestamp,FS_Error,"Storage*, const char*, uint32_t*" | Function,+,storage_common_timestamp,FS_Error,"Storage*, const char*, uint32_t*" | ||||||
| Function,+,storage_dir_close,_Bool,File* | Function,+,storage_dir_close,_Bool,File* | ||||||
|  | Function,+,storage_dir_exists,_Bool,"Storage*, const char*" | ||||||
| Function,+,storage_dir_open,_Bool,"File*, const char*" | Function,+,storage_dir_open,_Bool,"File*, const char*" | ||||||
| Function,+,storage_dir_read,_Bool,"File*, FileInfo*, char*, uint16_t" | Function,+,storage_dir_read,_Bool,"File*, FileInfo*, char*, uint16_t" | ||||||
| Function,-,storage_dir_rewind,_Bool,File* | Function,-,storage_dir_rewind,_Bool,File* | ||||||
| @ -1995,7 +2000,6 @@ Function,+,widget_alloc,Widget*, | |||||||
| Function,+,widget_free,void,Widget* | Function,+,widget_free,void,Widget* | ||||||
| Function,+,widget_get_view,View*,Widget* | Function,+,widget_get_view,View*,Widget* | ||||||
| Function,+,widget_reset,void,Widget* | Function,+,widget_reset,void,Widget* | ||||||
| Function,-,write_mutex,_Bool,"ValueMutex*, void*, size_t, uint32_t" |  | ||||||
| Function,-,xPortGetFreeHeapSize,size_t, | Function,-,xPortGetFreeHeapSize,size_t, | ||||||
| Function,-,xPortGetMinimumEverFreeHeapSize,size_t, | Function,-,xPortGetMinimumEverFreeHeapSize,size_t, | ||||||
| Function,-,xPortStartScheduler,BaseType_t, | Function,-,xPortStartScheduler,BaseType_t, | ||||||
|  | |||||||
| 
 | 
| @ -1,5 +1,5 @@ | |||||||
| entry,status,name,type,params | entry,status,name,type,params | ||||||
| Version,+,17.0,, | Version,+,18.0,, | ||||||
| Header,+,applications/services/bt/bt_service/bt.h,, | Header,+,applications/services/bt/bt_service/bt.h,, | ||||||
| Header,+,applications/services/cli/cli.h,, | Header,+,applications/services/cli/cli.h,, | ||||||
| Header,+,applications/services/cli/cli_vcp.h,, | Header,+,applications/services/cli/cli_vcp.h,, | ||||||
| @ -491,7 +491,6 @@ Function,-,acosh,double,double | |||||||
| Function,-,acoshf,float,float | Function,-,acoshf,float,float | ||||||
| Function,-,acoshl,long double,long double | Function,-,acoshl,long double,long double | ||||||
| Function,-,acosl,long double,long double | Function,-,acosl,long double,long double | ||||||
| Function,+,acquire_mutex,void*,"ValueMutex*, uint32_t" |  | ||||||
| Function,-,aligned_alloc,void*,"size_t, size_t" | Function,-,aligned_alloc,void*,"size_t, size_t" | ||||||
| Function,+,aligned_free,void,void* | Function,+,aligned_free,void,void* | ||||||
| Function,+,aligned_malloc,void*,"size_t, size_t" | Function,+,aligned_malloc,void*,"size_t, size_t" | ||||||
| @ -703,7 +702,6 @@ Function,-,ctermid,char*,char* | |||||||
| Function,-,ctime,char*,const time_t* | Function,-,ctime,char*,const time_t* | ||||||
| Function,-,ctime_r,char*,"const time_t*, char*" | Function,-,ctime_r,char*,"const time_t*, char*" | ||||||
| Function,-,cuserid,char*,char* | Function,-,cuserid,char*,char* | ||||||
| Function,+,delete_mutex,_Bool,ValueMutex* |  | ||||||
| Function,+,dialog_ex_alloc,DialogEx*, | Function,+,dialog_ex_alloc,DialogEx*, | ||||||
| Function,+,dialog_ex_disable_extended_events,void,DialogEx* | Function,+,dialog_ex_disable_extended_events,void,DialogEx* | ||||||
| Function,+,dialog_ex_enable_extended_events,void,DialogEx* | Function,+,dialog_ex_enable_extended_events,void,DialogEx* | ||||||
| @ -1692,7 +1690,6 @@ Function,+,infrared_worker_tx_set_get_signal_callback,void,"InfraredWorker*, Inf | |||||||
| Function,+,infrared_worker_tx_set_signal_sent_callback,void,"InfraredWorker*, InfraredWorkerMessageSentCallback, void*" | Function,+,infrared_worker_tx_set_signal_sent_callback,void,"InfraredWorker*, InfraredWorkerMessageSentCallback, void*" | ||||||
| Function,+,infrared_worker_tx_start,void,InfraredWorker* | Function,+,infrared_worker_tx_start,void,InfraredWorker* | ||||||
| Function,+,infrared_worker_tx_stop,void,InfraredWorker* | Function,+,infrared_worker_tx_stop,void,InfraredWorker* | ||||||
| Function,+,init_mutex,_Bool,"ValueMutex*, void*, size_t" |  | ||||||
| Function,-,initstate,char*,"unsigned, char*, size_t" | Function,-,initstate,char*,"unsigned, char*, size_t" | ||||||
| Function,+,input_get_key_name,const char*,InputKey | Function,+,input_get_key_name,const char*,InputKey | ||||||
| Function,+,input_get_type_name,const char*,InputType | Function,+,input_get_type_name,const char*,InputType | ||||||
| @ -2164,12 +2161,10 @@ Function,+,rand,int, | |||||||
| Function,-,rand_r,int,unsigned* | Function,-,rand_r,int,unsigned* | ||||||
| Function,+,random,long, | Function,+,random,long, | ||||||
| Function,-,rawmemchr,void*,"const void*, int" | Function,-,rawmemchr,void*,"const void*, int" | ||||||
| Function,-,read_mutex,_Bool,"ValueMutex*, void*, size_t, uint32_t" |  | ||||||
| Function,+,realloc,void*,"void*, size_t" | Function,+,realloc,void*,"void*, size_t" | ||||||
| Function,-,reallocarray,void*,"void*, size_t, size_t" | Function,-,reallocarray,void*,"void*, size_t, size_t" | ||||||
| Function,-,reallocf,void*,"void*, size_t" | Function,-,reallocf,void*,"void*, size_t" | ||||||
| Function,-,realpath,char*,"const char*, char*" | Function,-,realpath,char*,"const char*, char*" | ||||||
| Function,+,release_mutex,_Bool,"ValueMutex*, const void*" |  | ||||||
| Function,-,remainder,double,"double, double" | Function,-,remainder,double,"double, double" | ||||||
| Function,-,remainderf,float,"float, float" | Function,-,remainderf,float,"float, float" | ||||||
| Function,-,remainderl,long double,"long double, long double" | Function,-,remainderl,long double,"long double, long double" | ||||||
| @ -2967,7 +2962,6 @@ Function,+,widget_alloc,Widget*, | |||||||
| Function,+,widget_free,void,Widget* | Function,+,widget_free,void,Widget* | ||||||
| Function,+,widget_get_view,View*,Widget* | Function,+,widget_get_view,View*,Widget* | ||||||
| Function,+,widget_reset,void,Widget* | Function,+,widget_reset,void,Widget* | ||||||
| Function,-,write_mutex,_Bool,"ValueMutex*, void*, size_t, uint32_t" |  | ||||||
| Function,-,xPortGetFreeHeapSize,size_t, | Function,-,xPortGetFreeHeapSize,size_t, | ||||||
| Function,-,xPortGetMinimumEverFreeHeapSize,size_t, | Function,-,xPortGetMinimumEverFreeHeapSize,size_t, | ||||||
| Function,-,xPortStartScheduler,BaseType_t, | Function,-,xPortStartScheduler,BaseType_t, | ||||||
|  | |||||||
| 
 | 
| @ -1,59 +0,0 @@ | |||||||
| #include "valuemutex.h" |  | ||||||
| 
 |  | ||||||
| #include <string.h> |  | ||||||
| 
 |  | ||||||
| bool init_mutex(ValueMutex* valuemutex, void* value, size_t size) { |  | ||||||
|     // mutex without name,
 |  | ||||||
|     // no attributes (unfortunately robust mutex is not supported by FreeRTOS),
 |  | ||||||
|     // with dynamic memory allocation
 |  | ||||||
|     valuemutex->mutex = furi_mutex_alloc(FuriMutexTypeNormal); |  | ||||||
|     if(valuemutex->mutex == NULL) return false; |  | ||||||
| 
 |  | ||||||
|     valuemutex->value = value; |  | ||||||
|     valuemutex->size = size; |  | ||||||
| 
 |  | ||||||
|     return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool delete_mutex(ValueMutex* valuemutex) { |  | ||||||
|     if(furi_mutex_acquire(valuemutex->mutex, FuriWaitForever) == FuriStatusOk) { |  | ||||||
|         furi_mutex_free(valuemutex->mutex); |  | ||||||
|         return true; |  | ||||||
|     } else { |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void* acquire_mutex(ValueMutex* valuemutex, uint32_t timeout) { |  | ||||||
|     if(furi_mutex_acquire(valuemutex->mutex, timeout) == FuriStatusOk) { |  | ||||||
|         return valuemutex->value; |  | ||||||
|     } else { |  | ||||||
|         return NULL; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool release_mutex(ValueMutex* valuemutex, const void* value) { |  | ||||||
|     if(value != valuemutex->value) return false; |  | ||||||
| 
 |  | ||||||
|     if(furi_mutex_release(valuemutex->mutex) != FuriStatusOk) return false; |  | ||||||
| 
 |  | ||||||
|     return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool read_mutex(ValueMutex* valuemutex, void* data, size_t len, uint32_t timeout) { |  | ||||||
|     void* value = acquire_mutex(valuemutex, timeout); |  | ||||||
|     if(value == NULL || len > valuemutex->size) return false; |  | ||||||
|     memcpy(data, value, len > 0 ? len : valuemutex->size); |  | ||||||
|     if(!release_mutex(valuemutex, value)) return false; |  | ||||||
| 
 |  | ||||||
|     return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool write_mutex(ValueMutex* valuemutex, void* data, size_t len, uint32_t timeout) { |  | ||||||
|     void* value = acquire_mutex(valuemutex, timeout); |  | ||||||
|     if(value == NULL || len > valuemutex->size) return false; |  | ||||||
|     memcpy(value, data, len > 0 ? len : valuemutex->size); |  | ||||||
|     if(!release_mutex(valuemutex, value)) return false; |  | ||||||
| 
 |  | ||||||
|     return true; |  | ||||||
| } |  | ||||||
| @ -1,149 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| 
 |  | ||||||
| #include <stdbool.h> |  | ||||||
| #include "mutex.h" |  | ||||||
| 
 |  | ||||||
| #ifdef __cplusplus |  | ||||||
| extern "C" { |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * == ValueMutex == |  | ||||||
| 
 |  | ||||||
|  * The most simple concept is ValueMutex. |  | ||||||
|  * It is wrapper around mutex and value pointer. |  | ||||||
|  * You can take and give mutex to work with value and read and write value. |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| typedef struct { |  | ||||||
|     void* value; |  | ||||||
|     size_t size; |  | ||||||
|     FuriMutex* mutex; |  | ||||||
| } ValueMutex; |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * Creates ValueMutex. |  | ||||||
|  */ |  | ||||||
| bool init_mutex(ValueMutex* valuemutex, void* value, size_t size); |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * Free resources allocated by `init_mutex`. |  | ||||||
|  * This function doesn't free the memory occupied by `ValueMutex` itself. |  | ||||||
|  */ |  | ||||||
| bool delete_mutex(ValueMutex* valuemutex); |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * Call for work with data stored in mutex. |  | ||||||
|  * @return pointer to data if success, NULL otherwise. |  | ||||||
|  */ |  | ||||||
| void* acquire_mutex(ValueMutex* valuemutex, uint32_t timeout); |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * Helper: infinitely wait for mutex |  | ||||||
|  */ |  | ||||||
| static inline void* acquire_mutex_block(ValueMutex* valuemutex) { |  | ||||||
|     return acquire_mutex(valuemutex, FuriWaitForever); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * With statement for value mutex, acts as lambda |  | ||||||
|  * @param name a resource name, const char* |  | ||||||
|  * @param function_body a (){} lambda declaration, |  | ||||||
|  * executed within you parent function context. |  | ||||||
|  */ |  | ||||||
| #define with_value_mutex(value_mutex, function_body) \ |  | ||||||
|     {                                                \ |  | ||||||
|         void* p = acquire_mutex_block(value_mutex);  \ |  | ||||||
|         furi_check(p);                               \ |  | ||||||
|         ({ void __fn__ function_body __fn__; })(p);  \ |  | ||||||
|         release_mutex(value_mutex, p);               \ |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * Release mutex after end of work with data. |  | ||||||
|  * Call `release_mutex` and pass ValueData instance and pointer to data. |  | ||||||
|  */ |  | ||||||
| bool release_mutex(ValueMutex* valuemutex, const void* value); |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * Instead of take-access-give sequence you can use `read_mutex` and `write_mutex` functions. |  | ||||||
|  * Both functions return true in case of success, false otherwise. |  | ||||||
|  */ |  | ||||||
| bool read_mutex(ValueMutex* valuemutex, void* data, size_t len, uint32_t timeout); |  | ||||||
| 
 |  | ||||||
| bool write_mutex(ValueMutex* valuemutex, void* data, size_t len, uint32_t timeout); |  | ||||||
| 
 |  | ||||||
| inline static bool write_mutex_block(ValueMutex* valuemutex, void* data, size_t len) { |  | ||||||
|     return write_mutex(valuemutex, data, len, FuriWaitForever); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| inline static bool read_mutex_block(ValueMutex* valuemutex, void* data, size_t len) { |  | ||||||
|     return read_mutex(valuemutex, data, len, FuriWaitForever); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #ifdef __cplusplus |  | ||||||
| } |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| /*
 |  | ||||||
| 
 |  | ||||||
| Usage example |  | ||||||
| 
 |  | ||||||
| ```C |  | ||||||
| // MANIFEST
 |  | ||||||
| // name="example-provider-app"
 |  | ||||||
| // stack=128
 |  | ||||||
| 
 |  | ||||||
| void provider_app(void* _p) { |  | ||||||
|     // create record with mutex
 |  | ||||||
|     uint32_t example_value = 0; |  | ||||||
|     ValueMutex example_mutex; |  | ||||||
|     // call `init_mutex`.
 |  | ||||||
|     if(!init_mutex(&example_mutex, (void*)&example_value, sizeof(uint32_t))) { |  | ||||||
|         printf("critical error\n"); |  | ||||||
|         flapp_exit(NULL); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     furi_record_create("provider/example", (void*)&example_mutex); |  | ||||||
| 
 |  | ||||||
|     // we are ready to provide record to other apps
 |  | ||||||
|     flapp_ready(); |  | ||||||
| 
 |  | ||||||
|     // get value and increment it
 |  | ||||||
|     while(1) { |  | ||||||
|         uint32_t* value = acquire_mutex(&example_mutex, OsWaitForever); |  | ||||||
|         if(value != NULL) { |  | ||||||
|             value++; |  | ||||||
|         } |  | ||||||
|         release_mutex(&example_mutex, value); |  | ||||||
| 
 |  | ||||||
|         furi_delay_ms(100); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // MANIFEST
 |  | ||||||
| // name="example-consumer-app"
 |  | ||||||
| // stack=128
 |  | ||||||
| // require="example-provider-app"
 |  | ||||||
| void consumer_app(void* _p) { |  | ||||||
|     // this app run after flapp_ready call in all requirements app
 |  | ||||||
| 
 |  | ||||||
|     // open mutex value
 |  | ||||||
|     ValueMutex* counter_mutex = furi_record_open("provider/example"); |  | ||||||
|     if(counter_mutex == NULL) { |  | ||||||
|         printf("critical error\n"); |  | ||||||
|         flapp_exit(NULL); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // continuously read value every 1s
 |  | ||||||
|     uint32_t counter; |  | ||||||
|     while(1) { |  | ||||||
|         if(read_mutex(counter_mutex, &counter, sizeof(counter), OsWaitForever)) { |  | ||||||
|             printf("counter value: %d\n", counter); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         furi_delay_ms(1000); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| ``` |  | ||||||
| */ |  | ||||||
| @ -16,7 +16,6 @@ | |||||||
| #include "core/semaphore.h" | #include "core/semaphore.h" | ||||||
| #include "core/thread.h" | #include "core/thread.h" | ||||||
| #include "core/timer.h" | #include "core/timer.h" | ||||||
| #include "core/valuemutex.h" |  | ||||||
| #include "core/string.h" | #include "core/string.h" | ||||||
| #include "core/stream_buffer.h" | #include "core/stream_buffer.h" | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Astra
						Astra