[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_i.h"
|
||||||
#include "cli_commands.h"
|
#include "cli_commands.h"
|
||||||
|
#include "cli_vcp.h"
|
||||||
#include <furi_hal_version.h>
|
#include <furi_hal_version.h>
|
||||||
#include <loader/loader.h>
|
#include <loader/loader.h>
|
||||||
|
|
||||||
|
#define TAG "CliSrv"
|
||||||
|
|
||||||
Cli* cli_alloc() {
|
Cli* cli_alloc() {
|
||||||
Cli* cli = malloc(sizeof(Cli));
|
Cli* cli = malloc(sizeof(Cli));
|
||||||
|
|
||||||
@ -12,55 +14,78 @@ Cli* cli_alloc() {
|
|||||||
string_init(cli->last_line);
|
string_init(cli->last_line);
|
||||||
string_init(cli->line);
|
string_init(cli->line);
|
||||||
|
|
||||||
|
cli->session = NULL;
|
||||||
|
|
||||||
cli->mutex = osMutexNew(NULL);
|
cli->mutex = osMutexNew(NULL);
|
||||||
furi_check(cli->mutex);
|
furi_check(cli->mutex);
|
||||||
|
|
||||||
|
cli->idle_sem = osSemaphoreNew(1, 0, NULL);
|
||||||
|
|
||||||
return cli;
|
return cli;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cli_free(Cli* cli) {
|
void cli_putc(Cli* cli, char c) {
|
||||||
furi_assert(cli);
|
furi_assert(cli);
|
||||||
|
if(cli->session != NULL) {
|
||||||
string_clear(cli->last_line);
|
cli->session->tx((uint8_t*)&c, 1);
|
||||||
string_clear(cli->line);
|
}
|
||||||
|
|
||||||
CliCommandTree_clear(cli->commands);
|
|
||||||
|
|
||||||
free(cli);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cli_putc(char c) {
|
|
||||||
furi_hal_vcp_tx((uint8_t*)&c, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char cli_getc(Cli* cli) {
|
char cli_getc(Cli* cli) {
|
||||||
furi_assert(cli);
|
furi_assert(cli);
|
||||||
char c;
|
char c = 0;
|
||||||
if(furi_hal_vcp_rx((uint8_t*)&c, 1) == 0) {
|
if(cli->session != NULL) {
|
||||||
|
if(cli->session->rx((uint8_t*)&c, 1, osWaitForever) == 0) {
|
||||||
|
cli_reset(cli);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
cli_reset(cli);
|
cli_reset(cli);
|
||||||
}
|
}
|
||||||
return c;
|
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) {
|
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) {
|
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) {
|
bool cli_cmd_interrupt_received(Cli* cli) {
|
||||||
|
furi_assert(cli);
|
||||||
char c = '\0';
|
char c = '\0';
|
||||||
if(furi_hal_vcp_rx_with_timeout((uint8_t*)&c, 1, 0) == 1) {
|
if(cli->session != NULL) {
|
||||||
return c == CliSymbolAsciiETX;
|
if(cli->session->rx((uint8_t*)&c, 1, 0) == 1) {
|
||||||
} else {
|
return c == CliSymbolAsciiETX;
|
||||||
return false;
|
}
|
||||||
}
|
}
|
||||||
|
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) {
|
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--;
|
cli->cursor_position--;
|
||||||
} else {
|
} else {
|
||||||
cli_putc(CliSymbolAsciiBell);
|
cli_putc(cli, CliSymbolAsciiBell);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,7 +235,7 @@ static void cli_handle_enter(Cli* cli) {
|
|||||||
printf(
|
printf(
|
||||||
"`%s` command not found, use `help` or `?` to list all available commands",
|
"`%s` command not found, use `help` or `?` to list all available commands",
|
||||||
string_get_cstr(command));
|
string_get_cstr(command));
|
||||||
cli_putc(CliSymbolAsciiBell);
|
cli_putc(cli, CliSymbolAsciiBell);
|
||||||
}
|
}
|
||||||
furi_check(osMutexRelease(cli->mutex) == osOK);
|
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) {
|
void cli_process_input(Cli* cli) {
|
||||||
char c = cli_getc(cli);
|
char in_chr = cli_getc(cli);
|
||||||
size_t r;
|
size_t rx_len;
|
||||||
|
|
||||||
if(c == CliSymbolAsciiTab) {
|
if(in_chr == CliSymbolAsciiTab) {
|
||||||
cli_handle_autocomplete(cli);
|
cli_handle_autocomplete(cli);
|
||||||
} else if(c == CliSymbolAsciiSOH) {
|
} else if(in_chr == CliSymbolAsciiSOH) {
|
||||||
osDelay(33); // We are too fast, Minicom is not ready yet
|
osDelay(33); // We are too fast, Minicom is not ready yet
|
||||||
cli_motd();
|
cli_motd();
|
||||||
cli_prompt(cli);
|
cli_prompt(cli);
|
||||||
} else if(c == CliSymbolAsciiETX) {
|
} else if(in_chr == CliSymbolAsciiETX) {
|
||||||
cli_reset(cli);
|
cli_reset(cli);
|
||||||
cli_prompt(cli);
|
cli_prompt(cli);
|
||||||
} else if(c == CliSymbolAsciiEOT) {
|
} else if(in_chr == CliSymbolAsciiEOT) {
|
||||||
cli_reset(cli);
|
cli_reset(cli);
|
||||||
} else if(c == CliSymbolAsciiEsc) {
|
} else if(in_chr == CliSymbolAsciiEsc) {
|
||||||
r = furi_hal_vcp_rx((uint8_t*)&c, 1);
|
rx_len = cli_read(cli, (uint8_t*)&in_chr, 1);
|
||||||
if(r && c == '[') {
|
if((rx_len > 0) && (in_chr == '[')) {
|
||||||
furi_hal_vcp_rx((uint8_t*)&c, 1);
|
cli_read(cli, (uint8_t*)&in_chr, 1);
|
||||||
cli_handle_escape(cli, c);
|
cli_handle_escape(cli, in_chr);
|
||||||
} else {
|
} 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);
|
cli_handle_backspace(cli);
|
||||||
} else if(c == CliSymbolAsciiCR) {
|
} else if(in_chr == CliSymbolAsciiCR) {
|
||||||
cli_handle_enter(cli);
|
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)) {
|
if(cli->cursor_position == string_size(cli->line)) {
|
||||||
string_push_back(cli->line, c);
|
string_push_back(cli->line, in_chr);
|
||||||
cli_putc(c);
|
cli_putc(cli, in_chr);
|
||||||
} else {
|
} else {
|
||||||
// ToDo: better way?
|
// ToDo: better way?
|
||||||
string_t temp;
|
string_t temp;
|
||||||
string_init(temp);
|
string_init(temp);
|
||||||
string_reserve(temp, string_size(cli->line) + 1);
|
string_reserve(temp, string_size(cli->line) + 1);
|
||||||
string_set_strn(temp, string_get_cstr(cli->line), cli->cursor_position);
|
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);
|
string_cat_str(temp, string_get_cstr(cli->line) + cli->cursor_position);
|
||||||
|
|
||||||
// cli->line is cleared and temp's buffer moved to cli->line
|
// 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
|
// NO MEMORY LEAK, STOP REPORTING IT
|
||||||
|
|
||||||
// Print character in replace mode
|
// Print character in replace mode
|
||||||
printf("\e[4h%c\e[4l", c);
|
printf("\e[4h%c\e[4l", in_chr);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
cli->cursor_position++;
|
cli->cursor_position++;
|
||||||
} else {
|
} 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);
|
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) {
|
int32_t cli_srv(void* p) {
|
||||||
Cli* cli = cli_alloc();
|
Cli* cli = cli_alloc();
|
||||||
|
|
||||||
furi_hal_vcp_init();
|
|
||||||
|
|
||||||
// Init basic cli commands
|
// Init basic cli commands
|
||||||
cli_commands_init(cli);
|
cli_commands_init(cli);
|
||||||
|
|
||||||
furi_record_create("cli", 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) {
|
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;
|
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);
|
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 cli Cli instance
|
||||||
* @param buffer pointer to buffer
|
* @param buffer pointer to buffer
|
||||||
* @param size size of buffer in bytes
|
* @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);
|
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
|
* @param cli Cli instance
|
||||||
*
|
*
|
||||||
@ -111,6 +122,12 @@ char cli_getc(Cli* cli);
|
|||||||
*/
|
*/
|
||||||
void cli_nl();
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -18,6 +18,17 @@ typedef struct {
|
|||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
} CliCommand;
|
} 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(
|
BPTREE_DEF2(
|
||||||
CliCommandTree,
|
CliCommandTree,
|
||||||
CLI_COMMANDS_TREE_RANK,
|
CLI_COMMANDS_TREE_RANK,
|
||||||
@ -31,18 +42,18 @@ BPTREE_DEF2(
|
|||||||
struct Cli {
|
struct Cli {
|
||||||
CliCommandTree_t commands;
|
CliCommandTree_t commands;
|
||||||
osMutexId_t mutex;
|
osMutexId_t mutex;
|
||||||
|
osSemaphoreId_t idle_sem;
|
||||||
string_t last_line;
|
string_t last_line;
|
||||||
string_t line;
|
string_t line;
|
||||||
|
CliSession* session;
|
||||||
|
|
||||||
size_t cursor_position;
|
size_t cursor_position;
|
||||||
};
|
};
|
||||||
|
|
||||||
Cli* cli_alloc();
|
Cli* cli_alloc();
|
||||||
|
|
||||||
void cli_free(Cli* cli);
|
|
||||||
|
|
||||||
void cli_reset(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);
|
void cli_stdout_callback(void* _cookie, const char* data, size_t size);
|
||||||
|
@ -2,8 +2,9 @@
|
|||||||
#include <furi_hal.h>
|
#include <furi_hal.h>
|
||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include <stream_buffer.h>
|
#include <stream_buffer.h>
|
||||||
|
#include "cli_i.h"
|
||||||
|
|
||||||
#define TAG "FuriHalVcp"
|
#define TAG "CliVcp"
|
||||||
|
|
||||||
#define USB_CDC_PKT_LEN CDC_DATA_SZ
|
#define USB_CDC_PKT_LEN CDC_DATA_SZ
|
||||||
#define VCP_RX_BUF_SIZE (USB_CDC_PKT_LEN * 3)
|
#define VCP_RX_BUF_SIZE (USB_CDC_PKT_LEN * 3)
|
||||||
@ -12,19 +13,18 @@
|
|||||||
#define VCP_IF_NUM 0
|
#define VCP_IF_NUM 0
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
VcpEvtEnable = (1 << 0),
|
VcpEvtStop = (1 << 0),
|
||||||
VcpEvtDisable = (1 << 1),
|
VcpEvtConnect = (1 << 1),
|
||||||
VcpEvtConnect = (1 << 2),
|
VcpEvtDisconnect = (1 << 2),
|
||||||
VcpEvtDisconnect = (1 << 3),
|
VcpEvtStreamRx = (1 << 3),
|
||||||
VcpEvtStreamRx = (1 << 4),
|
VcpEvtRx = (1 << 4),
|
||||||
VcpEvtRx = (1 << 5),
|
VcpEvtStreamTx = (1 << 5),
|
||||||
VcpEvtStreamTx = (1 << 6),
|
VcpEvtTx = (1 << 6),
|
||||||
VcpEvtTx = (1 << 7),
|
|
||||||
} WorkerEvtFlags;
|
} WorkerEvtFlags;
|
||||||
|
|
||||||
#define VCP_THREAD_FLAG_ALL \
|
#define VCP_THREAD_FLAG_ALL \
|
||||||
(VcpEvtEnable | VcpEvtDisable | VcpEvtConnect | VcpEvtDisconnect | VcpEvtRx | VcpEvtTx | \
|
(VcpEvtStop | VcpEvtConnect | VcpEvtDisconnect | VcpEvtRx | VcpEvtTx | VcpEvtStreamRx | \
|
||||||
VcpEvtStreamRx | VcpEvtStreamTx)
|
VcpEvtStreamTx)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
FuriThread* thread;
|
FuriThread* thread;
|
||||||
@ -33,9 +33,12 @@ typedef struct {
|
|||||||
StreamBufferHandle_t rx_stream;
|
StreamBufferHandle_t rx_stream;
|
||||||
|
|
||||||
volatile bool connected;
|
volatile bool connected;
|
||||||
|
volatile bool running;
|
||||||
|
|
||||||
|
FuriHalUsbInterface* usb_if_prev;
|
||||||
|
|
||||||
uint8_t data_buffer[USB_CDC_PKT_LEN];
|
uint8_t data_buffer[USB_CDC_PKT_LEN];
|
||||||
} FuriHalVcp;
|
} CliVcp;
|
||||||
|
|
||||||
static int32_t vcp_worker(void* context);
|
static int32_t vcp_worker(void* context);
|
||||||
static void vcp_on_cdc_tx_complete(void* context);
|
static void vcp_on_cdc_tx_complete(void* context);
|
||||||
@ -51,25 +54,23 @@ static CdcCallbacks cdc_cb = {
|
|||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
static FuriHalVcp* vcp = NULL;
|
static CliVcp* vcp = NULL;
|
||||||
|
|
||||||
static const uint8_t ascii_soh = 0x01;
|
static const uint8_t ascii_soh = 0x01;
|
||||||
static const uint8_t ascii_eot = 0x04;
|
static const uint8_t ascii_eot = 0x04;
|
||||||
|
|
||||||
void furi_hal_vcp_init() {
|
static void cli_vcp_init() {
|
||||||
vcp = malloc(sizeof(FuriHalVcp));
|
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->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();
|
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_stack_size(vcp->thread, 1024);
|
||||||
furi_thread_set_callback(vcp->thread, vcp_worker);
|
furi_thread_set_callback(vcp->thread, vcp_worker);
|
||||||
furi_thread_start(vcp->thread);
|
furi_thread_start(vcp->thread);
|
||||||
@ -77,48 +78,35 @@ void furi_hal_vcp_init() {
|
|||||||
FURI_LOG_I(TAG, "Init OK");
|
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) {
|
static int32_t vcp_worker(void* context) {
|
||||||
bool enabled = true;
|
bool tx_idle = true;
|
||||||
bool tx_idle = false;
|
|
||||||
size_t missed_rx = 0;
|
size_t missed_rx = 0;
|
||||||
uint8_t last_tx_pkt_len = 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_hal_cdc_set_callbacks(VCP_IF_NUM, &cdc_cb, NULL);
|
||||||
|
|
||||||
|
FURI_LOG_D(TAG, "Start");
|
||||||
|
vcp->running = true;
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
uint32_t flags = osThreadFlagsWait(VCP_THREAD_FLAG_ALL, osFlagsWaitAny, osWaitForever);
|
uint32_t flags = osThreadFlagsWait(VCP_THREAD_FLAG_ALL, osFlagsWaitAny, osWaitForever);
|
||||||
furi_assert((flags & osFlagsError) == 0);
|
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
|
// VCP session opened
|
||||||
if((flags & VcpEvtConnect) && enabled) {
|
if(flags & VcpEvtConnect) {
|
||||||
#ifdef FURI_HAL_USB_VCP_DEBUG
|
#ifdef CLI_VCP_DEBUG
|
||||||
FURI_LOG_D(TAG, "Connect");
|
FURI_LOG_D(TAG, "Connect");
|
||||||
#endif
|
#endif
|
||||||
if(vcp->connected == false) {
|
if(vcp->connected == false) {
|
||||||
@ -128,8 +116,8 @@ static int32_t vcp_worker(void* context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// VCP session closed
|
// VCP session closed
|
||||||
if((flags & VcpEvtDisconnect) && enabled) {
|
if(flags & VcpEvtDisconnect) {
|
||||||
#ifdef FURI_HAL_USB_VCP_DEBUG
|
#ifdef CLI_VCP_DEBUG
|
||||||
FURI_LOG_D(TAG, "Disconnect");
|
FURI_LOG_D(TAG, "Disconnect");
|
||||||
#endif
|
#endif
|
||||||
if(vcp->connected == true) {
|
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?
|
// Rx buffer was read, maybe there is enough space for new data?
|
||||||
if((flags & VcpEvtStreamRx) && enabled && missed_rx > 0) {
|
if((flags & VcpEvtStreamRx) && (missed_rx > 0)) {
|
||||||
#ifdef FURI_HAL_USB_VCP_DEBUG
|
#ifdef CLI_VCP_DEBUG
|
||||||
FURI_LOG_D(TAG, "StreamRx");
|
FURI_LOG_D(TAG, "StreamRx");
|
||||||
#endif
|
#endif
|
||||||
if(xStreamBufferSpacesAvailable(vcp->rx_stream) >= USB_CDC_PKT_LEN) {
|
if(xStreamBufferSpacesAvailable(vcp->rx_stream) >= USB_CDC_PKT_LEN) {
|
||||||
@ -151,10 +139,10 @@ static int32_t vcp_worker(void* context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// New data received
|
// New data received
|
||||||
if((flags & VcpEvtRx)) {
|
if(flags & VcpEvtRx) {
|
||||||
if(xStreamBufferSpacesAvailable(vcp->rx_stream) >= USB_CDC_PKT_LEN) {
|
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);
|
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);
|
FURI_LOG_D(TAG, "Rx %d", len);
|
||||||
#endif
|
#endif
|
||||||
if(len > 0) {
|
if(len > 0) {
|
||||||
@ -163,7 +151,7 @@ static int32_t vcp_worker(void* context) {
|
|||||||
len);
|
len);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
#ifdef FURI_HAL_USB_VCP_DEBUG
|
#ifdef CLI_VCP_DEBUG
|
||||||
FURI_LOG_D(TAG, "Rx missed");
|
FURI_LOG_D(TAG, "Rx missed");
|
||||||
#endif
|
#endif
|
||||||
missed_rx++;
|
missed_rx++;
|
||||||
@ -171,8 +159,8 @@ static int32_t vcp_worker(void* context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// New data in Tx buffer
|
// New data in Tx buffer
|
||||||
if((flags & VcpEvtStreamTx) && enabled) {
|
if(flags & VcpEvtStreamTx) {
|
||||||
#ifdef FURI_HAL_USB_VCP_DEBUG
|
#ifdef CLI_VCP_DEBUG
|
||||||
FURI_LOG_D(TAG, "StreamTx");
|
FURI_LOG_D(TAG, "StreamTx");
|
||||||
#endif
|
#endif
|
||||||
if(tx_idle) {
|
if(tx_idle) {
|
||||||
@ -181,10 +169,10 @@ static int32_t vcp_worker(void* context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CDC write transfer done
|
// CDC write transfer done
|
||||||
if((flags & VcpEvtTx) && enabled) {
|
if(flags & VcpEvtTx) {
|
||||||
size_t len =
|
size_t len =
|
||||||
xStreamBufferReceive(vcp->tx_stream, vcp->data_buffer, USB_CDC_PKT_LEN, 0);
|
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);
|
FURI_LOG_D(TAG, "Tx %d", len);
|
||||||
#endif
|
#endif
|
||||||
if(len > 0) { // Some data left in Tx buffer. Sending it now
|
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;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void furi_hal_vcp_enable() {
|
static size_t cli_vcp_rx(uint8_t* buffer, size_t size, uint32_t timeout) {
|
||||||
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) {
|
|
||||||
furi_assert(vcp);
|
furi_assert(vcp);
|
||||||
furi_assert(buffer);
|
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);
|
FURI_LOG_D(TAG, "rx %u start", size);
|
||||||
#endif
|
#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;
|
if(batch_size > VCP_RX_BUF_SIZE) batch_size = VCP_RX_BUF_SIZE;
|
||||||
|
|
||||||
size_t len = xStreamBufferReceive(vcp->rx_stream, buffer, batch_size, timeout);
|
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);
|
FURI_LOG_D(TAG, "rx %u ", batch_size);
|
||||||
#endif
|
#endif
|
||||||
if(len == 0) break;
|
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;
|
rx_cnt += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef FURI_HAL_USB_VCP_DEBUG
|
#ifdef CLI_VCP_DEBUG
|
||||||
FURI_LOG_D(TAG, "rx %u end", size);
|
FURI_LOG_D(TAG, "rx %u end", size);
|
||||||
#endif
|
#endif
|
||||||
return rx_cnt;
|
return rx_cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t furi_hal_vcp_rx(uint8_t* buffer, size_t size) {
|
static void cli_vcp_tx(const 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) {
|
|
||||||
furi_assert(vcp);
|
furi_assert(vcp);
|
||||||
furi_assert(buffer);
|
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);
|
FURI_LOG_D(TAG, "tx %u start", size);
|
||||||
#endif
|
#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);
|
xStreamBufferSend(vcp->tx_stream, buffer, batch_size, osWaitForever);
|
||||||
osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtStreamTx);
|
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);
|
FURI_LOG_D(TAG, "tx %u", batch_size);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -272,11 +269,15 @@ void furi_hal_vcp_tx(const uint8_t* buffer, size_t size) {
|
|||||||
buffer += batch_size;
|
buffer += batch_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef FURI_HAL_USB_VCP_DEBUG
|
#ifdef CLI_VCP_DEBUG
|
||||||
FURI_LOG_D(TAG, "tx %u end", size);
|
FURI_LOG_D(TAG, "tx %u end", size);
|
||||||
#endif
|
#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) {
|
static void vcp_state_callback(void* context, uint8_t state) {
|
||||||
if(state == 0) {
|
if(state == 0) {
|
||||||
osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtDisconnect);
|
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);
|
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);
|
furi_assert(vcp);
|
||||||
return vcp->connected;
|
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 <stdbool.h>
|
||||||
#include <toolbox/saved_struct.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_PATH "/int/desktop.settings"
|
||||||
#define DESKTOP_SETTINGS_MAGIC (0x17)
|
#define DESKTOP_SETTINGS_MAGIC (0x17)
|
||||||
#define PIN_MAX_LENGTH 12
|
#define PIN_MAX_LENGTH 12
|
||||||
@ -39,5 +39,6 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
uint16_t favorite;
|
uint16_t favorite;
|
||||||
PinCode pin_code;
|
PinCode pin_code;
|
||||||
|
uint8_t is_locked;
|
||||||
uint32_t auto_lock_delay_ms;
|
uint32_t auto_lock_delay_ms;
|
||||||
} DesktopSettings;
|
} DesktopSettings;
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include "../helpers/pin_lock.h"
|
#include "../helpers/pin_lock.h"
|
||||||
#include "../desktop_i.h"
|
#include "../desktop_i.h"
|
||||||
|
#include <cli/cli_vcp.h>
|
||||||
|
|
||||||
static const NotificationSequence sequence_pin_fail = {
|
static const NotificationSequence sequence_pin_fail = {
|
||||||
&message_display_on,
|
&message_display_on,
|
||||||
@ -61,26 +62,50 @@ uint32_t desktop_pin_lock_get_fail_timeout() {
|
|||||||
return pin_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_pin_fails(0);
|
||||||
furi_hal_rtc_set_flag(FuriHalRtcFlagLock);
|
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_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) {
|
void desktop_pin_lock_init(DesktopSettings* settings) {
|
||||||
|
furi_assert(settings);
|
||||||
|
|
||||||
if(settings->pin_code.length > 0) {
|
if(settings->pin_code.length > 0) {
|
||||||
furi_hal_rtc_set_flag(FuriHalRtcFlagLock);
|
if(settings->is_locked == 1) {
|
||||||
furi_hal_usb_disable();
|
furi_hal_rtc_set_flag(FuriHalRtcFlagLock);
|
||||||
|
} else {
|
||||||
|
if(desktop_pin_lock_is_locked()) {
|
||||||
|
settings->is_locked = 1;
|
||||||
|
SAVE_DESKTOP_SETTINGS(settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
furi_hal_rtc_set_pin_fails(0);
|
furi_hal_rtc_set_pin_fails(0);
|
||||||
furi_hal_rtc_reset_flag(FuriHalRtcFlagLock);
|
furi_hal_rtc_reset_flag(FuriHalRtcFlagLock);
|
||||||
furi_hal_usb_enable();
|
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) {
|
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();
|
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();
|
bool desktop_pin_lock_is_locked();
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) {
|
|||||||
break;
|
break;
|
||||||
case DesktopLockMenuEventPinLock:
|
case DesktopLockMenuEventPinLock:
|
||||||
if(desktop->settings.pin_code.length > 0) {
|
if(desktop->settings.pin_code.length > 0) {
|
||||||
desktop_pin_lock();
|
desktop_pin_lock(&desktop->settings);
|
||||||
desktop_lock(desktop);
|
desktop_lock(desktop);
|
||||||
} else {
|
} else {
|
||||||
LoaderStatus status =
|
LoaderStatus status =
|
||||||
|
@ -126,7 +126,7 @@ bool desktop_scene_pin_input_on_event(void* context, SceneManagerEvent event) {
|
|||||||
consumed = true;
|
consumed = true;
|
||||||
break;
|
break;
|
||||||
case DesktopPinInputEventUnlocked:
|
case DesktopPinInputEventUnlocked:
|
||||||
desktop_pin_unlock();
|
desktop_pin_unlock(&desktop->settings);
|
||||||
desktop_unlock(desktop);
|
desktop_unlock(desktop);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
break;
|
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];
|
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 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) {
|
if(xp_to_levelup) {
|
||||||
deed_weight = MIN(xp_to_levelup, deed_weight);
|
deed_weight = MIN(xp_to_levelup, deed_weight);
|
||||||
dolphin_state->data.icounter += deed_weight;
|
dolphin_state->data.icounter += deed_weight;
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
#include <stream_buffer.h>
|
#include <stream_buffer.h>
|
||||||
#include <furi_hal_usb_cdc_i.h>
|
#include <furi_hal_usb_cdc_i.h>
|
||||||
#include "usb_cdc.h"
|
#include "usb_cdc.h"
|
||||||
|
#include "cli/cli_vcp.h"
|
||||||
|
#include "cli/cli.h"
|
||||||
|
|
||||||
#define USB_CDC_PKT_LEN CDC_DATA_SZ
|
#define USB_CDC_PKT_LEN CDC_DATA_SZ
|
||||||
#define USB_UART_RX_BUF_SIZE (USB_CDC_PKT_LEN * 5)
|
#define USB_UART_RX_BUF_SIZE (USB_CDC_PKT_LEN * 5)
|
||||||
@ -16,17 +18,16 @@ static const GpioPin* flow_pins[][2] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
WorkerEvtReserved = (1 << 0), // Reserved for StreamBuffer internal event
|
WorkerEvtStop = (1 << 0),
|
||||||
WorkerEvtStop = (1 << 1),
|
WorkerEvtRxDone = (1 << 1),
|
||||||
WorkerEvtRxDone = (1 << 2),
|
|
||||||
|
|
||||||
WorkerEvtTxStop = (1 << 3),
|
WorkerEvtTxStop = (1 << 2),
|
||||||
WorkerEvtCdcRx = (1 << 4),
|
WorkerEvtCdcRx = (1 << 3),
|
||||||
|
|
||||||
WorkerEvtCfgChange = (1 << 5),
|
WorkerEvtCfgChange = (1 << 4),
|
||||||
|
|
||||||
WorkerEvtLineCfgSet = (1 << 6),
|
WorkerEvtLineCfgSet = (1 << 5),
|
||||||
WorkerEvtCtrlLineSet = (1 << 7),
|
WorkerEvtCtrlLineSet = (1 << 6),
|
||||||
|
|
||||||
} WorkerEvtFlags;
|
} 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) {
|
static void usb_uart_vcp_init(UsbUartBridge* usb_uart, uint8_t vcp_ch) {
|
||||||
furi_hal_usb_unlock();
|
furi_hal_usb_unlock();
|
||||||
|
FURI_LOG_I("", "Init %d", vcp_ch);
|
||||||
if(vcp_ch == 0) {
|
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_check(furi_hal_usb_set_config(&usb_cdc_single, NULL) == true);
|
||||||
furi_hal_vcp_disable();
|
|
||||||
} else {
|
} else {
|
||||||
furi_check(furi_hal_usb_set_config(&usb_cdc_dual, NULL) == true);
|
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);
|
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) {
|
static void usb_uart_vcp_deinit(UsbUartBridge* usb_uart, uint8_t vcp_ch) {
|
||||||
furi_hal_cdc_set_callbacks(vcp_ch, NULL, NULL);
|
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) {
|
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_context(usb_uart->tx_thread, usb_uart);
|
||||||
furi_thread_set_callback(usb_uart->tx_thread, usb_uart_tx_thread);
|
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_vcp_init(usb_uart, usb_uart->cfg.vcp_ch);
|
||||||
usb_uart_serial_init(usb_uart, usb_uart->cfg.uart_ch);
|
usb_uart_serial_init(usb_uart, usb_uart->cfg.uart_ch);
|
||||||
usb_uart_set_baudrate(usb_uart, usb_uart->cfg.baudrate);
|
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_update_ctrl_lines(usb_uart);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
usb_uart_vcp_deinit(usb_uart, usb_uart->cfg.vcp_ch);
|
usb_uart_vcp_deinit(usb_uart, usb_uart->cfg.vcp_ch);
|
||||||
usb_uart_serial_deinit(usb_uart, usb_uart->cfg.uart_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) {
|
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][0], GpioModeAnalog);
|
||||||
furi_hal_gpio_init_simple(flow_pins[usb_uart->cfg.flow_pins - 1][1], 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);
|
osMutexDelete(usb_uart->usb_mutex);
|
||||||
osSemaphoreDelete(usb_uart->tx_sem);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,8 +62,8 @@ void rpc_cli_command_start_session(Cli* cli, string_t args, void* context) {
|
|||||||
size_t size_received = 0;
|
size_t size_received = 0;
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
size_received = furi_hal_vcp_rx_with_timeout(buffer, CLI_READ_BUFFER_SIZE, 50);
|
size_received = cli_read_timeout(cli_rpc.cli, buffer, CLI_READ_BUFFER_SIZE, 50);
|
||||||
if(!furi_hal_vcp_is_connected() || cli_rpc.session_close_request) {
|
if(!cli_is_connected(cli_rpc.cli) || cli_rpc.session_close_request) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,8 @@ struct SubGhzChatWorker {
|
|||||||
volatile bool worker_stoping;
|
volatile bool worker_stoping;
|
||||||
osMessageQueueId_t event_queue;
|
osMessageQueueId_t event_queue;
|
||||||
uint32_t last_time_rx_data;
|
uint32_t last_time_rx_data;
|
||||||
|
|
||||||
|
Cli* cli;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Worker thread
|
/** Worker thread
|
||||||
@ -27,7 +29,7 @@ static int32_t subghz_chat_worker_thread(void* context) {
|
|||||||
event.event = SubGhzChatEventUserEntrance;
|
event.event = SubGhzChatEventUserEntrance;
|
||||||
osMessageQueuePut(instance->event_queue, &event, 0, 0);
|
osMessageQueuePut(instance->event_queue, &event, 0, 0);
|
||||||
while(instance->worker_running) {
|
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.event = SubGhzChatEventInputData;
|
||||||
event.c = c;
|
event.c = c;
|
||||||
osMessageQueuePut(instance->event_queue, &event, 0, osWaitForever);
|
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);
|
osMessageQueuePut(instance->event_queue, &event, 0, osWaitForever);
|
||||||
}
|
}
|
||||||
|
|
||||||
SubGhzChatWorker* subghz_chat_worker_alloc() {
|
SubGhzChatWorker* subghz_chat_worker_alloc(Cli* cli) {
|
||||||
SubGhzChatWorker* instance = malloc(sizeof(SubGhzChatWorker));
|
SubGhzChatWorker* instance = malloc(sizeof(SubGhzChatWorker));
|
||||||
|
|
||||||
|
instance->cli = cli;
|
||||||
|
|
||||||
instance->thread = furi_thread_alloc();
|
instance->thread = furi_thread_alloc();
|
||||||
furi_thread_set_name(instance->thread, "SubGhzChat");
|
furi_thread_set_name(instance->thread, "SubGhzChat");
|
||||||
furi_thread_set_stack_size(instance->thread, 2048);
|
furi_thread_set_stack_size(instance->thread, 2048);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "../subghz_i.h"
|
#include "../subghz_i.h"
|
||||||
|
#include <cli/cli.h>
|
||||||
|
|
||||||
typedef struct SubGhzChatWorker SubGhzChatWorker;
|
typedef struct SubGhzChatWorker SubGhzChatWorker;
|
||||||
|
|
||||||
@ -17,7 +18,7 @@ typedef struct {
|
|||||||
char c;
|
char c;
|
||||||
} SubGhzChatEvent;
|
} SubGhzChatEvent;
|
||||||
|
|
||||||
SubGhzChatWorker* subghz_chat_worker_alloc();
|
SubGhzChatWorker* subghz_chat_worker_alloc(Cli* cli);
|
||||||
void subghz_chat_worker_free(SubGhzChatWorker* instance);
|
void subghz_chat_worker_free(SubGhzChatWorker* instance);
|
||||||
bool subghz_chat_worker_start(SubGhzChatWorker* instance, uint32_t frequency);
|
bool subghz_chat_worker_start(SubGhzChatWorker* instance, uint32_t frequency);
|
||||||
void subghz_chat_worker_stop(SubGhzChatWorker* instance);
|
void subghz_chat_worker_stop(SubGhzChatWorker* instance);
|
||||||
|
@ -525,7 +525,7 @@ static void subghz_cli_command_chat(Cli* cli, string_t args) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SubGhzChatWorker* subghz_chat = subghz_chat_worker_alloc();
|
SubGhzChatWorker* subghz_chat = subghz_chat_worker_alloc(cli);
|
||||||
if(!subghz_chat_worker_start(subghz_chat, frequency)) {
|
if(!subghz_chat_worker_start(subghz_chat, frequency)) {
|
||||||
printf("Startup error SubGhzChatWorker\r\n");
|
printf("Startup error SubGhzChatWorker\r\n");
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#include "furi_hal_version.h"
|
#include "furi_hal_version.h"
|
||||||
#include "furi_hal_usb_i.h"
|
#include "furi_hal_usb_i.h"
|
||||||
#include "furi_hal_usb.h"
|
#include "furi_hal_usb.h"
|
||||||
#include "furi_hal_vcp.h"
|
|
||||||
#include <furi_hal_power.h>
|
#include <furi_hal_power.h>
|
||||||
#include <stm32wbxx_ll_pwr.h>
|
#include <stm32wbxx_ll_pwr.h>
|
||||||
#include <furi.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(callbacks[if_num]->state_callback != NULL) {
|
||||||
if(connected == true) callbacks[if_num]->state_callback(cb_ctx[if_num], 1);
|
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_light.h"
|
||||||
#include "furi_hal_delay.h"
|
#include "furi_hal_delay.h"
|
||||||
#include "furi_hal_power.h"
|
#include "furi_hal_power.h"
|
||||||
#include "furi_hal_vcp.h"
|
|
||||||
#include "furi_hal_interrupt.h"
|
#include "furi_hal_interrupt.h"
|
||||||
#include "furi_hal_version.h"
|
#include "furi_hal_version.h"
|
||||||
#include "furi_hal_bt.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…
Reference in New Issue
Block a user