arduino Serial is not thread safe

This commit is contained in:
folkert van heusden 2024-05-09 22:03:46 +02:00
parent 13c71164e8
commit 6cc093fea2
Signed by untrusted user who does not match committer: folkert
GPG key ID: 6B6455EDFEED3BD1
4 changed files with 53 additions and 71 deletions

View file

@ -53,12 +53,6 @@
constexpr const char SERIAL_CFG_FILE[] = "/serial.json"; constexpr const char SERIAL_CFG_FILE[] = "/serial.json";
#if defined(BUILD_FOR_RP2040)
#define Serial_RS232 Serial1
#elif defined(TTY_SERIAL_RX)
HardwareSerial Serial_RS232(2);
#endif
bus *b = nullptr; bus *b = nullptr;
cpu *c = nullptr; cpu *c = nullptr;
tty *tty_ = nullptr; tty *tty_ = nullptr;
@ -78,7 +72,7 @@ bool trace_output { false };
ntp *ntp_ { nullptr }; ntp *ntp_ { nullptr };
void console_thread_wrapper_panel(void *const c) static void console_thread_wrapper_panel(void *const c)
{ {
console *const cnsl = reinterpret_cast<console *>(c); console *const cnsl = reinterpret_cast<console *>(c);
@ -213,17 +207,12 @@ void start_network(console *const c)
dc11 *dc11_ = new dc11(1100, b); dc11 *dc11_ = new dc11(1100, b);
#if !defined(BUILD_FOR_RP2040) && defined(TTY_SERIAL_RX) #if !defined(BUILD_FOR_RP2040) && defined(TTY_SERIAL_RX)
constexpr uint32_t hwSerialConfig = SERIAL_8N1; uint32_t bitrate = load_serial_speed_configuration();
uint32_t bitrate = load_serial_speed_configuration();
Serial.printf("* Init TTY (on DC11), baudrate: %d bps, RX: %d, TX: %d", bitrate, TTY_SERIAL_RX, TTY_SERIAL_TX); Serial.printf("* Init TTY (on DC11), baudrate: %d bps, RX: %d, TX: %d", bitrate, TTY_SERIAL_RX, TTY_SERIAL_TX);
Serial.println(F("")); Serial.println(F(""));
Serial_RS232.begin(bitrate, hwSerialConfig, TTY_SERIAL_RX, TTY_SERIAL_TX); dc11_->set_serial(bitrate, TTY_SERIAL_RX, TTY_SERIAL_TX);
Serial_RS232.setHwFlowCtrlMode(0);
Serial_RS232.println(F("Go!"));
dc11_->set_serial(&Serial_RS232);
#endif #endif
b->add_DC11(dc11_); b->add_DC11(dc11_);
@ -244,16 +233,6 @@ void recall_configuration(console *const cnsl)
} }
#endif #endif
#if defined(TTY_SERIAL_RX)
void set_tty_serial_speed(console *const c, const uint32_t bps)
{
Serial_RS232.begin(bps);
if (save_serial_speed_configuration(bps) == false)
c->put_string_lf("Failed to store configuration file with serial settings");
}
#endif
#if defined(ESP32) #if defined(ESP32)
void heap_caps_alloc_failed_hook(size_t requested_size, uint32_t caps, const char *function_name) void heap_caps_alloc_failed_hook(size_t requested_size, uint32_t caps, const char *function_name)
{ {

View file

@ -8,6 +8,7 @@
#include <lwip/sockets.h> #include <lwip/sockets.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <driver/uart.h>
#elif defined(_WIN32) #elif defined(_WIN32)
#include <ws2tcpip.h> #include <ws2tcpip.h>
#include <winsock2.h> #include <winsock2.h>
@ -26,6 +27,8 @@
#include "utils.h" #include "utils.h"
#define ESP32_UART UART_NUM_1
const char *const dc11_register_names[] { "RCSR", "RBUF", "TSCR", "TBUF" }; const char *const dc11_register_names[] { "RCSR", "RBUF", "TSCR", "TBUF" };
bool setup_telnet_session(const int fd) bool setup_telnet_session(const int fd)
@ -89,10 +92,7 @@ dc11::~dc11()
delete [] pfds; delete [] pfds;
#if defined(ESP32) #if defined(ESP32)
if (serial_th) { // won't work due to freertos thread
serial_th->join();
delete serial_th;
}
#endif #endif
} }
@ -241,18 +241,47 @@ void dc11::operator()()
} }
#if defined(ESP32) #if defined(ESP32)
void dc11::set_serial(Stream *const s) void dc11_thread_wrapper_serial_handler(void *const c)
{ {
if (serial_th) { dc11 *const d = reinterpret_cast<dc11 *>(c);
d->serial_handler();
vTaskSuspend(nullptr);
}
void dc11::set_serial(const int bitrate, const int rx, const int tx)
{
if (serial_thread_running) {
DOLOG(info, true, "DC11: serial port already configured"); DOLOG(info, true, "DC11: serial port already configured");
return; return;
} }
std::unique_lock<std::mutex> lck(s_lock); serial_thread_running = true;
this->s = s;
s->write("Press enter to connect");
serial_th = new std::thread(&dc11::serial_handler, this); // Configure UART parameters
static uart_config_t uart_config = {
.baud_rate = bitrate,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.rx_flow_ctrl_thresh = 122,
};
ESP_ERROR_CHECK(uart_param_config(ESP32_UART, &uart_config));
ESP_ERROR_CHECK(uart_set_pin(ESP32_UART, tx, rx, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
// Setup UART buffered IO with event queue
const int uart_buffer_size = 1024 * 2;
static QueueHandle_t uart_queue;
// Install UART driver using an event queue here
ESP_ERROR_CHECK(uart_driver_install(ESP32_UART, uart_buffer_size, uart_buffer_size, 10, &uart_queue, 0));
const char msg[] = "Press enter to connect\r\n";
uart_write_bytes(ESP32_UART, msg, sizeof(msg) - 1);
xTaskCreate(&dc11_thread_wrapper_serial_handler, "dc11_tty", 3072, this, 1, nullptr);
} }
void dc11::serial_handler() void dc11::serial_handler()
@ -260,15 +289,14 @@ void dc11::serial_handler()
while(!stop_flag) { while(!stop_flag) {
yield(); yield();
size_t n_available = 0;
ESP_ERROR_CHECK(uart_get_buffered_data_len(ESP32_UART, &n_available));
if (n_available == 0)
continue;
char c = 0; char c = 0;
if (uart_read_bytes(ESP32_UART, &c, 1, 100) == 0)
{ continue;
std::unique_lock<std::mutex> lck(s_lock);
if (s->available() == 0)
continue;
c = s->read();
}
// 3 is reserved for a serial port // 3 is reserved for a serial port
constexpr const int serial_line = 3; constexpr const int serial_line = 3;
@ -416,11 +444,8 @@ void dc11::write_word(const uint16_t addr, const uint16_t v)
#if defined(ESP32) #if defined(ESP32)
if (line_nr == 3) { if (line_nr == 3) {
if (s != nullptr) { if (serial_thread_running)
std::unique_lock<std::mutex> lck(s_lock); uart_write_bytes(ESP32_UART, &c, 1);
s->write(c);
}
if (is_tx_interrupt_enabled(line_nr)) if (is_tx_interrupt_enabled(line_nr))
trigger_interrupt(line_nr, true); trigger_interrupt(line_nr, true);

6
dc11.h
View file

@ -49,9 +49,7 @@ private:
std::vector<char> recv_buffers[dc11_n_lines]; std::vector<char> recv_buffers[dc11_n_lines];
std::mutex input_lock[dc11_n_lines]; std::mutex input_lock[dc11_n_lines];
#if defined(ESP32) #if defined(ESP32)
std::mutex s_lock; std::atomic_bool serial_thread_running { false };
Stream *s { nullptr };
std::thread *serial_th { nullptr };
bool serial_enabled { false }; bool serial_enabled { false };
#endif #endif
@ -70,7 +68,7 @@ public:
void reset(); void reset();
#if defined(ESP32) #if defined(ESP32)
void set_serial(Stream *const s); void set_serial(const int bitrate, const int rx, const int tx);
void serial_handler(); void serial_handler();
#endif #endif

View file

@ -43,8 +43,6 @@
void configure_network(console *const cnsl); void configure_network(console *const cnsl);
void check_network(console *const cnsl); void check_network(console *const cnsl);
void start_network(console *const cnsl); void start_network(console *const cnsl);
void set_tty_serial_speed(console *const c, const uint32_t bps);
#endif #endif
#if !defined(BUILD_FOR_RP2040) && !defined(linux) && !defined(_WIN32) #if !defined(BUILD_FOR_RP2040) && !defined(linux) && !defined(_WIN32)
@ -891,21 +889,6 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
continue; continue;
} }
#if defined(CONSOLE_SERIAL_RX)
else if (parts.at(0) == "serspd") {
if (parts.size() == 2) {
uint32_t speed = std::stoi(parts.at(1), nullptr, 10);
set_tty_serial_speed(cnsl, speed);
cnsl->put_string_lf(format("Set baudrate to %d", speed));
}
else {
cnsl->put_string_lf("serspd requires an (decimal) parameter");
}
continue;
}
#endif
#endif #endif
else if (cmd == "stats") { else if (cmd == "stats") {
show_run_statistics(cnsl, c); show_run_statistics(cnsl, c);
@ -1112,9 +1095,6 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
"cfgnet - configure network (e.g. WiFi)", "cfgnet - configure network (e.g. WiFi)",
"startnet - start network", "startnet - start network",
"chknet - check network status", "chknet - check network status",
#if defined(CONSOLE_SERIAL_RX)
"serspd x - set serial speed in bps (8N1 are default)",
#endif
#endif #endif
"cfgdisk - configure disk", "cfgdisk - configure disk",
"log ... - log a message to the logfile", "log ... - log a message to the logfile",