From e35b08711470ecd99bbf260336fd6583c02006de Mon Sep 17 00:00:00 2001 From: Neucrack Date: Thu, 1 Aug 2024 19:28:22 +0800 Subject: [PATCH] uart support set_received_callback function --- components/peripheral/include/maix_uart.hpp | 14 ++++ .../peripheral/port/linux/maix_uart.cpp | 78 ++++++++++++++++++- .../peripheral/port/maixcam/maix_uart.cpp | 78 ++++++++++++++++++- 3 files changed, 162 insertions(+), 8 deletions(-) diff --git a/components/peripheral/include/maix_uart.hpp b/components/peripheral/include/maix_uart.hpp index b5b8421f..a876ec80 100755 --- a/components/peripheral/include/maix_uart.hpp +++ b/components/peripheral/include/maix_uart.hpp @@ -10,6 +10,8 @@ #include "stdint.h" #include "maix_comm_base.hpp" #include "maix_type.hpp" +#include "maix_thread.hpp" +#include /** * @brief maix uart peripheral driver @@ -150,6 +152,13 @@ namespace maix::peripheral::uart */ err::Err close(); + /** + * Set received callback function + * @param callback function to call when received data + * @maixpy maix.peripheral.uart.UART.set_received_callback + */ + void set_received_callback(std::function callback); + /** * Send data to device * @param buff data buffer @@ -233,6 +242,7 @@ namespace maix::peripheral::uart * >0 means block until read len data or timeout. * @return received data, bytes type. * Attention, you need to delete the returned object yourself in C++. + * @throw Read failed will raise err.Exception error. * @maixpy maix.peripheral.uart.UART.read */ Bytes *read(int len = -1, int timeout = 0); @@ -256,6 +266,10 @@ namespace maix::peripheral::uart uart::STOP _stopbits; uart::FLOW_CTRL _flow_ctrl; int _one_byte_time_us; + std::function callback; + thread::Thread *_read_thread; + bool _read_thread_need_exit; + bool _read_thread_exit; }; }; // namespace maix.peripheral.uart diff --git a/components/peripheral/port/linux/maix_uart.cpp b/components/peripheral/port/linux/maix_uart.cpp index cbe653aa..644a5d4b 100755 --- a/components/peripheral/port/linux/maix_uart.cpp +++ b/components/peripheral/port/linux/maix_uart.cpp @@ -9,6 +9,8 @@ #include "maix_log.hpp" #include "maix_time.hpp" #include "maix_fs.hpp" +#include "maix_thread.hpp" +#include "maix_app.hpp" #include #include #include @@ -206,7 +208,18 @@ namespace maix::peripheral::uart static int _uart_write(int fd, const void *buff, int len) { - return write(fd, buff, len); + ssize_t bytes_written = write(fd, buff, len); + if (bytes_written < 0) { + log::error("uart write failed: %d", bytes_written); + return bytes_written; + } + + // wait for data transmit completion + // if (tcdrain(fd) != 0) { + // log::error("uart wait write failed: %d", bytes_written); + // return -1; + // } + return bytes_written; } UART::UART(const std::string &port, int baudrate, uart::BITS databits, @@ -220,6 +233,7 @@ namespace maix::peripheral::uart _parity = parity; _stopbits = stopbits; _flow_ctrl = flow_ctrl; + _read_thread = nullptr; if (!port.empty()) { err::Err e = this->open(); @@ -267,7 +281,25 @@ namespace maix::peripheral::uart { if (_fd <= 0) return err::ERR_NONE; - if (0 < _uart_deinit(_fd)) + int ret = _uart_deinit(_fd); + _fd = -1; + if(_read_thread) + { + _read_thread_need_exit = true; + uint64_t t = time::ticks_ms(); + while(!_read_thread_exit) + { + time::sleep_ms(10); + if(time::ticks_ms() - t > 5000) + { + log::error("waiting uart read thread exit"); + t = time::ticks_ms(); + } + } + delete _read_thread; + _read_thread = nullptr; + } + if (ret != 0) { log::error("uart close failed\r\n"); return err::ERR_IO; @@ -275,6 +307,41 @@ namespace maix::peripheral::uart return err::ERR_NONE; } + void UART::set_received_callback(std::function callback) + { + if(!_read_thread) + { + _read_thread_need_exit = false; + _read_thread_exit = false; + _read_thread = new thread::Thread([callback](void *args){ + UART *uart = (UART*)args; + while(!app::need_exit() && !uart->_read_thread_need_exit) + { + Bytes *data = NULL; + try + { + data = uart->read(-1, -1); + } + catch(err::Exception) + { + log::error("read file failed"); + break; + } + if(!data) + { + log::error("uart read data is null"); + break; + } + callback(*uart, *data); + delete data; + } + uart->_read_thread_exit = true; + }, this); + _read_thread->detach(); + } + this->callback = callback; + } + int UART::write(const uint8_t *buff, int len) { if (!is_open()) @@ -413,7 +480,7 @@ namespace maix::peripheral::uart { int wait_time = _one_byte_time_us * 30; // system maybe use some time time::sleep_us(wait_time > 50000 ? 50000: wait_time); - if (available(0) > 0) + if (available(0) > 0 || (timeout < 0 && read_len == 0)) continue; break; } @@ -463,7 +530,10 @@ namespace maix::peripheral::uart break; read_len = read(data->data + received, buff_len - received, len > 0 ? len - received : len, timeout > 0 ? t2 : timeout); if (read_len < 0) - read_len = 0; + { + delete data; + throw err::Exception(err::Err(-read_len), "read failed"); + } received += read_len; data->data_len = received; if(len > 0 && received == len) diff --git a/components/peripheral/port/maixcam/maix_uart.cpp b/components/peripheral/port/maixcam/maix_uart.cpp index cbe653aa..644a5d4b 100755 --- a/components/peripheral/port/maixcam/maix_uart.cpp +++ b/components/peripheral/port/maixcam/maix_uart.cpp @@ -9,6 +9,8 @@ #include "maix_log.hpp" #include "maix_time.hpp" #include "maix_fs.hpp" +#include "maix_thread.hpp" +#include "maix_app.hpp" #include #include #include @@ -206,7 +208,18 @@ namespace maix::peripheral::uart static int _uart_write(int fd, const void *buff, int len) { - return write(fd, buff, len); + ssize_t bytes_written = write(fd, buff, len); + if (bytes_written < 0) { + log::error("uart write failed: %d", bytes_written); + return bytes_written; + } + + // wait for data transmit completion + // if (tcdrain(fd) != 0) { + // log::error("uart wait write failed: %d", bytes_written); + // return -1; + // } + return bytes_written; } UART::UART(const std::string &port, int baudrate, uart::BITS databits, @@ -220,6 +233,7 @@ namespace maix::peripheral::uart _parity = parity; _stopbits = stopbits; _flow_ctrl = flow_ctrl; + _read_thread = nullptr; if (!port.empty()) { err::Err e = this->open(); @@ -267,7 +281,25 @@ namespace maix::peripheral::uart { if (_fd <= 0) return err::ERR_NONE; - if (0 < _uart_deinit(_fd)) + int ret = _uart_deinit(_fd); + _fd = -1; + if(_read_thread) + { + _read_thread_need_exit = true; + uint64_t t = time::ticks_ms(); + while(!_read_thread_exit) + { + time::sleep_ms(10); + if(time::ticks_ms() - t > 5000) + { + log::error("waiting uart read thread exit"); + t = time::ticks_ms(); + } + } + delete _read_thread; + _read_thread = nullptr; + } + if (ret != 0) { log::error("uart close failed\r\n"); return err::ERR_IO; @@ -275,6 +307,41 @@ namespace maix::peripheral::uart return err::ERR_NONE; } + void UART::set_received_callback(std::function callback) + { + if(!_read_thread) + { + _read_thread_need_exit = false; + _read_thread_exit = false; + _read_thread = new thread::Thread([callback](void *args){ + UART *uart = (UART*)args; + while(!app::need_exit() && !uart->_read_thread_need_exit) + { + Bytes *data = NULL; + try + { + data = uart->read(-1, -1); + } + catch(err::Exception) + { + log::error("read file failed"); + break; + } + if(!data) + { + log::error("uart read data is null"); + break; + } + callback(*uart, *data); + delete data; + } + uart->_read_thread_exit = true; + }, this); + _read_thread->detach(); + } + this->callback = callback; + } + int UART::write(const uint8_t *buff, int len) { if (!is_open()) @@ -413,7 +480,7 @@ namespace maix::peripheral::uart { int wait_time = _one_byte_time_us * 30; // system maybe use some time time::sleep_us(wait_time > 50000 ? 50000: wait_time); - if (available(0) > 0) + if (available(0) > 0 || (timeout < 0 && read_len == 0)) continue; break; } @@ -463,7 +530,10 @@ namespace maix::peripheral::uart break; read_len = read(data->data + received, buff_len - received, len > 0 ? len - received : len, timeout > 0 ? t2 : timeout); if (read_len < 0) - read_len = 0; + { + delete data; + throw err::Exception(err::Err(-read_len), "read failed"); + } received += read_len; data->data_len = received; if(len > 0 && received == len)