Руслан Урядинский / libuavcan

Dependents:   UAVCAN UAVCAN_Subscriber

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers frame.cpp Source File

frame.cpp

00001 /*
00002  * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
00003  */
00004 
00005 #include <string>
00006 #include <gtest/gtest.h>
00007 #include <uavcan/transport/transfer.hpp>
00008 #include <uavcan/transport/crc.hpp>
00009 #include "../clock.hpp"
00010 #include "can/can.hpp"
00011 
00012 
00013 TEST(Frame, MessageParseCompile)
00014 {
00015     using uavcan::Frame;
00016     using uavcan::CanFrame;
00017     using uavcan::TransferID;
00018     using uavcan::TransferType;
00019 
00020     Frame frame;
00021 
00022     /*
00023      * Priority
00024      * Message Type ID
00025      * Service Not Message
00026      * Source Node ID
00027      */
00028     const uint32_t can_id =
00029         (16 << 24) |    // Priority
00030         (20000 << 8) |  // Message Type ID
00031         (0 << 7) |      // Service Not Message
00032         (42 << 0);      // Source Node ID
00033 
00034     const std::string payload_string = "hello\xD4"; // SET = 110, TID = 20
00035 
00036     /*
00037      * Parse
00038      */
00039     // Invalid CAN frames
00040     ASSERT_FALSE(frame.parse(CanFrame(can_id | CanFrame::FlagRTR, reinterpret_cast<const uint8_t*>(""), 0)));
00041     ASSERT_FALSE(frame.parse(makeCanFrame(can_id, payload_string, STD)));
00042 
00043     // Valid
00044     ASSERT_TRUE(frame.parse(makeCanFrame(can_id, payload_string, EXT)));
00045 
00046     EXPECT_EQ(TransferID(20), frame.getTransferID());
00047     EXPECT_TRUE(frame.isStartOfTransfer());
00048     EXPECT_TRUE(frame.isEndOfTransfer());
00049     EXPECT_FALSE(frame.getToggle());
00050     EXPECT_EQ(uavcan::NodeID(42), frame.getSrcNodeID());
00051     EXPECT_TRUE(frame.getDstNodeID().isBroadcast());
00052     EXPECT_EQ(uavcan::TransferTypeMessageBroadcast, frame.getTransferType());
00053     EXPECT_EQ(20000, frame.getDataTypeID().get());
00054     EXPECT_EQ(16, frame.getPriority().get());
00055 
00056     EXPECT_EQ(payload_string.length() - 1, frame.getPayloadLen());
00057     EXPECT_TRUE(std::equal(frame.getPayloadPtr(), frame.getPayloadPtr() + frame.getPayloadLen(),
00058                            payload_string.begin()));
00059 
00060     std::cout << frame.toString() << std::endl;
00061 
00062     /*
00063      * Compile
00064      */
00065     CanFrame can_frame;
00066     ASSERT_TRUE(frame.parse(makeCanFrame(can_id, payload_string, EXT)));
00067 
00068     ASSERT_TRUE(frame.compile(can_frame));
00069     ASSERT_EQ(can_frame, makeCanFrame(can_id, payload_string, EXT));
00070 
00071     EXPECT_EQ(payload_string.length(), can_frame.dlc);
00072     std::cout << can_frame.toString() << std::endl;
00073     /*
00074      * FUN FACT: comparison of uint8_t with char may fail on the character 0xD4 (depending on the locale),
00075      * because it will be considered a Unicode character. Hence, we do reinterpret_cast<>.
00076      */
00077     EXPECT_TRUE(std::equal(can_frame.data, can_frame.data + can_frame.dlc,
00078                            reinterpret_cast<const uint8_t*>(&payload_string[0])));
00079 
00080     /*
00081      * Comparison
00082      */
00083     ASSERT_FALSE(Frame() == frame);
00084     ASSERT_TRUE(Frame() != frame);
00085     frame = Frame();
00086     ASSERT_TRUE(Frame() == frame);
00087     ASSERT_FALSE(Frame() != frame);
00088 }
00089 
00090 
00091 TEST(Frame, ServiceParseCompile)
00092 {
00093     using uavcan::Frame;
00094     using uavcan::CanFrame;
00095     using uavcan::TransferID;
00096     using uavcan::TransferType;
00097 
00098     Frame frame;
00099 
00100     /*
00101      * Priority
00102      * Service Type ID
00103      * Request Not Response
00104      * Destination Node ID
00105      * Service Not Message
00106      * Source Node ID
00107      */
00108     const uint32_t can_id =
00109         (31 << 24) |    // Priority
00110         (200 << 16) |   // Service Type ID
00111         (1 << 15) |     // Request Not Response
00112         (0x42 << 8) |   // Destination Node ID
00113         (1 << 7) |      // Service Not Message
00114         (42 << 0);      // Source Node ID
00115 
00116     const std::string payload_string = "hello\x6a"; // SET = 011, TID = 10
00117 
00118     /*
00119      * Parse
00120      */
00121     // Invalid CAN frames
00122     ASSERT_FALSE(frame.parse(CanFrame(can_id | CanFrame::FlagRTR, reinterpret_cast<const uint8_t*>(""), 0)));
00123     ASSERT_FALSE(frame.parse(makeCanFrame(can_id, payload_string, STD)));
00124 
00125     // Valid
00126     ASSERT_TRUE(frame.parse(makeCanFrame(can_id, payload_string, EXT)));
00127 
00128     EXPECT_EQ(TransferID(10), frame.getTransferID());
00129     EXPECT_FALSE(frame.isStartOfTransfer());
00130     EXPECT_TRUE(frame.isEndOfTransfer());
00131     EXPECT_TRUE(frame.getToggle());
00132     EXPECT_EQ(uavcan::NodeID(42), frame.getSrcNodeID());
00133     EXPECT_EQ(uavcan::NodeID(0x42), frame.getDstNodeID());
00134     EXPECT_EQ(uavcan::TransferTypeServiceRequest, frame.getTransferType());
00135     EXPECT_EQ(200, frame.getDataTypeID().get());
00136     EXPECT_EQ(31, frame.getPriority().get());
00137 
00138     EXPECT_EQ(payload_string.length(), frame.getPayloadLen() + 1);
00139     EXPECT_TRUE(std::equal(frame.getPayloadPtr(), frame.getPayloadPtr() + frame.getPayloadLen(),
00140                            reinterpret_cast<const uint8_t*>(&payload_string[0])));
00141 
00142     std::cout << frame.toString() << std::endl;
00143 
00144     /*
00145      * Compile
00146      */
00147     CanFrame can_frame;
00148     ASSERT_TRUE(frame.parse(makeCanFrame(can_id, payload_string, EXT)));
00149 
00150     ASSERT_TRUE(frame.compile(can_frame));
00151     ASSERT_EQ(can_frame, makeCanFrame(can_id, payload_string, EXT));
00152 
00153     EXPECT_EQ(payload_string.length(), can_frame.dlc);
00154     EXPECT_TRUE(std::equal(can_frame.data, can_frame.data + can_frame.dlc,
00155                            reinterpret_cast<const uint8_t*>(&payload_string[0])));
00156 
00157     /*
00158      * Comparison
00159      */
00160     ASSERT_FALSE(Frame() == frame);
00161     ASSERT_TRUE(Frame() != frame);
00162     frame = Frame();
00163     ASSERT_TRUE(Frame() == frame);
00164     ASSERT_FALSE(Frame() != frame);
00165 }
00166 
00167 
00168 TEST(Frame, AnonymousParseCompile)
00169 {
00170     using uavcan::Frame;
00171     using uavcan::CanFrame;
00172     using uavcan::TransferID;
00173     using uavcan::TransferType;
00174 
00175     Frame frame;
00176 
00177     /*
00178      * Priority
00179      * Discriminator
00180      * Message Type ID
00181      * Service Not Message
00182      * Source Node ID
00183      */
00184     const uint32_t can_id =
00185         (16383 << 10) | // Discriminator
00186         (1 << 8);       // Message Type ID
00187 
00188     const std::string payload_string = "hello\xd4"; // SET = 110, TID = 20
00189 
00190     uavcan::TransferCRC payload_crc;
00191     payload_crc.add(reinterpret_cast<const uint8_t*>(payload_string.c_str()), unsigned(payload_string.length()));
00192 
00193     /*
00194      * Parse
00195      */
00196     ASSERT_TRUE(frame.parse(makeCanFrame(can_id, payload_string, EXT)));
00197 
00198     EXPECT_EQ(TransferID(20), frame.getTransferID());
00199     EXPECT_TRUE(frame.isStartOfTransfer());
00200     EXPECT_TRUE(frame.isEndOfTransfer());
00201     EXPECT_FALSE(frame.getToggle());
00202     EXPECT_TRUE(frame.getSrcNodeID().isBroadcast());
00203     EXPECT_TRUE(frame.getDstNodeID().isBroadcast());
00204     EXPECT_EQ(uavcan::TransferTypeMessageBroadcast, frame.getTransferType());
00205     EXPECT_EQ(1, frame.getDataTypeID().get());
00206     EXPECT_EQ(0, frame.getPriority().get());
00207 
00208     EXPECT_EQ(payload_string.length() - 1, frame.getPayloadLen());
00209     EXPECT_TRUE(std::equal(frame.getPayloadPtr(), frame.getPayloadPtr() + frame.getPayloadLen(),
00210                            reinterpret_cast<const uint8_t*>(&payload_string[0])));
00211 
00212     std::cout << frame.toString() << std::endl;
00213 
00214     /*
00215      * Compile
00216      */
00217     const uint32_t DiscriminatorMask = 0x00FFFC00;
00218     const uint32_t NoDiscriminatorMask = 0xFF0003FF;
00219 
00220     CanFrame can_frame;
00221     ASSERT_TRUE(frame.parse(makeCanFrame(can_id, payload_string, EXT)));
00222 
00223     ASSERT_TRUE(frame.compile(can_frame));
00224     ASSERT_EQ(can_id & NoDiscriminatorMask & uavcan::CanFrame::MaskExtID,
00225               can_frame.id & NoDiscriminatorMask & uavcan::CanFrame::MaskExtID);
00226 
00227     EXPECT_EQ(payload_string.length(), can_frame.dlc);
00228     EXPECT_TRUE(std::equal(can_frame.data, can_frame.data + can_frame.dlc,
00229                            reinterpret_cast<const uint8_t*>(&payload_string[0])));
00230 
00231     EXPECT_EQ((can_frame.id & DiscriminatorMask & uavcan::CanFrame::MaskExtID) >> 10, payload_crc.get() & 16383);
00232 
00233     /*
00234      * Comparison
00235      */
00236     ASSERT_FALSE(Frame() == frame);
00237     ASSERT_TRUE(Frame() != frame);
00238     frame = Frame();
00239     ASSERT_TRUE(Frame() == frame);
00240     ASSERT_FALSE(Frame() != frame);
00241 }
00242 
00243 
00244 TEST(Frame, FrameParsing)
00245 {
00246     using uavcan::Frame;
00247     using uavcan::CanFrame;
00248     using uavcan::NodeID;
00249     using uavcan::TransferID;
00250 
00251     CanFrame can;
00252     Frame frame;
00253     ASSERT_FALSE(frame.parse(can));
00254 
00255     for (unsigned i = 0; i < sizeof(CanFrame::data); i++)
00256     {
00257         can.data[i] = uint8_t(i | (i << 4));
00258     }
00259 
00260     /*
00261      * Message CAN ID fields and offsets:
00262      *   24 Priority
00263      *   8  Message Type ID
00264      *   7  Service Not Message (0)
00265      *   0  Source Node ID
00266      *
00267      * Service CAN ID fields and offsets:
00268      *   24 Priority
00269      *   16 Service Type ID
00270      *   15 Request Not Response
00271      *   8  Destination Node ID
00272      *   7  Service Not Message (1)
00273      *   0  Source Node ID
00274      */
00275 
00276     /*
00277      * SFT message broadcast
00278      */
00279     can.id = CanFrame::FlagEFF |
00280              (2 << 24) |
00281              (456 << 8) |
00282              (0 << 7) |
00283              (42 << 0);
00284 
00285     can.data[7] = 0xcf; // SET=110, TID=0
00286 
00287     ASSERT_FALSE(frame.parse(can));
00288     can.dlc = 8;
00289 
00290     ASSERT_TRUE(frame.parse(can));
00291     EXPECT_TRUE(frame.isStartOfTransfer());
00292     EXPECT_TRUE(frame.isEndOfTransfer());
00293     EXPECT_FALSE(frame.getToggle());
00294     ASSERT_EQ(2, frame.getPriority().get());
00295     ASSERT_EQ(NodeID(42), frame.getSrcNodeID());
00296     ASSERT_EQ(NodeID::Broadcast, frame.getDstNodeID());
00297     ASSERT_EQ(456, frame.getDataTypeID().get());
00298     ASSERT_EQ(TransferID(15), frame.getTransferID());
00299     ASSERT_EQ(uavcan::TransferTypeMessageBroadcast, frame.getTransferType());
00300 
00301     // TODO: test service frames
00302     // TODO: test malformed frames
00303 }
00304 
00305 
00306 TEST(Frame, RxFrameParse)
00307 {
00308     using uavcan::Frame;
00309     using uavcan::RxFrame;
00310     using uavcan::CanFrame;
00311     using uavcan::CanRxFrame;
00312 
00313     CanRxFrame can_rx_frame;
00314     RxFrame rx_frame;
00315 
00316     // Failure
00317     ASSERT_FALSE(rx_frame.parse(can_rx_frame));
00318 
00319     // Valid
00320     can_rx_frame.ts_mono = uavcan::MonotonicTime::fromUSec(1);  // Zero is not allowed
00321     can_rx_frame.id = CanFrame::FlagEFF |
00322         (2 << 24) |
00323         (456 << 8) |
00324         (0 << 7) |
00325         (42 << 0);
00326 
00327     ASSERT_FALSE(rx_frame.parse(can_rx_frame));
00328 
00329     can_rx_frame.data[0] = 0xc0; // SOT, EOT
00330     can_rx_frame.dlc = 1;
00331 
00332     ASSERT_TRUE(rx_frame.parse(can_rx_frame));
00333     ASSERT_EQ(1, rx_frame.getMonotonicTimestamp().toUSec());
00334     ASSERT_EQ(0, rx_frame.getIfaceIndex());
00335 
00336     can_rx_frame.ts_mono = tsMono(123);
00337     can_rx_frame.iface_index = 2;
00338 
00339     Frame frame(456, uavcan::TransferTypeMessageBroadcast, 1, uavcan::NodeID::Broadcast, 0);
00340     ASSERT_TRUE(frame.compile(can_rx_frame));
00341 
00342     ASSERT_TRUE(rx_frame.parse(can_rx_frame));
00343     ASSERT_EQ(123, rx_frame.getMonotonicTimestamp().toUSec());
00344     ASSERT_EQ(2, rx_frame.getIfaceIndex());
00345     ASSERT_EQ(456, rx_frame.getDataTypeID().get());
00346     ASSERT_EQ(uavcan::TransferTypeMessageBroadcast, rx_frame.getTransferType());
00347 }
00348 
00349 
00350 TEST(Frame, FrameToString)
00351 {
00352     using uavcan::Frame;
00353     using uavcan::RxFrame;
00354 
00355     // RX frame default
00356     RxFrame rx_frame;
00357     EXPECT_EQ("prio=255 dtid=65535 tt=3 snid=255 dnid=255 sot=0 eot=0 togl=0 tid=0 payload=[] ts_m=0.000000 ts_utc=0.000000 iface=0",
00358               rx_frame.toString());
00359 
00360     // RX frame max len
00361     rx_frame = RxFrame(Frame(uavcan::DataTypeID::MaxPossibleDataTypeIDValue, uavcan::TransferTypeMessageBroadcast,
00362                              uavcan::NodeID::Max, 0, uavcan::TransferID::Max),
00363                        uavcan::MonotonicTime::getMax(), uavcan::UtcTime::getMax(), 3);
00364 
00365     uint8_t data[8];
00366     for (unsigned i = 0; i < sizeof(data); i++)
00367     {
00368         data[i] = uint8_t(i);
00369     }
00370     rx_frame.setPayload(data, sizeof(data));
00371 
00372     rx_frame.setStartOfTransfer(true);
00373     rx_frame.setEndOfTransfer(true);
00374     rx_frame.flipToggle();
00375     rx_frame.setPriority(uavcan::TransferPriority::NumericallyMax);
00376 
00377     EXPECT_EQ("prio=31 dtid=65535 tt=2 snid=127 dnid=0 sot=1 eot=1 togl=1 tid=31 payload=[00 01 02 03 04 05 06] "
00378               "ts_m=18446744073709.551615 ts_utc=18446744073709.551615 iface=3",
00379               rx_frame.toString());
00380 
00381     // Plain frame default
00382     Frame frame;
00383     EXPECT_EQ("prio=255 dtid=65535 tt=3 snid=255 dnid=255 sot=0 eot=0 togl=0 tid=0 payload=[]", frame.toString());
00384 
00385     // Plain frame max len
00386     frame = rx_frame;
00387     EXPECT_EQ("prio=31 dtid=65535 tt=2 snid=127 dnid=0 sot=1 eot=1 togl=1 tid=31 payload=[00 01 02 03 04 05 06]",
00388               frame.toString());
00389 }