我正在实现一种串行通信协议,通过UART与外部设备进行通信。我正在使用boost asio。到目前为止一切正常,除了很少的情况。我发现在某些情况下,套接字的读取可能“miss” 1个字节。
我使用UART嗅探器查看了串行通信,以查看来自套接字的原始数据。这很难过,我确实看到通过套接字传输的完整字节帧。但在我的应用程序中,最后一个字节没有收到。
我发现他的字节不是“丢失”它在某种程度上只是“卡住”在内核缓冲区或其他什么东西。因为在接收到下一帧时,我会在所有新字节前面得到“missing”字节。如果框架连续进入,这不会是一个大问题。但是,如果程序确认了前一帧,则下一帧仅由设备发送。
这是我的写和处理接收方法的代码:
void serial::write(std::vector<uint8_t> message) {
static boost::mutex mu;
mu.lock();
uint8_t cmd = message.at(3);
//if its an ACK frame - just send it
if ((message[3]>>4)==0xE) {
// --- Write message to serial port --- //
boost::asio::write(serial_,boost::asio::buffer(message));
usleep(20000);
mu.unlock();
return;
}
//if its not an ACK frame write the frame and wait for an ACK!
//create new promise for the request
promise = new boost::promise<deque<uint8_t>>;
boost::unique_future<deque<uint8_t>> future = promise->get_future();
// --- Write message to serial port --- //
boost::asio::write(serial_,boost::asio::buffer(message));
usleep(20000);
mu.unlock();
//wait for ACK or timeout
if (future.wait_for(boost::chrono::milliseconds(100))==boost::future_status::timeout) {
spdlog::get("logger")->trace("ACK timeout!");
//delete pointer and set it to 0
delete promise;
promise=nullptr;
//need to resend this frame
}
//delete pointer and set it to 0 after getting a message
delete promise;
promise=nullptr;
}
处理接收:
void serial::handle_receive(const boost::system::error_code& error, size_t bytes_transferred) {
static deque<uint8_t> read_buffer;
static boost::posix_time::ptime start = boost::posix_time::microsec_clock::local_time( );
if (boost::posix_time::microsec_clock::local_time( ) - start > boost::posix_time::milliseconds(99) && !read_buffer.empty()) {
spdlog::get("logger")->trace("time condition, clearing buffer!");
read_buffer.clear();
}
start = boost::posix_time::microsec_clock::local_time( );
if (!error) {
//push all the recieved data into the deque
for (unsigned int i = 0; i < bytes_transferred; i++) {
read_buffer.push_back((int)data_[i]);
}
}
else if (error){
spdlog::get("logger")->error("\n\n\n\nERROR: {0}\n\n\n\n", error);
}
while ( !read_buffer.empty()) {
/*do here some checks if this could be a correct frame
...
...
...
*/
//received frame is ready
//check if it is an ACK frame
//check if its a data frame and ACK it!
//send an ACK if its a dataframe
if (ACK)) {
write(frame);
}
//give the data to the upper layer
m_Receive_data_handler(receivedFrame,receivedFrame.size());
}
serial_.async_read_some(boost::asio::buffer(data_,max_length),
boost::bind(&serial::handle_receive, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
也许有人知道为什么它适用于大多数情况,但只是在帧的最后一个字节失败?
谢谢!
答案 0 :(得分:0)
您正在使用异步调用来读取数据,并且无法保证您将阅读所有内容。
说明
读取操作可能无法读取所有请求的字节数。 如果需要确保使用async_read函数,请考虑使用 在异步操作之前读取请求的数据量 完成。
可能会发生的情况是,在您的情况下,您的内核具有很少的缓冲区,并且当它有一些数据时它会向应用程序发出信号,但是您尝试发送的数据多于此数据。一旦它只停留在缓冲区中的小数据,它将等待更多的数据来保存呼叫。这些只是假设,我没有UART的第一手经验。
是否可以选择切换到同步读取调用(read_some)?
答案 1 :(得分:0)
可能是这样,而不是卡在某个内核缓冲区中,最后一个字节是否卡在UART的接收FIFO中?也许您需要使用字符间超时配置驱动程序?