SocketCAN driver: Fixed frame reordering

This commit is contained in:
Pavel Kirienko
2015-07-13 15:44:03 +03:00
parent 4f63d569da
commit f94649f1cc
@@ -43,10 +43,14 @@ enum class SocketCanError
* no more than 'max_frames_in_socket_tx_queue_' TX frames, rest is waiting in the user space TX queue; when the * no more than 'max_frames_in_socket_tx_queue_' TX frames, rest is waiting in the user space TX queue; when the
* socket produces loopback for the previously sent TX frame the next frame from the user space TX queue will * socket produces loopback for the previously sent TX frame the next frame from the user space TX queue will
* be sent into the socket. * be sent into the socket.
*
* This approach allows to properly maintain TX timeouts (http://stackoverflow.com/questions/19633015/). * This approach allows to properly maintain TX timeouts (http://stackoverflow.com/questions/19633015/).
* TX timestamping is implemented by means of reading RX timestamps of loopback frames (see "TX timestamping" on * TX timestamping is implemented by means of reading RX timestamps of loopback frames (see "TX timestamping" on
* linux-can mailing list, http://permalink.gmane.org/gmane.linux.can/5322). * linux-can mailing list, http://permalink.gmane.org/gmane.linux.can/5322).
* *
* Note that if max_frames_in_socket_tx_queue_ is greater than one, frame reordering may occur (depending on the
* unrderlying logic).
*
* This class is too complex and needs to be refactored later. At least, basic socket IO and configuration * This class is too complex and needs to be refactored later. At least, basic socket IO and configuration
* should be extracted into a different class. * should be extracted into a different class.
*/ */
@@ -93,19 +97,29 @@ class SocketCanIface : public uavcan::ICanIface
{ {
uavcan::CanFrame frame; uavcan::CanFrame frame;
uavcan::MonotonicTime deadline; uavcan::MonotonicTime deadline;
uavcan::CanIOFlags flags; uavcan::CanIOFlags flags = 0;
std::uint64_t order = 0;
TxItem() TxItem(const uavcan::CanFrame& arg_frame, uavcan::MonotonicTime arg_deadline,
: flags(0) uavcan::CanIOFlags arg_flags, std::uint64_t arg_order)
{ }
TxItem(const uavcan::CanFrame& arg_frame, uavcan::MonotonicTime arg_deadline, uavcan::CanIOFlags arg_flags)
: frame(arg_frame) : frame(arg_frame)
, deadline(arg_deadline) , deadline(arg_deadline)
, flags(arg_flags) , flags(arg_flags)
, order(arg_order)
{ } { }
bool operator<(const TxItem& rhs) const { return frame.priorityLowerThan(rhs.frame); } bool operator<(const TxItem& rhs) const
{
if (frame.priorityLowerThan(rhs.frame))
{
return true;
}
if (frame.priorityHigherThan(rhs.frame))
{
return false;
}
return order > rhs.order;
}
}; };
struct RxItem struct RxItem
@@ -124,7 +138,9 @@ class SocketCanIface : public uavcan::ICanIface
const int fd_; const int fd_;
const unsigned max_frames_in_socket_tx_queue_; const unsigned max_frames_in_socket_tx_queue_;
unsigned frames_in_socket_tx_queue_; unsigned frames_in_socket_tx_queue_ = 0;
std::uint64_t tx_frame_counter_ = 0; ///< Increments with every frame pushed into the TX queue
std::map<SocketCanError, std::uint64_t> errors_; std::map<SocketCanError, std::uint64_t> errors_;
@@ -302,12 +318,13 @@ class SocketCanIface : public uavcan::ICanIface
public: public:
/** /**
* Takes ownership of socket's file descriptor. * Takes ownership of socket's file descriptor.
*
* @ref max_frames_in_socket_tx_queue See a note in the class comment.
*/ */
SocketCanIface(const SystemClock& clock, int socket_fd, int max_frames_in_socket_tx_queue = 3) SocketCanIface(const SystemClock& clock, int socket_fd, int max_frames_in_socket_tx_queue = 3)
: clock_(clock) : clock_(clock)
, fd_(socket_fd) , fd_(socket_fd)
, max_frames_in_socket_tx_queue_(max_frames_in_socket_tx_queue) , max_frames_in_socket_tx_queue_(max_frames_in_socket_tx_queue)
, frames_in_socket_tx_queue_(0)
{ {
assert(fd_ >= 0); assert(fd_ >= 0);
} }
@@ -326,7 +343,8 @@ public:
std::int16_t send(const uavcan::CanFrame& frame, const uavcan::MonotonicTime tx_deadline, std::int16_t send(const uavcan::CanFrame& frame, const uavcan::MonotonicTime tx_deadline,
const uavcan::CanIOFlags flags) override const uavcan::CanIOFlags flags) override
{ {
tx_queue_.emplace(frame, tx_deadline, flags); tx_queue_.emplace(frame, tx_deadline, flags, tx_frame_counter_);
tx_frame_counter_++;
pollRead(); // Read poll is necessary because it can release the pending TX flag pollRead(); // Read poll is necessary because it can release the pending TX flag
pollWrite(); pollWrite();
return 1; return 1;
@@ -509,7 +527,7 @@ private:
const SystemClock& clock_; const SystemClock& clock_;
uavcan::LazyConstructor<SocketCanIface> ifaces_[MaxIfaces]; uavcan::LazyConstructor<SocketCanIface> ifaces_[MaxIfaces];
::pollfd pollfds_[MaxIfaces]; ::pollfd pollfds_[MaxIfaces];
std::uint8_t num_ifaces_; std::uint8_t num_ifaces_ = 0;
public: public:
/** /**
@@ -517,7 +535,6 @@ public:
*/ */
explicit SocketCanDriver(const SystemClock& clock) explicit SocketCanDriver(const SystemClock& clock)
: clock_(clock) : clock_(clock)
, num_ifaces_(0)
{ {
for (auto& p : pollfds_) for (auto& p : pollfds_)
{ {