This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| tamiwiki:users:6r1d:diymall_esp32_s3_fixture [2025/10/20 05:25] – [ESP-IDF (+ history and PWM debug)] 6r1d | tamiwiki:users:6r1d:diymall_esp32_s3_fixture [2025/10/20 05:43] (current) – [ESP-IDF (+ history and PWM debug)] 6r1d | ||
|---|---|---|---|
| Line 108: | Line 108: | ||
| </ | </ | ||
| - | CMake config (code): | + | For your convenience, |
| - | < | + | Clone it like that: |
| - | idf_component_register(SRCS "main.c" | + | |
| - | INCLUDE_DIRS ".") | + | < |
| + | git clone https://git.telavivmakers.space/ | ||
| </ | </ | ||
| - | CMake config (project): | + | Also, you can use Minicom to interact with the tracing code if you'd like. It's just one of the default baudrates, 115200. |
| - | < | + | < |
| - | # The following five lines of boilerplate have to be in your project' | + | minicom -D /dev/ttyUSB0 -b 115200 -o |
| - | # CMakeLists in this exact order for cmake to work correctly | + | |
| - | cmake_minimum_required(VERSION 3.16) | + | |
| - | + | ||
| - | include($ENV{IDF_PATH}/tools/cmake/ | + | |
| - | project(.) | + | |
| </ | </ | ||
| - | |||
| - | <file cpp esp32_s3_pin_tracer.c> | ||
| - | #include < | ||
| - | #include < | ||
| - | #include < | ||
| - | #include < | ||
| - | #include < | ||
| - | |||
| - | #include " | ||
| - | #include " | ||
| - | |||
| - | #include " | ||
| - | #include " | ||
| - | #include " | ||
| - | #include " | ||
| - | #include " | ||
| - | #include " | ||
| - | #include " | ||
| - | |||
| - | /*======== CONFIG ========*/ | ||
| - | // Blink defaults | ||
| - | static uint32_t g_blink_delay_ms = 100; | ||
| - | |||
| - | // Console config | ||
| - | #define CLI_LINE_MAX 128 | ||
| - | #define HIST_MAX | ||
| - | |||
| - | // PWM configuration (safe defaults) | ||
| - | #define LEDC_TIMER | ||
| - | #define LEDC_MODE | ||
| - | #define LEDC_CHANNEL | ||
| - | #define LEDC_DUTY_RES | ||
| - | #define LEDC_FREQUENCY_DEFAULT | ||
| - | |||
| - | /*======== SAFE GPIO CANDIDATES ========*/ | ||
| - | static const gpio_num_t TEST_SAFE_GPIO[] = { | ||
| - | 1, 2, | ||
| - | 4, 5, 6, 7, | ||
| - | 8, 9, 10, 11, 12, 13, 14, | ||
| - | 15, 16, 17, 18, | ||
| - | /* 19,20 excluded (USB D-/D+) */ | ||
| - | 21, | ||
| - | /* 22..34 not bonded on typical modules */ | ||
| - | /* 35,36,37 excluded (PSRAM on some variants) */ | ||
| - | 38, 39, 40, 41, 42, /* JTAG-capable if configured */ | ||
| - | /* 43,44 excluded (UART0 console) */ | ||
| - | 47, 48 /* may be 1.8 V on R16V */ | ||
| - | }; | ||
| - | static const size_t TEST_SAFE_GPIO_COUNT = sizeof(TEST_SAFE_GPIO)/ | ||
| - | |||
| - | /*======== CONSTANTS & HELPERS ========*/ | ||
| - | |||
| - | /* Sentinels */ | ||
| - | #define HIST_NONE | ||
| - | #define INVALID_GPIO | ||
| - | |||
| - | /* Bounds */ | ||
| - | #define BLINK_DELAY_MIN_MS | ||
| - | #define BLINK_DELAY_MAX_MS | ||
| - | |||
| - | #define BRIGHT_MIN | ||
| - | #define BRIGHT_MAX | ||
| - | |||
| - | #define FREQ_MIN_HZ | ||
| - | #define FREQ_MAX_HZ | ||
| - | |||
| - | /* Task sizes & priorities */ | ||
| - | #define BLINK_STACK | ||
| - | #define CONSOLE_STACK | ||
| - | #define BLINK_TASK_PRIO | ||
| - | #define CONSOLE_TASK_PRIO | ||
| - | |||
| - | /* UART driver buffer */ | ||
| - | #define UART_RX_BUF | ||
| - | |||
| - | /* Generic clamps */ | ||
| - | static inline uint32_t clamp_u32(uint32_t v, uint32_t lo, uint32_t hi) { | ||
| - | return (v < lo) ? lo : (v > hi) ? hi : v; | ||
| - | } | ||
| - | static inline int clamp_int(int v, int lo, int hi) { | ||
| - | return (v < lo) ? lo : (v > hi) ? hi : v; | ||
| - | } | ||
| - | |||
| - | /* LEDC helpers */ | ||
| - | static inline uint32_t ledc_max_duty(void) { | ||
| - | // LEDC_DUTY_RES is enum like LEDC_TIMER_8_BIT → 8 | ||
| - | return (1u << LEDC_DUTY_RES) - 1u; | ||
| - | } | ||
| - | static inline uint32_t brightness_to_duty(uint8_t level) { | ||
| - | // Map BRIGHT_MIN..BRIGHT_MAX → 0..max_duty; | ||
| - | const uint32_t maxd = ledc_max_duty(); | ||
| - | const uint32_t denom = (BRIGHT_MAX > 0) ? (uint32_t)BRIGHT_MAX : 1u; | ||
| - | return (uint32_t)level * maxd / denom; | ||
| - | } | ||
| - | |||
| - | /* Tiny predicates */ | ||
| - | static inline bool is_valid_gpio(gpio_num_t pin) { return pin != INVALID_GPIO; | ||
| - | |||
| - | /*======== RUNTIME ========*/ | ||
| - | static gpio_num_t | ||
| - | static bool | ||
| - | static bool | ||
| - | static uint8_t | ||
| - | static uint32_t | ||
| - | static TaskHandle_t g_blink_task | ||
| - | |||
| - | /*======== CLI ========*/ | ||
| - | typedef struct { | ||
| - | uart_port_t uart; | ||
| - | char *line; | ||
| - | size_t *pos; | ||
| - | size_t *cursor; | ||
| - | char (*hist)[CLI_LINE_MAX]; | ||
| - | int | ||
| - | } cli_ctx_t; | ||
| - | |||
| - | /*---- CLI helpers ----*/ | ||
| - | static inline void cli_write(cli_ctx_t *c, const char *s) { | ||
| - | uart_write_bytes(c-> | ||
| - | } | ||
| - | |||
| - | static void cli_prompt(cli_ctx_t *c) { | ||
| - | cli_write(c, | ||
| - | fflush(stdout); | ||
| - | } | ||
| - | |||
| - | static void cli_redraw(cli_ctx_t *c) { | ||
| - | // Clear line, print prompt + buffer, then move cursor left if needed | ||
| - | cli_write(c, | ||
| - | if (*c-> | ||
| - | if (*c->pos > *c-> | ||
| - | char seq[16]; | ||
| - | int n = snprintf(seq, | ||
| - | uart_write_bytes(c-> | ||
| - | } | ||
| - | } | ||
| - | |||
| - | static void cli_push_hist(cli_ctx_t *c, const char *cmd) { | ||
| - | if (!cmd[0]) return; | ||
| - | int last = (*c-> | ||
| - | if (*c-> | ||
| - | strncpy(c-> | ||
| - | c-> | ||
| - | *c-> | ||
| - | if (*c-> | ||
| - | } | ||
| - | |||
| - | static void cli_load_hist(cli_ctx_t *c, int idx) { | ||
| - | strncpy(c-> | ||
| - | c-> | ||
| - | *c->pos = *c-> | ||
| - | cli_redraw(c); | ||
| - | } | ||
| - | |||
| - | static inline bool cli_in_hist(cli_ctx_t *c) { return *c-> | ||
| - | |||
| - | /*======== HELPERS ========*/ | ||
| - | static bool is_test_safe(gpio_num_t gpio) { | ||
| - | for (size_t i = 0; i < TEST_SAFE_GPIO_COUNT; | ||
| - | if (TEST_SAFE_GPIO[i] == gpio) return true; | ||
| - | } | ||
| - | return false; | ||
| - | } | ||
| - | |||
| - | static void print_test_safe_pins(void) { | ||
| - | printf(" | ||
| - | for (size_t i = 0; i < TEST_SAFE_GPIO_COUNT; | ||
| - | printf(" | ||
| - | } | ||
| - | printf(" | ||
| - | printf(" | ||
| - | } | ||
| - | |||
| - | static void release_pin(gpio_num_t pin) { | ||
| - | if (is_valid_gpio(pin)) { | ||
| - | gpio_set_level(pin, | ||
| - | gpio_reset_pin(pin); | ||
| - | } | ||
| - | } | ||
| - | |||
| - | static void stop_pwm(void) { | ||
| - | if (g_pwm_mode) { | ||
| - | ledc_stop(LEDC_MODE, | ||
| - | g_pwm_mode = false; | ||
| - | } | ||
| - | } | ||
| - | |||
| - | static void stop_blink(void) { | ||
| - | if (g_blink_task) { | ||
| - | TaskHandle_t t = g_blink_task; | ||
| - | g_blink_task = NULL; // signal task to exit | ||
| - | for (int i = 0; i < 20 && eTaskGetState(t) != eDeleted; ++i) { | ||
| - | vTaskDelay(pdMS_TO_TICKS(5)); | ||
| - | } | ||
| - | } | ||
| - | g_blinking = false; | ||
| - | } | ||
| - | |||
| - | static void stop_all(void) { | ||
| - | stop_blink(); | ||
| - | stop_pwm(); | ||
| - | release_pin(g_current_pin); | ||
| - | g_current_pin = INVALID_GPIO; | ||
| - | printf(" | ||
| - | } | ||
| - | |||
| - | /*======== BLINK TASK ========*/ | ||
| - | static void blink_task(void *arg) { | ||
| - | gpio_num_t pin = (gpio_num_t)(intptr_t)arg; | ||
| - | gpio_config_t io = { | ||
| - | .pin_bit_mask = 1ULL << pin, | ||
| - | .mode = GPIO_MODE_OUTPUT, | ||
| - | .pull_up_en = GPIO_PULLUP_DISABLE, | ||
| - | .pull_down_en = GPIO_PULLDOWN_DISABLE, | ||
| - | .intr_type = GPIO_INTR_DISABLE | ||
| - | }; | ||
| - | gpio_config(& | ||
| - | gpio_set_level(pin, | ||
| - | while (g_blink_task == xTaskGetCurrentTaskHandle()) { | ||
| - | gpio_set_level(pin, | ||
| - | vTaskDelay(pdMS_TO_TICKS(g_blink_delay_ms)); | ||
| - | gpio_set_level(pin, | ||
| - | vTaskDelay(pdMS_TO_TICKS(g_blink_delay_ms)); | ||
| - | } | ||
| - | release_pin(pin); | ||
| - | vTaskDelete(NULL); | ||
| - | } | ||
| - | |||
| - | /*======== PWM ========*/ | ||
| - | static bool setup_pwm(gpio_num_t gpio) { | ||
| - | if (g_pwm_mode) ledc_stop(LEDC_MODE, | ||
| - | // Configure LEDC timer | ||
| - | ledc_timer_config_t ledc_timer = { | ||
| - | .speed_mode | ||
| - | .timer_num | ||
| - | .duty_resolution = LEDC_DUTY_RES, | ||
| - | .freq_hz | ||
| - | .clk_cfg | ||
| - | }; | ||
| - | esp_err_t ret = ledc_timer_config(& | ||
| - | if (ret != ESP_OK) { | ||
| - | printf(" | ||
| - | return false; | ||
| - | } | ||
| - | // Configure LEDC channel | ||
| - | ledc_channel_config_t ledc_channel = { | ||
| - | .speed_mode = LEDC_MODE, | ||
| - | .channel | ||
| - | .timer_sel | ||
| - | .intr_type | ||
| - | .gpio_num | ||
| - | .duty = 0, | ||
| - | .hpoint | ||
| - | }; | ||
| - | ret = ledc_channel_config(& | ||
| - | if (ret != ESP_OK) { | ||
| - | printf(" | ||
| - | return false; | ||
| - | } | ||
| - | return true; | ||
| - | } | ||
| - | |||
| - | static void set_pwm_brightness(uint8_t level) { | ||
| - | level = (uint8_t)clamp_int(level, | ||
| - | g_pwm_brightness = level; | ||
| - | const uint32_t duty = brightness_to_duty(level); | ||
| - | ledc_set_duty(LEDC_MODE, | ||
| - | ledc_update_duty(LEDC_MODE, | ||
| - | printf(" | ||
| - | | ||
| - | } | ||
| - | |||
| - | static void set_pwm_frequency(uint32_t freq) { | ||
| - | g_pwm_frequency = clamp_u32(freq, | ||
| - | if (g_pwm_mode) { | ||
| - | ledc_timer_config_t ledc_timer = { | ||
| - | .speed_mode | ||
| - | .timer_num | ||
| - | .duty_resolution = LEDC_DUTY_RES, | ||
| - | .freq_hz | ||
| - | .clk_cfg | ||
| - | }; | ||
| - | esp_err_t ret = ledc_timer_config(& | ||
| - | if (ret == ESP_OK) { | ||
| - | printf(" | ||
| - | set_pwm_brightness(g_pwm_brightness); | ||
| - | } else { | ||
| - | printf(" | ||
| - | } | ||
| - | } else { | ||
| - | printf(" | ||
| - | } | ||
| - | } | ||
| - | |||
| - | /*======== MODE START ========*/ | ||
| - | static void start_blink(gpio_num_t gpio) { | ||
| - | if (!is_test_safe(gpio)) { | ||
| - | printf(" | ||
| - | return; | ||
| - | } | ||
| - | stop_all(); | ||
| - | g_current_pin = gpio; | ||
| - | g_blinking = true; | ||
| - | if (xTaskCreatePinnedToCore(blink_task, | ||
| - | BLINK_TASK_PRIO, | ||
| - | printf(" | ||
| - | g_blinking = false; | ||
| - | g_current_pin = INVALID_GPIO; | ||
| - | return; | ||
| - | } | ||
| - | printf(" | ||
| - | } | ||
| - | |||
| - | static void start_pwm(gpio_num_t gpio, uint8_t brightness) { | ||
| - | if (!is_test_safe(gpio)) { | ||
| - | printf(" | ||
| - | return; | ||
| - | } | ||
| - | stop_all(); | ||
| - | if (!setup_pwm(gpio)) { | ||
| - | printf(" | ||
| - | return; | ||
| - | } | ||
| - | g_current_pin = gpio; | ||
| - | g_pwm_mode = true; | ||
| - | set_pwm_brightness(brightness); | ||
| - | printf(" | ||
| - | } | ||
| - | |||
| - | /*======== COMMAND PARSER ========*/ | ||
| - | static void trim(char *s) { | ||
| - | size_t len = strlen(s); | ||
| - | while (len && (s[len-1] == ' | ||
| - | size_t i = 0; | ||
| - | while (s[i] && isspace((unsigned char)s[i])) i++; | ||
| - | if (i) memmove(s, s+i, strlen(s+i)+1); | ||
| - | } | ||
| - | |||
| - | static bool all_digits(const char *s) { | ||
| - | if (!*s) return false; | ||
| - | for (const char *p = s; *p; ++p) if (!isdigit((unsigned char)*p)) return false; | ||
| - | return true; | ||
| - | } | ||
| - | |||
| - | static void handle_command(char *line) { | ||
| - | trim(line); | ||
| - | if (!*line) return; | ||
| - | |||
| - | char cmd[64]; | ||
| - | strncpy(cmd, | ||
| - | cmd[sizeof(cmd)-1] = 0; | ||
| - | for (char *p = cmd; *p; ++p) *p = (char)tolower((unsigned char)*p); | ||
| - | |||
| - | if (strcmp(cmd, | ||
| - | print_test_safe_pins(); | ||
| - | return; | ||
| - | } | ||
| - | if (strcmp(cmd, | ||
| - | printf(" | ||
| - | | ||
| - | if (g_blinking) { | ||
| - | printf(" | ||
| - | } else if (g_pwm_mode) { | ||
| - | printf(" | ||
| - | | ||
| - | } else { | ||
| - | printf(" | ||
| - | } | ||
| - | return; | ||
| - | } | ||
| - | if (strcmp(cmd, | ||
| - | stop_all(); | ||
| - | return; | ||
| - | } | ||
| - | if (strncmp(cmd, | ||
| - | int gpio = atoi(line + 4); | ||
| - | start_blink((gpio_num_t)gpio); | ||
| - | return; | ||
| - | } | ||
| - | if (strncmp(cmd, | ||
| - | int v = atoi(line + 6); | ||
| - | g_blink_delay_ms = clamp_u32((uint32_t)v, | ||
| - | printf(" | ||
| - | return; | ||
| - | } | ||
| - | if (strncmp(cmd, | ||
| - | // "pwm <pin> [brightness]" | ||
| - | char *args = line + 4; trim(args); | ||
| - | int gpio = -1, brightness = g_pwm_brightness; | ||
| - | if (sscanf(args, | ||
| - | brightness = clamp_int(brightness, | ||
| - | start_pwm((gpio_num_t)gpio, | ||
| - | } else { | ||
| - | printf(" | ||
| - | | ||
| - | } | ||
| - | return; | ||
| - | } | ||
| - | if (strncmp(cmd, | ||
| - | const char *arg = (strncmp(cmd, | ||
| - | int brightness = atoi(arg); | ||
| - | brightness = clamp_int(brightness, | ||
| - | if (g_pwm_mode) { | ||
| - | set_pwm_brightness((uint8_t)brightness); | ||
| - | } else { | ||
| - | printf(" | ||
| - | } | ||
| - | return; | ||
| - | } | ||
| - | if (strncmp(cmd, | ||
| - | char *arg = (cmd[4] == ' ') ? (line + 5) : (line + 10); | ||
| - | int freq = atoi(arg); | ||
| - | if (freq > 0) set_pwm_frequency((uint32_t)freq); | ||
| - | else printf(" | ||
| - | return; | ||
| - | } | ||
| - | if (strcmp(cmd, | ||
| - | printf(" | ||
| - | " | ||
| - | " | ||
| - | " | ||
| - | " | ||
| - | " | ||
| - | " | ||
| - | " | ||
| - | " | ||
| - | " | ||
| - | | ||
| - | | ||
| - | | ||
| - | | ||
| - | return; | ||
| - | } | ||
| - | if (all_digits(line)) { // bare number = pin | ||
| - | start_blink((gpio_num_t)atoi(line)); | ||
| - | return; | ||
| - | } | ||
| - | printf(" | ||
| - | } | ||
| - | |||
| - | /*======== CONSOLE TASK ========*/ | ||
| - | static void console_task(void *arg) { | ||
| - | const uart_port_t uart_num = UART_NUM_0; | ||
| - | char | ||
| - | size_t pos = 0; // length used | ||
| - | size_t cursor = 0; // caret position | ||
| - | char hist[HIST_MAX][CLI_LINE_MAX] = {{0}}; | ||
| - | int hist_count = 0; | ||
| - | int hist_head | ||
| - | int hist_view | ||
| - | cli_ctx_t C = { | ||
| - | .uart = uart_num, | ||
| - | .line = line, | ||
| - | .pos = &pos, | ||
| - | .cursor | ||
| - | .hist = hist, | ||
| - | .hist_count = & | ||
| - | .hist_head | ||
| - | .hist_view | ||
| - | }; | ||
| - | cli_prompt(& | ||
| - | enum { ESC_IDLE, ESC_ESC, ESC_CSI } esc = ESC_IDLE; | ||
| - | char csi_param_buf[4] = {0}; | ||
| - | int csi_param_len = 0; | ||
| - | while (1) { | ||
| - | uint8_t ch; | ||
| - | int got = uart_read_bytes(uart_num, | ||
| - | if (got != 1) continue; | ||
| - | // Escape handling (arrows/ | ||
| - | if (esc == ESC_ESC) { | ||
| - | if (ch == ' | ||
| - | // Alt-b / Alt-f | ||
| - | if (ch == ' | ||
| - | if (cursor > 0) { | ||
| - | while (cursor > 0 && isspace((unsigned char)line[cursor-1])) cursor--; | ||
| - | while (cursor > 0 && !isspace((unsigned char)line[cursor-1])) cursor--; | ||
| - | cli_redraw(& | ||
| - | } | ||
| - | esc = ESC_IDLE; continue; | ||
| - | } | ||
| - | if (ch == ' | ||
| - | if (cursor < pos) { | ||
| - | while (cursor < pos && !isspace((unsigned char)line[cursor])) cursor++; | ||
| - | while (cursor < pos && | ||
| - | cli_redraw(& | ||
| - | } | ||
| - | esc = ESC_IDLE; continue; | ||
| - | } | ||
| - | esc = ESC_IDLE; // unknown ESC seq | ||
| - | continue; | ||
| - | } else if (esc == ESC_CSI) { | ||
| - | if (ch >= ' | ||
| - | if (csi_param_len < (int)sizeof(csi_param_buf)-1) csi_param_buf[csi_param_len++] = (char)ch; | ||
| - | continue; | ||
| - | } | ||
| - | if (ch == ' | ||
| - | // [3~ delete, [1~ home, [4~ end | ||
| - | int p = atoi(csi_param_buf); | ||
| - | if (p == 3) { // Delete forward | ||
| - | if (cursor < pos) { | ||
| - | memmove(& | ||
| - | pos--; line[pos] = 0; | ||
| - | cli_redraw(& | ||
| - | } | ||
| - | } else if (p == 1) { | ||
| - | cursor = 0; cli_redraw(& | ||
| - | } else if (p == 4) { | ||
| - | cursor = pos; cli_redraw(& | ||
| - | } | ||
| - | esc = ESC_IDLE; continue; | ||
| - | } | ||
| - | // Final byte for standard arrows/ | ||
| - | if (ch == ' | ||
| - | if (hist_count) { | ||
| - | if (!cli_in_hist(& | ||
| - | else { | ||
| - | int oldest = (hist_head - hist_count + HIST_MAX) % HIST_MAX; | ||
| - | if (hist_view != oldest) hist_view = (hist_view - 1 + HIST_MAX) % HIST_MAX; | ||
| - | } | ||
| - | cli_load_hist(& | ||
| - | } | ||
| - | } else if (ch == ' | ||
| - | if (cli_in_hist(& | ||
| - | int newest = (hist_head - 1 + HIST_MAX) % HIST_MAX; | ||
| - | if (hist_view != newest) { hist_view = (hist_view + 1) % HIST_MAX; cli_load_hist(& | ||
| - | else { hist_view = HIST_NONE; pos = cursor = 0; line[0] = 0; cli_redraw(& | ||
| - | } | ||
| - | } else if (ch == ' | ||
| - | if (cursor < pos) { cursor++; cli_redraw(& | ||
| - | } else if (ch == ' | ||
| - | if (cursor > 0) { cursor--; cli_redraw(& | ||
| - | } else if (ch == ' | ||
| - | cursor = 0; cli_redraw(& | ||
| - | } else if (ch == ' | ||
| - | cursor = pos; cli_redraw(& | ||
| - | } | ||
| - | esc = ESC_IDLE; | ||
| - | continue; | ||
| - | } | ||
| - | if (ch == 0x1B) { esc = ESC_ESC; continue; } // start ESC | ||
| - | // CR / LF -> execute | ||
| - | if (ch == ' | ||
| - | cli_write(& | ||
| - | line[pos] = 0; | ||
| - | if (pos) { cli_push_hist(& | ||
| - | handle_command(line); | ||
| - | pos = cursor = 0; line[0] = 0; | ||
| - | cli_prompt(& | ||
| - | continue; | ||
| - | } | ||
| - | // Ctrl-A / Ctrl-E | ||
| - | if (ch == 0x01) { cursor = 0; cli_redraw(& | ||
| - | if (ch == 0x05) { cursor = pos; cli_redraw(& | ||
| - | // Backspace | ||
| - | if (ch == 0x08 || ch == 0x7F) { | ||
| - | if (cursor > 0) { | ||
| - | memmove(& | ||
| - | cursor--; pos--; | ||
| - | line[pos] = 0; | ||
| - | cli_redraw(& | ||
| - | } | ||
| - | continue; | ||
| - | } | ||
| - | // Ctrl-U: clear line | ||
| - | if (ch == 0x15) { pos = cursor = 0; line[0] = 0; cli_redraw(& | ||
| - | // Ctrl-L: redraw | ||
| - | if (ch == 0x0C) { cli_redraw(& | ||
| - | // Ctrl-W: delete previous word | ||
| - | if (ch == 0x17) { | ||
| - | size_t start = cursor; | ||
| - | while (start > 0 && isspace((unsigned char)line[start-1])) start--; | ||
| - | while (start > 0 && !isspace((unsigned char)line[start-1])) start--; | ||
| - | if (start < cursor) { | ||
| - | memmove(& | ||
| - | pos -= (cursor - start); | ||
| - | cursor = start; | ||
| - | line[pos] = 0; | ||
| - | cli_redraw(& | ||
| - | } | ||
| - | continue; | ||
| - | } | ||
| - | // Printable ASCII: insert at cursor | ||
| - | if (isprint(ch)) { | ||
| - | if (pos + 1 < CLI_LINE_MAX) { | ||
| - | if (cli_in_hist(& | ||
| - | memmove(& | ||
| - | line[cursor++] = (char)ch; | ||
| - | pos++; | ||
| - | line[pos] = 0; | ||
| - | cli_redraw(& | ||
| - | } | ||
| - | continue; | ||
| - | } | ||
| - | // ignore other control bytes | ||
| - | } | ||
| - | } | ||
| - | |||
| - | /*======== APP ========*/ | ||
| - | void app_main(void) { | ||
| - | const int baud = 115200; | ||
| - | const uart_port_t uart_num = UART_NUM_0; | ||
| - | uart_config_t cfg = { | ||
| - | .baud_rate | ||
| - | .data_bits | ||
| - | .parity | ||
| - | .stop_bits | ||
| - | .flow_ctrl | ||
| - | .source_clk = UART_SCLK_DEFAULT, | ||
| - | }; | ||
| - | ESP_ERROR_CHECK(uart_driver_install(uart_num, | ||
| - | ESP_ERROR_CHECK(uart_param_config(uart_num, | ||
| - | uart_vfs_dev_use_driver(uart_num); | ||
| - | uart_vfs_dev_port_set_rx_line_endings(uart_num, | ||
| - | uart_vfs_dev_port_set_tx_line_endings(uart_num, | ||
| - | vTaskDelay(pdMS_TO_TICKS(200)); | ||
| - | uart_flush_input(uart_num); | ||
| - | printf(" | ||
| - | printf(" | ||
| - | print_test_safe_pins(); | ||
| - | xTaskCreatePinnedToCore(console_task, | ||
| - | CONSOLE_TASK_PRIO, | ||
| - | // Don't return; keep prompt active | ||
| - | vTaskDelete(NULL); | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | |||
| ===== Arduino (basic version) ===== | ===== Arduino (basic version) ===== | ||