diff --git a/applications/applications.c b/applications/applications.c index 7b125f6a107..8153dcfa61b 100644 --- a/applications/applications.c +++ b/applications/applications.c @@ -11,7 +11,6 @@ extern int32_t gui_srv(void* p); extern int32_t input_srv(void* p); extern int32_t loader_srv(void* p); extern int32_t notification_srv(void* p); -extern int32_t power_observer_srv(void* p); extern int32_t power_srv(void* p); extern int32_t storage_srv(void* p); extern int32_t desktop_srv(void* p); @@ -115,10 +114,6 @@ const FlipperApplication FLIPPER_SERVICES[] = { {.app = power_srv, .name = "PowerSrv", .stack_size = 1024, .icon = NULL}, #endif -#ifdef SRV_POWER_OBSERVER - {.app = power_observer_srv, .name = "PowerAuditSrv", .stack_size = 1024, .icon = NULL}, -#endif - #ifdef SRV_STORAGE {.app = storage_srv, .name = "StorageSrv", .stack_size = 3072, .icon = NULL}, #endif diff --git a/applications/applications.mk b/applications/applications.mk index aa17e05f366..5733e76165f 100644 --- a/applications/applications.mk +++ b/applications/applications.mk @@ -18,7 +18,6 @@ SRV_INPUT = 1 SRV_LOADER = 1 SRV_NOTIFICATION = 1 SRV_POWER = 1 -SRV_POWER_OBSERVER = 1 SRV_RPC = 1 SRV_STORAGE = 1 @@ -256,13 +255,6 @@ endif endif -SRV_POWER_OBSERVER ?= 0 -ifeq ($(SRV_POWER_OBSERVER), 1) -CFLAGS += -DSRV_POWER_OBSERVER -SRV_POWER = 1 -endif - - SRV_POWER ?= 0 ifeq ($(SRV_POWER), 1) CFLAGS += -DSRV_POWER diff --git a/applications/gui/elements.c b/applications/gui/elements.c index 2b874ec1c24..fe95102bc45 100644 --- a/applications/gui/elements.c +++ b/applications/gui/elements.c @@ -1,4 +1,5 @@ #include "elements.h" +#include "m-core.h" #include #include "furi_hal_resources.h" #include @@ -36,30 +37,15 @@ void elements_progress_bar( furi_assert(canvas); furi_assert(total > 0); uint8_t height = 9; - uint8_t marker_width = 7; - furi_assert(width > marker_width); - - uint8_t progress_length = ((float)progress / total) * (width - marker_width - 2); - - // rframe doesnt work if (radius * 2) > any rect side, so write manually - uint8_t x_max = x + width - 1; - uint8_t y_max = y + height - 1; - canvas_draw_line(canvas, x + 3, y, x_max - 3, y); - canvas_draw_line(canvas, x_max - 3, y, x_max, y + 3); - canvas_draw_line(canvas, x_max, y + 3, x_max, y_max - 3); - canvas_draw_line(canvas, x_max, y_max - 3, x_max - 3, y_max); - canvas_draw_line(canvas, x_max - 3, y_max, x + 3, y_max); - canvas_draw_line(canvas, x + 3, y_max, x, y_max - 3); - canvas_draw_line(canvas, x, y_max - 3, x, y + 3); - canvas_draw_line(canvas, x, y + 3, x + 3, y); - - canvas_draw_rbox(canvas, x + 1, y + 1, marker_width + progress_length, height - 2, 3); - canvas_invert_color(canvas); - canvas_draw_dot(canvas, x + progress_length + 3, y + 2); - canvas_draw_dot(canvas, x + progress_length + 4, y + 2); - canvas_draw_dot(canvas, x + progress_length + 5, y + 3); - canvas_draw_dot(canvas, x + progress_length + 6, y + 4); - canvas_invert_color(canvas); + + uint8_t progress_length = roundf(((float)progress / total) * (width - 2)); + + canvas_set_color(canvas, ColorWhite); + canvas_draw_box(canvas, x + 1, y + 1, width - 2, height - 2); + canvas_set_color(canvas, ColorBlack); + canvas_draw_rframe(canvas, x, y, width, height, 3); + + canvas_draw_box(canvas, x + 1, y + 1, progress_length, height - 2); } void elements_scrollbar_pos( @@ -202,6 +188,48 @@ void elements_button_center(Canvas* canvas, const char* str) { canvas_invert_color(canvas); } +static size_t + elements_get_max_chars_to_fit(Canvas* canvas, Align horizontal, const char* text, uint8_t x) { + const char* end = strchr(text, '\n'); + if(end == NULL) { + end = text + strlen(text); + } + size_t text_size = end - text; + string_t str; + string_init_set_str(str, text); + string_left(str, text_size); + size_t result = 0; + + uint16_t len_px = canvas_string_width(canvas, string_get_cstr(str)); + uint8_t px_left = 0; + if(horizontal == AlignCenter) { + px_left = canvas_width(canvas) - (x - len_px / 2); + } else if(horizontal == AlignLeft) { + px_left = canvas_width(canvas) - x; + } else if(horizontal == AlignRight) { + px_left = x; + } else { + furi_assert(0); + } + + if(len_px > px_left) { + uint8_t excess_symbols_approximately = + ((float)len_px - px_left) / ((float)len_px / text_size); + // reduce to 5 to be sure dash fit, and next line will be at least 5 symbols long + excess_symbols_approximately = MAX(excess_symbols_approximately, 5); + if(text_size > (excess_symbols_approximately + 5)) { + result = text_size - excess_symbols_approximately - 5; + } else { + result = text_size - 1; + } + } else { + result = text_size; + } + + string_clear(str); + return result; +} + void elements_multiline_text_aligned( Canvas* canvas, uint8_t x, @@ -212,64 +240,40 @@ void elements_multiline_text_aligned( furi_assert(canvas); furi_assert(text); + uint8_t lines_count = 0; uint8_t font_height = canvas_current_font_height(canvas); - string_t str; - string_init(str); - const char* start = text; - char* end; + string_t line; + + /* go through text line by line and count lines */ + for(const char* start = text; start[0];) { + size_t chars_fit = elements_get_max_chars_to_fit(canvas, horizontal, start, x); + ++lines_count; + start += chars_fit; + start += start[0] == '\n' ? 1 : 0; + } - // get lines count - uint8_t i, lines_count; - for(i = 0, lines_count = 0; text[i]; i++) lines_count += (text[i] == '\n'); - - switch(vertical) { - case AlignBottom: - y -= font_height * lines_count; - break; - case AlignCenter: - y -= (font_height * lines_count) / 2; - break; - case AlignTop: - default: - break; + if(vertical == AlignBottom) { + y -= font_height * (lines_count - 1); + } else if(vertical == AlignCenter) { + y -= (font_height * (lines_count - 1)) / 2; } - do { - end = strchr(start, '\n'); + /* go through text line by line and print them */ + for(const char* start = text; start[0];) { + size_t chars_fit = elements_get_max_chars_to_fit(canvas, horizontal, start, x); - if(end) { - string_set_strn(str, start, end - start); + if((start[chars_fit] == '\n') || (start[chars_fit] == 0)) { + string_init_printf(line, "%.*s", chars_fit, start); } else { - string_set_str(str, start); + string_init_printf(line, "%.*s-\n", chars_fit, start); } - - uint16_t len_px = canvas_string_width(canvas, string_get_cstr(str)); - uint8_t px_left = - canvas_width(canvas) - (x - (horizontal == AlignCenter ? len_px / 2 : 0)); - - // hacky - if(len_px > px_left) { - string_t buff; - string_init_set(buff, str); - size_t s_len = string_size(str); - uint8_t end_pos = s_len - ((len_px - px_left) / (len_px / s_len) + 5); - - string_left(buff, end_pos); - string_cat(buff, "-"); - string_right(str, end_pos); - - canvas_draw_str_aligned(canvas, x, y, horizontal, vertical, string_get_cstr(buff)); - string_clear(buff); - - start = end + 1; - y += font_height; - } - - canvas_draw_str_aligned(canvas, x, y, horizontal, vertical, string_get_cstr(str)); - start = end + 1; + canvas_draw_str_aligned(canvas, x, y, horizontal, vertical, string_get_cstr(line)); + string_clear(line); y += font_height; - } while(end); - string_clear(str); + + start += chars_fit; + start += start[0] == '\n' ? 1 : 0; + } } void elements_multiline_text(Canvas* canvas, uint8_t x, uint8_t y, const char* text) { diff --git a/applications/gui/modules/button_menu.c b/applications/gui/modules/button_menu.c index 605e73eb225..e8bbb6a18c3 100644 --- a/applications/gui/modules/button_menu.c +++ b/applications/gui/modules/button_menu.c @@ -99,8 +99,6 @@ static void button_menu_view_draw_callback(Canvas* canvas, void* _model) { furi_assert(_model); ButtonMenuModel* model = (ButtonMenuModel*)_model; - - canvas_clear(canvas); canvas_set_font(canvas, FontSecondary); uint8_t item_position = 0; @@ -117,11 +115,14 @@ static void button_menu_view_draw_callback(Canvas* canvas, void* _model) { canvas_draw_icon(canvas, 28, 123, &I_IrdaArrowDown_4x8); } - string_t disp_str; - string_init_set_str(disp_str, model->header); - elements_string_fit_width(canvas, disp_str, ITEM_WIDTH - 6); - canvas_draw_str_aligned(canvas, 32, 10, AlignCenter, AlignCenter, string_get_cstr(disp_str)); - string_clear(disp_str); + if(model->header) { + string_t disp_str; + string_init_set_str(disp_str, model->header); + elements_string_fit_width(canvas, disp_str, ITEM_WIDTH - 6); + canvas_draw_str_aligned( + canvas, 32, 10, AlignCenter, AlignCenter, string_get_cstr(disp_str)); + string_clear(disp_str); + } for(ButtonMenuItemArray_it(it, model->items); !ButtonMenuItemArray_end_p(it); ButtonMenuItemArray_next(it), ++item_position) { @@ -248,6 +249,7 @@ void button_menu_reset(ButtonMenu* button_menu) { button_menu->view, (ButtonMenuModel * model) { ButtonMenuItemArray_reset(model->items); model->position = 0; + model->header = NULL; return true; }); } diff --git a/applications/input/input.c b/applications/input/input.c index 85f985bed72..55a10113dae 100644 --- a/applications/input/input.c +++ b/applications/input/input.c @@ -40,91 +40,6 @@ void input_isr(void* _ctx) { osThreadFlagsSet(input->thread, INPUT_THREAD_FLAG_ISR); } -#ifdef SRV_CLI -void input_cli_send(Cli* cli, string_t args, void* context) { - InputEvent event; - - // Get first word as key name - string_t key_name; - string_init(key_name); - size_t ws = string_search_char(args, ' '); - if(ws == STRING_FAILURE) { - printf("Invalid arguments. Use `input_send KEY TYPE`."); - string_clear(key_name); - return; - } else { - string_set_n(key_name, args, 0, ws); - string_right(args, ws); - string_strim(args); - } - // Check key name and set event key - if(!string_cmp(key_name, "up")) { - event.key = InputKeyUp; - } else if(!string_cmp(key_name, "down")) { - event.key = InputKeyDown; - } else if(!string_cmp(key_name, "left")) { - event.key = InputKeyLeft; - } else if(!string_cmp(key_name, "right")) { - event.key = InputKeyRight; - } else if(!string_cmp(key_name, "ok")) { - event.key = InputKeyOk; - } else if(!string_cmp(key_name, "back")) { - event.key = InputKeyBack; - } else { - printf("Invalid key name. Valid keys: `up`, `down`, `left`, `right`, `back`, `ok`."); - string_clear(key_name); - return; - } - string_clear(key_name); - // Check the rest of args string and set event type - if(!string_cmp(args, "press")) { - event.type = InputTypePress; - } else if(!string_cmp(args, "release")) { - event.type = InputTypeRelease; - } else if(!string_cmp(args, "short")) { - event.type = InputTypeShort; - } else if(!string_cmp(args, "long")) { - event.type = InputTypeLong; - } else { - printf("Ivalid type. Valid types: `press`, `release`, `short`, `long`."); - return; - } - // Publish input event - furi_pubsub_publish(input->event_pubsub, &event); -} - -static void input_cli_dump_events_callback(const void* value, void* ctx) { - furi_assert(value); - furi_assert(ctx); - osMessageQueueId_t input_queue = ctx; - osMessageQueuePut(input_queue, value, 0, osWaitForever); -} - -static void input_cli_dump(Cli* cli, string_t args, void* context) { - osMessageQueueId_t input_queue = osMessageQueueNew(8, sizeof(InputEvent), NULL); - FuriPubSubSubscription* input_subscription = - furi_pubsub_subscribe(input->event_pubsub, input_cli_dump_events_callback, input_queue); - - bool stop = false; - InputEvent input_event; - while(!stop) { - if(osMessageQueueGet(input_queue, &input_event, NULL, 100) == osOK) { - printf( - "key: %s type: %s\r\n", - input_get_key_name(input_event.key), - input_get_type_name(input_event.type)); - } - - if(cli_cmd_interrupt_received(cli)) { - stop = true; - } - } - - furi_pubsub_unsubscribe(input->event_pubsub, input_subscription); - osMessageQueueDelete(input_queue); -} -#endif - const char* input_get_key_name(InputKey key) { for(size_t i = 0; i < input_pins_count; i++) { if(input_pins[i].key == key) { @@ -159,10 +74,7 @@ int32_t input_srv() { #ifdef SRV_CLI input->cli = furi_record_open("cli"); if(input->cli) { - cli_add_command( - input->cli, "input_send", CliCommandFlagParallelSafe, input_cli_send, NULL); - cli_add_command( - input->cli, "input_dump", CliCommandFlagParallelSafe, input_cli_dump, NULL); + cli_add_command(input->cli, "input", CliCommandFlagParallelSafe, input_cli, input); } #endif diff --git a/applications/input/input_cli.c b/applications/input/input_cli.c new file mode 100644 index 00000000000..c244ece5ec5 --- /dev/null +++ b/applications/input/input_cli.c @@ -0,0 +1,127 @@ +#include "input_i.h" + +#include +#include +#include + +static void input_cli_usage() { + printf("Usage:\r\n"); + printf("input \r\n"); + printf("Cmd list:\r\n"); + printf("\tdump\t\t\t - dump input events\r\n"); + printf("\tsend \t - send input event\r\n"); +} + +static void input_cli_dump_events_callback(const void* value, void* ctx) { + furi_assert(value); + furi_assert(ctx); + osMessageQueueId_t input_queue = ctx; + osMessageQueuePut(input_queue, value, 0, osWaitForever); +} + +static void input_cli_dump(Cli* cli, string_t args, Input* input) { + osMessageQueueId_t input_queue = osMessageQueueNew(8, sizeof(InputEvent), NULL); + FuriPubSubSubscription* input_subscription = + furi_pubsub_subscribe(input->event_pubsub, input_cli_dump_events_callback, input_queue); + + bool stop = false; + InputEvent input_event; + while(!stop) { + if(osMessageQueueGet(input_queue, &input_event, NULL, 100) == osOK) { + printf( + "key: %s type: %s\r\n", + input_get_key_name(input_event.key), + input_get_type_name(input_event.type)); + } + + if(cli_cmd_interrupt_received(cli)) { + stop = true; + } + } + + furi_pubsub_unsubscribe(input->event_pubsub, input_subscription); + osMessageQueueDelete(input_queue); +} + +static void input_cli_send_print_usage() { + printf("Invalid arguments. Usage:\r\n"); + printf("\tinput send \r\n"); + printf("\t\t \t - one of 'up', 'down', 'left', 'right', 'back', 'ok'\r\n"); + printf("\t\t \t - one of 'press', 'release', 'short', 'long'\r\n"); +} + +void input_cli_send(Cli* cli, string_t args, Input* input) { + InputEvent event; + string_t key_str; + string_init(key_str); + bool parsed = false; + + do { + // Parse Key + if(!args_read_string_and_trim(args, key_str)) { + break; + } + if(!string_cmp(key_str, "up")) { + event.key = InputKeyUp; + } else if(!string_cmp(key_str, "down")) { + event.key = InputKeyDown; + } else if(!string_cmp(key_str, "left")) { + event.key = InputKeyLeft; + } else if(!string_cmp(key_str, "right")) { + event.key = InputKeyRight; + } else if(!string_cmp(key_str, "ok")) { + event.key = InputKeyOk; + } else if(!string_cmp(key_str, "back")) { + event.key = InputKeyBack; + } else { + break; + } + // Parse Type + if(!string_cmp(args, "press")) { + event.type = InputTypePress; + } else if(!string_cmp(args, "release")) { + event.type = InputTypeRelease; + } else if(!string_cmp(args, "short")) { + event.type = InputTypeShort; + } else if(!string_cmp(args, "long")) { + event.type = InputTypeLong; + } else { + break; + } + parsed = true; + } while(false); + + if(parsed) { + furi_pubsub_publish(input->event_pubsub, &event); + } else { + input_cli_send_print_usage(); + } + string_clear(key_str); +} + +void input_cli(Cli* cli, string_t args, void* context) { + furi_assert(cli); + furi_assert(context); + Input* input = context; + string_t cmd; + string_init(cmd); + + do { + if(!args_read_string_and_trim(args, cmd)) { + input_cli_usage(); + break; + } + if(string_cmp_str(cmd, "dump") == 0) { + input_cli_dump(cli, args, input); + break; + } + if(string_cmp_str(cmd, "send") == 0) { + input_cli_send(cli, args, input); + break; + } + + input_cli_usage(); + } while(false); + + string_clear(cmd); +} diff --git a/applications/input/input_i.h b/applications/input/input_i.h index 78c3116561d..4bd777ef348 100644 --- a/applications/input/input_i.h +++ b/applications/input/input_i.h @@ -44,3 +44,6 @@ void input_press_timer_callback(void* arg); /** Input interrupt handler */ void input_isr(void* _ctx); + +/** Input CLI command handler */ +void input_cli(Cli* cli, string_t args, void* context); diff --git a/applications/irda/cli/irda_cli.cpp b/applications/irda/cli/irda_cli.cpp index cdb44e8be8b..3a4121df8ed 100644 --- a/applications/irda/cli/irda_cli.cpp +++ b/applications/irda/cli/irda_cli.cpp @@ -13,6 +13,17 @@ #include #include "../helpers/irda_parser.h" +static void irda_cli_start_ir_rx(Cli* cli, string_t args); +static void irda_cli_start_ir_tx(Cli* cli, string_t args); + +static const struct { + const char* cmd; + void (*process_function)(Cli* cli, string_t args); +} irda_cli_commands[] = { + {.cmd = "rx", .process_function = irda_cli_start_ir_rx}, + {.cmd = "tx", .process_function = irda_cli_start_ir_tx}, +}; + static void signal_received_callback(void* context, IrdaWorkerSignal* received_signal) { furi_assert(received_signal); char buf[100]; @@ -48,12 +59,7 @@ static void signal_received_callback(void* context, IrdaWorkerSignal* received_s } } -void irda_cli_start_ir_rx(Cli* cli, string_t args, void* context) { - if(furi_hal_irda_is_busy()) { - printf("IRDA is busy. Exit."); - return; - } - +static void irda_cli_start_ir_rx(Cli* cli, string_t args) { IrdaWorker* worker = irda_worker_alloc(); irda_worker_rx_start(worker); irda_worker_rx_set_received_signal_callback(worker, signal_received_callback, cli); @@ -68,7 +74,9 @@ void irda_cli_start_ir_rx(Cli* cli, string_t args, void* context) { } static void irda_cli_print_usage(void) { - printf("Usage:\r\n\tir_tx
\r\n"); + printf("Usage:\r\n"); + printf("\tir rx\r\n"); + printf("\tir tx
\r\n"); printf("\t and
are hex-formatted\r\n"); printf("\tAvailable protocols:"); for(int i = 0; irda_is_protocol_valid((IrdaProtocol)i); ++i) { @@ -131,12 +139,7 @@ static bool parse_signal_raw( return irda_parser_is_raw_signal_valid(*frequency, *duty_cycle, *timings_cnt); } -void irda_cli_start_ir_tx(Cli* cli, string_t args, void* context) { - if(furi_hal_irda_is_busy()) { - printf("IRDA is busy. Exit."); - return; - } - +static void irda_cli_start_ir_tx(Cli* cli, string_t args) { IrdaMessage message; const char* str = string_get_cstr(args); uint32_t frequency; @@ -156,11 +159,38 @@ void irda_cli_start_ir_tx(Cli* cli, string_t args, void* context) { free(timings); } +static void irda_cli_start_ir(Cli* cli, string_t args, void* context) { + if(furi_hal_irda_is_busy()) { + printf("IRDA is busy. Exit."); + return; + } + + size_t i = 0; + for(; i < COUNT_OF(irda_cli_commands); ++i) { + size_t size = strlen(irda_cli_commands[i].cmd); + bool cmd_found = !strncmp(string_get_cstr(args), irda_cli_commands[i].cmd, size); + if(cmd_found) { + if(string_size(args) == size) { + break; + } + if(string_get_cstr(args)[size] == ' ') { + string_right(args, size); + break; + } + } + } + + if(i < COUNT_OF(irda_cli_commands)) { + irda_cli_commands[i].process_function(cli, args); + } else { + irda_cli_print_usage(); + } +} + extern "C" void irda_on_system_start() { #ifdef SRV_CLI Cli* cli = (Cli*)furi_record_open("cli"); - cli_add_command(cli, "ir_rx", CliCommandFlagDefault, irda_cli_start_ir_rx, NULL); - cli_add_command(cli, "ir_tx", CliCommandFlagDefault, irda_cli_start_ir_tx, NULL); + cli_add_command(cli, "ir", CliCommandFlagDefault, irda_cli_start_ir, NULL); furi_record_close("cli"); #endif } diff --git a/applications/irda/helpers/irda_parser.cpp b/applications/irda/helpers/irda_parser.cpp index 3bfa485054f..be0b17aa33a 100644 --- a/applications/irda/helpers/irda_parser.cpp +++ b/applications/irda/helpers/irda_parser.cpp @@ -96,26 +96,30 @@ bool irda_parser_is_parsed_signal_valid(const IrdaMessage* signal) { result = false; } - uint32_t address_length = irda_get_protocol_address_length(signal->protocol); - uint32_t address_mask = (1LU << address_length) - 1; - if(signal->address != (signal->address & address_mask)) { - FURI_LOG_E( - TAG, - "Address is out of range (mask 0x%08lX): 0x%lX\r\n", - address_mask, - signal->address); - result = false; + if(result) { + uint32_t address_length = irda_get_protocol_address_length(signal->protocol); + uint32_t address_mask = (1LU << address_length) - 1; + if(signal->address != (signal->address & address_mask)) { + FURI_LOG_E( + TAG, + "Address is out of range (mask 0x%08lX): 0x%lX\r\n", + address_mask, + signal->address); + result = false; + } } - uint32_t command_length = irda_get_protocol_command_length(signal->protocol); - uint32_t command_mask = (1LU << command_length) - 1; - if(signal->command != (signal->command & command_mask)) { - FURI_LOG_E( - TAG, - "Command is out of range (mask 0x%08lX): 0x%lX\r\n", - command_mask, - signal->command); - result = false; + if(result) { + uint32_t command_length = irda_get_protocol_command_length(signal->protocol); + uint32_t command_mask = (1LU << command_length) - 1; + if(signal->command != (signal->command & command_mask)) { + FURI_LOG_E( + TAG, + "Command is out of range (mask 0x%08lX): 0x%lX\r\n", + command_mask, + signal->command); + result = false; + } } return result; diff --git a/applications/irda/irda_app.h b/applications/irda/irda_app.h index 5d660824a8e..e8de29bb3b4 100644 --- a/applications/irda/irda_app.h +++ b/applications/irda/irda_app.h @@ -33,6 +33,7 @@ class IrdaApp { LearnSuccess, LearnEnterName, LearnDone, + AskBack, Remote, RemoteList, Edit, @@ -123,6 +124,7 @@ class IrdaApp { {Scene::LearnSuccess, new IrdaAppSceneLearnSuccess()}, {Scene::LearnEnterName, new IrdaAppSceneLearnEnterName()}, {Scene::LearnDone, new IrdaAppSceneLearnDone()}, + {Scene::AskBack, new IrdaAppSceneAskBack()}, {Scene::Remote, new IrdaAppSceneRemote()}, {Scene::RemoteList, new IrdaAppSceneRemoteList()}, {Scene::Edit, new IrdaAppSceneEdit()}, diff --git a/applications/irda/irda_app_remote_manager.cpp b/applications/irda/irda_app_remote_manager.cpp index d7c331348e5..8b88d37dac1 100644 --- a/applications/irda/irda_app_remote_manager.cpp +++ b/applications/irda/irda_app_remote_manager.cpp @@ -110,10 +110,11 @@ std::string IrdaAppRemoteManager::get_button_name(uint32_t index) { } std::string IrdaAppRemoteManager::get_remote_name() { - return remote ? remote->name : std::string(); + return remote.get() ? remote->name : std::string(); } int IrdaAppRemoteManager::find_remote_name(const std::vector& strings) { + furi_assert(remote.get() != nullptr); int i = 0; for(const auto& str : strings) { if(!str.compare(remote->name)) { diff --git a/applications/irda/irda_app_signal.cpp b/applications/irda/irda_app_signal.cpp index 3c6ea8cfcc3..7e40a041ade 100644 --- a/applications/irda/irda_app_signal.cpp +++ b/applications/irda/irda_app_signal.cpp @@ -70,8 +70,6 @@ IrdaAppSignal::IrdaAppSignal(const IrdaAppSignal& other) { } IrdaAppSignal::IrdaAppSignal(IrdaAppSignal&& other) { - clear_timings(); - raw_signal = other.raw_signal; if(!raw_signal) { payload.message = other.payload.message; diff --git a/applications/irda/scene/irda_app_scene.h b/applications/irda/scene/irda_app_scene.h index 9de48e18e89..f687d405f14 100644 --- a/applications/irda/scene/irda_app_scene.h +++ b/applications/irda/scene/irda_app_scene.h @@ -89,6 +89,13 @@ class IrdaAppSceneRemoteList : public IrdaAppScene { std::vector remote_names; }; +class IrdaAppSceneAskBack : public IrdaAppScene { +public: + void on_enter(IrdaApp* app) final; + bool on_event(IrdaApp* app, IrdaAppEvent* event) final; + void on_exit(IrdaApp* app) final; +}; + class IrdaAppSceneEdit : public IrdaAppScene { public: void on_enter(IrdaApp* app) final; diff --git a/applications/irda/scene/irda_app_scene_ask_back.cpp b/applications/irda/scene/irda_app_scene_ask_back.cpp new file mode 100644 index 00000000000..34c8b61f6e9 --- /dev/null +++ b/applications/irda/scene/irda_app_scene_ask_back.cpp @@ -0,0 +1,71 @@ +#include "../irda_app.h" +#include "gui/modules/dialog_ex.h" +#include "irda.h" +#include "irda/scene/irda_app_scene.h" +#include + +static void dialog_result_callback(DialogExResult result, void* context) { + auto app = static_cast(context); + IrdaAppEvent event; + + event.type = IrdaAppEvent::Type::DialogExSelected; + event.payload.dialog_ex_result = result; + + app->get_view_manager()->send_event(&event); +} + +void IrdaAppSceneAskBack::on_enter(IrdaApp* app) { + IrdaAppViewManager* view_manager = app->get_view_manager(); + DialogEx* dialog_ex = view_manager->get_dialog_ex(); + + if(app->get_learn_new_remote()) { + dialog_ex_set_header(dialog_ex, "Exit to Infrared menu?", 64, 0, AlignCenter, AlignTop); + } else { + dialog_ex_set_header(dialog_ex, "Exit to remote menu?", 64, 0, AlignCenter, AlignTop); + } + + dialog_ex_set_text( + dialog_ex, "All unsaved data\nwill be lost", 64, 31, AlignCenter, AlignCenter); + dialog_ex_set_icon(dialog_ex, 0, 0, NULL); + dialog_ex_set_left_button_text(dialog_ex, "Exit"); + dialog_ex_set_center_button_text(dialog_ex, nullptr); + dialog_ex_set_right_button_text(dialog_ex, "Stay"); + dialog_ex_set_result_callback(dialog_ex, dialog_result_callback); + dialog_ex_set_context(dialog_ex, app); + + view_manager->switch_to(IrdaAppViewManager::ViewType::DialogEx); +} + +bool IrdaAppSceneAskBack::on_event(IrdaApp* app, IrdaAppEvent* event) { + bool consumed = false; + + if(event->type == IrdaAppEvent::Type::DialogExSelected) { + switch(event->payload.dialog_ex_result) { + case DialogExResultLeft: + consumed = true; + if(app->get_learn_new_remote()) { + app->search_and_switch_to_previous_scene({IrdaApp::Scene::Start}); + } else { + app->search_and_switch_to_previous_scene( + {IrdaApp::Scene::Edit, IrdaApp::Scene::Remote}); + } + break; + case DialogExResultCenter: + furi_assert(0); + break; + case DialogExResultRight: + app->switch_to_previous_scene(); + consumed = true; + break; + } + } + + if(event->type == IrdaAppEvent::Type::Back) { + consumed = true; + } + + return consumed; +} + +void IrdaAppSceneAskBack::on_exit(IrdaApp* app) { +} diff --git a/applications/irda/scene/irda_app_scene_edit_delete.cpp b/applications/irda/scene/irda_app_scene_edit_delete.cpp index 511ffd4b260..36dcbd017f5 100644 --- a/applications/irda/scene/irda_app_scene_edit_delete.cpp +++ b/applications/irda/scene/irda_app_scene_edit_delete.cpp @@ -21,7 +21,7 @@ void IrdaAppSceneEditDelete::on_enter(IrdaApp* app) { if(app->get_edit_element() == IrdaApp::EditElement::Button) { auto signal = remote_manager->get_button_data(app->get_current_button()); - dialog_ex_set_header(dialog_ex, "Delete button?", 64, 6, AlignCenter, AlignCenter); + dialog_ex_set_header(dialog_ex, "Delete button?", 64, 0, AlignCenter, AlignTop); if(!signal.is_raw()) { auto message = &signal.get_message(); app->set_text_store( @@ -41,7 +41,7 @@ void IrdaAppSceneEditDelete::on_enter(IrdaApp* app) { signal.get_raw_signal().timings_cnt); } } else { - dialog_ex_set_header(dialog_ex, "Delete remote?", 64, 6, AlignCenter, AlignCenter); + dialog_ex_set_header(dialog_ex, "Delete remote?", 64, 0, AlignCenter, AlignTop); app->set_text_store( 0, "%s\n with %lu buttons", @@ -49,7 +49,7 @@ void IrdaAppSceneEditDelete::on_enter(IrdaApp* app) { remote_manager->get_number_of_buttons()); } - dialog_ex_set_text(dialog_ex, app->get_text_store(0), 64, 32, AlignCenter, AlignCenter); + dialog_ex_set_text(dialog_ex, app->get_text_store(0), 64, 31, AlignCenter, AlignCenter); dialog_ex_set_icon(dialog_ex, 0, 0, NULL); dialog_ex_set_left_button_text(dialog_ex, "Back"); dialog_ex_set_right_button_text(dialog_ex, "Delete"); diff --git a/applications/irda/scene/irda_app_scene_edit_delete_done.cpp b/applications/irda/scene/irda_app_scene_edit_delete_done.cpp index 4b8172060e2..e429e72d642 100644 --- a/applications/irda/scene/irda_app_scene_edit_delete_done.cpp +++ b/applications/irda/scene/irda_app_scene_edit_delete_done.cpp @@ -5,7 +5,7 @@ void IrdaAppSceneEditDeleteDone::on_enter(IrdaApp* app) { Popup* popup = view_manager->get_popup(); popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62); - popup_set_text(popup, "Deleted", 83, 19, AlignLeft, AlignBottom); + popup_set_header(popup, "Deleted", 83, 19, AlignLeft, AlignBottom); popup_set_callback(popup, IrdaApp::popup_callback); popup_set_context(popup, app); @@ -32,4 +32,7 @@ bool IrdaAppSceneEditDeleteDone::on_event(IrdaApp* app, IrdaAppEvent* event) { } void IrdaAppSceneEditDeleteDone::on_exit(IrdaApp* app) { + IrdaAppViewManager* view_manager = app->get_view_manager(); + Popup* popup = view_manager->get_popup(); + popup_set_header(popup, nullptr, 0, 0, AlignLeft, AlignTop); } diff --git a/applications/irda/scene/irda_app_scene_edit_rename.cpp b/applications/irda/scene/irda_app_scene_edit_rename.cpp index db6b8e4defa..28c13456878 100644 --- a/applications/irda/scene/irda_app_scene_edit_rename.cpp +++ b/applications/irda/scene/irda_app_scene_edit_rename.cpp @@ -32,7 +32,7 @@ void IrdaAppSceneEditRename::on_enter(IrdaApp* app) { app, app->get_text_store(0), enter_name_length, - true); + false); view_manager->switch_to(IrdaAppViewManager::ViewType::TextInput); } diff --git a/applications/irda/scene/irda_app_scene_edit_rename_done.cpp b/applications/irda/scene/irda_app_scene_edit_rename_done.cpp index 230d613ef2e..181b9670b24 100644 --- a/applications/irda/scene/irda_app_scene_edit_rename_done.cpp +++ b/applications/irda/scene/irda_app_scene_edit_rename_done.cpp @@ -6,7 +6,7 @@ void IrdaAppSceneEditRenameDone::on_enter(IrdaApp* app) { popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); - popup_set_text(popup, "Saved!", 13, 22, AlignLeft, AlignTop); + popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop); popup_set_callback(popup, IrdaApp::popup_callback); popup_set_context(popup, app); diff --git a/applications/irda/scene/irda_app_scene_learn.cpp b/applications/irda/scene/irda_app_scene_learn.cpp index 10cc4f33f2b..7075f0f8637 100644 --- a/applications/irda/scene/irda_app_scene_learn.cpp +++ b/applications/irda/scene/irda_app_scene_learn.cpp @@ -69,4 +69,7 @@ bool IrdaAppSceneLearn::on_event(IrdaApp* app, IrdaAppEvent* event) { void IrdaAppSceneLearn::on_exit(IrdaApp* app) { irda_worker_rx_stop(app->get_irda_worker()); + auto view_manager = app->get_view_manager(); + auto popup = view_manager->get_popup(); + popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignCenter); } diff --git a/applications/irda/scene/irda_app_scene_learn_done.cpp b/applications/irda/scene/irda_app_scene_learn_done.cpp index c659b5ce950..f2669baad79 100644 --- a/applications/irda/scene/irda_app_scene_learn_done.cpp +++ b/applications/irda/scene/irda_app_scene_learn_done.cpp @@ -9,9 +9,9 @@ void IrdaAppSceneLearnDone::on_enter(IrdaApp* app) { DOLPHIN_DEED(DolphinDeedIrSave); if(app->get_learn_new_remote()) { - popup_set_text(popup, "New remote\ncreated!", 5, 7, AlignLeft, AlignTop); + popup_set_header(popup, "New remote\ncreated!", 0, 0, AlignLeft, AlignTop); } else { - popup_set_text(popup, "Saved!", 5, 7, AlignLeft, AlignTop); + popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop); } popup_set_callback(popup, IrdaApp::popup_callback); @@ -35,4 +35,7 @@ bool IrdaAppSceneLearnDone::on_event(IrdaApp* app, IrdaAppEvent* event) { void IrdaAppSceneLearnDone::on_exit(IrdaApp* app) { app->set_learn_new_remote(false); + IrdaAppViewManager* view_manager = app->get_view_manager(); + Popup* popup = view_manager->get_popup(); + popup_set_header(popup, nullptr, 0, 0, AlignLeft, AlignTop); } diff --git a/applications/irda/scene/irda_app_scene_learn_success.cpp b/applications/irda/scene/irda_app_scene_learn_success.cpp index d7bd85d2405..3ca828d24fa 100644 --- a/applications/irda/scene/irda_app_scene_learn_success.cpp +++ b/applications/irda/scene/irda_app_scene_learn_success.cpp @@ -91,12 +91,17 @@ bool IrdaAppSceneLearnSuccess::on_event(IrdaApp* app, IrdaAppEvent* event) { } } + if(event->type == IrdaAppEvent::Type::Back) { + app->switch_to_next_scene(IrdaApp::Scene::AskBack); + consumed = true; + } + return consumed; } void IrdaAppSceneLearnSuccess::on_exit(IrdaApp* app) { IrdaAppViewManager* view_manager = app->get_view_manager(); DialogEx* dialog_ex = view_manager->get_dialog_ex(); - dialog_ex_set_center_button_text(dialog_ex, nullptr); + dialog_ex_reset(dialog_ex); app->notify_green_off(); } diff --git a/applications/irda/scene/irda_app_scene_remote_list.cpp b/applications/irda/scene/irda_app_scene_remote_list.cpp index 9532f912812..c20fbafbbcf 100644 --- a/applications/irda/scene/irda_app_scene_remote_list.cpp +++ b/applications/irda/scene/irda_app_scene_remote_list.cpp @@ -15,6 +15,11 @@ void IrdaAppSceneRemoteList::on_enter(IrdaApp* app) { last_selected_remote.size() ? last_selected_remote.c_str() : nullptr; auto filename_ts = std::make_unique(IrdaAppRemoteManager::max_remote_name_length); + IrdaAppViewManager* view_manager = app->get_view_manager(); + ButtonMenu* button_menu = view_manager->get_button_menu(); + button_menu_reset(button_menu); + view_manager->switch_to(IrdaAppViewManager::ViewType::ButtonMenu); + file_select_result = file_worker.file_select( IrdaApp::irda_directory, IrdaApp::irda_extension, diff --git a/applications/irda/view/irda_app_brut_view.c b/applications/irda/view/irda_app_brut_view.c index 330ff04faba..4b2db6421ec 100644 --- a/applications/irda/view/irda_app_brut_view.c +++ b/applications/irda/view/irda_app_brut_view.c @@ -52,7 +52,7 @@ void popup_brut_draw_callback(Canvas* canvas, void* context) { canvas_draw_line(canvas, x_max - 1, y_max - 2, x_max - 3, y_max - 2); elements_progress_bar( - canvas, x + 4, y + 19, x_max - 8, popup_brut->progress, popup_brut->progress_max); + canvas, x + 4, y + 19, x_max - 7, popup_brut->progress, popup_brut->progress_max); canvas_set_font(canvas, FontSecondary); canvas_draw_str(canvas, x + 15, y + 12, "Sending ..."); diff --git a/applications/nfc/nfc_cli.c b/applications/nfc/nfc_cli.c index 94367fcd198..a2f816e4c7f 100755 --- a/applications/nfc/nfc_cli.c +++ b/applications/nfc/nfc_cli.c @@ -1,21 +1,22 @@ -#include "nfc_cli.h" -#include "nfc_types.h" #include #include +#include +#include -void nfc_on_system_start() { -#ifdef SRV_CLI - Cli* cli = furi_record_open("cli"); - cli_add_command(cli, "nfc_detect", CliCommandFlagDefault, nfc_cli_detect, NULL); - cli_add_command(cli, "nfc_emulate", CliCommandFlagDefault, nfc_cli_emulate, NULL); - furi_record_close("cli"); -#endif +#include "nfc_types.h" + +static void nfc_cli_print_usage() { + printf("Usage:\r\n"); + printf("nfc \r\n"); + printf("Cmd list:\r\n"); + printf("\tdetect\t - detect nfc device\r\n"); + printf("\temulate\t - emulate predefined nfca card\r\n"); } -void nfc_cli_detect(Cli* cli, string_t args, void* context) { +void nfc_cli_detect(Cli* cli, string_t args) { // Check if nfc worker is not busy if(furi_hal_nfc_is_busy()) { - printf("Nfc is busy"); + printf("Nfc is busy\r\n"); return; } rfalNfcDevice* dev_list; @@ -45,15 +46,15 @@ void nfc_cli_detect(Cli* cli, string_t args, void* context) { furi_hal_nfc_deactivate(); } -void nfc_cli_emulate(Cli* cli, string_t args, void* context) { +void nfc_cli_emulate(Cli* cli, string_t args) { // Check if nfc worker is not busy if(furi_hal_nfc_is_busy()) { - printf("Nfc is busy"); + printf("Nfc is busy\r\n"); return; } furi_hal_nfc_exit_sleep(); - printf("Emulating NFC-A Type: T2T UID: CF72D440 SAK: 20 ATQA: 00/04\r\n"); + printf("Emulating NFC-A Type: T2T UID: 36 9C E7 B1 0A C1 34 SAK: 00 ATQA: 00/44\r\n"); printf("Press Ctrl+C to abort\r\n"); NfcDeviceCommonData params = { @@ -74,3 +75,35 @@ void nfc_cli_emulate(Cli* cli, string_t args, void* context) { } furi_hal_nfc_deactivate(); } + +static void nfc_cli(Cli* cli, string_t args, void* context) { + string_t cmd; + string_init(cmd); + + do { + if(!args_read_string_and_trim(args, cmd)) { + nfc_cli_print_usage(); + break; + } + if(string_cmp_str(cmd, "detect") == 0) { + nfc_cli_detect(cli, args); + break; + } + if(string_cmp_str(cmd, "emulate") == 0) { + nfc_cli_emulate(cli, args); + break; + } + + nfc_cli_print_usage(); + } while(false); + + string_clear(cmd); +} + +void nfc_on_system_start() { +#ifdef SRV_CLI + Cli* cli = furi_record_open("cli"); + cli_add_command(cli, "nfc", CliCommandFlagDefault, nfc_cli, NULL); + furi_record_close("cli"); +#endif +} diff --git a/applications/nfc/nfc_cli.h b/applications/nfc/nfc_cli.h deleted file mode 100644 index df722dff683..00000000000 --- a/applications/nfc/nfc_cli.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include - -void nfc_on_system_start(); - -void nfc_cli_detect(Cli* cli, string_t args, void* context); - -void nfc_cli_emulate(Cli* cli, string_t args, void* context); diff --git a/applications/nfc/scenes/nfc_scene_device_info.c b/applications/nfc/scenes/nfc_scene_device_info.c index e9d5bfda609..f0f326f68b5 100755 --- a/applications/nfc/scenes/nfc_scene_device_info.c +++ b/applications/nfc/scenes/nfc_scene_device_info.c @@ -189,14 +189,7 @@ void nfc_scene_device_info_on_exit(void* context) { if(nfc->dev->format == NfcDeviceSaveFormatUid) { // Clear Dialog DialogEx* dialog_ex = nfc->dialog_ex; - dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter); - dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop); - dialog_ex_set_icon(dialog_ex, 0, 0, NULL); - dialog_ex_set_left_button_text(dialog_ex, NULL); - dialog_ex_set_right_button_text(dialog_ex, NULL); - dialog_ex_set_center_button_text(dialog_ex, NULL); - dialog_ex_set_result_callback(dialog_ex, NULL); - dialog_ex_set_context(dialog_ex, NULL); + dialog_ex_reset(dialog_ex); } else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { // Clear TextBox text_box_reset(nfc->text_box); diff --git a/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c b/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c index b396fae1cbc..603ad54ae7b 100755 --- a/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c +++ b/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c @@ -103,14 +103,7 @@ void nfc_scene_read_mifare_ul_success_on_exit(void* context) { // Clean dialog DialogEx* dialog_ex = nfc->dialog_ex; - dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter); - dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop); - dialog_ex_set_icon(dialog_ex, 0, 0, NULL); - dialog_ex_set_left_button_text(dialog_ex, NULL); - dialog_ex_set_right_button_text(dialog_ex, NULL); - dialog_ex_set_center_button_text(dialog_ex, NULL); - dialog_ex_set_result_callback(dialog_ex, NULL); - dialog_ex_set_context(dialog_ex, NULL); + dialog_ex_reset(dialog_ex); // Clean TextBox TextBox* text_box = nfc->text_box; diff --git a/applications/power/power_service/power.c b/applications/power/power_service/power.c index 2659e2ec734..3934b20d141 100755 --- a/applications/power/power_service/power.c +++ b/applications/power/power_service/power.c @@ -196,6 +196,11 @@ int32_t power_srv(void* p) { // Update battery view port if(need_refresh) view_port_update(power->battery_view_port); + // Check OTG status and disable it in case of fault + if(furi_hal_power_is_otg_enabled()) { + furi_hal_power_check_otg_status(); + } + osDelay(1000); } diff --git a/applications/power_observer/power_observer.c b/applications/power_observer/power_observer.c deleted file mode 100644 index b32447f06ed..00000000000 --- a/applications/power_observer/power_observer.c +++ /dev/null @@ -1,76 +0,0 @@ -#include -#include -#include - -typedef struct { - osThreadId_t thread; - -} PowerObserverSrv; - -const NotificationMessage message_green_110 = { - .type = NotificationMessageTypeLedGreen, - .data.led.value = 110, -}; - -static const NotificationSequence sequence_overconsumption = { - &message_green_110, - &message_red_255, - &message_delay_100, - NULL, -}; - -typedef enum { - EventReset = (1 << 0), - EventRequest = (1 << 1), -} UsbEvent; - -static void usb_state_callback(FuriHalUsbStateEvent state, void* context) { - PowerObserverSrv* srv = (PowerObserverSrv*)(context); - if(state == FuriHalUsbStateEventReset) { - osThreadFlagsSet(srv->thread, EventReset); - } else if(state == FuriHalUsbStateEventDescriptorRequest) { - osThreadFlagsSet(srv->thread, EventRequest); - } -} - -int32_t power_observer_srv(void* p) { - NotificationApp* notifications = furi_record_open("notification"); - PowerObserverSrv* srv = furi_alloc(sizeof(PowerObserverSrv)); - srv->thread = osThreadGetId(); - - const float overconsumption_limit = 0.03f; - bool usb_request_pending = false; - uint8_t usb_wait_time = 0; - - furi_hal_usb_set_state_callback(usb_state_callback, srv); - - while(true) { - uint32_t flags = osThreadFlagsWait(EventReset | EventRequest, osFlagsWaitAny, 500); - if((flags & osFlagsError) == 0) { - if(flags & EventReset) { - usb_request_pending = true; - usb_wait_time = 0; - } - if(flags & EventRequest) { - usb_request_pending = false; - } - } else if(usb_request_pending) { - usb_wait_time++; - if(usb_wait_time > 4) { - furi_hal_usb_reinit(); - usb_request_pending = false; - } - } - - float current = -furi_hal_power_get_battery_current(FuriHalPowerICFuelGauge); - if(current > overconsumption_limit) { - notification_message_block(notifications, &sequence_overconsumption); - } - if(furi_hal_power_is_otg_enabled()) { - furi_hal_power_check_otg_status(); - } - } - - free(srv); - return 0; -} diff --git a/firmware/targets/f6/ble_glue/ble_app.c b/firmware/targets/f6/ble_glue/ble_app.c index c3359e58c82..6afd36481b7 100644 --- a/firmware/targets/f6/ble_glue/ble_app.c +++ b/firmware/targets/f6/ble_glue/ble_app.c @@ -42,7 +42,7 @@ bool ble_app_init() { ble_app->event_flags = osEventFlagsNew(NULL); // HCI transport layer thread to handle user asynch events ble_app->thread = furi_thread_alloc(); - furi_thread_set_name(ble_app->thread, "BleHciWorker"); + furi_thread_set_name(ble_app->thread, "BleHciDriver"); furi_thread_set_stack_size(ble_app->thread, 1024); furi_thread_set_context(ble_app->thread, ble_app); furi_thread_set_callback(ble_app->thread, ble_app_hci_thread); diff --git a/firmware/targets/f6/ble_glue/ble_glue.c b/firmware/targets/f6/ble_glue/ble_glue.c index 6e55b3680f8..4c26e0863f9 100644 --- a/firmware/targets/f6/ble_glue/ble_glue.c +++ b/firmware/targets/f6/ble_glue/ble_glue.c @@ -88,7 +88,7 @@ void ble_glue_init() { // FreeRTOS system task creation ble_glue->thread = furi_thread_alloc(); - furi_thread_set_name(ble_glue->thread, "BleShciWorker"); + furi_thread_set_name(ble_glue->thread, "BleShciDriver"); furi_thread_set_stack_size(ble_glue->thread, 1024); furi_thread_set_context(ble_glue->thread, ble_glue); furi_thread_set_callback(ble_glue->thread, ble_glue_shci_thread); diff --git a/firmware/targets/f6/ble_glue/gap.c b/firmware/targets/f6/ble_glue/gap.c index d9a2096f973..1bd0cbbf60b 100755 --- a/firmware/targets/f6/ble_glue/gap.c +++ b/firmware/targets/f6/ble_glue/gap.c @@ -481,7 +481,7 @@ bool gap_init(GapConfig* config, GapEventCallback on_event_cb, void* context) { // Thread configuration gap->thread = furi_thread_alloc(); - furi_thread_set_name(gap->thread, "BleGapWorker"); + furi_thread_set_name(gap->thread, "BleGapDriver"); furi_thread_set_stack_size(gap->thread, 1024); furi_thread_set_context(gap->thread, gap); furi_thread_set_callback(gap->thread, gap_app); diff --git a/firmware/targets/f6/furi_hal/furi_hal.c b/firmware/targets/f6/furi_hal/furi_hal.c index da529893e9e..082956b1c2d 100644 --- a/firmware/targets/f6/furi_hal/furi_hal.c +++ b/firmware/targets/f6/furi_hal/furi_hal.c @@ -38,7 +38,6 @@ void furi_hal_init() { // VCP + USB furi_hal_usb_init(); - furi_hal_usb_set_config(&usb_cdc_single); furi_hal_vcp_init(); FURI_LOG_I(TAG, "USB OK"); diff --git a/firmware/targets/f6/furi_hal/furi_hal_usb.c b/firmware/targets/f6/furi_hal/furi_hal_usb.c index 7ca8ffdfa93..c948a3cfbe3 100644 --- a/firmware/targets/f6/furi_hal/furi_hal_usb.c +++ b/firmware/targets/f6/furi_hal/furi_hal_usb.c @@ -1,6 +1,7 @@ #include "furi_hal_version.h" #include "furi_hal_usb_i.h" #include "furi_hal_usb.h" +#include "furi_hal_vcp.h" #include #include @@ -10,29 +11,46 @@ #define USB_RECONNECT_DELAY 500 -static FuriHalUsbInterface* usb_if_cur; -static FuriHalUsbInterface* usb_if_next; +typedef struct { + FuriThread* thread; + osTimerId_t tmr; + bool enabled; + bool connected; + FuriHalUsbInterface* if_cur; + FuriHalUsbInterface* if_next; + FuriHalUsbStateCallback callback; + void* cb_ctx; +} UsbSrv; + +typedef enum { + EventModeChange = (1 << 0), + EventEnable = (1 << 1), + EventDisable = (1 << 2), + EventReinit = (1 << 3), + + EventReset = (1 << 4), + EventRequest = (1 << 5), + + EventModeChangeStart = (1 << 6), +} UsbEvent; + +#define USB_SRV_ALL_EVENTS \ + (EventModeChange | EventEnable | EventDisable | EventReinit | EventReset | EventRequest | \ + EventModeChangeStart) + +static UsbSrv usb; static const struct usb_string_descriptor dev_lang_desc = USB_ARRAY_DESC(USB_LANGID_ENG_US); static uint32_t ubuf[0x20]; usbd_device udev; -static FuriHalUsbStateCallback callback; -static void* cb_ctx; - +static int32_t furi_hal_usb_thread(void* context); static usbd_respond usb_descriptor_get(usbd_ctlreq* req, void** address, uint16_t* length); static void reset_evt(usbd_device* dev, uint8_t event, uint8_t ep); static void susp_evt(usbd_device* dev, uint8_t event, uint8_t ep); static void wkup_evt(usbd_device* dev, uint8_t event, uint8_t ep); -struct UsbCfg { - osTimerId_t reconnect_tmr; - bool enabled; - bool connected; - bool mode_changing; -} usb_config; - static void furi_hal_usb_tmr_cb(void* context); /* Low-level init */ @@ -56,79 +74,51 @@ void furi_hal_usb_init(void) { usbd_reg_event(&udev, usbd_evt_wkup, wkup_evt); // Reset callback will be enabled after first mode change to avoid getting false reset events - usb_config.enabled = false; - usb_config.reconnect_tmr = NULL; + usb.enabled = false; + usb.if_cur = NULL; HAL_NVIC_SetPriority(USB_LP_IRQn, 5, 0); NVIC_EnableIRQ(USB_LP_IRQn); + usb.thread = furi_thread_alloc(); + furi_thread_set_name(usb.thread, "UsbDriver"); + furi_thread_set_stack_size(usb.thread, 1024); + furi_thread_set_callback(usb.thread, furi_hal_usb_thread); + furi_thread_start(usb.thread); + FURI_LOG_I(TAG, "Init OK"); } void furi_hal_usb_set_config(FuriHalUsbInterface* new_if) { - if((new_if != usb_if_cur) && (usb_config.enabled)) { // Interface mode change - first stage - usb_config.mode_changing = true; - usb_if_next = new_if; - if(usb_config.reconnect_tmr == NULL) - usb_config.reconnect_tmr = osTimerNew(furi_hal_usb_tmr_cb, osTimerOnce, NULL, NULL); - furi_hal_usb_disable(); - usb_config.mode_changing = true; - osTimerStart(usb_config.reconnect_tmr, USB_RECONNECT_DELAY); - } else if( - (usb_config.mode_changing) && - (usb_if_next != new_if)) { // Last interface mode change wasn't completed - osTimerStop(usb_config.reconnect_tmr); - usb_if_next = new_if; - osTimerStart(usb_config.reconnect_tmr, USB_RECONNECT_DELAY); - } else { // Interface mode change - second stage - if(usb_if_cur != NULL) usb_if_cur->deinit(&udev); - if(new_if != NULL) { - new_if->init(&udev, new_if); - usbd_reg_event(&udev, usbd_evt_reset, reset_evt); - FURI_LOG_I(TAG, "USB Mode change done"); - usb_config.enabled = true; - usb_if_cur = new_if; - usb_config.mode_changing = false; - } + usb.if_next = new_if; + if(usb.thread == NULL) { + // Service thread hasn't started yet, so just save interface mode + return; } -} - -void furi_hal_usb_reinit() { - // Temporary disable callback to avoid getting false reset events - usbd_reg_event(&udev, usbd_evt_reset, NULL); - FURI_LOG_I(TAG, "USB Reinit"); - furi_hal_usb_disable(); - usbd_enable(&udev, false); - usbd_enable(&udev, true); - if(usb_config.reconnect_tmr == NULL) - usb_config.reconnect_tmr = osTimerNew(furi_hal_usb_tmr_cb, osTimerOnce, NULL, NULL); - usb_config.mode_changing = true; - usb_if_next = usb_if_cur; - osTimerStart(usb_config.reconnect_tmr, USB_RECONNECT_DELAY); + furi_assert(usb.thread); + osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventModeChange); } FuriHalUsbInterface* furi_hal_usb_get_config() { - return usb_if_cur; + return usb.if_cur; } void furi_hal_usb_disable() { - if(usb_config.enabled) { - susp_evt(&udev, 0, 0); - usbd_connect(&udev, false); - usb_config.enabled = false; - FURI_LOG_I(TAG, "USB Disable"); - } + furi_assert(usb.thread); + osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventDisable); } void furi_hal_usb_enable() { - if((!usb_config.enabled) && (usb_if_cur != NULL)) { - usbd_connect(&udev, true); - usb_config.enabled = true; - FURI_LOG_I(TAG, "USB Enable"); - } + osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventEnable); +} + +void furi_hal_usb_reinit() { + furi_assert(usb.thread); + osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventReinit); } static void furi_hal_usb_tmr_cb(void* context) { - furi_hal_usb_set_config(usb_if_next); + furi_assert(usb.thread); + osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventModeChangeStart); } /* Get device / configuration descriptors */ @@ -137,28 +127,29 @@ static usbd_respond usb_descriptor_get(usbd_ctlreq* req, void** address, uint16_ const uint8_t dnumber = req->wValue & 0xFF; const void* desc; uint16_t len = 0; - if(usb_if_cur == NULL) return usbd_fail; + if(usb.if_cur == NULL) return usbd_fail; switch(dtype) { case USB_DTYPE_DEVICE: - if(callback != NULL) { - callback(FuriHalUsbStateEventDescriptorRequest, cb_ctx); + osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventRequest); + if(usb.callback != NULL) { + usb.callback(FuriHalUsbStateEventDescriptorRequest, usb.cb_ctx); } - desc = usb_if_cur->dev_descr; + desc = usb.if_cur->dev_descr; break; case USB_DTYPE_CONFIGURATION: - desc = usb_if_cur->cfg_descr; - len = ((struct usb_string_descriptor*)(usb_if_cur->cfg_descr))->wString[0]; + desc = usb.if_cur->cfg_descr; + len = ((struct usb_string_descriptor*)(usb.if_cur->cfg_descr))->wString[0]; break; case USB_DTYPE_STRING: if(dnumber == UsbDevLang) { desc = &dev_lang_desc; - } else if((dnumber == UsbDevManuf) && (usb_if_cur->str_manuf_descr != NULL)) { - desc = usb_if_cur->str_manuf_descr; - } else if((dnumber == UsbDevProduct) && (usb_if_cur->str_prod_descr != NULL)) { - desc = usb_if_cur->str_prod_descr; - } else if((dnumber == UsbDevSerial) && (usb_if_cur->str_serial_descr != NULL)) { - desc = usb_if_cur->str_serial_descr; + } else if((dnumber == UsbDevManuf) && (usb.if_cur->str_manuf_descr != NULL)) { + desc = usb.if_cur->str_manuf_descr; + } else if((dnumber == UsbDevProduct) && (usb.if_cur->str_prod_descr != NULL)) { + desc = usb.if_cur->str_prod_descr; + } else if((dnumber == UsbDevSerial) && (usb.if_cur->str_serial_descr != NULL)) { + desc = usb.if_cur->str_serial_descr; } else return usbd_fail; break; @@ -176,36 +167,122 @@ static usbd_respond usb_descriptor_get(usbd_ctlreq* req, void** address, uint16_ } void furi_hal_usb_set_state_callback(FuriHalUsbStateCallback cb, void* ctx) { - callback = cb; - cb_ctx = ctx; + usb.callback = cb; + usb.cb_ctx = ctx; } static void reset_evt(usbd_device* dev, uint8_t event, uint8_t ep) { - if(callback != NULL) { - callback(FuriHalUsbStateEventReset, cb_ctx); + osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventReset); + if(usb.callback != NULL) { + usb.callback(FuriHalUsbStateEventReset, usb.cb_ctx); } } static void susp_evt(usbd_device* dev, uint8_t event, uint8_t ep) { - if((usb_if_cur != NULL) && (usb_config.connected == true)) { - usb_config.connected = false; - usb_if_cur->suspend(&udev); + if((usb.if_cur != NULL) && (usb.connected == true)) { + usb.connected = false; + usb.if_cur->suspend(&udev); furi_hal_power_insomnia_exit(); } - if(callback != NULL) { - callback(FuriHalUsbStateEventSuspend, cb_ctx); + if(usb.callback != NULL) { + usb.callback(FuriHalUsbStateEventSuspend, usb.cb_ctx); } } static void wkup_evt(usbd_device* dev, uint8_t event, uint8_t ep) { - if((usb_if_cur != NULL) && (usb_config.connected == false)) { - usb_config.connected = true; - usb_if_cur->wakeup(&udev); + if((usb.if_cur != NULL) && (usb.connected == false)) { + usb.connected = true; + usb.if_cur->wakeup(&udev); furi_hal_power_insomnia_enter(); } - if(callback != NULL) { - callback(FuriHalUsbStateEventWakeup, cb_ctx); + if(usb.callback != NULL) { + usb.callback(FuriHalUsbStateEventWakeup, usb.cb_ctx); + } +} + +static int32_t furi_hal_usb_thread(void* context) { + usb.tmr = osTimerNew(furi_hal_usb_tmr_cb, osTimerOnce, NULL, NULL); + + bool usb_request_pending = false; + uint8_t usb_wait_time = 0; + + if(usb.if_next != NULL) { + osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventModeChange); + } + + while(true) { + uint32_t flags = osThreadFlagsWait(USB_SRV_ALL_EVENTS, osFlagsWaitAny, 500); + if((flags & osFlagsError) == 0) { + if(flags & EventModeChange) { + if(usb.if_next != usb.if_cur) { + if(usb.enabled) { // Disable current interface + susp_evt(&udev, 0, 0); + usbd_connect(&udev, false); + usb.enabled = false; + osTimerStart(usb.tmr, USB_RECONNECT_DELAY); + } else { + flags |= EventModeChangeStart; + } + } + } + if(flags & EventReinit) { + // Temporary disable callback to avoid getting false reset events + usbd_reg_event(&udev, usbd_evt_reset, NULL); + FURI_LOG_I(TAG, "USB Reinit"); + susp_evt(&udev, 0, 0); + usbd_connect(&udev, false); + usb.enabled = false; + + usbd_enable(&udev, false); + usbd_enable(&udev, true); + + usb.if_next = usb.if_cur; + osTimerStart(usb.tmr, USB_RECONNECT_DELAY); + } + if(flags & EventModeChangeStart) { // Second stage of mode change process + if(usb.if_cur != NULL) { + usb.if_cur->deinit(&udev); + } + if(usb.if_next != NULL) { + usb.if_next->init(&udev, usb.if_next); + usbd_reg_event(&udev, usbd_evt_reset, reset_evt); + FURI_LOG_I(TAG, "USB Mode change done"); + usb.enabled = true; + usb.if_cur = usb.if_next; + } + } + if(flags & EventEnable) { + if((!usb.enabled) && (usb.if_cur != NULL)) { + usbd_connect(&udev, true); + usb.enabled = true; + FURI_LOG_I(TAG, "USB Enable"); + } + } + if(flags & EventDisable) { + if(usb.enabled) { + susp_evt(&udev, 0, 0); + usbd_connect(&udev, false); + usb.enabled = false; + usb_request_pending = false; + FURI_LOG_I(TAG, "USB Disable"); + } + } + if(flags & EventReset) { + usb_request_pending = true; + usb_wait_time = 0; + } + if(flags & EventRequest) { + usb_request_pending = false; + } + } else if(usb_request_pending) { + usb_wait_time++; + if(usb_wait_time > 4) { + furi_hal_usb_reinit(); + usb_request_pending = false; + } + } } + return 0; } diff --git a/firmware/targets/f6/furi_hal/furi_hal_vcp.c b/firmware/targets/f6/furi_hal/furi_hal_vcp.c index 4ac59ae3fae..409a61a02fc 100644 --- a/firmware/targets/f6/furi_hal/furi_hal_vcp.c +++ b/firmware/targets/f6/furi_hal/furi_hal_vcp.c @@ -1,5 +1,5 @@ #include -#include +#include #include #include @@ -65,7 +65,7 @@ void furi_hal_vcp_init() { vcp->rx_stream = xStreamBufferCreate(VCP_RX_BUF_SIZE, 1); vcp->thread = furi_thread_alloc(); - furi_thread_set_name(vcp->thread, "VcpWorker"); + furi_thread_set_name(vcp->thread, "VcpDriver"); furi_thread_set_stack_size(vcp->thread, 1024); furi_thread_set_callback(vcp->thread, vcp_worker); furi_thread_start(vcp->thread); @@ -79,6 +79,7 @@ static int32_t vcp_worker(void* context) { size_t missed_rx = 0; uint8_t last_tx_pkt_len = 0; + furi_hal_usb_set_config(&usb_cdc_single); furi_hal_cdc_set_callbacks(VCP_IF_NUM, &cdc_cb, NULL); while(1) { diff --git a/firmware/targets/f7/ble_glue/ble_app.c b/firmware/targets/f7/ble_glue/ble_app.c index c3359e58c82..6afd36481b7 100644 --- a/firmware/targets/f7/ble_glue/ble_app.c +++ b/firmware/targets/f7/ble_glue/ble_app.c @@ -42,7 +42,7 @@ bool ble_app_init() { ble_app->event_flags = osEventFlagsNew(NULL); // HCI transport layer thread to handle user asynch events ble_app->thread = furi_thread_alloc(); - furi_thread_set_name(ble_app->thread, "BleHciWorker"); + furi_thread_set_name(ble_app->thread, "BleHciDriver"); furi_thread_set_stack_size(ble_app->thread, 1024); furi_thread_set_context(ble_app->thread, ble_app); furi_thread_set_callback(ble_app->thread, ble_app_hci_thread); diff --git a/firmware/targets/f7/ble_glue/ble_glue.c b/firmware/targets/f7/ble_glue/ble_glue.c index 6e55b3680f8..4c26e0863f9 100644 --- a/firmware/targets/f7/ble_glue/ble_glue.c +++ b/firmware/targets/f7/ble_glue/ble_glue.c @@ -88,7 +88,7 @@ void ble_glue_init() { // FreeRTOS system task creation ble_glue->thread = furi_thread_alloc(); - furi_thread_set_name(ble_glue->thread, "BleShciWorker"); + furi_thread_set_name(ble_glue->thread, "BleShciDriver"); furi_thread_set_stack_size(ble_glue->thread, 1024); furi_thread_set_context(ble_glue->thread, ble_glue); furi_thread_set_callback(ble_glue->thread, ble_glue_shci_thread); diff --git a/firmware/targets/f7/ble_glue/gap.c b/firmware/targets/f7/ble_glue/gap.c index d9a2096f973..1bd0cbbf60b 100755 --- a/firmware/targets/f7/ble_glue/gap.c +++ b/firmware/targets/f7/ble_glue/gap.c @@ -481,7 +481,7 @@ bool gap_init(GapConfig* config, GapEventCallback on_event_cb, void* context) { // Thread configuration gap->thread = furi_thread_alloc(); - furi_thread_set_name(gap->thread, "BleGapWorker"); + furi_thread_set_name(gap->thread, "BleGapDriver"); furi_thread_set_stack_size(gap->thread, 1024); furi_thread_set_context(gap->thread, gap); furi_thread_set_callback(gap->thread, gap_app); diff --git a/firmware/targets/f7/furi_hal/furi_hal.c b/firmware/targets/f7/furi_hal/furi_hal.c index da529893e9e..082956b1c2d 100644 --- a/firmware/targets/f7/furi_hal/furi_hal.c +++ b/firmware/targets/f7/furi_hal/furi_hal.c @@ -38,7 +38,6 @@ void furi_hal_init() { // VCP + USB furi_hal_usb_init(); - furi_hal_usb_set_config(&usb_cdc_single); furi_hal_vcp_init(); FURI_LOG_I(TAG, "USB OK"); diff --git a/firmware/targets/f7/furi_hal/furi_hal_usb.c b/firmware/targets/f7/furi_hal/furi_hal_usb.c index 7ca8ffdfa93..c948a3cfbe3 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_usb.c +++ b/firmware/targets/f7/furi_hal/furi_hal_usb.c @@ -1,6 +1,7 @@ #include "furi_hal_version.h" #include "furi_hal_usb_i.h" #include "furi_hal_usb.h" +#include "furi_hal_vcp.h" #include #include @@ -10,29 +11,46 @@ #define USB_RECONNECT_DELAY 500 -static FuriHalUsbInterface* usb_if_cur; -static FuriHalUsbInterface* usb_if_next; +typedef struct { + FuriThread* thread; + osTimerId_t tmr; + bool enabled; + bool connected; + FuriHalUsbInterface* if_cur; + FuriHalUsbInterface* if_next; + FuriHalUsbStateCallback callback; + void* cb_ctx; +} UsbSrv; + +typedef enum { + EventModeChange = (1 << 0), + EventEnable = (1 << 1), + EventDisable = (1 << 2), + EventReinit = (1 << 3), + + EventReset = (1 << 4), + EventRequest = (1 << 5), + + EventModeChangeStart = (1 << 6), +} UsbEvent; + +#define USB_SRV_ALL_EVENTS \ + (EventModeChange | EventEnable | EventDisable | EventReinit | EventReset | EventRequest | \ + EventModeChangeStart) + +static UsbSrv usb; static const struct usb_string_descriptor dev_lang_desc = USB_ARRAY_DESC(USB_LANGID_ENG_US); static uint32_t ubuf[0x20]; usbd_device udev; -static FuriHalUsbStateCallback callback; -static void* cb_ctx; - +static int32_t furi_hal_usb_thread(void* context); static usbd_respond usb_descriptor_get(usbd_ctlreq* req, void** address, uint16_t* length); static void reset_evt(usbd_device* dev, uint8_t event, uint8_t ep); static void susp_evt(usbd_device* dev, uint8_t event, uint8_t ep); static void wkup_evt(usbd_device* dev, uint8_t event, uint8_t ep); -struct UsbCfg { - osTimerId_t reconnect_tmr; - bool enabled; - bool connected; - bool mode_changing; -} usb_config; - static void furi_hal_usb_tmr_cb(void* context); /* Low-level init */ @@ -56,79 +74,51 @@ void furi_hal_usb_init(void) { usbd_reg_event(&udev, usbd_evt_wkup, wkup_evt); // Reset callback will be enabled after first mode change to avoid getting false reset events - usb_config.enabled = false; - usb_config.reconnect_tmr = NULL; + usb.enabled = false; + usb.if_cur = NULL; HAL_NVIC_SetPriority(USB_LP_IRQn, 5, 0); NVIC_EnableIRQ(USB_LP_IRQn); + usb.thread = furi_thread_alloc(); + furi_thread_set_name(usb.thread, "UsbDriver"); + furi_thread_set_stack_size(usb.thread, 1024); + furi_thread_set_callback(usb.thread, furi_hal_usb_thread); + furi_thread_start(usb.thread); + FURI_LOG_I(TAG, "Init OK"); } void furi_hal_usb_set_config(FuriHalUsbInterface* new_if) { - if((new_if != usb_if_cur) && (usb_config.enabled)) { // Interface mode change - first stage - usb_config.mode_changing = true; - usb_if_next = new_if; - if(usb_config.reconnect_tmr == NULL) - usb_config.reconnect_tmr = osTimerNew(furi_hal_usb_tmr_cb, osTimerOnce, NULL, NULL); - furi_hal_usb_disable(); - usb_config.mode_changing = true; - osTimerStart(usb_config.reconnect_tmr, USB_RECONNECT_DELAY); - } else if( - (usb_config.mode_changing) && - (usb_if_next != new_if)) { // Last interface mode change wasn't completed - osTimerStop(usb_config.reconnect_tmr); - usb_if_next = new_if; - osTimerStart(usb_config.reconnect_tmr, USB_RECONNECT_DELAY); - } else { // Interface mode change - second stage - if(usb_if_cur != NULL) usb_if_cur->deinit(&udev); - if(new_if != NULL) { - new_if->init(&udev, new_if); - usbd_reg_event(&udev, usbd_evt_reset, reset_evt); - FURI_LOG_I(TAG, "USB Mode change done"); - usb_config.enabled = true; - usb_if_cur = new_if; - usb_config.mode_changing = false; - } + usb.if_next = new_if; + if(usb.thread == NULL) { + // Service thread hasn't started yet, so just save interface mode + return; } -} - -void furi_hal_usb_reinit() { - // Temporary disable callback to avoid getting false reset events - usbd_reg_event(&udev, usbd_evt_reset, NULL); - FURI_LOG_I(TAG, "USB Reinit"); - furi_hal_usb_disable(); - usbd_enable(&udev, false); - usbd_enable(&udev, true); - if(usb_config.reconnect_tmr == NULL) - usb_config.reconnect_tmr = osTimerNew(furi_hal_usb_tmr_cb, osTimerOnce, NULL, NULL); - usb_config.mode_changing = true; - usb_if_next = usb_if_cur; - osTimerStart(usb_config.reconnect_tmr, USB_RECONNECT_DELAY); + furi_assert(usb.thread); + osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventModeChange); } FuriHalUsbInterface* furi_hal_usb_get_config() { - return usb_if_cur; + return usb.if_cur; } void furi_hal_usb_disable() { - if(usb_config.enabled) { - susp_evt(&udev, 0, 0); - usbd_connect(&udev, false); - usb_config.enabled = false; - FURI_LOG_I(TAG, "USB Disable"); - } + furi_assert(usb.thread); + osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventDisable); } void furi_hal_usb_enable() { - if((!usb_config.enabled) && (usb_if_cur != NULL)) { - usbd_connect(&udev, true); - usb_config.enabled = true; - FURI_LOG_I(TAG, "USB Enable"); - } + osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventEnable); +} + +void furi_hal_usb_reinit() { + furi_assert(usb.thread); + osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventReinit); } static void furi_hal_usb_tmr_cb(void* context) { - furi_hal_usb_set_config(usb_if_next); + furi_assert(usb.thread); + osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventModeChangeStart); } /* Get device / configuration descriptors */ @@ -137,28 +127,29 @@ static usbd_respond usb_descriptor_get(usbd_ctlreq* req, void** address, uint16_ const uint8_t dnumber = req->wValue & 0xFF; const void* desc; uint16_t len = 0; - if(usb_if_cur == NULL) return usbd_fail; + if(usb.if_cur == NULL) return usbd_fail; switch(dtype) { case USB_DTYPE_DEVICE: - if(callback != NULL) { - callback(FuriHalUsbStateEventDescriptorRequest, cb_ctx); + osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventRequest); + if(usb.callback != NULL) { + usb.callback(FuriHalUsbStateEventDescriptorRequest, usb.cb_ctx); } - desc = usb_if_cur->dev_descr; + desc = usb.if_cur->dev_descr; break; case USB_DTYPE_CONFIGURATION: - desc = usb_if_cur->cfg_descr; - len = ((struct usb_string_descriptor*)(usb_if_cur->cfg_descr))->wString[0]; + desc = usb.if_cur->cfg_descr; + len = ((struct usb_string_descriptor*)(usb.if_cur->cfg_descr))->wString[0]; break; case USB_DTYPE_STRING: if(dnumber == UsbDevLang) { desc = &dev_lang_desc; - } else if((dnumber == UsbDevManuf) && (usb_if_cur->str_manuf_descr != NULL)) { - desc = usb_if_cur->str_manuf_descr; - } else if((dnumber == UsbDevProduct) && (usb_if_cur->str_prod_descr != NULL)) { - desc = usb_if_cur->str_prod_descr; - } else if((dnumber == UsbDevSerial) && (usb_if_cur->str_serial_descr != NULL)) { - desc = usb_if_cur->str_serial_descr; + } else if((dnumber == UsbDevManuf) && (usb.if_cur->str_manuf_descr != NULL)) { + desc = usb.if_cur->str_manuf_descr; + } else if((dnumber == UsbDevProduct) && (usb.if_cur->str_prod_descr != NULL)) { + desc = usb.if_cur->str_prod_descr; + } else if((dnumber == UsbDevSerial) && (usb.if_cur->str_serial_descr != NULL)) { + desc = usb.if_cur->str_serial_descr; } else return usbd_fail; break; @@ -176,36 +167,122 @@ static usbd_respond usb_descriptor_get(usbd_ctlreq* req, void** address, uint16_ } void furi_hal_usb_set_state_callback(FuriHalUsbStateCallback cb, void* ctx) { - callback = cb; - cb_ctx = ctx; + usb.callback = cb; + usb.cb_ctx = ctx; } static void reset_evt(usbd_device* dev, uint8_t event, uint8_t ep) { - if(callback != NULL) { - callback(FuriHalUsbStateEventReset, cb_ctx); + osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventReset); + if(usb.callback != NULL) { + usb.callback(FuriHalUsbStateEventReset, usb.cb_ctx); } } static void susp_evt(usbd_device* dev, uint8_t event, uint8_t ep) { - if((usb_if_cur != NULL) && (usb_config.connected == true)) { - usb_config.connected = false; - usb_if_cur->suspend(&udev); + if((usb.if_cur != NULL) && (usb.connected == true)) { + usb.connected = false; + usb.if_cur->suspend(&udev); furi_hal_power_insomnia_exit(); } - if(callback != NULL) { - callback(FuriHalUsbStateEventSuspend, cb_ctx); + if(usb.callback != NULL) { + usb.callback(FuriHalUsbStateEventSuspend, usb.cb_ctx); } } static void wkup_evt(usbd_device* dev, uint8_t event, uint8_t ep) { - if((usb_if_cur != NULL) && (usb_config.connected == false)) { - usb_config.connected = true; - usb_if_cur->wakeup(&udev); + if((usb.if_cur != NULL) && (usb.connected == false)) { + usb.connected = true; + usb.if_cur->wakeup(&udev); furi_hal_power_insomnia_enter(); } - if(callback != NULL) { - callback(FuriHalUsbStateEventWakeup, cb_ctx); + if(usb.callback != NULL) { + usb.callback(FuriHalUsbStateEventWakeup, usb.cb_ctx); + } +} + +static int32_t furi_hal_usb_thread(void* context) { + usb.tmr = osTimerNew(furi_hal_usb_tmr_cb, osTimerOnce, NULL, NULL); + + bool usb_request_pending = false; + uint8_t usb_wait_time = 0; + + if(usb.if_next != NULL) { + osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventModeChange); + } + + while(true) { + uint32_t flags = osThreadFlagsWait(USB_SRV_ALL_EVENTS, osFlagsWaitAny, 500); + if((flags & osFlagsError) == 0) { + if(flags & EventModeChange) { + if(usb.if_next != usb.if_cur) { + if(usb.enabled) { // Disable current interface + susp_evt(&udev, 0, 0); + usbd_connect(&udev, false); + usb.enabled = false; + osTimerStart(usb.tmr, USB_RECONNECT_DELAY); + } else { + flags |= EventModeChangeStart; + } + } + } + if(flags & EventReinit) { + // Temporary disable callback to avoid getting false reset events + usbd_reg_event(&udev, usbd_evt_reset, NULL); + FURI_LOG_I(TAG, "USB Reinit"); + susp_evt(&udev, 0, 0); + usbd_connect(&udev, false); + usb.enabled = false; + + usbd_enable(&udev, false); + usbd_enable(&udev, true); + + usb.if_next = usb.if_cur; + osTimerStart(usb.tmr, USB_RECONNECT_DELAY); + } + if(flags & EventModeChangeStart) { // Second stage of mode change process + if(usb.if_cur != NULL) { + usb.if_cur->deinit(&udev); + } + if(usb.if_next != NULL) { + usb.if_next->init(&udev, usb.if_next); + usbd_reg_event(&udev, usbd_evt_reset, reset_evt); + FURI_LOG_I(TAG, "USB Mode change done"); + usb.enabled = true; + usb.if_cur = usb.if_next; + } + } + if(flags & EventEnable) { + if((!usb.enabled) && (usb.if_cur != NULL)) { + usbd_connect(&udev, true); + usb.enabled = true; + FURI_LOG_I(TAG, "USB Enable"); + } + } + if(flags & EventDisable) { + if(usb.enabled) { + susp_evt(&udev, 0, 0); + usbd_connect(&udev, false); + usb.enabled = false; + usb_request_pending = false; + FURI_LOG_I(TAG, "USB Disable"); + } + } + if(flags & EventReset) { + usb_request_pending = true; + usb_wait_time = 0; + } + if(flags & EventRequest) { + usb_request_pending = false; + } + } else if(usb_request_pending) { + usb_wait_time++; + if(usb_wait_time > 4) { + furi_hal_usb_reinit(); + usb_request_pending = false; + } + } } + return 0; } diff --git a/firmware/targets/f7/furi_hal/furi_hal_vcp.c b/firmware/targets/f7/furi_hal/furi_hal_vcp.c index 4ac59ae3fae..409a61a02fc 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_vcp.c +++ b/firmware/targets/f7/furi_hal/furi_hal_vcp.c @@ -1,5 +1,5 @@ #include -#include +#include #include #include @@ -65,7 +65,7 @@ void furi_hal_vcp_init() { vcp->rx_stream = xStreamBufferCreate(VCP_RX_BUF_SIZE, 1); vcp->thread = furi_thread_alloc(); - furi_thread_set_name(vcp->thread, "VcpWorker"); + furi_thread_set_name(vcp->thread, "VcpDriver"); furi_thread_set_stack_size(vcp->thread, 1024); furi_thread_set_callback(vcp->thread, vcp_worker); furi_thread_start(vcp->thread); @@ -79,6 +79,7 @@ static int32_t vcp_worker(void* context) { size_t missed_rx = 0; uint8_t last_tx_pkt_len = 0; + furi_hal_usb_set_config(&usb_cdc_single); furi_hal_cdc_set_callbacks(VCP_IF_NUM, &cdc_cb, NULL); while(1) { diff --git a/lib/ST25RFAL002/platform.c b/lib/ST25RFAL002/platform.c index a88b1acbd9a..a4759f2a9e5 100644 --- a/lib/ST25RFAL002/platform.c +++ b/lib/ST25RFAL002/platform.c @@ -5,7 +5,7 @@ #include static const osThreadAttr_t platform_irq_thread_attr = { - .name = "RfalIrqWorker", + .name = "RfalIrqDriver", .stack_size = 1024, .priority = osPriorityRealtime, }; @@ -20,7 +20,7 @@ void nfc_isr(void* _ctx) { } } -void platformIrqWorker() { +void platformIrqThread() { while(1) { uint32_t flags = osThreadFlagsWait(0x1, osFlagsWaitAny, osWaitForever); if(flags & 0x1) { @@ -41,7 +41,7 @@ void platformDisableIrqCallback() { void platformSetIrqCallback(PlatformIrqCallback callback) { platform_irq_callback = callback; - platform_irq_thread_id = osThreadNew(platformIrqWorker, NULL, &platform_irq_thread_attr); + platform_irq_thread_id = osThreadNew(platformIrqThread, NULL, &platform_irq_thread_attr); hal_gpio_add_int_callback(&pin, nfc_isr, NULL); // Disable interrupt callback as the pin is shared between 2 apps // It is enabled in rfalLowPowerModeStop() diff --git a/lib/irda/encoder_decoder/irda.c b/lib/irda/encoder_decoder/irda.c index f7cc2875636..0fad0d89107 100644 --- a/lib/irda/encoder_decoder/irda.c +++ b/lib/irda/encoder_decoder/irda.c @@ -268,9 +268,11 @@ IrdaProtocol irda_get_protocol_by_name(const char* protocol_name) { static const IrdaProtocolSpecification* irda_get_spec_by_protocol(IrdaProtocol protocol) { int index = irda_find_index_by_protocol(protocol); - furi_check(index >= 0); - const IrdaProtocolSpecification* spec = - irda_encoder_decoder[index].get_protocol_spec(protocol); + const IrdaProtocolSpecification* spec = NULL; + if(index >= 0) { + spec = irda_encoder_decoder[index].get_protocol_spec(protocol); + } + furi_assert(spec); return spec; }