libuav original

Dependents:   UAVCAN UAVCAN_Subscriber

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers transfer_sender.cpp Source File

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 }