|
|
|
@ -25,173 +25,258 @@ using serial::stopbits_t;
|
|
|
|
|
|
|
|
|
|
class Serial::ScopedReadLock {
|
|
|
|
|
public:
|
|
|
|
|
// 构造函数,传入串行实现类指针,并获取读锁
|
|
|
|
|
ScopedReadLock(SerialImpl *pimpl) : pimpl_(pimpl) {
|
|
|
|
|
this->pimpl_->readLock();
|
|
|
|
|
}
|
|
|
|
|
// 析构函数,释放读锁
|
|
|
|
|
~ScopedReadLock() { this->pimpl_->readUnlock(); }
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
// Disable copy constructors
|
|
|
|
|
// 禁用复制构造函数
|
|
|
|
|
ScopedReadLock(const ScopedReadLock &);
|
|
|
|
|
// 禁用赋值操作符
|
|
|
|
|
const ScopedReadLock &operator=(ScopedReadLock);
|
|
|
|
|
|
|
|
|
|
SerialImpl *pimpl_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class Serial::ScopedWriteLock {
|
|
|
|
|
public:
|
|
|
|
|
ScopedWriteLock(SerialImpl *pimpl) : pimpl_(pimpl) {
|
|
|
|
|
this->pimpl_->writeLock();
|
|
|
|
|
}
|
|
|
|
|
~ScopedWriteLock() { this->pimpl_->writeUnlock(); }
|
|
|
|
|
|
|
|
|
|
// 这是一个私有的类定义部分,可能是一个互斥锁封装类
|
|
|
|
|
class ScopedWriteLock {
|
|
|
|
|
private:
|
|
|
|
|
// 禁用拷贝构造函数,避免对象被误拷贝
|
|
|
|
|
// Disable copy constructors there
|
|
|
|
|
ScopedWriteLock(const ScopedWriteLock &);
|
|
|
|
|
const ScopedWriteLock &operator=(ScopedWriteLock);
|
|
|
|
|
ScopedWriteLock(const ScopedWriteLock &); // 删除此函数或声明为=delete
|
|
|
|
|
|
|
|
|
|
// 禁用赋值运算符,避免对象被误赋值
|
|
|
|
|
const ScopedWriteLock &operator=(ScopedWriteLock); // 缺少引用符号,应改为const ScopedWriteLock& operator=(const ScopedWriteLock&) = delete;
|
|
|
|
|
|
|
|
|
|
// 指向实现类的指针,使用了Pimpl(Pointer to Implementation)技术
|
|
|
|
|
SerialImpl *pimpl_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Serial::Serial(const string &port, uint32_t baudrate, serial::Timeout timeout,
|
|
|
|
|
// 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);
|
|
|
|
|
}
|
|
|
|
|
pimpl_->setTimeout(timeout); // 设置超时时间
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Serial::~Serial() { delete pimpl_; }
|
|
|
|
|
// 析构函数,释放资源
|
|
|
|
|
~Serial() { delete pimpl_; }
|
|
|
|
|
|
|
|
|
|
void Serial::open() { pimpl_->open(); }
|
|
|
|
|
// 打开串口
|
|
|
|
|
void open() { pimpl_->open(); }
|
|
|
|
|
|
|
|
|
|
void Serial::close() { pimpl_->close(); }
|
|
|
|
|
// 关闭串口
|
|
|
|
|
void close() { pimpl_->close(); }
|
|
|
|
|
|
|
|
|
|
bool Serial::isOpen() const { return pimpl_->isOpen(); }
|
|
|
|
|
// 检查串口是否打开
|
|
|
|
|
bool isOpen() const { return pimpl_->isOpen(); }
|
|
|
|
|
|
|
|
|
|
size_t Serial::available() { return pimpl_->available(); }
|
|
|
|
|
// 获取串口上可用的字节数
|
|
|
|
|
size_t available() { return pimpl_->available(); }
|
|
|
|
|
|
|
|
|
|
bool Serial::waitReadable() {
|
|
|
|
|
// 等待串口可读
|
|
|
|
|
bool waitReadable() {
|
|
|
|
|
serial::Timeout timeout(pimpl_->getTimeout());
|
|
|
|
|
return pimpl_->waitReadable(timeout.read_timeout_constant);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Serial::waitByteTimes(size_t count) { pimpl_->waitByteTimes(count); }
|
|
|
|
|
// 等待特定数量的字节时间(可能是为了同步)
|
|
|
|
|
void waitByteTimes(size_t count) { pimpl_->waitByteTimes(count); }
|
|
|
|
|
|
|
|
|
|
size_t Serial::read_(uint8_t *buffer, size_t size) {
|
|
|
|
|
// 从串口读取数据(无锁)
|
|
|
|
|
size_t read_(uint8_t *buffer, size_t size) {
|
|
|
|
|
return this->pimpl_->read(buffer, size);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t Serial::read(uint8_t *buffer, size_t size) {
|
|
|
|
|
ScopedReadLock lock(this->pimpl_);
|
|
|
|
|
// 从串口读取数据(使用ScopedReadLock加锁)
|
|
|
|
|
size_t read(uint8_t *buffer, size_t size) {
|
|
|
|
|
ScopedReadLock lock(this->pimpl_); // 假设ScopedReadLock是一个读取锁类
|
|
|
|
|
return this->pimpl_->read(buffer, size);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
// 指向实现类的指针,使用了Pimpl(Pointer 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;
|
|
|
|
|
this->read(buffer, size);
|
|
|
|
|
return buffer;
|
|
|
|
|
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_);
|
|
|
|
|
size_t eol_len = eol.length();
|
|
|
|
|
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;
|
|
|
|
|
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; // Timeout occured on reading 1 byte
|
|
|
|
|
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; // EOL found
|
|
|
|
|
break; // 找到行结束符
|
|
|
|
|
}
|
|
|
|
|
// 如果已经读取了最大字节数,则退出循环
|
|
|
|
|
if (read_so_far == size) {
|
|
|
|
|
break; // Reached the maximum read length
|
|
|
|
|
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);
|
|
|
|
|
return buffer;
|
|
|
|
|
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_);
|
|
|
|
|
std::vector<std::string> lines;
|
|
|
|
|
size_t eol_len = eol.length();
|
|
|
|
|
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;
|
|
|
|
|
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; // Timeout occured on reading 1 byte
|
|
|
|
|
break; // 读取1字节时发生超时,退出循环
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果当前读取的字节数还不足以构成一个完整的行结束符,则继续读取
|
|
|
|
|
if (read_so_far < eol_len)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// 检查当前读取到的数据是否包含行结束符
|
|
|
|
|
if (string(reinterpret_cast<const char *>(buffer_ + read_so_far - eol_len),
|
|
|
|
|
eol_len) == eol) {
|
|
|
|
|
// EOL found
|
|
|
|
|
// 发现行结束符,将当前行添加到lines中
|
|
|
|
|
lines.push_back(
|
|
|
|
|
string(reinterpret_cast<const char *>(buffer_ + start_of_line),
|
|
|
|
|
read_so_far - 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; // Reached the maximum read length
|
|
|
|
|
break; // 达到最大读取长度,退出循环
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 返回读取到的多行数据
|
|
|
|
|
return lines;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|