0

众所周知,在CAN总线通信协议中,发送方知道数据是否发送成功。我发送socketcan数据如下。

ret = write (socket, frame, sizeof (struct can_frame));

但是即使CAN通讯线断开了,ret的返回值仍然是16(=sizeof(struct can_frame))。我查询了资料,发现问题出在socketcan使用的网络栈的tx_queue上。多次调用write时,缓冲区已满,ret的返回值为-1。但这不是我所期望的行为,我希望发送的每一帧数据都会立即获得成功或失败的状态。经过

echo 0> / sys / class / net / can0 / tx_queue_len

我想取消 tx_queue,但它不起作用。我想问的是,有没有办法取消socketcan的tx_queue,或者通过API(如libsocketcan)获取关于控制器的每个发送帧的状态。谢谢。

4

1 回答 1

3

您不能使用write()它自己来发现 CAN 帧是否已成功放入总线,因为它所做的只是将帧写入内核套接字缓冲区。然后内核将帧移动到 SocketCAN 网络接口的传输队列,然后驱动程序将其移动到 CAN 控制器的传输缓冲区,最终将帧放到总线上。您想要的是绕过所有这些缓冲区的直接写入,但使用 SocketCAN 是不可能的,即使您将传输队列长度设置为 0。

但是,还有另一种获得确认的方法。如果启用CAN_RAW_RECV_OWN_MSGS套接字选项(请参阅SocketCAN 文档中的 4.1.4 和 4.1.7 节),您将收到已成功发送的帧。您需要使用recvmsg()才能获得消息标志。msg_flags将为MSG_CONFIRM由接收它的同一个套接字成功发送的帧设置位。您不会被告知失败,但您可以通过使用超时进行确认来检测它们。

这不是一个理想的解决方案,因为它在您的应用程序中混合了读写逻辑。避免这种情况的一种方法是使用两个套接字。一个用于写入和读取MSG_CONFIRM帧,另一个用于读取所有其他帧。然后,您可以创建一个(阻塞)写入函数,该函数执行 awrite()之后的多次调用,recvmsg()并具有适当的超时。

CAN_RAW_ERR_FILTER最后,启用错误帧(通过套接字选项)很有用。如果您在电缆断开的情况下在套接字上发送帧,这通常会导致总线关闭状态,这将在错误帧中报告。

于 2020-06-03T14:20:56.193 回答