You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
wwcs-1314/src/serial.cpp

379 lines
13 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include <algorithm>
#if !defined(_WIN32) && !defined(__OpenBSD__) && !defined(__FreeBSD__)
#include <alloca.h>
#endif
#include "serial/serial.h"
#include "serial/impl/unix.h"
using std::invalid_argument;
using std::min;
using std::numeric_limits;
using std::size_t;
using std::string;
using std::vector;
using serial::bytesize_t;
using serial::flowcontrol_t;
using serial::IOException;
using serial::parity_t;
using serial::Serial;
using serial::SerialException;
using serial::stopbits_t;
class Serial::ScopedReadLock {
public:
// 构造函数,传入串行实现类指针,并获取读锁
ScopedReadLock(SerialImpl *pimpl) : pimpl_(pimpl) {
this->pimpl_->readLock();
}
// 析构函数,释放读锁
~ScopedReadLock() { this->pimpl_->readUnlock(); }
private:
// 禁用复制构造函数
ScopedReadLock(const ScopedReadLock &);
// 禁用赋值操作符
const ScopedReadLock &operator=(ScopedReadLock);
SerialImpl *pimpl_;
};
// 这是一个私有的类定义部分,可能是一个互斥锁封装类
class ScopedWriteLock {
private:
// 禁用拷贝构造函数,避免对象被误拷贝
// Disable copy constructors there
ScopedWriteLock(const ScopedWriteLock &); // 删除此函数或声明为=delete
// 禁用赋值运算符,避免对象被误赋值
const ScopedWriteLock &operator=(ScopedWriteLock); // 缺少引用符号应改为const ScopedWriteLock& operator=(const ScopedWriteLock&) = delete;
// 指向实现类的指针使用了PimplPointer to Implementation技术
SerialImpl *pimpl_;
};
// Serial类定义可能是一个串口通信类
class Serial {
public:
// 构造函数,初始化串口设置
Serial(const string &port, uint32_t baudrate, serial::Timeout timeout,
bytesize_t bytesize, parity_t parity, stopbits_t stopbits,
flowcontrol_t flowcontrol)
: pimpl_(new SerialImpl(port, baudrate, bytesize, parity, stopbits,
flowcontrol)) {
pimpl_->setTimeout(timeout); // 设置超时时间
}
// 析构函数,释放资源
~Serial() { delete pimpl_; }
// 打开串口
void open() { pimpl_->open(); }
// 关闭串口
void close() { pimpl_->close(); }
// 检查串口是否打开
bool isOpen() const { return pimpl_->isOpen(); }
// 获取串口上可用的字节数
size_t available() { return pimpl_->available(); }
// 等待串口可读
bool waitReadable() {
serial::Timeout timeout(pimpl_->getTimeout());
return pimpl_->waitReadable(timeout.read_timeout_constant);
}
// 等待特定数量的字节时间(可能是为了同步)
void waitByteTimes(size_t count) { pimpl_->waitByteTimes(count); }
// 从串口读取数据(无锁)
size_t read_(uint8_t *buffer, size_t size) {
return this->pimpl_->read(buffer, size);
}
// 从串口读取数据使用ScopedReadLock加锁
size_t read(uint8_t *buffer, size_t size) {
ScopedReadLock lock(this->pimpl_); // 假设ScopedReadLock是一个读取锁类
return this->pimpl_->read(buffer, size);
}
private:
// 指向实现类的指针使用了PimplPointer to Implementation技术
SerialImpl *pimpl_;
};
size_t Serial::read(std::vector<uint8_t> &buffer, size_t size) {
// 创建一个读锁,保证读操作的安全性
ScopedReadLock lock(this->pimpl_);
// 分配一个新的缓冲区来存储读取的数据
uint8_t *buffer_ = new uint8_t[size];
// 初始化已读取的字节数为0
size_t bytes_read = 0;
try {
// 尝试从串行端口读取数据到缓冲区
bytes_read = this->pimpl_->read(buffer_, size);
} catch (const std::exception &e) {
// 如果读取过程中发生异常,删除缓冲区并重新抛出异常
delete[] buffer_;
throw;
}
// 将读取的数据插入到传入的vector中
buffer.insert(buffer.end(), buffer_, buffer_ + bytes_read);
// 删除临时缓冲区
delete[] buffer_;
// 返回实际读取的字节数
return bytes_read;
}
size_t Serial::read(std::string &buffer, size_t size) {
// 创建一个读锁,保证读操作的安全性
ScopedReadLock lock(this->pimpl_);
// 分配一个新的缓冲区来存储读取的数据
uint8_t *buffer_ = new uint8_t[size];
// 初始化已读取的字节数为0
size_t bytes_read = 0;
try {
// 尝试从串行端口读取数据到缓冲区
bytes_read = this->pimpl_->read(buffer_, size);
} catch (const std::exception &e) {
// 如果读取过程中发生异常,删除缓冲区并重新抛出异常
delete[] buffer_;
throw;
}
// 将读取的数据追加到传入的string中
buffer.append(reinterpret_cast<const char *>(buffer_), bytes_read);
// 删除临时缓冲区
delete[] buffer_;
// 返回实际读取的字节数
return bytes_read;
}
// Serial类中的成员函数用于读取指定字节数并返回字符串
string Serial::read(size_t size) {
std::string buffer; // 创建一个字符串用于存储读取的数据
buffer.resize(size); // 预分配足够的存储空间
this->read(&buffer[0], size); // 调用重载的read函数将读取的数据填充到buffer中
return buffer; // 返回读取到的字符串
}
// Serial类中的成员函数用于读取一行数据并返回字符串
size_t Serial::readline(string &buffer, size_t size, string eol) {
ScopedReadLock lock(this->pimpl_); // 使用ScopedReadLock对读取操作进行加锁
size_t eol_len = eol.length(); // 获取行结束符的长度
// 使用alloca函数在栈上动态分配足够大小的字节数组来存储读取的数据
// 注意alloca函数不是C++标准库的一部分,并且在某些平台上可能不被支持或存在安全问题
// 在实践中更推荐使用std::vector<uint8_t>或std::array<uint8_t, N>来替代
uint8_t *buffer_ = static_cast<uint8_t *>(alloca(size * sizeof(uint8_t)));
size_t read_so_far = 0; // 记录已经读取的字节数
while (true) {
// 尝试读取一个字节
size_t bytes_read = this->read_(buffer_ + read_so_far, 1);
read_so_far += bytes_read;
// 如果没有读取到任何数据(可能是超时),则退出循环
if (bytes_read == 0) {
break; // 读取1字节时发生超时
}
// 如果已经读取的字节数还不足以构成一个完整的行结束符,则继续读取
if (read_so_far < eol_len)
continue;
// 检查当前读取到的数据是否包含行结束符
if (string(reinterpret_cast<const char *>(buffer_ + read_so_far - eol_len),
eol_len) == eol) {
break; // 找到行结束符
}
// 如果已经读取了最大字节数,则退出循环
if (read_so_far == size) {
break; // 达到最大读取长度
}
}
// 将读取到的数据转换为字符串并追加到传入的buffer中
buffer.append(reinterpret_cast<const char *>(buffer_), read_so_far);
// 返回实际读取的字节数
return read_so_far;
}
// Serial类中的成员函数读取一行数据并返回字符串使用临时字符串对象
string Serial::readline(size_t size, string eol) {
std::string buffer; // 创建一个临时字符串对象
this->readline(buffer, size, eol); // 调用重载的readline函数
return buffer; // 返回读取到的字符串
}
// 中文注释:
// Serial::read函数
// 读取指定字节数的数据,并将数据转换为字符串返回。
//
// Serial::readline函数带引用参数
// 读取一行数据,直到遇到指定的行结束符或者读取了指定数量的字节或者发生超时。
// 读取到的数据会被追加到传入的字符串buffer中并返回实际读取的字节数。
// 该函数使用ScopedReadLock进行加锁操作以确保在多线程环境中线程安全。
//
// Serial::readline函数返回字符串
// 与带引用参数的readline函数功能相同但返回的是一个新创建的字符串对象。
// 内部使用了一个临时字符串对象来存储读取到的数据。
// Serial类中的成员函数用于从串口读取多行数据并返回一个string向量
vector<string> Serial::readlines(size_t size, string eol) {
ScopedReadLock lock(this->pimpl_); // 使用ScopedReadLock对读取操作进行加锁
std::vector<std::string> lines; // 创建一个字符串向量来存储读取到的多行数据
size_t eol_len = eol.length(); // 获取行结束符的长度
// 注意虽然这里使用了alloca来分配内存但在C++中更推荐使用std::vector或std::array
// 这里为了保持与原始代码的一致性仍然使用alloca
uint8_t *buffer_ = static_cast<uint8_t *>(alloca(size * sizeof(uint8_t)));
size_t read_so_far = 0; // 记录已经读取的字节数
size_t start_of_line = 0; // 记录当前行的起始位置
// 循环读取数据,直到达到最大读取长度或发生超时
while (read_so_far < size) {
// 尝试读取一个字节
size_t bytes_read = this->read_(buffer_ + read_so_far, 1);
read_so_far += bytes_read;
// 如果读取失败(可能是超时)
if (bytes_read == 0) {
// 如果当前行有数据即start_of_line不等于当前位置则添加到lines中
if (start_of_line != read_so_far) {
lines.push_back(
string(reinterpret_cast<const char *>(buffer_ + start_of_line),
read_so_far - start_of_line));
}
break; // 读取1字节时发生超时退出循环
}
// 如果当前读取的字节数还不足以构成一个完整的行结束符,则继续读取
if (read_so_far < eol_len)
continue;
// 检查当前读取到的数据是否包含行结束符
if (string(reinterpret_cast<const char *>(buffer_ + read_so_far - eol_len),
eol_len) == eol) {
// 发现行结束符将当前行添加到lines中
lines.push_back(
string(reinterpret_cast<const char *>(buffer_ + start_of_line),
read_so_far - eol_len));
// 更新当前行的起始位置为行结束符之后
start_of_line = read_so_far;
}
// 如果已经读取了最大字节数,则退出循环
if (read_so_far == size) {
// 如果当前行有数据即start_of_line不等于当前位置则添加到lines中
if (start_of_line != read_so_far) {
lines.push_back(
string(reinterpret_cast<const char *>(buffer_ + start_of_line),
read_so_far - start_of_line));
}
break; // 达到最大读取长度,退出循环
}
}
// 返回读取到的多行数据
return lines;
}
size_t Serial::write(const string &data) {
ScopedWriteLock lock(this->pimpl_);
return this->write_(reinterpret_cast<const uint8_t *>(data.c_str()),
data.length());
}
size_t Serial::write(const std::vector<uint8_t> &data) {
ScopedWriteLock lock(this->pimpl_);
return this->write_(&data[0], data.size());
}
size_t Serial::write(const uint8_t *data, size_t size) {
ScopedWriteLock lock(this->pimpl_);
return this->write_(data, size);
}
size_t Serial::write_(const uint8_t *data, size_t length) {
return pimpl_->write(data, length);
}
void Serial::setPort(const string &port) {
ScopedReadLock rlock(this->pimpl_);
ScopedWriteLock wlock(this->pimpl_);
bool was_open = pimpl_->isOpen();
if (was_open)
close();
pimpl_->setPort(port);
if (was_open)
open();
}
string Serial::getPort() const { return pimpl_->getPort(); }
void Serial::setTimeout(serial::Timeout &timeout) {
pimpl_->setTimeout(timeout);
}
serial::Timeout Serial::getTimeout() const { return pimpl_->getTimeout(); }
void Serial::setBaudrate(uint32_t baudrate) { pimpl_->setBaudrate(baudrate); }
uint32_t Serial::getBaudrate() const { return uint32_t(pimpl_->getBaudrate()); }
void Serial::setBytesize(bytesize_t bytesize) { pimpl_->setBytesize(bytesize); }
bytesize_t Serial::getBytesize() const { return pimpl_->getBytesize(); }
void Serial::setParity(parity_t parity) { pimpl_->setParity(parity); }
parity_t Serial::getParity() const { return pimpl_->getParity(); }
void Serial::setStopbits(stopbits_t stopbits) { pimpl_->setStopbits(stopbits); }
stopbits_t Serial::getStopbits() const { return pimpl_->getStopbits(); }
void Serial::setFlowcontrol(flowcontrol_t flowcontrol) {
pimpl_->setFlowcontrol(flowcontrol);
}
flowcontrol_t Serial::getFlowcontrol() const {
return pimpl_->getFlowcontrol();
}
void Serial::flush() {
ScopedReadLock rlock(this->pimpl_);
ScopedWriteLock wlock(this->pimpl_);
pimpl_->flush();
}
void Serial::flushInput() {
ScopedReadLock lock(this->pimpl_);
pimpl_->flushInput();
}
void Serial::flushOutput() {
ScopedWriteLock lock(this->pimpl_);
pimpl_->flushOutput();
}
void Serial::sendBreak(int duration) { pimpl_->sendBreak(duration); }
void Serial::setBreak(bool level) { pimpl_->setBreak(level); }
void Serial::setRTS(bool level) { pimpl_->setRTS(level); }
void Serial::setDTR(bool level) { pimpl_->setDTR(level); }
bool Serial::waitForChange() { return pimpl_->waitForChange(); }
bool Serial::getCTS() { return pimpl_->getCTS(); }
bool Serial::getDSR() { return pimpl_->getDSR(); }
bool Serial::getRI() { return pimpl_->getRI(); }
bool Serial::getCD() { return pimpl_->getCD(); }