[FL-2163] CLI: Separate session from CLI service (#1130)
* CLI: session refactoring * Added forgotten define * Desktop lock state save * Dolphin: use proper type for value returned by dolphin_state_xp_to_levelup Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									76221021ec
								
							
						
					
					
						commit
						0eac917f91
					
				| @ -1,9 +1,11 @@ | ||||
| #include "cli_i.h" | ||||
| #include "cli_commands.h" | ||||
| 
 | ||||
| #include "cli_vcp.h" | ||||
| #include <furi_hal_version.h> | ||||
| #include <loader/loader.h> | ||||
| 
 | ||||
| #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); | ||||
|     if(cli->session != NULL) { | ||||
|         cli->session->tx((uint8_t*)&c, 1); | ||||
|     } | ||||
| 
 | ||||
| void cli_putc(char c) { | ||||
|     furi_hal_vcp_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) { | ||||
|     if(cli->session != NULL) { | ||||
|         if(cli->session->rx((uint8_t*)&c, 1, 0) == 1) { | ||||
|             return c == CliSymbolAsciiETX; | ||||
|     } else { | ||||
|         } | ||||
|     } | ||||
|     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) { | ||||
|         if(cli->session != NULL) { | ||||
|             cli_process_input(cli); | ||||
|         } else { | ||||
|             furi_check(osSemaphoreAcquire(cli->idle_sem, osWaitForever) == osOK); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return 0; | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -2,8 +2,9 @@ | ||||
| #include <furi_hal.h> | ||||
| #include <furi.h> | ||||
| #include <stream_buffer.h> | ||||
| #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) | ||||
|     (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)); | ||||
|     vcp->connected = false; | ||||
| 
 | ||||
| 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); | ||||
| 
 | ||||
|     if(furi_hal_rtc_get_boot_mode() != FuriHalRtcBootModeNormal) { | ||||
|         FURI_LOG_W(TAG, "Skipped worker init: device in special startup mode"); | ||||
|         return; | ||||
|     } | ||||
|     furi_assert(vcp->thread == NULL); | ||||
| 
 | ||||
|     vcp->connected = false; | ||||
| 
 | ||||
|     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; | ||||
| 
 | ||||
|     // 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, | ||||
| }; | ||||
							
								
								
									
										18
									
								
								applications/cli/cli_vcp.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								applications/cli/cli_vcp.h
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||
| @ -5,7 +5,7 @@ | ||||
| #include <stdbool.h> | ||||
| #include <toolbox/saved_struct.h> | ||||
| 
 | ||||
| #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; | ||||
|  | ||||
| @ -8,6 +8,7 @@ | ||||
| 
 | ||||
| #include "../helpers/pin_lock.h" | ||||
| #include "../desktop_i.h" | ||||
| #include <cli/cli_vcp.h> | ||||
| 
 | ||||
| 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) { | ||||
|         if(settings->is_locked == 1) { | ||||
|             furi_hal_rtc_set_flag(FuriHalRtcFlagLock); | ||||
|         furi_hal_usb_disable(); | ||||
|         } 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) { | ||||
|  | ||||
| @ -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(); | ||||
| 
 | ||||
|  | ||||
| @ -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 = | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -3,6 +3,8 @@ | ||||
| #include <stream_buffer.h> | ||||
| #include <furi_hal_usb_cdc_i.h> | ||||
| #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; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -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; | ||||
|         } | ||||
| 
 | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| #pragma once | ||||
| #include "../subghz_i.h" | ||||
| #include <cli/cli.h> | ||||
| 
 | ||||
| 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); | ||||
|  | ||||
| @ -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"); | ||||
| 
 | ||||
|  | ||||
| @ -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 <furi_hal_power.h> | ||||
| #include <stm32wbxx_ll_pwr.h> | ||||
| #include <furi.h> | ||||
|  | ||||
| @ -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]); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -22,7 +22,6 @@ template <unsigned int N> 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" | ||||
|  | ||||
| @ -1,63 +0,0 @@ | ||||
| /**
 | ||||
|  * @file furi_hal_vcp.h | ||||
|  * VCP HAL API | ||||
|  */ | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <stdbool.h> | ||||
| #include <stdint.h> | ||||
| #include <string.h> | ||||
| 
 | ||||
| #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 | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Nikolay Minaylov
						Nikolay Minaylov