diff --git a/applications/cli/cli.c b/applications/cli/cli.c index 091d37f8..4e200d6b 100644 --- a/applications/cli/cli.c +++ b/applications/cli/cli.c @@ -1,9 +1,11 @@ #include "cli_i.h" #include "cli_commands.h" - +#include "cli_vcp.h" #include #include +#define TAG "CliSrv" + Cli* cli_alloc() { Cli* cli = malloc(sizeof(Cli)); @@ -12,55 +14,78 @@ Cli* cli_alloc() { string_init(cli->last_line); string_init(cli->line); + cli->session = NULL; + cli->mutex = osMutexNew(NULL); furi_check(cli->mutex); + cli->idle_sem = osSemaphoreNew(1, 0, NULL); + return cli; } -void cli_free(Cli* cli) { +void cli_putc(Cli* cli, char c) { furi_assert(cli); - - string_clear(cli->last_line); - string_clear(cli->line); - - CliCommandTree_clear(cli->commands); - - free(cli); -} - -void cli_putc(char c) { - furi_hal_vcp_tx((uint8_t*)&c, 1); + if(cli->session != NULL) { + cli->session->tx((uint8_t*)&c, 1); + } } char cli_getc(Cli* cli) { furi_assert(cli); - char c; - if(furi_hal_vcp_rx((uint8_t*)&c, 1) == 0) { + char c = 0; + if(cli->session != NULL) { + if(cli->session->rx((uint8_t*)&c, 1, osWaitForever) == 0) { + cli_reset(cli); + } + } else { cli_reset(cli); } return c; } -void cli_stdout_callback(void* _cookie, const char* data, size_t size) { - furi_hal_vcp_tx((const uint8_t*)data, size); -} - void cli_write(Cli* cli, const uint8_t* buffer, size_t size) { - return furi_hal_vcp_tx(buffer, size); + furi_assert(cli); + if(cli->session != NULL) { + cli->session->tx(buffer, size); + } } size_t cli_read(Cli* cli, uint8_t* buffer, size_t size) { - return furi_hal_vcp_rx(buffer, size); + furi_assert(cli); + if(cli->session != NULL) { + return cli->session->rx(buffer, size, osWaitForever); + } else { + return 0; + } +} + +size_t cli_read_timeout(Cli* cli, uint8_t* buffer, size_t size, uint32_t timeout) { + furi_assert(cli); + if(cli->session != NULL) { + return cli->session->rx(buffer, size, timeout); + } else { + return 0; + } } bool cli_cmd_interrupt_received(Cli* cli) { + furi_assert(cli); char c = '\0'; - if(furi_hal_vcp_rx_with_timeout((uint8_t*)&c, 1, 0) == 1) { - return c == CliSymbolAsciiETX; - } else { - return false; + if(cli->session != NULL) { + if(cli->session->rx((uint8_t*)&c, 1, 0) == 1) { + return c == CliSymbolAsciiETX; + } } + return false; +} + +bool cli_is_connected(Cli* cli) { + furi_assert(cli); + if(cli->session != NULL) { + return (cli->session->is_connected()); + } + return false; } void cli_print_usage(const char* cmd, const char* usage, const char* arg) { @@ -139,7 +164,7 @@ static void cli_handle_backspace(Cli* cli) { cli->cursor_position--; } else { - cli_putc(CliSymbolAsciiBell); + cli_putc(cli, CliSymbolAsciiBell); } } @@ -210,7 +235,7 @@ static void cli_handle_enter(Cli* cli) { printf( "`%s` command not found, use `help` or `?` to list all available commands", string_get_cstr(command)); - cli_putc(CliSymbolAsciiBell); + cli_putc(cli, CliSymbolAsciiBell); } furi_check(osMutexRelease(cli->mutex) == osOK); @@ -301,43 +326,43 @@ static void cli_handle_escape(Cli* cli, char c) { } void cli_process_input(Cli* cli) { - char c = cli_getc(cli); - size_t r; + char in_chr = cli_getc(cli); + size_t rx_len; - if(c == CliSymbolAsciiTab) { + if(in_chr == CliSymbolAsciiTab) { cli_handle_autocomplete(cli); - } else if(c == CliSymbolAsciiSOH) { + } else if(in_chr == CliSymbolAsciiSOH) { osDelay(33); // We are too fast, Minicom is not ready yet cli_motd(); cli_prompt(cli); - } else if(c == CliSymbolAsciiETX) { + } else if(in_chr == CliSymbolAsciiETX) { cli_reset(cli); cli_prompt(cli); - } else if(c == CliSymbolAsciiEOT) { + } else if(in_chr == CliSymbolAsciiEOT) { cli_reset(cli); - } else if(c == CliSymbolAsciiEsc) { - r = furi_hal_vcp_rx((uint8_t*)&c, 1); - if(r && c == '[') { - furi_hal_vcp_rx((uint8_t*)&c, 1); - cli_handle_escape(cli, c); + } else if(in_chr == CliSymbolAsciiEsc) { + rx_len = cli_read(cli, (uint8_t*)&in_chr, 1); + if((rx_len > 0) && (in_chr == '[')) { + cli_read(cli, (uint8_t*)&in_chr, 1); + cli_handle_escape(cli, in_chr); } else { - cli_putc(CliSymbolAsciiBell); + cli_putc(cli, CliSymbolAsciiBell); } - } else if(c == CliSymbolAsciiBackspace || c == CliSymbolAsciiDel) { + } else if(in_chr == CliSymbolAsciiBackspace || in_chr == CliSymbolAsciiDel) { cli_handle_backspace(cli); - } else if(c == CliSymbolAsciiCR) { + } else if(in_chr == CliSymbolAsciiCR) { cli_handle_enter(cli); - } else if(c >= 0x20 && c < 0x7F) { + } else if(in_chr >= 0x20 && in_chr < 0x7F) { if(cli->cursor_position == string_size(cli->line)) { - string_push_back(cli->line, c); - cli_putc(c); + string_push_back(cli->line, in_chr); + cli_putc(cli, in_chr); } else { // ToDo: better way? string_t temp; string_init(temp); string_reserve(temp, string_size(cli->line) + 1); string_set_strn(temp, string_get_cstr(cli->line), cli->cursor_position); - string_push_back(temp, c); + string_push_back(temp, in_chr); string_cat_str(temp, string_get_cstr(cli->line) + cli->cursor_position); // cli->line is cleared and temp's buffer moved to cli->line @@ -345,12 +370,12 @@ void cli_process_input(Cli* cli) { // NO MEMORY LEAK, STOP REPORTING IT // Print character in replace mode - printf("\e[4h%c\e[4l", c); + printf("\e[4h%c\e[4l", in_chr); fflush(stdout); } cli->cursor_position++; } else { - cli_putc(CliSymbolAsciiBell); + cli_putc(cli, CliSymbolAsciiBell); } } @@ -398,19 +423,59 @@ void cli_delete_command(Cli* cli, const char* name) { string_clear(name_str); } +void cli_session_open(Cli* cli, void* session) { + furi_assert(cli); + + furi_check(osMutexAcquire(cli->mutex, osWaitForever) == osOK); + cli->session = session; + if(cli->session != NULL) { + cli->session->init(); + furi_stdglue_set_thread_stdout_callback(cli->session->tx_stdout); + } else { + furi_stdglue_set_thread_stdout_callback(NULL); + } + osSemaphoreRelease(cli->idle_sem); + furi_check(osMutexRelease(cli->mutex) == osOK); +} + +void cli_session_close(Cli* cli) { + furi_assert(cli); + + furi_check(osMutexAcquire(cli->mutex, osWaitForever) == osOK); + if(cli->session != NULL) { + cli->session->deinit(); + } + cli->session = NULL; + furi_stdglue_set_thread_stdout_callback(NULL); + furi_check(osMutexRelease(cli->mutex) == osOK); +} + int32_t cli_srv(void* p) { Cli* cli = cli_alloc(); - furi_hal_vcp_init(); - // Init basic cli commands cli_commands_init(cli); furi_record_create("cli", cli); - furi_stdglue_set_thread_stdout_callback(cli_stdout_callback); + if(cli->session != NULL) { + furi_stdglue_set_thread_stdout_callback(cli->session->tx_stdout); + } else { + furi_stdglue_set_thread_stdout_callback(NULL); + } + + if(furi_hal_rtc_get_boot_mode() == FuriHalRtcBootModeNormal) { + cli_session_open(cli, &cli_vcp); + } else { + FURI_LOG_W(TAG, "Skipped CLI session open: device in special startup mode"); + } + while(1) { - cli_process_input(cli); + if(cli->session != NULL) { + cli_process_input(cli); + } else { + furi_check(osSemaphoreAcquire(cli->idle_sem, osWaitForever) == osOK); + } } return 0; diff --git a/applications/cli/cli.h b/applications/cli/cli.h index 1f1b61a2..29f27392 100644 --- a/applications/cli/cli.h +++ b/applications/cli/cli.h @@ -73,17 +73,28 @@ void cli_print_usage(const char* cmd, const char* usage, const char* arg); */ void cli_delete_command(Cli* cli, const char* name); -/** Read from terminal Do it only from inside of cli call. +/** Read from terminal * * @param cli Cli instance * @param buffer pointer to buffer * @param size size of buffer in bytes * - * @return bytes written + * @return bytes read */ size_t cli_read(Cli* cli, uint8_t* buffer, size_t size); -/** Not blocking check for interrupt command received +/** Non-blocking read from terminal + * + * @param cli Cli instance + * @param buffer pointer to buffer + * @param size size of buffer in bytes + * @param timeout timeout value in ms + * + * @return bytes read + */ +size_t cli_read_timeout(Cli* cli, uint8_t* buffer, size_t size, uint32_t timeout); + +/** Non-blocking check for interrupt command received * * @param cli Cli instance * @@ -111,6 +122,12 @@ char cli_getc(Cli* cli); */ void cli_nl(); +void cli_session_open(Cli* cli, void* session); + +void cli_session_close(Cli* cli); + +bool cli_is_connected(Cli* cli); + #ifdef __cplusplus } #endif diff --git a/applications/cli/cli_i.h b/applications/cli/cli_i.h index c645f1a3..feb3bcb7 100755 --- a/applications/cli/cli_i.h +++ b/applications/cli/cli_i.h @@ -18,6 +18,17 @@ typedef struct { uint32_t flags; } CliCommand; +typedef struct CliSession CliSession; + +struct CliSession { + void (*init)(void); + void (*deinit)(void); + size_t (*rx)(uint8_t* buffer, size_t size, uint32_t timeout); + void (*tx)(const uint8_t* buffer, size_t size); + void (*tx_stdout)(void* _cookie, const char* data, size_t size); + bool (*is_connected)(void); +}; + BPTREE_DEF2( CliCommandTree, CLI_COMMANDS_TREE_RANK, @@ -31,18 +42,18 @@ BPTREE_DEF2( struct Cli { CliCommandTree_t commands; osMutexId_t mutex; + osSemaphoreId_t idle_sem; string_t last_line; string_t line; + CliSession* session; size_t cursor_position; }; Cli* cli_alloc(); -void cli_free(Cli* cli); - void cli_reset(Cli* cli); -void cli_putc(char c); +void cli_putc(Cli* cli, char c); void cli_stdout_callback(void* _cookie, const char* data, size_t size); diff --git a/firmware/targets/f7/furi_hal/furi_hal_vcp.c b/applications/cli/cli_vcp.c similarity index 69% rename from firmware/targets/f7/furi_hal/furi_hal_vcp.c rename to applications/cli/cli_vcp.c index ac8ee730..f570aee1 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_vcp.c +++ b/applications/cli/cli_vcp.c @@ -2,8 +2,9 @@ #include #include #include +#include "cli_i.h" -#define TAG "FuriHalVcp" +#define TAG "CliVcp" #define USB_CDC_PKT_LEN CDC_DATA_SZ #define VCP_RX_BUF_SIZE (USB_CDC_PKT_LEN * 3) @@ -12,19 +13,18 @@ #define VCP_IF_NUM 0 typedef enum { - VcpEvtEnable = (1 << 0), - VcpEvtDisable = (1 << 1), - VcpEvtConnect = (1 << 2), - VcpEvtDisconnect = (1 << 3), - VcpEvtStreamRx = (1 << 4), - VcpEvtRx = (1 << 5), - VcpEvtStreamTx = (1 << 6), - VcpEvtTx = (1 << 7), + VcpEvtStop = (1 << 0), + VcpEvtConnect = (1 << 1), + VcpEvtDisconnect = (1 << 2), + VcpEvtStreamRx = (1 << 3), + VcpEvtRx = (1 << 4), + VcpEvtStreamTx = (1 << 5), + VcpEvtTx = (1 << 6), } WorkerEvtFlags; -#define VCP_THREAD_FLAG_ALL \ - (VcpEvtEnable | VcpEvtDisable | VcpEvtConnect | VcpEvtDisconnect | VcpEvtRx | VcpEvtTx | \ - VcpEvtStreamRx | VcpEvtStreamTx) +#define VCP_THREAD_FLAG_ALL \ + (VcpEvtStop | VcpEvtConnect | VcpEvtDisconnect | VcpEvtRx | VcpEvtTx | VcpEvtStreamRx | \ + VcpEvtStreamTx) typedef struct { FuriThread* thread; @@ -33,9 +33,12 @@ typedef struct { StreamBufferHandle_t rx_stream; volatile bool connected; + volatile bool running; + + FuriHalUsbInterface* usb_if_prev; uint8_t data_buffer[USB_CDC_PKT_LEN]; -} FuriHalVcp; +} CliVcp; static int32_t vcp_worker(void* context); static void vcp_on_cdc_tx_complete(void* context); @@ -51,25 +54,23 @@ static CdcCallbacks cdc_cb = { NULL, }; -static FuriHalVcp* vcp = NULL; +static CliVcp* vcp = NULL; static const uint8_t ascii_soh = 0x01; static const uint8_t ascii_eot = 0x04; -void furi_hal_vcp_init() { - vcp = malloc(sizeof(FuriHalVcp)); +static void cli_vcp_init() { + if(vcp == NULL) { + vcp = malloc(sizeof(CliVcp)); + vcp->tx_stream = xStreamBufferCreate(VCP_TX_BUF_SIZE, 1); + vcp->rx_stream = xStreamBufferCreate(VCP_RX_BUF_SIZE, 1); + } + furi_assert(vcp->thread == NULL); + vcp->connected = false; - vcp->tx_stream = xStreamBufferCreate(VCP_TX_BUF_SIZE, 1); - vcp->rx_stream = xStreamBufferCreate(VCP_RX_BUF_SIZE, 1); - - if(furi_hal_rtc_get_boot_mode() != FuriHalRtcBootModeNormal) { - FURI_LOG_W(TAG, "Skipped worker init: device in special startup mode"); - return; - } - vcp->thread = furi_thread_alloc(); - furi_thread_set_name(vcp->thread, "VcpDriver"); + furi_thread_set_name(vcp->thread, "CliVcpWorker"); furi_thread_set_stack_size(vcp->thread, 1024); furi_thread_set_callback(vcp->thread, vcp_worker); furi_thread_start(vcp->thread); @@ -77,48 +78,35 @@ void furi_hal_vcp_init() { FURI_LOG_I(TAG, "Init OK"); } +static void cli_vcp_deinit() { + osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtStop); + furi_thread_join(vcp->thread); + furi_thread_free(vcp->thread); + vcp->thread = NULL; +} + static int32_t vcp_worker(void* context) { - bool enabled = true; - bool tx_idle = false; + bool tx_idle = true; size_t missed_rx = 0; uint8_t last_tx_pkt_len = 0; - furi_hal_usb_set_config(&usb_cdc_single, NULL); + // Switch USB to VCP mode (if it is not set yet) + vcp->usb_if_prev = furi_hal_usb_get_config(); + if((vcp->usb_if_prev != &usb_cdc_single) && (vcp->usb_if_prev != &usb_cdc_dual)) { + furi_hal_usb_set_config(&usb_cdc_single, NULL); + } furi_hal_cdc_set_callbacks(VCP_IF_NUM, &cdc_cb, NULL); + FURI_LOG_D(TAG, "Start"); + vcp->running = true; + while(1) { uint32_t flags = osThreadFlagsWait(VCP_THREAD_FLAG_ALL, osFlagsWaitAny, osWaitForever); furi_assert((flags & osFlagsError) == 0); - // VCP enabled - if((flags & VcpEvtEnable) && !enabled) { -#ifdef FURI_HAL_USB_VCP_DEBUG - FURI_LOG_D(TAG, "Enable"); -#endif - flags |= VcpEvtTx; - furi_hal_cdc_set_callbacks(VCP_IF_NUM, &cdc_cb, NULL); - enabled = true; - furi_hal_cdc_receive(VCP_IF_NUM, vcp->data_buffer, USB_CDC_PKT_LEN); // flush Rx buffer - if(furi_hal_cdc_get_ctrl_line_state(VCP_IF_NUM) & (1 << 0)) { - vcp->connected = true; - xStreamBufferSend(vcp->rx_stream, &ascii_soh, 1, osWaitForever); - } - } - - // VCP disabled - if((flags & VcpEvtDisable) && enabled) { -#ifdef FURI_HAL_USB_VCP_DEBUG - FURI_LOG_D(TAG, "Disable"); -#endif - enabled = false; - vcp->connected = false; - xStreamBufferReceive(vcp->tx_stream, vcp->data_buffer, USB_CDC_PKT_LEN, 0); - xStreamBufferSend(vcp->rx_stream, &ascii_eot, 1, osWaitForever); - } - // VCP session opened - if((flags & VcpEvtConnect) && enabled) { -#ifdef FURI_HAL_USB_VCP_DEBUG + if(flags & VcpEvtConnect) { +#ifdef CLI_VCP_DEBUG FURI_LOG_D(TAG, "Connect"); #endif if(vcp->connected == false) { @@ -128,8 +116,8 @@ static int32_t vcp_worker(void* context) { } // VCP session closed - if((flags & VcpEvtDisconnect) && enabled) { -#ifdef FURI_HAL_USB_VCP_DEBUG + if(flags & VcpEvtDisconnect) { +#ifdef CLI_VCP_DEBUG FURI_LOG_D(TAG, "Disconnect"); #endif if(vcp->connected == true) { @@ -140,8 +128,8 @@ static int32_t vcp_worker(void* context) { } // Rx buffer was read, maybe there is enough space for new data? - if((flags & VcpEvtStreamRx) && enabled && missed_rx > 0) { -#ifdef FURI_HAL_USB_VCP_DEBUG + if((flags & VcpEvtStreamRx) && (missed_rx > 0)) { +#ifdef CLI_VCP_DEBUG FURI_LOG_D(TAG, "StreamRx"); #endif if(xStreamBufferSpacesAvailable(vcp->rx_stream) >= USB_CDC_PKT_LEN) { @@ -151,10 +139,10 @@ static int32_t vcp_worker(void* context) { } // New data received - if((flags & VcpEvtRx)) { + if(flags & VcpEvtRx) { if(xStreamBufferSpacesAvailable(vcp->rx_stream) >= USB_CDC_PKT_LEN) { int32_t len = furi_hal_cdc_receive(VCP_IF_NUM, vcp->data_buffer, USB_CDC_PKT_LEN); -#ifdef FURI_HAL_USB_VCP_DEBUG +#ifdef CLI_VCP_DEBUG FURI_LOG_D(TAG, "Rx %d", len); #endif if(len > 0) { @@ -163,7 +151,7 @@ static int32_t vcp_worker(void* context) { len); } } else { -#ifdef FURI_HAL_USB_VCP_DEBUG +#ifdef CLI_VCP_DEBUG FURI_LOG_D(TAG, "Rx missed"); #endif missed_rx++; @@ -171,8 +159,8 @@ static int32_t vcp_worker(void* context) { } // New data in Tx buffer - if((flags & VcpEvtStreamTx) && enabled) { -#ifdef FURI_HAL_USB_VCP_DEBUG + if(flags & VcpEvtStreamTx) { +#ifdef CLI_VCP_DEBUG FURI_LOG_D(TAG, "StreamTx"); #endif if(tx_idle) { @@ -181,10 +169,10 @@ static int32_t vcp_worker(void* context) { } // CDC write transfer done - if((flags & VcpEvtTx) && enabled) { + if(flags & VcpEvtTx) { size_t len = xStreamBufferReceive(vcp->tx_stream, vcp->data_buffer, USB_CDC_PKT_LEN, 0); -#ifdef FURI_HAL_USB_VCP_DEBUG +#ifdef CLI_VCP_DEBUG FURI_LOG_D(TAG, "Tx %d", len); #endif if(len > 0) { // Some data left in Tx buffer. Sending it now @@ -202,23 +190,33 @@ static int32_t vcp_worker(void* context) { last_tx_pkt_len = 0; } } + + if(flags & VcpEvtStop) { + vcp->connected = false; + vcp->running = false; + furi_hal_cdc_set_callbacks(VCP_IF_NUM, NULL, NULL); + // Restore previous USB mode (if it was set during init) + if((vcp->usb_if_prev != &usb_cdc_single) && (vcp->usb_if_prev != &usb_cdc_dual)) { + furi_hal_usb_set_config(vcp->usb_if_prev, NULL); + } + xStreamBufferReceive(vcp->tx_stream, vcp->data_buffer, USB_CDC_PKT_LEN, 0); + xStreamBufferSend(vcp->rx_stream, &ascii_eot, 1, osWaitForever); + break; + } } + FURI_LOG_D(TAG, "End"); return 0; } -void furi_hal_vcp_enable() { - osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtEnable); -} - -void furi_hal_vcp_disable() { - osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtDisable); -} - -size_t furi_hal_vcp_rx_with_timeout(uint8_t* buffer, size_t size, uint32_t timeout) { +static size_t cli_vcp_rx(uint8_t* buffer, size_t size, uint32_t timeout) { furi_assert(vcp); furi_assert(buffer); -#ifdef FURI_HAL_USB_VCP_DEBUG + if(vcp->running == false) { + return 0; + } + +#ifdef CLI_VCP_DEBUG FURI_LOG_D(TAG, "rx %u start", size); #endif @@ -229,7 +227,7 @@ size_t furi_hal_vcp_rx_with_timeout(uint8_t* buffer, size_t size, uint32_t timeo if(batch_size > VCP_RX_BUF_SIZE) batch_size = VCP_RX_BUF_SIZE; size_t len = xStreamBufferReceive(vcp->rx_stream, buffer, batch_size, timeout); -#ifdef FURI_HAL_USB_VCP_DEBUG +#ifdef CLI_VCP_DEBUG FURI_LOG_D(TAG, "rx %u ", batch_size); #endif if(len == 0) break; @@ -239,22 +237,21 @@ size_t furi_hal_vcp_rx_with_timeout(uint8_t* buffer, size_t size, uint32_t timeo rx_cnt += len; } -#ifdef FURI_HAL_USB_VCP_DEBUG +#ifdef CLI_VCP_DEBUG FURI_LOG_D(TAG, "rx %u end", size); #endif return rx_cnt; } -size_t furi_hal_vcp_rx(uint8_t* buffer, size_t size) { - furi_assert(vcp); - return furi_hal_vcp_rx_with_timeout(buffer, size, osWaitForever); -} - -void furi_hal_vcp_tx(const uint8_t* buffer, size_t size) { +static void cli_vcp_tx(const uint8_t* buffer, size_t size) { furi_assert(vcp); furi_assert(buffer); -#ifdef FURI_HAL_USB_VCP_DEBUG + if(vcp->running == false) { + return; + } + +#ifdef CLI_VCP_DEBUG FURI_LOG_D(TAG, "tx %u start", size); #endif @@ -264,7 +261,7 @@ void furi_hal_vcp_tx(const uint8_t* buffer, size_t size) { xStreamBufferSend(vcp->tx_stream, buffer, batch_size, osWaitForever); osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtStreamTx); -#ifdef FURI_HAL_USB_VCP_DEBUG +#ifdef CLI_VCP_DEBUG FURI_LOG_D(TAG, "tx %u", batch_size); #endif @@ -272,11 +269,15 @@ void furi_hal_vcp_tx(const uint8_t* buffer, size_t size) { buffer += batch_size; } -#ifdef FURI_HAL_USB_VCP_DEBUG +#ifdef CLI_VCP_DEBUG FURI_LOG_D(TAG, "tx %u end", size); #endif } +static void cli_vcp_tx_stdout(void* _cookie, const char* data, size_t size) { + cli_vcp_tx((const uint8_t*)data, size); +} + static void vcp_state_callback(void* context, uint8_t state) { if(state == 0) { osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtDisconnect); @@ -303,7 +304,16 @@ static void vcp_on_cdc_tx_complete(void* context) { osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtTx); } -bool furi_hal_vcp_is_connected(void) { +static bool cli_vcp_is_connected(void) { furi_assert(vcp); return vcp->connected; } + +CliSession cli_vcp = { + cli_vcp_init, + cli_vcp_deinit, + cli_vcp_rx, + cli_vcp_tx, + cli_vcp_tx_stdout, + cli_vcp_is_connected, +}; diff --git a/applications/cli/cli_vcp.h b/applications/cli/cli_vcp.h new file mode 100644 index 00000000..2bd47efb --- /dev/null +++ b/applications/cli/cli_vcp.h @@ -0,0 +1,18 @@ +/** + * @file cli_vcp.h + * VCP HAL API + */ + +#pragma once + +#include "cli_i.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern CliSession cli_vcp; + +#ifdef __cplusplus +} +#endif diff --git a/applications/desktop/desktop_settings/desktop_settings.h b/applications/desktop/desktop_settings/desktop_settings.h index e096288d..85beb503 100644 --- a/applications/desktop/desktop_settings/desktop_settings.h +++ b/applications/desktop/desktop_settings/desktop_settings.h @@ -5,7 +5,7 @@ #include #include -#define DESKTOP_SETTINGS_VER (2) +#define DESKTOP_SETTINGS_VER (3) #define DESKTOP_SETTINGS_PATH "/int/desktop.settings" #define DESKTOP_SETTINGS_MAGIC (0x17) #define PIN_MAX_LENGTH 12 @@ -39,5 +39,6 @@ typedef struct { typedef struct { uint16_t favorite; PinCode pin_code; + uint8_t is_locked; uint32_t auto_lock_delay_ms; } DesktopSettings; diff --git a/applications/desktop/helpers/pin_lock.c b/applications/desktop/helpers/pin_lock.c index 8da238bd..4956c6cc 100644 --- a/applications/desktop/helpers/pin_lock.c +++ b/applications/desktop/helpers/pin_lock.c @@ -8,6 +8,7 @@ #include "../helpers/pin_lock.h" #include "../desktop_i.h" +#include static const NotificationSequence sequence_pin_fail = { &message_display_on, @@ -61,26 +62,50 @@ uint32_t desktop_pin_lock_get_fail_timeout() { return pin_timeout; } -void desktop_pin_lock() { +void desktop_pin_lock(DesktopSettings* settings) { + furi_assert(settings); + furi_hal_rtc_set_pin_fails(0); furi_hal_rtc_set_flag(FuriHalRtcFlagLock); - furi_hal_usb_disable(); + Cli* cli = furi_record_open("cli"); + cli_session_close(cli); + furi_record_close("cli"); + settings->is_locked = 1; + SAVE_DESKTOP_SETTINGS(settings); } -void desktop_pin_unlock() { +void desktop_pin_unlock(DesktopSettings* settings) { + furi_assert(settings); + furi_hal_rtc_reset_flag(FuriHalRtcFlagLock); - furi_hal_usb_enable(); + Cli* cli = furi_record_open("cli"); + cli_session_open(cli, &cli_vcp); + furi_record_close("cli"); + settings->is_locked = 0; + SAVE_DESKTOP_SETTINGS(settings); } void desktop_pin_lock_init(DesktopSettings* settings) { + furi_assert(settings); + if(settings->pin_code.length > 0) { - furi_hal_rtc_set_flag(FuriHalRtcFlagLock); - furi_hal_usb_disable(); + if(settings->is_locked == 1) { + furi_hal_rtc_set_flag(FuriHalRtcFlagLock); + } else { + if(desktop_pin_lock_is_locked()) { + settings->is_locked = 1; + SAVE_DESKTOP_SETTINGS(settings); + } + } } else { furi_hal_rtc_set_pin_fails(0); furi_hal_rtc_reset_flag(FuriHalRtcFlagLock); furi_hal_usb_enable(); } + + if(desktop_pin_lock_is_locked()) { + furi_hal_usb_disable(); + } } bool desktop_pin_lock_verify(const PinCode* pin_set, const PinCode* pin_entered) { diff --git a/applications/desktop/helpers/pin_lock.h b/applications/desktop/helpers/pin_lock.h index e99ef9f3..4454cda5 100644 --- a/applications/desktop/helpers/pin_lock.h +++ b/applications/desktop/helpers/pin_lock.h @@ -8,9 +8,9 @@ void desktop_pin_lock_error_notify(); uint32_t desktop_pin_lock_get_fail_timeout(); -void desktop_pin_lock(); +void desktop_pin_lock(DesktopSettings* settings); -void desktop_pin_unlock(); +void desktop_pin_unlock(DesktopSettings* settings); bool desktop_pin_lock_is_locked(); diff --git a/applications/desktop/scenes/desktop_scene_lock_menu.c b/applications/desktop/scenes/desktop_scene_lock_menu.c index b11b90a3..11478810 100644 --- a/applications/desktop/scenes/desktop_scene_lock_menu.c +++ b/applications/desktop/scenes/desktop_scene_lock_menu.c @@ -54,7 +54,7 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) { break; case DesktopLockMenuEventPinLock: if(desktop->settings.pin_code.length > 0) { - desktop_pin_lock(); + desktop_pin_lock(&desktop->settings); desktop_lock(desktop); } else { LoaderStatus status = diff --git a/applications/desktop/scenes/desktop_scene_pin_input.c b/applications/desktop/scenes/desktop_scene_pin_input.c index 156a5eb2..7f9d8fcf 100644 --- a/applications/desktop/scenes/desktop_scene_pin_input.c +++ b/applications/desktop/scenes/desktop_scene_pin_input.c @@ -126,7 +126,7 @@ bool desktop_scene_pin_input_on_event(void* context, SceneManagerEvent event) { consumed = true; break; case DesktopPinInputEventUnlocked: - desktop_pin_unlock(); + desktop_pin_unlock(&desktop->settings); desktop_unlock(desktop); consumed = true; break; diff --git a/applications/dolphin/helpers/dolphin_state.c b/applications/dolphin/helpers/dolphin_state.c index bfd467b8..86287a2a 100644 --- a/applications/dolphin/helpers/dolphin_state.c +++ b/applications/dolphin/helpers/dolphin_state.c @@ -148,7 +148,7 @@ void dolphin_state_on_deed(DolphinState* dolphin_state, DolphinDeed deed) { dolphin_deed_get_app_limit(app) - dolphin_state->data.icounter_daily_limit[app]; uint8_t deed_weight = CLAMP(dolphin_deed_get_weight(deed), weight_limit, 0); - uint8_t xp_to_levelup = dolphin_state_xp_to_levelup(dolphin_state->data.icounter); + uint32_t xp_to_levelup = dolphin_state_xp_to_levelup(dolphin_state->data.icounter); if(xp_to_levelup) { deed_weight = MIN(xp_to_levelup, deed_weight); dolphin_state->data.icounter += deed_weight; diff --git a/applications/gpio/usb_uart_bridge.c b/applications/gpio/usb_uart_bridge.c index c33f97b1..8f27340e 100644 --- a/applications/gpio/usb_uart_bridge.c +++ b/applications/gpio/usb_uart_bridge.c @@ -3,6 +3,8 @@ #include #include #include "usb_cdc.h" +#include "cli/cli_vcp.h" +#include "cli/cli.h" #define USB_CDC_PKT_LEN CDC_DATA_SZ #define USB_UART_RX_BUF_SIZE (USB_CDC_PKT_LEN * 5) @@ -16,17 +18,16 @@ static const GpioPin* flow_pins[][2] = { }; typedef enum { - WorkerEvtReserved = (1 << 0), // Reserved for StreamBuffer internal event - WorkerEvtStop = (1 << 1), - WorkerEvtRxDone = (1 << 2), + WorkerEvtStop = (1 << 0), + WorkerEvtRxDone = (1 << 1), - WorkerEvtTxStop = (1 << 3), - WorkerEvtCdcRx = (1 << 4), + WorkerEvtTxStop = (1 << 2), + WorkerEvtCdcRx = (1 << 3), - WorkerEvtCfgChange = (1 << 5), + WorkerEvtCfgChange = (1 << 4), - WorkerEvtLineCfgSet = (1 << 6), - WorkerEvtCtrlLineSet = (1 << 7), + WorkerEvtLineCfgSet = (1 << 5), + WorkerEvtCtrlLineSet = (1 << 6), } WorkerEvtFlags; @@ -84,18 +85,29 @@ static void usb_uart_on_irq_cb(UartIrqEvent ev, uint8_t data, void* context) { static void usb_uart_vcp_init(UsbUartBridge* usb_uart, uint8_t vcp_ch) { furi_hal_usb_unlock(); + FURI_LOG_I("", "Init %d", vcp_ch); if(vcp_ch == 0) { + Cli* cli = furi_record_open("cli"); + cli_session_close(cli); + furi_record_close("cli"); furi_check(furi_hal_usb_set_config(&usb_cdc_single, NULL) == true); - furi_hal_vcp_disable(); } else { furi_check(furi_hal_usb_set_config(&usb_cdc_dual, NULL) == true); + Cli* cli = furi_record_open("cli"); + cli_session_open(cli, &cli_vcp); + furi_record_close("cli"); } furi_hal_cdc_set_callbacks(vcp_ch, (CdcCallbacks*)&cdc_cb, usb_uart); } static void usb_uart_vcp_deinit(UsbUartBridge* usb_uart, uint8_t vcp_ch) { furi_hal_cdc_set_callbacks(vcp_ch, NULL, NULL); - if(vcp_ch == 0) furi_hal_vcp_enable(); + FURI_LOG_I("", "Deinit %d", vcp_ch); + if(vcp_ch != 0) { + Cli* cli = furi_record_open("cli"); + cli_session_close(cli); + furi_record_close("cli"); + } } static void usb_uart_serial_init(UsbUartBridge* usb_uart, uint8_t uart_ch) { @@ -155,7 +167,6 @@ static int32_t usb_uart_worker(void* context) { furi_thread_set_context(usb_uart->tx_thread, usb_uart); furi_thread_set_callback(usb_uart->tx_thread, usb_uart_tx_thread); - FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config(); usb_uart_vcp_init(usb_uart, usb_uart->cfg.vcp_ch); usb_uart_serial_init(usb_uart, usb_uart->cfg.uart_ch); usb_uart_set_baudrate(usb_uart, usb_uart->cfg.baudrate); @@ -247,11 +258,9 @@ static int32_t usb_uart_worker(void* context) { usb_uart_update_ctrl_lines(usb_uart); } } - usb_uart_vcp_deinit(usb_uart, usb_uart->cfg.vcp_ch); usb_uart_serial_deinit(usb_uart, usb_uart->cfg.uart_ch); - furi_hal_usb_unlock(); - furi_hal_usb_set_config(usb_mode_prev, NULL); + if(usb_uart->cfg.flow_pins != 0) { furi_hal_gpio_init_simple(flow_pins[usb_uart->cfg.flow_pins - 1][0], GpioModeAnalog); furi_hal_gpio_init_simple(flow_pins[usb_uart->cfg.flow_pins - 1][1], GpioModeAnalog); @@ -265,6 +274,12 @@ static int32_t usb_uart_worker(void* context) { osMutexDelete(usb_uart->usb_mutex); osSemaphoreDelete(usb_uart->tx_sem); + furi_hal_usb_unlock(); + furi_check(furi_hal_usb_set_config(&usb_cdc_single, NULL) == true); + Cli* cli = furi_record_open("cli"); + cli_session_open(cli, &cli_vcp); + furi_record_close("cli"); + return 0; } diff --git a/applications/rpc/rpc_cli.c b/applications/rpc/rpc_cli.c index fd1f6e7f..b9304367 100644 --- a/applications/rpc/rpc_cli.c +++ b/applications/rpc/rpc_cli.c @@ -62,8 +62,8 @@ void rpc_cli_command_start_session(Cli* cli, string_t args, void* context) { size_t size_received = 0; while(1) { - size_received = furi_hal_vcp_rx_with_timeout(buffer, CLI_READ_BUFFER_SIZE, 50); - if(!furi_hal_vcp_is_connected() || cli_rpc.session_close_request) { + size_received = cli_read_timeout(cli_rpc.cli, buffer, CLI_READ_BUFFER_SIZE, 50); + if(!cli_is_connected(cli_rpc.cli) || cli_rpc.session_close_request) { break; } diff --git a/applications/subghz/helpers/subghz_chat.c b/applications/subghz/helpers/subghz_chat.c index 30618813..e6b7b7bc 100644 --- a/applications/subghz/helpers/subghz_chat.c +++ b/applications/subghz/helpers/subghz_chat.c @@ -12,6 +12,8 @@ struct SubGhzChatWorker { volatile bool worker_stoping; osMessageQueueId_t event_queue; uint32_t last_time_rx_data; + + Cli* cli; }; /** Worker thread @@ -27,7 +29,7 @@ static int32_t subghz_chat_worker_thread(void* context) { event.event = SubGhzChatEventUserEntrance; osMessageQueuePut(instance->event_queue, &event, 0, 0); while(instance->worker_running) { - if(furi_hal_vcp_rx_with_timeout((uint8_t*)&c, 1, 1000) == 1) { + if(cli_read_timeout(instance->cli, (uint8_t*)&c, 1, 1000) == 1) { event.event = SubGhzChatEventInputData; event.c = c; osMessageQueuePut(instance->event_queue, &event, 0, osWaitForever); @@ -52,9 +54,11 @@ static void subghz_chat_worker_update_rx_event_chat(void* context) { osMessageQueuePut(instance->event_queue, &event, 0, osWaitForever); } -SubGhzChatWorker* subghz_chat_worker_alloc() { +SubGhzChatWorker* subghz_chat_worker_alloc(Cli* cli) { SubGhzChatWorker* instance = malloc(sizeof(SubGhzChatWorker)); + instance->cli = cli; + instance->thread = furi_thread_alloc(); furi_thread_set_name(instance->thread, "SubGhzChat"); furi_thread_set_stack_size(instance->thread, 2048); diff --git a/applications/subghz/helpers/subghz_chat.h b/applications/subghz/helpers/subghz_chat.h index 6556d0c3..b418bbdb 100644 --- a/applications/subghz/helpers/subghz_chat.h +++ b/applications/subghz/helpers/subghz_chat.h @@ -1,5 +1,6 @@ #pragma once #include "../subghz_i.h" +#include typedef struct SubGhzChatWorker SubGhzChatWorker; @@ -17,7 +18,7 @@ typedef struct { char c; } SubGhzChatEvent; -SubGhzChatWorker* subghz_chat_worker_alloc(); +SubGhzChatWorker* subghz_chat_worker_alloc(Cli* cli); void subghz_chat_worker_free(SubGhzChatWorker* instance); bool subghz_chat_worker_start(SubGhzChatWorker* instance, uint32_t frequency); void subghz_chat_worker_stop(SubGhzChatWorker* instance); diff --git a/applications/subghz/subghz_cli.c b/applications/subghz/subghz_cli.c index 6928c4ba..65ea0cf2 100644 --- a/applications/subghz/subghz_cli.c +++ b/applications/subghz/subghz_cli.c @@ -525,7 +525,7 @@ static void subghz_cli_command_chat(Cli* cli, string_t args) { return; } - SubGhzChatWorker* subghz_chat = subghz_chat_worker_alloc(); + SubGhzChatWorker* subghz_chat = subghz_chat_worker_alloc(cli); if(!subghz_chat_worker_start(subghz_chat, frequency)) { printf("Startup error SubGhzChatWorker\r\n"); diff --git a/firmware/targets/f7/furi_hal/furi_hal_usb.c b/firmware/targets/f7/furi_hal/furi_hal_usb.c index f1044c36..7032d059 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_usb.c +++ b/firmware/targets/f7/furi_hal/furi_hal_usb.c @@ -1,7 +1,6 @@ #include "furi_hal_version.h" #include "furi_hal_usb_i.h" #include "furi_hal_usb.h" -#include "furi_hal_vcp.h" #include #include #include diff --git a/firmware/targets/f7/furi_hal/furi_hal_usb_cdc.c b/firmware/targets/f7/furi_hal/furi_hal_usb_cdc.c index 028e3e30..807f1634 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_usb_cdc.c +++ b/firmware/targets/f7/furi_hal/furi_hal_usb_cdc.c @@ -482,6 +482,9 @@ void furi_hal_cdc_set_callbacks(uint8_t if_num, CdcCallbacks* cb, void* context) if(callbacks[if_num]->state_callback != NULL) { if(connected == true) callbacks[if_num]->state_callback(cb_ctx[if_num], 1); } + if(callbacks[if_num]->ctrl_line_callback != NULL) { + callbacks[if_num]->ctrl_line_callback(cb_ctx[if_num], cdc_ctrl_line_state[if_num]); + } } } diff --git a/firmware/targets/furi_hal_include/furi_hal.h b/firmware/targets/furi_hal_include/furi_hal.h index a1e4a90f..8480f884 100644 --- a/firmware/targets/furi_hal_include/furi_hal.h +++ b/firmware/targets/furi_hal_include/furi_hal.h @@ -22,7 +22,6 @@ template struct STOP_EXTERNING_ME {}; #include "furi_hal_light.h" #include "furi_hal_delay.h" #include "furi_hal_power.h" -#include "furi_hal_vcp.h" #include "furi_hal_interrupt.h" #include "furi_hal_version.h" #include "furi_hal_bt.h" diff --git a/firmware/targets/furi_hal_include/furi_hal_vcp.h b/firmware/targets/furi_hal_include/furi_hal_vcp.h deleted file mode 100644 index ef5c18f9..00000000 --- a/firmware/targets/furi_hal_include/furi_hal_vcp.h +++ /dev/null @@ -1,63 +0,0 @@ -/** - * @file furi_hal_vcp.h - * VCP HAL API - */ - -#pragma once - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** Init VCP HAL Allocates ring buffer and initializes state - */ -void furi_hal_vcp_init(); - -/** Disable VCP to make CDC interface usable by other application - */ -void furi_hal_vcp_disable(); - -/** Enable VCP - */ -void furi_hal_vcp_enable(); - -/** Recieve data from VCP Waits till some data arrives, never returns 0 - * - * @param buffer pointer to buffer - * @param size buffer size - * - * @return items copied in buffer, 0 if channel closed - */ -size_t furi_hal_vcp_rx(uint8_t* buffer, size_t size); - -/** Recieve data from VCP with timeout Waits till some data arrives during - * timeout - * - * @param buffer pointer to buffer - * @param size buffer size - * @param timeout rx timeout in ms - * - * @return items copied in buffer, 0 if channel closed or timeout occurs - */ -size_t furi_hal_vcp_rx_with_timeout(uint8_t* buffer, size_t size, uint32_t timeout); - -/** Transmit data to VCP - * - * @param buffer pointer to buffer - * @param size buffer size - */ -void furi_hal_vcp_tx(const uint8_t* buffer, size_t size); - -/** Check whether VCP is connected - * - * @return true if connected - */ -bool furi_hal_vcp_is_connected(void); - -#ifdef __cplusplus -} -#endif