#include "serial.h" #include namespace cppbox { using serial_port = asio::serial_port; class CSerialOprImp { public: CSerialOprImp() : timer_(io_), baud_rate_(serial_port::baud_rate(19200)), stop_bits_(serial_port::stop_bits::one), parity_(serial_port::parity::none), flow_control_(serial_port::flow_control::none) { port_ = new serial_port(io_); error_ = new char[1024]; std::memset(error_, 0x0, 1024); } ~CSerialOprImp() { close(); delete port_; delete[] error_; } public: void set_port(const char* port) { std::memset(port_name_, 0x0, sizeof(port_name_)); std::snprintf(port_name_, sizeof(port_name_), "%s", port); } int open() { port_->open(port_name_, ec_); if (!port_->is_open()) { std::memset(error_, 0x0, 1024); std::snprintf(error_, 1024, "%s", ec_.message().c_str()); return ec_.value(); } port_->set_option(baud_rate_, ec_); port_->set_option(flow_control_, ec_); port_->set_option(parity_, ec_); port_->set_option(stop_bits_, ec_); port_->set_option(character_size_, ec_); return 0; } void close() { if (port_->is_open()) { port_->close(); } } int write(const char* data, int len) { bytes_transferred_ = 0; io_.reset(); asio::error_code write_ec; std::size_t ret = asio::write(*port_, asio::buffer(data, len), write_ec); int send_size = static_cast(ret); return send_size; } int read(char* data) { bytes_transferred_ = 0; io_.reset(); timer_.expires_from_now(asio::chrono::milliseconds(time_out_)); timer_.async_wait(std::bind(&CSerialOprImp::time_out, this, asio::placeholders::error)); port_->async_read_some( asio::buffer(buffer_), std::bind(&CSerialOprImp::handle_read, this, asio::placeholders::error, asio::placeholders::bytes_transferred)); io_.run(); if (bytes_transferred_ > 0) { std::memcpy(data, buffer_, bytes_transferred_); data[bytes_transferred_] = '\0'; } return bytes_transferred_; } const char* get_last_error() const { return error_; } void set_timeout(uint64_t timeout) { time_out_ = timeout; } void set_baudrate(uint32_t baudrate) { baud_rate_ = serial_port::baud_rate(baudrate); } void set_databits(serial_port::character_size size) { character_size_ = size; } void set_parity(serial_port::parity parity) { parity_ = parity; } void set_stopbits(serial_port::stop_bits stop_bits) { stop_bits_ = stop_bits; } void set_flow_control(serial_port::flow_control flow_control) { flow_control_ = flow_control; } private: void time_out(const asio::error_code& code) { if (code) { return; } bytes_transferred_ = -1; port_->cancel(); } void handle_read(const asio::error_code& error, std::size_t bytes_transferred) { if (!error) { bytes_transferred_ = static_cast(bytes_transferred); timer_.cancel(); } } private: char port_name_[128]{}; serial_port::baud_rate baud_rate_; serial_port::character_size character_size_{8}; serial_port::stop_bits stop_bits_; serial_port::parity parity_; uint64_t time_out_{1000}; serial_port::flow_control flow_control_; private: int bytes_transferred_{}; asio::io_context io_{}; asio::serial_port* port_{}; asio::error_code ec_{}; char buffer_[512]{}; asio::steady_timer timer_; char* error_{}; }; CSerialOpr::CSerialOpr() { imp_ = new CSerialOprImp(); } CSerialOpr::~CSerialOpr() { delete imp_; } void CSerialOpr::set_port(const char* port) { imp_->set_port(port); } void CSerialOpr::set_baudrate(uint32_t baudrate) { imp_->set_baudrate(baudrate); } void CSerialOpr::set_data_bits(DataBits data_bits) { switch (data_bits) { case D5: imp_->set_databits(serial_port::character_size(5)); break; case D6: imp_->set_databits(serial_port::character_size(6)); break; case D7: imp_->set_databits(serial_port::character_size(7)); break; case D8: imp_->set_databits(serial_port::character_size(8)); break; default: imp_->set_databits(serial_port::character_size(5)); break; } } void CSerialOpr::set_stop_bits(StopBits stop_bits) { switch (stop_bits) { case OneStop: imp_->set_stopbits(serial_port::stop_bits(serial_port::stop_bits::one)); break; case OneAndHalfStop: imp_->set_stopbits(serial_port::stop_bits(serial_port::stop_bits::onepointfive)); break; case TwoStop: imp_->set_stopbits(serial_port::stop_bits(serial_port::stop_bits::two)); break; default: imp_->set_stopbits(serial_port::stop_bits(serial_port::stop_bits::one)); break; } } void CSerialOpr::set_parity(Parity parity) { switch (parity) { case EvenParity: imp_->set_parity(serial_port::parity(serial_port::parity::even)); break; case OddParity: imp_->set_parity(serial_port::parity(serial_port::parity::odd)); break; default: imp_->set_parity(serial_port::parity(serial_port::parity::none)); break; } } void CSerialOpr::set_flow_control(FlowControl flow_control) { switch (flow_control) { case NoFlowControl: imp_->set_flow_control(serial_port::flow_control(serial_port::flow_control::none)); break; case HardwareControl: imp_->set_flow_control(serial_port::flow_control(serial_port::flow_control::hardware)); break; case SoftwareControl: imp_->set_flow_control(serial_port::flow_control(serial_port::flow_control::software)); break; default: imp_->set_flow_control(serial_port::flow_control(serial_port::flow_control::none)); break; } } void CSerialOpr::set_timeout(uint64_t timeout) { imp_->set_timeout(timeout); } int CSerialOpr::open() { return imp_->open(); } void CSerialOpr::close() { imp_->close(); } int CSerialOpr::read(char* data) { return imp_->read(data); } int CSerialOpr::write(const char* data, int len) { return imp_->write(data, len); } const char* CSerialOpr::get_last_error() const { return imp_->get_last_error(); } } // namespace cppbox