libuav original
Dependents: UAVCAN UAVCAN_Subscriber
uc_transfer_sender.cpp
00001 /* 00002 * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com> 00003 */ 00004 00005 #include <uavcan/transport/transfer_sender.hpp> 00006 #include <uavcan/debug.hpp> 00007 #include <cassert> 00008 00009 00010 namespace uavcan 00011 { 00012 00013 void TransferSender::registerError() const 00014 { 00015 dispatcher_.getTransferPerfCounter().addError(); 00016 } 00017 00018 void TransferSender::init(const DataTypeDescriptor& dtid, CanTxQueue::Qos qos) 00019 { 00020 UAVCAN_ASSERT(!isInitialized()); 00021 00022 qos_ = qos; 00023 data_type_id_ = dtid.getID(); 00024 crc_base_ = dtid.getSignature().toTransferCRC(); 00025 } 00026 00027 int TransferSender::send(const uint8_t* payload, unsigned payload_len, MonotonicTime tx_deadline, 00028 MonotonicTime blocking_deadline, TransferType transfer_type, NodeID dst_node_id, 00029 TransferID tid) const 00030 { 00031 Frame frame(data_type_id_, transfer_type, dispatcher_.getNodeID(), dst_node_id, tid); 00032 00033 frame.setPriority(priority_); 00034 frame.setStartOfTransfer(true); 00035 00036 UAVCAN_TRACE("TransferSender", "%s", frame.toString().c_str()); 00037 00038 /* 00039 * Checking if we're allowed to send. 00040 * In passive mode we can send only anonymous transfers, if they are enabled. 00041 */ 00042 if (dispatcher_.isPassiveMode()) 00043 { 00044 const bool allow = allow_anonymous_transfers_ && 00045 (transfer_type == TransferTypeMessageBroadcast) && 00046 (int(payload_len) <= frame.getPayloadCapacity()); 00047 if (!allow) 00048 { 00049 return -ErrPassiveMode; 00050 } 00051 } 00052 00053 dispatcher_.getTransferPerfCounter().addTxTransfer(); 00054 00055 /* 00056 * Sending frames 00057 */ 00058 if (frame.getPayloadCapacity() >= payload_len) // Single Frame Transfer 00059 { 00060 const int res = frame.setPayload(payload, payload_len); 00061 if (res != int(payload_len)) 00062 { 00063 UAVCAN_ASSERT(0); 00064 UAVCAN_TRACE("TransferSender", "Frame payload write failure, %i", res); 00065 registerError(); 00066 return (res < 0) ? res : -ErrLogic; 00067 } 00068 00069 frame.setEndOfTransfer(true); 00070 UAVCAN_ASSERT(frame.isStartOfTransfer() && frame.isEndOfTransfer() && !frame.getToggle()); 00071 00072 const CanIOFlags flags = frame.getSrcNodeID().isUnicast() ? flags_ : (flags_ | CanIOFlagAbortOnError); 00073 00074 return dispatcher_.send(frame, tx_deadline, blocking_deadline, qos_, flags, iface_mask_); 00075 } 00076 else // Multi Frame Transfer 00077 { 00078 UAVCAN_ASSERT(!dispatcher_.isPassiveMode()); 00079 UAVCAN_ASSERT(frame.getSrcNodeID().isUnicast()); 00080 00081 int offset = 0; 00082 { 00083 TransferCRC crc = crc_base_; 00084 crc.add(payload, payload_len); 00085 00086 static const int BUFLEN = sizeof(static_cast<CanFrame*>(0)->data); 00087 uint8_t buf[BUFLEN]; 00088 00089 buf[0] = uint8_t(crc.get() & 0xFFU); // Transfer CRC, little endian 00090 buf[1] = uint8_t((crc.get() >> 8) & 0xFF); 00091 (void)copy(payload, payload + BUFLEN - 2, buf + 2); 00092 00093 const int write_res = frame.setPayload(buf, BUFLEN); 00094 if (write_res < 2) 00095 { 00096 UAVCAN_TRACE("TransferSender", "Frame payload write failure, %i", write_res); 00097 registerError(); 00098 return write_res; 00099 } 00100 offset = write_res - 2; 00101 UAVCAN_ASSERT(int(payload_len) > offset); 00102 } 00103 00104 int num_sent = 0; 00105 00106 while (true) 00107 { 00108 const int send_res = dispatcher_.send(frame, tx_deadline, blocking_deadline, qos_, flags_, iface_mask_); 00109 if (send_res < 0) 00110 { 00111 registerError(); 00112 return send_res; 00113 } 00114 00115 num_sent++; 00116 if (frame.isEndOfTransfer()) 00117 { 00118 return num_sent; // Number of frames transmitted 00119 } 00120 00121 frame.setStartOfTransfer(false); 00122 frame.flipToggle(); 00123 00124 UAVCAN_ASSERT(offset >= 0); 00125 const int write_res = frame.setPayload(payload + offset, payload_len - unsigned(offset)); 00126 if (write_res < 0) 00127 { 00128 UAVCAN_TRACE("TransferSender", "Frame payload write failure, %i", write_res); 00129 registerError(); 00130 return write_res; 00131 } 00132 00133 offset += write_res; 00134 UAVCAN_ASSERT(offset <= int(payload_len)); 00135 if (offset >= int(payload_len)) 00136 { 00137 frame.setEndOfTransfer(true); 00138 } 00139 } 00140 } 00141 00142 UAVCAN_ASSERT(0); 00143 return -ErrLogic; // Return path analysis is apparently broken. There should be no warning, this 'return' is unreachable. 00144 } 00145 00146 int TransferSender::send(const uint8_t* payload, unsigned payload_len, MonotonicTime tx_deadline, 00147 MonotonicTime blocking_deadline, TransferType transfer_type, NodeID dst_node_id) const 00148 { 00149 /* 00150 * TODO: TID is not needed for anonymous transfers, this part of the code can be skipped? 00151 */ 00152 const OutgoingTransferRegistryKey otr_key(data_type_id_, transfer_type, dst_node_id); 00153 00154 UAVCAN_ASSERT(!tx_deadline.isZero()); 00155 const MonotonicTime otr_deadline = tx_deadline + max(max_transfer_interval_ * 2, 00156 OutgoingTransferRegistry::MinEntryLifetime); 00157 00158 TransferID* const tid = dispatcher_.getOutgoingTransferRegistry().accessOrCreate(otr_key, otr_deadline); 00159 if (tid == UAVCAN_NULLPTR) 00160 { 00161 UAVCAN_TRACE("TransferSender", "OTR access failure, dtid=%d tt=%i", 00162 int(data_type_id_.get()), int(transfer_type)); 00163 return -ErrMemory; 00164 } 00165 00166 const TransferID this_tid = tid->get(); 00167 tid->increment(); 00168 00169 return send(payload, payload_len, tx_deadline, blocking_deadline, transfer_type, 00170 dst_node_id, this_tid); 00171 } 00172 00173 }
Generated on Tue Jul 12 2022 17:17:35 by 1.7.2