USB VCP Cli (#237)
* Core: ring buffer. * Api: usb vcp. F3: vcp glue code. * Applications: cli draft version. * Cli: basic working version, includes help and version commands * HAL: vcp on f2 * Makefile: update openocd conf * F3: vcp rx with freertos stream * Cli: help * Cli: standard commands, api-hal-uid * Power: cli poweroff.
This commit is contained in:
		
							parent
							
								
									466ea087a0
								
							
						
					
					
						commit
						3749eb0eed
					
				| @ -35,12 +35,17 @@ void power_task(void* p); | |||||||
| void sd_card_test(void* p); | void sd_card_test(void* p); | ||||||
| void application_vibro(void* p); | void application_vibro(void* p); | ||||||
| void app_gpio_test(void* p); | void app_gpio_test(void* p); | ||||||
|  | void cli_task(void* p); | ||||||
| 
 | 
 | ||||||
| const FlipperStartupApp FLIPPER_STARTUP[] = { | const FlipperStartupApp FLIPPER_STARTUP[] = { | ||||||
| #ifdef APP_DISPLAY | #ifdef APP_DISPLAY | ||||||
|     {.app = display_u8g2, .name = "display_u8g2", .libs = {0}}, |     {.app = display_u8g2, .name = "display_u8g2", .libs = {0}}, | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #ifdef APP_CLI | ||||||
|  |     {.app = cli_task, .name = "cli_task", .libs = {0}}, | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| #ifdef APP_EXAMPLE_BLINK | #ifdef APP_EXAMPLE_BLINK | ||||||
|     {.app = application_blink, .name = "blink", .libs = {1, FURI_LIB{"input_task"}}}, |     {.app = application_blink, .name = "blink", .libs = {1, FURI_LIB{"input_task"}}}, | ||||||
| #endif | #endif | ||||||
| @ -68,7 +73,7 @@ const FlipperStartupApp FLIPPER_STARTUP[] = { | |||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef APP_POWER | #ifdef APP_POWER | ||||||
|     {.app = power_task, .name = "power_task", .libs = {1, FURI_LIB{"gui_task"}}}, |     {.app = power_task, .name = "power_task", .libs = {2, FURI_LIB{"cli_task", "gui_task"}}}, | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef APP_CC1101 | #ifdef APP_CC1101 | ||||||
|  | |||||||
| @ -11,6 +11,7 @@ ifeq ($(APP_RELEASE), 1) | |||||||
| APP_MENU = 1 | APP_MENU = 1 | ||||||
| APP_NFC  = 1 | APP_NFC  = 1 | ||||||
| APP_POWER = 1 | APP_POWER = 1 | ||||||
|  | APP_CLI = 1 | ||||||
| BUILD_IRDA  = 1 | BUILD_IRDA  = 1 | ||||||
| APP_IRUKAGOTCHI = 1 | APP_IRUKAGOTCHI = 1 | ||||||
| BUILD_EXAMPLE_BLINK = 1 | BUILD_EXAMPLE_BLINK = 1 | ||||||
| @ -45,6 +46,13 @@ CFLAGS		+= -DAPP_POWER | |||||||
| C_SOURCES	+= $(wildcard $(APP_DIR)/power/*.c) | C_SOURCES	+= $(wildcard $(APP_DIR)/power/*.c) | ||||||
| endif | endif | ||||||
| 
 | 
 | ||||||
|  | APP_CLI ?= 0 | ||||||
|  | ifeq ($(APP_CLI), 1) | ||||||
|  | APP_GUI		= 1 | ||||||
|  | CFLAGS		+= -DAPP_CLI | ||||||
|  | C_SOURCES	+= $(wildcard $(APP_DIR)/cli/*.c) | ||||||
|  | endif | ||||||
|  | 
 | ||||||
| APP_MENU ?= 0 | APP_MENU ?= 0 | ||||||
| ifeq ($(APP_MENU), 1) | ifeq ($(APP_MENU), 1) | ||||||
| CFLAGS += -DAPP_MENU | CFLAGS += -DAPP_MENU | ||||||
|  | |||||||
							
								
								
									
										173
									
								
								applications/cli/cli.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								applications/cli/cli.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,173 @@ | |||||||
|  | #include "cli_i.h" | ||||||
|  | #include "cli_commands.h" | ||||||
|  | 
 | ||||||
|  | #include <api-hal-vcp.h> | ||||||
|  | 
 | ||||||
|  | Cli* cli_alloc() { | ||||||
|  |     Cli* cli = furi_alloc(sizeof(Cli)); | ||||||
|  |     CliCommandDict_init(cli->commands); | ||||||
|  | 
 | ||||||
|  |     cli->mutex = osMutexNew(NULL); | ||||||
|  |     furi_check(cli->mutex); | ||||||
|  | 
 | ||||||
|  |     cli_reset_state(cli); | ||||||
|  | 
 | ||||||
|  |     return cli; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void cli_free(Cli* cli) { | ||||||
|  |     free(cli); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void cli_reset_state(Cli* cli) { | ||||||
|  |     string_clear(cli->line); | ||||||
|  |     string_init(cli->line); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void cli_putc(char c) { | ||||||
|  |     api_hal_vcp_tx((uint8_t*)&c, 1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void cli_print(const char* str) { | ||||||
|  |     api_hal_vcp_tx((uint8_t*)str, strlen(str)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void cli_print_version() { | ||||||
|  |     cli_print("Build date:" BUILD_DATE ". " | ||||||
|  |               "Git Commit:" GIT_COMMIT ". " | ||||||
|  |               "Git Branch:" GIT_BRANCH ". " | ||||||
|  |               "Commit Number:" GIT_BRANCH_NUM "."); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void cli_motd() { | ||||||
|  |     cli_print("Flipper cli.\r\n"); | ||||||
|  |     cli_print_version(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void cli_nl() { | ||||||
|  |     cli_print("\r\n"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void cli_prompt() { | ||||||
|  |     cli_print("\r\n>: "); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void cli_backspace(Cli* cli) { | ||||||
|  |     size_t s = string_size(cli->line); | ||||||
|  |     if(s > 0) { | ||||||
|  |         s--; | ||||||
|  |         string_left(cli->line, s); | ||||||
|  |         cli_putc(CliSymbolAsciiBackspace); | ||||||
|  |         cli_putc(CliSymbolAsciiSpace); | ||||||
|  |         cli_putc(CliSymbolAsciiBackspace); | ||||||
|  |     } else { | ||||||
|  |         cli_putc(CliSymbolAsciiBell); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void cli_enter(Cli* cli) { | ||||||
|  |     // Normalize input
 | ||||||
|  |     string_strim(cli->line); | ||||||
|  |     if(string_size(cli->line) == 0) { | ||||||
|  |         cli_prompt(); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Get first word as command name
 | ||||||
|  |     string_t command; | ||||||
|  |     string_init(command); | ||||||
|  |     size_t ws = string_search_char(cli->line, ' '); | ||||||
|  |     if(ws == STRING_FAILURE) { | ||||||
|  |         string_set(command, cli->line); | ||||||
|  |         string_clear(cli->line); | ||||||
|  |         string_init(cli->line); | ||||||
|  |     } else { | ||||||
|  |         string_set_n(command, cli->line, 0, ws); | ||||||
|  |         string_right(cli->line, ws); | ||||||
|  |         string_strim(cli->line); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Search for command
 | ||||||
|  |     furi_check(osMutexAcquire(cli->mutex, osWaitForever) == osOK); | ||||||
|  |     CliCommand* cli_command = CliCommandDict_get(cli->commands, command); | ||||||
|  |     furi_check(osMutexRelease(cli->mutex) == osOK); | ||||||
|  |     if(cli_command) { | ||||||
|  |         cli_nl(); | ||||||
|  |         cli_command->callback(cli->line, cli_command->context); | ||||||
|  |         cli_prompt(); | ||||||
|  |     } else { | ||||||
|  |         cli_nl(); | ||||||
|  |         cli_print("Command not found: "); | ||||||
|  |         cli_print(string_get_cstr(command)); | ||||||
|  |         cli_prompt(); | ||||||
|  |         cli_putc(CliSymbolAsciiBell); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Always finish with clean state
 | ||||||
|  |     cli_reset_state(cli); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void cli_process_input(Cli* cli) { | ||||||
|  |     char c; | ||||||
|  |     size_t r; | ||||||
|  | 
 | ||||||
|  |     r = api_hal_vcp_rx((uint8_t*)&c, 1); | ||||||
|  |     if(r == 0) { | ||||||
|  |         cli_reset_state(cli); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if(c == CliSymbolAsciiTab) { | ||||||
|  |         cli_putc(CliSymbolAsciiBell); | ||||||
|  |     } else if(c == CliSymbolAsciiSOH) { | ||||||
|  |         cli_motd(); | ||||||
|  |         cli_prompt(); | ||||||
|  |     } else if(c == CliSymbolAsciiEOT) { | ||||||
|  |         cli_reset_state(cli); | ||||||
|  |     } else if(c == CliSymbolAsciiEsc) { | ||||||
|  |         r = api_hal_vcp_rx((uint8_t*)&c, 1); | ||||||
|  |         if(r && c == '[') { | ||||||
|  |             api_hal_vcp_rx((uint8_t*)&c, 1); | ||||||
|  |         } else { | ||||||
|  |             cli_putc(CliSymbolAsciiBell); | ||||||
|  |         } | ||||||
|  |     } else if(c == CliSymbolAsciiBackspace || c == CliSymbolAsciiDel) { | ||||||
|  |         cli_backspace(cli); | ||||||
|  |     } else if(c == CliSymbolAsciiCR) { | ||||||
|  |         cli_enter(cli); | ||||||
|  |     } else if(c >= 0x20 && c < 0x7F) { | ||||||
|  |         string_push_back(cli->line, c); | ||||||
|  |         cli_putc(c); | ||||||
|  |     } else { | ||||||
|  |         cli_putc(CliSymbolAsciiBell); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void cli_add_command(Cli* cli, const char* name, CliCallback callback, void* context) { | ||||||
|  |     string_t name_str; | ||||||
|  |     string_init_set_str(name_str, name); | ||||||
|  |     CliCommand c; | ||||||
|  |     c.callback = callback; | ||||||
|  |     c.context = context; | ||||||
|  | 
 | ||||||
|  |     furi_check(osMutexAcquire(cli->mutex, osWaitForever) == osOK); | ||||||
|  |     CliCommandDict_set_at(cli->commands, name_str, c); | ||||||
|  |     furi_check(osMutexRelease(cli->mutex) == osOK); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void cli_task(void* p) { | ||||||
|  |     Cli* cli = cli_alloc(); | ||||||
|  | 
 | ||||||
|  |     // Init basic cli commands
 | ||||||
|  |     cli_commands_init(cli); | ||||||
|  | 
 | ||||||
|  |     if(!furi_create("cli", cli)) { | ||||||
|  |         printf("[cli_task] cannot create the cli record\n"); | ||||||
|  |         furiac_exit(NULL); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     furiac_ready(); | ||||||
|  | 
 | ||||||
|  |     while(1) { | ||||||
|  |         cli_process_input(cli); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										42
									
								
								applications/cli/cli.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								applications/cli/cli.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <m-string.h> | ||||||
|  | 
 | ||||||
|  | /* Cli type
 | ||||||
|  |  * Anonymous structure. Use cli_i.h if you need to go deeper. | ||||||
|  |  */ | ||||||
|  | typedef struct Cli Cli; | ||||||
|  | 
 | ||||||
|  | /* Cli callback function pointer.
 | ||||||
|  |  * Implement this interface and use add_cli_command | ||||||
|  |  * @param args - string with what was passed after command | ||||||
|  |  * @param context - pointer to whatever you gave us on cli_add_command | ||||||
|  |  */ | ||||||
|  | typedef void (*CliCallback)(string_t args, void* context); | ||||||
|  | 
 | ||||||
|  | /* Add cli command
 | ||||||
|  |  * Registers you command callback | ||||||
|  |  * @param cli - pointer to cli instance | ||||||
|  |  * @param name - command name | ||||||
|  |  * @param callback - callback function | ||||||
|  |  * @param context - pointer to whatever we need to pass to callback | ||||||
|  |  */ | ||||||
|  | void cli_add_command(Cli* cli, const char* name, CliCallback callback, void* context); | ||||||
|  | 
 | ||||||
|  | /* Read terminal input.
 | ||||||
|  |  * Do it only from inside of callback. | ||||||
|  |  * @param buffer - buffer pointer to char buffer | ||||||
|  |  * @param size - size of buffer in bytes | ||||||
|  |  */ | ||||||
|  | void cli_read(char* buffer, size_t size); | ||||||
|  | 
 | ||||||
|  | /* Print to terminal
 | ||||||
|  |  * Do it only from inside of callback. | ||||||
|  |  * @param buffer - pointer to null terminated string to print. | ||||||
|  |  */ | ||||||
|  | void cli_print(const char* buffer); | ||||||
|  | 
 | ||||||
|  | /* New line 
 | ||||||
|  |  * Send new ine sequence | ||||||
|  |  */ | ||||||
|  | void cli_nl(); | ||||||
							
								
								
									
										54
									
								
								applications/cli/cli_commands.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								applications/cli/cli_commands.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,54 @@ | |||||||
|  | #include "cli_commands.h" | ||||||
|  | #include <api-hal.h> | ||||||
|  | 
 | ||||||
|  | void cli_command_help(string_t args, void* context) { | ||||||
|  |     (void)args; | ||||||
|  |     Cli* cli = context; | ||||||
|  |     cli_print("Commands we have:"); | ||||||
|  | 
 | ||||||
|  |     furi_check(osMutexAcquire(cli->mutex, osWaitForever) == osOK); | ||||||
|  |     CliCommandDict_it_t it; | ||||||
|  |     for(CliCommandDict_it(it, cli->commands); !CliCommandDict_end_p(it); CliCommandDict_next(it)) { | ||||||
|  |         CliCommandDict_itref_t* ref = CliCommandDict_ref(it); | ||||||
|  |         cli_print(" "); | ||||||
|  |         cli_print(string_get_cstr(ref->key)); | ||||||
|  |     }; | ||||||
|  |     furi_check(osMutexRelease(cli->mutex) == osOK); | ||||||
|  | 
 | ||||||
|  |     if(string_size(args) > 0) { | ||||||
|  |         cli_nl(); | ||||||
|  |         cli_print("Also I have no clue what '"); | ||||||
|  |         cli_print(string_get_cstr(args)); | ||||||
|  |         cli_print("' is."); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void cli_command_version(string_t args, void* context) { | ||||||
|  |     (void)args; | ||||||
|  |     (void)context; | ||||||
|  |     cli_print_version(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void cli_command_uuid(string_t args, void* context) { | ||||||
|  |     (void)args; | ||||||
|  |     (void)context; | ||||||
|  |     size_t uid_size = api_hal_uid_size(); | ||||||
|  |     const uint8_t* uid = api_hal_uid(); | ||||||
|  | 
 | ||||||
|  |     string_t byte_str; | ||||||
|  |     string_init(byte_str); | ||||||
|  |     string_cat_printf(byte_str, "UID:"); | ||||||
|  |     for(size_t i = 0; i < uid_size; i++) { | ||||||
|  |         uint8_t uid_byte = uid[i]; | ||||||
|  |         string_cat_printf(byte_str, "%02X", uid_byte); | ||||||
|  |     } | ||||||
|  |     cli_print(string_get_cstr(byte_str)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void cli_commands_init(Cli* cli) { | ||||||
|  |     cli_add_command(cli, "help", cli_command_help, cli); | ||||||
|  |     cli_add_command(cli, "?", cli_command_help, cli); | ||||||
|  |     cli_add_command(cli, "version", cli_command_version, cli); | ||||||
|  |     cli_add_command(cli, "!", cli_command_version, cli); | ||||||
|  |     cli_add_command(cli, "uid", cli_command_uuid, cli); | ||||||
|  | } | ||||||
							
								
								
									
										5
									
								
								applications/cli/cli_commands.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								applications/cli/cli_commands.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "cli_i.h" | ||||||
|  | 
 | ||||||
|  | void cli_commands_init(Cli* cli); | ||||||
							
								
								
									
										42
									
								
								applications/cli/cli_i.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								applications/cli/cli_i.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "cli.h" | ||||||
|  | 
 | ||||||
|  | #include <flipper.h> | ||||||
|  | #include <flipper_v2.h> | ||||||
|  | 
 | ||||||
|  | #include <m-dict.h> | ||||||
|  | 
 | ||||||
|  | #define CLI_LINE_SIZE_MAX | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     CliCallback callback; | ||||||
|  |     void* context; | ||||||
|  | } CliCommand; | ||||||
|  | 
 | ||||||
|  | DICT_DEF2(CliCommandDict, string_t, STRING_OPLIST, CliCommand, M_POD_OPLIST) | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     CliSymbolAsciiSOH = 0x01, | ||||||
|  |     CliSymbolAsciiEOT = 0x04, | ||||||
|  |     CliSymbolAsciiBell = 0x07, | ||||||
|  |     CliSymbolAsciiBackspace = 0x08, | ||||||
|  |     CliSymbolAsciiTab = 0x09, | ||||||
|  |     CliSymbolAsciiCR = 0x0D, | ||||||
|  |     CliSymbolAsciiEsc = 0x1B, | ||||||
|  |     CliSymbolAsciiUS = 0x1F, | ||||||
|  |     CliSymbolAsciiSpace = 0x20, | ||||||
|  |     CliSymbolAsciiDel = 0x7F, | ||||||
|  | } CliSymbols; | ||||||
|  | 
 | ||||||
|  | struct Cli { | ||||||
|  |     CliCommandDict_t commands; | ||||||
|  |     osMutexId_t mutex; | ||||||
|  |     string_t line; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | Cli* cli_alloc(); | ||||||
|  | void cli_free(Cli* cli); | ||||||
|  | void cli_reset_state(Cli* cli); | ||||||
|  | void cli_print_version(); | ||||||
|  | void cli_putc(char c); | ||||||
| @ -8,6 +8,7 @@ | |||||||
| #include <gui/widget.h> | #include <gui/widget.h> | ||||||
| #include <assets_icons.h> | #include <assets_icons.h> | ||||||
| #include <api-hal-power.h> | #include <api-hal-power.h> | ||||||
|  | #include <cli/cli.h> | ||||||
| 
 | 
 | ||||||
| struct Power { | struct Power { | ||||||
|     Icon* usb_icon; |     Icon* usb_icon; | ||||||
| @ -17,6 +18,7 @@ struct Power { | |||||||
|     Widget* battery_widget; |     Widget* battery_widget; | ||||||
| 
 | 
 | ||||||
|     ValueMutex* menu_vm; |     ValueMutex* menu_vm; | ||||||
|  |     Cli* cli; | ||||||
|     MenuItem* menu; |     MenuItem* menu; | ||||||
| 
 | 
 | ||||||
|     uint8_t charge; |     uint8_t charge; | ||||||
| @ -54,6 +56,9 @@ Power* power_alloc() { | |||||||
|     power->menu_vm = furi_open("menu"); |     power->menu_vm = furi_open("menu"); | ||||||
|     furi_check(power->menu_vm); |     furi_check(power->menu_vm); | ||||||
| 
 | 
 | ||||||
|  |     power->cli = furi_open("cli"); | ||||||
|  |     furi_check(power->cli); | ||||||
|  | 
 | ||||||
|     power->menu = menu_item_alloc_menu("Power", NULL); |     power->menu = menu_item_alloc_menu("Power", NULL); | ||||||
|     menu_item_subitem_add( |     menu_item_subitem_add( | ||||||
|         power->menu, menu_item_alloc_function("Poweroff", NULL, power_off_callback, power)); |         power->menu, menu_item_alloc_function("Poweroff", NULL, power_off_callback, power)); | ||||||
| @ -82,10 +87,18 @@ void power_free(Power* power) { | |||||||
|     free(power); |     free(power); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void power_cli_poweroff(string_t args, void* context) { | ||||||
|  |     cli_print("Poweroff in 5 seconds"); | ||||||
|  |     osDelay(5000); | ||||||
|  |     api_hal_power_off(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void power_task(void* p) { | void power_task(void* p) { | ||||||
|     (void)p; |     (void)p; | ||||||
|     Power* power = power_alloc(); |     Power* power = power_alloc(); | ||||||
| 
 | 
 | ||||||
|  |     cli_add_command(power->cli, "poweroff", power_cli_poweroff, power); | ||||||
|  | 
 | ||||||
|     FuriRecordSubscriber* gui_record = furi_open_deprecated("gui", false, false, NULL, NULL, NULL); |     FuriRecordSubscriber* gui_record = furi_open_deprecated("gui", false, false, NULL, NULL, NULL); | ||||||
|     assert(gui_record); |     assert(gui_record); | ||||||
|     GuiApi* gui = furi_take(gui_record); |     GuiApi* gui = furi_take(gui_record); | ||||||
|  | |||||||
							
								
								
									
										138
									
								
								core/ring.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								core/ring.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,138 @@ | |||||||
|  | #include "ring.h" | ||||||
|  | #include <flipper_v2.h> | ||||||
|  | 
 | ||||||
|  | struct Ring { | ||||||
|  |     uint8_t* data; | ||||||
|  |     size_t size; | ||||||
|  |     volatile size_t read_ptr; | ||||||
|  |     volatile size_t write_ptr; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | Ring* ring_alloc(size_t size) { | ||||||
|  |     Ring* ring = furi_alloc(sizeof(Ring)); | ||||||
|  |     ring->size = size + 1; | ||||||
|  |     ring->data = furi_alloc(ring->size); | ||||||
|  |     ring_clear(ring); | ||||||
|  |     return ring; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ring_free(Ring* ring) { | ||||||
|  |     furi_assert(ring); | ||||||
|  |     free(ring->data); | ||||||
|  |     free(ring); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | size_t ring_size(Ring* ring) { | ||||||
|  |     furi_assert(ring); | ||||||
|  |     return ring->size - 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inline static size_t ring_read_calculate(Ring* ring, size_t r, size_t w) { | ||||||
|  |     if(w >= r) { | ||||||
|  |         return w - r; | ||||||
|  |     } else { | ||||||
|  |         return ring->size - (r - w); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | size_t ring_read_space(Ring* ring) { | ||||||
|  |     furi_assert(ring); | ||||||
|  | 
 | ||||||
|  |     const size_t r = ring->read_ptr; | ||||||
|  |     const size_t w = ring->write_ptr; | ||||||
|  | 
 | ||||||
|  |     return ring_read_calculate(ring, r, w); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inline static size_t ring_write_calculate(Ring* ring, size_t r, size_t w) { | ||||||
|  |     if(r > w) { | ||||||
|  |         return r - w - 1; | ||||||
|  |     } else { | ||||||
|  |         return ring->size - (r - w); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | size_t ring_write_space(Ring* ring) { | ||||||
|  |     furi_assert(ring); | ||||||
|  | 
 | ||||||
|  |     const size_t r = ring->read_ptr; | ||||||
|  |     const size_t w = ring->write_ptr; | ||||||
|  | 
 | ||||||
|  |     return ring_write_calculate(ring, r, w); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | size_t ring_push(Ring* ring, const uint8_t* data, size_t size) { | ||||||
|  |     furi_assert(ring); | ||||||
|  |     furi_assert(data); | ||||||
|  | 
 | ||||||
|  |     const size_t r = ring->read_ptr; | ||||||
|  |     size_t w = ring->write_ptr; | ||||||
|  |     const size_t write_space = ring_write_calculate(ring, r, w); | ||||||
|  | 
 | ||||||
|  |     if(write_space == 0) return 0; | ||||||
|  | 
 | ||||||
|  |     const size_t to_write = size > write_space ? write_space : size; | ||||||
|  |     size_t end, first, second; | ||||||
|  | 
 | ||||||
|  |     end = w + to_write; | ||||||
|  |     if(end > ring->size) { | ||||||
|  |         first = ring->size - w; | ||||||
|  |         second = end % ring->size; | ||||||
|  |     } else { | ||||||
|  |         first = to_write; | ||||||
|  |         second = 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     memcpy(ring->data + w, data, first); | ||||||
|  |     w = (w + first) % ring->size; | ||||||
|  | 
 | ||||||
|  |     if(second) { | ||||||
|  |         memcpy(ring->data + w, data + first, second); | ||||||
|  |         w = (w + second) % ring->size; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ring->write_ptr = w; | ||||||
|  | 
 | ||||||
|  |     return to_write; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | size_t ring_pull(Ring* ring, uint8_t* data, size_t size) { | ||||||
|  |     furi_assert(ring); | ||||||
|  |     furi_assert(data); | ||||||
|  | 
 | ||||||
|  |     size_t r = ring->read_ptr; | ||||||
|  |     const size_t w = ring->write_ptr; | ||||||
|  |     const size_t read_space = ring_read_calculate(ring, r, w); | ||||||
|  | 
 | ||||||
|  |     if(read_space == 0) return 0; | ||||||
|  | 
 | ||||||
|  |     size_t to_read = size > read_space ? read_space : size; | ||||||
|  |     size_t end, first, second; | ||||||
|  | 
 | ||||||
|  |     end = r + to_read; | ||||||
|  |     if(end > ring->size) { | ||||||
|  |         first = ring->size - r; | ||||||
|  |         second = end % ring->size; | ||||||
|  |     } else { | ||||||
|  |         first = to_read; | ||||||
|  |         second = 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     memcpy(data, ring->data + r, first); | ||||||
|  |     r = (r + first) % ring->size; | ||||||
|  | 
 | ||||||
|  |     if(second) { | ||||||
|  |         memcpy(data + first, ring->data + r, second); | ||||||
|  |         r = (r + second) % ring->size; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ring->read_ptr = r; | ||||||
|  | 
 | ||||||
|  |     return to_read; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ring_clear(Ring* ring) { | ||||||
|  |     furi_assert(ring); | ||||||
|  |     ring->read_ptr = 0; | ||||||
|  |     ring->write_ptr = 0; | ||||||
|  | } | ||||||
							
								
								
									
										22
									
								
								core/ring.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								core/ring.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <stdint.h> | ||||||
|  | #include <string.h> | ||||||
|  | 
 | ||||||
|  | typedef struct Ring Ring; | ||||||
|  | 
 | ||||||
|  | Ring* ring_alloc(size_t size); | ||||||
|  | 
 | ||||||
|  | void ring_free(Ring* ring); | ||||||
|  | 
 | ||||||
|  | size_t ring_size(Ring* ring); | ||||||
|  | 
 | ||||||
|  | size_t ring_read_space(Ring* ring); | ||||||
|  | 
 | ||||||
|  | size_t ring_write_space(Ring* ring); | ||||||
|  | 
 | ||||||
|  | size_t ring_push(Ring* ring, const uint8_t* data, size_t size); | ||||||
|  | 
 | ||||||
|  | size_t ring_pull(Ring* ring, uint8_t* data, size_t size); | ||||||
|  | 
 | ||||||
|  | void ring_clear(Ring* ring); | ||||||
| @ -1,105 +0,0 @@ | |||||||
| # script for stm32wbx family |  | ||||||
| 
 |  | ||||||
| gdb_port 4242 |  | ||||||
| 
 |  | ||||||
| # |  | ||||||
| # stm32wb devices support both JTAG and SWD transports. |  | ||||||
| # |  | ||||||
| source [find target/swj-dp.tcl] |  | ||||||
| source [find mem_helper.tcl] |  | ||||||
| 
 |  | ||||||
| if { [info exists CHIPNAME] } { |  | ||||||
|    set _CHIPNAME $CHIPNAME |  | ||||||
| } else { |  | ||||||
|    set _CHIPNAME stm32wbx |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| set _ENDIAN little |  | ||||||
| 
 |  | ||||||
| # Work-area is a space in RAM used for flash programming |  | ||||||
| # By default use 64kB |  | ||||||
| if { [info exists WORKAREASIZE] } { |  | ||||||
|    set _WORKAREASIZE $WORKAREASIZE |  | ||||||
| } else { |  | ||||||
|    set _WORKAREASIZE 0x10000 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #jtag scan chain |  | ||||||
| if { [info exists CPUTAPID] } { |  | ||||||
|    set _CPUTAPID $CPUTAPID |  | ||||||
| } else { |  | ||||||
|    if { [using_jtag] } { |  | ||||||
|       set _CPUTAPID 0x6ba00477 |  | ||||||
|    } else { |  | ||||||
|       # SWD IDCODE (single drop, arm) |  | ||||||
|       set _CPUTAPID 0x6ba02477 |  | ||||||
|    } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID |  | ||||||
| dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu |  | ||||||
| 
 |  | ||||||
| if {[using_jtag]} { |  | ||||||
|    jtag newtap $_CHIPNAME bs -irlen 5 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| set _TARGETNAME $_CHIPNAME.cpu |  | ||||||
| target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap |  | ||||||
| 
 |  | ||||||
| $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 |  | ||||||
| 
 |  | ||||||
| set _FLASHNAME $_CHIPNAME.flash |  | ||||||
| flash bank $_FLASHNAME stm32l4x 0 0 0 0 $_TARGETNAME |  | ||||||
| 
 |  | ||||||
| # Common knowledges tells JTAG speed should be <= F_CPU/6. |  | ||||||
| # F_CPU after reset is MSI 4MHz, so use F_JTAG = 500 kHz to stay on |  | ||||||
| # the safe side. |  | ||||||
| # |  | ||||||
| # Note that there is a pretty wide band where things are |  | ||||||
| # more or less stable, see http://openocd.zylin.com/#/c/3366/ |  | ||||||
| adapter speed 500 |  | ||||||
| 
 |  | ||||||
| adapter srst delay 100 |  | ||||||
| if {[using_jtag]} { |  | ||||||
|  jtag_ntrst_delay 100 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| reset_config srst_nogate |  | ||||||
| 
 |  | ||||||
| if {![using_hla]} { |  | ||||||
|    # if srst is not fitted use SYSRESETREQ to |  | ||||||
|    # perform a soft reset |  | ||||||
|    cortex_m reset_config sysresetreq |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| $_TARGETNAME configure -event reset-init { |  | ||||||
|     # CPU comes out of reset with MSI_ON | MSI_RDY | MSI Range 4 MHz. |  | ||||||
|     # Configure system to use MSI 24 MHz clock, compliant with VOS default Range1. |  | ||||||
|     # 2 WS compliant with VOS=Range1 and 24 MHz. |  | ||||||
|     mmw 0x58004000 0x00000102 0  ;# FLASH_ACR |= PRFTBE | 2(Latency) |  | ||||||
|     mmw 0x58000000 0x00000091 0  ;# RCC_CR = MSI_ON | MSI Range 24 MHz |  | ||||||
|     # Boost JTAG frequency |  | ||||||
|     adapter speed 4000 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| $_TARGETNAME configure -event reset-start { |  | ||||||
|     # Reset clock is MSI (4 MHz) |  | ||||||
|     adapter speed 500 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| $_TARGETNAME configure -event examine-end { |  | ||||||
|     # Enable debug during low power modes (uses more power) |  | ||||||
|     # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP |  | ||||||
|     mmw 0xE0042004 0x00000007 0 |  | ||||||
| 
 |  | ||||||
|     # Stop watchdog counters during halt |  | ||||||
|     # DBGMCU_APB1_FZR1 |= DBG_IWDG_STOP | DBG_WWDG_STOP |  | ||||||
|     mmw 0xE004203C 0x00001800 0 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| $_TARGETNAME configure -event trace-config { |  | ||||||
|     # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync |  | ||||||
|     # change this value accordingly to configure trace pins |  | ||||||
|     # assignment |  | ||||||
|     mmw 0xE0042004 0x00000020 0 |  | ||||||
| } |  | ||||||
							
								
								
									
										10
									
								
								firmware/targets/Inc/api-hal-uid.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								firmware/targets/Inc/api-hal-uid.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <stdint.h> | ||||||
|  | #include <stddef.h> | ||||||
|  | 
 | ||||||
|  | /* Get platform UID size in bytes */ | ||||||
|  | size_t api_hal_uid_size(); | ||||||
|  | 
 | ||||||
|  | /* Get const pointer to UID */ | ||||||
|  | const uint8_t* api_hal_uid(); | ||||||
							
								
								
									
										24
									
								
								firmware/targets/Inc/api-hal-vcp.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								firmware/targets/Inc/api-hal-vcp.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stdint.h> | ||||||
|  | #include <string.h> | ||||||
|  | 
 | ||||||
|  | /* Init VCP HAL
 | ||||||
|  |  * Allocates ring buffer and initializes state | ||||||
|  |  */ | ||||||
|  | void api_hal_vcp_init(); | ||||||
|  | 
 | ||||||
|  | /* 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 api_hal_vcp_rx(uint8_t* buffer, size_t size); | ||||||
|  | 
 | ||||||
|  | /* Transmit data to VCP
 | ||||||
|  |  * @param buffer - pointer to buffer | ||||||
|  |  * @param size - buffer size | ||||||
|  |  */ | ||||||
|  | void api_hal_vcp_tx(uint8_t* buffer, size_t size); | ||||||
| @ -5,3 +5,6 @@ | |||||||
| #include "api-hal-pwm.h" | #include "api-hal-pwm.h" | ||||||
| #include "api-hal-task.h" | #include "api-hal-task.h" | ||||||
| #include "api-hal-tim.h" | #include "api-hal-tim.h" | ||||||
|  | #include "api-hal-power.h" | ||||||
|  | #include "api-hal-vcp.h" | ||||||
|  | #include "api-hal-uid.h" | ||||||
| @ -51,8 +51,8 @@ | |||||||
| /* USER CODE BEGIN EXPORTED_DEFINES */ | /* USER CODE BEGIN EXPORTED_DEFINES */ | ||||||
| /* Define size for the receive and transmit buffer over CDC */ | /* Define size for the receive and transmit buffer over CDC */ | ||||||
| /* It's up to user to redefine and/or remove those define */ | /* It's up to user to redefine and/or remove those define */ | ||||||
| #define APP_RX_DATA_SIZE  2048 | #define APP_RX_DATA_SIZE  CDC_DATA_HS_MAX_PACKET_SIZE | ||||||
| #define APP_TX_DATA_SIZE  2048 | #define APP_TX_DATA_SIZE  CDC_DATA_HS_MAX_PACKET_SIZE | ||||||
| 
 | 
 | ||||||
| /* USER CODE END EXPORTED_DEFINES */ | /* USER CODE END EXPORTED_DEFINES */ | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -104,6 +104,7 @@ int main(void) | |||||||
|   /* USER CODE BEGIN 2 */ |   /* USER CODE BEGIN 2 */ | ||||||
|   MX_FATFS_Init(); |   MX_FATFS_Init(); | ||||||
|   delay_us_init_DWT(); |   delay_us_init_DWT(); | ||||||
|  |   api_hal_vcp_init(); | ||||||
|   /* USER CODE END 2 */ |   /* USER CODE END 2 */ | ||||||
| 
 | 
 | ||||||
|   /* Init scheduler */ |   /* Init scheduler */ | ||||||
|  | |||||||
| @ -51,6 +51,12 @@ | |||||||
| 
 | 
 | ||||||
| /* USER CODE BEGIN PRIVATE_TYPES */ | /* USER CODE BEGIN PRIVATE_TYPES */ | ||||||
| 
 | 
 | ||||||
|  | extern void _api_hal_vcp_init(); | ||||||
|  | extern void _api_hal_vcp_deinit(); | ||||||
|  | extern void _api_hal_vcp_control_line(uint8_t state); | ||||||
|  | extern void _api_hal_vcp_rx_callback(char* buffer, size_t size); | ||||||
|  | extern void _api_hal_vcp_tx_complete(size_t size); | ||||||
|  | 
 | ||||||
| /* USER CODE END PRIVATE_TYPES */ | /* USER CODE END PRIVATE_TYPES */ | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
| @ -156,6 +162,7 @@ static int8_t CDC_Init_FS(void) | |||||||
|   /* Set Application Buffers */ |   /* Set Application Buffers */ | ||||||
|   USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, 0); |   USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, 0); | ||||||
|   USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS); |   USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS); | ||||||
|  |   _api_hal_vcp_init(); | ||||||
|   return (USBD_OK); |   return (USBD_OK); | ||||||
|   /* USER CODE END 3 */ |   /* USER CODE END 3 */ | ||||||
| } | } | ||||||
| @ -167,6 +174,7 @@ static int8_t CDC_Init_FS(void) | |||||||
| static int8_t CDC_DeInit_FS(void) | static int8_t CDC_DeInit_FS(void) | ||||||
| { | { | ||||||
|   /* USER CODE BEGIN 4 */ |   /* USER CODE BEGIN 4 */ | ||||||
|  |   _api_hal_vcp_deinit(); | ||||||
|   return (USBD_OK); |   return (USBD_OK); | ||||||
|   /* USER CODE END 4 */ |   /* USER CODE END 4 */ | ||||||
| } | } | ||||||
| @ -181,63 +189,34 @@ static int8_t CDC_DeInit_FS(void) | |||||||
| static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length) | static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length) | ||||||
| { | { | ||||||
|   /* USER CODE BEGIN 5 */ |   /* USER CODE BEGIN 5 */ | ||||||
|   switch(cmd) |   if (cmd == CDC_SEND_ENCAPSULATED_COMMAND) { | ||||||
|   { |   } else if (cmd == CDC_GET_ENCAPSULATED_RESPONSE) { | ||||||
|     case CDC_SEND_ENCAPSULATED_COMMAND: |   } else if (cmd == CDC_SET_COMM_FEATURE) { | ||||||
| 
 |   } else if (cmd == CDC_GET_COMM_FEATURE) { | ||||||
|     break; |   } else if (cmd == CDC_CLEAR_COMM_FEATURE) { | ||||||
| 
 |   } else if (cmd == CDC_SET_LINE_CODING) { | ||||||
|     case CDC_GET_ENCAPSULATED_RESPONSE: |       /*******************************************************************************/ | ||||||
| 
 |       /* Line Coding Structure                                                       */ | ||||||
|     break; |       /*-----------------------------------------------------------------------------*/ | ||||||
| 
 |       /* Offset | Field       | Size | Value  | Description                          */ | ||||||
|     case CDC_SET_COMM_FEATURE: |       /* 0      | dwDTERate   |   4  | Number |Data terminal rate, in bits per second*/ | ||||||
| 
 |       /* 4      | bCharFormat |   1  | Number | Stop bits                            */ | ||||||
|     break; |       /*                                        0 - 1 Stop bit                       */ | ||||||
| 
 |       /*                                        1 - 1.5 Stop bits                    */ | ||||||
|     case CDC_GET_COMM_FEATURE: |       /*                                        2 - 2 Stop bits                      */ | ||||||
| 
 |       /* 5      | bParityType |  1   | Number | Parity                               */ | ||||||
|     break; |       /*                                        0 - None                             */ | ||||||
| 
 |       /*                                        1 - Odd                              */ | ||||||
|     case CDC_CLEAR_COMM_FEATURE: |       /*                                        2 - Even                             */ | ||||||
| 
 |       /*                                        3 - Mark                             */ | ||||||
|     break; |       /*                                        4 - Space                            */ | ||||||
| 
 |       /* 6      | bDataBits  |   1   | Number Data bits (5, 6, 7, 8 or 16).          */ | ||||||
|   /*******************************************************************************/ |       /*******************************************************************************/ | ||||||
|   /* Line Coding Structure                                                       */ |   } else if (cmd == CDC_GET_LINE_CODING) { | ||||||
|   /*-----------------------------------------------------------------------------*/ |   } else if (cmd == CDC_SET_CONTROL_LINE_STATE) { | ||||||
|   /* Offset | Field       | Size | Value  | Description                          */ |     _api_hal_vcp_control_line(((USBD_SetupReqTypedef*)pbuf)->wValue); | ||||||
|   /* 0      | dwDTERate   |   4  | Number |Data terminal rate, in bits per second*/ |   } else if (cmd == CDC_SEND_BREAK) { | ||||||
|   /* 4      | bCharFormat |   1  | Number | Stop bits                            */ |   } else { | ||||||
|   /*                                        0 - 1 Stop bit                       */ |  | ||||||
|   /*                                        1 - 1.5 Stop bits                    */ |  | ||||||
|   /*                                        2 - 2 Stop bits                      */ |  | ||||||
|   /* 5      | bParityType |  1   | Number | Parity                               */ |  | ||||||
|   /*                                        0 - None                             */ |  | ||||||
|   /*                                        1 - Odd                              */ |  | ||||||
|   /*                                        2 - Even                             */ |  | ||||||
|   /*                                        3 - Mark                             */ |  | ||||||
|   /*                                        4 - Space                            */ |  | ||||||
|   /* 6      | bDataBits  |   1   | Number Data bits (5, 6, 7, 8 or 16).          */ |  | ||||||
|   /*******************************************************************************/ |  | ||||||
|     case CDC_SET_LINE_CODING: |  | ||||||
| 
 |  | ||||||
|     break; |  | ||||||
| 
 |  | ||||||
|     case CDC_GET_LINE_CODING: |  | ||||||
| 
 |  | ||||||
|     break; |  | ||||||
| 
 |  | ||||||
|     case CDC_SET_CONTROL_LINE_STATE: |  | ||||||
| 
 |  | ||||||
|     break; |  | ||||||
| 
 |  | ||||||
|     case CDC_SEND_BREAK: |  | ||||||
| 
 |  | ||||||
|     break; |  | ||||||
| 
 |  | ||||||
|   default: |  | ||||||
|     break; |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   return (USBD_OK); |   return (USBD_OK); | ||||||
| @ -262,7 +241,7 @@ static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length) | |||||||
| static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len) | static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len) | ||||||
| { | { | ||||||
|   /* USER CODE BEGIN 6 */ |   /* USER CODE BEGIN 6 */ | ||||||
|   USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]); |   _api_hal_vcp_rx_callback((char*)Buf, *Len); | ||||||
|   USBD_CDC_ReceivePacket(&hUsbDeviceFS); |   USBD_CDC_ReceivePacket(&hUsbDeviceFS); | ||||||
|   return (USBD_OK); |   return (USBD_OK); | ||||||
|   /* USER CODE END 6 */ |   /* USER CODE END 6 */ | ||||||
| @ -287,7 +266,8 @@ uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len) | |||||||
|   if (hcdc->TxState != 0){ |   if (hcdc->TxState != 0){ | ||||||
|     return USBD_BUSY; |     return USBD_BUSY; | ||||||
|   } |   } | ||||||
|   USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len); |   memcpy(UserTxBufferFS, Buf, Len); | ||||||
|  |   USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, Len); | ||||||
|   result = USBD_CDC_TransmitPacket(&hUsbDeviceFS); |   result = USBD_CDC_TransmitPacket(&hUsbDeviceFS); | ||||||
|   /* USER CODE END 7 */ |   /* USER CODE END 7 */ | ||||||
|   return result; |   return result; | ||||||
| @ -310,8 +290,8 @@ static int8_t CDC_TransmitCplt_FS(uint8_t *Buf, uint32_t *Len, uint8_t epnum) | |||||||
|   uint8_t result = USBD_OK; |   uint8_t result = USBD_OK; | ||||||
|   /* USER CODE BEGIN 13 */ |   /* USER CODE BEGIN 13 */ | ||||||
|   UNUSED(Buf); |   UNUSED(Buf); | ||||||
|   UNUSED(Len); |  | ||||||
|   UNUSED(epnum); |   UNUSED(epnum); | ||||||
|  |   _api_hal_vcp_tx_complete(*Len); | ||||||
|   /* USER CODE END 13 */ |   /* USER CODE END 13 */ | ||||||
|   return result; |   return result; | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										10
									
								
								firmware/targets/f2/api-hal/api-hal-uid.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								firmware/targets/f2/api-hal/api-hal-uid.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | #include <api-hal-uid.h> | ||||||
|  | #include <stm32l4xx.h> | ||||||
|  | 
 | ||||||
|  | size_t api_hal_uid_size() { | ||||||
|  |     return 96/8; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const uint8_t* api_hal_uid() { | ||||||
|  |     return (const uint8_t *)UID_BASE; | ||||||
|  | } | ||||||
							
								
								
									
										92
									
								
								firmware/targets/f2/api-hal/api-hal-vcp.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								firmware/targets/f2/api-hal/api-hal-vcp.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,92 @@ | |||||||
|  | #include <api-hal-vcp.h> | ||||||
|  | #include <usbd_cdc_if.h> | ||||||
|  | #include <flipper_v2.h> | ||||||
|  | #include <stream_buffer.h> | ||||||
|  | 
 | ||||||
|  | #define API_HAL_VCP_RX_BUFFER_SIZE 600 | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     StreamBufferHandle_t rx_stream; | ||||||
|  |     osSemaphoreId_t tx_semaphore; | ||||||
|  |     volatile bool alive; | ||||||
|  |     volatile bool underrun; | ||||||
|  | } ApiHalVcp; | ||||||
|  | 
 | ||||||
|  | ApiHalVcp api_hal_vcp; | ||||||
|  | 
 | ||||||
|  | static const uint8_t ascii_soh = 0x01; | ||||||
|  | static const uint8_t ascii_eot = 0x04; | ||||||
|  | 
 | ||||||
|  | void _api_hal_vcp_init(); | ||||||
|  | void _api_hal_vcp_deinit(); | ||||||
|  | void _api_hal_vcp_control_line(uint8_t state); | ||||||
|  | void _api_hal_vcp_rx_callback(const uint8_t* buffer, size_t size); | ||||||
|  | void _api_hal_vcp_tx_complete(size_t size); | ||||||
|  | 
 | ||||||
|  | void api_hal_vcp_init() { | ||||||
|  |     api_hal_vcp.rx_stream = xStreamBufferCreate(API_HAL_VCP_RX_BUFFER_SIZE, 1); | ||||||
|  |     api_hal_vcp.tx_semaphore = osSemaphoreNew(1, 1, NULL); | ||||||
|  |     api_hal_vcp.alive = false; | ||||||
|  |     api_hal_vcp.underrun = false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void _api_hal_vcp_init() { | ||||||
|  |     osSemaphoreRelease(api_hal_vcp.tx_semaphore); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void _api_hal_vcp_deinit() { | ||||||
|  |     api_hal_vcp.alive = false; | ||||||
|  |     osSemaphoreRelease(api_hal_vcp.tx_semaphore); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void _api_hal_vcp_control_line(uint8_t state) { | ||||||
|  |     // bit 0: DTR state, bit 1: RTS state
 | ||||||
|  |     // bool dtr = state & 0b01;
 | ||||||
|  |     bool rts = state & 0b10; | ||||||
|  | 
 | ||||||
|  |     if (rts) { | ||||||
|  |         api_hal_vcp.alive = true; | ||||||
|  |         _api_hal_vcp_rx_callback(&ascii_soh, 1); // SOH
 | ||||||
|  |     } else { | ||||||
|  |         api_hal_vcp.alive = false; | ||||||
|  |         _api_hal_vcp_rx_callback(&ascii_eot, 1); // EOT
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     osSemaphoreRelease(api_hal_vcp.tx_semaphore); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void _api_hal_vcp_rx_callback(const uint8_t* buffer, size_t size) { | ||||||
|  |     BaseType_t xHigherPriorityTaskWoken = pdFALSE; | ||||||
|  |     size_t ret = xStreamBufferSendFromISR(api_hal_vcp.rx_stream, buffer, size, &xHigherPriorityTaskWoken); | ||||||
|  |     if (ret != size) { | ||||||
|  |         api_hal_vcp.underrun = true; | ||||||
|  |     } | ||||||
|  |     portYIELD_FROM_ISR(xHigherPriorityTaskWoken); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void _api_hal_vcp_tx_complete(size_t size) { | ||||||
|  |     osSemaphoreRelease(api_hal_vcp.tx_semaphore); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | size_t api_hal_vcp_rx(uint8_t* buffer, size_t size) { | ||||||
|  |     return xStreamBufferReceive(api_hal_vcp.rx_stream, buffer, size, portMAX_DELAY); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void api_hal_vcp_tx(uint8_t* buffer, size_t size) { | ||||||
|  |     while (size > 0 && api_hal_vcp.alive) { | ||||||
|  |         furi_check(osSemaphoreAcquire(api_hal_vcp.tx_semaphore, osWaitForever) == osOK); | ||||||
|  | 
 | ||||||
|  |         size_t batch_size = size; | ||||||
|  |         if (batch_size > APP_TX_DATA_SIZE) { | ||||||
|  |             batch_size = APP_TX_DATA_SIZE; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (CDC_Transmit_FS(buffer, batch_size) == USBD_OK) { | ||||||
|  |             size -= batch_size; | ||||||
|  |             buffer += batch_size; | ||||||
|  |         } else { | ||||||
|  |             // Shouldn't be there 
 | ||||||
|  |             osDelay(100); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,6 +1,6 @@ | |||||||
| TOOLCHAIN = arm | TOOLCHAIN = arm | ||||||
| 
 | 
 | ||||||
| DEBUG_AGENT		= set -m; st-util -n --semihosting | DEBUG_AGENT		= openocd -f interface/stlink-v2.cfg -c "transport select hla_swd" -f target/stm32l4x.cfg -c "init" | ||||||
| 
 | 
 | ||||||
| BOOT_ADDRESS	= 0x08000000 | BOOT_ADDRESS	= 0x08000000 | ||||||
| FW_ADDRESS		= 0x08008000 | FW_ADDRESS		= 0x08008000 | ||||||
|  | |||||||
| @ -51,8 +51,8 @@ | |||||||
| /* USER CODE BEGIN EXPORTED_DEFINES */ | /* USER CODE BEGIN EXPORTED_DEFINES */ | ||||||
| /* Define size for the receive and transmit buffer over CDC */ | /* Define size for the receive and transmit buffer over CDC */ | ||||||
| /* It's up to user to redefine and/or remove those define */ | /* It's up to user to redefine and/or remove those define */ | ||||||
| #define APP_RX_DATA_SIZE  2048 | #define APP_RX_DATA_SIZE  CDC_DATA_HS_MAX_PACKET_SIZE | ||||||
| #define APP_TX_DATA_SIZE  2048 | #define APP_TX_DATA_SIZE  CDC_DATA_HS_MAX_PACKET_SIZE | ||||||
| 
 | 
 | ||||||
| /* USER CODE END EXPORTED_DEFINES */ | /* USER CODE END EXPORTED_DEFINES */ | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -111,6 +111,7 @@ int main(void) | |||||||
|   /* USER CODE BEGIN 2 */ |   /* USER CODE BEGIN 2 */ | ||||||
|   MX_FATFS_Init(); |   MX_FATFS_Init(); | ||||||
|   delay_us_init_DWT(); |   delay_us_init_DWT(); | ||||||
|  |   api_hal_vcp_init(); | ||||||
|   /* USER CODE END 2 */ |   /* USER CODE END 2 */ | ||||||
| 
 | 
 | ||||||
|   /* Init scheduler */ |   /* Init scheduler */ | ||||||
|  | |||||||
| @ -51,6 +51,12 @@ | |||||||
| 
 | 
 | ||||||
| /* USER CODE BEGIN PRIVATE_TYPES */ | /* USER CODE BEGIN PRIVATE_TYPES */ | ||||||
| 
 | 
 | ||||||
|  | extern void _api_hal_vcp_init(); | ||||||
|  | extern void _api_hal_vcp_deinit(); | ||||||
|  | extern void _api_hal_vcp_control_line(uint8_t state); | ||||||
|  | extern void _api_hal_vcp_rx_callback(char* buffer, size_t size); | ||||||
|  | extern void _api_hal_vcp_tx_complete(size_t size); | ||||||
|  | 
 | ||||||
| /* USER CODE END PRIVATE_TYPES */ | /* USER CODE END PRIVATE_TYPES */ | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
| @ -156,6 +162,7 @@ static int8_t CDC_Init_FS(void) | |||||||
|   /* Set Application Buffers */ |   /* Set Application Buffers */ | ||||||
|   USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, 0); |   USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, 0); | ||||||
|   USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS); |   USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS); | ||||||
|  |   _api_hal_vcp_init(); | ||||||
|   return (USBD_OK); |   return (USBD_OK); | ||||||
|   /* USER CODE END 3 */ |   /* USER CODE END 3 */ | ||||||
| } | } | ||||||
| @ -167,6 +174,7 @@ static int8_t CDC_Init_FS(void) | |||||||
| static int8_t CDC_DeInit_FS(void) | static int8_t CDC_DeInit_FS(void) | ||||||
| { | { | ||||||
|   /* USER CODE BEGIN 4 */ |   /* USER CODE BEGIN 4 */ | ||||||
|  |   _api_hal_vcp_deinit(); | ||||||
|   return (USBD_OK); |   return (USBD_OK); | ||||||
|   /* USER CODE END 4 */ |   /* USER CODE END 4 */ | ||||||
| } | } | ||||||
| @ -181,63 +189,34 @@ static int8_t CDC_DeInit_FS(void) | |||||||
| static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length) | static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length) | ||||||
| { | { | ||||||
|   /* USER CODE BEGIN 5 */ |   /* USER CODE BEGIN 5 */ | ||||||
|   switch(cmd) |   if (cmd == CDC_SEND_ENCAPSULATED_COMMAND) { | ||||||
|   { |   } else if (cmd == CDC_GET_ENCAPSULATED_RESPONSE) { | ||||||
|     case CDC_SEND_ENCAPSULATED_COMMAND: |   } else if (cmd == CDC_SET_COMM_FEATURE) { | ||||||
| 
 |   } else if (cmd == CDC_GET_COMM_FEATURE) { | ||||||
|     break; |   } else if (cmd == CDC_CLEAR_COMM_FEATURE) { | ||||||
| 
 |   } else if (cmd == CDC_SET_LINE_CODING) { | ||||||
|     case CDC_GET_ENCAPSULATED_RESPONSE: |       /*******************************************************************************/ | ||||||
| 
 |       /* Line Coding Structure                                                       */ | ||||||
|     break; |       /*-----------------------------------------------------------------------------*/ | ||||||
| 
 |       /* Offset | Field       | Size | Value  | Description                          */ | ||||||
|     case CDC_SET_COMM_FEATURE: |       /* 0      | dwDTERate   |   4  | Number |Data terminal rate, in bits per second*/ | ||||||
| 
 |       /* 4      | bCharFormat |   1  | Number | Stop bits                            */ | ||||||
|     break; |       /*                                        0 - 1 Stop bit                       */ | ||||||
| 
 |       /*                                        1 - 1.5 Stop bits                    */ | ||||||
|     case CDC_GET_COMM_FEATURE: |       /*                                        2 - 2 Stop bits                      */ | ||||||
| 
 |       /* 5      | bParityType |  1   | Number | Parity                               */ | ||||||
|     break; |       /*                                        0 - None                             */ | ||||||
| 
 |       /*                                        1 - Odd                              */ | ||||||
|     case CDC_CLEAR_COMM_FEATURE: |       /*                                        2 - Even                             */ | ||||||
| 
 |       /*                                        3 - Mark                             */ | ||||||
|     break; |       /*                                        4 - Space                            */ | ||||||
| 
 |       /* 6      | bDataBits  |   1   | Number Data bits (5, 6, 7, 8 or 16).          */ | ||||||
|   /*******************************************************************************/ |       /*******************************************************************************/ | ||||||
|   /* Line Coding Structure                                                       */ |   } else if (cmd == CDC_GET_LINE_CODING) { | ||||||
|   /*-----------------------------------------------------------------------------*/ |   } else if (cmd == CDC_SET_CONTROL_LINE_STATE) { | ||||||
|   /* Offset | Field       | Size | Value  | Description                          */ |     _api_hal_vcp_control_line(((USBD_SetupReqTypedef*)pbuf)->wValue); | ||||||
|   /* 0      | dwDTERate   |   4  | Number |Data terminal rate, in bits per second*/ |   } else if (cmd == CDC_SEND_BREAK) { | ||||||
|   /* 4      | bCharFormat |   1  | Number | Stop bits                            */ |   } else { | ||||||
|   /*                                        0 - 1 Stop bit                       */ |  | ||||||
|   /*                                        1 - 1.5 Stop bits                    */ |  | ||||||
|   /*                                        2 - 2 Stop bits                      */ |  | ||||||
|   /* 5      | bParityType |  1   | Number | Parity                               */ |  | ||||||
|   /*                                        0 - None                             */ |  | ||||||
|   /*                                        1 - Odd                              */ |  | ||||||
|   /*                                        2 - Even                             */ |  | ||||||
|   /*                                        3 - Mark                             */ |  | ||||||
|   /*                                        4 - Space                            */ |  | ||||||
|   /* 6      | bDataBits  |   1   | Number Data bits (5, 6, 7, 8 or 16).          */ |  | ||||||
|   /*******************************************************************************/ |  | ||||||
|     case CDC_SET_LINE_CODING: |  | ||||||
| 
 |  | ||||||
|     break; |  | ||||||
| 
 |  | ||||||
|     case CDC_GET_LINE_CODING: |  | ||||||
| 
 |  | ||||||
|     break; |  | ||||||
| 
 |  | ||||||
|     case CDC_SET_CONTROL_LINE_STATE: |  | ||||||
| 
 |  | ||||||
|     break; |  | ||||||
| 
 |  | ||||||
|     case CDC_SEND_BREAK: |  | ||||||
| 
 |  | ||||||
|     break; |  | ||||||
| 
 |  | ||||||
|   default: |  | ||||||
|     break; |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   return (USBD_OK); |   return (USBD_OK); | ||||||
| @ -262,7 +241,7 @@ static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length) | |||||||
| static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len) | static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len) | ||||||
| { | { | ||||||
|   /* USER CODE BEGIN 6 */ |   /* USER CODE BEGIN 6 */ | ||||||
|   USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]); |   _api_hal_vcp_rx_callback((char*)Buf, *Len); | ||||||
|   USBD_CDC_ReceivePacket(&hUsbDeviceFS); |   USBD_CDC_ReceivePacket(&hUsbDeviceFS); | ||||||
|   return (USBD_OK); |   return (USBD_OK); | ||||||
|   /* USER CODE END 6 */ |   /* USER CODE END 6 */ | ||||||
| @ -287,7 +266,8 @@ uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len) | |||||||
|   if (hcdc->TxState != 0){ |   if (hcdc->TxState != 0){ | ||||||
|     return USBD_BUSY; |     return USBD_BUSY; | ||||||
|   } |   } | ||||||
|   USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len); |   memcpy(UserTxBufferFS, Buf, Len); | ||||||
|  |   USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, Len); | ||||||
|   result = USBD_CDC_TransmitPacket(&hUsbDeviceFS); |   result = USBD_CDC_TransmitPacket(&hUsbDeviceFS); | ||||||
|   /* USER CODE END 7 */ |   /* USER CODE END 7 */ | ||||||
|   return result; |   return result; | ||||||
| @ -310,8 +290,8 @@ static int8_t CDC_TransmitCplt_FS(uint8_t *Buf, uint32_t *Len, uint8_t epnum) | |||||||
|   uint8_t result = USBD_OK; |   uint8_t result = USBD_OK; | ||||||
|   /* USER CODE BEGIN 13 */ |   /* USER CODE BEGIN 13 */ | ||||||
|   UNUSED(Buf); |   UNUSED(Buf); | ||||||
|   UNUSED(Len); |  | ||||||
|   UNUSED(epnum); |   UNUSED(epnum); | ||||||
|  |   _api_hal_vcp_tx_complete(*Len); | ||||||
|   /* USER CODE END 13 */ |   /* USER CODE END 13 */ | ||||||
|   return result; |   return result; | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										10
									
								
								firmware/targets/f3/api-hal/api-hal-uuid.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								firmware/targets/f3/api-hal/api-hal-uuid.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | #include <api-hal-uid.h> | ||||||
|  | #include <stm32wbxx.h> | ||||||
|  | 
 | ||||||
|  | size_t api_hal_uid_size() { | ||||||
|  |     return 64/8; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const uint8_t* api_hal_uid() { | ||||||
|  |     return (const uint8_t *)UID64_BASE; | ||||||
|  | } | ||||||
							
								
								
									
										92
									
								
								firmware/targets/f3/api-hal/api-hal-vcp.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								firmware/targets/f3/api-hal/api-hal-vcp.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,92 @@ | |||||||
|  | #include <api-hal-vcp.h> | ||||||
|  | #include <usbd_cdc_if.h> | ||||||
|  | #include <flipper_v2.h> | ||||||
|  | #include <stream_buffer.h> | ||||||
|  | 
 | ||||||
|  | #define API_HAL_VCP_RX_BUFFER_SIZE 600 | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     StreamBufferHandle_t rx_stream; | ||||||
|  |     osSemaphoreId_t tx_semaphore; | ||||||
|  |     volatile bool alive; | ||||||
|  |     volatile bool underrun; | ||||||
|  | } ApiHalVcp; | ||||||
|  | 
 | ||||||
|  | ApiHalVcp api_hal_vcp; | ||||||
|  | 
 | ||||||
|  | static const uint8_t ascii_soh = 0x01; | ||||||
|  | static const uint8_t ascii_eot = 0x04; | ||||||
|  | 
 | ||||||
|  | void _api_hal_vcp_init(); | ||||||
|  | void _api_hal_vcp_deinit(); | ||||||
|  | void _api_hal_vcp_control_line(uint8_t state); | ||||||
|  | void _api_hal_vcp_rx_callback(const uint8_t* buffer, size_t size); | ||||||
|  | void _api_hal_vcp_tx_complete(size_t size); | ||||||
|  | 
 | ||||||
|  | void api_hal_vcp_init() { | ||||||
|  |     api_hal_vcp.rx_stream = xStreamBufferCreate(API_HAL_VCP_RX_BUFFER_SIZE, 1); | ||||||
|  |     api_hal_vcp.tx_semaphore = osSemaphoreNew(1, 1, NULL); | ||||||
|  |     api_hal_vcp.alive = false; | ||||||
|  |     api_hal_vcp.underrun = false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void _api_hal_vcp_init() { | ||||||
|  |     osSemaphoreRelease(api_hal_vcp.tx_semaphore); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void _api_hal_vcp_deinit() { | ||||||
|  |     api_hal_vcp.alive = false; | ||||||
|  |     osSemaphoreRelease(api_hal_vcp.tx_semaphore); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void _api_hal_vcp_control_line(uint8_t state) { | ||||||
|  |     // bit 0: DTR state, bit 1: RTS state
 | ||||||
|  |     // bool dtr = state & 0b01;
 | ||||||
|  |     bool rts = state & 0b10; | ||||||
|  | 
 | ||||||
|  |     if (rts) { | ||||||
|  |         api_hal_vcp.alive = true; | ||||||
|  |         _api_hal_vcp_rx_callback(&ascii_soh, 1); // SOH
 | ||||||
|  |     } else { | ||||||
|  |         api_hal_vcp.alive = false; | ||||||
|  |         _api_hal_vcp_rx_callback(&ascii_eot, 1); // EOT
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     osSemaphoreRelease(api_hal_vcp.tx_semaphore); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void _api_hal_vcp_rx_callback(const uint8_t* buffer, size_t size) { | ||||||
|  |     BaseType_t xHigherPriorityTaskWoken = pdFALSE; | ||||||
|  |     size_t ret = xStreamBufferSendFromISR(api_hal_vcp.rx_stream, buffer, size, &xHigherPriorityTaskWoken); | ||||||
|  |     if (ret != size) { | ||||||
|  |         api_hal_vcp.underrun = true; | ||||||
|  |     } | ||||||
|  |     portYIELD_FROM_ISR(xHigherPriorityTaskWoken); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void _api_hal_vcp_tx_complete(size_t size) { | ||||||
|  |     osSemaphoreRelease(api_hal_vcp.tx_semaphore); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | size_t api_hal_vcp_rx(uint8_t* buffer, size_t size) { | ||||||
|  |     return xStreamBufferReceive(api_hal_vcp.rx_stream, buffer, size, portMAX_DELAY); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void api_hal_vcp_tx(uint8_t* buffer, size_t size) { | ||||||
|  |     while (size > 0 && api_hal_vcp.alive) { | ||||||
|  |         furi_check(osSemaphoreAcquire(api_hal_vcp.tx_semaphore, osWaitForever) == osOK); | ||||||
|  | 
 | ||||||
|  |         size_t batch_size = size; | ||||||
|  |         if (batch_size > APP_TX_DATA_SIZE) { | ||||||
|  |             batch_size = APP_TX_DATA_SIZE; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (CDC_Transmit_FS(buffer, batch_size) == USBD_OK) { | ||||||
|  |             size -= batch_size; | ||||||
|  |             buffer += batch_size; | ||||||
|  |         } else { | ||||||
|  |             // Shouldn't be there 
 | ||||||
|  |             osDelay(100); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,7 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| 
 |  | ||||||
| #include "api-hal-gpio.h" |  | ||||||
| #include "api-hal-delay.h" |  | ||||||
| #include "api-hal-pwm.h" |  | ||||||
| #include "api-hal-task.h" |  | ||||||
| #include "api-hal-tim.h" |  | ||||||
| @ -270,6 +270,7 @@ Mcu.Pin12=PA2 | |||||||
| PD0.GPIOParameters=GPIO_Speed,PinState,GPIO_Label | PD0.GPIOParameters=GPIO_Speed,PinState,GPIO_Label | ||||||
| Mcu.Pin10=PA0 | Mcu.Pin10=PA0 | ||||||
| SH.GPXTI10.ConfNb=1 | SH.GPXTI10.ConfNb=1 | ||||||
|  | USB_DEVICE.APP_RX_DATA_SIZE=512 | ||||||
| TIM2.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_ENABLE | TIM2.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_ENABLE | ||||||
| PC3.GPIO_Label=PC3 | PC3.GPIO_Label=PC3 | ||||||
| PA3.PinState=GPIO_PIN_SET | PA3.PinState=GPIO_PIN_SET | ||||||
| @ -453,7 +454,7 @@ OSC_IN.GPIOParameters=GPIO_Label | |||||||
| PB12.Locked=true | PB12.Locked=true | ||||||
| ProjectManager.DeletePrevious=true | ProjectManager.DeletePrevious=true | ||||||
| PB10.Locked=true | PB10.Locked=true | ||||||
| USB_DEVICE.IPParameters=VirtualMode,VirtualModeFS,CLASS_NAME_FS,MANUFACTURER_STRING,PRODUCT_STRING_CDC_FS | USB_DEVICE.IPParameters=VirtualMode,VirtualModeFS,CLASS_NAME_FS,MANUFACTURER_STRING,PRODUCT_STRING_CDC_FS,APP_RX_DATA_SIZE,APP_TX_DATA_SIZE | ||||||
| TIM16.Channel=TIM_CHANNEL_1 | TIM16.Channel=TIM_CHANNEL_1 | ||||||
| RCC.AHB2CLKDivider=RCC_SYSCLK_DIV2 | RCC.AHB2CLKDivider=RCC_SYSCLK_DIV2 | ||||||
| RCC.FamilyName=M | RCC.FamilyName=M | ||||||
| @ -528,6 +529,7 @@ PA13.Locked=true | |||||||
| RF1.Mode=RF1_Activate | RF1.Mode=RF1_Activate | ||||||
| PB7.Mode=Asynchronous | PB7.Mode=Asynchronous | ||||||
| NVIC.EXTI9_5_IRQn=true\:5\:0\:true\:false\:true\:false\:true\:true | NVIC.EXTI9_5_IRQn=true\:5\:0\:true\:false\:true\:false\:true\:true | ||||||
|  | USB_DEVICE.APP_TX_DATA_SIZE=512 | ||||||
| PA14.Signal=SYS_JTCK-SWCLK | PA14.Signal=SYS_JTCK-SWCLK | ||||||
| PB2.GPIO_Label=PB2 | PB2.GPIO_Label=PB2 | ||||||
| PC6.GPIOParameters=GPIO_Label | PC6.GPIOParameters=GPIO_Label | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| TOOLCHAIN = arm | TOOLCHAIN = arm | ||||||
| 
 | 
 | ||||||
| DEBUG_AGENT		= openocd -f interface/stlink-v2.cfg -c "transport select hla_swd" -f ../debug/stm32wbx.cfg -c "init" -c "reset halt" | DEBUG_AGENT		= openocd -f interface/stlink.cfg -c "transport select hla_swd" -f target/stm32wbx.cfg -c "init" | ||||||
| 
 | 
 | ||||||
| BOOT_ADDRESS	= 0x08000000 | BOOT_ADDRESS	= 0x08000000 | ||||||
| FW_ADDRESS		= 0x08008000 | FW_ADDRESS		= 0x08008000 | ||||||
|  | |||||||
							
								
								
									
										2
									
								
								lib/mlib
									
									
									
									
									
								
							
							
								
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								lib/mlib
									
									
									
									
									
								
							| @ -1 +1 @@ | |||||||
| Subproject commit eb7556f88faf0bbfd6a4ae99a3d53dcbe2064b88 | Subproject commit ebf440731d44f5eba926e0f648758676461bbba4 | ||||||
| @ -73,7 +73,7 @@ upload: $(OBJ_DIR)/upload | |||||||
| debug: flash | debug: flash | ||||||
| 	$(DEBUG_AGENT) & echo $$! > $(OBJ_DIR)/agent.PID | 	$(DEBUG_AGENT) & echo $$! > $(OBJ_DIR)/agent.PID | ||||||
| 	arm-none-eabi-gdb \
 | 	arm-none-eabi-gdb \
 | ||||||
| 		-ex "target extended-remote 127.0.0.1:4242" \
 | 		-ex "target extended-remote 127.0.0.1:3333" \
 | ||||||
| 		-ex "set confirm off" \
 | 		-ex "set confirm off" \
 | ||||||
| 		-ex "source ../debug/FreeRTOS/FreeRTOS.py" \
 | 		-ex "source ../debug/FreeRTOS/FreeRTOS.py" \
 | ||||||
| 		$(OBJ_DIR)/$(PROJECT).elf; \
 | 		$(OBJ_DIR)/$(PROJECT).elf; \
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 あく
						あく