diff --git a/libs/acn/LLRPProbeReplyPDU.cpp b/libs/acn/LLRPProbeReplyPDU.cpp index 830766fd8..f92ad721b 100644 --- a/libs/acn/LLRPProbeReplyPDU.cpp +++ b/libs/acn/LLRPProbeReplyPDU.cpp @@ -32,6 +32,27 @@ using ola::network::HostToNetwork; using ola::network::MACAddress; using ola::rdm::UID; +bool LLRPProbeReplyPDU::PackData(uint8_t *data, unsigned int *length) const { + llrp_probe_reply_pdu_data pdu_data; + m_target_uid.Pack(pdu_data.target_uid, sizeof(pdu_data.target_uid)); + m_hardware_address.Pack(pdu_data.hardware_address, + sizeof(pdu_data.hardware_address)); + pdu_data.type = HostToNetwork(static_cast(m_type)); + + *length = sizeof(llrp_probe_reply_pdu_data); + memcpy(data, &pdu_data, *length); + return true; +} + +void LLRPProbeReplyPDU::PackData(ola::io::OutputStream *stream) const { + llrp_probe_reply_pdu_data data; + m_target_uid.Pack(data.target_uid, sizeof(data.target_uid)); + m_hardware_address.Pack(data.hardware_address, sizeof(data.hardware_address)); + data.type = HostToNetwork(static_cast(m_type)); + stream->Write(reinterpret_cast(&data), + static_cast(sizeof(llrp_probe_reply_pdu_data))); +} + void LLRPProbeReplyPDU::PrependPDU(ola::io::IOStack *stack, const UID &target_uid, const MACAddress &hardware_address, diff --git a/libs/acn/LLRPProbeReplyPDU.h b/libs/acn/LLRPProbeReplyPDU.h index 08bbc5583..96b064415 100644 --- a/libs/acn/LLRPProbeReplyPDU.h +++ b/libs/acn/LLRPProbeReplyPDU.h @@ -30,7 +30,7 @@ namespace ola { namespace acn { -class LLRPProbeReplyPDU : private PDU { +class LLRPProbeReplyPDU : public PDU { public: typedef enum { LLRP_COMPONENT_TYPE_RPT_DEVICE = 0, /**< Device */ @@ -39,6 +39,27 @@ class LLRPProbeReplyPDU : private PDU { LLRP_COMPONENT_TYPE_NON_RDMNET = 0xff, /**< Non-RDMnet */ } LLRPComponentType; + explicit LLRPProbeReplyPDU(unsigned int vector, + const ola::rdm::UID &target_uid, + const ola::network::MACAddress &hardware_address, + const LLRPComponentType type): + PDU(vector, ONE_BYTE, true), + m_target_uid(target_uid), + m_hardware_address(hardware_address), + m_type(type) {} + + unsigned int HeaderSize() const { return 0; } + bool PackHeader(OLA_UNUSED uint8_t *data, + unsigned int *length) const { + *length = 0; + return true; + } + void PackHeader(OLA_UNUSED ola::io::OutputStream *stream) const {} + + unsigned int DataSize() const { return sizeof(llrp_probe_reply_pdu_data); } + bool PackData(uint8_t *data, unsigned int *length) const; + void PackData(ola::io::OutputStream *stream) const; + static void PrependPDU(ola::io::IOStack *stack, const ola::rdm::UID &target_uid, const ola::network::MACAddress &hardware_address, @@ -53,6 +74,11 @@ class LLRPProbeReplyPDU : private PDU { uint8_t type; }); typedef struct llrp_probe_reply_pdu_data_s llrp_probe_reply_pdu_data; + + private: + const ola::rdm::UID m_target_uid; + const ola::network::MACAddress m_hardware_address; + const LLRPComponentType m_type; }; } // namespace acn } // namespace ola diff --git a/libs/acn/LLRPProbeReplyPDUTest.cpp b/libs/acn/LLRPProbeReplyPDUTest.cpp index 2ae354c47..1ce2ca86f 100644 --- a/libs/acn/LLRPProbeReplyPDUTest.cpp +++ b/libs/acn/LLRPProbeReplyPDUTest.cpp @@ -23,7 +23,9 @@ #include #include "ola/Logging.h" +#include "ola/io/IOQueue.h" #include "ola/io/IOStack.h" +#include "ola/io/OutputStream.h" #include "ola/network/NetworkUtils.h" #include "ola/rdm/UID.h" #include "ola/rdm/UIDSet.h" @@ -35,16 +37,23 @@ namespace ola { namespace acn { using ola::acn::LLRPProbeReplyPDU; +using ola::io::IOQueue; using ola::io::IOStack; +using ola::io::OutputStream; +using ola::network::HostToNetwork; using ola::network::MACAddress; using ola::rdm::UID; class LLRPProbeReplyPDUTest: public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(LLRPProbeReplyPDUTest); + CPPUNIT_TEST(testSimpleLLRPProbeReplyPDU); + CPPUNIT_TEST(testSimpleLLRPProbeReplyPDUToOutputStream); CPPUNIT_TEST(testPrepend); CPPUNIT_TEST_SUITE_END(); public: + void testSimpleLLRPProbeReplyPDU(); + void testSimpleLLRPProbeReplyPDUToOutputStream(); void testPrepend(); private: @@ -53,6 +62,98 @@ class LLRPProbeReplyPDUTest: public CppUnit::TestFixture { CPPUNIT_TEST_SUITE_REGISTRATION(LLRPProbeReplyPDUTest); +const unsigned int LLRPProbeReplyPDUTest::TEST_VECTOR = 39; + + +/* + * Test that packing a LLRPProbeReplyPDU works. + */ +void LLRPProbeReplyPDUTest::testSimpleLLRPProbeReplyPDU() { + UID target_uid = UID(0x4321, 0x12345678); + MACAddress hardware_address; + MACAddress::FromString("01:23:45:67:89:ab", &hardware_address); + LLRPProbeReplyPDU pdu( + TEST_VECTOR, + target_uid, + hardware_address, + LLRPProbeReplyPDU::LLRP_COMPONENT_TYPE_NON_RDMNET); + + OLA_ASSERT_EQ(0u, pdu.HeaderSize()); + OLA_ASSERT_EQ(13u, pdu.DataSize()); + OLA_ASSERT_EQ(17u, pdu.Size()); + + unsigned int size = pdu.Size(); + uint8_t *data = new uint8_t[size]; + unsigned int bytes_used = size; + OLA_ASSERT(pdu.Pack(data, &bytes_used)); + OLA_ASSERT_EQ(size, bytes_used); + + // spot check the data + OLA_ASSERT_EQ((uint8_t) 0xf0, data[0]); + // bytes_used is technically data[1] and data[2] if > 255 + OLA_ASSERT_EQ((uint8_t) bytes_used, data[2]); + OLA_ASSERT_EQ(HostToNetwork((uint8_t) TEST_VECTOR), data[3]); + + uint8_t buffer[UID::LENGTH]; + target_uid.Pack(buffer, sizeof(buffer)); + OLA_ASSERT_DATA_EQUALS(&data[4], UID::LENGTH, buffer, sizeof(buffer)); + uint8_t buffer2[MACAddress::LENGTH]; + hardware_address.Pack(buffer2, sizeof(buffer2)); + OLA_ASSERT_DATA_EQUALS(&data[10], MACAddress::LENGTH, + buffer2, sizeof(buffer2)); + + // test undersized buffer + bytes_used = size - 1; + OLA_ASSERT_FALSE(pdu.Pack(data, &bytes_used)); + OLA_ASSERT_EQ(0u, bytes_used); + + // test oversized buffer + bytes_used = size + 1; + OLA_ASSERT(pdu.Pack(data, &bytes_used)); + OLA_ASSERT_EQ(size, bytes_used); + delete[] data; +} + + +/* + * Test that writing to an output stream works. + */ +void LLRPProbeReplyPDUTest::testSimpleLLRPProbeReplyPDUToOutputStream() { + UID target_uid = UID(0x4321, 0x12345678); + MACAddress hardware_address; + MACAddress::FromString("01:23:45:67:89:ab", &hardware_address); + LLRPProbeReplyPDU pdu( + TEST_VECTOR, + target_uid, + hardware_address, + LLRPProbeReplyPDU::LLRP_COMPONENT_TYPE_NON_RDMNET); + + OLA_ASSERT_EQ(0u, pdu.HeaderSize()); + OLA_ASSERT_EQ(13u, pdu.DataSize()); + OLA_ASSERT_EQ(17u, pdu.Size()); + + IOQueue output; + OutputStream stream(&output); + pdu.Write(&stream); + OLA_ASSERT_EQ(17u, output.Size()); + + uint8_t *pdu_data = new uint8_t[output.Size()]; + unsigned int pdu_size = output.Peek(pdu_data, output.Size()); + OLA_ASSERT_EQ(output.Size(), pdu_size); + + uint8_t EXPECTED[] = { + 0xf0, 0x00, 0x11, + 39, + 0x43, 0x21, 0x12, 0x34, 0x56, 0x78, + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, + 0xff + }; + OLA_ASSERT_DATA_EQUALS(EXPECTED, sizeof(EXPECTED), pdu_data, pdu_size); + output.Pop(output.Size()); + delete[] pdu_data; +} + + void LLRPProbeReplyPDUTest::testPrepend() { IOStack stack; UID target_uid = UID(0x4321, 0x12345678); diff --git a/libs/acn/MessageBuilder.cpp b/libs/acn/MessageBuilder.cpp index 41d352539..0216cfed6 100644 --- a/libs/acn/MessageBuilder.cpp +++ b/libs/acn/MessageBuilder.cpp @@ -25,6 +25,7 @@ #include "ola/e133/MessageBuilder.h" #include "ola/io/IOStack.h" #include "ola/rdm/RDMCommandSerializer.h" +#include "ola/rdm/UID.h" #include "libs/acn/BrokerPDU.h" #include "libs/acn/E133PDU.h" @@ -72,12 +73,27 @@ void MessageBuilder::BuildTCPRDMCommandPDU(IOStack *packet, uint16_t source_endpoint_id, uint16_t destination_endpoint_id, uint32_t sequence_number) { + // TODO(Peter): Potentially need some future way to handle controller + // messages here + ola::rdm::UID rpt_destination_uid = request->DestinationUID(); + if (rpt_destination_uid.IsBroadcast()) { + if (rpt_destination_uid.IsVendorcast()) { + rpt_destination_uid = ola::rdm::UID::RPTVendorcastAddressDevices( + rpt_destination_uid); + } else { + rpt_destination_uid = ola::rdm::UID::RPTAllDevices(); + } + if (destination_endpoint_id != NULL_ENDPOINT) { + // TODO(Peter): Should we handle the reserved endpoints now? + destination_endpoint_id = BROADCAST_ENDPOINT; + } + } ola::rdm::RDMCommandSerializer::Write(*request, packet); ola::acn::RDMPDU::PrependPDU(packet); ola::acn::RPTRequestPDU::PrependPDU(packet); RPTPDU::PrependPDU(packet, ola::acn::VECTOR_RPT_REQUEST, request->SourceUID(), source_endpoint_id, - request->DestinationUID(), destination_endpoint_id, + rpt_destination_uid, destination_endpoint_id, sequence_number); RootPDU::PrependPDU(packet, ola::acn::VECTOR_ROOT_RPT, m_cid, true); PreamblePacker::AddTCPPreamble(packet);