libuav original
Dependents: UAVCAN UAVCAN_Subscriber
transfer_sender.cpp
00001 /* 00002 * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com> 00003 */ 00004 00005 #include <algorithm> 00006 #include <gtest/gtest.h> 00007 #include "transfer_test_helpers.hpp" 00008 #include "can/can.hpp" 00009 #include <uavcan/transport/transfer_sender.hpp> 00010 00011 static int sendOne(uavcan::TransferSender& sender, const std::string& data, 00012 uint64_t monotonic_tx_deadline, uint64_t monotonic_blocking_deadline, 00013 uavcan::TransferType transfer_type, uavcan::NodeID dst_node_id) 00014 { 00015 return sender.send(reinterpret_cast<const uint8_t*>(data.c_str()), unsigned(data.length()), 00016 uavcan::MonotonicTime::fromUSec(monotonic_tx_deadline), 00017 uavcan::MonotonicTime::fromUSec(monotonic_blocking_deadline), transfer_type, dst_node_id); 00018 } 00019 00020 static int sendOne(uavcan::TransferSender& sender, const std::string& data, 00021 uint64_t monotonic_tx_deadline, uint64_t monotonic_blocking_deadline, 00022 uavcan::TransferType transfer_type, uavcan::NodeID dst_node_id, uavcan::TransferID tid) 00023 { 00024 return sender.send(reinterpret_cast<const uint8_t*>(data.c_str()), unsigned(data.length()), 00025 uavcan::MonotonicTime::fromUSec(monotonic_tx_deadline), 00026 uavcan::MonotonicTime::fromUSec(monotonic_blocking_deadline), transfer_type, dst_node_id, tid); 00027 } 00028 00029 00030 TEST(TransferSender, Basic) 00031 { 00032 uavcan::PoolAllocator<uavcan::MemPoolBlockSize * 100, uavcan::MemPoolBlockSize> poolmgr; 00033 00034 SystemClockMock clockmock(100); 00035 CanDriverMock driver(2, clockmock); 00036 00037 static const uavcan::NodeID TX_NODE_ID(64); 00038 static const uavcan::NodeID RX_NODE_ID(65); 00039 uavcan::Dispatcher dispatcher_tx(driver, poolmgr, clockmock); 00040 uavcan::Dispatcher dispatcher_rx(driver, poolmgr, clockmock); 00041 ASSERT_TRUE(dispatcher_tx.setNodeID(TX_NODE_ID)); 00042 ASSERT_TRUE(dispatcher_rx.setNodeID(RX_NODE_ID)); 00043 00044 /* 00045 * Test environment 00046 */ 00047 static const uavcan::DataTypeDescriptor TYPES[2] = 00048 { 00049 makeDataType(uavcan::DataTypeKindMessage, 1), 00050 makeDataType(uavcan::DataTypeKindService, 1) 00051 }; 00052 00053 uavcan::TransferSender senders[2] = 00054 { 00055 uavcan::TransferSender(dispatcher_tx, TYPES[0], uavcan::CanTxQueue::Volatile), 00056 uavcan::TransferSender(dispatcher_tx, TYPES[1], uavcan::CanTxQueue::Persistent) 00057 }; 00058 00059 static const std::string DATA[4] = 00060 { 00061 "Don't panic.", 00062 00063 "The ships hung in the sky in much the same way that bricks don't.", 00064 00065 "Would it save you a lot of time if I just gave up and went mad now?", 00066 00067 "If there's anything more important than my ego around, I want it caught and shot now." 00068 }; 00069 00070 /* 00071 * Transmission 00072 */ 00073 static const uint64_t TX_DEADLINE = 1000000; 00074 00075 // Low priority 00076 senders[0].setPriority(20); 00077 sendOne(senders[0], DATA[0], TX_DEADLINE, 0, uavcan::TransferTypeMessageBroadcast, 0); 00078 sendOne(senders[0], DATA[1], TX_DEADLINE, 0, uavcan::TransferTypeMessageBroadcast, 0); 00079 // High priority 00080 senders[0].setPriority(10); 00081 sendOne(senders[0], "123", TX_DEADLINE, 0, uavcan::TransferTypeMessageBroadcast, 0); 00082 sendOne(senders[0], "456", TX_DEADLINE, 0, uavcan::TransferTypeMessageBroadcast, 0); 00083 00084 senders[1].setPriority(15); 00085 sendOne(senders[1], DATA[2], TX_DEADLINE, 0, uavcan::TransferTypeServiceRequest, RX_NODE_ID); 00086 sendOne(senders[1], DATA[3], TX_DEADLINE, 0, uavcan::TransferTypeServiceResponse, RX_NODE_ID, 1); 00087 sendOne(senders[1], "", TX_DEADLINE, 0, uavcan::TransferTypeServiceRequest, RX_NODE_ID); 00088 sendOne(senders[1], "", TX_DEADLINE, 0, uavcan::TransferTypeServiceResponse, RX_NODE_ID, 2); 00089 00090 using namespace uavcan; 00091 static const Transfer TRANSFERS[8] = 00092 { 00093 Transfer(TX_DEADLINE, 0, 20, TransferTypeMessageBroadcast, 0, TX_NODE_ID, 0, DATA[0], TYPES[0]), 00094 Transfer(TX_DEADLINE, 0, 20, TransferTypeMessageBroadcast, 1, TX_NODE_ID, 0, DATA[1], TYPES[0]), 00095 Transfer(TX_DEADLINE, 0, 10, TransferTypeMessageBroadcast, 2, TX_NODE_ID, 0, "123", TYPES[0]), 00096 Transfer(TX_DEADLINE, 0, 10, TransferTypeMessageBroadcast, 3, TX_NODE_ID, 0, "456", TYPES[0]), 00097 00098 Transfer(TX_DEADLINE, 0, 15, TransferTypeServiceRequest, 0, TX_NODE_ID, RX_NODE_ID, DATA[2], TYPES[1]), 00099 Transfer(TX_DEADLINE, 0, 15, TransferTypeServiceResponse, 1, TX_NODE_ID, RX_NODE_ID, DATA[3], TYPES[1]), 00100 Transfer(TX_DEADLINE, 0, 15, TransferTypeServiceRequest, 1, TX_NODE_ID, RX_NODE_ID, "", TYPES[1]), 00101 Transfer(TX_DEADLINE, 0, 15, TransferTypeServiceResponse, 2, TX_NODE_ID, RX_NODE_ID, "", TYPES[1]) 00102 }; 00103 00104 /* 00105 * Making sure that the abort flag is not used. 00106 */ 00107 ASSERT_EQ(0, driver.ifaces.at(0).tx.front().flags); 00108 00109 /* 00110 * Receiving on the other side. 00111 */ 00112 for (uint8_t i = 0; i < driver.getNumIfaces(); i++) // Moving the frames from TX to RX side 00113 { 00114 CanIfaceMock& iface = driver.ifaces.at(i); 00115 std::cout << "Num frames: " << iface.tx.size() << std::endl; 00116 while (!iface.tx.empty()) 00117 { 00118 CanIfaceMock::FrameWithTime ft = iface.tx.front(); 00119 iface.tx.pop(); 00120 iface.rx.push(ft); 00121 } 00122 } 00123 00124 TestListener sub_msg(dispatcher_rx.getTransferPerfCounter(), TYPES[0], 512, poolmgr); 00125 TestListener sub_srv_req(dispatcher_rx.getTransferPerfCounter(), TYPES[1], 512, poolmgr); 00126 TestListener sub_srv_resp(dispatcher_rx.getTransferPerfCounter(), TYPES[1], 512, poolmgr); 00127 00128 dispatcher_rx.registerMessageListener(&sub_msg); 00129 dispatcher_rx.registerServiceRequestListener(&sub_srv_req); 00130 dispatcher_rx.registerServiceResponseListener(&sub_srv_resp); 00131 00132 while (true) 00133 { 00134 const int res = dispatcher_rx.spin(tsMono(0)); 00135 ASSERT_LE(0, res); 00136 clockmock.advance(100); 00137 if (res == 0) 00138 { 00139 break; 00140 } 00141 } 00142 00143 /* 00144 * Validation 00145 */ 00146 ASSERT_TRUE(sub_msg.matchAndPop(TRANSFERS[0])); 00147 ASSERT_TRUE(sub_msg.matchAndPop(TRANSFERS[1])); 00148 ASSERT_TRUE(sub_msg.matchAndPop(TRANSFERS[2])); 00149 ASSERT_TRUE(sub_msg.matchAndPop(TRANSFERS[3])); 00150 00151 ASSERT_TRUE(sub_srv_req.matchAndPop(TRANSFERS[4])); 00152 ASSERT_TRUE(sub_srv_req.matchAndPop(TRANSFERS[6])); 00153 00154 ASSERT_TRUE(sub_srv_resp.matchAndPop(TRANSFERS[5])); 00155 ASSERT_TRUE(sub_srv_resp.matchAndPop(TRANSFERS[7])); 00156 00157 /* 00158 * Perf counters 00159 */ 00160 EXPECT_EQ(0, dispatcher_tx.getTransferPerfCounter().getErrorCount()); 00161 EXPECT_EQ(8, dispatcher_tx.getTransferPerfCounter().getTxTransferCount()); 00162 EXPECT_EQ(0, dispatcher_tx.getTransferPerfCounter().getRxTransferCount()); 00163 00164 EXPECT_EQ(0, dispatcher_rx.getTransferPerfCounter().getErrorCount()); 00165 EXPECT_EQ(0, dispatcher_rx.getTransferPerfCounter().getTxTransferCount()); 00166 EXPECT_EQ(8, dispatcher_rx.getTransferPerfCounter().getRxTransferCount()); 00167 } 00168 00169 00170 struct TransferSenderTestLoopbackFrameListener : public uavcan::LoopbackFrameListenerBase 00171 { 00172 uavcan::RxFrame last_frame; 00173 unsigned count; 00174 00175 TransferSenderTestLoopbackFrameListener(uavcan::Dispatcher& dispatcher) 00176 : uavcan::LoopbackFrameListenerBase(dispatcher) 00177 , count(0) 00178 { 00179 startListening(); 00180 } 00181 00182 void handleLoopbackFrame(const uavcan::RxFrame& frame) 00183 { 00184 last_frame = frame; 00185 count++; 00186 } 00187 }; 00188 00189 TEST(TransferSender, Loopback) 00190 { 00191 uavcan::PoolAllocator<uavcan::MemPoolBlockSize * 100, uavcan::MemPoolBlockSize> poolmgr; 00192 00193 SystemClockMock clockmock(100); 00194 CanDriverMock driver(2, clockmock); 00195 00196 static const uavcan::NodeID TX_NODE_ID(64); 00197 uavcan::Dispatcher dispatcher(driver, poolmgr, clockmock); 00198 ASSERT_TRUE(dispatcher.setNodeID(TX_NODE_ID)); 00199 00200 uavcan::DataTypeDescriptor desc = makeDataType(uavcan::DataTypeKindMessage, 1, "Foobar"); 00201 00202 uavcan::TransferSender sender(dispatcher, desc, uavcan::CanTxQueue::Volatile); 00203 00204 sender.setCanIOFlags(uavcan::CanIOFlagLoopback); 00205 ASSERT_EQ(uavcan::CanIOFlagLoopback, sender.getCanIOFlags()); 00206 00207 sender.setIfaceMask(2); 00208 ASSERT_EQ(2, sender.getIfaceMask()); 00209 00210 TransferSenderTestLoopbackFrameListener listener(dispatcher); 00211 00212 ASSERT_LE(0, sender.send(reinterpret_cast<const uint8_t*>("123"), 3, tsMono(1000), tsMono(0), 00213 uavcan::TransferTypeMessageBroadcast, 0)); 00214 00215 ASSERT_EQ(0, listener.count); 00216 ASSERT_EQ(0, dispatcher.spin(tsMono(1000))); 00217 ASSERT_EQ(1, listener.count); 00218 ASSERT_EQ(1, listener.last_frame.getIfaceIndex()); 00219 ASSERT_EQ(3, listener.last_frame.getPayloadLen()); 00220 ASSERT_TRUE(TX_NODE_ID == listener.last_frame.getSrcNodeID()); 00221 ASSERT_TRUE(listener.last_frame.isEndOfTransfer()); 00222 00223 EXPECT_EQ(0, dispatcher.getTransferPerfCounter().getErrorCount()); 00224 EXPECT_EQ(1, dispatcher.getTransferPerfCounter().getTxTransferCount()); 00225 EXPECT_EQ(0, dispatcher.getTransferPerfCounter().getRxTransferCount()); 00226 } 00227 00228 TEST(TransferSender, PassiveMode) 00229 { 00230 uavcan::PoolAllocator<uavcan::MemPoolBlockSize * 100, uavcan::MemPoolBlockSize> poolmgr; 00231 00232 SystemClockMock clockmock(100); 00233 CanDriverMock driver(2, clockmock); 00234 00235 uavcan::Dispatcher dispatcher(driver, poolmgr, clockmock); 00236 00237 uavcan::TransferSender sender(dispatcher, makeDataType(uavcan::DataTypeKindMessage, 123), 00238 uavcan::CanTxQueue::Volatile); 00239 00240 static const uint8_t Payload[] = {1, 2, 3, 4, 5}; 00241 00242 // By default, sending in passive mode is not enabled 00243 ASSERT_EQ(-uavcan::ErrPassiveMode, 00244 sender.send(Payload, sizeof(Payload), tsMono(1000), uavcan::MonotonicTime(), 00245 uavcan::TransferTypeMessageBroadcast, uavcan::NodeID::Broadcast)); 00246 00247 // Overriding the default 00248 sender.allowAnonymousTransfers(); 00249 00250 // OK, now we can broadcast in any mode 00251 ASSERT_LE(0, sender.send(Payload, sizeof(Payload), tsMono(1000), uavcan::MonotonicTime(), 00252 uavcan::TransferTypeMessageBroadcast, uavcan::NodeID::Broadcast)); 00253 00254 // ...but not unicast or anything else 00255 ASSERT_EQ(-uavcan::ErrPassiveMode, 00256 sender.send(Payload, sizeof(Payload), tsMono(1000), uavcan::MonotonicTime(), 00257 uavcan::TransferTypeServiceRequest, uavcan::NodeID(42))); 00258 00259 // Making sure the abort flag is set 00260 ASSERT_FALSE(driver.ifaces.at(0).tx.empty()); 00261 ASSERT_EQ(uavcan::CanIOFlagAbortOnError, driver.ifaces.at(0).tx.front().flags); 00262 00263 EXPECT_EQ(0, dispatcher.getTransferPerfCounter().getErrorCount()); 00264 EXPECT_EQ(1, dispatcher.getTransferPerfCounter().getTxTransferCount()); 00265 EXPECT_EQ(0, dispatcher.getTransferPerfCounter().getRxTransferCount()); 00266 }
Generated on Tue Jul 12 2022 17:17:35 by 1.7.2