251 lines
6.8 KiB
C++
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
|