282 lines
8.5 KiB
C++
282 lines
8.5 KiB
C++
#include "Serial.h"
|
|
#include "Core/Statistics/Frequency_Limit.h"
|
|
#include "Serial_p.h"
|
|
#include <thread>
|
|
#include <utility>
|
|
#include <string_view>
|
|
|
|
void serial_log(Log_Type &log_type, std::string_view MSG) {
|
|
Frequency_Limit_Multi lm;
|
|
bool ok = lm.test(std::to_string(Psc::get_error_code()));
|
|
if (!ok)
|
|
return;
|
|
|
|
std::ostringstream oss;
|
|
BaseLogger::Log_Info info{true, spdlog::level::debug, "", log_type, std::string(MSG)};
|
|
oss << Psc::get_error_message()
|
|
<< BaseLogger::to_log(info)
|
|
<< std::endl;
|
|
if (!Psc::serial::serial_logger) {
|
|
std::cout << oss.str() << std::endl;
|
|
} else {
|
|
Psc::serial::serial_logger->error(" ", {}, oss.str());
|
|
}
|
|
}
|
|
namespace Psc::serial {
|
|
BaseLogger *serial_logger = nullptr;
|
|
|
|
bool Serial::open() {
|
|
fd = Psc::serial::open(serial_name);
|
|
if (fd == INVALID_HANDLE_VALUE) {
|
|
LOG_ERROR("Serial::open() 打开串口失败!");
|
|
return false;
|
|
}
|
|
serial_info = get_serial_info(fd);
|
|
set_binary_mode(serial_info);
|
|
std::ostringstream oss;
|
|
oss << "\n属性来源:\n";
|
|
if (buffer_byte_size == -1) {
|
|
buffer_byte_size = serial::get_buffer_byte_size(fd);
|
|
oss << "\t获取 buffer_byte_size: " << buffer_byte_size << std::endl;
|
|
} else {
|
|
serial::set_buffer_byte_size(fd, buffer_byte_size);
|
|
oss << "\t设置 buffer_byte_size: " << buffer_byte_size << std::endl;
|
|
}
|
|
if (baud_rate == -1) {
|
|
baud_rate = serial::get_baud_rate(serial_info);
|
|
oss << "\t获取 baud_rate: " << baud_rate << std::endl;
|
|
} else {
|
|
serial::set_baud_rate(serial_info, fd, baud_rate);
|
|
oss << "\t设置 baud_rate: " << baud_rate << std::endl;
|
|
}
|
|
if (dataBits == DataBits::UnknownDataBits) {
|
|
dataBits = serial::get_data_bits(serial_info);
|
|
oss << "\t获取 dataBits: " << Psc::to_string(dataBits) << std::endl;
|
|
} else {
|
|
serial::set_data_bits(serial_info, dataBits);
|
|
oss << "\t设置 dataBits: " << Psc::to_string(dataBits) << std::endl;
|
|
}
|
|
if (stopBits == StopBits::UnknownStopBits) {
|
|
stopBits = serial::get_stop_bits(serial_info);
|
|
oss << "\t获取 stopBits: " << Psc::to_string(stopBits) << std::endl;
|
|
} else {
|
|
serial::set_stop_bits(serial_info, stopBits);
|
|
oss << "\t设置 stopBits: " << Psc::to_string(stopBits) << std::endl;
|
|
}
|
|
if (parity == Parity::UnknownParity) {
|
|
parity = serial::get_parity(serial_info);
|
|
oss << "\t获取 parity: " << Psc::to_string(parity) << std::endl;
|
|
} else {
|
|
serial::set_parity(serial_info, parity);
|
|
oss << "\t设置 parity: " << Psc::to_string(parity) << std::endl;
|
|
}
|
|
if (flow_control == FlowControl::UnknownFlowControl) {
|
|
flow_control = serial::get_flow_control(serial_info);
|
|
oss << "\t获取 flow_control: " << Psc::to_string(flow_control) << std::endl;
|
|
} else {
|
|
serial::set_flow_control(serial_info, flow_control);
|
|
oss << "\t设置 flow_control: " << Psc::to_string(flow_control) << std::endl;
|
|
}
|
|
// oss << "最终设置: " << to_string();
|
|
// std::string s = oss.str();
|
|
// std::cout << s << std::endl;
|
|
|
|
set_block(fd, false);
|
|
set_serial_info(fd, serial_info);
|
|
serial_logger->debug("", {}, oss.str());
|
|
return true;
|
|
}
|
|
|
|
void Serial::close() {
|
|
serial::close(fd);
|
|
fd = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
int64_t Serial::write(std::string_view data) {
|
|
return serial::write(fd, data.data(), data.size());
|
|
}
|
|
|
|
std::string Serial::read(int64_t size) { return read_all(fd); }
|
|
|
|
int Serial::get_available_bytes() { return serial::get_available_bytes(fd); }
|
|
|
|
std::string Serial::to_string() {
|
|
std::stringstream oss;
|
|
oss << "{" << std::endl;
|
|
oss << "\tfd:" << fd << std::endl;
|
|
oss << "\tbuffer_byte_size: " << serial::get_buffer_byte_size(fd)
|
|
<< std::endl;
|
|
oss << "\tbaud_rate: " << serial::get_baud_rate(serial_info) << std::endl;
|
|
oss << "\tdataBits: " << Psc::to_string(serial::get_data_bits(serial_info))
|
|
<< std::endl;
|
|
oss << "\tstopBits: " << Psc::to_string(serial::get_stop_bits(serial_info))
|
|
<< std::endl;
|
|
oss << "\tparity: " << Psc::to_string(serial::get_parity(serial_info))
|
|
<< std::endl;
|
|
oss << "\tflow_control: "
|
|
<< Psc::to_string(serial::get_flow_control(serial_info)) << std::endl;
|
|
oss << "}" << std::endl;
|
|
return oss.str();
|
|
}
|
|
|
|
void Serial::set_serial_name(std::string_view serial_name) {
|
|
this->serial_name = serial_name;
|
|
}
|
|
|
|
std::string Serial::get_serial_name() { return this->serial_name; }
|
|
|
|
void Serial::set_baud_rate(Baud_Rate_Type baud_rate) {
|
|
this->baud_rate = baud_rate;
|
|
if (fd != INVALID_HANDLE_VALUE) {
|
|
serial::set_baud_rate(serial_info, fd, baud_rate);
|
|
set_serial_info(fd, serial_info);
|
|
}
|
|
}
|
|
|
|
Baud_Rate_Type Serial::get_baud_rate() { return baud_rate; }
|
|
|
|
void Serial::set_data_bits(DataBits data_bits) {
|
|
this->dataBits = data_bits;
|
|
if (fd != INVALID_HANDLE_VALUE) {
|
|
serial::set_data_bits(serial_info, data_bits);
|
|
set_serial_info(fd, serial_info);
|
|
}
|
|
}
|
|
|
|
DataBits Serial::get_data_bits() { return dataBits; }
|
|
|
|
void Serial::set_stop_bits(StopBits stop_bits) {
|
|
this->stopBits = stop_bits;
|
|
if (fd != INVALID_HANDLE_VALUE) {
|
|
serial::set_stop_bits(serial_info, stop_bits);
|
|
set_serial_info(fd, serial_info);
|
|
}
|
|
}
|
|
|
|
StopBits Serial::get_stop_bits() { return stopBits; }
|
|
|
|
void Serial::set_parity(Parity parity) {
|
|
this->parity = parity;
|
|
if (fd != INVALID_HANDLE_VALUE) {
|
|
serial::set_parity(serial_info, parity);
|
|
set_serial_info(fd, serial_info);
|
|
}
|
|
}
|
|
|
|
Parity Serial::get_parity() { return parity; }
|
|
|
|
void Serial::set_flow_control(FlowControl flow_control) {
|
|
this->flow_control = flow_control;
|
|
if (fd != INVALID_HANDLE_VALUE) {
|
|
serial::set_flow_control(serial_info, flow_control);
|
|
set_serial_info(fd, serial_info);
|
|
}
|
|
}
|
|
|
|
FlowControl Serial::get_flow_control() { return flow_control; }
|
|
|
|
void Serial::set_buffer_byte_size(int byte_size) {
|
|
this->buffer_byte_size = byte_size;
|
|
if (fd != INVALID_HANDLE_VALUE) {
|
|
serial::set_buffer_byte_size(fd, byte_size);
|
|
}
|
|
}
|
|
|
|
int Serial::get_buffer_byte_size() { return buffer_byte_size; }
|
|
|
|
std::string read_block_all(Serial_FD fd, int64_t chunkSize) {
|
|
std::string result;
|
|
// 使用 vector 分配一个缓冲区
|
|
std::vector<char> buffer(static_cast<size_t>(chunkSize));
|
|
while (true) {
|
|
int64_t bytesRead = read_data(fd, buffer.data(), chunkSize);
|
|
// std::cout << "bytesRead " << bytesRead;
|
|
if (bytesRead <= 0) {
|
|
// 出错或者没有读取到数据时退出循环
|
|
break;
|
|
}
|
|
// 累积读取的数据
|
|
result.append(buffer.data(), static_cast<size_t>(bytesRead));
|
|
// 如果本次读取的数据不足 chunkSize,通常认为已经没有更多数据
|
|
if (bytesRead <= chunkSize) {
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
std::string read_all(Serial_FD fd) {
|
|
int size = get_available_bytes(fd);
|
|
if (size == 0)
|
|
return "";
|
|
auto ret = read_block_all(fd, 1024 * 4);
|
|
return ret;
|
|
}
|
|
|
|
bool noblock_error() {
|
|
#ifdef _WIN32
|
|
DWORD code = GetLastError();
|
|
return code == ERROR_IO_PENDING || code == ERROR_NO_SYSTEM_RESOURCES;
|
|
#elif defined(__linux__)
|
|
return errno == EAGAIN || errno == EWOULDBLOCK;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
int64_t write_all(Serial_FD fd, std::string_view data, int64_t chunkSize,
|
|
int64_t milliseconds, int64_t retry_count) {
|
|
int64_t total_written = 0;
|
|
int64_t data_size = static_cast<int64_t>(data.size());
|
|
|
|
while (total_written < data_size) {
|
|
int64_t this_chunk = std::min(chunkSize, data_size - total_written);
|
|
int64_t cur_written = 0;
|
|
int64_t retry_left = retry_count;
|
|
|
|
while (cur_written < this_chunk) {
|
|
int64_t to_write = this_chunk - cur_written;
|
|
int64_t written = serial::write(
|
|
fd, data.data() + total_written + cur_written, to_write);
|
|
if (written < 0) {
|
|
// 写入错误,返回 -1
|
|
LOG_ERROR(VAR_STR_2(fd, written))
|
|
return -1;
|
|
}
|
|
if (written > 0) {
|
|
cur_written += written;
|
|
retry_left = retry_count; // 成功写入一次后,重置 retry
|
|
} else if (written == -1) {
|
|
if (noblock_error()) {
|
|
// 非阻塞暂时无法写入
|
|
if (retry_count != -1) {
|
|
if (--retry_left <= 0) {
|
|
LOG_ERROR("Retry limit reached");
|
|
return total_written;
|
|
}
|
|
}
|
|
} else {
|
|
LOG_ERROR("write failed");
|
|
return -1;
|
|
}
|
|
} else if (written == 0) {
|
|
// 不应该发生,write 返回 0 通常表示未写任何数据
|
|
LOG_ERROR("write returned 0 unexpectedly");
|
|
return -1;
|
|
}
|
|
if (cur_written == this_chunk)
|
|
break;
|
|
if (milliseconds > 0) {
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
|
|
}
|
|
}
|
|
|
|
total_written += cur_written;
|
|
}
|
|
|
|
return total_written;
|
|
}
|
|
|
|
} // namespace Psc::serial
|