Add Phase 0 RS-232 characterization harness and test firmware with cli
This commit is contained in:
+12
-1
@@ -1,4 +1,15 @@
|
||||
idf_component_register(
|
||||
SRCS "main.c"
|
||||
SRCS
|
||||
"main.c"
|
||||
"status_led.c"
|
||||
"rs232_hw_test.c"
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES
|
||||
console
|
||||
esp_driver_gpio
|
||||
esp_driver_uart
|
||||
esp_psram
|
||||
esp_timer
|
||||
freertos
|
||||
led_strip
|
||||
)
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/uart.h"
|
||||
|
||||
/*
|
||||
* Hardware profile: ESP32-S3-DevKitC-1-compatible N16R8 board connected to
|
||||
* the Adafruit MAX3243 full-pinout RS-232 breakout (product 5988).
|
||||
*
|
||||
* Keep these definitions in one place so future board profiles can select a
|
||||
* different pin map without scattering hardware assumptions through drivers.
|
||||
*/
|
||||
#define BOARD_RGB_LED_GPIO GPIO_NUM_48
|
||||
|
||||
#define RS232_UART_PORT UART_NUM_1
|
||||
#define RS232_TX_GPIO GPIO_NUM_17
|
||||
#define RS232_RX_GPIO GPIO_NUM_18
|
||||
#define RS232_RTS_GPIO GPIO_NUM_15
|
||||
#define RS232_CTS_GPIO GPIO_NUM_16
|
||||
|
||||
#define RS232_DTR_GPIO GPIO_NUM_7
|
||||
#define RS232_DSR_GPIO GPIO_NUM_5
|
||||
#define RS232_DCD_GPIO GPIO_NUM_4
|
||||
#define RS232_RI_GPIO GPIO_NUM_6
|
||||
|
||||
#define RS232_VALID_GPIO GPIO_NUM_8
|
||||
|
||||
/*
|
||||
* Adafruit labels this pin OFF, but it is connected to the MAX3243
|
||||
* active-low !FORCEOFF input. Releasing the open-drain GPIO enables the
|
||||
* transceiver through the breakout's pull-up; driving it low disables it.
|
||||
*/
|
||||
#define RS232_FORCE_OFF_N_GPIO GPIO_NUM_9
|
||||
+36
-57
@@ -1,54 +1,20 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "driver/uart.h"
|
||||
#include "esp_console.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_psram.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "led_strip.h"
|
||||
#include "led_strip_rmt.h"
|
||||
#include "rs232_hw_test.h"
|
||||
#include "status_led.h"
|
||||
|
||||
#ifndef RGB_LED_GPIO
|
||||
#define RGB_LED_GPIO 48
|
||||
#endif
|
||||
#define CONSOLE_BAUD_RATE 115200
|
||||
#define CONSOLE_TX_GPIO 43
|
||||
#define CONSOLE_RX_GPIO 44
|
||||
|
||||
#define RGB_LED_COUNT 1
|
||||
#define RGB_LED_BRIGHTNESS 32
|
||||
#define FADE_STEP_DELAY_MS 20
|
||||
|
||||
static const char *TAG = "rgb_smoke_test";
|
||||
|
||||
static led_strip_handle_t configure_rgb_led(void)
|
||||
{
|
||||
const led_strip_config_t strip_config = {
|
||||
.strip_gpio_num = RGB_LED_GPIO,
|
||||
.max_leds = RGB_LED_COUNT,
|
||||
.led_model = LED_MODEL_WS2812,
|
||||
.color_component_format = LED_STRIP_COLOR_COMPONENT_FMT_GRB,
|
||||
.flags = {
|
||||
.invert_out = false,
|
||||
},
|
||||
};
|
||||
|
||||
const led_strip_rmt_config_t rmt_config = {
|
||||
.clk_src = RMT_CLK_SRC_DEFAULT,
|
||||
.resolution_hz = 10 * 1000 * 1000,
|
||||
.mem_block_symbols = 0,
|
||||
.flags = {
|
||||
.with_dma = false,
|
||||
},
|
||||
};
|
||||
|
||||
led_strip_handle_t strip = NULL;
|
||||
ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &strip));
|
||||
ESP_ERROR_CHECK(led_strip_clear(strip));
|
||||
|
||||
return strip;
|
||||
}
|
||||
static const char *TAG = "phase0";
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "ESP32-S3 build-chain smoke test started");
|
||||
ESP_LOGI(TAG, "ESP32-S3 RS-232 Phase 0 hardware characterization started");
|
||||
|
||||
if (esp_psram_is_initialized()) {
|
||||
ESP_LOGI(TAG, "PSRAM initialized: %u bytes", (unsigned int)esp_psram_get_size());
|
||||
@@ -56,19 +22,32 @@ void app_main(void)
|
||||
ESP_LOGW(TAG, "PSRAM is not initialized");
|
||||
}
|
||||
|
||||
led_strip_handle_t strip = configure_rgb_led();
|
||||
ESP_LOGI(TAG, "Sweeping the onboard RGB LED on GPIO%d", RGB_LED_GPIO);
|
||||
/* Blue means that the test harness is initialized and waiting for a command. */
|
||||
ESP_ERROR_CHECK(status_led_init());
|
||||
ESP_ERROR_CHECK(rs232_hw_test_init());
|
||||
|
||||
while (true) {
|
||||
for (uint16_t hue = 0; hue < 360; ++hue) {
|
||||
ESP_ERROR_CHECK(led_strip_set_pixel_hsv(
|
||||
strip,
|
||||
0,
|
||||
hue,
|
||||
UINT8_MAX,
|
||||
RGB_LED_BRIGHTNESS));
|
||||
ESP_ERROR_CHECK(led_strip_refresh(strip));
|
||||
vTaskDelay(pdMS_TO_TICKS(FADE_STEP_DELAY_MS));
|
||||
}
|
||||
}
|
||||
esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();
|
||||
repl_config.prompt = "rs232-test> ";
|
||||
repl_config.max_cmdline_length = 160;
|
||||
repl_config.task_stack_size = 8192;
|
||||
|
||||
/*
|
||||
* UART0 remains dedicated to development and diagnostics. The external
|
||||
* RS-232 data path uses UART1 on GPIO17/18 and cannot disturb this REPL.
|
||||
*/
|
||||
esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT();
|
||||
uart_config.channel = UART_NUM_0;
|
||||
uart_config.baud_rate = CONSOLE_BAUD_RATE;
|
||||
uart_config.tx_gpio_num = CONSOLE_TX_GPIO;
|
||||
uart_config.rx_gpio_num = CONSOLE_RX_GPIO;
|
||||
|
||||
esp_console_repl_t *repl = NULL;
|
||||
ESP_ERROR_CHECK(esp_console_new_repl_uart(&uart_config, &repl_config, &repl));
|
||||
|
||||
/* The REPL constructor initializes esp_console and installs `help`. */
|
||||
ESP_ERROR_CHECK(rs232_hw_test_register_console_commands());
|
||||
ESP_ERROR_CHECK(esp_console_start_repl(repl));
|
||||
|
||||
ESP_LOGI(TAG, "Interactive test console ready at %d baud", CONSOLE_BAUD_RATE);
|
||||
ESP_LOGI(TAG, "Type 'help' for commands; no test runs automatically");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,878 @@
|
||||
#include "rs232_hw_test.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "board_pins.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/uart.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_console.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_timer.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/task.h"
|
||||
#include "status_led.h"
|
||||
|
||||
#define STATIC_SETTLE_TIME_MS 20
|
||||
#define TRANSCEIVER_SETTLE_TIME_MS 100
|
||||
#define UART_RX_BUFFER_SIZE 4096
|
||||
#define UART_EVENT_QUEUE_SIZE 20
|
||||
#define UART_MAX_PAYLOAD_SIZE 512
|
||||
#define UART_MIN_BAUD_RATE 110
|
||||
#define UART_MAX_BAUD_RATE 1000000
|
||||
|
||||
/*
|
||||
* These values describe the state commanded on the MAX3243's logic side.
|
||||
* A MAX3243 driver inverts them: logic 0 becomes a positive RS-232 voltage,
|
||||
* while logic 1 becomes a negative RS-232 voltage (the idle/MARK state).
|
||||
*/
|
||||
static int s_tx_level = 1;
|
||||
static int s_dtr_level = 1;
|
||||
static int s_rts_level = 1;
|
||||
static bool s_transceiver_enabled = true;
|
||||
static bool s_initialized;
|
||||
static bool s_uart_active;
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
uart_word_length_t data_bits;
|
||||
uart_parity_t parity;
|
||||
uart_stop_bits_t stop_bits;
|
||||
uint8_t data_mask;
|
||||
} serial_format_t;
|
||||
|
||||
typedef struct {
|
||||
unsigned int frame_errors;
|
||||
unsigned int parity_errors;
|
||||
unsigned int fifo_overflows;
|
||||
unsigned int buffer_full_events;
|
||||
unsigned int breaks;
|
||||
} uart_error_counts_t;
|
||||
|
||||
typedef struct {
|
||||
int baud_rate;
|
||||
const char *format;
|
||||
size_t payload_size;
|
||||
} uart_suite_case_t;
|
||||
|
||||
static const serial_format_t s_serial_formats[] = {
|
||||
{"8N1", UART_DATA_8_BITS, UART_PARITY_DISABLE, UART_STOP_BITS_1, 0xff},
|
||||
{"8E1", UART_DATA_8_BITS, UART_PARITY_EVEN, UART_STOP_BITS_1, 0xff},
|
||||
{"8O1", UART_DATA_8_BITS, UART_PARITY_ODD, UART_STOP_BITS_1, 0xff},
|
||||
{"8N2", UART_DATA_8_BITS, UART_PARITY_DISABLE, UART_STOP_BITS_2, 0xff},
|
||||
{"7E1", UART_DATA_7_BITS, UART_PARITY_EVEN, UART_STOP_BITS_1, 0x7f},
|
||||
{"7O1", UART_DATA_7_BITS, UART_PARITY_ODD, UART_STOP_BITS_1, 0x7f},
|
||||
};
|
||||
|
||||
static const uart_suite_case_t s_uart_suite[] = {
|
||||
{300, "8N1", 32},
|
||||
{1200, "8N1", 64},
|
||||
{9600, "8N1", 256},
|
||||
{115200, "8N1", 512},
|
||||
{230400, "8N1", 512},
|
||||
{250000, "8N1", 512},
|
||||
{9600, "8E1", 128},
|
||||
{9600, "8O1", 128},
|
||||
{9600, "8N2", 128},
|
||||
{9600, "7E1", 128},
|
||||
{9600, "7O1", 128},
|
||||
};
|
||||
|
||||
static TickType_t milliseconds_to_ticks(uint64_t milliseconds)
|
||||
{
|
||||
TickType_t ticks = pdMS_TO_TICKS(milliseconds);
|
||||
|
||||
/* A non-zero wait must remain non-zero even with a coarse RTOS tick. */
|
||||
return (milliseconds > 0 && ticks == 0) ? 1 : ticks;
|
||||
}
|
||||
|
||||
static esp_err_t drive_transceiver_enabled(bool enabled)
|
||||
{
|
||||
return gpio_set_level(RS232_FORCE_OFF_N_GPIO, enabled ? 1 : 0);
|
||||
}
|
||||
|
||||
static esp_err_t configure_static_gpio(bool reset_driver_levels)
|
||||
{
|
||||
bool enable_after_configuration = s_transceiver_enabled;
|
||||
|
||||
/*
|
||||
* Shut the MAX3243 down before changing pin routing. gpio_set_level sets
|
||||
* the output latch first; GPIO_MODE_INPUT_OUTPUT_OD then actively pulls
|
||||
* !FORCEOFF low and also permits physical pin-level readback.
|
||||
*/
|
||||
ESP_RETURN_ON_ERROR(
|
||||
drive_transceiver_enabled(false),
|
||||
"rs232_test",
|
||||
"Set OFF latch for safe reconfiguration");
|
||||
const gpio_config_t shutdown_config = {
|
||||
.pin_bit_mask = 1ULL << RS232_FORCE_OFF_N_GPIO,
|
||||
.mode = GPIO_MODE_INPUT_OUTPUT_OD,
|
||||
.pull_up_en = GPIO_PULLUP_ENABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE,
|
||||
};
|
||||
ESP_RETURN_ON_ERROR(gpio_config(&shutdown_config), "rs232_test", "Configure OFF GPIO");
|
||||
|
||||
if (reset_driver_levels) {
|
||||
s_tx_level = 1;
|
||||
s_dtr_level = 1;
|
||||
s_rts_level = 1;
|
||||
}
|
||||
|
||||
/* Set output latches before enabling output drivers to minimize glitches. */
|
||||
ESP_RETURN_ON_ERROR(gpio_set_level(RS232_TX_GPIO, s_tx_level), "rs232_test", "Set TX latch");
|
||||
ESP_RETURN_ON_ERROR(gpio_set_level(RS232_DTR_GPIO, s_dtr_level), "rs232_test", "Set DTR latch");
|
||||
ESP_RETURN_ON_ERROR(gpio_set_level(RS232_RTS_GPIO, s_rts_level), "rs232_test", "Set RTS latch");
|
||||
|
||||
const gpio_config_t driver_config = {
|
||||
.pin_bit_mask = (1ULL << RS232_TX_GPIO) |
|
||||
(1ULL << RS232_DTR_GPIO) |
|
||||
(1ULL << RS232_RTS_GPIO),
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE,
|
||||
};
|
||||
ESP_RETURN_ON_ERROR(gpio_config(&driver_config), "rs232_test", "Configure driver GPIOs");
|
||||
|
||||
const gpio_config_t receiver_config = {
|
||||
.pin_bit_mask = (1ULL << RS232_RX_GPIO) |
|
||||
(1ULL << RS232_CTS_GPIO) |
|
||||
(1ULL << RS232_DSR_GPIO) |
|
||||
(1ULL << RS232_DCD_GPIO) |
|
||||
(1ULL << RS232_RI_GPIO) |
|
||||
(1ULL << RS232_VALID_GPIO),
|
||||
.mode = GPIO_MODE_INPUT,
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE,
|
||||
};
|
||||
ESP_RETURN_ON_ERROR(gpio_config(&receiver_config), "rs232_test", "Configure receiver GPIOs");
|
||||
|
||||
ESP_RETURN_ON_ERROR(
|
||||
drive_transceiver_enabled(enable_after_configuration),
|
||||
"rs232_test",
|
||||
"Restore OFF state after configuration");
|
||||
|
||||
s_uart_active = false;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t set_transceiver_enabled(bool enabled)
|
||||
{
|
||||
esp_err_t err = drive_transceiver_enabled(enabled);
|
||||
if (err == ESP_OK) {
|
||||
s_transceiver_enabled = enabled;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static esp_err_t set_driver_levels(int tx, int dtr, int rts)
|
||||
{
|
||||
ESP_RETURN_ON_ERROR(gpio_set_level(RS232_TX_GPIO, tx), "rs232_test", "Set TX");
|
||||
ESP_RETURN_ON_ERROR(gpio_set_level(RS232_DTR_GPIO, dtr), "rs232_test", "Set DTR");
|
||||
ESP_RETURN_ON_ERROR(gpio_set_level(RS232_RTS_GPIO, rts), "rs232_test", "Set RTS");
|
||||
|
||||
s_tx_level = tx;
|
||||
s_dtr_level = dtr;
|
||||
s_rts_level = rts;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static bool parse_binary_level(const char *text, int *level)
|
||||
{
|
||||
if (strcmp(text, "0") == 0) {
|
||||
*level = 0;
|
||||
return true;
|
||||
}
|
||||
if (strcmp(text, "1") == 0) {
|
||||
*level = 1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool parse_integer(const char *text, long minimum, long maximum, long *value)
|
||||
{
|
||||
char *end = NULL;
|
||||
errno = 0;
|
||||
long parsed = strtol(text, &end, 10);
|
||||
|
||||
if (errno != 0 || end == text || *end != '\0' || parsed < minimum || parsed > maximum) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*value = parsed;
|
||||
return true;
|
||||
}
|
||||
|
||||
static const serial_format_t *find_serial_format(const char *name)
|
||||
{
|
||||
for (size_t index = 0; index < sizeof(s_serial_formats) / sizeof(s_serial_formats[0]); ++index) {
|
||||
if (strcmp(name, s_serial_formats[index].name) == 0) {
|
||||
return &s_serial_formats[index];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int command_status(int argc, char **argv)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
printf("MAX3243: %s (OFF/!FORCEOFF GPIO%d=%d, 1 means released)\n",
|
||||
s_transceiver_enabled ? "enabled" : "disabled",
|
||||
RS232_FORCE_OFF_N_GPIO,
|
||||
gpio_get_level(RS232_FORCE_OFF_N_GPIO));
|
||||
printf("Drivers: TX=%d DTR=%d RTS=%d [logic 0 -> positive RS-232, logic 1 -> negative]\n",
|
||||
s_tx_level,
|
||||
s_dtr_level,
|
||||
s_rts_level);
|
||||
printf("Receivers: RX=%d DSR=%d CTS=%d DCD=%d RI=%d\n",
|
||||
gpio_get_level(RS232_RX_GPIO),
|
||||
gpio_get_level(RS232_DSR_GPIO),
|
||||
gpio_get_level(RS232_CTS_GPIO),
|
||||
gpio_get_level(RS232_DCD_GPIO),
|
||||
gpio_get_level(RS232_RI_GPIO));
|
||||
printf("VLD=%d (%s valid RS-232 voltage detected)\n",
|
||||
gpio_get_level(RS232_VALID_GPIO),
|
||||
gpio_get_level(RS232_VALID_GPIO) ? "at least one" : "no");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int command_transceiver(int argc, char **argv)
|
||||
{
|
||||
if (argc != 2 || (strcmp(argv[1], "enable") != 0 && strcmp(argv[1], "disable") != 0)) {
|
||||
printf("Usage: transceiver <enable|disable>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool enable = strcmp(argv[1], "enable") == 0;
|
||||
esp_err_t err = set_transceiver_enabled(enable);
|
||||
if (err != ESP_OK) {
|
||||
printf("Could not control the transceiver: %s\n", esp_err_to_name(err));
|
||||
return 1;
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(STATIC_SETTLE_TIME_MS));
|
||||
printf("MAX3243 %s; OFF/!FORCEOFF is %s. VLD=%d\n",
|
||||
enable ? "enabled" : "disabled",
|
||||
enable ? "released high" : "driven low",
|
||||
gpio_get_level(RS232_VALID_GPIO));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int command_drivers(int argc, char **argv)
|
||||
{
|
||||
int tx;
|
||||
int dtr;
|
||||
int rts;
|
||||
|
||||
if (argc != 4 ||
|
||||
!parse_binary_level(argv[1], &tx) ||
|
||||
!parse_binary_level(argv[2], &dtr) ||
|
||||
!parse_binary_level(argv[3], &rts)) {
|
||||
printf("Usage: drivers <tx 0|1> <dtr 0|1> <rts 0|1>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
esp_err_t err = set_driver_levels(tx, dtr, rts);
|
||||
if (err != ESP_OK) {
|
||||
printf("Could not set driver levels: %s\n", esp_err_to_name(err));
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("TX=%d DTR=%d RTS=%d\n", tx, dtr, rts);
|
||||
printf("Logic 0 -> positive RS-232 voltage; logic 1 -> negative RS-232 voltage.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
LOOPBACK_CONFIGURATION_A,
|
||||
LOOPBACK_CONFIGURATION_B,
|
||||
} loopback_configuration_t;
|
||||
|
||||
static esp_err_t run_static_loopback(loopback_configuration_t configuration)
|
||||
{
|
||||
bool all_passed = true;
|
||||
esp_err_t err = status_led_set(STATUS_LED_RUNNING);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
ESP_RETURN_ON_ERROR(set_transceiver_enabled(true), "rs232_test", "Enable transceiver");
|
||||
vTaskDelay(pdMS_TO_TICKS(TRANSCEIVER_SETTLE_TIME_MS));
|
||||
|
||||
if (configuration == LOOPBACK_CONFIGURATION_A) {
|
||||
printf("Configuration A expects DE-9 3->2, 4->6, and 7->8.\n");
|
||||
printf("TX DTR RTS | RX DSR CTS VLD | result\n");
|
||||
} else {
|
||||
printf("Configuration B expects DE-9 3->1, 4->9, and 7->2.\n");
|
||||
printf("TX DTR RTS | DCD RI RX VLD | result\n");
|
||||
}
|
||||
|
||||
for (unsigned int pattern = 0; pattern < 8; ++pattern) {
|
||||
int tx = (pattern >> 2) & 1;
|
||||
int dtr = (pattern >> 1) & 1;
|
||||
int rts = pattern & 1;
|
||||
|
||||
err = set_driver_levels(tx, dtr, rts);
|
||||
if (err != ESP_OK) {
|
||||
all_passed = false;
|
||||
break;
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(STATIC_SETTLE_TIME_MS));
|
||||
|
||||
int first;
|
||||
int second;
|
||||
int third;
|
||||
bool pattern_passed;
|
||||
int valid = gpio_get_level(RS232_VALID_GPIO);
|
||||
|
||||
if (configuration == LOOPBACK_CONFIGURATION_A) {
|
||||
first = gpio_get_level(RS232_RX_GPIO);
|
||||
second = gpio_get_level(RS232_DSR_GPIO);
|
||||
third = gpio_get_level(RS232_CTS_GPIO);
|
||||
pattern_passed = first == tx && second == dtr && third == rts && valid == 1;
|
||||
} else {
|
||||
first = gpio_get_level(RS232_DCD_GPIO);
|
||||
second = gpio_get_level(RS232_RI_GPIO);
|
||||
third = gpio_get_level(RS232_RX_GPIO);
|
||||
pattern_passed = first == tx && second == dtr && third == rts && valid == 1;
|
||||
}
|
||||
|
||||
printf(" %d %d %d | %d %d %d %d | %s\n",
|
||||
tx, dtr, rts, first, second, third, valid,
|
||||
pattern_passed ? "PASS" : "FAIL");
|
||||
all_passed = all_passed && pattern_passed;
|
||||
}
|
||||
|
||||
/* Return every RS-232 output to its idle negative-voltage state. */
|
||||
esp_err_t idle_err = set_driver_levels(1, 1, 1);
|
||||
if (err == ESP_OK && idle_err != ESP_OK) {
|
||||
err = idle_err;
|
||||
all_passed = false;
|
||||
}
|
||||
|
||||
if (err != ESP_OK) {
|
||||
printf("GPIO error: %s\n", esp_err_to_name(err));
|
||||
}
|
||||
printf("Static loopback %c: %s\n",
|
||||
configuration == LOOPBACK_CONFIGURATION_A ? 'A' : 'B',
|
||||
all_passed ? "PASS" : "FAIL");
|
||||
status_led_set(all_passed ? STATUS_LED_PASS : STATUS_LED_FAIL);
|
||||
return all_passed ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
static int command_loopback_a(int argc, char **argv)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
return run_static_loopback(LOOPBACK_CONFIGURATION_A) == ESP_OK ? 0 : 1;
|
||||
}
|
||||
|
||||
static int command_loopback_b(int argc, char **argv)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
return run_static_loopback(LOOPBACK_CONFIGURATION_B) == ESP_OK ? 0 : 1;
|
||||
}
|
||||
|
||||
static int command_valid_test(int argc, char **argv)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
bool passed = true;
|
||||
esp_err_t err = status_led_set(STATUS_LED_RUNNING);
|
||||
if (err != ESP_OK) {
|
||||
printf("Could not set status LED: %s\n", esp_err_to_name(err));
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("This test requires loopback A or B and no externally powered RS-232 peer.\n");
|
||||
printf("It will briefly shut down the MAX3243 through active-low OFF/!FORCEOFF.\n");
|
||||
|
||||
/* Positive outputs provide an unambiguous valid voltage to looped receivers. */
|
||||
if (set_driver_levels(0, 0, 0) != ESP_OK || set_transceiver_enabled(true) != ESP_OK) {
|
||||
passed = false;
|
||||
goto cleanup;
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(TRANSCEIVER_SETTLE_TIME_MS));
|
||||
int enabled_before = gpio_get_level(RS232_VALID_GPIO);
|
||||
printf("Enabled: VLD=%d (expected 1) %s\n",
|
||||
enabled_before, enabled_before == 1 ? "PASS" : "FAIL");
|
||||
passed = passed && enabled_before == 1;
|
||||
|
||||
if (set_transceiver_enabled(false) != ESP_OK) {
|
||||
passed = false;
|
||||
goto cleanup;
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(TRANSCEIVER_SETTLE_TIME_MS));
|
||||
int disabled = gpio_get_level(RS232_VALID_GPIO);
|
||||
printf("Disabled: VLD=%d (expected 0) %s\n",
|
||||
disabled, disabled == 0 ? "PASS" : "FAIL");
|
||||
passed = passed && disabled == 0;
|
||||
|
||||
if (set_transceiver_enabled(true) != ESP_OK) {
|
||||
passed = false;
|
||||
goto cleanup;
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(TRANSCEIVER_SETTLE_TIME_MS));
|
||||
int enabled_after = gpio_get_level(RS232_VALID_GPIO);
|
||||
printf("Re-enabled: VLD=%d (expected 1) %s\n",
|
||||
enabled_after, enabled_after == 1 ? "PASS" : "FAIL");
|
||||
passed = passed && enabled_after == 1;
|
||||
|
||||
cleanup:;
|
||||
/*
|
||||
* Run every cleanup step independently: one GPIO error must not prevent us
|
||||
* from attempting to restore the other safety-relevant outputs.
|
||||
*/
|
||||
esp_err_t shutdown_error = set_transceiver_enabled(false);
|
||||
esp_err_t idle_error = set_driver_levels(1, 1, 1);
|
||||
esp_err_t enable_error = set_transceiver_enabled(true);
|
||||
if (shutdown_error != ESP_OK || idle_error != ESP_OK || enable_error != ESP_OK) {
|
||||
printf("Cleanup error: OFF-low=%s idle-drivers=%s OFF-high=%s\n",
|
||||
esp_err_to_name(shutdown_error),
|
||||
esp_err_to_name(idle_error),
|
||||
esp_err_to_name(enable_error));
|
||||
passed = false;
|
||||
}
|
||||
|
||||
printf("VLD/OFF test: %s\n", passed ? "PASS" : "FAIL");
|
||||
status_led_set(passed ? STATUS_LED_PASS : STATUS_LED_FAIL);
|
||||
return passed ? 0 : 1;
|
||||
}
|
||||
|
||||
static void generate_payload(uint8_t *payload, size_t payload_size, uint8_t mask)
|
||||
{
|
||||
static const uint8_t diagnostic_prefix[] = {
|
||||
0x00, 0xff, 0x55, 0xaa,
|
||||
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
|
||||
0xfe, 0xfd, 0xfb, 0xf7,
|
||||
};
|
||||
uint32_t pseudo_random = 0x6d2b79f5;
|
||||
|
||||
for (size_t index = 0; index < payload_size; ++index) {
|
||||
uint8_t value;
|
||||
if (index < sizeof(diagnostic_prefix)) {
|
||||
value = diagnostic_prefix[index];
|
||||
} else {
|
||||
/* xorshift32 is deterministic, making failures exactly repeatable. */
|
||||
pseudo_random ^= pseudo_random << 13;
|
||||
pseudo_random ^= pseudo_random >> 17;
|
||||
pseudo_random ^= pseudo_random << 5;
|
||||
value = (uint8_t)pseudo_random;
|
||||
}
|
||||
payload[index] = value & mask;
|
||||
}
|
||||
}
|
||||
|
||||
static void collect_uart_events(QueueHandle_t event_queue, uart_error_counts_t *errors)
|
||||
{
|
||||
uart_event_t event;
|
||||
while (xQueueReceive(event_queue, &event, 0) == pdTRUE) {
|
||||
switch (event.type) {
|
||||
case UART_FRAME_ERR:
|
||||
++errors->frame_errors;
|
||||
break;
|
||||
case UART_PARITY_ERR:
|
||||
++errors->parity_errors;
|
||||
break;
|
||||
case UART_FIFO_OVF:
|
||||
++errors->fifo_overflows;
|
||||
break;
|
||||
case UART_BUFFER_FULL:
|
||||
++errors->buffer_full_events;
|
||||
break;
|
||||
case UART_BREAK:
|
||||
case UART_DATA_BREAK:
|
||||
++errors->breaks;
|
||||
break;
|
||||
default:
|
||||
/* UART_DATA notifications need no action because reads use the ring buffer. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t uart_test_timeout_ms(int baud_rate, size_t payload_size)
|
||||
{
|
||||
/* Twelve bits per character safely covers the widest supported frame. */
|
||||
uint64_t nominal_ms = ((uint64_t)payload_size * 12U * 1000U + (uint64_t)baud_rate - 1U) /
|
||||
(uint64_t)baud_rate;
|
||||
return 1000U + nominal_ms * 3U;
|
||||
}
|
||||
|
||||
static esp_err_t run_uart_loopback(int baud_rate, const serial_format_t *format, size_t payload_size)
|
||||
{
|
||||
uint8_t transmitted[UART_MAX_PAYLOAD_SIZE];
|
||||
uint8_t received[UART_MAX_PAYLOAD_SIZE];
|
||||
QueueHandle_t event_queue = NULL;
|
||||
uart_error_counts_t uart_errors = {0};
|
||||
bool driver_installed = false;
|
||||
bool test_passed = false;
|
||||
esp_err_t result = ESP_FAIL;
|
||||
size_t received_size = 0;
|
||||
size_t extra_bytes = 0;
|
||||
size_t mismatches = 0;
|
||||
|
||||
generate_payload(transmitted, payload_size, format->data_mask);
|
||||
memset(received, 0, sizeof(received));
|
||||
|
||||
result = status_led_set(STATUS_LED_RUNNING);
|
||||
if (result != ESP_OK) {
|
||||
printf("Could not set running LED: %s\n", esp_err_to_name(result));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Keep all RS-232 drivers off while GPIO17/18 are handed to UART1. */
|
||||
result = drive_transceiver_enabled(false);
|
||||
if (result != ESP_OK) {
|
||||
printf("Could not shut down MAX3243 before UART setup: %s\n", esp_err_to_name(result));
|
||||
goto cleanup;
|
||||
}
|
||||
result = set_driver_levels(1, 1, 1);
|
||||
if (result != ESP_OK) {
|
||||
printf("Could not set idle outputs before UART setup: %s\n", esp_err_to_name(result));
|
||||
goto cleanup;
|
||||
}
|
||||
s_uart_active = true;
|
||||
|
||||
const uart_config_t uart_config = {
|
||||
.baud_rate = baud_rate,
|
||||
.data_bits = format->data_bits,
|
||||
.parity = format->parity,
|
||||
.stop_bits = format->stop_bits,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.rx_flow_ctrl_thresh = 0,
|
||||
.source_clk = UART_SCLK_DEFAULT,
|
||||
.flags = {
|
||||
.allow_pd = 0,
|
||||
},
|
||||
};
|
||||
|
||||
result = uart_driver_install(
|
||||
RS232_UART_PORT,
|
||||
UART_RX_BUFFER_SIZE,
|
||||
0,
|
||||
UART_EVENT_QUEUE_SIZE,
|
||||
&event_queue,
|
||||
0);
|
||||
if (result != ESP_OK) {
|
||||
printf("uart_driver_install failed: %s\n", esp_err_to_name(result));
|
||||
goto cleanup;
|
||||
}
|
||||
driver_installed = true;
|
||||
|
||||
result = uart_param_config(RS232_UART_PORT, &uart_config);
|
||||
if (result != ESP_OK) {
|
||||
printf("uart_param_config failed: %s\n", esp_err_to_name(result));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* RTS and CTS remain ordinary GPIOs until a dedicated flow-control test. */
|
||||
result = uart_set_pin(
|
||||
RS232_UART_PORT,
|
||||
RS232_TX_GPIO,
|
||||
RS232_RX_GPIO,
|
||||
UART_PIN_NO_CHANGE,
|
||||
UART_PIN_NO_CHANGE);
|
||||
if (result != ESP_OK) {
|
||||
printf("uart_set_pin failed: %s\n", esp_err_to_name(result));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
result = uart_flush_input(RS232_UART_PORT);
|
||||
if (result != ESP_OK) {
|
||||
printf("Could not flush UART input: %s\n", esp_err_to_name(result));
|
||||
goto cleanup;
|
||||
}
|
||||
xQueueReset(event_queue);
|
||||
|
||||
result = set_transceiver_enabled(true);
|
||||
if (result != ESP_OK) {
|
||||
printf("Could not enable MAX3243 after UART setup: %s\n", esp_err_to_name(result));
|
||||
goto cleanup;
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(TRANSCEIVER_SETTLE_TIME_MS));
|
||||
|
||||
printf("UART1 %d %s, %u bytes: transmitting...\n",
|
||||
baud_rate, format->name, (unsigned int)payload_size);
|
||||
int written = uart_write_bytes(RS232_UART_PORT, transmitted, payload_size);
|
||||
if (written < 0 || (size_t)written != payload_size) {
|
||||
printf("uart_write_bytes wrote %d of %u bytes\n", written, (unsigned int)payload_size);
|
||||
result = ESP_FAIL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
uint64_t timeout_ms = uart_test_timeout_ms(baud_rate, payload_size);
|
||||
result = uart_wait_tx_done(RS232_UART_PORT, milliseconds_to_ticks(timeout_ms));
|
||||
if (result != ESP_OK) {
|
||||
printf("Timed out waiting for UART transmission: %s\n", esp_err_to_name(result));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
int64_t deadline_us = esp_timer_get_time() + (int64_t)(timeout_ms * 1000U);
|
||||
while (received_size < payload_size) {
|
||||
int64_t remaining_us = deadline_us - esp_timer_get_time();
|
||||
if (remaining_us <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
uint64_t remaining_ms = ((uint64_t)remaining_us + 999U) / 1000U;
|
||||
int count = uart_read_bytes(
|
||||
RS232_UART_PORT,
|
||||
received + received_size,
|
||||
payload_size - received_size,
|
||||
milliseconds_to_ticks(remaining_ms));
|
||||
if (count < 0) {
|
||||
printf("uart_read_bytes failed\n");
|
||||
result = ESP_FAIL;
|
||||
goto cleanup;
|
||||
}
|
||||
if (count == 0) {
|
||||
break;
|
||||
}
|
||||
received_size += (size_t)count;
|
||||
}
|
||||
|
||||
size_t buffered_bytes = 0;
|
||||
if (uart_get_buffered_data_len(RS232_UART_PORT, &buffered_bytes) == ESP_OK) {
|
||||
uint8_t discard[64];
|
||||
while (buffered_bytes > 0) {
|
||||
size_t request = buffered_bytes < sizeof(discard) ? buffered_bytes : sizeof(discard);
|
||||
int count = uart_read_bytes(RS232_UART_PORT, discard, request, 0);
|
||||
if (count <= 0) {
|
||||
break;
|
||||
}
|
||||
extra_bytes += (size_t)count;
|
||||
buffered_bytes -= (size_t)count;
|
||||
}
|
||||
}
|
||||
|
||||
collect_uart_events(event_queue, &uart_errors);
|
||||
|
||||
size_t comparable = received_size < payload_size ? received_size : payload_size;
|
||||
for (size_t index = 0; index < comparable; ++index) {
|
||||
if (received[index] != transmitted[index]) {
|
||||
++mismatches;
|
||||
if (mismatches <= 8) {
|
||||
printf(" mismatch at byte %u: sent 0x%02x, received 0x%02x\n",
|
||||
(unsigned int)index, transmitted[index], received[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
mismatches += payload_size - comparable;
|
||||
mismatches += extra_bytes;
|
||||
|
||||
test_passed = received_size == payload_size &&
|
||||
extra_bytes == 0 &&
|
||||
mismatches == 0 &&
|
||||
uart_errors.frame_errors == 0 &&
|
||||
uart_errors.parity_errors == 0 &&
|
||||
uart_errors.fifo_overflows == 0 &&
|
||||
uart_errors.buffer_full_events == 0 &&
|
||||
uart_errors.breaks == 0;
|
||||
|
||||
printf("sent=%u received=%u extra=%u mismatches=%u\n",
|
||||
(unsigned int)payload_size,
|
||||
(unsigned int)received_size,
|
||||
(unsigned int)extra_bytes,
|
||||
(unsigned int)mismatches);
|
||||
printf("UART events: frame=%u parity=%u FIFO-overflow=%u buffer-full=%u break=%u\n",
|
||||
uart_errors.frame_errors,
|
||||
uart_errors.parity_errors,
|
||||
uart_errors.fifo_overflows,
|
||||
uart_errors.buffer_full_events,
|
||||
uart_errors.breaks);
|
||||
printf("UART1 %d %s: %s\n", baud_rate, format->name, test_passed ? "PASS" : "FAIL");
|
||||
result = test_passed ? ESP_OK : ESP_FAIL;
|
||||
|
||||
cleanup:;
|
||||
/* Disable the line drivers before UART1 disconnects from GPIO17/18. */
|
||||
esp_err_t shutdown_error = drive_transceiver_enabled(false);
|
||||
if (shutdown_error != ESP_OK) {
|
||||
printf("Could not shut down MAX3243 during cleanup: %s\n", esp_err_to_name(shutdown_error));
|
||||
if (result == ESP_OK) {
|
||||
result = shutdown_error;
|
||||
}
|
||||
}
|
||||
|
||||
if (driver_installed) {
|
||||
esp_err_t delete_error = uart_driver_delete(RS232_UART_PORT);
|
||||
if (delete_error != ESP_OK) {
|
||||
printf("Could not delete UART1 driver: %s\n", esp_err_to_name(delete_error));
|
||||
if (result == ESP_OK) {
|
||||
result = delete_error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* GPIO17/18 return to static idle mode, then the transceiver is re-enabled. */
|
||||
s_transceiver_enabled = true;
|
||||
esp_err_t restore_error = configure_static_gpio(true);
|
||||
if (restore_error != ESP_OK) {
|
||||
printf("Could not restore static GPIO mode: %s\n", esp_err_to_name(restore_error));
|
||||
if (result == ESP_OK) {
|
||||
result = restore_error;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t led_error = status_led_set(result == ESP_OK ? STATUS_LED_PASS : STATUS_LED_FAIL);
|
||||
if (led_error != ESP_OK) {
|
||||
printf("Could not update status LED: %s\n", esp_err_to_name(led_error));
|
||||
if (result == ESP_OK) {
|
||||
result = led_error;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static int command_uart_loopback(int argc, char **argv)
|
||||
{
|
||||
long baud_rate;
|
||||
long payload_size = 256;
|
||||
const char *format_name = "8N1";
|
||||
|
||||
if (argc < 2 || argc > 4 ||
|
||||
!parse_integer(argv[1], UART_MIN_BAUD_RATE, UART_MAX_BAUD_RATE, &baud_rate)) {
|
||||
printf("Usage: uart-loopback <baud 110..1000000> [8N1|8E1|8O1|8N2|7E1|7O1] [bytes 1..512]\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (argc >= 3) {
|
||||
format_name = argv[2];
|
||||
}
|
||||
const serial_format_t *format = find_serial_format(format_name);
|
||||
if (format == NULL) {
|
||||
printf("Unsupported format '%s'. Use 8N1, 8E1, 8O1, 8N2, 7E1, or 7O1.\n", format_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (argc == 4 && !parse_integer(argv[3], 1, UART_MAX_PAYLOAD_SIZE, &payload_size)) {
|
||||
printf("Payload size must be between 1 and %d bytes.\n", UART_MAX_PAYLOAD_SIZE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Requires DE-9 pin 3 (TX) connected only to pin 2 (RX).\n");
|
||||
return run_uart_loopback((int)baud_rate, format, (size_t)payload_size) == ESP_OK ? 0 : 1;
|
||||
}
|
||||
|
||||
static int command_uart_suite(int argc, char **argv)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
bool all_passed = true;
|
||||
printf("Requires DE-9 pin 3 (TX) connected only to pin 2 (RX).\n");
|
||||
printf("Running %u UART loopback cases. This takes several seconds.\n",
|
||||
(unsigned int)(sizeof(s_uart_suite) / sizeof(s_uart_suite[0])));
|
||||
|
||||
for (size_t index = 0; index < sizeof(s_uart_suite) / sizeof(s_uart_suite[0]); ++index) {
|
||||
const uart_suite_case_t *test_case = &s_uart_suite[index];
|
||||
const serial_format_t *format = find_serial_format(test_case->format);
|
||||
printf("\n[%u/%u] ",
|
||||
(unsigned int)(index + 1),
|
||||
(unsigned int)(sizeof(s_uart_suite) / sizeof(s_uart_suite[0])));
|
||||
|
||||
if (format == NULL ||
|
||||
run_uart_loopback(test_case->baud_rate, format, test_case->payload_size) != ESP_OK) {
|
||||
all_passed = false;
|
||||
}
|
||||
}
|
||||
|
||||
printf("\nUART loopback suite: %s\n", all_passed ? "PASS" : "FAIL");
|
||||
status_led_set(all_passed ? STATUS_LED_PASS : STATUS_LED_FAIL);
|
||||
return all_passed ? 0 : 1;
|
||||
}
|
||||
|
||||
esp_err_t rs232_hw_test_init(void)
|
||||
{
|
||||
s_transceiver_enabled = true;
|
||||
ESP_RETURN_ON_ERROR(configure_static_gpio(true), "rs232_test", "Initialize static GPIO mode");
|
||||
s_initialized = true;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rs232_hw_test_register_console_commands(void)
|
||||
{
|
||||
if (!s_initialized || s_uart_active) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
const esp_console_cmd_t commands[] = {
|
||||
{
|
||||
.command = "status",
|
||||
.help = "Show MAX3243 driver, receiver, VLD, and shutdown states",
|
||||
.hint = NULL,
|
||||
.func = &command_status,
|
||||
.argtable = NULL,
|
||||
},
|
||||
{
|
||||
.command = "transceiver",
|
||||
.help = "Control active-low OFF: transceiver <enable|disable>",
|
||||
.hint = NULL,
|
||||
.func = &command_transceiver,
|
||||
.argtable = NULL,
|
||||
},
|
||||
{
|
||||
.command = "drivers",
|
||||
.help = "Set static logic levels: drivers <TX 0|1> <DTR 0|1> <RTS 0|1>",
|
||||
.hint = NULL,
|
||||
.func = &command_drivers,
|
||||
.argtable = NULL,
|
||||
},
|
||||
{
|
||||
.command = "loopback-a",
|
||||
.help = "Test TX->RX, DTR->DSR, RTS->CTS for all eight patterns",
|
||||
.hint = NULL,
|
||||
.func = &command_loopback_a,
|
||||
.argtable = NULL,
|
||||
},
|
||||
{
|
||||
.command = "loopback-b",
|
||||
.help = "Test TX->DCD, DTR->RI, RTS->RX for all eight patterns",
|
||||
.hint = NULL,
|
||||
.func = &command_loopback_b,
|
||||
.argtable = NULL,
|
||||
},
|
||||
{
|
||||
.command = "valid-test",
|
||||
.help = "Verify VLD while enabled, shut down, and re-enabled",
|
||||
.hint = NULL,
|
||||
.func = &command_valid_test,
|
||||
.argtable = NULL,
|
||||
},
|
||||
{
|
||||
.command = "uart-loopback",
|
||||
.help = "Run one UART1 test: uart-loopback <baud> [format] [bytes]",
|
||||
.hint = NULL,
|
||||
.func = &command_uart_loopback,
|
||||
.argtable = NULL,
|
||||
},
|
||||
{
|
||||
.command = "uart-suite",
|
||||
.help = "Run the predefined baud-rate and frame-format loopback suite",
|
||||
.hint = NULL,
|
||||
.func = &command_uart_suite,
|
||||
.argtable = NULL,
|
||||
},
|
||||
};
|
||||
|
||||
for (size_t index = 0; index < sizeof(commands) / sizeof(commands[0]); ++index) {
|
||||
ESP_RETURN_ON_ERROR(
|
||||
esp_console_cmd_register(&commands[index]),
|
||||
"rs232_test",
|
||||
"Register console command");
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "esp_err.h"
|
||||
|
||||
/* Configure all MAX3243 logic-side signals in their safe static-test state. */
|
||||
esp_err_t rs232_hw_test_init(void);
|
||||
|
||||
/* Register the Phase 0 hardware-characterization commands with esp_console. */
|
||||
esp_err_t rs232_hw_test_register_console_commands(void);
|
||||
@@ -0,0 +1,78 @@
|
||||
#include "status_led.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "board_pins.h"
|
||||
#include "led_strip.h"
|
||||
#include "led_strip_rmt.h"
|
||||
|
||||
#define RGB_LED_COUNT 1
|
||||
#define RGB_LED_BRIGHTNESS 32
|
||||
|
||||
static led_strip_handle_t s_strip;
|
||||
|
||||
esp_err_t status_led_init(void)
|
||||
{
|
||||
const led_strip_config_t strip_config = {
|
||||
.strip_gpio_num = BOARD_RGB_LED_GPIO,
|
||||
.max_leds = RGB_LED_COUNT,
|
||||
.led_model = LED_MODEL_WS2812,
|
||||
.color_component_format = LED_STRIP_COLOR_COMPONENT_FMT_GRB,
|
||||
.flags = {
|
||||
.invert_out = false,
|
||||
},
|
||||
};
|
||||
|
||||
const led_strip_rmt_config_t rmt_config = {
|
||||
.clk_src = RMT_CLK_SRC_DEFAULT,
|
||||
.resolution_hz = 10 * 1000 * 1000,
|
||||
.mem_block_symbols = 0,
|
||||
.flags = {
|
||||
.with_dma = false,
|
||||
},
|
||||
};
|
||||
|
||||
esp_err_t err = led_strip_new_rmt_device(&strip_config, &rmt_config, &s_strip);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return status_led_set(STATUS_LED_IDLE);
|
||||
}
|
||||
|
||||
esp_err_t status_led_set(status_led_state_t state)
|
||||
{
|
||||
uint8_t red = 0;
|
||||
uint8_t green = 0;
|
||||
uint8_t blue = 0;
|
||||
|
||||
if (s_strip == NULL) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case STATUS_LED_IDLE:
|
||||
blue = RGB_LED_BRIGHTNESS;
|
||||
break;
|
||||
case STATUS_LED_RUNNING:
|
||||
red = RGB_LED_BRIGHTNESS;
|
||||
green = RGB_LED_BRIGHTNESS / 2;
|
||||
break;
|
||||
case STATUS_LED_PASS:
|
||||
green = RGB_LED_BRIGHTNESS;
|
||||
break;
|
||||
case STATUS_LED_FAIL:
|
||||
red = RGB_LED_BRIGHTNESS;
|
||||
break;
|
||||
default:
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_err_t err = led_strip_set_pixel(s_strip, 0, red, green, blue);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return led_strip_refresh(s_strip);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "esp_err.h"
|
||||
|
||||
typedef enum {
|
||||
STATUS_LED_IDLE,
|
||||
STATUS_LED_RUNNING,
|
||||
STATUS_LED_PASS,
|
||||
STATUS_LED_FAIL,
|
||||
} status_led_state_t;
|
||||
|
||||
esp_err_t status_led_init(void);
|
||||
esp_err_t status_led_set(status_led_state_t state);
|
||||
Reference in New Issue
Block a user