TEST(Frame, FrameParsing) { using uavcan::Frame; using uavcan::CanFrame; using uavcan::NodeID; using uavcan::TransferID; CanFrame can; Frame frame; ASSERT_FALSE(frame.parse(can)); for (unsigned i = 0; i < sizeof(CanFrame::data); i++) { can.data[i] = uint8_t(i | (i << 4)); } /* * Message CAN ID fields and offsets: * 24 Priority * 8 Message Type ID * 7 Service Not Message (0) * 0 Source Node ID * * Service CAN ID fields and offsets: * 24 Priority * 16 Service Type ID * 15 Request Not Response * 8 Destination Node ID * 7 Service Not Message (1) * 0 Source Node ID */ /* * SFT message broadcast */ can.id = CanFrame::FlagEFF | (2 << 24) | (456 << 8) | (0 << 7) | (42 << 0); can.data[7] = 0xcf; // SET=110, TID=0 ASSERT_FALSE(frame.parse(can)); can.dlc = 8; ASSERT_TRUE(frame.parse(can)); EXPECT_TRUE(frame.isStartOfTransfer()); EXPECT_TRUE(frame.isEndOfTransfer()); EXPECT_FALSE(frame.getToggle()); ASSERT_EQ(2, frame.getPriority().get()); ASSERT_EQ(NodeID(42), frame.getSrcNodeID()); ASSERT_EQ(NodeID::Broadcast, frame.getDstNodeID()); ASSERT_EQ(456, frame.getDataTypeID().get()); ASSERT_EQ(TransferID(15), frame.getTransferID()); ASSERT_EQ(uavcan::TransferTypeMessageBroadcast, frame.getTransferType()); // TODO: test service frames // TODO: test malformed frames }
int Dispatcher::send(const Frame& frame, MonotonicTime tx_deadline, MonotonicTime blocking_deadline, CanTxQueue::Qos qos, CanIOFlags flags, uint8_t iface_mask) { if (frame.getSrcNodeID() != getNodeID()) { UAVCAN_ASSERT(0); return -ErrLogic; } CanFrame can_frame; if (!frame.compile(can_frame)) { UAVCAN_TRACE("Dispatcher", "Unable to send: frame is malformed: %s", frame.toString().c_str()); UAVCAN_ASSERT(0); return -ErrLogic; } return canio_.send(can_frame, tx_deadline, blocking_deadline, iface_mask, qos, flags); }
TEST(Frame, ServiceParseCompile) { using uavcan::Frame; using uavcan::CanFrame; using uavcan::TransferID; using uavcan::TransferType; Frame frame; /* * Priority * Service Type ID * Request Not Response * Destination Node ID * Service Not Message * Source Node ID */ const uint32_t can_id = (31 << 24) | // Priority (200 << 16) | // Service Type ID (1 << 15) | // Request Not Response (0x42 << 8) | // Destination Node ID (1 << 7) | // Service Not Message (42 << 0); // Source Node ID const std::string payload_string = "hello\x6a"; // SET = 011, TID = 10 /* * Parse */ // Invalid CAN frames ASSERT_FALSE(frame.parse(CanFrame(can_id | CanFrame::FlagRTR, (const uint8_t*)"", 0))); ASSERT_FALSE(frame.parse(makeCanFrame(can_id, payload_string, STD))); // Valid ASSERT_TRUE(frame.parse(makeCanFrame(can_id, payload_string, EXT))); EXPECT_EQ(TransferID(10), frame.getTransferID()); EXPECT_FALSE(frame.isStartOfTransfer()); EXPECT_TRUE(frame.isEndOfTransfer()); EXPECT_TRUE(frame.getToggle()); EXPECT_EQ(uavcan::NodeID(42), frame.getSrcNodeID()); EXPECT_EQ(uavcan::NodeID(0x42), frame.getDstNodeID()); EXPECT_EQ(uavcan::TransferTypeServiceRequest, frame.getTransferType()); EXPECT_EQ(200, frame.getDataTypeID().get()); EXPECT_EQ(31, frame.getPriority().get()); EXPECT_EQ(payload_string.length(), frame.getPayloadLen() + 1); EXPECT_TRUE(std::equal(frame.getPayloadPtr(), frame.getPayloadPtr() + frame.getPayloadLen(), reinterpret_cast<const uint8_t*>(&payload_string[0]))); std::cout << frame.toString() << std::endl; /* * Compile */ CanFrame can_frame; ASSERT_TRUE(frame.parse(makeCanFrame(can_id, payload_string, EXT))); ASSERT_TRUE(frame.compile(can_frame)); ASSERT_EQ(can_frame, makeCanFrame(can_id, payload_string, EXT)); EXPECT_EQ(payload_string.length(), can_frame.dlc); EXPECT_TRUE(std::equal(can_frame.data, can_frame.data + can_frame.dlc, reinterpret_cast<const uint8_t*>(&payload_string[0]))); /* * Comparison */ ASSERT_FALSE(Frame() == frame); ASSERT_TRUE(Frame() != frame); frame = Frame(); ASSERT_TRUE(Frame() == frame); ASSERT_FALSE(Frame() != frame); }
TEST(Frame, AnonymousParseCompile) { using uavcan::Frame; using uavcan::CanFrame; using uavcan::TransferID; using uavcan::TransferType; Frame frame; /* * Priority * Discriminator * Message Type ID * Service Not Message * Source Node ID */ const uint32_t can_id = (16383 << 10) | // Discriminator (1 << 8); // Message Type ID const std::string payload_string = "hello\xd4"; // SET = 110, TID = 20 uavcan::TransferCRC payload_crc; payload_crc.add(reinterpret_cast<const uint8_t*>(payload_string.c_str()), unsigned(payload_string.length())); /* * Parse */ ASSERT_TRUE(frame.parse(makeCanFrame(can_id, payload_string, EXT))); EXPECT_EQ(TransferID(20), frame.getTransferID()); EXPECT_TRUE(frame.isStartOfTransfer()); EXPECT_TRUE(frame.isEndOfTransfer()); EXPECT_FALSE(frame.getToggle()); EXPECT_TRUE(frame.getSrcNodeID().isBroadcast()); EXPECT_TRUE(frame.getDstNodeID().isBroadcast()); EXPECT_EQ(uavcan::TransferTypeMessageBroadcast, frame.getTransferType()); EXPECT_EQ(1, frame.getDataTypeID().get()); EXPECT_EQ(0, frame.getPriority().get()); EXPECT_EQ(payload_string.length() - 1, frame.getPayloadLen()); EXPECT_TRUE(std::equal(frame.getPayloadPtr(), frame.getPayloadPtr() + frame.getPayloadLen(), reinterpret_cast<const uint8_t*>(&payload_string[0]))); std::cout << frame.toString() << std::endl; /* * Compile */ const uint32_t DiscriminatorMask = 0x00FFFC00; const uint32_t NoDiscriminatorMask = 0xFF0003FF; CanFrame can_frame; ASSERT_TRUE(frame.parse(makeCanFrame(can_id, payload_string, EXT))); ASSERT_TRUE(frame.compile(can_frame)); ASSERT_EQ(can_id & NoDiscriminatorMask & uavcan::CanFrame::MaskExtID, can_frame.id & NoDiscriminatorMask & uavcan::CanFrame::MaskExtID); EXPECT_EQ(payload_string.length(), can_frame.dlc); EXPECT_TRUE(std::equal(can_frame.data, can_frame.data + can_frame.dlc, reinterpret_cast<const uint8_t*>(&payload_string[0]))); EXPECT_EQ((can_frame.id & DiscriminatorMask & uavcan::CanFrame::MaskExtID) >> 10, payload_crc.get() & 16383); /* * Comparison */ ASSERT_FALSE(Frame() == frame); ASSERT_TRUE(Frame() != frame); frame = Frame(); ASSERT_TRUE(Frame() == frame); ASSERT_FALSE(Frame() != frame); }
TEST(Frame, MessageParseCompile) { using uavcan::Frame; using uavcan::CanFrame; using uavcan::TransferID; using uavcan::TransferType; Frame frame; /* * Priority * Message Type ID * Service Not Message * Source Node ID */ const uint32_t can_id = (16 << 24) | // Priority (20000 << 8) | // Message Type ID (0 << 7) | // Service Not Message (42 << 0); // Source Node ID const std::string payload_string = "hello\xD4"; // SET = 110, TID = 20 /* * Parse */ // Invalid CAN frames ASSERT_FALSE(frame.parse(CanFrame(can_id | CanFrame::FlagRTR, (const uint8_t*)"", 0))); ASSERT_FALSE(frame.parse(makeCanFrame(can_id, payload_string, STD))); // Valid ASSERT_TRUE(frame.parse(makeCanFrame(can_id, payload_string, EXT))); EXPECT_EQ(TransferID(20), frame.getTransferID()); EXPECT_TRUE(frame.isStartOfTransfer()); EXPECT_TRUE(frame.isEndOfTransfer()); EXPECT_FALSE(frame.getToggle()); EXPECT_EQ(uavcan::NodeID(42), frame.getSrcNodeID()); EXPECT_TRUE(frame.getDstNodeID().isBroadcast()); EXPECT_EQ(uavcan::TransferTypeMessageBroadcast, frame.getTransferType()); EXPECT_EQ(20000, frame.getDataTypeID().get()); EXPECT_EQ(16, frame.getPriority().get()); EXPECT_EQ(payload_string.length() - 1, frame.getPayloadLen()); EXPECT_TRUE(std::equal(frame.getPayloadPtr(), frame.getPayloadPtr() + frame.getPayloadLen(), payload_string.begin())); std::cout << frame.toString() << std::endl; /* * Compile */ CanFrame can_frame; ASSERT_TRUE(frame.parse(makeCanFrame(can_id, payload_string, EXT))); ASSERT_TRUE(frame.compile(can_frame)); ASSERT_EQ(can_frame, makeCanFrame(can_id, payload_string, EXT)); EXPECT_EQ(payload_string.length(), can_frame.dlc); std::cout << can_frame.toString() << std::endl; /* * FUN FACT: comparison of uint8_t with char may fail on the character 0xD4 (depending on the locale), * because it will be considered a Unicode character. Hence, we do reinterpret_cast<>. */ EXPECT_TRUE(std::equal(can_frame.data, can_frame.data + can_frame.dlc, reinterpret_cast<const uint8_t*>(&payload_string[0]))); /* * Comparison */ ASSERT_FALSE(Frame() == frame); ASSERT_TRUE(Frame() != frame); frame = Frame(); ASSERT_TRUE(Frame() == frame); ASSERT_FALSE(Frame() != frame); }