diff --git a/.github/assets/Born2bSportyV2.ttf b/.github/assets/Born2bSportyV2.ttf new file mode 100644 index 00000000..02001782 Binary files /dev/null and b/.github/assets/Born2bSportyV2.ttf differ diff --git a/.github/assets/latest-firmware-template.png b/.github/assets/latest-firmware-template.png new file mode 100644 index 00000000..11eb523a Binary files /dev/null and b/.github/assets/latest-firmware-template.png differ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3774154e..21d61278 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,8 @@ jobs: - name: Checkout code uses: actions/checkout@v2 with: - submodules: true + fetch-depth: 0 + submodules: true - uses: satackey/action-docker-layer-caching@v0.0.8 continue-on-error: true with: @@ -110,12 +111,12 @@ jobs: - name: Get bootloader uses: actions/download-artifact@v2 with: - name: bootloader_f2 + name: bootloader_f3 path: bootloader - name: Get firmware uses: actions/download-artifact@v2 with: - name: firmware_f2 + name: firmware_f3 path: firmware - name: Upload bootloader uses: burnett01/rsync-deployments@4.1 @@ -145,18 +146,13 @@ jobs: - name: Get bootloader uses: actions/download-artifact@v2 with: - name: bootloader_f2 + name: bootloader_f3 path: bootloader - name: Get firmware uses: actions/download-artifact@v2 with: - name: firmware_f2 - path: firmware - - name: Get firmware - uses: actions/download-artifact@v2 - with: - name: firmware_f2 - path: firmware + name: firmware_f3 + path: firmware - name: cp run: cp ./bootloader/bootloader.bin full_firmware_latest.bin - name: truncate @@ -185,14 +181,8 @@ jobs: uses: actions/checkout@v2 with: fetch-depth: 0 - ref: master + ref: master submodules: true - - name: Echo debug - run: echo ${{ github.ref }} - - name: Get template and font - run: | - wget https://zhovner.com/tmp/latest-firmware-template.png - wget https://zhovner.com/tmp/Born2bSportyV2.ttf - name: Set test env run: echo "NUMBER_OF_COMMITS=$(git rev-list --count HEAD)" >> $GITHUB_ENV - name: Test output NUMBER_OF_COMMITS @@ -205,12 +195,12 @@ jobs: - name: Test output PREP_DATE run: echo $PREP_DATE - name: Gen pic - run: convert latest-firmware-template.png -font ./Born2bSportyV2.ttf -weight 700 -pointsize 140 -annotate +900+330 "$NUMBER_OF_COMMITS $PREP_DATE" out.png + run: convert ./.github/assets/latest-firmware-template.png -font ./.github/assets/Born2bSportyV2.ttf -weight 700 -pointsize 140 -annotate +900+330 "$NUMBER_OF_COMMITS $PREP_DATE" latest-firmware-banner.png - name: Upload pic uses: burnett01/rsync-deployments@4.1 with: switches: -avzp --delete - path: out.png + path: latest-firmware-banner.png remote_path: "${{ secrets.RSYNC_DEPLOY_BASE_PATH }}/" remote_host: ${{ secrets.RSYNC_DEPLOY_HOST }} remote_user: ${{ secrets.RSYNC_DEPLOY_USER }} diff --git a/README.md b/README.md index 93691271..cec4908f 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Welcome to [Flipper Zero](https://flipperzero.one/)'s Firmware repo! Our goal is # Update firmware - + Flipper Zero's firmware consists of two components: Bootloader and main firmware. Bootloader controls firmware update process over USB. You need working bootloader installed before update firmware over USB. diff --git a/applications/applications.h b/applications/applications.h index 8c5c7e96..01520473 100644 --- a/applications/applications.h +++ b/applications/applications.h @@ -36,12 +36,18 @@ void sd_card_test(void* p); void application_vibro(void* p); void app_gpio_test(void* p); void app_ibutton(void* p); +void cli_task(void* p); +void music_player(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 @@ -69,7 +75,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 @@ -117,6 +123,10 @@ const FlipperStartupApp FLIPPER_STARTUP[] = { {.app = sd_card_test, .name = "sd_card_test", .libs = {1, FURI_LIB{"gui_task"}}}, #endif +#ifdef APP_MUSIC_PLAYER + {.app = music_player, .name = "music player", .libs = {1, FURI_LIB{"gui_task"}}}, +#endif + #ifdef APP_GPIO_DEMO { .app = app_gpio_test, @@ -173,4 +183,8 @@ const FlipperStartupApp FLIPPER_APPS[] = { #ifdef BUILD_IBUTTON {.app = app_ibutton, .name = "ibutton", .libs = {1, FURI_LIB{"gui_task"}}}, #endif + +#ifdef BUILD_MUSIC_PLAYER + {.app = music_player, .name = "music player", .libs = {1, FURI_LIB{"gui_task"}}}, +#endif }; \ No newline at end of file diff --git a/applications/applications.mk b/applications/applications.mk index a4d99c1b..ba21c519 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 @@ -22,6 +23,7 @@ BUILD_SPEAKER_DEMO = 1 BUILD_VIBRO_DEMO = 1 BUILD_SD_TEST = 1 BUILD_GPIO_DEMO = 1 +BUILD_MUSIC_PLAYER = 1 endif APP_NFC ?= 0 @@ -45,6 +47,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 @@ -238,6 +247,17 @@ CFLAGS += -DBUILD_GPIO_DEMO C_SOURCES += $(wildcard $(APP_DIR)/gpio-tester/*.c) endif +APP_MUSIC_PLAYER ?= 0 +ifeq ($(APP_MUSIC_PLAYER), 1) +CFLAGS += -DAPP_MUSIC_PLAYER +BUILD_MUSIC_PLAYER = 1 +endif +BUILD_MUSIC_PLAYER ?= 0 +ifeq ($(BUILD_MUSIC_PLAYER), 1) +CFLAGS += -DBUILD_MUSIC_PLAYER +C_SOURCES += $(wildcard $(APP_DIR)/music-player/*.c) +endif + # device drivers APP_GUI ?= 0 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/music-player/music-player.c b/applications/music-player/music-player.c new file mode 100644 index 00000000..09e3ae47 --- /dev/null +++ b/applications/music-player/music-player.c @@ -0,0 +1,444 @@ +#include "flipper_v2.h" + +// TODO float note freq +typedef enum { + // Delay + N = 0, + // Octave 4 + B4 = 494, + // Octave 5 + C5 = 523, + D5 = 587, + E5 = 659, + F_5 = 740, + G5 = 784, + A5 = 880, + B5 = 988, + // Octave 6 + C6 = 1046, + D6 = 1175, + E6 = 1319, +} MelodyEventNote; + +typedef enum { + L1 = 1, + L2 = 2, + L4 = 4, + L8 = 8, + L16 = 16, + L32 = 32, + L64 = 64, + L128 = 128, +} MelodyEventLength; + +typedef struct { + MelodyEventNote note; + MelodyEventLength length; +} MelodyEventRecord; + +typedef struct { + const MelodyEventRecord* record; + int8_t loop_count; +} SongPattern; + +const MelodyEventRecord melody_start[] = { + {E6, L8}, {N, L8}, {E5, L8}, {B5, L8}, {N, L4}, {E5, L8}, {A5, L8}, {G5, L8}, {A5, L8}, + {E5, L8}, {B5, L8}, {N, L8}, {G5, L8}, {A5, L8}, {D6, L8}, {N, L4}, {D5, L8}, {B5, L8}, + {N, L4}, {D5, L8}, {A5, L8}, {G5, L8}, {A5, L8}, {D5, L8}, {F_5, L8}, {N, L8}, {G5, L8}, + {A5, L8}, {D6, L8}, {N, L4}, {F_5, L8}, {B5, L8}, {N, L4}, {F_5, L8}, {D6, L8}, {C6, L8}, + {B5, L8}, {F_5, L8}, {A5, L8}, {N, L8}, {G5, L8}, {F_5, L8}, {E5, L8}, {N, L8}, {C5, L8}, + {E5, L8}, {B5, L8}, {B4, L8}, {C5, L8}, {D5, L8}, {D6, L8}, {C6, L8}, {B5, L8}, {F_5, L8}, + {A5, L8}, {N, L8}, {G5, L8}, {A5, L8}, {E6, L8}}; + +const MelodyEventRecord melody_loop[] = { + {N, L4}, {E5, L8}, {B5, L8}, {N, L4}, {E5, L8}, {A5, L8}, {G5, L8}, {A5, L8}, {E5, L8}, + {B5, L8}, {N, L8}, {G5, L8}, {A5, L8}, {D6, L8}, {N, L4}, {D5, L8}, {B5, L8}, {N, L4}, + {D5, L8}, {A5, L8}, {G5, L8}, {A5, L8}, {D5, L8}, {F_5, L8}, {N, L8}, {G5, L8}, {A5, L8}, + {D6, L8}, {N, L4}, {F_5, L8}, {B5, L8}, {N, L4}, {F_5, L8}, {D6, L8}, {C6, L8}, {B5, L8}, + {F_5, L8}, {A5, L8}, {N, L8}, {G5, L8}, {F_5, L8}, {E5, L8}, {N, L8}, {C5, L8}, {E5, L8}, + {B5, L8}, {B4, L8}, {C5, L8}, {D5, L8}, {D6, L8}, {C6, L8}, {B5, L8}, {F_5, L8}, {A5, L8}, + {N, L8}, {G5, L8}, {A5, L8}, {E6, L8}}; + +const MelodyEventRecord melody_chords_1bar[] = { + {E6, L8}, {N, L8}, {B4, L128}, {E5, L128}, {B4, L128}, {E5, L128}, {B4, L128}, {E5, L128}, + {B4, L128}, {E5, L128}, {B4, L128}, {E5, L128}, {B4, L128}, {E5, L128}, {B4, L128}, {E5, L128}, + {B4, L128}, {E5, L128}, {B5, L8}, {N, L4}, {B4, L128}, {E5, L128}, {B4, L128}, {E5, L128}, + {B4, L128}, {E5, L128}, {B4, L128}, {E5, L128}, {B4, L128}, {E5, L128}, {B4, L128}, {E5, L128}, + {B4, L128}, {E5, L128}, {B4, L128}, {E5, L128}, {A5, L8}}; + +const SongPattern song[] = {{melody_start, 1}, {melody_loop, -1}}; + +typedef enum { + EventTypeTick, + EventTypeKey, + EventTypeNote, + // add your events type +} MusicDemoEventType; + +typedef struct { + union { + InputEvent input; + const MelodyEventRecord* note_record; + } value; + MusicDemoEventType type; +} MusicDemoEvent; + +typedef struct { + ValueMutex* state_mutex; + osMessageQueueId_t event_queue; + +} MusicDemoContext; + +#define note_stack_size 4 +typedef struct { + // describe state here + const MelodyEventRecord* note_record; + const MelodyEventRecord* note_stack[note_stack_size]; + uint8_t volume_id; + uint8_t volume_id_max; +} State; + +float volumes[] = {0, 0.02, 0.05, 0.1, 0.5}; + +bool is_white_note(const MelodyEventRecord* note_record, uint8_t id) { + if(note_record == NULL) return false; + + switch(note_record->note) { + case C5: + case C6: + if(id == 0) return true; + break; + case D5: + case D6: + if(id == 1) return true; + break; + case E5: + case E6: + if(id == 2) return true; + break; + case G5: + if(id == 4) return true; + break; + case A5: + if(id == 5) return true; + break; + case B4: + case B5: + if(id == 6) return true; + break; + default: + break; + } + + return false; +} + +bool is_black_note(const MelodyEventRecord* note_record, uint8_t id) { + if(note_record == NULL) return false; + + switch(note_record->note) { + case F_5: + if(id == 3) return true; + break; + default: + break; + } + + return false; +} + +const char* get_note_name(const MelodyEventRecord* note_record) { + if(note_record == NULL) return ""; + + switch(note_record->note) { + case N: + return "---"; + break; + case B4: + return "B4-"; + break; + case C5: + return "C5-"; + break; + case D5: + return "D5-"; + break; + case E5: + return "E5-"; + break; + case F_5: + return "F#5"; + break; + case G5: + return "G5-"; + break; + case A5: + return "A5-"; + break; + case B5: + return "B5-"; + break; + case C6: + return "C6-"; + break; + case D6: + return "D6-"; + break; + case E6: + return "E6-"; + break; + default: + return "UNK"; + break; + } +} +const char* get_note_len_name(const MelodyEventRecord* note_record) { + if(note_record == NULL) return ""; + + switch(note_record->length) { + case L1: + return "1-"; + break; + case L2: + return "2-"; + break; + case L4: + return "4-"; + break; + case L8: + return "8-"; + break; + case L16: + return "16"; + break; + case L32: + return "32"; + break; + case L64: + return "64"; + break; + case L128: + return "1+"; + break; + default: + return "--"; + break; + } +} + +static void render_callback(CanvasApi* canvas, void* ctx) { + State* state = (State*)acquire_mutex((ValueMutex*)ctx, 25); + + canvas->clear(canvas); + canvas->set_color(canvas, ColorBlack); + canvas->set_font(canvas, FontPrimary); + canvas->draw_str(canvas, 0, 12, "MusicPlayer"); + + uint8_t x_pos = 0; + uint8_t y_pos = 24; + const uint8_t white_w = 10; + const uint8_t white_h = 40; + + const int8_t black_x = 6; + const int8_t black_y = -5; + const uint8_t black_w = 8; + const uint8_t black_h = 32; + + // white keys + for(size_t i = 0; i < 7; i++) { + if(is_white_note(state->note_record, i)) { + canvas->draw_box(canvas, x_pos + white_w * i, y_pos, white_w + 1, white_h); + } else { + canvas->draw_frame(canvas, x_pos + white_w * i, y_pos, white_w + 1, white_h); + } + } + + // black keys + for(size_t i = 0; i < 7; i++) { + if(i != 2 && i != 6) { + canvas->set_color(canvas, ColorWhite); + canvas->draw_box( + canvas, x_pos + white_w * i + black_x, y_pos + black_y, black_w + 1, black_h); + canvas->set_color(canvas, ColorBlack); + if(is_black_note(state->note_record, i)) { + canvas->draw_box( + canvas, x_pos + white_w * i + black_x, y_pos + black_y, black_w + 1, black_h); + } else { + canvas->draw_frame( + canvas, x_pos + white_w * i + black_x, y_pos + black_y, black_w + 1, black_h); + } + } + } + + // volume widget + x_pos = 124; + y_pos = 0; + const uint8_t volume_h = (64 / (state->volume_id_max - 1)) * state->volume_id; + canvas->draw_frame(canvas, x_pos, y_pos, 4, 64); + canvas->draw_box(canvas, x_pos, y_pos + (64 - volume_h), 4, volume_h); + + // note stack widget + x_pos = 73; + y_pos = 0; + canvas->set_color(canvas, ColorBlack); + canvas->set_font(canvas, FontPrimary); + canvas->draw_frame(canvas, x_pos, y_pos, 49, 64); + canvas->draw_line(canvas, x_pos + 28, 0, x_pos + 28, 64); + + for(uint8_t i = 0; i < note_stack_size; i++) { + if(i == 0) { + canvas->draw_box(canvas, x_pos, y_pos + 48, 49, 16); + canvas->set_color(canvas, ColorWhite); + } else { + canvas->set_color(canvas, ColorBlack); + } + canvas->draw_str(canvas, x_pos + 4, 64 - 16 * i - 3, get_note_name(state->note_stack[i])); + canvas->draw_str( + canvas, x_pos + 31, 64 - 16 * i - 3, get_note_len_name(state->note_stack[i])); + canvas->draw_line(canvas, x_pos, 64 - 16 * i, x_pos + 48, 64 - 16 * i); + } + + release_mutex((ValueMutex*)ctx, state); +} + +static void input_callback(InputEvent* input_event, void* ctx) { + osMessageQueueId_t event_queue = (QueueHandle_t)ctx; + + MusicDemoEvent event; + event.type = EventTypeKey; + event.value.input = *input_event; + osMessageQueuePut(event_queue, &event, 0, 0); +} + +void process_note( + const MelodyEventRecord* note_record, + float bar_length_ms, + MusicDemoContext* context) { + MusicDemoEvent event; + // send note event + event.type = EventTypeNote; + event.value.note_record = note_record; + osMessageQueuePut(context->event_queue, &event, 0, 0); + + // read volume + State* state = (State*)acquire_mutex(context->state_mutex, 25); + float volume = volumes[state->volume_id]; + release_mutex(context->state_mutex, state); + + // play note + float note_delay = bar_length_ms / (float)note_record->length; + if(note_record->note != N) { + hal_pwm_set(volume, note_record->note, &SPEAKER_TIM, SPEAKER_CH); + } + delay(note_delay); + hal_pwm_stop(&SPEAKER_TIM, SPEAKER_CH); +} + +void music_player_thread(void* p) { + MusicDemoContext* context = (MusicDemoContext*)p; + + const float bpm = 130.0f; + // 4/4 + const float bar_length_ms = (60.0f * 1000.0f / bpm) * 4; + const uint16_t melody_start_events_count = sizeof(melody_start) / sizeof(melody_start[0]); + const uint16_t melody_loop_events_count = sizeof(melody_loop) / sizeof(melody_loop[0]); + + for(size_t i = 0; i < melody_start_events_count; i++) { + process_note(&melody_start[i], bar_length_ms, context); + } + + while(1) { + for(size_t i = 0; i < melody_loop_events_count; i++) { + process_note(&melody_loop[i], bar_length_ms, context); + } + } +} + +void music_player(void* p) { + osMessageQueueId_t event_queue = osMessageQueueNew(1, sizeof(MusicDemoEvent), NULL); + + State _state; + _state.note_record = NULL; + for(size_t i = 0; i < note_stack_size; i++) { + _state.note_stack[i] = NULL; + } + _state.volume_id = 1; + _state.volume_id_max = sizeof(volumes) / sizeof(volumes[0]); + + ValueMutex state_mutex; + if(!init_mutex(&state_mutex, &_state, sizeof(State))) { + printf("cannot create mutex\n"); + furiac_exit(NULL); + } + + Widget* widget = widget_alloc(); + widget_draw_callback_set(widget, render_callback, &state_mutex); + widget_input_callback_set(widget, input_callback, event_queue); + + // Open GUI and register widget + GuiApi* gui = (GuiApi*)furi_open("gui"); + if(gui == NULL) { + printf("gui is not available\n"); + furiac_exit(NULL); + } + gui->add_widget(gui, widget, GuiLayerFullscreen); + + // open input record + PubSub* input_events_record = furi_open("input_events"); + // prepare "do nothing" event + InputEvent input_event = {InputRight, true}; + + // start player thread + // TODO change to fuirac_start + osThreadAttr_t player_attr = {.name = "music_player_thread", .stack_size = 512}; + MusicDemoContext context = {.state_mutex = &state_mutex, .event_queue = event_queue}; + osThreadId_t player = osThreadNew(music_player_thread, &context, &player_attr); + + MusicDemoEvent event; + while(1) { + osStatus_t event_status = osMessageQueueGet(event_queue, &event, NULL, 100); + + State* state = (State*)acquire_mutex_block(&state_mutex); + + if(event_status == osOK) { + if(event.type == EventTypeKey) { + // press events + if(event.value.input.state && event.value.input.input == InputBack) { + } + + if(event.value.input.state && event.value.input.input == InputUp) { + if(state->volume_id < state->volume_id_max - 1) state->volume_id++; + } + + if(event.value.input.state && event.value.input.input == InputDown) { + if(state->volume_id > 0) state->volume_id--; + } + + if(event.value.input.state && event.value.input.input == InputLeft) { + } + + if(event.value.input.state && event.value.input.input == InputRight) { + } + + if(event.value.input.input == InputOk) { + } + + } else if(event.type == EventTypeNote) { + // send "do nothing" event to prevent display backlight off + notify_pubsub(input_events_record, &input_event); + + state->note_record = event.value.note_record; + + for(size_t i = note_stack_size - 1; i > 0; i--) { + state->note_stack[i] = state->note_stack[i - 1]; + } + state->note_stack[0] = state->note_record; + } + } else { + // event timeout + } + + widget_update(widget); + release_mutex(&state_mutex, state); + } +} diff --git a/applications/nfc/nfc.c b/applications/nfc/nfc.c index 719d3c37..26ae41bf 100644 --- a/applications/nfc/nfc.c +++ b/applications/nfc/nfc.c @@ -68,6 +68,12 @@ void nfc_test_callback(void* context) { nfc->screen = 0; widget_enabled_set(nfc->widget, true); + // TODO only for workaround + if(nfc->ret != ERR_NONE) { + nfc->ret = rfalNfcInitialize(); + rfalLowPowerModeStart(); + } + if(nfc->ret == ERR_NONE && !nfc->worker) { // TODO change to fuirac_start nfc->worker = osThreadNew(nfc_worker_task, nfc, &nfc->worker_attr); @@ -77,11 +83,29 @@ void nfc_test_callback(void* context) { } void nfc_field_on_callback(void* context) { + furi_assert(context); + Nfc* nfc = context; + + // TODO only for workaround + if(nfc->ret != ERR_NONE) { + nfc->ret = rfalNfcInitialize(); + rfalLowPowerModeStart(); + } + st25r3916OscOn(); st25r3916TxRxOn(); } void nfc_field_off_callback(void* context) { + furi_assert(context); + Nfc* nfc = context; + + // TODO only for workaround + if(nfc->ret != ERR_NONE) { + nfc->ret = rfalNfcInitialize(); + rfalLowPowerModeStart(); + } + st25r3916TxRxOff(); } @@ -158,8 +182,8 @@ void nfc_task(void* p) { furiac_exit(NULL); } - nfc->ret = rfalNfcInitialize(); - rfalLowPowerModeStart(); + // TODO only for workaround + nfc->ret = ERR_WRONG_STATE; furiac_ready(); diff --git a/applications/power/power.c b/applications/power/power.c index 3bbd5142..bf4789f9 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,8 @@ Power* power_alloc() { power->menu_vm = furi_open("menu"); furi_check(power->menu_vm); + power->cli = furi_open("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 +86,20 @@ 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(); + if(power->cli) { + 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/flipper_v2.c b/core/flipper_v2.c index 9a4e4bc6..87ea47ce 100644 --- a/core/flipper_v2.c +++ b/core/flipper_v2.c @@ -1,5 +1,15 @@ #include "flipper_v2.h" bool init_flipper_api(void) { - return gpio_api_init(); + bool no_errors = true; + + if(!furi_init()) { + no_errors = false; + } + + if(!gpio_api_init()) { + no_errors = false; + } + + return no_errors; } \ No newline at end of file diff --git a/core/furi-deprecated.c b/core/furi-deprecated.c index 0df40efe..af420d49 100644 --- a/core/furi-deprecated.c +++ b/core/furi-deprecated.c @@ -11,6 +11,13 @@ static FuriRecord records[MAX_RECORD_COUNT]; static size_t current_buffer_idx = 0; +osMutexId_t furi_core_mutex; + +bool furi_init(void) { + furi_core_mutex = osMutexNew(NULL); + if(furi_core_mutex == NULL) return false; + return true; +} // find record pointer by name static FuriRecord* find_record(const char* name) { @@ -32,6 +39,11 @@ bool furi_create_deprecated(const char* name, void* value, size_t size) { printf("[FURI] creating %s record\n", name); #endif + // acquire mutex to prevent simultaneous write to record with same index + if(osMutexAcquire(furi_core_mutex, osWaitForever) != osOK) { + return false; + } + FuriRecord* record = find_record(name); if(record != NULL) { @@ -69,6 +81,8 @@ bool furi_create_deprecated(const char* name, void* value, size_t size) { current_buffer_idx++; + osMutexRelease(furi_core_mutex); + return true; } diff --git a/core/furi-deprecated.h b/core/furi-deprecated.h index 5f401bbe..0aa4cac6 100644 --- a/core/furi-deprecated.h +++ b/core/furi-deprecated.h @@ -87,6 +87,9 @@ typedef struct { FlipperAppLibrary libs; } FlipperStartupApp; +// Init core +bool furi_init(void); + /*! Simply starts application. It call app entrypoint with param passed as argument. diff --git a/core/furi_ac.c b/core/furi_ac.c index fc535dbc..75cc110d 100644 --- a/core/furi_ac.c +++ b/core/furi_ac.c @@ -31,12 +31,12 @@ void furiac_wait_libs(const FlipperAppLibrary* libs) { if(app_id == INVALID_TASK_ID) { #ifdef FURI_DEBUG - printf("[FURIAC] Invalid library name %s\n", lib_name); + printf("[FURIAC] Invalid library name %s\n", libs->name[i]); #endif } else { while(!task_buffer[app_id].ready) { #ifdef FURI_DEBUG - printf("[FURIAC] waiting for library \"%s\"\n", lib_name); + printf("[FURIAC] waiting for library \"%s\"\n", libs->name[i]); #endif osDelay(50); } 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/spi.c b/firmware/targets/f2/Src/spi.c index 7e767e11..72c50b01 100644 --- a/firmware/targets/f2/Src/spi.c +++ b/firmware/targets/f2/Src/spi.c @@ -120,7 +120,7 @@ void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle) */ GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_PULLDOWN; + GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF6_SPI3; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); 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; \