SerialOpr/libserial/serial.cpp

251 lines
6.8 KiB
C++

#include "serial.h"
#include <asio.hpp>
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<int>(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<int>(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