diff --git a/applications/applications.h b/applications/applications.h index 8c9018e0..1af3f23f 100644 --- a/applications/applications.h +++ b/applications/applications.h @@ -35,12 +35,17 @@ void power_task(void* p); void sd_card_test(void* p); void application_vibro(void* p); void app_gpio_test(void* p); +void cli_task(void* p); const FlipperStartupApp FLIPPER_STARTUP[] = { #ifdef APP_DISPLAY {.app = display_u8g2, .name = "display_u8g2", .libs = {0}}, #endif +#ifdef APP_CLI + {.app = cli_task, .name = "cli_task", .libs = {0}}, +#endif + #ifdef APP_EXAMPLE_BLINK {.app = application_blink, .name = "blink", .libs = {1, FURI_LIB{"input_task"}}}, #endif @@ -68,7 +73,7 @@ const FlipperStartupApp FLIPPER_STARTUP[] = { #endif #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 #ifdef APP_CC1101 diff --git a/applications/applications.mk b/applications/applications.mk index a4d99c1b..3aae9d92 100644 --- a/applications/applications.mk +++ b/applications/applications.mk @@ -11,6 +11,7 @@ ifeq ($(APP_RELEASE), 1) APP_MENU = 1 APP_NFC = 1 APP_POWER = 1 +APP_CLI = 1 BUILD_IRDA = 1 APP_IRUKAGOTCHI = 1 BUILD_EXAMPLE_BLINK = 1 @@ -45,6 +46,13 @@ CFLAGS += -DAPP_POWER C_SOURCES += $(wildcard $(APP_DIR)/power/*.c) 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 ifeq ($(APP_MENU), 1) CFLAGS += -DAPP_MENU diff --git a/applications/cli/cli.c b/applications/cli/cli.c new file mode 100644 index 00000000..f6fdfb1d --- /dev/null +++ b/applications/cli/cli.c @@ -0,0 +1,173 @@ +#include "cli_i.h" +#include "cli_commands.h" + +#include + +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); + } +} diff --git a/applications/cli/cli.h b/applications/cli/cli.h new file mode 100644 index 00000000..a7aa742a --- /dev/null +++ b/applications/cli/cli.h @@ -0,0 +1,42 @@ +#pragma once + +#include + +/* 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(); diff --git a/applications/cli/cli_commands.c b/applications/cli/cli_commands.c new file mode 100644 index 00000000..46c08723 --- /dev/null +++ b/applications/cli/cli_commands.c @@ -0,0 +1,54 @@ +#include "cli_commands.h" +#include + +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); +} \ No newline at end of file diff --git a/applications/cli/cli_commands.h b/applications/cli/cli_commands.h new file mode 100644 index 00000000..184eeb37 --- /dev/null +++ b/applications/cli/cli_commands.h @@ -0,0 +1,5 @@ +#pragma once + +#include "cli_i.h" + +void cli_commands_init(Cli* cli); diff --git a/applications/cli/cli_i.h b/applications/cli/cli_i.h new file mode 100644 index 00000000..e8a8363d --- /dev/null +++ b/applications/cli/cli_i.h @@ -0,0 +1,42 @@ +#pragma once + +#include "cli.h" + +#include +#include + +#include + +#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); diff --git a/applications/power/power.c b/applications/power/power.c index 3bbd5142..c8c0d5d6 100644 --- a/applications/power/power.c +++ b/applications/power/power.c @@ -8,6 +8,7 @@ #include #include #include +#include struct Power { Icon* usb_icon; @@ -17,6 +18,7 @@ struct Power { Widget* battery_widget; ValueMutex* menu_vm; + Cli* cli; MenuItem* menu; uint8_t charge; @@ -54,6 +56,9 @@ Power* power_alloc() { power->menu_vm = furi_open("menu"); furi_check(power->menu_vm); + power->cli = furi_open("cli"); + furi_check(power->cli); + power->menu = menu_item_alloc_menu("Power", NULL); menu_item_subitem_add( power->menu, menu_item_alloc_function("Poweroff", NULL, power_off_callback, power)); @@ -82,10 +87,18 @@ void power_free(Power* 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)p; 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); assert(gui_record); GuiApi* gui = furi_take(gui_record); diff --git a/core/ring.c b/core/ring.c new file mode 100644 index 00000000..e8fdd767 --- /dev/null +++ b/core/ring.c @@ -0,0 +1,138 @@ +#include "ring.h" +#include + +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; +} diff --git a/core/ring.h b/core/ring.h new file mode 100644 index 00000000..069a81cd --- /dev/null +++ b/core/ring.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include + +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); diff --git a/debug/stm32wbx.cfg b/debug/stm32wbx.cfg deleted file mode 100644 index ccb70d17..00000000 --- a/debug/stm32wbx.cfg +++ /dev/null @@ -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 -} diff --git a/firmware/targets/Inc/api-hal-uid.h b/firmware/targets/Inc/api-hal-uid.h new file mode 100644 index 00000000..7d97aa1d --- /dev/null +++ b/firmware/targets/Inc/api-hal-uid.h @@ -0,0 +1,10 @@ +#pragma once + +#include +#include + +/* Get platform UID size in bytes */ +size_t api_hal_uid_size(); + +/* Get const pointer to UID */ +const uint8_t* api_hal_uid(); diff --git a/firmware/targets/Inc/api-hal-vcp.h b/firmware/targets/Inc/api-hal-vcp.h new file mode 100644 index 00000000..ac3a5dc4 --- /dev/null +++ b/firmware/targets/Inc/api-hal-vcp.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include +#include + +/* 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); diff --git a/firmware/targets/f2/api-hal/api-hal.h b/firmware/targets/Inc/api-hal.h similarity index 65% rename from firmware/targets/f2/api-hal/api-hal.h rename to firmware/targets/Inc/api-hal.h index 556f617b..e91b05bd 100644 --- a/firmware/targets/f2/api-hal/api-hal.h +++ b/firmware/targets/Inc/api-hal.h @@ -5,3 +5,6 @@ #include "api-hal-pwm.h" #include "api-hal-task.h" #include "api-hal-tim.h" +#include "api-hal-power.h" +#include "api-hal-vcp.h" +#include "api-hal-uid.h" diff --git a/firmware/targets/f2/Inc/usbd_cdc_if.h b/firmware/targets/f2/Inc/usbd_cdc_if.h index 38a7059c..32c1a228 100644 --- a/firmware/targets/f2/Inc/usbd_cdc_if.h +++ b/firmware/targets/f2/Inc/usbd_cdc_if.h @@ -51,8 +51,8 @@ /* USER CODE BEGIN EXPORTED_DEFINES */ /* Define size for the receive and transmit buffer over CDC */ /* It's up to user to redefine and/or remove those define */ -#define APP_RX_DATA_SIZE 2048 -#define APP_TX_DATA_SIZE 2048 +#define APP_RX_DATA_SIZE CDC_DATA_HS_MAX_PACKET_SIZE +#define APP_TX_DATA_SIZE CDC_DATA_HS_MAX_PACKET_SIZE /* USER CODE END EXPORTED_DEFINES */ diff --git a/firmware/targets/f2/Src/main.c b/firmware/targets/f2/Src/main.c index bf0c980e..d5a5d06b 100644 --- a/firmware/targets/f2/Src/main.c +++ b/firmware/targets/f2/Src/main.c @@ -104,6 +104,7 @@ int main(void) /* USER CODE BEGIN 2 */ MX_FATFS_Init(); delay_us_init_DWT(); + api_hal_vcp_init(); /* USER CODE END 2 */ /* Init scheduler */ diff --git a/firmware/targets/f2/Src/usbd_cdc_if.c b/firmware/targets/f2/Src/usbd_cdc_if.c index 21b4d13f..9299f924 100644 --- a/firmware/targets/f2/Src/usbd_cdc_if.c +++ b/firmware/targets/f2/Src/usbd_cdc_if.c @@ -51,6 +51,12 @@ /* 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 */ /** @@ -156,6 +162,7 @@ static int8_t CDC_Init_FS(void) /* Set Application Buffers */ USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, 0); USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS); + _api_hal_vcp_init(); return (USBD_OK); /* USER CODE END 3 */ } @@ -167,6 +174,7 @@ static int8_t CDC_Init_FS(void) static int8_t CDC_DeInit_FS(void) { /* USER CODE BEGIN 4 */ + _api_hal_vcp_deinit(); return (USBD_OK); /* 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) { /* USER CODE BEGIN 5 */ - switch(cmd) - { - case CDC_SEND_ENCAPSULATED_COMMAND: - - break; - - case CDC_GET_ENCAPSULATED_RESPONSE: - - break; - - case CDC_SET_COMM_FEATURE: - - break; - - case CDC_GET_COMM_FEATURE: - - break; - - case CDC_CLEAR_COMM_FEATURE: - - break; - - /*******************************************************************************/ - /* Line Coding Structure */ - /*-----------------------------------------------------------------------------*/ - /* Offset | Field | Size | Value | Description */ - /* 0 | dwDTERate | 4 | Number |Data terminal rate, in bits per second*/ - /* 4 | bCharFormat | 1 | Number | Stop bits */ - /* 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; + if (cmd == CDC_SEND_ENCAPSULATED_COMMAND) { + } else if (cmd == CDC_GET_ENCAPSULATED_RESPONSE) { + } else if (cmd == CDC_SET_COMM_FEATURE) { + } else if (cmd == CDC_GET_COMM_FEATURE) { + } else if (cmd == CDC_CLEAR_COMM_FEATURE) { + } else if (cmd == CDC_SET_LINE_CODING) { + /*******************************************************************************/ + /* Line Coding Structure */ + /*-----------------------------------------------------------------------------*/ + /* Offset | Field | Size | Value | Description */ + /* 0 | dwDTERate | 4 | Number |Data terminal rate, in bits per second*/ + /* 4 | bCharFormat | 1 | Number | Stop bits */ + /* 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). */ + /*******************************************************************************/ + } else if (cmd == CDC_GET_LINE_CODING) { + } else if (cmd == CDC_SET_CONTROL_LINE_STATE) { + _api_hal_vcp_control_line(((USBD_SetupReqTypedef*)pbuf)->wValue); + } else if (cmd == CDC_SEND_BREAK) { + } else { } 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) { /* USER CODE BEGIN 6 */ - USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]); + _api_hal_vcp_rx_callback((char*)Buf, *Len); USBD_CDC_ReceivePacket(&hUsbDeviceFS); return (USBD_OK); /* USER CODE END 6 */ @@ -287,7 +266,8 @@ uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len) if (hcdc->TxState != 0){ return USBD_BUSY; } - USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len); + memcpy(UserTxBufferFS, Buf, Len); + USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, Len); result = USBD_CDC_TransmitPacket(&hUsbDeviceFS); /* USER CODE END 7 */ 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; /* USER CODE BEGIN 13 */ UNUSED(Buf); - UNUSED(Len); UNUSED(epnum); + _api_hal_vcp_tx_complete(*Len); /* USER CODE END 13 */ return result; } diff --git a/firmware/targets/f2/api-hal/api-hal-uid.c b/firmware/targets/f2/api-hal/api-hal-uid.c new file mode 100644 index 00000000..2849a8b4 --- /dev/null +++ b/firmware/targets/f2/api-hal/api-hal-uid.c @@ -0,0 +1,10 @@ +#include +#include + +size_t api_hal_uid_size() { + return 96/8; +} + +const uint8_t* api_hal_uid() { + return (const uint8_t *)UID_BASE; +} diff --git a/firmware/targets/f2/api-hal/api-hal-vcp.c b/firmware/targets/f2/api-hal/api-hal-vcp.c new file mode 100644 index 00000000..bf98d7ef --- /dev/null +++ b/firmware/targets/f2/api-hal/api-hal-vcp.c @@ -0,0 +1,92 @@ +#include +#include +#include +#include + +#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); + } + } +} diff --git a/firmware/targets/f2/target.mk b/firmware/targets/f2/target.mk index 41b82d21..c7a63b38 100644 --- a/firmware/targets/f2/target.mk +++ b/firmware/targets/f2/target.mk @@ -1,6 +1,6 @@ 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 FW_ADDRESS = 0x08008000 diff --git a/firmware/targets/f3/Inc/usbd_cdc_if.h b/firmware/targets/f3/Inc/usbd_cdc_if.h index 1bd4eb8e..40223874 100644 --- a/firmware/targets/f3/Inc/usbd_cdc_if.h +++ b/firmware/targets/f3/Inc/usbd_cdc_if.h @@ -51,8 +51,8 @@ /* USER CODE BEGIN EXPORTED_DEFINES */ /* Define size for the receive and transmit buffer over CDC */ /* It's up to user to redefine and/or remove those define */ -#define APP_RX_DATA_SIZE 2048 -#define APP_TX_DATA_SIZE 2048 +#define APP_RX_DATA_SIZE CDC_DATA_HS_MAX_PACKET_SIZE +#define APP_TX_DATA_SIZE CDC_DATA_HS_MAX_PACKET_SIZE /* USER CODE END EXPORTED_DEFINES */ diff --git a/firmware/targets/f3/Src/main.c b/firmware/targets/f3/Src/main.c index 43f82d5a..c089ee16 100644 --- a/firmware/targets/f3/Src/main.c +++ b/firmware/targets/f3/Src/main.c @@ -111,6 +111,7 @@ int main(void) /* USER CODE BEGIN 2 */ MX_FATFS_Init(); delay_us_init_DWT(); + api_hal_vcp_init(); /* USER CODE END 2 */ /* Init scheduler */ diff --git a/firmware/targets/f3/Src/usbd_cdc_if.c b/firmware/targets/f3/Src/usbd_cdc_if.c index 2141aec8..cd6946c4 100644 --- a/firmware/targets/f3/Src/usbd_cdc_if.c +++ b/firmware/targets/f3/Src/usbd_cdc_if.c @@ -51,6 +51,12 @@ /* 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 */ /** @@ -156,6 +162,7 @@ static int8_t CDC_Init_FS(void) /* Set Application Buffers */ USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, 0); USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS); + _api_hal_vcp_init(); return (USBD_OK); /* USER CODE END 3 */ } @@ -167,6 +174,7 @@ static int8_t CDC_Init_FS(void) static int8_t CDC_DeInit_FS(void) { /* USER CODE BEGIN 4 */ + _api_hal_vcp_deinit(); return (USBD_OK); /* 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) { /* USER CODE BEGIN 5 */ - switch(cmd) - { - case CDC_SEND_ENCAPSULATED_COMMAND: - - break; - - case CDC_GET_ENCAPSULATED_RESPONSE: - - break; - - case CDC_SET_COMM_FEATURE: - - break; - - case CDC_GET_COMM_FEATURE: - - break; - - case CDC_CLEAR_COMM_FEATURE: - - break; - - /*******************************************************************************/ - /* Line Coding Structure */ - /*-----------------------------------------------------------------------------*/ - /* Offset | Field | Size | Value | Description */ - /* 0 | dwDTERate | 4 | Number |Data terminal rate, in bits per second*/ - /* 4 | bCharFormat | 1 | Number | Stop bits */ - /* 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; + if (cmd == CDC_SEND_ENCAPSULATED_COMMAND) { + } else if (cmd == CDC_GET_ENCAPSULATED_RESPONSE) { + } else if (cmd == CDC_SET_COMM_FEATURE) { + } else if (cmd == CDC_GET_COMM_FEATURE) { + } else if (cmd == CDC_CLEAR_COMM_FEATURE) { + } else if (cmd == CDC_SET_LINE_CODING) { + /*******************************************************************************/ + /* Line Coding Structure */ + /*-----------------------------------------------------------------------------*/ + /* Offset | Field | Size | Value | Description */ + /* 0 | dwDTERate | 4 | Number |Data terminal rate, in bits per second*/ + /* 4 | bCharFormat | 1 | Number | Stop bits */ + /* 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). */ + /*******************************************************************************/ + } else if (cmd == CDC_GET_LINE_CODING) { + } else if (cmd == CDC_SET_CONTROL_LINE_STATE) { + _api_hal_vcp_control_line(((USBD_SetupReqTypedef*)pbuf)->wValue); + } else if (cmd == CDC_SEND_BREAK) { + } else { } 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) { /* USER CODE BEGIN 6 */ - USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]); + _api_hal_vcp_rx_callback((char*)Buf, *Len); USBD_CDC_ReceivePacket(&hUsbDeviceFS); return (USBD_OK); /* USER CODE END 6 */ @@ -287,7 +266,8 @@ uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len) if (hcdc->TxState != 0){ return USBD_BUSY; } - USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len); + memcpy(UserTxBufferFS, Buf, Len); + USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, Len); result = USBD_CDC_TransmitPacket(&hUsbDeviceFS); /* USER CODE END 7 */ 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; /* USER CODE BEGIN 13 */ UNUSED(Buf); - UNUSED(Len); UNUSED(epnum); + _api_hal_vcp_tx_complete(*Len); /* USER CODE END 13 */ return result; } diff --git a/firmware/targets/f3/api-hal/api-hal-uuid.c b/firmware/targets/f3/api-hal/api-hal-uuid.c new file mode 100644 index 00000000..7ef256f1 --- /dev/null +++ b/firmware/targets/f3/api-hal/api-hal-uuid.c @@ -0,0 +1,10 @@ +#include +#include + +size_t api_hal_uid_size() { + return 64/8; +} + +const uint8_t* api_hal_uid() { + return (const uint8_t *)UID64_BASE; +} diff --git a/firmware/targets/f3/api-hal/api-hal-vcp.c b/firmware/targets/f3/api-hal/api-hal-vcp.c new file mode 100644 index 00000000..bf98d7ef --- /dev/null +++ b/firmware/targets/f3/api-hal/api-hal-vcp.c @@ -0,0 +1,92 @@ +#include +#include +#include +#include + +#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); + } + } +} diff --git a/firmware/targets/f3/api-hal/api-hal.h b/firmware/targets/f3/api-hal/api-hal.h deleted file mode 100644 index 556f617b..00000000 --- a/firmware/targets/f3/api-hal/api-hal.h +++ /dev/null @@ -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" diff --git a/firmware/targets/f3/f3.ioc b/firmware/targets/f3/f3.ioc index a68bc4de..96ae441e 100644 --- a/firmware/targets/f3/f3.ioc +++ b/firmware/targets/f3/f3.ioc @@ -270,6 +270,7 @@ Mcu.Pin12=PA2 PD0.GPIOParameters=GPIO_Speed,PinState,GPIO_Label Mcu.Pin10=PA0 SH.GPXTI10.ConfNb=1 +USB_DEVICE.APP_RX_DATA_SIZE=512 TIM2.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_ENABLE PC3.GPIO_Label=PC3 PA3.PinState=GPIO_PIN_SET @@ -453,7 +454,7 @@ OSC_IN.GPIOParameters=GPIO_Label PB12.Locked=true ProjectManager.DeletePrevious=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 RCC.AHB2CLKDivider=RCC_SYSCLK_DIV2 RCC.FamilyName=M @@ -528,6 +529,7 @@ PA13.Locked=true RF1.Mode=RF1_Activate PB7.Mode=Asynchronous 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 PB2.GPIO_Label=PB2 PC6.GPIOParameters=GPIO_Label diff --git a/firmware/targets/f3/target.mk b/firmware/targets/f3/target.mk index bed22073..7eda0fa1 100644 --- a/firmware/targets/f3/target.mk +++ b/firmware/targets/f3/target.mk @@ -1,6 +1,6 @@ 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 FW_ADDRESS = 0x08008000 diff --git a/lib/mlib b/lib/mlib index eb7556f8..ebf44073 160000 --- a/lib/mlib +++ b/lib/mlib @@ -1 +1 @@ -Subproject commit eb7556f88faf0bbfd6a4ae99a3d53dcbe2064b88 +Subproject commit ebf440731d44f5eba926e0f648758676461bbba4 diff --git a/make/rules.mk b/make/rules.mk index f4d0c95e..57e87ce1 100644 --- a/make/rules.mk +++ b/make/rules.mk @@ -73,7 +73,7 @@ upload: $(OBJ_DIR)/upload debug: flash $(DEBUG_AGENT) & echo $$! > $(OBJ_DIR)/agent.PID 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 "source ../debug/FreeRTOS/FreeRTOS.py" \ $(OBJ_DIR)/$(PROJECT).elf; \