uc_transfer_receiver.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
3  */
4 
7 #include <uavcan/debug.hpp>
8 #include <cstdlib>
9 #include <cassert>
10 
11 namespace uavcan
12 {
13 
18 
20 {
22 }
23 
25 {
27 }
28 
30 {
31  error_cnt_ = static_cast<uint8_t>(error_cnt_ + 1) & ErrorCntMask;
32 }
33 
35 {
37 
38  const MonotonicTime prev_prev_ts = prev_transfer_ts_;
40 
41  if ((!prev_prev_ts.isZero()) && (!prev_transfer_ts_.isZero()) && (prev_transfer_ts_ >= prev_prev_ts))
42  {
43  uint64_t interval_msec = uint64_t((prev_transfer_ts_ - prev_prev_ts).toMSec());
44  interval_msec = min(interval_msec, uint64_t(MaxTransferIntervalMSec));
45  interval_msec = max(interval_msec, uint64_t(MinTransferIntervalMSec));
46  transfer_interval_msec_ = static_cast<uint16_t>((uint64_t(transfer_interval_msec_) * 7U + interval_msec) / 8U);
47  }
48 }
49 
51 {
52  tid_.increment();
53  next_toggle_ = false;
55 }
56 
58 {
59  if (iface_index_ != frame.getIfaceIndex())
60  {
61  return false;
62  }
63  if (frame.isStartOfTransfer() && !frame.isEndOfTransfer() && (frame.getPayloadLen() < TransferCRC::NumBytes))
64  {
65  UAVCAN_TRACE("TransferReceiver", "CRC expected, %s", frame.toString().c_str());
66  registerError();
67  return false;
68  }
69  if (frame.isStartOfTransfer() && frame.getToggle())
70  {
71  UAVCAN_TRACE("TransferReceiver", "Toggle bit is not cleared, %s", frame.toString().c_str());
72  registerError();
73  return false;
74  }
75  if (frame.isStartOfTransfer() && isMidTransfer())
76  {
77  UAVCAN_TRACE("TransferReceiver", "Unexpected start of transfer, %s", frame.toString().c_str());
78  registerError();
79  }
80  if (frame.getToggle() != next_toggle_)
81  {
82  UAVCAN_TRACE("TransferReceiver", "Unexpected toggle bit (not %i), %s",
83  int(next_toggle_), frame.toString().c_str());
84  registerError();
85  return false;
86  }
87  if (frame.getTransferID() != tid_)
88  {
89  UAVCAN_TRACE("TransferReceiver", "Unexpected TID (current %i), %s", tid_.get(), frame.toString().c_str());
90  registerError();
91  return false;
92  }
93  return true;
94 }
95 
97 {
98  const uint8_t* const payload = frame.getPayloadPtr();
99  const unsigned payload_len = frame.getPayloadLen();
100 
101  if (frame.isStartOfTransfer()) // First frame contains CRC, we need to extract it now
102  {
103  if (frame.getPayloadLen() < TransferCRC::NumBytes)
104  {
105  return false; // Must have been validated earlier though. I think I'm paranoid.
106  }
107  this_transfer_crc_ = static_cast<uint16_t>(payload[0] & 0xFF);
108  this_transfer_crc_ |= static_cast<uint16_t>(static_cast<uint16_t>(payload[1] & 0xFF) << 8); // Little endian.
109 
110  const unsigned effective_payload_len = payload_len - TransferCRC::NumBytes;
111  const int res = buf.write(buffer_write_pos_, payload + TransferCRC::NumBytes, effective_payload_len);
112  const bool success = res == static_cast<int>(effective_payload_len);
113  if (success)
114  {
115  buffer_write_pos_ = static_cast<uint16_t>(buffer_write_pos_ + effective_payload_len);
116  }
117  return success;
118  }
119  else
120  {
121  const int res = buf.write(buffer_write_pos_, payload, payload_len);
122  const bool success = res == static_cast<int>(payload_len);
123  if (success)
124  {
125  buffer_write_pos_ = static_cast<uint16_t>(buffer_write_pos_ + payload_len);
126  }
127  return success;
128  }
129 }
130 
132 {
133  // Transfer timestamps are derived from the first frame
134  if (frame.isStartOfTransfer())
135  {
138  }
139 
140  if (frame.isStartOfTransfer() && frame.isEndOfTransfer())
141  {
142  tba.remove();
145  this_transfer_crc_ = 0; // SFT has no CRC
146  return ResultSingleFrame;
147  }
148 
149  // Payload write
150  ITransferBuffer* buf = tba.access();
151  if (buf == UAVCAN_NULLPTR)
152  {
153  buf = tba.create();
154  }
155  if (buf == UAVCAN_NULLPTR)
156  {
157  UAVCAN_TRACE("TransferReceiver", "Failed to access the buffer, %s", frame.toString().c_str());
159  registerError();
160  return ResultNotComplete;
161  }
162  if (!writePayload(frame, *buf))
163  {
164  UAVCAN_TRACE("TransferReceiver", "Payload write failed, %s", frame.toString().c_str());
165  tba.remove();
167  registerError();
168  return ResultNotComplete;
169  }
171 
172  if (frame.isEndOfTransfer())
173  {
176  return ResultComplete;
177  }
178  return ResultNotComplete;
179 }
180 
182 {
183  return (current_ts - this_transfer_ts_) > getTidTimeout();
184 }
185 
187 {
188  if ((frame.getMonotonicTimestamp().isZero()) ||
191  {
192  UAVCAN_TRACE("TransferReceiver", "Invalid frame, %s", frame.toString().c_str());
193  return ResultNotComplete;
194  }
195 
196  const bool not_initialized = !isInitialized();
197  const bool tid_timed_out = isTimedOut(frame.getMonotonicTimestamp());
198  const bool same_iface = frame.getIfaceIndex() == iface_index_;
199  const bool first_frame = frame.isStartOfTransfer();
200  const bool non_wrapped_tid = tid_.computeForwardDistance(frame.getTransferID()) < TransferID::Half;
201  const bool not_previous_tid = frame.getTransferID().computeForwardDistance(tid_) > 1;
202  const bool iface_switch_allowed = (frame.getMonotonicTimestamp() - this_transfer_ts_) > getIfaceSwitchDelay();
203 
204  // FSM, the hard way
205  const bool need_restart =
206  (not_initialized) ||
207  (tid_timed_out) ||
208  (same_iface && first_frame && not_previous_tid) ||
209  (iface_switch_allowed && first_frame && non_wrapped_tid);
210 
211  if (need_restart)
212  {
213  if (!not_initialized && (tid_ != frame.getTransferID()))
214  {
215  registerError();
216  }
217  UAVCAN_TRACE("TransferReceiver", "Restart [ni=%d, isa=%d, tt=%d, si=%d, ff=%d, nwtid=%d, nptid=%d, tid=%d], %s",
218  int(not_initialized), int(iface_switch_allowed), int(tid_timed_out), int(same_iface),
219  int(first_frame), int(non_wrapped_tid), int(not_previous_tid), int(tid_.get()),
220  frame.toString().c_str());
221  tba.remove();
223  tid_ = frame.getTransferID();
224  next_toggle_ = false;
225  buffer_write_pos_ = 0;
226  this_transfer_crc_ = 0;
227  if (!first_frame)
228  {
229  tid_.increment();
230  return ResultNotComplete;
231  }
232  }
233 
234  if (!validate(frame))
235  {
236  return ResultNotComplete;
237  }
238  return receive(frame, tba);
239 }
240 
242 {
243  const uint8_t ret = error_cnt_;
244  error_cnt_ = 0;
245  return ret;
246 }
247 
248 }
std::uint8_t uint8_t
Definition: std.hpp:24
bool isZero() const
Definition: time.hpp:123
bool isStartOfTransfer() const
Definition: frame.hpp:84
MonotonicTime getMonotonicTimestamp() const
Definition: frame.hpp:128
unsigned getPayloadLen() const
Definition: frame.hpp:72
static const uint16_t DefaultTransferIntervalMSec
MonotonicDuration getTidTimeout() const
bool isTimedOut(MonotonicTime current_ts) const
TransferID getTransferID() const
Definition: frame.hpp:79
static const uint8_t Half
Definition: transfer.hpp:78
const uint8_t * getPayloadPtr() const
Definition: frame.hpp:73
virtual int write(unsigned offset, const uint8_t *data, unsigned len)=0
UAVCAN_EXPORT const T & max(const T &a, const T &b)
Definition: templates.hpp:291
bool isEndOfTransfer() const
Definition: frame.hpp:85
static const uint16_t MaxTransferIntervalMSec
uint8_t getIfaceIndex() const
Definition: frame.hpp:135
int computeForwardDistance(TransferID rhs) const
Definition: uc_transfer.cpp:44
UAVCAN_EXPORT const T & min(const T &a, const T &b)
Definition: templates.hpp:281
std::uint64_t uint64_t
Definition: std.hpp:27
bool writePayload(const RxFrame &frame, ITransferBuffer &buf)
bool validate(const RxFrame &frame) const
uint8_t get() const
Definition: transfer.hpp:99
ResultCode receive(const RxFrame &frame, TransferBufferAccessor &tba)
static const uint16_t MinTransferIntervalMSec
UtcTime getUtcTimestamp() const
Definition: frame.hpp:133
uavcan::CanFrame frame
Definition: can.cpp:78
MonotonicDuration getIfaceSwitchDelay() const
std::uint16_t uint16_t
Definition: std.hpp:25
static const uint16_t DefaultTidTimeoutMSec
static MonotonicDuration fromMSec(int64_t ms)
Definition: time.hpp:41
bool getToggle() const
Definition: frame.hpp:88
ResultCode addFrame(const RxFrame &frame, TransferBufferAccessor &tba)


uavcan_communicator
Author(s):
autogenerated on Wed Jan 11 2023 03:59:40