From 23a00bbc5ce89055c08bda9c342449fcfbade2fd Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Wed, 29 Jan 2020 18:58:52 +0000 Subject: [PATCH 01/71] First attempt at LLRP header and PDU All there apart from flags should always be 0xF0 rather than 0x70 --- include/ola/acn/ACNVectors.h | 3 + libs/acn/HeaderSet.h | 8 +- libs/acn/LLRPHeader.h | 69 ++++++++++++++++ libs/acn/LLRPInflator.cpp | 70 ++++++++++++++++ libs/acn/LLRPInflator.h | 58 ++++++++++++++ libs/acn/LLRPInflatorTest.cpp | 126 +++++++++++++++++++++++++++++ libs/acn/LLRPPDU.cpp | 117 +++++++++++++++++++++++++++ libs/acn/LLRPPDU.h | 62 ++++++++++++++ libs/acn/LLRPPDUTest.cpp | 147 ++++++++++++++++++++++++++++++++++ libs/acn/Makefile.mk | 14 ++++ 10 files changed, 673 insertions(+), 1 deletion(-) create mode 100644 libs/acn/LLRPHeader.h create mode 100644 libs/acn/LLRPInflator.cpp create mode 100644 libs/acn/LLRPInflator.h create mode 100644 libs/acn/LLRPInflatorTest.cpp create mode 100644 libs/acn/LLRPPDU.cpp create mode 100644 libs/acn/LLRPPDU.h create mode 100644 libs/acn/LLRPPDUTest.cpp diff --git a/include/ola/acn/ACNVectors.h b/include/ola/acn/ACNVectors.h index 26c94da543..028c0e264b 100644 --- a/include/ola/acn/ACNVectors.h +++ b/include/ola/acn/ACNVectors.h @@ -47,6 +47,9 @@ enum RootVector { VECTOR_ROOT_E131 = 4, /**< E1.31 (sACN) */ VECTOR_ROOT_E133 = 5, /**< E1.33 (RDNNet) */ VECTOR_ROOT_NULL = 6, /**< NULL (empty) root */ + VECTOR_ROOT_BROKER = 9, /**< E1.33 (Broker) */ + VECTOR_ROOT_LLRP = 0x0A, /**< E1.33 (LLRP) */ + VECTOR_ROOT_EPT = 0x0B, /**< E1.33 (EPT) */ }; /** diff --git a/libs/acn/HeaderSet.h b/libs/acn/HeaderSet.h index c3e9a44f98..06a56c26aa 100644 --- a/libs/acn/HeaderSet.h +++ b/libs/acn/HeaderSet.h @@ -26,6 +26,7 @@ #include "libs/acn/DMPHeader.h" #include "libs/acn/E131Header.h" #include "libs/acn/E133Header.h" +#include "libs/acn/LLRPHeader.h" #include "libs/acn/RootHeader.h" #include "libs/acn/TransportHeader.h" @@ -56,13 +57,17 @@ class HeaderSet { const DMPHeader &GetDMPHeader() const { return m_dmp_header; } void SetDMPHeader(const DMPHeader &header) { m_dmp_header = header; } + const LLRPHeader &GetLLRPHeader() const { return m_llrp_header; } + void SetLLRPHeader(const LLRPHeader &header) { m_llrp_header = header; } + bool operator==(const HeaderSet &other) const { return ( m_transport_header == other.m_transport_header && m_root_header == other.m_root_header && m_e131_header == other.m_e131_header && m_e133_header == other.m_e133_header && - m_dmp_header == other.m_dmp_header); + m_dmp_header == other.m_dmp_header && + m_llrp_header == other.m_llrp_header); } private: @@ -71,6 +76,7 @@ class HeaderSet { E131Header m_e131_header; E133Header m_e133_header; DMPHeader m_dmp_header; + LLRPHeader m_llrp_header; }; } // namespace acn } // namespace ola diff --git a/libs/acn/LLRPHeader.h b/libs/acn/LLRPHeader.h new file mode 100644 index 0000000000..1d964268fd --- /dev/null +++ b/libs/acn/LLRPHeader.h @@ -0,0 +1,69 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * LLRPHeader.h + * The E1.33 LLRP Header + * Copyright (C) 2020 Peter Newman + */ + +#ifndef LIBS_ACN_LLRPHEADER_H_ +#define LIBS_ACN_LLRPHEADER_H_ + +#include +#include + +#include + +namespace ola { +namespace acn { + +/* + * Header for the LLRP layer + */ +class LLRPHeader { + public: + LLRPHeader() + : m_transaction_number(0) { + } + + LLRPHeader(const ola::acn::CID &destination_cid, + uint32_t transaction_number) + : m_destination_cid(destination_cid), + m_transaction_number(transaction_number) { + } + ~LLRPHeader() {} + + const ola::acn::CID DestinationCid() const { return m_destination_cid; } + uint32_t TransactionNumber() const { return m_transaction_number; } + + bool operator==(const LLRPHeader &other) const { + return m_destination_cid == other.m_destination_cid && + m_transaction_number == other.m_transaction_number; + } + + PACK( + struct llrp_pdu_header_s { + uint8_t destination_cid[CID::CID_LENGTH]; + uint32_t transaction_number; + }); + typedef struct llrp_pdu_header_s llrp_pdu_header; + + private: + ola::acn::CID m_destination_cid; + uint32_t m_transaction_number; +}; +} // namespace acn +} // namespace ola +#endif // LIBS_ACN_LLRPHEADER_H_ diff --git a/libs/acn/LLRPInflator.cpp b/libs/acn/LLRPInflator.cpp new file mode 100644 index 0000000000..e629df8d50 --- /dev/null +++ b/libs/acn/LLRPInflator.cpp @@ -0,0 +1,70 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * LLRPInflator.cpp + * The Inflator for E1.33 LLRP + * Copyright (C) 2020 Peter Newman + */ + +#include "ola/Logging.h" +#include "ola/network/NetworkUtils.h" +#include "libs/acn/LLRPInflator.h" + +namespace ola { +namespace acn { + +using ola::network::NetworkToHost; + +/* + * Decode the E1.33 LLRP headers. If data is null we're expected to use the + * last header we got. + * @param headers the HeaderSet to add to + * @param data a pointer to the data + * @param length length of the data + * @returns true if successful, false otherwise + */ +bool LLRPInflator::DecodeHeader(HeaderSet *headers, + const uint8_t *data, + unsigned int length, + unsigned int *bytes_used) { + if (data) { + // the header bit was set, decode it + if (length >= sizeof(LLRPHeader::llrp_pdu_header)) { + LLRPHeader::llrp_pdu_header raw_header; + memcpy(&raw_header, data, sizeof(LLRPHeader::llrp_pdu_header)); + LLRPHeader header( + ola::acn::CID::FromData(raw_header.destination_cid), + NetworkToHost(raw_header.transaction_number)); + m_last_header = header; + m_last_header_valid = true; + headers->SetLLRPHeader(header); + *bytes_used = sizeof(LLRPHeader::llrp_pdu_header); + return true; + } + *bytes_used = 0; + return false; + } + + // use the last header if it exists + *bytes_used = 0; + if (!m_last_header_valid) { + OLA_WARN << "Missing E1.33 LLRP Header data"; + return false; + } + headers->SetLLRPHeader(m_last_header); + return true; +} +} // namespace acn +} // namespace ola diff --git a/libs/acn/LLRPInflator.h b/libs/acn/LLRPInflator.h new file mode 100644 index 0000000000..34a5aa023d --- /dev/null +++ b/libs/acn/LLRPInflator.h @@ -0,0 +1,58 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * LLRPInflator.h + * Interface for the LLRPInflator class. + * Copyright (C) 2020 Peter Newman + */ + +#ifndef LIBS_ACN_LLRPINFLATOR_H_ +#define LIBS_ACN_LLRPINFLATOR_H_ + +#include "ola/acn/ACNVectors.h" +#include "libs/acn/BaseInflator.h" +#include "libs/acn/LLRPHeader.h" + +namespace ola { +namespace acn { + +class LLRPInflator: public BaseInflator { + friend class LLRPInflatorTest; + + public: + LLRPInflator() + : BaseInflator(), + m_last_header_valid(false) { + } + ~LLRPInflator() {} + + uint32_t Id() const { return ola::acn::VECTOR_ROOT_LLRP; } + + protected: + bool DecodeHeader(HeaderSet *headers, + const uint8_t *data, + unsigned int len, + unsigned int *bytes_used); + + void ResetHeaderField() { + m_last_header_valid = false; + } + private: + LLRPHeader m_last_header; + bool m_last_header_valid; +}; +} // namespace acn +} // namespace ola +#endif // LIBS_ACN_LLRPINFLATOR_H_ diff --git a/libs/acn/LLRPInflatorTest.cpp b/libs/acn/LLRPInflatorTest.cpp new file mode 100644 index 0000000000..b36c5cdc05 --- /dev/null +++ b/libs/acn/LLRPInflatorTest.cpp @@ -0,0 +1,126 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * LLRPInflatorTest.cpp + * Test fixture for the LLRPInflator class + * Copyright (C) 2020 Peter Newman + */ + +#include + +#include "ola/Logging.h" +#include "ola/network/NetworkUtils.h" +#include "libs/acn/HeaderSet.h" +#include "libs/acn/PDUTestCommon.h" +#include "libs/acn/LLRPInflator.h" +#include "libs/acn/LLRPPDU.h" +#include "ola/testing/TestUtils.h" + + +namespace ola { +namespace acn { + +using ola::network::HostToNetwork; + +class LLRPInflatorTest: public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(LLRPInflatorTest); + CPPUNIT_TEST(testDecodeHeader); + CPPUNIT_TEST(testInflatePDU); + CPPUNIT_TEST_SUITE_END(); + + public: + void testDecodeHeader(); + void testInflatePDU(); + private: + static const uint8_t TEST_DATA[]; + static const uint8_t TEST_DATA2[]; +}; + +const uint8_t LLRPInflatorTest::TEST_DATA[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15}; +const uint8_t LLRPInflatorTest::TEST_DATA2[] = {10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, + 25}; +CPPUNIT_TEST_SUITE_REGISTRATION(LLRPInflatorTest); + + +/* + * Check that we can decode headers properly + */ +void LLRPInflatorTest::testDecodeHeader() { + LLRPHeader::llrp_pdu_header header; + memset(&header, 0, sizeof(header)); + LLRPInflator inflator; + HeaderSet header_set, header_set2; + unsigned int bytes_used; + const ola::acn::CID destination_cid = CID::FromData(TEST_DATA); + + destination_cid.Pack(header.destination_cid); + header.transaction_number = HostToNetwork(72650u); + + OLA_ASSERT(inflator.DecodeHeader(&header_set, + reinterpret_cast(&header), + sizeof(header), + &bytes_used)); + OLA_ASSERT_EQ((unsigned int) sizeof(header), bytes_used); + LLRPHeader decoded_header = header_set.GetLLRPHeader(); + OLA_ASSERT(destination_cid == decoded_header.DestinationCid()); + OLA_ASSERT_EQ((uint32_t) 72650, decoded_header.TransactionNumber()); + + // try an undersized header + OLA_ASSERT_FALSE(inflator.DecodeHeader( + &header_set, + reinterpret_cast(&header), + static_cast(sizeof(header) - 1), + &bytes_used)); + OLA_ASSERT_EQ((unsigned int) 0, bytes_used); + + // test inheriting the header from the prev call + OLA_ASSERT(inflator.DecodeHeader(&header_set2, NULL, 0, &bytes_used)); + OLA_ASSERT_EQ((unsigned int) 0, bytes_used); + decoded_header = header_set2.GetLLRPHeader(); + OLA_ASSERT(destination_cid == decoded_header.DestinationCid()); + OLA_ASSERT_EQ((uint32_t) 72650, decoded_header.TransactionNumber()); + + inflator.ResetHeaderField(); + OLA_ASSERT_FALSE(inflator.DecodeHeader(&header_set2, NULL, 0, &bytes_used)); + OLA_ASSERT_EQ((unsigned int) 0, bytes_used); +} + + +/* + * Check that we can inflate a LLRP PDU that contains other PDUs + */ +void LLRPInflatorTest::testInflatePDU() { + const ola::acn::CID destination_cid = CID::FromData(TEST_DATA2); + LLRPHeader header(destination_cid, 2370); + // TODO(Peter): pass a different type of msg here as well + LLRPPDU pdu(3, header, NULL); + OLA_ASSERT_EQ((unsigned int) 26, 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((unsigned int) size, bytes_used); + + LLRPInflator inflator; + HeaderSet header_set; + OLA_ASSERT(inflator.InflatePDUBlock(&header_set, data, size)); + OLA_ASSERT(header == header_set.GetLLRPHeader()); + delete[] data; +} +} // namespace acn +} // namespace ola diff --git a/libs/acn/LLRPPDU.cpp b/libs/acn/LLRPPDU.cpp new file mode 100644 index 0000000000..5d8eba531d --- /dev/null +++ b/libs/acn/LLRPPDU.cpp @@ -0,0 +1,117 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * LLRPPDU.cpp + * The LLRPPDU + * Copyright (C) 2020 Peter Newman + */ + + +#include "ola/Logging.h" +#include "ola/base/Array.h" +#include "ola/network/NetworkUtils.h" +#include "libs/acn/LLRPPDU.h" + +namespace ola { +namespace acn { + +using ola::io::OutputStream; +using ola::network::HostToNetwork; + +/* + * Size of the header portion. + */ +unsigned int LLRPPDU::HeaderSize() const { + return sizeof(LLRPHeader::llrp_pdu_header); +} + + +/* + * Size of the data portion + */ +unsigned int LLRPPDU::DataSize() const { + return m_pdu ? m_pdu->Size() : 0; +} + + +/* + * Pack the header portion. + */ +bool LLRPPDU::PackHeader(uint8_t *data, unsigned int *length) const { + unsigned int header_size = HeaderSize(); + + if (*length < header_size) { + OLA_WARN << "LLRPPDU::PackHeader: buffer too small, got " << *length + << " required " << header_size; + *length = 0; + return false; + } + + LLRPHeader::llrp_pdu_header header; + m_header.DestinationCid().Pack(header.destination_cid); + header.transaction_number = HostToNetwork(m_header.TransactionNumber()); + *length = sizeof(LLRPHeader::llrp_pdu_header); + memcpy(data, &header, *length); + return true; +} + + +/* + * Pack the data portion. + */ +bool LLRPPDU::PackData(uint8_t *data, unsigned int *length) const { + if (m_pdu) + return m_pdu->Pack(data, length); + *length = 0; + return true; +} + + +/* + * Pack the header into a buffer. + */ +void LLRPPDU::PackHeader(OutputStream *stream) const { + LLRPHeader::llrp_pdu_header header; + m_header.DestinationCid().Pack(header.destination_cid); + header.transaction_number = HostToNetwork(m_header.TransactionNumber()); + stream->Write(reinterpret_cast(&header), + sizeof(LLRPHeader::llrp_pdu_header)); +} + + +/* + * Pack the data into a buffer + */ +void LLRPPDU::PackData(OutputStream *stream) const { + if (m_pdu) + m_pdu->Write(stream); +} + + +void LLRPPDU::PrependPDU(ola::io::IOStack *stack, uint32_t vector, + const ola::acn::CID &destination_cid, uint32_t transaction_number) { + LLRPHeader::llrp_pdu_header header; + destination_cid.Pack(header.destination_cid); + header.transaction_number = HostToNetwork(transaction_number); + stack->Write(reinterpret_cast(&header), + sizeof(LLRPHeader::llrp_pdu_header)); + + vector = HostToNetwork(vector); + stack->Write(reinterpret_cast(&vector), sizeof(vector)); + // Flags for LLRP should always be 0xF0 + PrependFlagsAndLength(stack, 0xf0); +} +} // namespace acn +} // namespace ola diff --git a/libs/acn/LLRPPDU.h b/libs/acn/LLRPPDU.h new file mode 100644 index 0000000000..76ccdc7d65 --- /dev/null +++ b/libs/acn/LLRPPDU.h @@ -0,0 +1,62 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * LLRPPDU.h + * Interface for the LLRPPDU class + * Copyright (C) 2020 Peter Newman + */ + +#ifndef LIBS_ACN_LLRPPDU_H_ +#define LIBS_ACN_LLRPPDU_H_ + +#include +#include + +#include "libs/acn/PDU.h" +#include "libs/acn/LLRPHeader.h" + +namespace ola { +namespace acn { + +class RDMPDU; + +class LLRPPDU: public PDU { + public: + LLRPPDU(unsigned int vector, + const LLRPHeader &header, + const PDU *pdu): + PDU(vector), + m_header(header), + m_pdu(pdu) {} + ~LLRPPDU() {} + + unsigned int HeaderSize() const; + unsigned int DataSize() const; + bool PackHeader(uint8_t *data, unsigned int *length) const; + bool PackData(uint8_t *data, unsigned int *length) const; + + void PackHeader(ola::io::OutputStream *stream) const; + void PackData(ola::io::OutputStream *stream) const; + + static void PrependPDU(ola::io::IOStack *stack, uint32_t vector, + const ola::acn::CID &destination_cid, uint32_t transaction_number); + + private: + LLRPHeader m_header; + const PDU *m_pdu; +}; +} // namespace acn +} // namespace ola +#endif // LIBS_ACN_LLRPPDU_H_ diff --git a/libs/acn/LLRPPDUTest.cpp b/libs/acn/LLRPPDUTest.cpp new file mode 100644 index 0000000000..b924d8a422 --- /dev/null +++ b/libs/acn/LLRPPDUTest.cpp @@ -0,0 +1,147 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * LLRPPDUTest.cpp + * Test fixture for the LLRPPDU class + * Copyright (C) 2020 Peter Newman + */ + +#include + +#include "ola/Logging.h" +#include "ola/io/IOQueue.h" +#include "ola/io/OutputStream.h" +#include "ola/network/NetworkUtils.h" +#include "ola/testing/TestUtils.h" +#include "libs/acn/LLRPPDU.h" +#include "libs/acn/PDUTestCommon.h" + + +namespace ola { +namespace acn { + +using ola::io::IOQueue; +using ola::io::OutputStream; +using ola::network::HostToNetwork; +using std::string; + +class LLRPPDUTest: public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(LLRPPDUTest); + CPPUNIT_TEST(testSimpleLLRPPDU); + CPPUNIT_TEST(testSimpleLLRPPDUToOutputStream); + CPPUNIT_TEST_SUITE_END(); + + public: + void testSimpleLLRPPDU(); + void testSimpleLLRPPDUToOutputStream(); + + void setUp() { + ola::InitLogging(ola::OLA_LOG_DEBUG, ola::OLA_LOG_STDERR); + } + + private: + static const unsigned int TEST_VECTOR; + static const uint8_t TEST_DATA[]; +}; + +const uint8_t LLRPPDUTest::TEST_DATA[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15}; + +CPPUNIT_TEST_SUITE_REGISTRATION(LLRPPDUTest); + +const unsigned int LLRPPDUTest::TEST_VECTOR = 39; + + +/* + * Test that packing a LLRPPDU without data works. + */ +void LLRPPDUTest::testSimpleLLRPPDU() { + const CID destination_cid = CID::FromData(TEST_DATA); + LLRPHeader header(destination_cid, 101); + LLRPPDU pdu(TEST_VECTOR, header, NULL); + + OLA_ASSERT_EQ(20u, pdu.HeaderSize()); + OLA_ASSERT_EQ(0u, pdu.DataSize()); + OLA_ASSERT_EQ(26u, 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) 0x70, data[0]); + OLA_ASSERT_EQ((uint8_t) bytes_used, data[1]); + unsigned int actual_value; + memcpy(&actual_value, data + 2, sizeof(actual_value)); + OLA_ASSERT_EQ(HostToNetwork(TEST_VECTOR), actual_value); + + uint8_t buffer[CID::CID_LENGTH]; + destination_cid.Pack(buffer); + OLA_ASSERT_FALSE(memcmp(&data[6], buffer, CID::CID_LENGTH)); + // transaction number + OLA_ASSERT_EQ((uint8_t) 0, data[6 + CID::CID_LENGTH]); + OLA_ASSERT_EQ((uint8_t) 0, data[6 + CID::CID_LENGTH + 1]); + OLA_ASSERT_EQ((uint8_t) 0, data[6 + CID::CID_LENGTH + 2]); + OLA_ASSERT_EQ((uint8_t) 101, data[6 + CID::CID_LENGTH + 3]); + + // 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 LLRPPDUTest::testSimpleLLRPPDUToOutputStream() { + const ola::acn::CID destination_cid = CID::FromData(TEST_DATA); + LLRPHeader header(destination_cid, 101); + LLRPPDU pdu(TEST_VECTOR, header, NULL); + + OLA_ASSERT_EQ(20u, pdu.HeaderSize()); + OLA_ASSERT_EQ(0u, pdu.DataSize()); + OLA_ASSERT_EQ(26u, pdu.Size()); + + IOQueue output; + OutputStream stream(&output); + pdu.Write(&stream); + OLA_ASSERT_EQ(26u, 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, 0x1a, + 0, 0, 0, 39, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 0, 0, 0, 101, // transaction number + }; + OLA_ASSERT_DATA_EQUALS(EXPECTED, sizeof(EXPECTED), pdu_data, pdu_size); + output.Pop(output.Size()); + delete[] pdu_data; +} +} // namespace acn +} // namespace ola diff --git a/libs/acn/Makefile.mk b/libs/acn/Makefile.mk index 57bcf5276e..42d91ea17d 100644 --- a/libs/acn/Makefile.mk +++ b/libs/acn/Makefile.mk @@ -61,6 +61,11 @@ libs_acn_libolae131core_la_SOURCES = \ libs/acn/E133StatusPDU.cpp \ libs/acn/E133StatusPDU.h \ libs/acn/HeaderSet.h \ + libs/acn/LLRPHeader.h \ + libs/acn/LLRPInflator.cpp \ + libs/acn/LLRPInflator.h \ + libs/acn/LLRPPDU.cpp \ + libs/acn/LLRPPDU.h \ libs/acn/PDU.cpp \ libs/acn/PDU.h \ libs/acn/PDUTestCommon.h \ @@ -108,6 +113,7 @@ libs_acn_e131_loadtest_LDADD = libs/acn/libolae131core.la test_programs += \ libs/acn/E131Tester \ libs/acn/E133Tester \ + libs/acn/LLRPTester \ libs/acn/TransportTester libs_acn_E131Tester_SOURCES = \ @@ -140,6 +146,14 @@ libs_acn_E133Tester_LDADD = \ libs/acn/libolae131core.la \ $(COMMON_TESTING_LIBS) +libs_acn_LLRPTester_SOURCES = \ + libs/acn/LLRPInflatorTest.cpp \ + libs/acn/LLRPPDUTest.cpp +libs_acn_LLRPTester_CPPFLAGS = $(COMMON_TESTING_FLAGS) +libs_acn_LLRPTester_LDADD = \ + libs/acn/libolae131core.la \ + $(COMMON_TESTING_LIBS) + libs_acn_TransportTester_SOURCES = \ libs/acn/TCPTransportTest.cpp \ libs/acn/UDPTransportTest.cpp From 8524079996d758de6f5f323d897b8a78f523be23 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Mon, 3 Feb 2020 01:56:25 +0000 Subject: [PATCH 02/71] Fix a Doxygen typo --- include/ola/acn/ACNVectors.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ola/acn/ACNVectors.h b/include/ola/acn/ACNVectors.h index 028c0e264b..8523ff2313 100644 --- a/include/ola/acn/ACNVectors.h +++ b/include/ola/acn/ACNVectors.h @@ -64,7 +64,7 @@ enum DMPVector { * @brief Vectors used at the E1.31 layer. */ enum E131Vector { - VECTOR_E131_DATA = 2, /**< DMP data (DATA_PACKET_VECTOR( */ + VECTOR_E131_DATA = 2, /**< DMP data (DATA_PACKET_VECTOR) */ VECTOR_E131_SYNC = 3, /**< Sync data (SYNC_PACKET_VECTOR) */ VECTOR_E131_DISCOVERY = 4, /**< Discovery data (DISCOVERY_PACKET_VECTOR) */ }; From 674ea511416bb3a8d955a1755d5251db6c53deeb Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Mon, 3 Feb 2020 14:30:00 +0000 Subject: [PATCH 03/71] Update some E1.33 Vectors --- include/ola/acn/ACNVectors.h | 11 ++++++++++- libs/acn/E133Inflator.h | 2 +- tools/e133/MessageBuilder.cpp | 4 ++-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/include/ola/acn/ACNVectors.h b/include/ola/acn/ACNVectors.h index 8523ff2313..db99ff2bb8 100644 --- a/include/ola/acn/ACNVectors.h +++ b/include/ola/acn/ACNVectors.h @@ -45,7 +45,7 @@ namespace acn { enum RootVector { VECTOR_ROOT_E131_REV2 = 3, /**< Draft E1.31, used by some old gear. */ VECTOR_ROOT_E131 = 4, /**< E1.31 (sACN) */ - VECTOR_ROOT_E133 = 5, /**< E1.33 (RDNNet) */ + VECTOR_ROOT_RPT = 5, /**< E1.33 (RPT) */ VECTOR_ROOT_NULL = 6, /**< NULL (empty) root */ VECTOR_ROOT_BROKER = 9, /**< E1.33 (Broker) */ VECTOR_ROOT_LLRP = 0x0A, /**< E1.33 (LLRP) */ @@ -89,6 +89,15 @@ enum E133ControllerVector { VECTOR_CONTROLLER_DEVICE_RELEASED = 4, /**< Device released message */ VECTOR_CONTROLLER_EXPECT_MASTER = 5, /**< Expect master message */ }; + +/** + * @brief Vectors used at the E1.33 LLRP layer. + */ +enum LLRPVector { + VECTOR_LLRP_PROBE_REQUEST = 1, /**< LLRP Probe Request */ + VECTOR_LLRP_PROBE_REPLY = 1, /**< LLRP Probe Reply */ + VECTOR_LLRP_RDM_CMD = 1, /**< LLRP RDM Command */ +}; } // namespace acn } // namespace ola diff --git a/libs/acn/E133Inflator.h b/libs/acn/E133Inflator.h index ee7c968f66..d2f57daf66 100644 --- a/libs/acn/E133Inflator.h +++ b/libs/acn/E133Inflator.h @@ -38,7 +38,7 @@ class E133Inflator: public BaseInflator { } ~E133Inflator() {} - uint32_t Id() const { return ola::acn::VECTOR_ROOT_E133; } + uint32_t Id() const { return ola::acn::VECTOR_ROOT_RPT; } protected: bool DecodeHeader(HeaderSet *headers, diff --git a/tools/e133/MessageBuilder.cpp b/tools/e133/MessageBuilder.cpp index d2c6a5143a..a192b45bf0 100644 --- a/tools/e133/MessageBuilder.cpp +++ b/tools/e133/MessageBuilder.cpp @@ -109,7 +109,7 @@ void MessageBuilder::BuildTCPRootE133(IOStack *packet, uint16_t endpoint_id) { E133PDU::PrependPDU(packet, vector, m_source_name, sequence_number, endpoint_id); - RootPDU::PrependPDU(packet, ola::acn::VECTOR_ROOT_E133, m_cid); + RootPDU::PrependPDU(packet, ola::acn::VECTOR_ROOT_RPT, m_cid); PreamblePacker::AddTCPPreamble(packet); } @@ -123,7 +123,7 @@ void MessageBuilder::BuildUDPRootE133(IOStack *packet, uint16_t endpoint_id) { E133PDU::PrependPDU(packet, vector, m_source_name, sequence_number, endpoint_id); - RootPDU::PrependPDU(packet, ola::acn::VECTOR_ROOT_E133, m_cid); + RootPDU::PrependPDU(packet, ola::acn::VECTOR_ROOT_RPT, m_cid); PreamblePacker::AddUDPPreamble(packet); } } // namespace e133 From bd619c2b597cdccaf9df2dbeb2eedeadcba5c0a3 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Tue, 4 Feb 2020 00:07:24 +0000 Subject: [PATCH 04/71] Add the ability to pack UIDSets --- common/rdm/UIDTest.cpp | 15 +++++++++++++-- include/ola/rdm/UIDSet.h | 21 ++++++++++++++++++++- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/common/rdm/UIDTest.cpp b/common/rdm/UIDTest.cpp index 9a09da67a9..e02dfd0751 100644 --- a/common/rdm/UIDTest.cpp +++ b/common/rdm/UIDTest.cpp @@ -105,13 +105,13 @@ void UIDTest::testUID() { OLA_ASSERT_TRUE(uid.Pack(buffer, buffer_size)); uint8_t expected[] = {0, 1, 0, 0, 0, 2}; - OLA_ASSERT_EQ(0, memcmp(expected, buffer, buffer_size)); + OLA_ASSERT_DATA_EQUALS(expected, sizeof(expected), buffer, buffer_size); UID unpacked_uid1(buffer); OLA_ASSERT_EQ(uid, unpacked_uid1); OLA_ASSERT_TRUE(uid3.Pack(buffer, buffer_size)); uint8_t expected2[] = {0, 2, 0, 0, 0, 0x0a}; - OLA_ASSERT_EQ(0, memcmp(expected2, buffer, buffer_size)); + OLA_ASSERT_DATA_EQUALS(expected2, sizeof(expected2), buffer, buffer_size); UID unpacked_uid2(buffer); OLA_ASSERT_EQ(uid3, unpacked_uid2); @@ -234,6 +234,17 @@ void UIDTest::testUIDSet() { difference = set3.SetDifference(set1); OLA_ASSERT_EQ(0u, difference.Size()); + + // now test the packing & unpacking + UID uid3(3, 4); + UIDSet set4(set1); + set4.AddUID(uid3); + unsigned int buffer_size = UID::UID_SIZE * 3; + uint8_t *buffer = new uint8_t[buffer_size]; + OLA_ASSERT_TRUE(set4.Pack(buffer, buffer_size)); + + uint8_t expected[] = {0, 1, 0, 0, 0, 2, 0, 2, 0, 0, 0, 10, 0, 3, 0, 0, 0, 4}; + OLA_ASSERT_DATA_EQUALS(expected, sizeof(expected), buffer, buffer_size); } diff --git a/include/ola/rdm/UIDSet.h b/include/ola/rdm/UIDSet.h index 88b43df66d..a60105b980 100644 --- a/include/ola/rdm/UIDSet.h +++ b/include/ola/rdm/UIDSet.h @@ -87,7 +87,7 @@ class UIDSet { * @return the number of UIDs in the set. */ unsigned int Size() const { - return m_uids.size(); + return static_cast(m_uids.size()); } /** @@ -207,6 +207,25 @@ class UIDSet { return out << uid_set.ToString(); } + /** + * @brief Write the binary representation of the UID to memory. + * @param buffer a pointer to memory to write the UID to + * @param length the size of the memory block, should be at least UID_SIZE. + * @returns true if length was >= UID_SIZE, false otherwise. + */ + bool Pack(uint8_t *buffer, unsigned int length) const { + if (static_cast(length) < (m_uids.size() * UID::UID_SIZE)) { + return false; + } + uint8_t *ptr = buffer; + std::set::const_iterator iter; + for (iter = m_uids.begin(); iter != m_uids.end(); ++iter) { + iter->Pack(ptr, UID::UID_SIZE); + ptr += UID::UID_SIZE; + } + return true; + } + private: std::set m_uids; From a89f3dba7d7d9251a6100c73648edae94e03b443 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Tue, 4 Feb 2020 00:08:55 +0000 Subject: [PATCH 05/71] Fix the Doxygen --- include/ola/rdm/UIDSet.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/include/ola/rdm/UIDSet.h b/include/ola/rdm/UIDSet.h index a60105b980..40ad0a0547 100644 --- a/include/ola/rdm/UIDSet.h +++ b/include/ola/rdm/UIDSet.h @@ -208,10 +208,11 @@ class UIDSet { } /** - * @brief Write the binary representation of the UID to memory. - * @param buffer a pointer to memory to write the UID to - * @param length the size of the memory block, should be at least UID_SIZE. - * @returns true if length was >= UID_SIZE, false otherwise. + * @brief Write the binary representation of the UID set to memory. + * @param buffer a pointer to memory to write the UID set to + * @param length the size of the memory block, should be at least UID_SIZE + * * set size. + * @returns true if length was >= UID_SIZE * set size, false otherwise. */ bool Pack(uint8_t *buffer, unsigned int length) const { if (static_cast(length) < (m_uids.size() * UID::UID_SIZE)) { From 063de3d6bf8dddba2dec06067a3c24df8c141ace Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Tue, 4 Feb 2020 00:09:27 +0000 Subject: [PATCH 06/71] Fix a Doxygen typo --- include/ola/acn/CID.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ola/acn/CID.h b/include/ola/acn/CID.h index 9114f2b468..91c403a5f4 100644 --- a/include/ola/acn/CID.h +++ b/include/ola/acn/CID.h @@ -15,7 +15,7 @@ * * CID.h * The CID class, this just wraps a CIDImpl so we don't need to include all the - * UID headers. + * UUID headers. * Copyright (C) 2007 Simon Newton */ From 0204d595c8f2753e0581d8bb88020a12dddc9ea1 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Tue, 4 Feb 2020 00:14:24 +0000 Subject: [PATCH 07/71] Add the initial LLRPProbeRequestPDU --- include/ola/acn/ACNPort.h | 5 ++ libs/acn/LLRPHeader.h | 2 + libs/acn/LLRPPDU.h | 2 - libs/acn/LLRPProbeRequestPDU.cpp | 62 ++++++++++++++++++++ libs/acn/LLRPProbeRequestPDU.h | 62 ++++++++++++++++++++ libs/acn/LLRPProbeRequestPDUTest.cpp | 85 ++++++++++++++++++++++++++++ libs/acn/Makefile.mk | 5 +- 7 files changed, 220 insertions(+), 3 deletions(-) create mode 100644 libs/acn/LLRPProbeRequestPDU.cpp create mode 100644 libs/acn/LLRPProbeRequestPDU.h create mode 100644 libs/acn/LLRPProbeRequestPDUTest.cpp diff --git a/include/ola/acn/ACNPort.h b/include/ola/acn/ACNPort.h index bef7619c38..97f98a1ab2 100644 --- a/include/ola/acn/ACNPort.h +++ b/include/ola/acn/ACNPort.h @@ -61,6 +61,11 @@ const uint16_t ACN_PORT = 5568; */ const uint16_t E133_PORT = 5569; +/** + * @brief The port used for E1.33 LLRP communication. + */ +const uint16_t LLRP_PORT = 5569; + /** * @} */ diff --git a/libs/acn/LLRPHeader.h b/libs/acn/LLRPHeader.h index 1d964268fd..40a5098c42 100644 --- a/libs/acn/LLRPHeader.h +++ b/libs/acn/LLRPHeader.h @@ -29,6 +29,8 @@ namespace ola { namespace acn { +// TODO(Peter): I think technically this probably shouldn't be a header and +// instead is just data at this level! /* * Header for the LLRP layer */ diff --git a/libs/acn/LLRPPDU.h b/libs/acn/LLRPPDU.h index 76ccdc7d65..67ccf7af58 100644 --- a/libs/acn/LLRPPDU.h +++ b/libs/acn/LLRPPDU.h @@ -30,8 +30,6 @@ namespace ola { namespace acn { -class RDMPDU; - class LLRPPDU: public PDU { public: LLRPPDU(unsigned int vector, diff --git a/libs/acn/LLRPProbeRequestPDU.cpp b/libs/acn/LLRPProbeRequestPDU.cpp new file mode 100644 index 0000000000..6fe5378081 --- /dev/null +++ b/libs/acn/LLRPProbeRequestPDU.cpp @@ -0,0 +1,62 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * LLRPProbeRequestPDU.cpp + * The LLRPProbeRequestPDU + * Copyright (C) 2020 Peter Newman + */ + +#include "libs/acn/LLRPProbeRequestPDU.h" + +#include +#include +#include + +namespace ola { +namespace acn { + +using ola::io::OutputStream; +using ola::network::HostToNetwork; +using ola::rdm::UID; +using std::vector; + +void LLRPProbeRequestPDU::PrependPDU(ola::io::IOStack *stack, + const UID &lower_uid, + const UID &upper_uid, + bool client_tcp_connection_inactive, + bool brokers_only, + const ola::rdm::UIDSet &known_uids) { + llrp_probe_request_pdu_data data; + lower_uid.Pack(data.lower_uid, sizeof(data.lower_uid)); + upper_uid.Pack(data.upper_uid, sizeof(data.upper_uid)); + uint16_t filter = 0; + if (client_tcp_connection_inactive) { + filter |= FILTER_CLIENT_TCP_CONNECTION_INACTIVE; + } + if (brokers_only) { + filter |= FILTER_BROKERS_ONLY; + } + data.filter = HostToNetwork(filter); + known_uids.Pack(data.known_uids, sizeof(data.known_uids)); + stack->Write(reinterpret_cast(&data), + static_cast(sizeof(llrp_probe_request_pdu_data) - + sizeof(data.known_uids) + + (known_uids.Size() * UID::LENGTH))); + uint8_t vector = HostToNetwork(VECTOR_PROBE_REQUEST_DATA); + stack->Write(reinterpret_cast(&vector), sizeof(vector)); + PrependFlagsAndLength(stack); +} +} // namespace acn +} // namespace ola diff --git a/libs/acn/LLRPProbeRequestPDU.h b/libs/acn/LLRPProbeRequestPDU.h new file mode 100644 index 0000000000..34e5ac79e0 --- /dev/null +++ b/libs/acn/LLRPProbeRequestPDU.h @@ -0,0 +1,62 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * LLRPProbeRequestPDU.h + * The LLRPProbeRequestPDU class + * Copyright (C) 2020 Peter Newman + */ + +#ifndef LIBS_ACN_LLRPPROBEREQUESTPDU_H_ +#define LIBS_ACN_LLRPPROBEREQUESTPDU_H_ + +#include +#include +#include + +#include "libs/acn/PDU.h" + +namespace ola { +namespace acn { + +class LLRPProbeRequestPDU : private PDU { + public: + static void PrependPDU(ola::io::IOStack *stack, + const ola::rdm::UID &lower_uid, + const ola::rdm::UID &upper_uid, + bool client_tcp_connection_inactive, + bool brokers_only, + const ola::rdm::UIDSet &known_uids); + + static const uint8_t VECTOR_PROBE_REQUEST_DATA = 0x01; + + static const unsigned int LLRP_KNOWN_UID_SIZE = 200; + + // bit masks for filter + static const uint16_t FILTER_CLIENT_TCP_CONNECTION_INACTIVE = 0x0001; + static const uint16_t FILTER_BROKERS_ONLY = 0x0002; + + private: + PACK( + struct llrp_probe_request_pdu_data_s { + uint8_t lower_uid[ola::rdm::UID::LENGTH]; + uint8_t upper_uid[ola::rdm::UID::LENGTH]; + uint16_t filter; + uint8_t known_uids[ola::rdm::UID::LENGTH * LLRP_KNOWN_UID_SIZE]; + }); + typedef struct llrp_probe_request_pdu_data_s llrp_probe_request_pdu_data; +}; +} // namespace acn +} // namespace ola +#endif // LIBS_ACN_LLRPProbeRequestPDU_H_ diff --git a/libs/acn/LLRPProbeRequestPDUTest.cpp b/libs/acn/LLRPProbeRequestPDUTest.cpp new file mode 100644 index 0000000000..ca6596991c --- /dev/null +++ b/libs/acn/LLRPProbeRequestPDUTest.cpp @@ -0,0 +1,85 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * LLRPProbeRequestPDUTest.cpp + * Test fixture for the LLRPProbeRequestPDU class + * Copyright (C) 2020 Peter Newman + */ + +#include +#include +#include + +#include "ola/Logging.h" +#include "ola/io/IOStack.h" +#include "ola/network/NetworkUtils.h" +#include "ola/rdm/UID.h" +#include "ola/rdm/UIDSet.h" +#include "ola/testing/TestUtils.h" +#include "libs/acn/PDUTestCommon.h" +#include "libs/acn/LLRPProbeRequestPDU.h" + +namespace ola { +namespace acn { + +using ola::io::IOStack; +using ola::rdm::UID; +using ola::rdm::UIDSet; + +class LLRPProbeRequestPDUTest: public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(LLRPProbeRequestPDUTest); + CPPUNIT_TEST(testPrepend); + CPPUNIT_TEST_SUITE_END(); + + public: + void testPrepend(); + + private: + static const unsigned int TEST_VECTOR; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(LLRPProbeRequestPDUTest); + +void LLRPProbeRequestPDUTest::testPrepend() { + IOStack stack; + UIDSet known_uids; + known_uids.AddUID(UID(0x1234, 0x00000001)); + known_uids.AddUID(UID(0x5678, 0x00000002)); + known_uids.AddUID(UID(0x4321, 0x12345678)); + LLRPProbeRequestPDU::PrependPDU(&stack, + UID(0x0000, 0x00000000), + UID(0xffff, 0xffffffff), + false, + false, + known_uids); + + unsigned int length = stack.Size(); + uint8_t *buffer = new uint8_t[length]; + OLA_ASSERT(stack.Read(buffer, length)); + + const uint8_t expected_data[] = { + 0xf0, 0x23, 1, + 0, 0, 0, 0, 0, 0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, + 0x12, 0x34, 0, 0, 0, 1, + 0x43, 0x21, 0x12, 0x34, 0x56, 0x78, + 0x56, 0x78, 0, 0, 0, 2, + }; + OLA_ASSERT_DATA_EQUALS(expected_data, sizeof(expected_data), buffer, length); + delete[] buffer; +} +} // namespace acn +} // namespace ola diff --git a/libs/acn/Makefile.mk b/libs/acn/Makefile.mk index 42d91ea17d..3402e80be6 100644 --- a/libs/acn/Makefile.mk +++ b/libs/acn/Makefile.mk @@ -64,6 +64,8 @@ libs_acn_libolae131core_la_SOURCES = \ libs/acn/LLRPHeader.h \ libs/acn/LLRPInflator.cpp \ libs/acn/LLRPInflator.h \ + libs/acn/LLRPProbeRequestPDU.cpp \ + libs/acn/LLRPProbeRequestPDU.h \ libs/acn/LLRPPDU.cpp \ libs/acn/LLRPPDU.h \ libs/acn/PDU.cpp \ @@ -148,7 +150,8 @@ libs_acn_E133Tester_LDADD = \ libs_acn_LLRPTester_SOURCES = \ libs/acn/LLRPInflatorTest.cpp \ - libs/acn/LLRPPDUTest.cpp + libs/acn/LLRPPDUTest.cpp \ + libs/acn/LLRPProbeRequestPDUTest.cpp libs_acn_LLRPTester_CPPFLAGS = $(COMMON_TESTING_FLAGS) libs_acn_LLRPTester_LDADD = \ libs/acn/libolae131core.la \ From f1cc481d6d900de8db5a64334fe7419b41bfffa4 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Tue, 4 Feb 2020 13:39:23 +0000 Subject: [PATCH 08/71] Tidy some Doxygen --- include/ola/acn/ACNVectors.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/ola/acn/ACNVectors.h b/include/ola/acn/ACNVectors.h index db99ff2bb8..fc08d266ff 100644 --- a/include/ola/acn/ACNVectors.h +++ b/include/ola/acn/ACNVectors.h @@ -98,10 +98,11 @@ enum LLRPVector { VECTOR_LLRP_PROBE_REPLY = 1, /**< LLRP Probe Reply */ VECTOR_LLRP_RDM_CMD = 1, /**< LLRP RDM Command */ }; -} // namespace acn -} // namespace ola /** * @} */ +} // namespace acn +} // namespace ola + #endif // INCLUDE_OLA_ACN_ACNVECTORS_H_ From 27c1cb51d84857b4e4da352e11f8af703ad4857e Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Tue, 4 Feb 2020 14:03:25 +0000 Subject: [PATCH 09/71] Add the ability to easily write a CID to an ostream --- include/ola/acn/CID.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/ola/acn/CID.h b/include/ola/acn/CID.h index 91c403a5f4..3b98d127d7 100644 --- a/include/ola/acn/CID.h +++ b/include/ola/acn/CID.h @@ -89,6 +89,15 @@ class CID { */ std::string ToString() const; + /** + * @brief A helper function to write a CID to an ostream. + * @param out the ostream + * @param cid the CID to write. + */ + friend std::ostream& operator<< (std::ostream &out, const CID &cid) { + return out << cid.ToString(); + } + /** * @brief Write the CID to an OutputBufferInterface */ From e9dd3742f9310c0a72bccacfc45cfb9bacf115aa Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Tue, 4 Feb 2020 15:35:15 +0000 Subject: [PATCH 10/71] Add LLRP Probe Request PDU, fix the length flags bug --- include/ola/acn/ACNFlags.h | 70 ++++++++++++++++++++++++++++ include/ola/acn/Makefile.mk | 1 + libs/acn/BaseInflator.cpp | 4 +- libs/acn/BaseInflator.h | 7 ++- libs/acn/BaseInflatorTest.cpp | 18 +++---- libs/acn/LLRPInflatorTest.cpp | 2 +- libs/acn/LLRPPDU.cpp | 3 +- libs/acn/LLRPPDU.h | 8 ++-- libs/acn/LLRPPDUTest.cpp | 25 +++++----- libs/acn/LLRPProbeRequestPDU.cpp | 2 +- libs/acn/LLRPProbeRequestPDUTest.cpp | 2 +- libs/acn/PDU.cpp | 32 ++++++++++--- libs/acn/PDU.h | 37 +++++++++++---- 13 files changed, 161 insertions(+), 50 deletions(-) create mode 100644 include/ola/acn/ACNFlags.h diff --git a/include/ola/acn/ACNFlags.h b/include/ola/acn/ACNFlags.h new file mode 100644 index 0000000000..a055a429b0 --- /dev/null +++ b/include/ola/acn/ACNFlags.h @@ -0,0 +1,70 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * ACNFlags.h + * Flags used in ACN PDUs + * Copyright (C) 2020 Peter Newman + */ + +#ifndef INCLUDE_OLA_ACN_ACNFLAGS_H_ +#define INCLUDE_OLA_ACN_ACNFLAGS_H_ + +/** + * @addtogroup acn + * @{ + * @file ACNFlags.h + * @brief ACN flag values. + * @} + */ + +#include + +namespace ola { +namespace acn { + +/** + * @addtogroup acn + * @{ + */ + +// masks for the flag fields +/** + * @brief This indicates a 20 bit length field (default is 12 bits) + */ +static const uint8_t LFLAG_MASK = 0x80; + +/** + * @brief This indicates a vector is present + */ +static const uint8_t VFLAG_MASK = 0x40; + +/** + * @brief This indicates a header field is present + */ +static const uint8_t HFLAG_MASK = 0x20; + +/** + * @brief This indicates a data field is present + */ +static const uint8_t DFLAG_MASK = 0x10; + +/** + * @} + */ + +} // namespace acn +} // namespace ola + +#endif // INCLUDE_OLA_ACN_ACNFLAGS_H_ diff --git a/include/ola/acn/Makefile.mk b/include/ola/acn/Makefile.mk index 56bc647eb5..afd628d812 100644 --- a/include/ola/acn/Makefile.mk +++ b/include/ola/acn/Makefile.mk @@ -3,6 +3,7 @@ olaacninclude_HEADERS = if INSTALL_ACN olaacninclude_HEADERS += \ + include/ola/acn/ACNFlags.h \ include/ola/acn/ACNPort.h \ include/ola/acn/ACNVectors.h \ include/ola/acn/CID.h diff --git a/libs/acn/BaseInflator.cpp b/libs/acn/BaseInflator.cpp index e3917967ad..a41dca370c 100644 --- a/libs/acn/BaseInflator.cpp +++ b/libs/acn/BaseInflator.cpp @@ -163,7 +163,7 @@ bool BaseInflator::DecodeLength(const uint8_t *data, bool BaseInflator::DecodeVector(uint8_t flags, const uint8_t *data, unsigned int length, uint32_t *vector, unsigned int *bytes_used) { - if (flags & PDU::VFLAG_MASK) { + if (flags & ola::acn::VFLAG_MASK) { if ((unsigned int) m_vector_size > length) { *vector = 0; *bytes_used = 0; @@ -223,7 +223,7 @@ bool BaseInflator::InflatePDU(HeaderSet *headers, return false; } - if (flags & PDU::HFLAG_MASK) { + if (flags & ola::acn::HFLAG_MASK) { result = DecodeHeader(headers, data + data_offset, pdu_len - data_offset, &header_bytes_used); diff --git a/libs/acn/BaseInflator.h b/libs/acn/BaseInflator.h index 384351bc28..07b7c6b88b 100644 --- a/libs/acn/BaseInflator.h +++ b/libs/acn/BaseInflator.h @@ -87,8 +87,11 @@ class BaseInflator : public InflatorInterface { unsigned int len); // masks for the flag fields - // This indicates a 20 bit length field (default is 12 bits) - static const uint8_t LFLAG_MASK = 0x80; + /** + * @brief This indicates a 20 bit length field (default is 12 bits) + * @deprecated Use ola::acn::LFLAG_MASK instead (4 Feb 2020). + */ + static const uint8_t LFLAG_MASK = ola::acn::LFLAG_MASK; // This masks the first 4 bits of the length field static const uint8_t LENGTH_MASK = 0x0F; diff --git a/libs/acn/BaseInflatorTest.cpp b/libs/acn/BaseInflatorTest.cpp index 17e86121b8..a4e0a0dd81 100644 --- a/libs/acn/BaseInflatorTest.cpp +++ b/libs/acn/BaseInflatorTest.cpp @@ -204,7 +204,7 @@ void BaseInflatorTest::testDecodeVector() { uint8_t data[] = {1, 2, 3, 4, 5, 6}; // the test data unsigned int vector = 1; unsigned int bytes_used = 0; - uint8_t flags = PDU::VFLAG_MASK; + uint8_t flags = VFLAG_MASK; OLA_ASSERT_FALSE(inflator.DecodeVector(flags, data, 0, &vector, &bytes_used)); OLA_ASSERT_EQ((unsigned int) 0, vector); @@ -235,7 +235,7 @@ void BaseInflatorTest::testDecodeVector() { } // now try with a vector size of 2 - flags = PDU::VFLAG_MASK; + flags = VFLAG_MASK; TestInflator inflator2(0, PDU::TWO_BYTES); for (unsigned int i = 0; i < 2; i++) { OLA_ASSERT_FALSE( @@ -270,7 +270,7 @@ void BaseInflatorTest::testDecodeVector() { } // now try with a vector size of 4 - flags = PDU::VFLAG_MASK; + flags = VFLAG_MASK; TestInflator inflator4(0, PDU::FOUR_BYTES); for (unsigned int i = 0; i < 4; i++) { OLA_ASSERT_FALSE( @@ -297,7 +297,7 @@ void BaseInflatorTest::testDecodeVector() { void BaseInflatorTest::testInflatePDU() { TestInflator inflator; // test with a vector size of 2 HeaderSet header_set; - uint8_t flags = PDU::VFLAG_MASK; + uint8_t flags = VFLAG_MASK; unsigned int data_size = static_cast(PDU::TWO_BYTES + sizeof(PDU_DATA)); uint8_t *data = new uint8_t[data_size]; @@ -324,7 +324,7 @@ void BaseInflatorTest::testInflatePDUBlock() { length_size + PDU::TWO_BYTES + sizeof(PDU_DATA)); uint8_t *data = new uint8_t[data_size]; // setup the vector - data[0] = PDU::VFLAG_MASK; + data[0] = VFLAG_MASK; data[1] = static_cast(data_size); data[2] = 0x01; data[3] = 0x21; @@ -337,14 +337,14 @@ void BaseInflatorTest::testInflatePDUBlock() { // inflate a multi-pdu block data = new uint8_t[2 * data_size]; - data[0] = PDU::VFLAG_MASK; + data[0] = VFLAG_MASK; data[1] = static_cast(data_size); data[2] = 0x01; data[3] = 0x21; memcpy(data + length_size + PDU::TWO_BYTES, PDU_DATA, sizeof(PDU_DATA)); - data[data_size] = PDU::VFLAG_MASK; + data[data_size] = VFLAG_MASK; data[data_size + 1] = static_cast(data_size); data[data_size + 2] = 0x01; data[data_size + 3] = 0x21; @@ -362,11 +362,11 @@ void BaseInflatorTest::testInflatePDUBlock() { unsigned int pdu_size = data_size + length_size + PDU::TWO_BYTES; data = new uint8_t[pdu_size]; - data[0] = PDU::VFLAG_MASK; + data[0] = VFLAG_MASK; data[1] = static_cast(pdu_size); data[2] = 0x01; data[3] = 0x21; - data[4] = PDU::VFLAG_MASK; + data[4] = VFLAG_MASK; data[5] = static_cast(data_size); data[6] = 0x01; data[7] = 0x21; diff --git a/libs/acn/LLRPInflatorTest.cpp b/libs/acn/LLRPInflatorTest.cpp index b36c5cdc05..16bcd96431 100644 --- a/libs/acn/LLRPInflatorTest.cpp +++ b/libs/acn/LLRPInflatorTest.cpp @@ -108,7 +108,7 @@ void LLRPInflatorTest::testInflatePDU() { LLRPHeader header(destination_cid, 2370); // TODO(Peter): pass a different type of msg here as well LLRPPDU pdu(3, header, NULL); - OLA_ASSERT_EQ((unsigned int) 26, pdu.Size()); + OLA_ASSERT_EQ((unsigned int) 27, pdu.Size()); unsigned int size = pdu.Size(); uint8_t *data = new uint8_t[size]; diff --git a/libs/acn/LLRPPDU.cpp b/libs/acn/LLRPPDU.cpp index 5d8eba531d..a1654338e9 100644 --- a/libs/acn/LLRPPDU.cpp +++ b/libs/acn/LLRPPDU.cpp @@ -110,8 +110,7 @@ void LLRPPDU::PrependPDU(ola::io::IOStack *stack, uint32_t vector, vector = HostToNetwork(vector); stack->Write(reinterpret_cast(&vector), sizeof(vector)); - // Flags for LLRP should always be 0xF0 - PrependFlagsAndLength(stack, 0xf0); + PrependFlagsAndLength(stack, VFLAG_MASK | HFLAG_MASK | DFLAG_MASK, true); } } // namespace acn } // namespace ola diff --git a/libs/acn/LLRPPDU.h b/libs/acn/LLRPPDU.h index 67ccf7af58..669f5b5c06 100644 --- a/libs/acn/LLRPPDU.h +++ b/libs/acn/LLRPPDU.h @@ -35,7 +35,7 @@ class LLRPPDU: public PDU { LLRPPDU(unsigned int vector, const LLRPHeader &header, const PDU *pdu): - PDU(vector), + PDU(vector, FOUR_BYTES, true), m_header(header), m_pdu(pdu) {} ~LLRPPDU() {} @@ -48,8 +48,10 @@ class LLRPPDU: public PDU { void PackHeader(ola::io::OutputStream *stream) const; void PackData(ola::io::OutputStream *stream) const; - static void PrependPDU(ola::io::IOStack *stack, uint32_t vector, - const ola::acn::CID &destination_cid, uint32_t transaction_number); + static void PrependPDU(ola::io::IOStack *stack, + uint32_t vector, + const ola::acn::CID &destination_cid, + uint32_t transaction_number); private: LLRPHeader m_header; diff --git a/libs/acn/LLRPPDUTest.cpp b/libs/acn/LLRPPDUTest.cpp index b924d8a422..13273f60ed 100644 --- a/libs/acn/LLRPPDUTest.cpp +++ b/libs/acn/LLRPPDUTest.cpp @@ -74,7 +74,7 @@ void LLRPPDUTest::testSimpleLLRPPDU() { OLA_ASSERT_EQ(20u, pdu.HeaderSize()); OLA_ASSERT_EQ(0u, pdu.DataSize()); - OLA_ASSERT_EQ(26u, pdu.Size()); + OLA_ASSERT_EQ(27u, pdu.Size()); unsigned int size = pdu.Size(); uint8_t *data = new uint8_t[size]; @@ -83,20 +83,21 @@ void LLRPPDUTest::testSimpleLLRPPDU() { OLA_ASSERT_EQ(size, bytes_used); // spot check the data - OLA_ASSERT_EQ((uint8_t) 0x70, data[0]); - OLA_ASSERT_EQ((uint8_t) bytes_used, data[1]); + 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]); unsigned int actual_value; - memcpy(&actual_value, data + 2, sizeof(actual_value)); + memcpy(&actual_value, data + 3, sizeof(actual_value)); OLA_ASSERT_EQ(HostToNetwork(TEST_VECTOR), actual_value); uint8_t buffer[CID::CID_LENGTH]; destination_cid.Pack(buffer); - OLA_ASSERT_FALSE(memcmp(&data[6], buffer, CID::CID_LENGTH)); + OLA_ASSERT_DATA_EQUALS(&data[7], CID::CID_LENGTH, buffer, sizeof(buffer)); // transaction number - OLA_ASSERT_EQ((uint8_t) 0, data[6 + CID::CID_LENGTH]); - OLA_ASSERT_EQ((uint8_t) 0, data[6 + CID::CID_LENGTH + 1]); - OLA_ASSERT_EQ((uint8_t) 0, data[6 + CID::CID_LENGTH + 2]); - OLA_ASSERT_EQ((uint8_t) 101, data[6 + CID::CID_LENGTH + 3]); + OLA_ASSERT_EQ((uint8_t) 0, data[7 + CID::CID_LENGTH]); + OLA_ASSERT_EQ((uint8_t) 0, data[7 + CID::CID_LENGTH + 1]); + OLA_ASSERT_EQ((uint8_t) 0, data[7 + CID::CID_LENGTH + 2]); + OLA_ASSERT_EQ((uint8_t) 101, data[7 + CID::CID_LENGTH + 3]); // test undersized buffer bytes_used = size - 1; @@ -121,19 +122,19 @@ void LLRPPDUTest::testSimpleLLRPPDUToOutputStream() { OLA_ASSERT_EQ(20u, pdu.HeaderSize()); OLA_ASSERT_EQ(0u, pdu.DataSize()); - OLA_ASSERT_EQ(26u, pdu.Size()); + OLA_ASSERT_EQ(27u, pdu.Size()); IOQueue output; OutputStream stream(&output); pdu.Write(&stream); - OLA_ASSERT_EQ(26u, output.Size()); + OLA_ASSERT_EQ(27u, 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, 0x1a, + 0xf0, 0x00, 0x1b, 0, 0, 0, 39, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, diff --git a/libs/acn/LLRPProbeRequestPDU.cpp b/libs/acn/LLRPProbeRequestPDU.cpp index 6fe5378081..ba1623ed3a 100644 --- a/libs/acn/LLRPProbeRequestPDU.cpp +++ b/libs/acn/LLRPProbeRequestPDU.cpp @@ -56,7 +56,7 @@ void LLRPProbeRequestPDU::PrependPDU(ola::io::IOStack *stack, (known_uids.Size() * UID::LENGTH))); uint8_t vector = HostToNetwork(VECTOR_PROBE_REQUEST_DATA); stack->Write(reinterpret_cast(&vector), sizeof(vector)); - PrependFlagsAndLength(stack); + PrependFlagsAndLength(stack, VFLAG_MASK | HFLAG_MASK | DFLAG_MASK, true); } } // namespace acn } // namespace ola diff --git a/libs/acn/LLRPProbeRequestPDUTest.cpp b/libs/acn/LLRPProbeRequestPDUTest.cpp index ca6596991c..6666002b6a 100644 --- a/libs/acn/LLRPProbeRequestPDUTest.cpp +++ b/libs/acn/LLRPProbeRequestPDUTest.cpp @@ -70,7 +70,7 @@ void LLRPProbeRequestPDUTest::testPrepend() { OLA_ASSERT(stack.Read(buffer, length)); const uint8_t expected_data[] = { - 0xf0, 0x23, 1, + 0xf0, 0x00, 0x24, 1, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, diff --git a/libs/acn/PDU.cpp b/libs/acn/PDU.cpp index c9166db6cb..0f256eca13 100644 --- a/libs/acn/PDU.cpp +++ b/libs/acn/PDU.cpp @@ -35,8 +35,9 @@ using ola::network::HostToNetwork; unsigned int PDU::Size() const { unsigned int length = m_vector_size + HeaderSize() + DataSize(); - if (length > TWOB_LENGTH_LIMIT - 2) + if ((length > TWOB_LENGTH_LIMIT - 2) || m_force_length_flag) { length += 1; + } length += 2; return length; } @@ -59,7 +60,7 @@ bool PDU::Pack(uint8_t *buffer, unsigned int *length) const { return false; } - if (size <= TWOB_LENGTH_LIMIT) { + if (size <= TWOB_LENGTH_LIMIT && !m_force_length_flag) { buffer[0] = (uint8_t) ((size & 0x0f00) >> 8); buffer[1] = (uint8_t) (size & 0xff); } else { @@ -69,6 +70,11 @@ bool PDU::Pack(uint8_t *buffer, unsigned int *length) const { offset += 1; } + if (m_force_length_flag) { + // TODO(Peter): Should this happen regardless of the force when we're + // writing 20 bits of length? + buffer[0] |= LFLAG_MASK; + } buffer[0] |= VFLAG_MASK; buffer[0] |= HFLAG_MASK; buffer[0] |= DFLAG_MASK; @@ -117,13 +123,18 @@ bool PDU::Pack(uint8_t *buffer, unsigned int *length) const { void PDU::Write(OutputStream *stream) const { unsigned int size = Size(); - if (size <= TWOB_LENGTH_LIMIT) { + if (size <= TWOB_LENGTH_LIMIT && !m_force_length_flag) { uint16_t flags_and_length = static_cast(size); flags_and_length |= (VFLAG_MASK | HFLAG_MASK | DFLAG_MASK) << 8u; *stream << HostToNetwork(flags_and_length); } else { uint8_t vhl_flags = static_cast((size & 0x0f0000) >> 16); vhl_flags |= VFLAG_MASK | HFLAG_MASK | DFLAG_MASK; + if (m_force_length_flag) { + // TODO(Peter): Should this happen regardless of the force as we're + // writing 20 bits of length? + vhl_flags |= LFLAG_MASK; + } *stream << vhl_flags; *stream << (uint8_t) ((size & 0xff00) >> 8); *stream << (uint8_t) (size & 0xff); @@ -150,8 +161,9 @@ void PDU::Write(OutputStream *stream) const { * Prepend the flags and length to an OutputBufferInterface. */ void PDU::PrependFlagsAndLength(ola::io::OutputBufferInterface *output, - uint8_t flags) { - PrependFlagsAndLength(output, output->Size(), flags); + uint8_t flags, + bool force_length_flag) { + PrependFlagsAndLength(output, output->Size(), flags, force_length_flag); } @@ -160,8 +172,9 @@ void PDU::PrependFlagsAndLength(ola::io::OutputBufferInterface *output, */ void PDU::PrependFlagsAndLength(ola::io::OutputBufferInterface *output, unsigned int size, - uint8_t flags) { - if (size + 2 <= TWOB_LENGTH_LIMIT) { + uint8_t flags, + bool force_length_flag) { + if (size + 2 <= TWOB_LENGTH_LIMIT && !force_length_flag) { size += 2; uint16_t flags_and_length = static_cast(size); flags_and_length |= static_cast(flags << 8u); @@ -173,6 +186,11 @@ void PDU::PrependFlagsAndLength(ola::io::OutputBufferInterface *output, uint8_t flags_and_length[3]; flags_and_length[0] = static_cast((size & 0x0f0000) >> 16); flags_and_length[0] |= flags; + if (force_length_flag) { + // TODO(Peter): Should this happen regardless of the force as we're + // writing 20 bits of length? + flags_and_length[0] |= LFLAG_MASK; + } flags_and_length[1] = static_cast((size & 0xff00) >> 8); flags_and_length[2] = static_cast(size & 0xff); output->Write(flags_and_length, sizeof(flags_and_length)); diff --git a/libs/acn/PDU.h b/libs/acn/PDU.h index 64c1e82adb..2be285dead 100644 --- a/libs/acn/PDU.h +++ b/libs/acn/PDU.h @@ -22,6 +22,7 @@ #define LIBS_ACN_PDU_H_ #include +#include #include #include #include @@ -41,9 +42,12 @@ class PDU { FOUR_BYTES = 4, } vector_size; - explicit PDU(unsigned int vector, vector_size size = FOUR_BYTES): + explicit PDU(unsigned int vector, + vector_size size = FOUR_BYTES, + bool force_length_flag = false): m_vector(vector), - m_vector_size(size) {} + m_vector_size(size), + m_force_length_flag(force_length_flag) {} virtual ~PDU() {} // Returns the size of this PDU @@ -72,23 +76,36 @@ class PDU { static void PrependFlagsAndLength( ola::io::OutputBufferInterface *output, - uint8_t flags = VFLAG_MASK | HFLAG_MASK | DFLAG_MASK); + uint8_t flags = VFLAG_MASK | HFLAG_MASK | DFLAG_MASK, + bool force_length_flag = false); static void PrependFlagsAndLength( ola::io::OutputBufferInterface *output, unsigned int length, - uint8_t flags); + uint8_t flags, + bool force_length_flag = false); + + /** + * @brief This indicates a vector is present. + * @deprecated Use ola::acn::VFLAG_MASK instead (4 Feb 2020). + */ + static const uint8_t VFLAG_MASK = ola::acn::VFLAG_MASK; + /** + * @brief This indicates a header field is present. + * @deprecated Use ola::acn::HFLAG_MASK instead (4 Feb 2020). + */ + static const uint8_t HFLAG_MASK = ola::acn::HFLAG_MASK; + /** + * @brief This indicates a data field is present. + * @deprecated Use ola::acn::DFLAG_MASK instead (4 Feb 2020). + */ + static const uint8_t DFLAG_MASK = ola::acn::DFLAG_MASK; - // This indicates a vector is present - static const uint8_t VFLAG_MASK = 0x40; - // This indicates a header field is present - static const uint8_t HFLAG_MASK = 0x20; - // This indicates a data field is present - static const uint8_t DFLAG_MASK = 0x10; private: unsigned int m_vector; unsigned int m_vector_size; + bool m_force_length_flag; // The max PDU length that can be represented with the 2 byte format for // the length field. From 2d0ed43d1d351c696a8c5122c6c469d79bd2ee9f Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Tue, 4 Feb 2020 16:46:09 +0000 Subject: [PATCH 11/71] Fix the lint issues --- libs/acn/LLRPPDU.cpp | 6 ++++-- libs/acn/LLRPPDUTest.cpp | 1 - libs/acn/LLRPProbeRequestPDU.h | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/libs/acn/LLRPPDU.cpp b/libs/acn/LLRPPDU.cpp index a1654338e9..4fb3b3644f 100644 --- a/libs/acn/LLRPPDU.cpp +++ b/libs/acn/LLRPPDU.cpp @@ -100,8 +100,10 @@ void LLRPPDU::PackData(OutputStream *stream) const { } -void LLRPPDU::PrependPDU(ola::io::IOStack *stack, uint32_t vector, - const ola::acn::CID &destination_cid, uint32_t transaction_number) { +void LLRPPDU::PrependPDU(ola::io::IOStack *stack, + uint32_t vector, + const ola::acn::CID &destination_cid, + uint32_t transaction_number) { LLRPHeader::llrp_pdu_header header; destination_cid.Pack(header.destination_cid); header.transaction_number = HostToNetwork(transaction_number); diff --git a/libs/acn/LLRPPDUTest.cpp b/libs/acn/LLRPPDUTest.cpp index 13273f60ed..01c30db22a 100644 --- a/libs/acn/LLRPPDUTest.cpp +++ b/libs/acn/LLRPPDUTest.cpp @@ -35,7 +35,6 @@ namespace acn { using ola::io::IOQueue; using ola::io::OutputStream; using ola::network::HostToNetwork; -using std::string; class LLRPPDUTest: public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(LLRPPDUTest); diff --git a/libs/acn/LLRPProbeRequestPDU.h b/libs/acn/LLRPProbeRequestPDU.h index 34e5ac79e0..b39b768cf9 100644 --- a/libs/acn/LLRPProbeRequestPDU.h +++ b/libs/acn/LLRPProbeRequestPDU.h @@ -59,4 +59,4 @@ class LLRPProbeRequestPDU : private PDU { }; } // namespace acn } // namespace ola -#endif // LIBS_ACN_LLRPProbeRequestPDU_H_ +#endif // LIBS_ACN_LLRPPROBEREQUESTPDU_H_ From 38d893db6b6bb1a8c0256fc7fc9320cd7ff65965 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Thu, 6 Feb 2020 00:30:59 +0000 Subject: [PATCH 12/71] Add the LLRPProbeReplyPDU --- libs/acn/LLRPProbeReplyPDU.cpp | 50 ++++++++++++++++++ libs/acn/LLRPProbeReplyPDU.h | 59 ++++++++++++++++++++++ libs/acn/LLRPProbeReplyPDUTest.cpp | 81 ++++++++++++++++++++++++++++++ libs/acn/Makefile.mk | 3 ++ 4 files changed, 193 insertions(+) create mode 100644 libs/acn/LLRPProbeReplyPDU.cpp create mode 100644 libs/acn/LLRPProbeReplyPDU.h create mode 100644 libs/acn/LLRPProbeReplyPDUTest.cpp diff --git a/libs/acn/LLRPProbeReplyPDU.cpp b/libs/acn/LLRPProbeReplyPDU.cpp new file mode 100644 index 0000000000..830766fd85 --- /dev/null +++ b/libs/acn/LLRPProbeReplyPDU.cpp @@ -0,0 +1,50 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * LLRPProbeReplyPDU.cpp + * The LLRPProbeReplyPDU + * Copyright (C) 2020 Peter Newman + */ + +#include "libs/acn/LLRPProbeReplyPDU.h" + +#include +#include +#include + +namespace ola { +namespace acn { + +using ola::io::OutputStream; +using ola::network::HostToNetwork; +using ola::network::MACAddress; +using ola::rdm::UID; + +void LLRPProbeReplyPDU::PrependPDU(ola::io::IOStack *stack, + const UID &target_uid, + const MACAddress &hardware_address, + const LLRPComponentType type) { + llrp_probe_reply_pdu_data data; + target_uid.Pack(data.target_uid, sizeof(data.target_uid)); + hardware_address.Pack(data.hardware_address, sizeof(data.hardware_address)); + data.type = HostToNetwork(static_cast(type)); + stack->Write(reinterpret_cast(&data), + static_cast(sizeof(llrp_probe_reply_pdu_data))); + uint8_t vector = HostToNetwork(VECTOR_PROBE_REPLY_DATA); + stack->Write(reinterpret_cast(&vector), sizeof(vector)); + PrependFlagsAndLength(stack, VFLAG_MASK | HFLAG_MASK | DFLAG_MASK, true); +} +} // namespace acn +} // namespace ola diff --git a/libs/acn/LLRPProbeReplyPDU.h b/libs/acn/LLRPProbeReplyPDU.h new file mode 100644 index 0000000000..08bbc55835 --- /dev/null +++ b/libs/acn/LLRPProbeReplyPDU.h @@ -0,0 +1,59 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * LLRPProbeReplyPDU.h + * The LLRPProbeReplyPDU class + * Copyright (C) 2020 Peter Newman + */ + +#ifndef LIBS_ACN_LLRPPROBEREPLYPDU_H_ +#define LIBS_ACN_LLRPPROBEREPLYPDU_H_ + +#include +#include +#include + +#include "libs/acn/PDU.h" + +namespace ola { +namespace acn { + +class LLRPProbeReplyPDU : private PDU { + public: + typedef enum { + LLRP_COMPONENT_TYPE_RPT_DEVICE = 0, /**< Device */ + LLRP_COMPONENT_TYPE_RPT_CONTROLLER = 1, /**< Controller */ + LLRP_COMPONENT_TYPE_BROKER = 2, /**< Broker */ + LLRP_COMPONENT_TYPE_NON_RDMNET = 0xff, /**< Non-RDMnet */ + } LLRPComponentType; + + static void PrependPDU(ola::io::IOStack *stack, + const ola::rdm::UID &target_uid, + const ola::network::MACAddress &hardware_address, + const LLRPComponentType type); + + static const uint8_t VECTOR_PROBE_REPLY_DATA = 0x01; + + PACK( + struct llrp_probe_reply_pdu_data_s { + uint8_t target_uid[ola::rdm::UID::LENGTH]; + uint8_t hardware_address[ola::network::MACAddress::LENGTH]; + uint8_t type; + }); + typedef struct llrp_probe_reply_pdu_data_s llrp_probe_reply_pdu_data; +}; +} // namespace acn +} // namespace ola +#endif // LIBS_ACN_LLRPPROBEREPLYPDU_H_ diff --git a/libs/acn/LLRPProbeReplyPDUTest.cpp b/libs/acn/LLRPProbeReplyPDUTest.cpp new file mode 100644 index 0000000000..2ae354c47d --- /dev/null +++ b/libs/acn/LLRPProbeReplyPDUTest.cpp @@ -0,0 +1,81 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * LLRPProbeReplyPDUTest.cpp + * Test fixture for the LLRPProbeReplyPDU class + * Copyright (C) 2020 Peter Newman + */ + +#include +#include +#include + +#include "ola/Logging.h" +#include "ola/io/IOStack.h" +#include "ola/network/NetworkUtils.h" +#include "ola/rdm/UID.h" +#include "ola/rdm/UIDSet.h" +#include "ola/testing/TestUtils.h" +#include "libs/acn/PDUTestCommon.h" +#include "libs/acn/LLRPProbeReplyPDU.h" + +namespace ola { +namespace acn { + +using ola::acn::LLRPProbeReplyPDU; +using ola::io::IOStack; +using ola::network::MACAddress; +using ola::rdm::UID; + +class LLRPProbeReplyPDUTest: public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(LLRPProbeReplyPDUTest); + CPPUNIT_TEST(testPrepend); + CPPUNIT_TEST_SUITE_END(); + + public: + void testPrepend(); + + private: + static const unsigned int TEST_VECTOR; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(LLRPProbeReplyPDUTest); + +void LLRPProbeReplyPDUTest::testPrepend() { + IOStack stack; + UID target_uid = UID(0x4321, 0x12345678); + MACAddress hardware_address; + MACAddress::FromString("01:23:45:67:89:ab", &hardware_address); + LLRPProbeReplyPDU::PrependPDU( + &stack, + target_uid, + hardware_address, + LLRPProbeReplyPDU::LLRP_COMPONENT_TYPE_NON_RDMNET); + + unsigned int length = stack.Size(); + uint8_t *buffer = new uint8_t[length]; + OLA_ASSERT(stack.Read(buffer, length)); + + const uint8_t expected_data[] = { + 0xf0, 0x00, 0x11, 1, + 0x43, 0x21, 0x12, 0x34, 0x56, 0x78, + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, + 0xff + }; + OLA_ASSERT_DATA_EQUALS(expected_data, sizeof(expected_data), buffer, length); + delete[] buffer; +} +} // namespace acn +} // namespace ola diff --git a/libs/acn/Makefile.mk b/libs/acn/Makefile.mk index 3402e80be6..b203c5b258 100644 --- a/libs/acn/Makefile.mk +++ b/libs/acn/Makefile.mk @@ -64,6 +64,8 @@ libs_acn_libolae131core_la_SOURCES = \ libs/acn/LLRPHeader.h \ libs/acn/LLRPInflator.cpp \ libs/acn/LLRPInflator.h \ + libs/acn/LLRPProbeReplyPDU.cpp \ + libs/acn/LLRPProbeReplyPDU.h \ libs/acn/LLRPProbeRequestPDU.cpp \ libs/acn/LLRPProbeRequestPDU.h \ libs/acn/LLRPPDU.cpp \ @@ -151,6 +153,7 @@ libs_acn_E133Tester_LDADD = \ libs_acn_LLRPTester_SOURCES = \ libs/acn/LLRPInflatorTest.cpp \ libs/acn/LLRPPDUTest.cpp \ + libs/acn/LLRPProbeReplyPDUTest.cpp \ libs/acn/LLRPProbeRequestPDUTest.cpp libs_acn_LLRPTester_CPPFLAGS = $(COMMON_TESTING_FLAGS) libs_acn_LLRPTester_LDADD = \ From 956c0fb0eaedb81a303d22cbcbe60239eebe0c1a Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Thu, 6 Feb 2020 01:21:41 +0000 Subject: [PATCH 13/71] Fix the LLRP vector values --- include/ola/acn/ACNVectors.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/ola/acn/ACNVectors.h b/include/ola/acn/ACNVectors.h index fc08d266ff..72c050ea91 100644 --- a/include/ola/acn/ACNVectors.h +++ b/include/ola/acn/ACNVectors.h @@ -95,8 +95,8 @@ enum E133ControllerVector { */ enum LLRPVector { VECTOR_LLRP_PROBE_REQUEST = 1, /**< LLRP Probe Request */ - VECTOR_LLRP_PROBE_REPLY = 1, /**< LLRP Probe Reply */ - VECTOR_LLRP_RDM_CMD = 1, /**< LLRP RDM Command */ + VECTOR_LLRP_PROBE_REPLY = 2, /**< LLRP Probe Reply */ + VECTOR_LLRP_RDM_CMD = 3, /**< LLRP RDM Command */ }; /** From d72c6aaf162bf2c1c7c409589f70c392353dcdb8 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Thu, 6 Feb 2020 14:58:13 +0000 Subject: [PATCH 14/71] Add the ability to force the length flag on a Root PDU --- libs/acn/RootPDU.cpp | 4 ++-- libs/acn/RootPDU.h | 6 +++--- libs/acn/RootSender.cpp | 4 ++-- libs/acn/RootSender.h | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libs/acn/RootPDU.cpp b/libs/acn/RootPDU.cpp index 227406124f..cec65ed7bb 100644 --- a/libs/acn/RootPDU.cpp +++ b/libs/acn/RootPDU.cpp @@ -86,12 +86,12 @@ void RootPDU::SetBlock(const PDUBlock *block) { /* * Prepend a Root Layer flags, length, vector & header */ -void RootPDU::PrependPDU(IOStack *stack, uint32_t vector, const CID &cid) { +void RootPDU::PrependPDU(IOStack *stack, uint32_t vector, const CID &cid, bool force_length_flag) { cid.Write(stack); vector = HostToNetwork(vector); stack->Write(reinterpret_cast(&vector), sizeof(vector)); - PrependFlagsAndLength(stack); + PrependFlagsAndLength(stack, VFLAG_MASK | HFLAG_MASK | DFLAG_MASK, force_length_flag); } } // namespace acn } // namespace ola diff --git a/libs/acn/RootPDU.h b/libs/acn/RootPDU.h index cc10ff8bcc..6d66ebc178 100644 --- a/libs/acn/RootPDU.h +++ b/libs/acn/RootPDU.h @@ -33,8 +33,8 @@ namespace acn { class RootPDU: public PDU { public: - explicit RootPDU(unsigned int vector): - PDU(vector), + explicit RootPDU(unsigned int vector, bool force_length_flag = false): + PDU(vector, FOUR_BYTES, force_length_flag), m_block(NULL), m_block_size(0) {} RootPDU(unsigned int vector, @@ -60,7 +60,7 @@ class RootPDU: public PDU { void SetBlock(const PDUBlock *block); static void PrependPDU(ola::io::IOStack *stack, uint32_t vector, - const ola::acn::CID &cid); + const ola::acn::CID &cid, bool force_length_flag = false); private: ola::acn::CID m_cid; diff --git a/libs/acn/RootSender.cpp b/libs/acn/RootSender.cpp index 009bb30f7e..767c8844c1 100644 --- a/libs/acn/RootSender.cpp +++ b/libs/acn/RootSender.cpp @@ -31,8 +31,8 @@ using ola::acn::CID; * Create a new RootSender * @param cid The CID to send in the Root PDU. */ -RootSender::RootSender(const CID &cid) - : m_root_pdu(0) { +RootSender::RootSender(const CID &cid, bool force_length_flag) + : m_root_pdu(0, force_length_flag) { m_root_pdu.Cid(cid); } diff --git a/libs/acn/RootSender.h b/libs/acn/RootSender.h index 31926ef8f0..a09bbf6199 100644 --- a/libs/acn/RootSender.h +++ b/libs/acn/RootSender.h @@ -32,7 +32,7 @@ namespace acn { class RootSender { public: - explicit RootSender(const ola::acn::CID &cid); + explicit RootSender(const ola::acn::CID &cid, bool force_length_flag = false); ~RootSender() {} // Convenience method to encapsulate & send a single PDU From d972695ecd437044be622982e490b63ca42c66b9 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Thu, 6 Feb 2020 14:59:22 +0000 Subject: [PATCH 15/71] Allow an LLRPProbeReplyPDU to be sent --- libs/acn/LLRPProbeReplyPDU.cpp | 20 ++++++ libs/acn/LLRPProbeReplyPDU.h | 28 +++++++- libs/acn/LLRPProbeReplyPDUTest.cpp | 100 +++++++++++++++++++++++++++++ 3 files changed, 147 insertions(+), 1 deletion(-) diff --git a/libs/acn/LLRPProbeReplyPDU.cpp b/libs/acn/LLRPProbeReplyPDU.cpp index 830766fd85..a7822e7dc9 100644 --- a/libs/acn/LLRPProbeReplyPDU.cpp +++ b/libs/acn/LLRPProbeReplyPDU.cpp @@ -32,6 +32,26 @@ 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 08bbc55835..96b0644151 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 2ae354c47d..ae25918683 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,97 @@ 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); From 3eb8518d9f08e27a7eeb22659f89e5700a93bf24 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Thu, 6 Feb 2020 14:59:51 +0000 Subject: [PATCH 16/71] Tidying and TODO --- libs/acn/LLRPProbeRequestPDU.cpp | 2 +- libs/acn/LLRPProbeRequestPDU.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/libs/acn/LLRPProbeRequestPDU.cpp b/libs/acn/LLRPProbeRequestPDU.cpp index ba1623ed3a..6db4af3bab 100644 --- a/libs/acn/LLRPProbeRequestPDU.cpp +++ b/libs/acn/LLRPProbeRequestPDU.cpp @@ -30,7 +30,6 @@ namespace acn { using ola::io::OutputStream; using ola::network::HostToNetwork; using ola::rdm::UID; -using std::vector; void LLRPProbeRequestPDU::PrependPDU(ola::io::IOStack *stack, const UID &lower_uid, @@ -49,6 +48,7 @@ void LLRPProbeRequestPDU::PrependPDU(ola::io::IOStack *stack, filter |= FILTER_BROKERS_ONLY; } data.filter = HostToNetwork(filter); + // TODO(Peter): We need to check we've got <= 200 UIDs here known_uids.Pack(data.known_uids, sizeof(data.known_uids)); stack->Write(reinterpret_cast(&data), static_cast(sizeof(llrp_probe_request_pdu_data) - diff --git a/libs/acn/LLRPProbeRequestPDU.h b/libs/acn/LLRPProbeRequestPDU.h index b39b768cf9..17a3145c69 100644 --- a/libs/acn/LLRPProbeRequestPDU.h +++ b/libs/acn/LLRPProbeRequestPDU.h @@ -47,7 +47,6 @@ class LLRPProbeRequestPDU : private PDU { static const uint16_t FILTER_CLIENT_TCP_CONNECTION_INACTIVE = 0x0001; static const uint16_t FILTER_BROKERS_ONLY = 0x0002; - private: PACK( struct llrp_probe_request_pdu_data_s { uint8_t lower_uid[ola::rdm::UID::LENGTH]; From f3b751195ab17d9796dfc4cc3eaa89a8db200699 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Thu, 6 Feb 2020 15:00:48 +0000 Subject: [PATCH 17/71] Initial handling of LLRPProbeRequest PDUs --- libs/acn/LLRPProbeRequestInflator.cpp | 119 ++++++++++++++++++++++++++ libs/acn/LLRPProbeRequestInflator.h | 71 +++++++++++++++ libs/acn/Makefile.mk | 2 + 3 files changed, 192 insertions(+) create mode 100644 libs/acn/LLRPProbeRequestInflator.cpp create mode 100644 libs/acn/LLRPProbeRequestInflator.h diff --git a/libs/acn/LLRPProbeRequestInflator.cpp b/libs/acn/LLRPProbeRequestInflator.cpp new file mode 100644 index 0000000000..cbc2fff04d --- /dev/null +++ b/libs/acn/LLRPProbeRequestInflator.cpp @@ -0,0 +1,119 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * LLRPProbeRequestInflator.cpp + * The Inflator for the LLRP Probe Request PDUs + * Copyright (C) 2020 Peter Newman + */ + +#include +#include +#include "ola/Logging.h" +#include "include/ola/rdm/UID.h" +#include "include/ola/rdm/UIDSet.h" +#include "include/ola/strings/Format.h" +#include "libs/acn/LLRPProbeRequestInflator.h" +#include "libs/acn/LLRPProbeRequestPDU.h" + +namespace ola { +namespace acn { + +using ola::acn::LLRPProbeRequestPDU; +using ola::rdm::UID; +using ola::rdm::UIDSet; + +/** + * Create a new LLRP Probe Request inflator + */ +LLRPProbeRequestInflator::LLRPProbeRequestInflator() + : BaseInflator(PDU::ONE_BYTE) { +} + +/** + * Set a RDMHandler to run when receiving a RDM message. + * @param handler the callback to invoke when there is rdm data for this + * universe. + */ +void LLRPProbeRequestInflator::SetLLRPProbeRequestHandler( + LLRPProbeRequestHandler *handler) { + m_llrp_probe_request_handler.reset(handler); +} + + +/* + * Decode the LLRP Probe Request 'header', which is 0 bytes in length. + * @param headers the HeaderSet to add to + * @param data a pointer to the data + * @param length length of the data + * @returns true if successful, false otherwise + */ +bool LLRPProbeRequestInflator::DecodeHeader(HeaderSet *, + const uint8_t*, + unsigned int, + unsigned int *bytes_used) { + *bytes_used = 0; + return true; +} + + +/* + * Handle a LLRP Probe Request PDU for E1.33. + */ +bool LLRPProbeRequestInflator::HandlePDUData(uint32_t vector, + const HeaderSet &headers, + const uint8_t *data, + unsigned int pdu_len) { + if (vector != LLRPProbeRequestPDU::VECTOR_PROBE_REQUEST_DATA) { + OLA_INFO << "Not a probe request, vector was " << vector; + return true; + } + + ola::strings::FormatData(&std::cout, data, pdu_len); + + LLRPProbeRequestPDU::llrp_probe_request_pdu_data pdu_data; + if (pdu_len > sizeof(pdu_data)) { + OLA_WARN << "Got too much data, received " << pdu_len << " only expecting " + << sizeof(pdu_data); + return false; + } + + unsigned int known_uids_size = static_cast( + pdu_len - (sizeof(pdu_data) - + sizeof(pdu_data.known_uids))); + if (known_uids_size % UID::UID_SIZE != 0) { + OLA_WARN << "Got a partial known UID, received " << known_uids_size << " bytes"; + return false; + } + + memcpy(reinterpret_cast(&pdu_data), data, sizeof(pdu_data)); + + OLA_DEBUG << "Probe from " << UID(pdu_data.lower_uid) << " to " << UID(pdu_data.upper_uid); + +// string rdm_message(reinterpret_cast(&data[0]), pdu_len); + + if (m_llrp_probe_request_handler.get()) { + m_llrp_probe_request_handler->Run(&headers, + UID(pdu_data.lower_uid), + UID(pdu_data.upper_uid) +//, +// UIDSet() +); + } else { + OLA_WARN << "No LLRP Probe Request handler defined!"; + } + return true; +} +} // namespace acn +} // namespace ola diff --git a/libs/acn/LLRPProbeRequestInflator.h b/libs/acn/LLRPProbeRequestInflator.h new file mode 100644 index 0000000000..1d63b84e9f --- /dev/null +++ b/libs/acn/LLRPProbeRequestInflator.h @@ -0,0 +1,71 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * LLRPProbeRequestInflator.h + * Copyright (C) 2020 Peter Newman + */ + +#ifndef LIBS_ACN_LLRPPROBEREQUESTINFLATOR_H_ +#define LIBS_ACN_LLRPPROBEREQUESTINFLATOR_H_ + +#include "ola/Callback.h" +#include "ola/acn/ACNVectors.h" +#include "ola/rdm/UID.h" +#include "ola/rdm/UIDSet.h" +#include "libs/acn/BaseInflator.h" +#include "libs/acn/HeaderSet.h" + +namespace ola { +namespace acn { + +class LLRPProbeRequestInflator: public BaseInflator { + friend class LLRPProbeRequestInflatorTest; + + public: + // These are pointers so the callers don't have to pull in all the headers. + typedef ola::Callback3 LLRPProbeRequestHandler; + + LLRPProbeRequestInflator(); + ~LLRPProbeRequestInflator() {} + + uint32_t Id() const { return ola::acn::VECTOR_LLRP_PROBE_REQUEST; } + + void SetLLRPProbeRequestHandler(LLRPProbeRequestHandler *handler); + + protected: + bool DecodeHeader(HeaderSet *headers, + const uint8_t *data, + unsigned int len, + unsigned int *bytes_used); + + void ResetHeaderField() {} // namespace noop + + virtual bool HandlePDUData(uint32_t vector, + const HeaderSet &headers, + const uint8_t *data, + unsigned int pdu_len); + + private: + std::auto_ptr m_llrp_probe_request_handler; +}; +} // namespace acn +} // namespace ola +#endif // LIBS_ACN_LLRPPROBEREQUESTINFLATOR_H_ diff --git a/libs/acn/Makefile.mk b/libs/acn/Makefile.mk index b203c5b258..7c81ef9031 100644 --- a/libs/acn/Makefile.mk +++ b/libs/acn/Makefile.mk @@ -66,6 +66,8 @@ libs_acn_libolae131core_la_SOURCES = \ libs/acn/LLRPInflator.h \ libs/acn/LLRPProbeReplyPDU.cpp \ libs/acn/LLRPProbeReplyPDU.h \ + libs/acn/LLRPProbeRequestInflator.cpp \ + libs/acn/LLRPProbeRequestInflator.h \ libs/acn/LLRPProbeRequestPDU.cpp \ libs/acn/LLRPProbeRequestPDU.h \ libs/acn/LLRPPDU.cpp \ From e445c32b48e203a380d9558e3763a99fd74768d6 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Thu, 6 Feb 2020 15:01:27 +0000 Subject: [PATCH 18/71] Initial LLRP discoverable device --- .gitignore | 2 + tools/e133/Makefile.mk | 6 +- tools/e133/llrp-receive-test.cpp | 236 +++++++++++++++++++++++++++++++ 3 files changed, 243 insertions(+), 1 deletion(-) create mode 100644 tools/e133/llrp-receive-test.cpp diff --git a/.gitignore b/.gitignore index b41ca378ac..6103d55d61 100644 --- a/.gitignore +++ b/.gitignore @@ -212,6 +212,8 @@ tools/e133/e133_monitor tools/e133/e133_monitor.exe tools/e133/e133_receiver tools/e133/e133_receiver.exe +tools/e133/llrp_receive_test +tools/e133/llrp_receive_test.exe tools/e133/slp_locate tools/e133/slp_locate.exe tools/e133/slp_register diff --git a/tools/e133/Makefile.mk b/tools/e133/Makefile.mk index 6b77f499d3..132da06b7b 100644 --- a/tools/e133/Makefile.mk +++ b/tools/e133/Makefile.mk @@ -70,7 +70,8 @@ noinst_PROGRAMS += \ tools/e133/basic_device \ tools/e133/e133_controller \ tools/e133/e133_monitor \ - tools/e133/e133_receiver + tools/e133/e133_receiver \ + tools/e133/llrp_receive_test tools_e133_e133_receiver_SOURCES = tools/e133/e133-receiver.cpp tools_e133_e133_receiver_LDADD = common/libolacommon.la \ @@ -104,3 +105,6 @@ tools_e133_basic_device_SOURCES = tools/e133/basic-device.cpp tools_e133_basic_device_LDADD = common/libolacommon.la \ libs/acn/libolaacn.la \ tools/e133/libolae133common.la + +tools_e133_llrp_receive_test_SOURCES = tools/e133/llrp-receive-test.cpp +tools_e133_llrp_receive_test_LDADD = libs/acn/libolae131core.la diff --git a/tools/e133/llrp-receive-test.cpp b/tools/e133/llrp-receive-test.cpp new file mode 100644 index 0000000000..e6530e6530 --- /dev/null +++ b/tools/e133/llrp-receive-test.cpp @@ -0,0 +1,236 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * e131_transmit_test.cpp + * The sends custom E1.31 packets in order to test the implementation of a + * remote node. + * Copyright (C) 2010 Simon Newton + * + * The remote node needs to be listening for Universe 1. + */ + +#include +#include +#include +#include +#include "libs/acn/HeaderSet.h" +#include "libs/acn/LLRPHeader.h" +#include "libs/acn/LLRPInflator.h" +#include "libs/acn/LLRPPDU.h" +#include "libs/acn/LLRPProbeReplyPDU.h" +#include "libs/acn/LLRPProbeRequestInflator.h" +#include "libs/acn/PreamblePacker.h" +#include "libs/acn/RootHeader.h" +#include "libs/acn/RootInflator.h" +#include "libs/acn/RootSender.h" +#include "libs/acn/Transport.h" +#include "libs/acn/UDPTransport.h" +#include "ola/Callback.h" +#include "ola/acn/ACNPort.h" +#include "ola/acn/CID.h" +#include "ola/io/SelectServer.h" +#include "ola/network/InterfacePicker.h" +#include "ola/network/IPV4Address.h" +#include "ola/network/MACAddress.h" +#include "ola/network/SocketAddress.h" +#include "ola/network/Socket.h" +#include "ola/rdm/UID.h" +#include "ola/DmxBuffer.h" +#include "ola/Logging.h" + +using std::string; +using std::vector; +using std::auto_ptr; + +using ola::acn::CID; +using ola::acn::IncomingUDPTransport; +using ola::acn::LLRPHeader; +using ola::acn::LLRPProbeReplyPDU; +using ola::acn::OutgoingUDPTransport; +using ola::acn::OutgoingUDPTransportImpl; +using ola::network::IPV4Address; +using ola::network::IPV4SocketAddress; +using ola::network::MACAddress; +using ola::rdm::UID; + +/* + * Display the help message + */ +void DisplayHelp(const char *binary_name) { + std::cout << "Usage: " << binary_name << " [--interactive]\n" + "\n" + "Run the E1.31 Transmit test. This test can run in one of two modes:\n" + " * interactive mode. This sends data to the multicast addresses\n" + " and a human gets to verify it.\n" + " * local mode (default). This starts a local E131Node and sends it data,\n" + " verifying against the expected output.\n" + "\n" + " -h, --help Display this help message and exit.\n" + " -i, --interactive Run in interactive mode.\n" + << std::endl; +} + + +ola::network::Interface m_interface; +const std::string m_preferred_ip; +ola::network::UDPSocket m_socket; +uint8_t *m_recv_buffer; + +ola::acn::PreamblePacker m_packer; +ola::acn::CID cid = CID::Generate(); +ola::acn::RootSender m_root_sender(cid, true); + +//void CheckData() { +// std::cout << "Awaiting data..." << std::endl; +// if (!m_recv_buffer) +// m_recv_buffer = new uint8_t[512]; +// +// ssize_t size = 512; +// ola::network::IPV4SocketAddress source; + +// if (!m_socket.RecvFrom(m_recv_buffer, &size, &source)) +// return; + +// std::cout << "Got " << size << " bytes" << std::endl; + +// ola::FormatData(&std::cout, m_recv_buffer, size); + +// ola::acn::HeaderSet header_set; +// if (root_inflator.InflatePDUBlock(&header_set, &m_recv_buffer[16], size - 16)) { +// std::cout << "Inflated" << std::endl; +// } else { +// std::cout << "Failed to inflate" << std::endl; +// } +//} + +void HandleLLRPProbeRequest( + const ola::acn::HeaderSet *headers, + const ola::rdm::UID &lower_uid, + const ola::rdm::UID &upper_uid) { + OLA_DEBUG << "Handling probe from " << lower_uid << " to " << upper_uid; + + const ola::acn::RootHeader root_header = headers->GetRootHeader(); + const ola::acn::LLRPHeader llrp_header = headers->GetLLRPHeader(); + + OLA_DEBUG << "Source CID: " << root_header.GetCid(); + OLA_DEBUG << "TN: " << llrp_header.TransactionNumber(); + + ola::acn::LLRPHeader reply_llrp_header = LLRPHeader(root_header.GetCid(), llrp_header.TransactionNumber()); + + IPV4Address *target_address = IPV4Address::FromString("239.255.250.134"); + + OutgoingUDPTransportImpl transport_impl = OutgoingUDPTransportImpl(&m_socket, &m_packer); + OutgoingUDPTransport transport(&transport_impl, + *target_address, + ola::acn::LLRP_PORT); + + UID target_uid = UID(0x4321, 0x12345678); + MACAddress hardware_address; + MACAddress::FromString("01:23:45:67:89:ab", &hardware_address); + + LLRPProbeReplyPDU probe_reply( + LLRPProbeReplyPDU::VECTOR_PROBE_REPLY_DATA, + target_uid, + hardware_address, + LLRPProbeReplyPDU::LLRP_COMPONENT_TYPE_NON_RDMNET); + + ola::acn::LLRPPDU pdu(ola::acn::VECTOR_LLRP_PROBE_REPLY, reply_llrp_header, &probe_reply); + m_root_sender.SendPDU(ola::acn::VECTOR_ROOT_LLRP, pdu, &transport); + OLA_DEBUG << "Sent PDU"; +} + +int main(int argc, char* argv[]) { + ola::InitLogging(ola::OLA_LOG_DEBUG, ola::OLA_LOG_STDERR); + + static struct option long_options[] = { + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0} + }; + + int option_index = 0; + + while (1) { + int c = getopt_long(argc, argv, "ih", long_options, &option_index); + + if (c == -1) + break; + + switch (c) { + case 0: + break; + case 'h': + DisplayHelp(argv[0]); + return 0; + case '?': + break; + default: + break; + } + } + + ola::io::SelectServer ss; + + if (!m_socket.Init()) { + return false; + } + std::cout << "Init!" << std::endl; + + std::cout << "Using CID " << cid << std::endl; + + if (!m_socket.Bind(IPV4SocketAddress(IPV4Address::WildCard(), + ola::acn::LLRP_PORT))) { + return false; + } + std::cout << "Bind!" << std::endl; + + IPV4Address *addr = IPV4Address::FromString("239.255.250.133"); + + auto_ptr picker( + ola::network::InterfacePicker::NewPicker()); + if (!picker->ChooseInterface(&m_interface, m_preferred_ip)) { + OLA_INFO << "Failed to find an interface"; + return false; + } + + std::cout << "IF " << m_interface << std::endl; + + if (!m_socket.JoinMulticast(m_interface.ip_address, *addr)) { + OLA_WARN << "Failed to join multicast group " << addr; + } + + ola::acn::RootInflator root_inflator; + ola::acn::LLRPInflator llrp_inflator; + ola::acn::LLRPProbeRequestInflator llrp_probe_request_inflator; + llrp_probe_request_inflator.SetLLRPProbeRequestHandler( + ola::NewCallback(&HandleLLRPProbeRequest)); + + // setup all the inflators + root_inflator.AddInflator(&llrp_inflator); + llrp_inflator.AddInflator(&llrp_probe_request_inflator); + + IncomingUDPTransport m_incoming_udp_transport(&m_socket, &root_inflator); + m_socket.SetOnData(ola::NewCallback(&m_incoming_udp_transport, + &IncomingUDPTransport::Receive)); +// m_socket.SetOnData(ola::NewCallback(&CheckData)); + ss.AddReadDescriptor(&m_socket); + + std::cout << "Pre run!" << std::endl; + + ss.Run(); + + std::cout << "Run!" << std::endl; + + return 0; +} From f74347603903a10421c2c6a9224e63586dad44cc Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Sun, 9 Feb 2020 16:32:52 +0000 Subject: [PATCH 19/71] Use the correct MAC address in the responses --- tools/e133/llrp-receive-test.cpp | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/tools/e133/llrp-receive-test.cpp b/tools/e133/llrp-receive-test.cpp index e6530e6530..e5817592dc 100644 --- a/tools/e133/llrp-receive-test.cpp +++ b/tools/e133/llrp-receive-test.cpp @@ -22,6 +22,7 @@ */ #include +#include #include #include #include @@ -41,6 +42,7 @@ #include "ola/acn/ACNPort.h" #include "ola/acn/CID.h" #include "ola/io/SelectServer.h" +#include "ola/network/Interface.h" #include "ola/network/InterfacePicker.h" #include "ola/network/IPV4Address.h" #include "ola/network/MACAddress.h" @@ -60,6 +62,7 @@ using ola::acn::LLRPHeader; using ola::acn::LLRPProbeReplyPDU; using ola::acn::OutgoingUDPTransport; using ola::acn::OutgoingUDPTransportImpl; +using ola::network::Interface; using ola::network::IPV4Address; using ola::network::IPV4SocketAddress; using ola::network::MACAddress; @@ -82,7 +85,8 @@ void DisplayHelp(const char *binary_name) { << std::endl; } - +auto_ptr picker( + ola::network::InterfacePicker::NewPicker()); ola::network::Interface m_interface; const std::string m_preferred_ip; ola::network::UDPSocket m_socket; @@ -92,6 +96,20 @@ ola::acn::PreamblePacker m_packer; ola::acn::CID cid = CID::Generate(); ola::acn::RootSender m_root_sender(cid, true); +bool CompareInterfaceMACs(Interface a, Interface b) { + return a.hw_address < b.hw_address; +} + +Interface FindLowestMAC() { + // TODO(Peter): Get some clarification on whether we only care about active + // interfaces, or any installed ones? + // TODO(Peter): Work out what to do here if running on localhost only? Return + // 00:00:00:00:00:00 + std::vector interfaces = picker->GetInterfaces(false); + std::vector::iterator result = std::min_element(interfaces.begin(), interfaces.end(), CompareInterfaceMACs); + return *result; +} + //void CheckData() { // std::cout << "Awaiting data..." << std::endl; // if (!m_recv_buffer) @@ -137,13 +155,11 @@ void HandleLLRPProbeRequest( ola::acn::LLRP_PORT); UID target_uid = UID(0x4321, 0x12345678); - MACAddress hardware_address; - MACAddress::FromString("01:23:45:67:89:ab", &hardware_address); LLRPProbeReplyPDU probe_reply( LLRPProbeReplyPDU::VECTOR_PROBE_REPLY_DATA, target_uid, - hardware_address, + FindLowestMAC().hw_address, LLRPProbeReplyPDU::LLRP_COMPONENT_TYPE_NON_RDMNET); ola::acn::LLRPPDU pdu(ola::acn::VECTOR_LLRP_PROBE_REPLY, reply_llrp_header, &probe_reply); @@ -197,8 +213,6 @@ int main(int argc, char* argv[]) { IPV4Address *addr = IPV4Address::FromString("239.255.250.133"); - auto_ptr picker( - ola::network::InterfacePicker::NewPicker()); if (!picker->ChooseInterface(&m_interface, m_preferred_ip)) { OLA_INFO << "Failed to find an interface"; return false; From 7e5f9352df85a41a5ae7b641e1957f3721cb2cca Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Sun, 9 Feb 2020 18:00:49 +0000 Subject: [PATCH 20/71] Fix a typo --- libs/acn/e131_transmit_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/acn/e131_transmit_test.cpp b/libs/acn/e131_transmit_test.cpp index 342d5c21c5..7ff99a268e 100644 --- a/libs/acn/e131_transmit_test.cpp +++ b/libs/acn/e131_transmit_test.cpp @@ -14,7 +14,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * e131_transmit_test.cpp - * The sends custom E1.31 packets in order to test the implementation of a + * This sends custom E1.31 packets in order to test the implementation of a * remote node. * Copyright (C) 2010 Simon Newton * From 4983aa97960762339935cd95b6e4824f972d7146 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Sun, 9 Feb 2020 18:37:35 +0000 Subject: [PATCH 21/71] Switch to our flags module and set the UID from the command line --- tools/e133/llrp-receive-test.cpp | 69 +++++++++----------------------- 1 file changed, 18 insertions(+), 51 deletions(-) diff --git a/tools/e133/llrp-receive-test.cpp b/tools/e133/llrp-receive-test.cpp index e5817592dc..ef7d6a9a5b 100644 --- a/tools/e133/llrp-receive-test.cpp +++ b/tools/e133/llrp-receive-test.cpp @@ -13,12 +13,9 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * e131_transmit_test.cpp - * The sends custom E1.31 packets in order to test the implementation of a - * remote node. - * Copyright (C) 2010 Simon Newton - * - * The remote node needs to be listening for Universe 1. + * llrp-receive-test.cpp + * Run a very simple E1.33 LLRP Responder. + * Copyright (C) 2020 Peter Newman */ #include @@ -41,6 +38,9 @@ #include "ola/Callback.h" #include "ola/acn/ACNPort.h" #include "ola/acn/CID.h" +#include "ola/base/Flags.h" +#include "ola/base/Init.h" +#include "ola/base/SysExits.h" #include "ola/io/SelectServer.h" #include "ola/network/Interface.h" #include "ola/network/InterfacePicker.h" @@ -68,22 +68,7 @@ using ola::network::IPV4SocketAddress; using ola::network::MACAddress; using ola::rdm::UID; -/* - * Display the help message - */ -void DisplayHelp(const char *binary_name) { - std::cout << "Usage: " << binary_name << " [--interactive]\n" - "\n" - "Run the E1.31 Transmit test. This test can run in one of two modes:\n" - " * interactive mode. This sends data to the multicast addresses\n" - " and a human gets to verify it.\n" - " * local mode (default). This starts a local E131Node and sends it data,\n" - " verifying against the expected output.\n" - "\n" - " -h, --help Display this help message and exit.\n" - " -i, --interactive Run in interactive mode.\n" - << std::endl; -} +DEFINE_string(uid, "7a70:00000001", "The UID of the responder."); auto_ptr picker( ola::network::InterfacePicker::NewPicker()); @@ -91,6 +76,7 @@ ola::network::Interface m_interface; const std::string m_preferred_ip; ola::network::UDPSocket m_socket; uint8_t *m_recv_buffer; +std::auto_ptr target_uid; ola::acn::PreamblePacker m_packer; ola::acn::CID cid = CID::Generate(); @@ -154,11 +140,9 @@ void HandleLLRPProbeRequest( *target_address, ola::acn::LLRP_PORT); - UID target_uid = UID(0x4321, 0x12345678); - LLRPProbeReplyPDU probe_reply( LLRPProbeReplyPDU::VECTOR_PROBE_REPLY_DATA, - target_uid, + *target_uid, FindLowestMAC().hw_address, LLRPProbeReplyPDU::LLRP_COMPONENT_TYPE_NON_RDMNET); @@ -168,32 +152,15 @@ void HandleLLRPProbeRequest( } int main(int argc, char* argv[]) { - ola::InitLogging(ola::OLA_LOG_DEBUG, ola::OLA_LOG_STDERR); - - static struct option long_options[] = { - {"help", no_argument, 0, 'h'}, - {0, 0, 0, 0} - }; - - int option_index = 0; - - while (1) { - int c = getopt_long(argc, argv, "ih", long_options, &option_index); - - if (c == -1) - break; - - switch (c) { - case 0: - break; - case 'h': - DisplayHelp(argv[0]); - return 0; - case '?': - break; - default: - break; - } + ola::AppInit(&argc, argv, "[options]", "Run a very simple E1.33 LLRP Responder."); + + target_uid.reset(UID::FromString(FLAGS_uid)); + if (!target_uid.get()) { + OLA_WARN << "Invalid UID: " << FLAGS_uid; + ola::DisplayUsage(); + exit(ola::EXIT_USAGE); + } else { + OLA_INFO << "Started LLRP Responder with UID " << *target_uid; } ola::io::SelectServer ss; From dc06b8ae5f60c361947d2bea250103d64081dc0e Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Sun, 9 Feb 2020 23:01:12 +0000 Subject: [PATCH 22/71] Add the ability to make a UID set from binary data --- common/rdm/UIDTest.cpp | 43 ++++++++++++++++++++++++++++++++++++++++ include/ola/rdm/UIDSet.h | 15 ++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/common/rdm/UIDTest.cpp b/common/rdm/UIDTest.cpp index e02dfd0751..685df3adf5 100644 --- a/common/rdm/UIDTest.cpp +++ b/common/rdm/UIDTest.cpp @@ -245,6 +245,49 @@ void UIDTest::testUIDSet() { uint8_t expected[] = {0, 1, 0, 0, 0, 2, 0, 2, 0, 0, 0, 10, 0, 3, 0, 0, 0, 4}; OLA_ASSERT_DATA_EQUALS(expected, sizeof(expected), buffer, buffer_size); + + // Creating UIDSets from binary data + uint8_t empty[] = {}; + unsigned int data_size = sizeof(empty); + UIDSet set5(empty, &data_size); + UIDSet empty_set = UIDSet(); + OLA_ASSERT_EQ(set5, empty_set); + + uint8_t raw_short[] = {0, 1}; + data_size = sizeof(raw_short); + UIDSet set6(raw_short, &data_size); + OLA_ASSERT_EQ(set6, empty_set); + + UIDSet set7; + set7.AddUID(UID(1, 2)); + uint8_t raw_one[] = {0, 1, 0, 0, 0, 2}; + data_size = sizeof(raw_one); + UIDSet set8(raw_one, &data_size); + OLA_ASSERT_EQ(6u, data_size); + OLA_ASSERT_EQ(set7, set8); + + uint8_t raw_one_extra[] = {0, 1, 0, 0, 0, 2, 3, 4}; + data_size = sizeof(raw_one_extra); + UIDSet set9(raw_one_extra, &data_size); + OLA_ASSERT_EQ(6u, data_size); + OLA_ASSERT_EQ(set7, set9); + + set7.AddUID(UID(2, 10)); + set7.AddUID(UID(3, 4)); + + uint8_t raw_three[] = + {0, 1, 0, 0, 0, 2, 0, 2, 0, 0, 0, 10, 0, 3, 0, 0, 0, 4}; + data_size = sizeof(raw_three); + UIDSet set10(raw_three, &data_size); + OLA_ASSERT_EQ(18u, data_size); + OLA_ASSERT_EQ(set7, set10); + + uint8_t raw_three_extra[] = + {0, 1, 0, 0, 0, 2, 0, 2, 0, 0, 0, 10, 0, 3, 0, 0, 0, 4, 5, 6}; + data_size = sizeof(raw_three_extra); + UIDSet set11(raw_three_extra, &data_size); + OLA_ASSERT_EQ(18u, data_size); + OLA_ASSERT_EQ(set7, set11); } diff --git a/include/ola/rdm/UIDSet.h b/include/ola/rdm/UIDSet.h index 40ad0a0547..308cb2a68f 100644 --- a/include/ola/rdm/UIDSet.h +++ b/include/ola/rdm/UIDSet.h @@ -65,6 +65,21 @@ class UIDSet { m_uids(other.m_uids) { } + /** + * @brief Construct a new UIDSet from binary data. + * @param data a pointer to the memory containing the UIDSet data. The data + * should be most significant byte first. + * @param length is the length of the data you wish to retrieve + */ + explicit UIDSet(const uint8_t *data, unsigned int *length) { + unsigned int used_length = 0; + while ((*length - used_length) >= UID::LENGTH) { + m_uids.insert(UID(data + used_length)); + used_length += UID::LENGTH; + } + *length = used_length; + } + /** * @brief Assignment operator */ From f2343ce127c43a395ffb5dec1457bc3165b02b6a Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Sun, 9 Feb 2020 23:08:23 +0000 Subject: [PATCH 23/71] Pass all the LLRPProbeRequest info across in the callback and act on more of it --- libs/acn/LLRPProbeRequestInflator.cpp | 12 ++++++------ libs/acn/LLRPProbeRequestInflator.h | 20 +++++++++++++++----- tools/e133/llrp-receive-test.cpp | 24 +++++++++++++++++++++--- 3 files changed, 42 insertions(+), 14 deletions(-) diff --git a/libs/acn/LLRPProbeRequestInflator.cpp b/libs/acn/LLRPProbeRequestInflator.cpp index cbc2fff04d..adf7d63fdd 100644 --- a/libs/acn/LLRPProbeRequestInflator.cpp +++ b/libs/acn/LLRPProbeRequestInflator.cpp @@ -101,15 +101,15 @@ bool LLRPProbeRequestInflator::HandlePDUData(uint32_t vector, OLA_DEBUG << "Probe from " << UID(pdu_data.lower_uid) << " to " << UID(pdu_data.upper_uid); -// string rdm_message(reinterpret_cast(&data[0]), pdu_len); + LLRPProbeRequest request(UID(pdu_data.lower_uid), UID(pdu_data.upper_uid)); + request.client_tcp_connection_inactive = (pdu_data.filter & LLRPProbeRequestPDU::FILTER_CLIENT_TCP_CONNECTION_INACTIVE); + request.brokers_only = (pdu_data.filter & LLRPProbeRequestPDU::FILTER_BROKERS_ONLY); + unsigned int known_uids_used_size = known_uids_size; + request.known_uids = UIDSet(pdu_data.known_uids, &known_uids_used_size); if (m_llrp_probe_request_handler.get()) { m_llrp_probe_request_handler->Run(&headers, - UID(pdu_data.lower_uid), - UID(pdu_data.upper_uid) -//, -// UIDSet() -); + request); } else { OLA_WARN << "No LLRP Probe Request handler defined!"; } diff --git a/libs/acn/LLRPProbeRequestInflator.h b/libs/acn/LLRPProbeRequestInflator.h index 1d63b84e9f..7cb4b49302 100644 --- a/libs/acn/LLRPProbeRequestInflator.h +++ b/libs/acn/LLRPProbeRequestInflator.h @@ -34,13 +34,23 @@ class LLRPProbeRequestInflator: public BaseInflator { friend class LLRPProbeRequestInflatorTest; public: + struct LLRPProbeRequest { + LLRPProbeRequest(const ola::rdm::UID &_lower, const ola::rdm::UID &_upper) + : lower(_lower), + upper(_upper) { + } + ola::rdm::UID lower; + ola::rdm::UID upper; + bool client_tcp_connection_inactive; + bool brokers_only; + ola::rdm::UIDSet known_uids; + }; + + // These are pointers so the callers don't have to pull in all the headers. - typedef ola::Callback3 LLRPProbeRequestHandler; LLRPProbeRequestInflator(); diff --git a/tools/e133/llrp-receive-test.cpp b/tools/e133/llrp-receive-test.cpp index ef7d6a9a5b..33446730d9 100644 --- a/tools/e133/llrp-receive-test.cpp +++ b/tools/e133/llrp-receive-test.cpp @@ -60,6 +60,7 @@ using ola::acn::CID; using ola::acn::IncomingUDPTransport; using ola::acn::LLRPHeader; using ola::acn::LLRPProbeReplyPDU; +using ola::acn::LLRPProbeRequestInflator; using ola::acn::OutgoingUDPTransport; using ola::acn::OutgoingUDPTransportImpl; using ola::network::Interface; @@ -121,9 +122,23 @@ Interface FindLowestMAC() { void HandleLLRPProbeRequest( const ola::acn::HeaderSet *headers, - const ola::rdm::UID &lower_uid, - const ola::rdm::UID &upper_uid) { - OLA_DEBUG << "Handling probe from " << lower_uid << " to " << upper_uid; + const LLRPProbeRequestInflator::LLRPProbeRequest &request) { + OLA_DEBUG << "Potentially handling probe from " << request.lower << " to " + << request.upper; + + if ((*target_uid < request.lower) || (*target_uid > request.upper)) { + OLA_INFO << "Ignoring probe request as we are not in the target UID range"; + return; + } + + OLA_DEBUG << "Known UIDs are: " << request.known_uids; + + if (request.known_uids.Contains(*target_uid)) { + OLA_INFO << "Ignoring probe request as we are already in the known UID list"; + return; + } + + // TODO(Peter): Check the filter bits! const ola::acn::RootHeader root_header = headers->GetRootHeader(); const ola::acn::LLRPHeader llrp_header = headers->GetLLRPHeader(); @@ -147,6 +162,9 @@ void HandleLLRPProbeRequest( LLRPProbeReplyPDU::LLRP_COMPONENT_TYPE_NON_RDMNET); ola::acn::LLRPPDU pdu(ola::acn::VECTOR_LLRP_PROBE_REPLY, reply_llrp_header, &probe_reply); + + // TODO(Peter): Delay sending by 0 to LLRP_MAX_BACKOFF! + m_root_sender.SendPDU(ola::acn::VECTOR_ROOT_LLRP, pdu, &transport); OLA_DEBUG << "Sent PDU"; } From 95837932508cb6d2fb08cd784cf3528120f251a3 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Mon, 10 Feb 2020 21:18:07 +0000 Subject: [PATCH 24/71] Fix a typo --- tools/e133/E133Device.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/e133/E133Device.cpp b/tools/e133/E133Device.cpp index c9350d61f6..ca2a4a69f9 100644 --- a/tools/e133/E133Device.cpp +++ b/tools/e133/E133Device.cpp @@ -205,8 +205,7 @@ void E133Device::EndpointRequest( const string &raw_request) { IPV4SocketAddress target = transport_header->Source(); uint16_t endpoint_id = e133_header->Endpoint(); - OLA_INFO << "Got request for to endpoint " << endpoint_id - << " from " << target; + OLA_INFO << "Got request for endpoint " << endpoint_id << " from " << target; E133EndpointInterface *endpoint = NULL; if (endpoint_id) From 1955638b07cb996447b8ba3c7274ce79514d244e Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Tue, 11 Feb 2020 00:08:26 +0000 Subject: [PATCH 25/71] Allow the RDMInflator to be used with both native E1.33 and LLRP RDM messages --- libs/acn/RDMInflator.cpp | 25 +++++++++++++++++++------ libs/acn/RDMInflator.h | 12 ++++++++++-- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/libs/acn/RDMInflator.cpp b/libs/acn/RDMInflator.cpp index a18f634e01..a4e32166e1 100644 --- a/libs/acn/RDMInflator.cpp +++ b/libs/acn/RDMInflator.cpp @@ -32,13 +32,14 @@ using std::string; /** * Create a new RDM inflator */ -RDMInflator::RDMInflator() - : BaseInflator(PDU::ONE_BYTE) { +RDMInflator::RDMInflator(unsigned int vector) + : BaseInflator(PDU::ONE_BYTE), + m_vector(vector) { } /** - * Set a RDMHandler to run when receiving a RDM message. - * @param handler the callback to invoke when there is rdm data for this + * Set an RDMMessageHandler to run when receiving a RDM message. + * @param handler the callback to invoke when there is RDM data for this * universe. */ void RDMInflator::SetRDMHandler(RDMMessageHandler *handler) { @@ -46,6 +47,16 @@ void RDMInflator::SetRDMHandler(RDMMessageHandler *handler) { } +/** + * Set a GenericRDMHandler to run when receiving a RDM message. + * @param handler the callback to invoke when there is RDM data for this + * universe. + */ +void RDMInflator::SetGenericRDMHandler(GenericRDMMessageHandler *handler) { + m_generic_rdm_handler.reset(handler); +} + + /* * Decode the RDM 'header', which is 0 bytes in length. * @param headers the HeaderSet to add to @@ -76,11 +87,13 @@ bool RDMInflator::HandlePDUData(uint32_t vector, string rdm_message(reinterpret_cast(&data[0]), pdu_len); - E133Header e133_header = headers.GetE133Header(); - if (m_rdm_handler.get()) { + E133Header e133_header = headers.GetE133Header(); + m_rdm_handler->Run(&headers.GetTransportHeader(), &e133_header, rdm_message); + } else if (m_generic_rdm_handler.get()) { + m_generic_rdm_handler->Run(&headers, rdm_message); } else { OLA_WARN << "No RDM handler defined!"; } diff --git a/libs/acn/RDMInflator.h b/libs/acn/RDMInflator.h index 36ccf48930..4c37cf6c0c 100644 --- a/libs/acn/RDMInflator.h +++ b/libs/acn/RDMInflator.h @@ -41,12 +41,18 @@ class RDMInflator: public BaseInflator { const std::string& // rdm data > RDMMessageHandler; - RDMInflator(); + typedef ola::Callback2 GenericRDMMessageHandler; + + RDMInflator(unsigned int vector = ola::acn::VECTOR_FRAMING_RDMNET); ~RDMInflator() {} - uint32_t Id() const { return ola::acn::VECTOR_FRAMING_RDMNET; } + uint32_t Id() const { return m_vector; } void SetRDMHandler(RDMMessageHandler *handler); + void SetGenericRDMHandler(GenericRDMMessageHandler *handler); static const unsigned int VECTOR_RDMNET_DATA = 0xcc; @@ -65,6 +71,8 @@ class RDMInflator: public BaseInflator { private: std::auto_ptr m_rdm_handler; + std::auto_ptr m_generic_rdm_handler; + unsigned int m_vector; }; } // namespace acn } // namespace ola From 32ecc529a99a243c79afc85e5174bf6e8507ca3b Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Tue, 11 Feb 2020 00:53:01 +0000 Subject: [PATCH 26/71] Add the ability to pack an RDMPDU --- libs/acn/RDMPDU.cpp | 15 ++++++ libs/acn/RDMPDU.h | 24 +++++++++- libs/acn/RDMPDUTest.cpp | 103 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 141 insertions(+), 1 deletion(-) diff --git a/libs/acn/RDMPDU.cpp b/libs/acn/RDMPDU.cpp index 7b7b61f6c8..cab7d20a5c 100644 --- a/libs/acn/RDMPDU.cpp +++ b/libs/acn/RDMPDU.cpp @@ -29,6 +29,21 @@ namespace acn { using ola::io::OutputStream; using ola::network::HostToNetwork; +unsigned int RDMPDU::DataSize() const { + return static_cast(m_command.size()); +} + +bool RDMPDU::PackData(uint8_t *data, unsigned int *length) const { + *length = static_cast(m_command.size()); + memcpy(data, reinterpret_cast(m_command.data()), *length); + return true; +} + +void RDMPDU::PackData(ola::io::OutputStream *stream) const { + stream->Write(reinterpret_cast(m_command.data()), + static_cast(m_command.size())); +} + void RDMPDU::PrependPDU(ola::io::IOStack *stack) { uint8_t vector = HostToNetwork(ola::rdm::START_CODE); stack->Write(reinterpret_cast(&vector), sizeof(vector)); diff --git a/libs/acn/RDMPDU.h b/libs/acn/RDMPDU.h index 8d36e0ced7..c51d9a140f 100644 --- a/libs/acn/RDMPDU.h +++ b/libs/acn/RDMPDU.h @@ -21,16 +21,38 @@ #ifndef LIBS_ACN_RDMPDU_H_ #define LIBS_ACN_RDMPDU_H_ +#include +#include #include +#include #include "libs/acn/PDU.h" namespace ola { namespace acn { -class RDMPDU : private PDU { +class RDMPDU : public PDU { public: + explicit RDMPDU(const ola::io::ByteString &command): + PDU(ola::rdm::START_CODE, ONE_BYTE, true), + m_command(command) {} + + 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; + bool PackData(uint8_t *data, unsigned int *length) const; + void PackData(ola::io::OutputStream *stream) const; + static void PrependPDU(ola::io::IOStack *stack); + + private: + const ola::io::ByteString m_command; }; } // namespace acn } // namespace ola diff --git a/libs/acn/RDMPDUTest.cpp b/libs/acn/RDMPDUTest.cpp index 4c6ce89df2..ff6489d0fb 100644 --- a/libs/acn/RDMPDUTest.cpp +++ b/libs/acn/RDMPDUTest.cpp @@ -23,6 +23,8 @@ #include #include "ola/Logging.h" +#include "ola/io/ByteString.h" +#include "ola/io/IOQueue.h" #include "ola/io/IOStack.h" #include "ola/network/NetworkUtils.h" #include "ola/testing/TestUtils.h" @@ -32,24 +34,125 @@ namespace ola { namespace acn { +using ola::io::ByteString; +using ola::io::IOQueue; using ola::io::IOStack; +using ola::io::OutputStream; +using ola::network::HostToNetwork; class RDMPDUTest: public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(RDMPDUTest); + CPPUNIT_TEST(testSimpleRDMPDU); + CPPUNIT_TEST(testSimpleRDMPDUToOutputStream); CPPUNIT_TEST(testPrepend); CPPUNIT_TEST_SUITE_END(); public: + void testSimpleRDMPDU(); + void testSimpleRDMPDUToOutputStream(); void testPrepend(); private: static const unsigned int TEST_VECTOR; + static const uint8_t EXPECTED_GET_RESPONSE_BUFFER[]; }; CPPUNIT_TEST_SUITE_REGISTRATION(RDMPDUTest); const unsigned int RDMPDUTest::TEST_VECTOR = 0xcc; +const uint8_t RDMPDUTest::EXPECTED_GET_RESPONSE_BUFFER[] = { + 1, 28, // sub code & length + 0, 3, 0, 0, 0, 4, // dst uid + 0, 1, 0, 0, 0, 2, // src uid + 0, 0, 0, 0, 10, // transaction, port id, msg count & sub device + 0x21, 1, 40, 4, // command, param id, param data length + 0x5a, 0x5a, 0x5a, 0x5a, // param data + 0x02, 0xb3 // checksum +}; + +/* + * Test that packing an RDMPDU works. + */ +void RDMPDUTest::testSimpleRDMPDU() { + ByteString empty; + RDMPDU empty_pdu(empty); + + OLA_ASSERT_EQ(0u, empty_pdu.HeaderSize()); + OLA_ASSERT_EQ(0u, empty_pdu.DataSize()); + OLA_ASSERT_EQ(4u, empty_pdu.Size()); + + ByteString response(EXPECTED_GET_RESPONSE_BUFFER, + sizeof(EXPECTED_GET_RESPONSE_BUFFER)); + RDMPDU pdu(response); + + OLA_ASSERT_EQ(0u, pdu.HeaderSize()); + OLA_ASSERT_EQ(29u, pdu.DataSize()); + OLA_ASSERT_EQ(33u, 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]); + + // 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 RDMPDUTest::testSimpleRDMPDUToOutputStream() { + ByteString response(EXPECTED_GET_RESPONSE_BUFFER, + sizeof(EXPECTED_GET_RESPONSE_BUFFER)); + RDMPDU pdu(response); + + OLA_ASSERT_EQ(0u, pdu.HeaderSize()); + OLA_ASSERT_EQ(29u, pdu.DataSize()); + OLA_ASSERT_EQ(33u, pdu.Size()); + + IOQueue output; + OutputStream stream(&output); + pdu.Write(&stream); + OLA_ASSERT_EQ(33u, 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, 0x21, + 0xcc, + 1, 28, // sub code & length + 0, 3, 0, 0, 0, 4, // dst uid + 0, 1, 0, 0, 0, 2, // src uid + 0, 0, 0, 0, 10, // transaction, port id, msg count & sub device + 0x21, 1, 40, 4, // command, param id, param data length + 0x5a, 0x5a, 0x5a, 0x5a, // param data + 0x02, 0xb3 // checksum + }; + OLA_ASSERT_DATA_EQUALS(EXPECTED, sizeof(EXPECTED), pdu_data, pdu_size); + output.Pop(output.Size()); + delete[] pdu_data; +} + + void RDMPDUTest::testPrepend() { IOStack stack; RDMPDU::PrependPDU(&stack); From 04697246fce5dc48d4489eac8e43c90fe5920353 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Tue, 11 Feb 2020 00:59:34 +0000 Subject: [PATCH 27/71] Initial version of an LLRP RDM responder --- tools/e133/llrp-receive-test.cpp | 129 ++++++++++++++++++++----------- 1 file changed, 85 insertions(+), 44 deletions(-) diff --git a/tools/e133/llrp-receive-test.cpp b/tools/e133/llrp-receive-test.cpp index 33446730d9..bb9a8921d4 100644 --- a/tools/e133/llrp-receive-test.cpp +++ b/tools/e133/llrp-receive-test.cpp @@ -23,6 +23,26 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "libs/acn/HeaderSet.h" #include "libs/acn/LLRPHeader.h" #include "libs/acn/LLRPInflator.h" @@ -30,27 +50,13 @@ #include "libs/acn/LLRPProbeReplyPDU.h" #include "libs/acn/LLRPProbeRequestInflator.h" #include "libs/acn/PreamblePacker.h" +#include "libs/acn/RDMInflator.h" +#include "libs/acn/RDMPDU.h" #include "libs/acn/RootHeader.h" #include "libs/acn/RootInflator.h" #include "libs/acn/RootSender.h" #include "libs/acn/Transport.h" #include "libs/acn/UDPTransport.h" -#include "ola/Callback.h" -#include "ola/acn/ACNPort.h" -#include "ola/acn/CID.h" -#include "ola/base/Flags.h" -#include "ola/base/Init.h" -#include "ola/base/SysExits.h" -#include "ola/io/SelectServer.h" -#include "ola/network/Interface.h" -#include "ola/network/InterfacePicker.h" -#include "ola/network/IPV4Address.h" -#include "ola/network/MACAddress.h" -#include "ola/network/SocketAddress.h" -#include "ola/network/Socket.h" -#include "ola/rdm/UID.h" -#include "ola/DmxBuffer.h" -#include "ola/Logging.h" using std::string; using std::vector; @@ -78,6 +84,7 @@ const std::string m_preferred_ip; ola::network::UDPSocket m_socket; uint8_t *m_recv_buffer; std::auto_ptr target_uid; +std::auto_ptr dummy_responder; ola::acn::PreamblePacker m_packer; ola::acn::CID cid = CID::Generate(); @@ -97,29 +104,6 @@ Interface FindLowestMAC() { return *result; } -//void CheckData() { -// std::cout << "Awaiting data..." << std::endl; -// if (!m_recv_buffer) -// m_recv_buffer = new uint8_t[512]; -// -// ssize_t size = 512; -// ola::network::IPV4SocketAddress source; - -// if (!m_socket.RecvFrom(m_recv_buffer, &size, &source)) -// return; - -// std::cout << "Got " << size << " bytes" << std::endl; - -// ola::FormatData(&std::cout, m_recv_buffer, size); - -// ola::acn::HeaderSet header_set; -// if (root_inflator.InflatePDUBlock(&header_set, &m_recv_buffer[16], size - 16)) { -// std::cout << "Inflated" << std::endl; -// } else { -// std::cout << "Failed to inflate" << std::endl; -// } -//} - void HandleLLRPProbeRequest( const ola::acn::HeaderSet *headers, const LLRPProbeRequestInflator::LLRPProbeRequest &request) { @@ -169,6 +153,62 @@ void HandleLLRPProbeRequest( OLA_DEBUG << "Sent PDU"; } +void RDMRequestComplete( + ola::acn::HeaderSet headers, + ola::rdm::RDMReply *reply) { + OLA_INFO << "Got RDM reply to send"; + OLA_DEBUG << reply->ToString(); + + const ola::acn::RootHeader root_header = headers.GetRootHeader(); + const ola::acn::LLRPHeader llrp_header = headers.GetLLRPHeader(); + + OLA_DEBUG << "Source CID: " << root_header.GetCid(); + OLA_DEBUG << "TN: " << llrp_header.TransactionNumber(); + + ola::acn::LLRPHeader reply_llrp_header = LLRPHeader(root_header.GetCid(), llrp_header.TransactionNumber()); + + IPV4Address *target_address = IPV4Address::FromString("239.255.250.134"); + + OutgoingUDPTransportImpl transport_impl = OutgoingUDPTransportImpl(&m_socket, &m_packer); + OutgoingUDPTransport transport(&transport_impl, + *target_address, + ola::acn::LLRP_PORT); + + ola::io::ByteString raw_reply; + ola::rdm::RDMCommandSerializer::Pack(*reply->Response(), &raw_reply); + + ola::acn::RDMPDU rdm_reply(raw_reply); + + ola::acn::LLRPPDU pdu(ola::acn::VECTOR_LLRP_RDM_CMD, reply_llrp_header, &rdm_reply); + + m_root_sender.SendPDU(ola::acn::VECTOR_ROOT_LLRP, pdu, &transport); + OLA_DEBUG << "Sent RDM PDU"; +} + +void HandleRDM( + const ola::acn::HeaderSet *headers, + const string &raw_request) { + IPV4SocketAddress target = headers->GetTransportHeader().Source(); + OLA_INFO << "Got RDM request from " << target; + + // attempt to unpack as a request + ola::rdm::RDMRequest *request = ola::rdm::RDMRequest::InflateFromData( + reinterpret_cast(raw_request.data()), + raw_request.size()); + + if (!request) { + OLA_WARN << "Failed to unpack LLRP RDM message, ignoring request."; + return; + } else { + OLA_DEBUG << "Got RDM request " << request->ToString(); + } + + dummy_responder->SendRDMRequest( + request, + ola::NewSingleCallback(&RDMRequestComplete, + *headers)); +} + int main(int argc, char* argv[]) { ola::AppInit(&argc, argv, "[options]", "Run a very simple E1.33 LLRP Responder."); @@ -181,6 +221,8 @@ int main(int argc, char* argv[]) { OLA_INFO << "Started LLRP Responder with UID " << *target_uid; } + dummy_responder.reset(new ola::rdm::DummyResponder(*target_uid)); + ola::io::SelectServer ss; if (!m_socket.Init()) { @@ -214,22 +256,21 @@ int main(int argc, char* argv[]) { ola::acn::LLRPProbeRequestInflator llrp_probe_request_inflator; llrp_probe_request_inflator.SetLLRPProbeRequestHandler( ola::NewCallback(&HandleLLRPProbeRequest)); + ola::acn::RDMInflator llrp_rdm_inflator(ola::acn::VECTOR_LLRP_RDM_CMD); + llrp_rdm_inflator.SetGenericRDMHandler( + ola::NewCallback(&HandleRDM)); // setup all the inflators root_inflator.AddInflator(&llrp_inflator); llrp_inflator.AddInflator(&llrp_probe_request_inflator); + llrp_inflator.AddInflator(&llrp_rdm_inflator); IncomingUDPTransport m_incoming_udp_transport(&m_socket, &root_inflator); m_socket.SetOnData(ola::NewCallback(&m_incoming_udp_transport, &IncomingUDPTransport::Receive)); -// m_socket.SetOnData(ola::NewCallback(&CheckData)); ss.AddReadDescriptor(&m_socket); - std::cout << "Pre run!" << std::endl; - ss.Run(); - std::cout << "Run!" << std::endl; - return 0; } From a150d7e263d3e55c3403af9325e37b6ef04644ad Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Tue, 11 Feb 2020 16:57:48 +0000 Subject: [PATCH 28/71] Add the LLRP Broadcast CID --- include/ola/acn/CID.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/ola/acn/CID.h b/include/ola/acn/CID.h index 3b98d127d7..295b0786c2 100644 --- a/include/ola/acn/CID.h +++ b/include/ola/acn/CID.h @@ -141,6 +141,10 @@ class CID { */ static CID FromString(const std::string &cid); + static CID LLRPBroadcastCID() { + return FromString("FBAD822C-BD0C-4D4C-BDC8-7EABEBC85AFF"); + } + private: class CIDImpl *m_impl; From b0662a0eaf3fb3c10d9be0945f6fa731793be414 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Tue, 11 Feb 2020 17:01:48 +0000 Subject: [PATCH 29/71] Fix some lint issues and follow more of the standard --- tools/e133/llrp-receive-test.cpp | 74 +++++++++++++++++++++++++------- 1 file changed, 59 insertions(+), 15 deletions(-) diff --git a/tools/e133/llrp-receive-test.cpp b/tools/e133/llrp-receive-test.cpp index bb9a8921d4..f669551df2 100644 --- a/tools/e133/llrp-receive-test.cpp +++ b/tools/e133/llrp-receive-test.cpp @@ -18,11 +18,6 @@ * Copyright (C) 2020 Peter Newman */ -#include -#include -#include -#include -#include #include #include #include @@ -39,10 +34,17 @@ #include #include #include +#include #include #include #include #include + +#include +#include +#include +#include + #include "libs/acn/HeaderSet.h" #include "libs/acn/LLRPHeader.h" #include "libs/acn/LLRPInflator.h" @@ -69,6 +71,7 @@ using ola::acn::LLRPProbeReplyPDU; using ola::acn::LLRPProbeRequestInflator; using ola::acn::OutgoingUDPTransport; using ola::acn::OutgoingUDPTransportImpl; +using ola::acn::RootHeader; using ola::network::Interface; using ola::network::IPV4Address; using ola::network::IPV4SocketAddress; @@ -87,9 +90,14 @@ std::auto_ptr target_uid; std::auto_ptr dummy_responder; ola::acn::PreamblePacker m_packer; -ola::acn::CID cid = CID::Generate(); +CID cid = CID::Generate(); ola::acn::RootSender m_root_sender(cid, true); +bool CheckCIDAddressedToUs(const CID destination_cid) { + return (destination_cid == CID::LLRPBroadcastCID() || + destination_cid == cid); +} + bool CompareInterfaceMACs(Interface a, Interface b) { return a.hw_address < b.hw_address; } @@ -99,8 +107,10 @@ Interface FindLowestMAC() { // interfaces, or any installed ones? // TODO(Peter): Work out what to do here if running on localhost only? Return // 00:00:00:00:00:00 - std::vector interfaces = picker->GetInterfaces(false); - std::vector::iterator result = std::min_element(interfaces.begin(), interfaces.end(), CompareInterfaceMACs); + vector interfaces = picker->GetInterfaces(false); + vector::iterator result = std::min_element(interfaces.begin(), + interfaces.end(), + CompareInterfaceMACs); return *result; } @@ -110,6 +120,12 @@ void HandleLLRPProbeRequest( OLA_DEBUG << "Potentially handling probe from " << request.lower << " to " << request.upper; + const LLRPHeader llrp_header = headers->GetLLRPHeader(); + if (!CheckCIDAddressedToUs(llrp_header.DestinationCid())) { + OLA_INFO << "Ignoring probe request as it's not addressed to us or the LLRP broadcast CID"; + return; + } + if ((*target_uid < request.lower) || (*target_uid > request.upper)) { OLA_INFO << "Ignoring probe request as we are not in the target UID range"; return; @@ -118,19 +134,20 @@ void HandleLLRPProbeRequest( OLA_DEBUG << "Known UIDs are: " << request.known_uids; if (request.known_uids.Contains(*target_uid)) { - OLA_INFO << "Ignoring probe request as we are already in the known UID list"; + OLA_INFO << "Ignoring probe request as we are already in the known UID " + << "list"; return; } // TODO(Peter): Check the filter bits! - const ola::acn::RootHeader root_header = headers->GetRootHeader(); - const ola::acn::LLRPHeader llrp_header = headers->GetLLRPHeader(); + const RootHeader root_header = headers->GetRootHeader(); OLA_DEBUG << "Source CID: " << root_header.GetCid(); OLA_DEBUG << "TN: " << llrp_header.TransactionNumber(); - ola::acn::LLRPHeader reply_llrp_header = LLRPHeader(root_header.GetCid(), llrp_header.TransactionNumber()); + LLRPHeader reply_llrp_header = LLRPHeader(root_header.GetCid(), + llrp_header.TransactionNumber()); IPV4Address *target_address = IPV4Address::FromString("239.255.250.134"); @@ -159,13 +176,20 @@ void RDMRequestComplete( OLA_INFO << "Got RDM reply to send"; OLA_DEBUG << reply->ToString(); - const ola::acn::RootHeader root_header = headers.GetRootHeader(); - const ola::acn::LLRPHeader llrp_header = headers.GetLLRPHeader(); +// TODO(Peter): Do the below +//LLRP Targets shall not return RDM responses with response types of ACK_TIMER or +//ACK_OVERFLOW. LLRP Targets shall respond with a NACK with reason code +//NR_ACTION_NOT_SUPPORTED to any RDM request that cannot be answered without starting +//an ACK_TIMER or ACK_OVERFLOW sequence. + + const RootHeader root_header = headers.GetRootHeader(); + const LLRPHeader llrp_header = headers.GetLLRPHeader(); OLA_DEBUG << "Source CID: " << root_header.GetCid(); OLA_DEBUG << "TN: " << llrp_header.TransactionNumber(); - ola::acn::LLRPHeader reply_llrp_header = LLRPHeader(root_header.GetCid(), llrp_header.TransactionNumber()); + LLRPHeader reply_llrp_header = LLRPHeader(root_header.GetCid(), + llrp_header.TransactionNumber()); IPV4Address *target_address = IPV4Address::FromString("239.255.250.134"); @@ -191,6 +215,11 @@ void HandleRDM( IPV4SocketAddress target = headers->GetTransportHeader().Source(); OLA_INFO << "Got RDM request from " << target; + if (!CheckCIDAddressedToUs(headers->GetLLRPHeader().DestinationCid())) { + OLA_INFO << "Ignoring probe request as it's not addressed to us or the LLRP broadcast CID"; + return; + } + // attempt to unpack as a request ola::rdm::RDMRequest *request = ola::rdm::RDMRequest::InflateFromData( reinterpret_cast(raw_request.data()), @@ -203,6 +232,20 @@ void HandleRDM( OLA_DEBUG << "Got RDM request " << request->ToString(); } + if (!request->DestinationUID().DirectedToUID(*target_uid)) { + OLA_WARN << "Destination UID " << request->DestinationUID() << " was not " + << "directed to us"; + return; + } + + if (!((request->SubDevice() == ola::rdm::ROOT_RDM_DEVICE) || + (request->SubDevice() == ola::rdm::ALL_RDM_SUBDEVICES))) { + OLA_WARN << "Subdevice " << request->SubDevice() << " was not the root or " + << "broadcast subdevice"; + // TODO(Peter): NACK with NR_SUB_DEVICE_OUT_OF_RANGE + return; + } + dummy_responder->SendRDMRequest( request, ola::NewSingleCallback(&RDMRequestComplete, @@ -249,6 +292,7 @@ int main(int argc, char* argv[]) { if (!m_socket.JoinMulticast(m_interface.ip_address, *addr)) { OLA_WARN << "Failed to join multicast group " << addr; + return false; } ola::acn::RootInflator root_inflator; From 280d3f6d02d4803997a67dd977a458c2f0c2615b Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Mon, 17 Feb 2020 02:52:32 +0000 Subject: [PATCH 30/71] Ensure we work on the same host as the manager --- tools/e133/llrp-receive-test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/e133/llrp-receive-test.cpp b/tools/e133/llrp-receive-test.cpp index f669551df2..8edbf4f3a3 100644 --- a/tools/e133/llrp-receive-test.cpp +++ b/tools/e133/llrp-receive-test.cpp @@ -290,7 +290,7 @@ int main(int argc, char* argv[]) { std::cout << "IF " << m_interface << std::endl; - if (!m_socket.JoinMulticast(m_interface.ip_address, *addr)) { + if (!m_socket.JoinMulticast(m_interface.ip_address, *addr, true)) { OLA_WARN << "Failed to join multicast group " << addr; return false; } From 324b4ec341d20d121c57e61afc6d272a6951d0c1 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Mon, 17 Feb 2020 16:20:57 +0000 Subject: [PATCH 31/71] Add a helper method to convert an RDMResponse to a NACKing RDMResponse --- common/rdm/RDMCommand.cpp | 16 ++++++++++++++++ common/rdm/RDMCommandTest.cpp | 27 +++++++++++++++++++++++++++ include/ola/rdm/RDMCommand.h | 8 ++++++++ 3 files changed, 51 insertions(+) diff --git a/common/rdm/RDMCommand.cpp b/common/rdm/RDMCommand.cpp index 3dd0987836..c8f0d145b8 100644 --- a/common/rdm/RDMCommand.cpp +++ b/common/rdm/RDMCommand.cpp @@ -592,6 +592,22 @@ RDMResponse *NackWithReason(const RDMRequest *request, outstanding_messages); } +RDMResponse *NackWithReason(const RDMResponse *response, + rdm_nack_reason reason_enum) { + uint16_t reason = ola::network::HostToNetwork( + static_cast(reason_enum)); + return new RDMResponse(response->SourceUID(), + response->DestinationUID(), + response->TransactionNumber(), + RDM_NACK_REASON, + response->MessageCount(), + response->SubDevice(), + response->CommandClass(), + response->ParamId(), + reinterpret_cast(&reason), + sizeof(reason)); +} + RDMResponse *GetResponseFromData(const RDMRequest *request, const uint8_t *data, unsigned int length, diff --git a/common/rdm/RDMCommandTest.cpp b/common/rdm/RDMCommandTest.cpp index 77d160f6ca..91b16efe47 100644 --- a/common/rdm/RDMCommandTest.cpp +++ b/common/rdm/RDMCommandTest.cpp @@ -670,6 +670,33 @@ void RDMCommandTest::testNackWithReason() { OLA_ASSERT_EQ(2u, response->ParamDataSize()); OLA_ASSERT_EQ((uint16_t) ola::rdm::NR_WRITE_PROTECT, NackReasonFromResponse(response.get())); + + RDMResponse get_command_response(source, + destination, + 0, // transaction # + ola::rdm::RDM_ACK, // response type + 5, // message count + 10, // sub device + RDMCommand::GET_COMMAND_RESPONSE, + 296, // param id + NULL, // data + 0); // data length + + response.reset(NackWithReason(&get_command_response, + ola::rdm::NR_DATA_OUT_OF_RANGE)); + OLA_ASSERT_NOT_NULL(response.get()); + // Comparing response to response, so no flipping of UIDs + OLA_ASSERT_EQ(source, response->SourceUID()); + OLA_ASSERT_EQ(destination, response->DestinationUID()); + OLA_ASSERT_EQ((uint8_t) 0, response->TransactionNumber()); + OLA_ASSERT_EQ((uint8_t) ola::rdm::RDM_NACK_REASON, response->ResponseType()); + OLA_ASSERT_EQ((uint8_t) 5, response->MessageCount()); + OLA_ASSERT_EQ((uint16_t) 10, response->SubDevice()); + OLA_ASSERT_EQ(RDMCommand::GET_COMMAND_RESPONSE, response->CommandClass()); + OLA_ASSERT_EQ((uint16_t) 296, response->ParamId()); + OLA_ASSERT_EQ(2u, response->ParamDataSize()); + OLA_ASSERT_EQ((uint16_t) ola::rdm::NR_DATA_OUT_OF_RANGE, + NackReasonFromResponse(response.get())); } diff --git a/include/ola/rdm/RDMCommand.h b/include/ola/rdm/RDMCommand.h index 56d02dabd0..50948860bf 100644 --- a/include/ola/rdm/RDMCommand.h +++ b/include/ola/rdm/RDMCommand.h @@ -649,6 +649,14 @@ typedef BaseRDMResponse RDMSetResponse; RDMResponse *NackWithReason(const RDMRequest *request, rdm_nack_reason reason, uint8_t outstanding_messages = 0); + +/** + * @brief Make a NACK response with a reason code based on an existing + * RDMResponse + */ +RDMResponse *NackWithReason(const RDMResponse *response, + rdm_nack_reason reason); + /** * @brief Generate an ACK Response with some data */ From ccba9fab044c5acb92aae5f766e6719b0e6babb6 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Mon, 17 Feb 2020 17:06:19 +0000 Subject: [PATCH 32/71] Don't send back ACK_OVERFLOW or ACK_TIMER responses --- tools/e133/llrp-receive-test.cpp | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/tools/e133/llrp-receive-test.cpp b/tools/e133/llrp-receive-test.cpp index 8edbf4f3a3..c3e8041064 100644 --- a/tools/e133/llrp-receive-test.cpp +++ b/tools/e133/llrp-receive-test.cpp @@ -32,10 +32,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -76,6 +78,7 @@ using ola::network::Interface; using ola::network::IPV4Address; using ola::network::IPV4SocketAddress; using ola::network::MACAddress; +using ola::rdm::RDMResponse; using ola::rdm::UID; DEFINE_string(uid, "7a70:00000001", "The UID of the responder."); @@ -176,11 +179,20 @@ void RDMRequestComplete( OLA_INFO << "Got RDM reply to send"; OLA_DEBUG << reply->ToString(); -// TODO(Peter): Do the below -//LLRP Targets shall not return RDM responses with response types of ACK_TIMER or -//ACK_OVERFLOW. LLRP Targets shall respond with a NACK with reason code -//NR_ACTION_NOT_SUPPORTED to any RDM request that cannot be answered without starting -//an ACK_TIMER or ACK_OVERFLOW sequence. + const RDMResponse *response = reply->Response(); + uint8_t response_type = response->ResponseType(); + + if (response_type == ola::rdm::RDM_ACK_TIMER || + response_type == ola::rdm::ACK_OVERFLOW) { + // Technically we shouldn't have even actioned the request but we can't + // really do that in OLA, as we don't know what it might return until we've + // done it + OLA_DEBUG << "Got a disallowed ACK, mangling to NR_ACTION_NOT_SUPPORTED"; + response = NackWithReason(response, ola::rdm::NR_ACTION_NOT_SUPPORTED); + } else { + OLA_DEBUG << "Got an acceptable response type: " + << (unsigned int)response_type; + } const RootHeader root_header = headers.GetRootHeader(); const LLRPHeader llrp_header = headers.GetLLRPHeader(); @@ -199,7 +211,7 @@ void RDMRequestComplete( ola::acn::LLRP_PORT); ola::io::ByteString raw_reply; - ola::rdm::RDMCommandSerializer::Pack(*reply->Response(), &raw_reply); + ola::rdm::RDMCommandSerializer::Pack(*response, &raw_reply); ola::acn::RDMPDU rdm_reply(raw_reply); @@ -216,7 +228,7 @@ void HandleRDM( OLA_INFO << "Got RDM request from " << target; if (!CheckCIDAddressedToUs(headers->GetLLRPHeader().DestinationCid())) { - OLA_INFO << "Ignoring probe request as it's not addressed to us or the LLRP broadcast CID"; + OLA_INFO << "Ignoring RDM request as it's not addressed to us or the LLRP broadcast CID"; return; } @@ -283,13 +295,17 @@ int main(int argc, char* argv[]) { IPV4Address *addr = IPV4Address::FromString("239.255.250.133"); - if (!picker->ChooseInterface(&m_interface, m_preferred_ip)) { + ola::network::InterfacePicker::Options options; + options.include_loopback = false; + if (!picker->ChooseInterface(&m_interface, m_preferred_ip, options)) { OLA_INFO << "Failed to find an interface"; return false; } std::cout << "IF " << m_interface << std::endl; + // If we enable multicast loopback, we can test two bits of software on the + // same machine, but we get, and must ignore, all our own requests too if (!m_socket.JoinMulticast(m_interface.ip_address, *addr, true)) { OLA_WARN << "Failed to join multicast group " << addr; return false; From 52e8913b99436fa8e5773f98fa5841c0667356ef Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Mon, 17 Feb 2020 17:26:39 +0000 Subject: [PATCH 33/71] NACK if an invalid subdevice is targetted --- tools/e133/llrp-receive-test.cpp | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/tools/e133/llrp-receive-test.cpp b/tools/e133/llrp-receive-test.cpp index c3e8041064..efed057d2f 100644 --- a/tools/e133/llrp-receive-test.cpp +++ b/tools/e133/llrp-receive-test.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -78,6 +79,7 @@ using ola::network::Interface; using ola::network::IPV4Address; using ola::network::IPV4SocketAddress; using ola::network::MACAddress; +using ola::rdm::RDMReply; using ola::rdm::RDMResponse; using ola::rdm::UID; @@ -253,15 +255,19 @@ void HandleRDM( if (!((request->SubDevice() == ola::rdm::ROOT_RDM_DEVICE) || (request->SubDevice() == ola::rdm::ALL_RDM_SUBDEVICES))) { OLA_WARN << "Subdevice " << request->SubDevice() << " was not the root or " - << "broadcast subdevice"; - // TODO(Peter): NACK with NR_SUB_DEVICE_OUT_OF_RANGE - return; + << "broadcast subdevice, NACKing"; + // Immediately send a NACK + RDMReply reply( + ola::rdm::RDM_COMPLETED_OK, + NackWithReason(request, ola::rdm::NR_SUB_DEVICE_OUT_OF_RANGE)); + RDMRequestComplete(*headers, &reply); + } else { + // Dispatch the message to the responder + dummy_responder->SendRDMRequest( + request, + ola::NewSingleCallback(&RDMRequestComplete, + *headers)); } - - dummy_responder->SendRDMRequest( - request, - ola::NewSingleCallback(&RDMRequestComplete, - *headers)); } int main(int argc, char* argv[]) { From bc2099bac694c2291f7dcb92cfb7025e4680218d Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Tue, 18 Feb 2020 02:12:23 +0000 Subject: [PATCH 34/71] Rename the target code to a more standardised name --- .gitignore | 4 ++-- tools/e133/Makefile.mk | 6 +++--- tools/e133/{llrp-receive-test.cpp => llrp-target.cpp} | 0 3 files changed, 5 insertions(+), 5 deletions(-) rename tools/e133/{llrp-receive-test.cpp => llrp-target.cpp} (100%) diff --git a/.gitignore b/.gitignore index 6103d55d61..c1299e8062 100644 --- a/.gitignore +++ b/.gitignore @@ -212,8 +212,8 @@ tools/e133/e133_monitor tools/e133/e133_monitor.exe tools/e133/e133_receiver tools/e133/e133_receiver.exe -tools/e133/llrp_receive_test -tools/e133/llrp_receive_test.exe +tools/e133/llrp_target +tools/e133/llrp_target.exe tools/e133/slp_locate tools/e133/slp_locate.exe tools/e133/slp_register diff --git a/tools/e133/Makefile.mk b/tools/e133/Makefile.mk index 132da06b7b..f354d0858a 100644 --- a/tools/e133/Makefile.mk +++ b/tools/e133/Makefile.mk @@ -71,7 +71,7 @@ noinst_PROGRAMS += \ tools/e133/e133_controller \ tools/e133/e133_monitor \ tools/e133/e133_receiver \ - tools/e133/llrp_receive_test + tools/e133/llrp_target tools_e133_e133_receiver_SOURCES = tools/e133/e133-receiver.cpp tools_e133_e133_receiver_LDADD = common/libolacommon.la \ @@ -106,5 +106,5 @@ tools_e133_basic_device_LDADD = common/libolacommon.la \ libs/acn/libolaacn.la \ tools/e133/libolae133common.la -tools_e133_llrp_receive_test_SOURCES = tools/e133/llrp-receive-test.cpp -tools_e133_llrp_receive_test_LDADD = libs/acn/libolae131core.la +tools_e133_llrp_target_SOURCES = tools/e133/llrp-target.cpp +tools_e133_llrp_target_LDADD = libs/acn/libolae131core.la diff --git a/tools/e133/llrp-receive-test.cpp b/tools/e133/llrp-target.cpp similarity index 100% rename from tools/e133/llrp-receive-test.cpp rename to tools/e133/llrp-target.cpp From ed113e142f91b7b0c642fc49b96aaa2ac337e987 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Tue, 18 Feb 2020 02:43:01 +0000 Subject: [PATCH 35/71] Update some missed docs --- tools/e133/llrp-target.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/e133/llrp-target.cpp b/tools/e133/llrp-target.cpp index efed057d2f..8d466e5a56 100644 --- a/tools/e133/llrp-target.cpp +++ b/tools/e133/llrp-target.cpp @@ -13,8 +13,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * llrp-receive-test.cpp - * Run a very simple E1.33 LLRP Responder. + * llrp-target.cpp + * Run a very simple E1.33 LLRP Target. * Copyright (C) 2020 Peter Newman */ @@ -83,7 +83,7 @@ using ola::rdm::RDMReply; using ola::rdm::RDMResponse; using ola::rdm::UID; -DEFINE_string(uid, "7a70:00000001", "The UID of the responder."); +DEFINE_string(uid, "7a70:00000001", "The UID of the target."); auto_ptr picker( ola::network::InterfacePicker::NewPicker()); @@ -271,7 +271,7 @@ void HandleRDM( } int main(int argc, char* argv[]) { - ola::AppInit(&argc, argv, "[options]", "Run a very simple E1.33 LLRP Responder."); + ola::AppInit(&argc, argv, "[options]", "Run a very simple E1.33 LLRP Target."); target_uid.reset(UID::FromString(FLAGS_uid)); if (!target_uid.get()) { From 8db5131776b31ada6cf78a0bd6c78a280840432b Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Tue, 18 Feb 2020 05:41:54 +0000 Subject: [PATCH 36/71] Add the ability to inflate an LLRP Probe Reply and build a Probe Request --- libs/acn/LLRPProbeReplyInflator.cpp | 107 +++++++++++++++++++++++++ libs/acn/LLRPProbeReplyInflator.h | 79 +++++++++++++++++++ libs/acn/LLRPProbeRequestPDU.cpp | 50 ++++++++++++ libs/acn/LLRPProbeRequestPDU.h | 34 +++++++- libs/acn/LLRPProbeRequestPDUTest.cpp | 112 +++++++++++++++++++++++++++ libs/acn/Makefile.mk | 2 + 6 files changed, 383 insertions(+), 1 deletion(-) create mode 100644 libs/acn/LLRPProbeReplyInflator.cpp create mode 100644 libs/acn/LLRPProbeReplyInflator.h diff --git a/libs/acn/LLRPProbeReplyInflator.cpp b/libs/acn/LLRPProbeReplyInflator.cpp new file mode 100644 index 0000000000..153433c166 --- /dev/null +++ b/libs/acn/LLRPProbeReplyInflator.cpp @@ -0,0 +1,107 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * LLRPProbeReplyInflator.cpp + * The Inflator for the LLRP Probe Reply PDUs + * Copyright (C) 2020 Peter Newman + */ + +#include +#include +#include "ola/Logging.h" +#include "include/ola/rdm/UID.h" +#include "include/ola/rdm/UIDSet.h" +#include "include/ola/strings/Format.h" +#include "libs/acn/LLRPProbeReplyInflator.h" +#include "libs/acn/LLRPProbeReplyPDU.h" + +namespace ola { +namespace acn { + +using ola::acn::LLRPProbeReplyPDU; +using ola::rdm::UID; +using ola::rdm::UIDSet; + +/** + * Create a new LLRP Probe Reply inflator + */ +LLRPProbeReplyInflator::LLRPProbeReplyInflator() + : BaseInflator(PDU::ONE_BYTE) { +} + +/** + * Set an LLRPProbeReplyHandler to run when receiving an LLRP Probe Reply + * message. + * @param handler the callback to invoke when there is and LLRP Probe Reply. + */ +void LLRPProbeReplyInflator::SetLLRPProbeReplyHandler( + LLRPProbeReplyHandler *handler) { + m_llrp_probe_reply_handler.reset(handler); +} + + +/* + * Decode the LLRP Probe Reply 'header', which is 0 bytes in length. + * @param headers the HeaderSet to add to + * @param data a pointer to the data + * @param length length of the data + * @returns true if successful, false otherwise + */ +bool LLRPProbeReplyInflator::DecodeHeader(HeaderSet *, + const uint8_t*, + unsigned int, + unsigned int *bytes_used) { + *bytes_used = 0; + return true; +} + + +/* + * Handle a LLRP Probe Reply PDU for E1.33. + */ +bool LLRPProbeReplyInflator::HandlePDUData(uint32_t vector, + const HeaderSet &headers, + const uint8_t *data, + unsigned int pdu_len) { + if (vector != LLRPProbeReplyPDU::VECTOR_PROBE_REPLY_DATA) { + OLA_INFO << "Not a probe reply, vector was " << vector; + return true; + } + + ola::strings::FormatData(&std::cout, data, pdu_len); + + LLRPProbeReplyPDU::llrp_probe_reply_pdu_data pdu_data; + if (pdu_len > sizeof(pdu_data)) { + OLA_WARN << "Got too much data, received " << pdu_len << " only expecting " + << sizeof(pdu_data); + return false; + } + + memcpy(reinterpret_cast(&pdu_data), data, sizeof(pdu_data)); + + OLA_DEBUG << "Probe from " << UID(pdu_data.target_uid); + + LLRPProbeReply reply(UID(pdu_data.target_uid)); + + if (m_llrp_probe_reply_handler.get()) { + m_llrp_probe_reply_handler->Run(&headers, + reply); + } else { + OLA_WARN << "No LLRP Probe Reply handler defined!"; + } + return true; +} +} // namespace acn +} // namespace ola diff --git a/libs/acn/LLRPProbeReplyInflator.h b/libs/acn/LLRPProbeReplyInflator.h new file mode 100644 index 0000000000..3aab45f7b1 --- /dev/null +++ b/libs/acn/LLRPProbeReplyInflator.h @@ -0,0 +1,79 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * LLRPProbeReplyInflator.h + * Copyright (C) 2020 Peter Newman + */ + +#ifndef LIBS_ACN_LLRPPROBEREPLYINFLATOR_H_ +#define LIBS_ACN_LLRPPROBEREPLYINFLATOR_H_ + +#include "ola/Callback.h" +#include "ola/acn/ACNVectors.h" +#include "ola/rdm/UID.h" +#include "ola/rdm/UIDSet.h" +#include "libs/acn/BaseInflator.h" +#include "libs/acn/HeaderSet.h" +#include "libs/acn/LLRPProbeReplyPDU.h" + +namespace ola { +namespace acn { + +class LLRPProbeReplyInflator: public BaseInflator { + friend class LLRPProbeReplyInflatorTest; + + public: + struct LLRPProbeReply { + LLRPProbeReply(const ola::rdm::UID &_uid) + : uid(_uid) { + } + ola::rdm::UID uid; + ola::network::MACAddress hardware_address; + ola::acn::LLRPProbeReplyPDU::LLRPComponentType component_type; + }; + + + // These are pointers so the callers don't have to pull in all the headers. + typedef ola::Callback2 LLRPProbeReplyHandler; + + LLRPProbeReplyInflator(); + ~LLRPProbeReplyInflator() {} + + uint32_t Id() const { return ola::acn::VECTOR_LLRP_PROBE_REPLY; } + + void SetLLRPProbeReplyHandler(LLRPProbeReplyHandler *handler); + + protected: + bool DecodeHeader(HeaderSet *headers, + const uint8_t *data, + unsigned int len, + unsigned int *bytes_used); + + void ResetHeaderField() {} // namespace noop + + virtual bool HandlePDUData(uint32_t vector, + const HeaderSet &headers, + const uint8_t *data, + unsigned int pdu_len); + + private: + std::auto_ptr m_llrp_probe_reply_handler; +}; +} // namespace acn +} // namespace ola +#endif // LIBS_ACN_LLRPPROBEREPLYINFLATOR_H_ diff --git a/libs/acn/LLRPProbeRequestPDU.cpp b/libs/acn/LLRPProbeRequestPDU.cpp index 6db4af3bab..ee8a021ec7 100644 --- a/libs/acn/LLRPProbeRequestPDU.cpp +++ b/libs/acn/LLRPProbeRequestPDU.cpp @@ -31,6 +31,56 @@ using ola::io::OutputStream; using ola::network::HostToNetwork; using ola::rdm::UID; +unsigned int LLRPProbeRequestPDU::DataSize() const { + llrp_probe_request_pdu_data data; + return static_cast(sizeof(llrp_probe_request_pdu_data) - + sizeof(data.known_uids) + + (m_known_uids.Size() * UID::LENGTH)); + +} + +bool LLRPProbeRequestPDU::PackData(uint8_t *data, unsigned int *length) const { + llrp_probe_request_pdu_data pdu_data; + m_lower_uid.Pack(pdu_data.lower_uid, sizeof(pdu_data.lower_uid)); + m_upper_uid.Pack(pdu_data.upper_uid, sizeof(pdu_data.upper_uid)); + uint16_t filter = 0; + if (m_client_tcp_connection_inactive) { + filter |= FILTER_CLIENT_TCP_CONNECTION_INACTIVE; + } + if (m_brokers_only) { + filter |= FILTER_BROKERS_ONLY; + } + pdu_data.filter = HostToNetwork(filter); + // TODO(Peter): We need to check we've got <= 200 UIDs here + m_known_uids.Pack(pdu_data.known_uids, sizeof(pdu_data.known_uids)); + *length = static_cast(sizeof(llrp_probe_request_pdu_data) - + sizeof(pdu_data.known_uids) + + (m_known_uids.Size() * UID::LENGTH)); + + memcpy(data, &pdu_data, *length); + return true; +} + +void LLRPProbeRequestPDU::PackData(ola::io::OutputStream *stream) const { + llrp_probe_request_pdu_data data; + m_lower_uid.Pack(data.lower_uid, sizeof(data.lower_uid)); + m_upper_uid.Pack(data.upper_uid, sizeof(data.upper_uid)); + uint16_t filter = 0; + if (m_client_tcp_connection_inactive) { + filter |= FILTER_CLIENT_TCP_CONNECTION_INACTIVE; + } + if (m_brokers_only) { + filter |= FILTER_BROKERS_ONLY; + } + data.filter = HostToNetwork(filter); + // TODO(Peter): We need to check we've got <= 200 UIDs here + m_known_uids.Pack(data.known_uids, sizeof(data.known_uids)); + stream->Write(reinterpret_cast(&data), + static_cast(sizeof(llrp_probe_request_pdu_data) - + sizeof(data.known_uids) + + (m_known_uids.Size() * UID::LENGTH))); +} + void LLRPProbeRequestPDU::PrependPDU(ola::io::IOStack *stack, const UID &lower_uid, const UID &upper_uid, diff --git a/libs/acn/LLRPProbeRequestPDU.h b/libs/acn/LLRPProbeRequestPDU.h index 17a3145c69..56095c709c 100644 --- a/libs/acn/LLRPProbeRequestPDU.h +++ b/libs/acn/LLRPProbeRequestPDU.h @@ -30,8 +30,33 @@ namespace ola { namespace acn { -class LLRPProbeRequestPDU : private PDU { +class LLRPProbeRequestPDU : public PDU { public: + explicit LLRPProbeRequestPDU(unsigned int vector, + const ola::rdm::UID &lower_uid, + const ola::rdm::UID &upper_uid, + bool client_tcp_connection_inactive, + bool brokers_only, + const ola::rdm::UIDSet &known_uids): + PDU(vector, ONE_BYTE, true), + m_lower_uid(lower_uid), + m_upper_uid(upper_uid), + m_client_tcp_connection_inactive(client_tcp_connection_inactive), + m_brokers_only(brokers_only), + m_known_uids(known_uids) {} + + 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; + 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 &lower_uid, const ola::rdm::UID &upper_uid, @@ -55,6 +80,13 @@ class LLRPProbeRequestPDU : private PDU { uint8_t known_uids[ola::rdm::UID::LENGTH * LLRP_KNOWN_UID_SIZE]; }); typedef struct llrp_probe_request_pdu_data_s llrp_probe_request_pdu_data; + + private: + const ola::rdm::UID m_lower_uid; + const ola::rdm::UID m_upper_uid; + bool m_client_tcp_connection_inactive; + bool m_brokers_only; + const ola::rdm::UIDSet m_known_uids; }; } // namespace acn } // namespace ola diff --git a/libs/acn/LLRPProbeRequestPDUTest.cpp b/libs/acn/LLRPProbeRequestPDUTest.cpp index 6666002b6a..88f39d587c 100644 --- a/libs/acn/LLRPProbeRequestPDUTest.cpp +++ b/libs/acn/LLRPProbeRequestPDUTest.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" @@ -34,16 +36,24 @@ namespace ola { namespace acn { +using ola::acn::LLRPProbeRequestPDU; +using ola::io::IOQueue; using ola::io::IOStack; +using ola::io::OutputStream; +using ola::network::HostToNetwork; using ola::rdm::UID; using ola::rdm::UIDSet; class LLRPProbeRequestPDUTest: public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(LLRPProbeRequestPDUTest); + CPPUNIT_TEST(testSimpleLLRPProbeRequestPDU); + CPPUNIT_TEST(testSimpleLLRPProbeRequestPDUToOutputStream); CPPUNIT_TEST(testPrepend); CPPUNIT_TEST_SUITE_END(); public: + void testSimpleLLRPProbeRequestPDU(); + void testSimpleLLRPProbeRequestPDUToOutputStream(); void testPrepend(); private: @@ -52,6 +62,108 @@ class LLRPProbeRequestPDUTest: public CppUnit::TestFixture { CPPUNIT_TEST_SUITE_REGISTRATION(LLRPProbeRequestPDUTest); +const unsigned int LLRPProbeRequestPDUTest::TEST_VECTOR = 39; + + +/* + * Test that packing a LLRPProbeRequestPDU works. + */ +void LLRPProbeRequestPDUTest::testSimpleLLRPProbeRequestPDU() { + UID lower_uid = UID(0x4321, 0x12345678); + UID upper_uid = UID(0x5678, 0x00abcdef); + UIDSet known_uids; + known_uids.AddUID(UID(0x1234, 0x00000001)); + known_uids.AddUID(UID(0x5678, 0x00000002)); + known_uids.AddUID(UID(0x4321, 0x56789abc)); + LLRPProbeRequestPDU pdu( + TEST_VECTOR, + lower_uid, + upper_uid, + false, + false, + known_uids); + + OLA_ASSERT_EQ(0u, pdu.HeaderSize()); + OLA_ASSERT_EQ(32u, pdu.DataSize()); + OLA_ASSERT_EQ(36u, 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]; + lower_uid.Pack(buffer, sizeof(buffer)); + OLA_ASSERT_DATA_EQUALS(&data[4], UID::LENGTH, buffer, sizeof(buffer)); + upper_uid.Pack(buffer, sizeof(buffer)); + OLA_ASSERT_DATA_EQUALS(&data[10], UID::LENGTH, buffer, sizeof(buffer)); + + // 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 LLRPProbeRequestPDUTest::testSimpleLLRPProbeRequestPDUToOutputStream() { + UID lower_uid = UID(0x4321, 0x12345678); + UID upper_uid = UID(0x5678, 0x00abcdef); + UIDSet known_uids; + known_uids.AddUID(UID(0x1234, 0x00000001)); + known_uids.AddUID(UID(0x5678, 0x00000002)); + known_uids.AddUID(UID(0x4321, 0x56789abc)); + LLRPProbeRequestPDU pdu( + TEST_VECTOR, + lower_uid, + upper_uid, + false, + false, + known_uids); + + OLA_ASSERT_EQ(0u, pdu.HeaderSize()); + OLA_ASSERT_EQ(32u, pdu.DataSize()); + OLA_ASSERT_EQ(36u, pdu.Size()); + + IOQueue output; + OutputStream stream(&output); + pdu.Write(&stream); + OLA_ASSERT_EQ(36u, 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, 0x24, + 39, + 0x43, 0x21, 0x12, 0x34, 0x56, 0x78, + 0x56, 0x78, 0x00, 0xab, 0xcd, 0xef, + 0x00, 0x00, + 0x12, 0x34, 0, 0, 0, 1, + 0x43, 0x21, 0x56, 0x78, 0x9a, 0xbc, + 0x56, 0x78, 0, 0, 0, 2 + }; + OLA_ASSERT_DATA_EQUALS(EXPECTED, sizeof(EXPECTED), pdu_data, pdu_size); + output.Pop(output.Size()); + delete[] pdu_data; +} + + void LLRPProbeRequestPDUTest::testPrepend() { IOStack stack; UIDSet known_uids; diff --git a/libs/acn/Makefile.mk b/libs/acn/Makefile.mk index 7c81ef9031..a036a3f55a 100644 --- a/libs/acn/Makefile.mk +++ b/libs/acn/Makefile.mk @@ -64,6 +64,8 @@ libs_acn_libolae131core_la_SOURCES = \ libs/acn/LLRPHeader.h \ libs/acn/LLRPInflator.cpp \ libs/acn/LLRPInflator.h \ + libs/acn/LLRPProbeReplyInflator.cpp \ + libs/acn/LLRPProbeReplyInflator.h \ libs/acn/LLRPProbeReplyPDU.cpp \ libs/acn/LLRPProbeReplyPDU.h \ libs/acn/LLRPProbeRequestInflator.cpp \ From bd0a09c536cdfccd4dec8e9b5fc1736690e630b3 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Wed, 19 Feb 2020 13:02:48 +0000 Subject: [PATCH 37/71] Minor tweak to some logging --- tools/e133/llrp-target.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/e133/llrp-target.cpp b/tools/e133/llrp-target.cpp index 8d466e5a56..b7159ec8c5 100644 --- a/tools/e133/llrp-target.cpp +++ b/tools/e133/llrp-target.cpp @@ -279,7 +279,7 @@ int main(int argc, char* argv[]) { ola::DisplayUsage(); exit(ola::EXIT_USAGE); } else { - OLA_INFO << "Started LLRP Responder with UID " << *target_uid; + OLA_INFO << "Started LLRP Target with UID " << *target_uid; } dummy_responder.reset(new ola::rdm::DummyResponder(*target_uid)); From fc8333076395abf6e22f1f5ba0f5769ada4cef25 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Wed, 19 Feb 2020 13:09:12 +0000 Subject: [PATCH 38/71] Initial basic attempt at an LLRP manager --- .gitignore | 2 + tools/e133/Makefile.mk | 10 +- tools/e133/llrp-manager.cpp | 433 ++++++++++++++++++++++++++++++++++++ 3 files changed, 444 insertions(+), 1 deletion(-) create mode 100644 tools/e133/llrp-manager.cpp diff --git a/.gitignore b/.gitignore index c1299e8062..447f772cf6 100644 --- a/.gitignore +++ b/.gitignore @@ -212,6 +212,8 @@ tools/e133/e133_monitor tools/e133/e133_monitor.exe tools/e133/e133_receiver tools/e133/e133_receiver.exe +tools/e133/llrp_manager +tools/e133/llrp_manager.exe tools/e133/llrp_target tools/e133/llrp_target.exe tools/e133/slp_locate diff --git a/tools/e133/Makefile.mk b/tools/e133/Makefile.mk index f354d0858a..76f23cdf21 100644 --- a/tools/e133/Makefile.mk +++ b/tools/e133/Makefile.mk @@ -71,6 +71,7 @@ noinst_PROGRAMS += \ tools/e133/e133_controller \ tools/e133/e133_monitor \ tools/e133/e133_receiver \ + tools/e133/llrp_manager \ tools/e133/llrp_target tools_e133_e133_receiver_SOURCES = tools/e133/e133-receiver.cpp @@ -106,5 +107,12 @@ tools_e133_basic_device_LDADD = common/libolacommon.la \ libs/acn/libolaacn.la \ tools/e133/libolae133common.la +tools_e133_llrp_manager_SOURCES = tools/e133/llrp-manager.cpp +tools_e133_llrp_manager_LDADD = common/libolacommon.la \ + libs/acn/libolaacn.la \ + tools/e133/libolae133common.la + tools_e133_llrp_target_SOURCES = tools/e133/llrp-target.cpp -tools_e133_llrp_target_LDADD = libs/acn/libolae131core.la +tools_e133_llrp_target_LDADD = common/libolacommon.la \ + libs/acn/libolaacn.la \ + tools/e133/libolae133common.la diff --git a/tools/e133/llrp-manager.cpp b/tools/e133/llrp-manager.cpp new file mode 100644 index 0000000000..35021e3e33 --- /dev/null +++ b/tools/e133/llrp-manager.cpp @@ -0,0 +1,433 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * llrp-manager.cpp + * Run a very simple E1.33 LLRP Manager. + * Copyright (C) 2020 Peter Newman + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "libs/acn/HeaderSet.h" +#include "libs/acn/LLRPHeader.h" +#include "libs/acn/LLRPInflator.h" +#include "libs/acn/LLRPPDU.h" +#include "libs/acn/LLRPProbeReplyInflator.h" +#include "libs/acn/LLRPProbeReplyPDU.h" +#include "libs/acn/LLRPProbeRequestPDU.h" +#include "libs/acn/PreamblePacker.h" +#include "libs/acn/RDMInflator.h" +#include "libs/acn/RDMPDU.h" +#include "libs/acn/RootHeader.h" +#include "libs/acn/RootInflator.h" +#include "libs/acn/RootSender.h" +#include "libs/acn/Transport.h" +#include "libs/acn/UDPTransport.h" + +using std::string; +using std::vector; +using std::auto_ptr; + +using ola::acn::CID; +using ola::acn::IncomingUDPTransport; +using ola::acn::LLRPHeader; +using ola::acn::LLRPProbeReplyInflator; +using ola::acn::LLRPProbeReplyPDU; +using ola::acn::LLRPProbeRequestPDU; +using ola::acn::OutgoingUDPTransport; +using ola::acn::OutgoingUDPTransportImpl; +using ola::acn::RootHeader; +using ola::network::Interface; +using ola::network::IPV4Address; +using ola::network::IPV4SocketAddress; +using ola::network::MACAddress; +using ola::network::NetworkToHost; +using ola::rdm::PidStoreHelper; +using ola::rdm::RDMGetRequest; +using ola::rdm::RDMReply; +using ola::rdm::RDMRequest; +using ola::rdm::RDMResponse; +using ola::rdm::UID; +using ola::rdm::UIDSet; + +DEFINE_string(manager_uid, "7a70:00000002", "The UID of the manager."); + +auto_ptr picker( + ola::network::InterfacePicker::NewPicker()); +ola::network::Interface m_interface; +const std::string m_preferred_ip; +ola::network::UDPSocket m_socket; +uint8_t *m_recv_buffer; +std::auto_ptr manager_uid; +std::auto_ptr m_pid_helper; +ola::SequenceNumber m_llrp_transaction_number_sequence; +ola::SequenceNumber m_rdm_transaction_number_sequence; + +std::string pid_name; +vector rdm_inputs; + +ola::acn::PreamblePacker m_packer; +CID cid = CID::Generate(); +ola::acn::RootSender m_root_sender(cid, true); + +bool CheckCIDAddressedToUs(const CID destination_cid) { + return (destination_cid == CID::LLRPBroadcastCID() || + destination_cid == cid); +} + +void SendLLRPProbeRequest() { + LLRPHeader llrp_header = LLRPHeader(CID::LLRPBroadcastCID(), + m_llrp_transaction_number_sequence.Next()); + + IPV4Address *target_address = IPV4Address::FromString("239.255.250.133"); + + OutgoingUDPTransportImpl transport_impl = OutgoingUDPTransportImpl(&m_socket, &m_packer); + OutgoingUDPTransport transport(&transport_impl, + *target_address, + ola::acn::LLRP_PORT); + + LLRPProbeRequestPDU probe_request( + LLRPProbeRequestPDU::VECTOR_PROBE_REQUEST_DATA, + *UID::FromString("0000:00000000"), + *UID::FromString("ffff:ffffffff"), + false, + false, + UIDSet()); + + ola::acn::LLRPPDU pdu(ola::acn::VECTOR_LLRP_PROBE_REQUEST, llrp_header, &probe_request); + + m_root_sender.SendPDU(ola::acn::VECTOR_ROOT_LLRP, pdu, &transport); + OLA_DEBUG << "Sent PDU"; +} + +void HandleLLRPProbeReply( + const ola::acn::HeaderSet *headers, + const LLRPProbeReplyInflator::LLRPProbeReply &reply) { + OLA_DEBUG << "Potentially handling probe reply from " << reply.uid; + + const LLRPHeader llrp_header = headers->GetLLRPHeader(); + if (!CheckCIDAddressedToUs(llrp_header.DestinationCid())) { + OLA_INFO << "Ignoring probe request as it's not addressed to us or the LLRP broadcast CID"; + return; + } + + const RootHeader root_header = headers->GetRootHeader(); + + OLA_DEBUG << "Source CID: " << root_header.GetCid(); + OLA_DEBUG << "TN: " << llrp_header.TransactionNumber(); + + LLRPHeader rdm_llrp_header = LLRPHeader(root_header.GetCid(), + m_llrp_transaction_number_sequence.Next()); + + IPV4Address *target_address = IPV4Address::FromString("239.255.250.133"); + + OutgoingUDPTransportImpl transport_impl = OutgoingUDPTransportImpl(&m_socket, &m_packer); + OutgoingUDPTransport transport(&transport_impl, + *target_address, + ola::acn::LLRP_PORT); + + // TODO(Peter): Enable set + bool is_set = false; + + // get the pid descriptor + const ola::rdm::PidDescriptor *pid_descriptor = m_pid_helper->GetDescriptor( + pid_name, + reply.uid.ManufacturerId()); + + uint16_t pid_value; + if (!pid_descriptor && + (ola::PrefixedHexStringToInt(pid_name, &pid_value) || + ola::StringToInt(pid_name, &pid_value))) { + pid_descriptor = m_pid_helper->GetDescriptor( + pid_value, + reply.uid.ManufacturerId()); + } + + if (!pid_descriptor) { + std::cout << "Unknown PID: " << pid_name << std::endl; + std::cout << "Use --list-pids to list the available PIDs." << std::endl; + return; + } + + const ola::messaging::Descriptor *descriptor = NULL; + if (is_set) + descriptor = pid_descriptor->SetRequest(); + else + descriptor = pid_descriptor->GetRequest(); + + if (!descriptor) { + std::cout << (is_set ? "SET" : "GET") << " command not supported for " + << pid_name << std::endl; + return; + } + + // attempt to build the message + auto_ptr message(m_pid_helper->BuildMessage( + descriptor, + rdm_inputs)); + + if (!message.get()) { + std::cout << m_pid_helper->SchemaAsString(descriptor); + return; + } + + unsigned int param_data_length; + const uint8_t *param_data = m_pid_helper->SerializeMessage( + message.get(), + ¶m_data_length); + + RDMRequest *request = new RDMGetRequest( + *manager_uid, + reply.uid, + m_rdm_transaction_number_sequence.Next(), // transaction # + 1, // port id + 0, // sub device + pid_descriptor->Value(), // param id + param_data, // data + param_data_length); // data length + + ola::io::ByteString raw_reply; + ola::rdm::RDMCommandSerializer::Pack(*request, &raw_reply); + + ola::acn::RDMPDU rdm_reply(raw_reply); + + ola::acn::LLRPPDU pdu(ola::acn::VECTOR_LLRP_RDM_CMD, rdm_llrp_header, &rdm_reply); + + m_root_sender.SendPDU(ola::acn::VECTOR_ROOT_LLRP, pdu, &transport); + OLA_DEBUG << "Sent PDU"; +} + +/** + * Handle an ACK response + */ +void HandleAckResponse(uint16_t manufacturer_id, + bool is_set, + uint16_t pid, + const uint8_t *data, + unsigned int length) { + const ola::rdm::PidDescriptor *pid_descriptor = m_pid_helper->GetDescriptor( + pid, + manufacturer_id); + + if (!pid_descriptor) { + OLA_WARN << "Unknown PID: " << pid << "."; + return; + } + + const ola::messaging::Descriptor *descriptor = NULL; + if (is_set) { + descriptor = pid_descriptor->SetResponse(); + } else { + descriptor = pid_descriptor->GetResponse(); + } + + if (!descriptor) { + OLA_WARN << "Unknown response message: " << (is_set ? "SET" : "GET") << + " " << pid_descriptor->Name(); + return; + } + + auto_ptr message( + m_pid_helper->DeserializeMessage(descriptor, data, length)); + + if (!message.get()) { + OLA_WARN << "Unable to inflate RDM response"; + return; + } + + std::cout << m_pid_helper->PrettyPrintMessage(manufacturer_id, + is_set, + pid, + message.get()); +} + +void HandleRDM( + const ola::acn::HeaderSet *headers, + const string &raw_response) { + IPV4SocketAddress target = headers->GetTransportHeader().Source(); + OLA_INFO << "Got RDM response from " << target; + + if (!CheckCIDAddressedToUs(headers->GetLLRPHeader().DestinationCid())) { + OLA_INFO << "Ignoring RDM response as it's not addressed to us or the LLRP broadcast CID"; + return; + } + + ola::rdm::RDMStatusCode status_code; + // attempt to unpack as a request + ola::rdm::RDMResponse *response = ola::rdm::RDMResponse::InflateFromData( + reinterpret_cast(raw_response.data()), + raw_response.size(), + &status_code); + + OLA_DEBUG << "Got status code " << ola::rdm::StatusCodeToString(status_code); + + if (!response) { + OLA_WARN << "Failed to unpack LLRP RDM message, ignoring request."; + return; + } else { + OLA_DEBUG << "Got RDM response " << response->ToString(); + } + + if (!response->DestinationUID().DirectedToUID(*manager_uid)) { + OLA_WARN << "Destination UID " << response->DestinationUID() << " was not " + << "directed to us"; + return; + } + + OLA_INFO << "Got RDM response from " << response->SourceUID(); + if (response->ResponseType() == ola::rdm::RDM_ACK) { + HandleAckResponse(response->SourceUID().ManufacturerId(), + (response->CommandClass() == + ola::rdm::RDMCommand::SET_COMMAND_RESPONSE), + response->ParamId(), + response->ParamData(), + response->ParamDataSize()); + } else if (response->ResponseType() == ola::rdm::RDM_NACK_REASON) { + uint16_t nack_reason; + if (response->ParamDataSize() != sizeof(nack_reason)) { + OLA_WARN << "Invalid NACK reason size of " << response->ParamDataSize(); + } else { + memcpy(reinterpret_cast(&nack_reason), response->ParamData(), + sizeof(nack_reason)); + nack_reason = NetworkToHost(nack_reason); + std::cout << "Request NACKed: " << + ola::rdm::NackReasonToString(nack_reason) << std::endl; + } + } else { + OLA_WARN << "Unknown RDM response type " + << ola::strings::ToHex(response->ResponseType()); + } +} + +int main(int argc, char* argv[]) { + ola::AppInit(&argc, argv, "[options]", "Run a very simple E1.33 LLRP Manager."); + + if (argc >= 2) { + pid_name = argv[1]; + + // split out rdm message params from the pid name (ignore program name) + rdm_inputs.resize(argc - 2); + for(int i = 0; i < argc - 2; i++) { + rdm_inputs[i] = argv[i+2]; + } + OLA_DEBUG << "Parsed RDM"; + } else { + OLA_INFO << "No RDM to parse"; + } + + m_pid_helper.reset(new PidStoreHelper("")); + m_pid_helper->Init(); + + manager_uid.reset(UID::FromString(FLAGS_manager_uid)); + if (!manager_uid.get()) { + OLA_WARN << "Invalid UID: " << FLAGS_manager_uid; + ola::DisplayUsage(); + exit(ola::EXIT_USAGE); + } else { + OLA_INFO << "Started LLRP Manager with UID " << *manager_uid; + } + + ola::io::SelectServer ss; + + if (!m_socket.Init()) { + return false; + } + std::cout << "Init!" << std::endl; + + std::cout << "Using CID " << cid << std::endl; + + IPV4Address *addr = IPV4Address::FromString("239.255.250.134"); + + if (!m_socket.Bind(IPV4SocketAddress(*addr, + ola::acn::LLRP_PORT))) { + return false; + } + std::cout << "Bind!" << std::endl; + + ola::network::InterfacePicker::Options options; + options.include_loopback = false; + if (!picker->ChooseInterface(&m_interface, m_preferred_ip, options)) { + OLA_INFO << "Failed to find an interface"; + return false; + } + + std::cout << "IF " << m_interface << std::endl; + + // If we enable multicast loopback, we can test two bits of software on the + // same machine, but we get, and must ignore, all our own requests too + if (!m_socket.JoinMulticast(m_interface.ip_address, *addr, true)) { + OLA_WARN << "Failed to join multicast group " << addr; + return false; + } + + ola::acn::RootInflator root_inflator; + ola::acn::LLRPInflator llrp_inflator; + ola::acn::LLRPProbeReplyInflator llrp_probe_reply_inflator; + llrp_probe_reply_inflator.SetLLRPProbeReplyHandler( + ola::NewCallback(&HandleLLRPProbeReply)); + ola::acn::RDMInflator llrp_rdm_inflator(ola::acn::VECTOR_LLRP_RDM_CMD); + llrp_rdm_inflator.SetGenericRDMHandler( + ola::NewCallback(&HandleRDM)); + + // setup all the inflators + root_inflator.AddInflator(&llrp_inflator); + llrp_inflator.AddInflator(&llrp_probe_reply_inflator); + llrp_inflator.AddInflator(&llrp_rdm_inflator); + + IncomingUDPTransport m_incoming_udp_transport(&m_socket, &root_inflator); + m_socket.SetOnData(ola::NewCallback(&m_incoming_udp_transport, + &IncomingUDPTransport::Receive)); + ss.AddReadDescriptor(&m_socket); + + // TODO(Peter): Add the ability to filter on UID or UID+CID to avoid the probing + + // TODO(Peter): Send this three times + // TODO(Peter): Deal with known UID list etc and proper discovery + SendLLRPProbeRequest(); + ss.Run(); + + return 0; +} From ac119e8248aeecd9198448bcd49dff4e3669f49f Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Tue, 25 Feb 2020 13:48:28 +0000 Subject: [PATCH 39/71] Support sending set commands --- tools/e133/llrp-manager.cpp | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/tools/e133/llrp-manager.cpp b/tools/e133/llrp-manager.cpp index 35021e3e33..4857919287 100644 --- a/tools/e133/llrp-manager.cpp +++ b/tools/e133/llrp-manager.cpp @@ -90,10 +90,12 @@ using ola::rdm::RDMGetRequest; using ola::rdm::RDMReply; using ola::rdm::RDMRequest; using ola::rdm::RDMResponse; +using ola::rdm::RDMSetRequest; using ola::rdm::UID; using ola::rdm::UIDSet; DEFINE_string(manager_uid, "7a70:00000002", "The UID of the manager."); +DEFINE_default_bool(set, false, "Send a set rather than a get."); auto_ptr picker( ola::network::InterfacePicker::NewPicker()); @@ -169,8 +171,7 @@ void HandleLLRPProbeReply( *target_address, ola::acn::LLRP_PORT); - // TODO(Peter): Enable set - bool is_set = false; + bool is_set = FLAGS_set; // get the pid descriptor const ola::rdm::PidDescriptor *pid_descriptor = m_pid_helper->GetDescriptor( @@ -193,10 +194,11 @@ void HandleLLRPProbeReply( } const ola::messaging::Descriptor *descriptor = NULL; - if (is_set) + if (is_set) { descriptor = pid_descriptor->SetRequest(); - else + } else { descriptor = pid_descriptor->GetRequest(); + } if (!descriptor) { std::cout << (is_set ? "SET" : "GET") << " command not supported for " @@ -219,7 +221,19 @@ void HandleLLRPProbeReply( message.get(), ¶m_data_length); - RDMRequest *request = new RDMGetRequest( + RDMRequest *request; + if (is_set) { + request = new RDMSetRequest( + *manager_uid, + reply.uid, + m_rdm_transaction_number_sequence.Next(), // transaction # + 1, // port id + 0, // sub device + pid_descriptor->Value(), // param id + param_data, // data + param_data_length); // data length + } else { + request = new RDMGetRequest( *manager_uid, reply.uid, m_rdm_transaction_number_sequence.Next(), // transaction # @@ -228,6 +242,7 @@ void HandleLLRPProbeReply( pid_descriptor->Value(), // param id param_data, // data param_data_length); // data length + } ola::io::ByteString raw_reply; ola::rdm::RDMCommandSerializer::Pack(*request, &raw_reply); From 9845e378fd0569c95206368f04af528bc269b412 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Tue, 25 Feb 2020 17:36:17 +0000 Subject: [PATCH 40/71] Update some RDM comments --- tools/rdm/TestDefinitions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/rdm/TestDefinitions.py b/tools/rdm/TestDefinitions.py index e88147380e..8071311099 100644 --- a/tools/rdm/TestDefinitions.py +++ b/tools/rdm/TestDefinitions.py @@ -911,7 +911,7 @@ class GetSubDeviceSupportedParameters(ResponderTestFixture): REQUIRES = ['sub_device_addresses'] PROVIDES = ['sub_device_supported_parameters'] - # E1.37, 2.1 Sub devices are required to support these. + # E1.37-1, 2.1 Sub devices are required to support these. MANDATORY_PIDS = ['SUPPORTED_PARAMETERS', 'DEVICE_INFO', 'SOFTWARE_VERSION_LABEL', @@ -4539,7 +4539,7 @@ class AllSubDevicesGetPresetPlayback(TestMixins.AllSubDevicesGetMixin, PID = 'PRESET_PLAYBACK' -# E1.37 PIDS +# E1.37-1 PIDS # ============================================================================= # IDENTIFY_MODE From e6b8f998585114223dd37241928b64c391c83641 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Tue, 25 Feb 2020 17:47:12 +0000 Subject: [PATCH 41/71] Update PIDs from rdm-app repo --- data/rdm/draft_pids.proto | 853 +-------------- data/rdm/manufacturer_names.proto | 1604 +++++++++++++++++++++++++++-- data/rdm/manufacturer_pids.proto | 244 +++-- data/rdm/pids.proto | 1263 ++++++++++++++++++++++- 4 files changed, 2912 insertions(+), 1052 deletions(-) diff --git a/data/rdm/draft_pids.proto b/data/rdm/draft_pids.proto index 69a87d8e2a..4d8425795f 100644 --- a/data/rdm/draft_pids.proto +++ b/data/rdm/draft_pids.proto @@ -1,852 +1 @@ -pid { - name: "BACKGROUND_QUEUED_STATUS_POLICY" - value: 32720 - get_request { - field { - type: UINT16 - name: "endpoint_id" - range { - min: 0 - max: 65534 - } - } - } - get_response { - field { - type: UINT16 - name: "endpoint_id" - range { - min: 0 - max: 65534 - } - } - field { - type: UINT8 - name: "current_policy_setting" - } - field { - type: UINT8 - name: "num_policy_settings" - } - } - get_sub_device_range: ROOT_DEVICE - set_request { - field { - type: UINT16 - name: "endpoint_id" - label { - value: 65535 - label: "All Endpoints" - } - range { - min: 0 - max: 65535 - } - } - field { - type: UINT8 - name: "policy" - } - } - set_response { - } - set_sub_device_range: ROOT_DEVICE -} -pid { - name: "BACKGROUND_QUEUED_STATUS_POLICY_DESCRIPTION" - value: 32721 - get_request { - field { - type: UINT8 - name: "policy_setting" - } - } - get_response { - field { - type: UINT8 - name: "policy_setting" - } - field { - type: STRING - name: "description" - max_size: 32 - } - } - get_sub_device_range: ROOT_DEVICE -} -pid { - name: "BACKGROUND_STATUS_TYPE" - value: 32722 - get_request { - field { - type: UINT16 - name: "endpoint_id" - range { - min: 0 - max: 65534 - } - } - } - get_response { - field { - type: UINT16 - name: "endpoint_id" - range { - min: 0 - max: 65534 - } - } - field { - type: UINT8 - name: "status_type" - } - } - get_sub_device_range: ROOT_DEVICE - set_request { - field { - type: UINT16 - name: "endpoint_id" - label { - value: 65535 - label: "All Endpoints" - } - range { - min: 0 - max: 65535 - } - } - field { - type: UINT8 - name: "status_type" - } - } - set_response { - } - set_sub_device_range: ROOT_DEVICE -} -pid { - name: "QUEUED_STATUS_ENDPOINT_COLLECTION" - value: 32723 - set_request { - field { - type: UINT16 - name: "endpoint_id" - label { - value: 65535 - label: "All Endpoints" - } - range { - min: 0 - max: 65534 - } - } - field { - type: UINT8 - name: "status_type" - } - } - set_response { - } - set_sub_device_range: ROOT_DEVICE -} -pid { - name: "QUEUED_STATUS_UID_COLLECTION" - value: 32724 - set_request { - field { - type: UINT16 - name: "endpoint_id" - range { - min: 0 - max: 65534 - } - } - field { - type: UID - name: "target_uid" - } - field { - type: UINT8 - name: "status_type" - } - } - set_response { - } - set_sub_device_range: ROOT_DEVICE -} -pid { - name: "ENDPOINT_LIST" - value: 32736 - get_request { - } - get_response { - field { - type: UINT32 - name: "list_change_number" - } - field { - type: GROUP - name: "endpoints" - field { - type: UINT16 - name: "endpoint_id" - } - } - } - get_sub_device_range: ROOT_DEVICE -} -pid { - name: "ENDPOINT_TO_UNIVERSE" - value: 32737 - get_request { - field { - type: UINT16 - name: "endpoint_id" - range { - min: 0 - max: 65534 - } - } - } - get_response { - field { - type: UINT16 - name: "endpoint_id" - } - field { - type: UINT16 - name: "universe" - label { - value: 65535 - label: "Composite" - } - range { - min: 1 - max: 65535 - } - } - field { - type: BOOL - name: "physical" - } - } - get_sub_device_range: ROOT_DEVICE - set_request { - field { - type: UINT16 - name: "endpoint_id" - label { - value: 65535 - label: "All Endpoints" - } - range { - min: 0 - max: 65535 - } - } - field { - type: UINT16 - name: "universe" - label { - value: 65535 - label: "Composite" - } - range { - min: 1 - max: 63999 - } - } - } - set_response { - } - set_sub_device_range: ROOT_DEVICE -} -pid { - name: "RDM_TRAFFIC_ENABLE" - value: 32738 - get_request { - field { - type: UINT16 - name: "endpoint_id" - range { - min: 0 - max: 65534 - } - } - } - get_response { - field { - type: UINT16 - name: "endpoint_id" - range { - min: 0 - max: 65534 - } - } - field { - type: BOOL - name: "rdm_enabled" - } - } - get_sub_device_range: ROOT_DEVICE - set_request { - field { - type: UINT16 - name: "endpoint_id" - label { - value: 65535 - label: "All Endpoints" - } - range { - min: 0 - max: 65535 - } - } - field { - type: BOOL - name: "rdm_enabled" - } - } - set_response { - } - set_sub_device_range: ROOT_DEVICE -} -pid { - name: "ENDPOINT_MODE" - value: 32739 - get_request { - field { - type: UINT16 - name: "endpoint_id" - range { - min: 0 - max: 65534 - } - } - } - get_response { - field { - type: UINT16 - name: "endpoint_id" - range { - min: 0 - max: 65534 - } - } - field { - type: UINT8 - name: "endpoint_function" - label { - value: 0 - label: "Disabled" - } - label { - value: 1 - label: "Input" - } - label { - value: 2 - label: "Output" - } - } - } - get_sub_device_range: ROOT_DEVICE - set_request { - field { - type: UINT16 - name: "endpoint_id" - label { - value: 65535 - label: "All Endpoints" - } - range { - min: 0 - max: 65535 - } - } - field { - type: UINT8 - name: "endpoint_function" - label { - value: 0 - label: "Disabled" - } - label { - value: 1 - label: "Input" - } - label { - value: 2 - label: "Output" - } - } - } - set_response { - } - set_sub_device_range: ROOT_DEVICE -} -pid { - name: "ENDPOINT_LABEL" - value: 32740 - get_request { - field { - type: UINT16 - name: "endpoint_id" - range { - min: 0 - max: 65534 - } - } - } - get_response { - field { - type: UINT16 - name: "endpoint_id" - range { - min: 0 - max: 65534 - } - } - field { - type: STRING - name: "endpoint_label" - max_size: 32 - } - } - get_sub_device_range: ROOT_DEVICE - set_request { - field { - type: UINT16 - name: "endpoint_id" - label { - value: 65535 - label: "All Endpoints" - } - range { - min: 0 - max: 65535 - } - } - field { - type: STRING - name: "endpoint_label" - max_size: 32 - } - } - set_response { - } - set_sub_device_range: ROOT_DEVICE -} -pid { - name: "DISCOVERY_STATE" - value: 32741 - get_request { - field { - type: UINT16 - name: "endpoint_id" - range { - min: 0 - max: 65534 - } - } - } - get_response { - field { - type: UINT16 - name: "endpoint_id" - range { - min: 0 - max: 65534 - } - } - field { - type: UINT16 - name: "device_count" - label { - value: 65535 - label: "Not Supported" - } - range { - min: 0 - max: 65534 - } - } - field { - type: UINT8 - name: "discovery_state" - label { - value: 0 - label: "Not Run" - } - label { - value: 1 - label: "Completed" - } - label { - value: 2 - label: "Incremental" - } - label { - value: 3 - label: "Full" - } - } - } - get_sub_device_range: ROOT_DEVICE - set_request { - field { - type: UINT16 - name: "endpoint_id" - label { - value: 65535 - label: "All Endpoints" - } - range { - min: 0 - max: 65535 - } - } - field { - type: UINT8 - name: "discovery_state" - label { - value: 0 - label: "Not Run" - } - label { - value: 1 - label: "Completed" - } - label { - value: 2 - label: "Incremental" - } - label { - value: 3 - label: "Full" - } - } - } - set_response { - } - set_sub_device_range: ROOT_DEVICE -} -pid { - name: "ENDPOINT_TIMING" - value: 32742 - get_request { - field { - type: UINT16 - name: "endpoint_id" - range { - min: 0 - max: 65534 - } - } - } - get_response { - field { - type: UINT16 - name: "endpoint_id" - range { - min: 0 - max: 65534 - } - } - field { - type: UINT8 - name: "current_setting" - } - field { - type: UINT8 - name: "number_of_settings" - } - } - get_sub_device_range: ROOT_DEVICE - set_request { - field { - type: UINT16 - name: "endpoint_id" - label { - value: 65535 - label: "All Endpoints" - } - range { - min: 0 - max: 65535 - } - } - field { - type: UINT8 - name: "timing_setting" - } - } - set_response { - } - set_sub_device_range: ROOT_DEVICE -} -pid { - name: "ENDPOINT_TIMING_DESCRIPTION" - value: 32743 - get_request { - field { - type: UINT8 - name: "timing_setting" - } - } - get_response { - field { - type: UINT8 - name: "timing_setting" - } - field { - type: STRING - name: "description" - max_size: 32 - } - } - get_sub_device_range: ROOT_DEVICE -} -pid { - name: "BINDING_CONTROL_FIELDS" - value: 32744 - get_request { - field { - type: UID - name: "uid" - } - } - get_response { - field { - type: UID - name: "uid" - } - field { - type: UINT16 - name: "endpoint_id" - range { - min: 0 - max: 65534 - } - } - field { - type: UINT16 - name: "control_bits" - } - field { - type: UID - name: "binding_uid" - } - } - get_sub_device_range: ROOT_DEVICE -} -pid { - name: "ENDPOINT_IDENTIFY" - value: 32745 - get_request { - field { - type: UINT16 - name: "endpoint_id" - range { - min: 0 - max: 65534 - } - } - } - get_response { - field { - type: UINT16 - name: "endpoint_id" - range { - min: 0 - max: 65534 - } - } - field { - type: BOOL - name: "identify_state" - } - } - get_sub_device_range: ROOT_DEVICE - set_request { - field { - type: UINT16 - name: "endpoint_id" - label { - value: 65535 - label: "All Endpoints" - } - range { - min: 0 - max: 65535 - } - } - field { - type: BOOL - name: "identify_state" - } - } - set_response { - } - set_sub_device_range: ROOT_DEVICE -} -pid { - name: "BACKGROUND_DISCOVERY" - value: 32746 - get_request { - field { - type: UINT16 - name: "endpoint_id" - range { - min: 0 - max: 65534 - } - } - } - get_response { - field { - type: UINT16 - name: "endpoint_id" - range { - min: 0 - max: 65534 - } - } - field { - type: BOOL - name: "background_discovery" - } - } - get_sub_device_range: ROOT_DEVICE - set_request { - field { - type: UINT16 - name: "endpoint_id" - label { - value: 65535 - label: "All Endpoints" - } - range { - min: 0 - max: 65535 - } - } - field { - type: BOOL - name: "background_discovery" - } - } - set_response { - } - set_sub_device_range: ROOT_DEVICE -} -pid { - name: "ENDPOINT_DEVICE_LIST_CHANGE" - value: 32747 - get_request { - field { - type: UINT16 - name: "endpoint_id" - range { - min: 0 - max: 65534 - } - } - } - get_response { - field { - type: UINT16 - name: "endpoint_id" - range { - min: 0 - max: 65534 - } - } - field { - type: UINT32 - name: "list_change_number" - } - } - get_sub_device_range: ROOT_DEVICE -} -pid { - name: "ENDPOINT_DEVICES" - value: 32748 - get_request { - field { - type: UINT16 - name: "endpoint_id" - range { - min: 0 - max: 65534 - } - } - } - get_response { - field { - type: UINT16 - name: "endpoint_id" - range { - min: 0 - max: 65534 - } - } - field { - type: UINT32 - name: "list_change_number" - } - field { - type: GROUP - name: "uids" - field { - type: UID - name: "uid" - } - } - } - get_sub_device_range: ROOT_DEVICE -} -pid { - name: "TCP_COMMS_STATUS" - value: 32749 - get_request { - } - get_response { - field { - type: IPV4 - name: "controller_ip" - label { - value: 0 - label: "No Connection" - } - } - field { - type: UINT16 - name: "unhealthy_events" - } - field { - type: UINT16 - name: "connection_events" - } - } - get_sub_device_range: ROOT_DEVICE - set_request { - } - set_response { - } - set_sub_device_range: ROOT_DEVICE -} -pid { - name: "ENDPOINT_LIST_CHANGE" - value: 32750 - get_request { - } - get_response { - field { - type: UINT32 - name: "list_change_number" - } - } - get_sub_device_range: ROOT_DEVICE -} -version: 1438559429 +version: 1582652719 diff --git a/data/rdm/manufacturer_names.proto b/data/rdm/manufacturer_names.proto index 25d58cca15..d04d83dfc2 100644 --- a/data/rdm/manufacturer_names.proto +++ b/data/rdm/manufacturer_names.proto @@ -1,7 +1,19 @@ +manufacturer { + manufacturer_id: 2279 + manufacturer_name: "3A Guangzhou Electronics Co., Ltd" +} manufacturer { manufacturer_id: 1966 manufacturer_name: "A-LITE B.V." } +manufacturer { + manufacturer_id: 262 + manufacturer_name: "A.L.A. Equipment Company Ltd." +} +manufacturer { + manufacturer_id: 109 + manufacturer_name: "AA Tasarim Ltd." +} manufacturer { manufacturer_id: 2223 manufacturer_name: "AAdyn Technology" @@ -22,6 +34,10 @@ manufacturer { manufacturer_id: 16707 manufacturer_name: "AC Lasers" } +manufacturer { + manufacturer_id: 111 + manufacturer_name: "AC Power Distribution/ACT Lighting Inc." +} manufacturer { manufacturer_id: 5388 manufacturer_name: "ACASS SYSTEMS LLC" @@ -52,7 +68,11 @@ manufacturer { } manufacturer { manufacturer_id: 16709 - manufacturer_name: "ADE ELETTRONICA srl " + manufacturer_name: "ADE ELETTRONICA srl" +} +manufacturer { + manufacturer_id: 6400 + manufacturer_name: "ADJ Products LLC" } manufacturer { manufacturer_id: 2202 @@ -66,6 +86,14 @@ manufacturer { manufacturer_id: 20055 manufacturer_name: "AIM Northwest" } +manufacturer { + manufacturer_id: 106 + manufacturer_name: "AIMTECH Electronik Tasarim Ltd. Sti." +} +manufacturer { + manufacturer_id: 1800 + manufacturer_name: "AK-LIGHT" +} manufacturer { manufacturer_id: 8358 manufacturer_name: "ALADIN Architekturlicht GmbH" @@ -82,6 +110,10 @@ manufacturer { manufacturer_id: 7104 manufacturer_name: "ALS Stanislaw Binkiewicz" } +manufacturer { + manufacturer_id: 1576 + manufacturer_name: "APEX PRO LIGHT CO.,LTD" +} manufacturer { manufacturer_id: 272 manufacturer_name: "APF S.r.l." @@ -90,6 +122,18 @@ manufacturer { manufacturer_id: 2165 manufacturer_name: "ARC Solid-State Lighting Corp." } +manufacturer { + manufacturer_id: 176 + manufacturer_name: "ARENA LUCI s.r.l." +} +manufacturer { + manufacturer_id: 4612 + manufacturer_name: "ARES s.r.l. - Socio Unico" +} +manufacturer { + manufacturer_id: 1973 + manufacturer_name: "ARM Automation, Inc" +} manufacturer { manufacturer_id: 16754 manufacturer_name: "ARNOLD LICHTTECHNIK" @@ -98,6 +142,14 @@ manufacturer { manufacturer_id: 8377 manufacturer_name: "ARRI -- Arnold & Richter Cine Technik GmbH & Co. Betriebs KG" } +manufacturer { + manufacturer_id: 20594 + manufacturer_name: "ARRI Rental Deutschland GmbH" +} +manufacturer { + manufacturer_id: 16710 + manufacturer_name: "AUS FX" +} manufacturer { manufacturer_id: 21553 manufacturer_name: "AUTOLUX Handels- und ProduktionsgmbH" @@ -122,10 +174,18 @@ manufacturer { manufacturer_id: 8365 manufacturer_name: "AZ e-lite Pte Ltd" } +manufacturer { + manufacturer_id: 1624 + manufacturer_name: "AZCOLOR LITE CO., LIMITED" +} manufacturer { manufacturer_id: 5860 manufacturer_name: "Aboutshow Color Light Co., LTD" } +manufacturer { + manufacturer_id: 2 + manufacturer_name: "Abstract AVR Ltd." +} manufacturer { manufacturer_id: 714 manufacturer_name: "Acclaim Lighting" @@ -182,6 +242,10 @@ manufacturer { manufacturer_id: 16689 manufacturer_name: "Altman Stage Lighting" } +manufacturer { + manufacturer_id: 188 + manufacturer_name: "Ambion GmbH (Ambrain)" +} manufacturer { manufacturer_id: 1308 manufacturer_name: "Ambitsel, Inc." @@ -206,6 +270,10 @@ manufacturer { manufacturer_id: 31392 manufacturer_name: "Anaren Inc." } +manufacturer { + manufacturer_id: 120 + manufacturer_name: "Andy Lighting Technology Group Ltd." +} manufacturer { manufacturer_id: 16713 manufacturer_name: "Anidea Engineering, Inc." @@ -234,6 +302,14 @@ manufacturer { manufacturer_id: 2483 manufacturer_name: "Aquatique Show Int." } +manufacturer { + manufacturer_id: 28652 + manufacturer_name: "Arc Lighting Co. Ltd." +} +manufacturer { + manufacturer_id: 470 + manufacturer_name: "Argent Data Systems, Inc." +} manufacturer { manufacturer_id: 2497 manufacturer_name: "Argetron Elektrik Elektronik Organizasyon Gida San. ve Dis Tic. Ltd. Sti." @@ -242,6 +318,14 @@ manufacturer { manufacturer_id: 16724 manufacturer_name: "Arnold Tang Productions" } +manufacturer { + manufacturer_id: 640 + manufacturer_name: "Arrigo Lighting" +} +manufacturer { + manufacturer_id: 418 + manufacturer_name: "Art Lighting Production, s.r.o." +} manufacturer { manufacturer_id: 515 manufacturer_name: "Artemide S.p.A" @@ -254,10 +338,18 @@ manufacturer { manufacturer_id: 16716 manufacturer_name: "Artistic Licence Engineering Ltd." } +manufacturer { + manufacturer_id: 366 + manufacturer_name: "Artled Technology Corp." +} manufacturer { manufacturer_id: 16755 manufacturer_name: "Astera LED Technology GmbH" } +manufacturer { + manufacturer_id: 2050 + manufacturer_name: "AstralPool" +} manufacturer { manufacturer_id: 16723 manufacturer_name: "Audio Scene" @@ -298,6 +390,14 @@ manufacturer { manufacturer_id: 8482 manufacturer_name: "BEGLEC NV" } +manufacturer { + manufacturer_id: 446 + manufacturer_name: "BEN-RI Electronica S.A." +} +manufacturer { + manufacturer_id: 1986 + manufacturer_name: "BOOQlight BV" +} manufacturer { manufacturer_id: 16975 manufacturer_name: "BOTEX" @@ -306,6 +406,10 @@ manufacturer { manufacturer_id: 276 manufacturer_name: "BSL Lighting" } +manufacturer { + manufacturer_id: 2156 + manufacturer_name: "Bafa Elektronik ve Isik Tasarimlari Sanayii Ticaret LTD Sti." +} manufacturer { manufacturer_id: 29541 manufacturer_name: "Ballantyne Strong Inc." @@ -322,14 +426,30 @@ manufacturer { manufacturer_id: 2445 manufacturer_name: "Batmink Ltd." } +manufacturer { + manufacturer_id: 1898 + manufacturer_name: "BeamZ (Tronios B.V.)" +} manufacturer { manufacturer_id: 1666 - manufacturer_name: "Beijing Ming Rui Lighting Technology Co., Ltd. " + manufacturer_name: "Beijing Ming Rui Lighting Technology Co., Ltd." +} +manufacturer { + manufacturer_id: 437 + manufacturer_name: "Beijing Soft Rock Technology Development Co., Ltd." +} +manufacturer { + manufacturer_id: 2313 + manufacturer_name: "Beijing Starlight Electronics Co., Ltd." } manufacturer { manufacturer_id: 1102 manufacturer_name: "Ben Peoples Industries, LLC" } +manufacturer { + manufacturer_id: 26985 + manufacturer_name: "Better Way Lighting" +} manufacturer { manufacturer_id: 675 manufacturer_name: "Big Bang Lightning" @@ -350,6 +470,10 @@ manufacturer { manufacturer_id: 15100 manufacturer_name: "Black Tank Engineering" } +manufacturer { + manufacturer_id: 513 + manufacturer_name: "Blinkinlabs, LLC" +} manufacturer { manufacturer_id: 260 manufacturer_name: "Blizzard Lighting, LLC" @@ -366,10 +490,22 @@ manufacturer { manufacturer_id: 2180 manufacturer_name: "Bright Group" } +manufacturer { + manufacturer_id: 2106 + manufacturer_name: "Bright Ideas Custom Electronics Inc." +} +manufacturer { + manufacturer_id: 2195 + manufacturer_name: "Brighten LED Lighting Limited" +} manufacturer { manufacturer_id: 1487 manufacturer_name: "Brighten Technology Development Co., Ltd." } +manufacturer { + manufacturer_id: 716 + manufacturer_name: "Brightix" +} manufacturer { manufacturer_id: 2429 manufacturer_name: "Brink Electronics" @@ -378,10 +514,18 @@ manufacturer { manufacturer_id: 2484 manufacturer_name: "Brompton Technology Ltd." } +manufacturer { + manufacturer_id: 183 + manufacturer_name: "Bron Elektronik AG" +} manufacturer { manufacturer_id: 8481 manufacturer_name: "Brother,Brother & Sons Aps" } +manufacturer { + manufacturer_id: 1761 + manufacturer_name: "Burck IT GmbH & Co. KG" +} manufacturer { manufacturer_id: 2220 manufacturer_name: "Bushveld Labs" @@ -390,10 +534,18 @@ manufacturer { manufacturer_id: 16965 manufacturer_name: "Bytecraft Entertainment Pty Ltd" } +manufacturer { + manufacturer_id: 8712 + manufacturer_name: "C.I.M.E.S. (Conception Installation Maintenance En Eclairage & Sonorisation)" +} manufacturer { manufacturer_id: 17225 manufacturer_name: "C.I.Tronics Lighting Designers Ltda" } +manufacturer { + manufacturer_id: 1710 + manufacturer_name: "CANARA LIGHTING INDUSTRIES PVT LTD" +} manufacturer { manufacturer_id: 458 manufacturer_name: "CASCADE s.a.s." @@ -414,6 +566,14 @@ manufacturer { manufacturer_id: 25444 manufacturer_name: "CDS advanced technology bv" } +manufacturer { + manufacturer_id: 6648 + manufacturer_name: "CEZOS Spolka z ograniczona odpowiedzialnoscia, sp.k." +} +manufacturer { + manufacturer_id: 119 + manufacturer_name: "CHAMP Licht" +} manufacturer { manufacturer_id: 8612 manufacturer_name: "CHAUVET Lighting" @@ -470,10 +630,18 @@ manufacturer { manufacturer_id: 8617 manufacturer_name: "CaptSystemes" } +manufacturer { + manufacturer_id: 18433 + manufacturer_name: "Capture Visualisation AB" +} manufacturer { manufacturer_id: 812 manufacturer_name: "Carallon Ltd." } +manufacturer { + manufacturer_id: 32490 + manufacturer_name: "Cartwright Engineering" +} manufacturer { manufacturer_id: 2330 manufacturer_name: "Celex LED Technology Ltd." @@ -486,6 +654,10 @@ manufacturer { manufacturer_id: 26646 manufacturer_name: "ChamberPlus Co., Ltd" } +manufacturer { + manufacturer_id: 13621 + manufacturer_name: "ChangshaA Spark Technology Electronics Ltd." +} manufacturer { manufacturer_id: 21360 manufacturer_name: "Chroma-Q" @@ -494,6 +666,10 @@ manufacturer { manufacturer_id: 8629 manufacturer_name: "ChromaCove LLC" } +manufacturer { + manufacturer_id: 13622 + manufacturer_name: "Cindy Professional Lighting Co., Ltd." +} manufacturer { manufacturer_id: 6669 manufacturer_name: "Cineo Lighting" @@ -522,6 +698,10 @@ manufacturer { manufacturer_id: 2153 manufacturer_name: "Club Cannon LLC" } +manufacturer { + manufacturer_id: 1984 + manufacturer_name: "Code Mercenaries GmbH" +} manufacturer { manufacturer_id: 17229 manufacturer_name: "Coemar Spa" @@ -566,10 +746,18 @@ manufacturer { manufacturer_id: 1851 manufacturer_name: "Corsair Technology Ltd." } +manufacturer { + manufacturer_id: 19802 + manufacturer_name: "Covert Science GmbH" +} manufacturer { manufacturer_id: 161 manufacturer_name: "Creative Lighting And Sound Systems Pty Ltd." } +manufacturer { + manufacturer_id: 2353 + manufacturer_name: "Cristal Controles" +} manufacturer { manufacturer_id: 2504 manufacturer_name: "Crystal Fountains Inc." @@ -578,6 +766,18 @@ manufacturer { manufacturer_id: 8609 manufacturer_name: "Culture Crew bvba" } +manufacturer { + manufacturer_id: 2117 + manufacturer_name: "Cush Light LLC" +} +manufacturer { + manufacturer_id: 420 + manufacturer_name: "Custom Effects LED Solutions Inc." +} +manufacturer { + manufacturer_id: 144 + manufacturer_name: "Cyclops Lighting" +} manufacturer { manufacturer_id: 1491 manufacturer_name: "D-LED Illumination Technologies Ltd." @@ -598,6 +798,10 @@ manufacturer { manufacturer_id: 1808 manufacturer_name: "D.T.S. Illuminazione srl" } +manufacturer { + manufacturer_id: 197 + manufacturer_name: "DAGE Stage Lighting Master Co., Ltd." +} manufacturer { manufacturer_id: 17486 manufacturer_name: "DALCNET SRL" @@ -630,6 +834,10 @@ manufacturer { manufacturer_id: 20781 manufacturer_name: "DJPOWER ELECTRONIC STAGE LIGHTING FIXTURE FACTORY (GUANGZHOU)" } +manufacturer { + manufacturer_id: 434 + manufacturer_name: "DJSI Schinstad ANS (Northern Light)" +} manufacturer { manufacturer_id: 13105 manufacturer_name: "DMG Lumiere" @@ -646,14 +854,30 @@ manufacturer { manufacturer_id: 17488 manufacturer_name: "DMXPROFI.EU GmbH i.G." } +manufacturer { + manufacturer_id: 415 + manufacturer_name: "DaisaLed Ltd." +} +manufacturer { + manufacturer_id: 29696 + manufacturer_name: "Danalux" +} manufacturer { manufacturer_id: 25700 manufacturer_name: "Dangeross Design" } +manufacturer { + manufacturer_id: 472 + manufacturer_name: "Daniel Large Lighting" +} manufacturer { manufacturer_id: 2328 manufacturer_name: "David O Smith Design" } +manufacturer { + manufacturer_id: 165 + manufacturer_name: "Delta Electronics, Inc." +} manufacturer { manufacturer_id: 17185 manufacturer_name: "Design Partners of Canada" @@ -670,6 +894,14 @@ manufacturer { manufacturer_id: 17477 manufacturer_name: "Dezelectric Kft." } +manufacturer { + manufacturer_id: 773 + manufacturer_name: "DiCon Fiberoptics, Inc." +} +manufacturer { + manufacturer_id: 182 + manufacturer_name: "DiGidot Technologies BV" +} manufacturer { manufacturer_id: 17513 manufacturer_name: "Diamante Lighting Srl" @@ -690,6 +922,10 @@ manufacturer { manufacturer_id: 30600 manufacturer_name: "DigitaLicht AG" } +manufacturer { + manufacturer_id: 187 + manufacturer_name: "Digital Lighting Engineering & Design, LLC" +} manufacturer { manufacturer_id: 2447 manufacturer_name: "Digital Sputnik Lighting" @@ -698,6 +934,18 @@ manufacturer { manufacturer_id: 31515 manufacturer_name: "DimLight Ltd." } +manufacturer { + manufacturer_id: 428 + manufacturer_name: "DongGuan Phcistar Optoelectronics Technology Co., Ltd." +} +manufacturer { + manufacturer_id: 2306 + manufacturer_name: "DongGuan Betterway Lighting Co.,Ltd" +} +manufacturer { + manufacturer_id: 419 + manufacturer_name: "Dongguan Yongya Technology Co., Ltd" +} manufacturer { manufacturer_id: 17478 manufacturer_name: "Doug Fleenor Design, Inc." @@ -734,6 +982,10 @@ manufacturer { manufacturer_id: 17731 manufacturer_name: "EC Elettronica Srl" } +manufacturer { + manufacturer_id: 2245 + manufacturer_name: "EHRGEIZ Lichttechnik GmbH" +} manufacturer { manufacturer_id: 25964 manufacturer_name: "ELC lighting" @@ -754,6 +1006,10 @@ manufacturer { manufacturer_id: 17742 manufacturer_name: "ENTTEC Pty Ltd" } +manufacturer { + manufacturer_id: 521 + manufacturer_name: "ER Productions" +} manufacturer { manufacturer_id: 17747 manufacturer_name: "ERAL srl" @@ -782,17 +1038,25 @@ manufacturer { manufacturer_id: 17733 manufacturer_name: "EastSun Technology Co. Ltd." } +manufacturer { + manufacturer_id: 2056 + manufacturer_name: "Eaton - Zero 88" +} manufacturer { manufacturer_id: 2446 - manufacturer_name: "Ecosense Lighting Company Limited " + manufacturer_name: "Ecosense Lighting Company Limited" +} +manufacturer { + manufacturer_id: 2361 + manufacturer_name: "Edelmann Electronics" } manufacturer { manufacturer_id: 1193 manufacturer_name: "Edward J. Keefe Jr." } manufacturer { - manufacturer_id: 2245 - manufacturer_name: "Ehrgeiz" + manufacturer_id: 159 + manufacturer_name: "Efore SpA" } manufacturer { manufacturer_id: 2399 @@ -800,7 +1064,11 @@ manufacturer { } manufacturer { manufacturer_id: 8870 - manufacturer_name: "Elation Lighting" + manufacturer_name: "Elation Lighting Inc." +} +manufacturer { + manufacturer_id: 411 + manufacturer_name: "ElectroTAS Soluciones Profesionales" } manufacturer { manufacturer_id: 5806 @@ -822,6 +1090,10 @@ manufacturer { manufacturer_id: 17772 manufacturer_name: "Element Labs Inc." } +manufacturer { + manufacturer_id: 2342 + manufacturer_name: "Elumeros Lighting Limited" +} manufacturer { manufacturer_id: 18518 manufacturer_name: "Enfis Ltd" @@ -854,6 +1126,14 @@ manufacturer { manufacturer_id: 1766 manufacturer_name: "Equipson S.A." } +manufacturer { + manufacturer_id: 122 + manufacturer_name: "Equivalent" +} +manufacturer { + manufacturer_id: 25939 + manufacturer_name: "EtherShow" +} manufacturer { manufacturer_id: 8889 manufacturer_name: "Etherlight" @@ -874,6 +1154,14 @@ manufacturer { manufacturer_id: 1344 manufacturer_name: "EverBrighten Co., Ltd." } +manufacturer { + manufacturer_id: 28653 + manufacturer_name: "Explorentis" +} +manufacturer { + manufacturer_id: 1875 + manufacturer_name: "F&V Europe B.V." +} manufacturer { manufacturer_id: 1930 manufacturer_name: "FATEC sarl" @@ -886,6 +1174,10 @@ manufacturer { manufacturer_id: 1060 manufacturer_name: "FLUX ECLAIRAGE" } +manufacturer { + manufacturer_id: 2193 + manufacturer_name: "Feiner Lichttechnik GMBH" +} manufacturer { manufacturer_id: 16706 manufacturer_name: "Filmgear, Inc." @@ -910,13 +1202,21 @@ manufacturer { manufacturer_id: 2191 manufacturer_name: "First Design System Inc." } +manufacturer { + manufacturer_id: 13620 + manufacturer_name: "Five4, LLC" +} +manufacturer { + manufacturer_id: 108 + manufacturer_name: "Flash-Butrym Sp.J." +} manufacturer { manufacturer_id: 17996 manufacturer_name: "Flashlight/Ampco Holding" } manufacturer { manufacturer_id: 25091 - manufacturer_name: "Flektor " + manufacturer_name: "Flektor" } manufacturer { manufacturer_id: 18006 @@ -926,6 +1226,10 @@ manufacturer { manufacturer_id: 14472 manufacturer_name: "Fly Dragon Lighting Equipment Co.,ltd" } +manufacturer { + manufacturer_id: 2010 + manufacturer_name: "Flytech s.r.l." +} manufacturer { manufacturer_id: 9015 manufacturer_name: "Focon Showtechnic" @@ -938,6 +1242,18 @@ manufacturer { manufacturer_id: 259 manufacturer_name: "Fontana Technologies" } +manufacturer { + manufacturer_id: 2250 + manufacturer_name: "Foshan City Xuandao Optoelectronics Equipment Co., Ltd" +} +manufacturer { + manufacturer_id: 2329 + manufacturer_name: "Foshan Leiyuan Photoelectric Co., LTD" +} +manufacturer { + manufacturer_id: 192 + manufacturer_name: "Foshan Yinhe Lanjing Lighting & Electrical Co., Ltd." +} manufacturer { manufacturer_id: 2466 manufacturer_name: "Fountain People" @@ -946,6 +1262,14 @@ manufacturer { manufacturer_id: 26227 manufacturer_name: "Freescale Semiconductor U.K. Ltd." } +manufacturer { + manufacturer_id: 20483 + manufacturer_name: "Futlight Optoelectronics Co.,Ltd." +} +manufacturer { + manufacturer_id: 18247 + manufacturer_name: "G&G LED Lighting" +} manufacturer { manufacturer_id: 18252 manufacturer_name: "G-LEC Europe GmbH" @@ -954,10 +1278,18 @@ manufacturer { manufacturer_id: 1 manufacturer_name: "GEE" } +manufacturer { + manufacturer_id: 466 + manufacturer_name: "GIP Innovation Tools GmbH" +} manufacturer { manufacturer_id: 26476 manufacturer_name: "GLP German Light Products GmbH" } +manufacturer { + manufacturer_id: 1708 + manufacturer_name: "GOLVER PROJECTS S.L." +} manufacturer { manufacturer_id: 18245 manufacturer_name: "GPE srl" @@ -966,10 +1298,30 @@ manufacturer { manufacturer_id: 2316 manufacturer_name: "GRE Alpha" } +manufacturer { + manufacturer_id: 655 + manufacturer_name: "GRE Alpha Electronics Ltd." +} +manufacturer { + manufacturer_id: 191 + manufacturer_name: "GTR Industries" +} +manufacturer { + manufacturer_id: 1515 + manufacturer_name: "GUANGZHOU BO WEI TE LIGHTING CO.LTD" +} +manufacturer { + manufacturer_id: 1647 + manufacturer_name: "GUANGZHOU CY LIGHTING EQUIPMENT CO.,LTD" +} manufacturer { manufacturer_id: 1721 manufacturer_name: "GUANGZHOU DASEN LIGHTING CORPORATION LIMITED" } +manufacturer { + manufacturer_id: 1678 + manufacturer_name: "GUANGZHOU TEANMA STAGE LIGHTING FACTORY" +} manufacturer { manufacturer_id: 6280 manufacturer_name: "GUANZHOU KAVON STAGE EQUIPMENT CO., LTD." @@ -1022,9 +1374,13 @@ manufacturer { manufacturer_id: 18259 manufacturer_name: "Golden Sea Disco Light Manufacturer" } +manufacturer { + manufacturer_id: 2230 + manufacturer_name: "Graf Lichttechnik UG" +} manufacturer { manufacturer_id: 1167 - manufacturer_name: "Grand Canyon LED Lighting System (Suzhou) Co., Ltd. " + manufacturer_name: "Grand Canyon LED Lighting System (Suzhou) Co., Ltd." } manufacturer { manufacturer_id: 5264 @@ -1038,129 +1394,425 @@ manufacturer { manufacturer_id: 712 manufacturer_name: "Growflux LLC" } +manufacturer { + manufacturer_id: 2288 + manufacturer_name: "Guang Dong LMJ Lighting Co., Ltd" +} +manufacturer { + manufacturer_id: 2215 + manufacturer_name: "GuangZhou Deliya Opto-electronic Tech Co., Ltd" +} +manufacturer { + manufacturer_id: 479 + manufacturer_name: "GuangZhou Dream Lighting Equipment Co., Ltd." +} +manufacturer { + manufacturer_id: 163 + manufacturer_name: "GuangZhou Huanshi Lighting Equipment Co., Limited" +} manufacturer { manufacturer_id: 2176 manufacturer_name: "GuangZhou LiDang Technology Inc." } manufacturer { manufacturer_id: 5536 - manufacturer_name: "GuangZhou MCSWE Technologies, INC " + manufacturer_name: "GuangZhou MCSWE Technologies, INC" +} +manufacturer { + manufacturer_id: 1416 + manufacturer_name: "GuangZhou XiangMing Light Limited" } manufacturer { manufacturer_id: 270 manufacturer_name: "Guangzhou ATON Lighting Technology Co.,Ltd" } manufacturer { - manufacturer_id: 2124 - manufacturer_name: "Guangzhou Ba Lin Electronic Technology Co., Ltd." + manufacturer_id: 2321 + manufacturer_name: "Guangzhou Aceda Professional Lighting Co., Ltd." } manufacturer { - manufacturer_id: 1519 - manufacturer_name: "Guangzhou Chai Yi Light Co., Ltd." + manufacturer_id: 2341 + manufacturer_name: "Guangzhou Aiweidy Lighting Acoustics Equipment Co.,Ltd." } manufacturer { - manufacturer_id: 17491 - manufacturer_name: "Guangzhou Desheng Lighting Industrial Co., Ltd." + manufacturer_id: 142 + manufacturer_name: "Guangzhou Ao Mei Di Stage Lighting Equipment Co.,Ltd." } manufacturer { - manufacturer_id: 767 - manufacturer_name: "Guangzhou Eway Stage Equipment Technology Co., Ltd." + manufacturer_id: 2163 + manufacturer_name: "Guangzhou BKLite Stage Lighting Equipment Co.,LTD" } manufacturer { - manufacturer_id: 2385 - manufacturer_name: "Guangzhou GTD Lighting Technology Co., Ltd " + manufacturer_id: 2124 + manufacturer_name: "Guangzhou Ba Lin Electronic Technology Co., Ltd." } manufacturer { - manufacturer_id: 1240 - manufacturer_name: "Guangzhou Hong Yuan Electronic Technology Co., LTD." + manufacturer_id: 185 + manufacturer_name: "Guangzhou Baiyun District Sanjie Eletronic Stage Lighting Audio Equipment Factory" } manufacturer { - manufacturer_id: 1208 - manufacturer_name: "Guangzhou Hongcai Stage Equipment Co., Ltd." + manufacturer_id: 478 + manufacturer_name: "Guangzhou Baiyun Xinxiang Lighting Equipment Factory (XPRO LIGHT)" } manufacturer { - manufacturer_id: 456 - manufacturer_name: "Guangzhou JINLIN Stage Lighting Equipment Co., Ltd. " + manufacturer_id: 2408 + manufacturer_name: "Guangzhou Beyond Lighting Co., Limited." } manufacturer { - manufacturer_id: 783 - manufacturer_name: "Guangzhou Litewise Lighting Equipments Co., Ltd. dba \"EK Lights\"" + manufacturer_id: 131 + manufacturer_name: "Guangzhou Bright Moon Technology Co., Ltd." } manufacturer { - manufacturer_id: 1088 - manufacturer_name: "Guangzhou VAS Lighting Co., Ltd." + manufacturer_id: 2235 + manufacturer_name: "Guangzhou CHEN Electronic Technology Co., Ltd." } manufacturer { - manufacturer_id: 14474 - manufacturer_name: "Guangzhou Yajiang (Yagang - Silver Star) Photoelectric Equipment Ltd." + manufacturer_id: 1519 + manufacturer_name: "Guangzhou Chai Yi Light Co., Ltd." } manufacturer { - manufacturer_id: 9249 - manufacturer_name: "HB-Laserkomponenten GmbH" + manufacturer_id: 2348 + manufacturer_name: "Guangzhou Chaoran Computer Co., Ltd." } manufacturer { - manufacturer_id: 18508 - manufacturer_name: "HBE Lighting Systems" + manufacturer_id: 2325 + manufacturer_name: "Guangzhou Chuangfeng Photoelectric Equipment Co., Ltd." } manufacturer { - manufacturer_id: 2061 - manufacturer_name: "HBJ Elektronik" + manufacturer_id: 20544 + manufacturer_name: "Guangzhou Color Imagination LED Lighting Ltd." } manufacturer { - manufacturer_id: 2362 - manufacturer_name: "HDT impex s.r.o." + manufacturer_id: 196 + manufacturer_name: "Guangzhou Dahe Electronic Technology Co. Ltd." } manufacturer { - manufacturer_id: 26732 - manufacturer_name: "HERA LED" + manufacturer_id: 474 + manufacturer_name: "Guangzhou Daisy Electronic Technology Co., Ltd." } manufacturer { - manufacturer_id: 32097 - manufacturer_name: "HMB|TEC GmbH" + manufacturer_id: 17491 + manufacturer_name: "Guangzhou Desheng Lighting Industrial Co., Ltd." } manufacturer { - manufacturer_id: 4626 - manufacturer_name: "HPL Light Company" + manufacturer_id: 2323 + manufacturer_name: "Guangzhou ECK Light Equipment Company Limited" } manufacturer { - manufacturer_id: 5220 - manufacturer_name: "HUMAL Elektroonika OU" + manufacturer_id: 2419 + manufacturer_name: "Guangzhou Eagle Wei Photoelectric Technology Co., Ltd." } manufacturer { - manufacturer_id: 9328 - manufacturer_name: "Hale Microsystems LLC" + manufacturer_id: 767 + manufacturer_name: "Guangzhou Eway Stage Equipment Technology Co., Ltd." } manufacturer { - manufacturer_id: 170 - manufacturer_name: "Hangzhou Easun Technology Co., Ltd." + manufacturer_id: 158 + manufacturer_name: "Guangzhou Flying Butterfly Stage Lighting Equipment Co., Ltd." } manufacturer { - manufacturer_id: 2339 - manufacturer_name: "Hangzhou Roleds Lighting System Co., Ltd." + manufacturer_id: 1955 + manufacturer_name: "Guangzhou GBR PROLIGHT GROUP CO.,LTD (GBR PROLIGHT)" } manufacturer { - manufacturer_id: 264 - manufacturer_name: "Haya Lighting Equipment Limited" + manufacturer_id: 2385 + manufacturer_name: "Guangzhou GTD Lighting Technology Co., Ltd" } manufacturer { - manufacturer_id: 25626 - manufacturer_name: "Heliospectra AB" + manufacturer_id: 2210 + manufacturer_name: "Guangzhou Gesida Light Equipment Co., Ltd." } manufacturer { - manufacturer_id: 9266 - manufacturer_name: "Helvar Ltd" + manufacturer_id: 2047 + manufacturer_name: "Guangzhou HOMEI LIGHT Manufacturer" } manufacturer { - manufacturer_id: 19538 - manufacturer_name: "High End Systems Inc." + manufacturer_id: 154 + manufacturer_name: "Guangzhou Haoyang Electronic Co., Ltd." } manufacturer { - manufacturer_id: 2186 - manufacturer_name: "Highendled Electronics Company Limited" + manufacturer_id: 2158 + manufacturer_name: "Guangzhou Hi-LTTE Electronics Technology Co.,Ltd" } manufacturer { - manufacturer_id: 721 - manufacturer_name: "Hoffmeister Leuchten GmbH" + manufacturer_id: 1240 + manufacturer_name: "Guangzhou Hong Yuan Electronic Technology Co., LTD." +} +manufacturer { + manufacturer_id: 1208 + manufacturer_name: "Guangzhou Hongcai Stage Equipment Co., Ltd." +} +manufacturer { + manufacturer_id: 2363 + manufacturer_name: "Guangzhou Hongmingwei Stage Lighting Co., Ltd." +} +manufacturer { + manufacturer_id: 282 + manufacturer_name: "Guangzhou Hotion Technology Co., Ltd." +} +manufacturer { + manufacturer_id: 2233 + manufacturer_name: "Guangzhou Hua Rong Electronic Technology Co., Ltd." +} +manufacturer { + manufacturer_id: 2423 + manufacturer_name: "Guangzhou HuaYong Intelligent Technology Co., Ltd." +} +manufacturer { + manufacturer_id: 2357 + manufacturer_name: "Guangzhou Huadu District Richa Lighting Equipment Factory" +} +manufacturer { + manufacturer_id: 113 + manufacturer_name: "Guangzhou Huaxinyuan Electronics Co., Ltd." +} +manufacturer { + manufacturer_id: 28416 + manufacturer_name: "Guangzhou Huaying Stage Lighting Equipment Co. Ltd." +} +manufacturer { + manufacturer_id: 456 + manufacturer_name: "Guangzhou JINLIN Stage Lighting Equipment Co., Ltd." +} +manufacturer { + manufacturer_id: 155 + manufacturer_name: "Guangzhou Jiawei Electronic Technology Co., Ltd." +} +manufacturer { + manufacturer_id: 2275 + manufacturer_name: "Guangzhou JinZhiHui Electronic Technology Co.,Ltd." +} +manufacturer { + manufacturer_id: 6152 + manufacturer_name: "Guangzhou Jinye Electronic Technology Co., Ltd." +} +manufacturer { + manufacturer_id: 2367 + manufacturer_name: "Guangzhou Julong Platform Lighting Equipment Factory" +} +manufacturer { + manufacturer_id: 198 + manufacturer_name: "Guangzhou Lantian Electronic Technology Co., Ltd." +} +manufacturer { + manufacturer_id: 138 + manufacturer_name: "Guangzhou Lees Electronics Co., Ltd." +} +manufacturer { + manufacturer_id: 2347 + manufacturer_name: "Guangzhou Lightful Stage Lighting&Sound Equipment Co,.Ltd." +} +manufacturer { + manufacturer_id: 2373 + manufacturer_name: "Guangzhou Lin Xiang Stage Lighting Equipment CO.,LTD" +} +manufacturer { + manufacturer_id: 2189 + manufacturer_name: "Guangzhou Ling Yang lighting Science and Technology Co.,Ltd" +} +manufacturer { + manufacturer_id: 783 + manufacturer_name: "Guangzhou Litewise Lighting Equipments Co., Ltd. dba \"EK Lights\"" +} +manufacturer { + manufacturer_id: 2138 + manufacturer_name: "Guangzhou Ming Jing Stage Light Equipment Co., Ltd." +} +manufacturer { + manufacturer_id: 141 + manufacturer_name: "Guangzhou Minghao Electronic Technology Co., Ltd." +} +manufacturer { + manufacturer_id: 2343 + manufacturer_name: "Guangzhou Mingying Electronic Technology Co., Ltd." +} +manufacturer { + manufacturer_id: 2125 + manufacturer_name: "Guangzhou NECO Stage Lighting Factory" +} +manufacturer { + manufacturer_id: 133 + manufacturer_name: "Guangzhou Nanshi Light Equipment Co., Ltd." +} +manufacturer { + manufacturer_id: 177 + manufacturer_name: "Guangzhou Omarte Lighting Co., Ltd." +} +manufacturer { + manufacturer_id: 785 + manufacturer_name: "Guangzhou PUGUANG Electronic Technology Co., Ltd." +} +manufacturer { + manufacturer_id: 2262 + manufacturer_name: "Guangzhou Precision Vision Intelligent Equipment Co, Ltd" +} +manufacturer { + manufacturer_id: 2287 + manufacturer_name: "Guangzhou RuiYang lighting technology co. LTD." +} +manufacturer { + manufacturer_id: 2252 + manufacturer_name: "Guangzhou Santu Stage Lighting Equipment Co.Ltd" +} +manufacturer { + manufacturer_id: 2351 + manufacturer_name: "Guangzhou Shinelight Stage Equipment Factory" +} +manufacturer { + manufacturer_id: 145 + manufacturer_name: "Guangzhou Shuozhi Optoelectronic Technology Co., Ltd. (Konelite)" +} +manufacturer { + manufacturer_id: 2243 + manufacturer_name: "Guangzhou Spark Stage Equipment Co. Ltd" +} +manufacturer { + manufacturer_id: 2386 + manufacturer_name: "Guangzhou Sunway Entertainment Equipment Co., Ltd." +} +manufacturer { + manufacturer_id: 1088 + manufacturer_name: "Guangzhou VAS Lighting Co., Ltd." +} +manufacturer { + manufacturer_id: 2360 + manufacturer_name: "Guangzhou Vanray Lighting Equipment CO.,Ltd." +} +manufacturer { + manufacturer_id: 1861 + manufacturer_name: "Guangzhou Wingo Stage Light Co., Ltd" +} +manufacturer { + manufacturer_id: 2413 + manufacturer_name: "Guangzhou Xin Yilong Stage Lighting Equipment Co., Limited" +} +manufacturer { + manufacturer_id: 2500 + manufacturer_name: "Guangzhou XinHuang Industrial Co., Ltd." +} +manufacturer { + manufacturer_id: 786 + manufacturer_name: "Guangzhou Xingkong Studio Lighting Co., Ltd." +} +manufacturer { + manufacturer_id: 6586 + manufacturer_name: "Guangzhou Xinzhijie Photoelectric Co., Ltd." +} +manufacturer { + manufacturer_id: 136 + manufacturer_name: "Guangzhou YaFeng Optoelectronic Equipment Co., Ltd." +} +manufacturer { + manufacturer_id: 14474 + manufacturer_name: "Guangzhou Yajiang (Yagang - Silver Star) Photoelectric Equipment Ltd." +} +manufacturer { + manufacturer_id: 399 + manufacturer_name: "Guangzhou YiCheng Light Industry Ltd." +} +manufacturer { + manufacturer_id: 1542 + manufacturer_name: "Guangzhou YiGuang Stage Lighting Co., Ltd." +} +manufacturer { + manufacturer_id: 2516 + manufacturer_name: "Guangzhou Yilaiming Photoelectric Technology Co., Ltd" +} +manufacturer { + manufacturer_id: 32488 + manufacturer_name: "Guangzhou Yingfeng Lighting Equipment Co., Ltd." +} +manufacturer { + manufacturer_id: 114 + manufacturer_name: "Guangzhou Zenith Aurora Lighting Co., Ltd." +} +manufacturer { + manufacturer_id: 2337 + manufacturer_name: "Guangzhou mengyi stage lighting equipment co., LTD." +} +manufacturer { + manufacturer_id: 1549 + manufacturer_name: "HANIL TNC CO.,LTD" +} +manufacturer { + manufacturer_id: 9249 + manufacturer_name: "HB-Laserkomponenten GmbH" +} +manufacturer { + manufacturer_id: 18508 + manufacturer_name: "HBE Lighting Systems" +} +manufacturer { + manufacturer_id: 2061 + manufacturer_name: "HBJ Elektronik" +} +manufacturer { + manufacturer_id: 2362 + manufacturer_name: "HDT impex s.r.o." +} +manufacturer { + manufacturer_id: 26732 + manufacturer_name: "HERA LED" +} +manufacturer { + manufacturer_id: 32097 + manufacturer_name: "HMB|TEC GmbH" +} +manufacturer { + manufacturer_id: 4626 + manufacturer_name: "HPL Light Company" +} +manufacturer { + manufacturer_id: 5220 + manufacturer_name: "HUMAL Elektroonika OU" +} +manufacturer { + manufacturer_id: 1620 + manufacturer_name: "HUNAN XIANG CAIXU FILM AND TELEVISION CULTURE CO.LTD" +} +manufacturer { + manufacturer_id: 9328 + manufacturer_name: "Hale Microsystems LLC" +} +manufacturer { + manufacturer_id: 170 + manufacturer_name: "Hangzhou Easun Technology Co., Ltd." +} +manufacturer { + manufacturer_id: 2339 + manufacturer_name: "Hangzhou Roleds Lighting System Co., Ltd." +} +manufacturer { + manufacturer_id: 264 + manufacturer_name: "Haya Lighting Equipment Limited" +} +manufacturer { + manufacturer_id: 25626 + manufacturer_name: "Heliospectra AB" +} +manufacturer { + manufacturer_id: 9266 + manufacturer_name: "Helvar Ltd" +} +manufacturer { + manufacturer_id: 422 + manufacturer_name: "Hengmei Lighting Technology Co., Ltd." +} +manufacturer { + manufacturer_id: 19538 + manufacturer_name: "High End Systems Inc." +} +manufacturer { + manufacturer_id: 2186 + manufacturer_name: "Highendled Electronics Company Limited" +} +manufacturer { + manufacturer_id: 365 + manufacturer_name: "Hive Lighting" +} +manufacturer { + manufacturer_id: 721 + manufacturer_name: "Hoffmeister Leuchten GmbH" } manufacturer { manufacturer_id: 18511 @@ -1170,6 +1822,10 @@ manufacturer { manufacturer_id: 4858 manufacturer_name: "Hollywood Rentals LLC" } +manufacturer { + manufacturer_id: 2048 + manufacturer_name: "Hongyeah Light" +} manufacturer { manufacturer_id: 18499 manufacturer_name: "Horizon Control Inc." @@ -1178,10 +1834,30 @@ manufacturer { manufacturer_id: 18501 manufacturer_name: "Howard Eaton Lighting Ltd." } +manufacturer { + manufacturer_id: 20481 + manufacturer_name: "Hua Yuan Ke Tai" +} manufacturer { manufacturer_id: 26725 manufacturer_name: "Hubbell Entertainment, Inc." } +manufacturer { + manufacturer_id: 124 + manufacturer_name: "Huizhou Desay Intelligent Technology Co., Ltd." +} +manufacturer { + manufacturer_id: 2359 + manufacturer_name: "Huizhou Zhonghan Electronic Technology Co., Ltd" +} +manufacturer { + manufacturer_id: 431 + manufacturer_name: "Hunan Minghe Opto Tech Co., Ltd." +} +manufacturer { + manufacturer_id: 2160 + manufacturer_name: "Hunan YESTECH Optoelectronic Co., Ltd" +} manufacturer { manufacturer_id: 9258 manufacturer_name: "Hungaroflash" @@ -1190,10 +1866,6 @@ manufacturer { manufacturer_id: 18500 manufacturer_name: "HxDx" } -manufacturer { - manufacturer_id: 459 - manufacturer_name: "I-Light USA, Inc." -} manufacturer { manufacturer_id: 18764 manufacturer_name: "I-Lum" @@ -1210,10 +1882,22 @@ manufacturer { manufacturer_id: 1669 manufacturer_name: "IBL/ESD-Datentechnik GmbH" } +manufacturer { + manufacturer_id: 480 + manufacturer_name: "IBN Labs Ltd." +} manufacturer { manufacturer_id: 18759 manufacturer_name: "IGuzzini illuminazione spa" } +manufacturer { + manufacturer_id: 459 + manufacturer_name: "ILT Italy SRL" +} +manufacturer { + manufacturer_id: 1880 + manufacturer_name: "IMPOLUX GmbH" +} manufacturer { manufacturer_id: 929 manufacturer_name: "INAREX INC." @@ -1240,7 +1924,7 @@ manufacturer { } manufacturer { manufacturer_id: 776 - manufacturer_name: "ImageCue LLC " + manufacturer_name: "ImageCue LLC" } manufacturer { manufacturer_id: 603 @@ -1248,7 +1932,7 @@ manufacturer { } manufacturer { manufacturer_id: 1527 - manufacturer_name: "Immersive Design Studios Inc. " + manufacturer_name: "Immersive Design Studios Inc." } manufacturer { manufacturer_id: 21314 @@ -1278,10 +1962,18 @@ manufacturer { manufacturer_id: 20951 manufacturer_name: "Innovative Dimmers LLC" } +manufacturer { + manufacturer_id: 28651 + manufacturer_name: "Insight Lighting" +} manufacturer { manufacturer_id: 18757 manufacturer_name: "Insta Elektro GmbH" } +manufacturer { + manufacturer_id: 112 + manufacturer_name: "Instalighting GmbH" +} manufacturer { manufacturer_id: 18771 manufacturer_name: "Integrated System Technologies Ltd." @@ -1290,6 +1982,10 @@ manufacturer { manufacturer_id: 18772 manufacturer_name: "Integrated Theatre, Inc." } +manufacturer { + manufacturer_id: 134 + manufacturer_name: "Intella System Co., Ltd." +} manufacturer { manufacturer_id: 5280 manufacturer_name: "Intense Lighting, LLC" @@ -1306,6 +2002,10 @@ manufacturer { manufacturer_id: 1206 manufacturer_name: "IntiLED" } +manufacturer { + manufacturer_id: 436 + manufacturer_name: "Inventeq B.V." +} manufacturer { manufacturer_id: 263 manufacturer_name: "Inventronics (Hangzhou), Inc." @@ -1314,10 +2014,18 @@ manufacturer { manufacturer_id: 18770 manufacturer_name: "Invisible Rival Incorporated" } +manufacturer { + manufacturer_id: 2379 + manufacturer_name: "Invisua Lighting BV" +} manufacturer { manufacturer_id: 26996 manufacturer_name: "Ittermann electronic GmbH" } +manufacturer { + manufacturer_id: 168 + manufacturer_name: "Iwasaki Electric Co., Ltd." +} manufacturer { manufacturer_id: 19009 manufacturer_name: "JANUS srl" @@ -1326,6 +2034,10 @@ manufacturer { manufacturer_id: 20809 manufacturer_name: "JAP Optoelectronic Ltd." } +manufacturer { + manufacturer_id: 1571 + manufacturer_name: "JAS LIGHTING & SOUND CO., LTD." +} manufacturer { manufacturer_id: 19010 manufacturer_name: "JB-lighting GmbH" @@ -1342,6 +2054,10 @@ manufacturer { manufacturer_id: 19027 manufacturer_name: "JSC 'MFG'" } +manufacturer { + manufacturer_id: 467 + manufacturer_name: "JSC Aksera" +} manufacturer { manufacturer_id: 26724 manufacturer_name: "James Embedded Systems Engineering (JESE Ltd)" @@ -1358,25 +2074,45 @@ manufacturer { manufacturer_id: 19041 manufacturer_name: "Jands Pty Ltd." } +manufacturer { + manufacturer_id: 143 + manufacturer_name: "Jiangmen Coolfish Technology Co., Ltd." +} +manufacturer { + manufacturer_id: 193 + manufacturer_name: "Jingchuang Water Technology" +} manufacturer { manufacturer_id: 682 - manufacturer_name: "Jinnax Opto Technology Co., Ltd. " + manufacturer_name: "Jinnax Opto Technology Co., Ltd." } manufacturer { manufacturer_id: 19020 manufacturer_name: "Johnsson Lighting Technologies AB" } +manufacturer { + manufacturer_id: 148 + manufacturer_name: "Joinmax Display Technology Co., Ltd." +} manufacturer { manufacturer_id: 18993 manufacturer_name: "Joshua 1 Systems Inc." } +manufacturer { + manufacturer_id: 283 + manufacturer_name: "Jumptronic GmbH" +} manufacturer { manufacturer_id: 2129 manufacturer_name: "Junction Inc. Ltd" } manufacturer { manufacturer_id: 2136 - manufacturer_name: "Juno Lighting Group " + manufacturer_name: "Juno Lighting Group" +} +manufacturer { + manufacturer_id: 1414 + manufacturer_name: "K 5600, Inc." } manufacturer { manufacturer_id: 2421 @@ -1390,10 +2126,18 @@ manufacturer { manufacturer_id: 19276 manufacturer_name: "KLH Electronics PLC" } +manufacturer { + manufacturer_id: 2182 + manufacturer_name: "KLIK Systems" +} manufacturer { manufacturer_id: 19277 manufacturer_name: "KMX Inc." } +manufacturer { + manufacturer_id: 1506 + manufacturer_name: "KORRO PLUS" +} manufacturer { manufacturer_id: 27492 manufacturer_name: "Key Delfin" @@ -1438,10 +2182,18 @@ manufacturer { manufacturer_id: 19778 manufacturer_name: "LAN Systems--Midibox project" } +manufacturer { + manufacturer_id: 179 + manufacturer_name: "LANTERN" +} manufacturer { manufacturer_id: 9762 manufacturer_name: "LDDE Vertriebs Gmbh" } +manufacturer { + manufacturer_id: 2118 + manufacturer_name: "LDR - Luci della Ribalta Srl" +} manufacturer { manufacturer_id: 9761 manufacturer_name: "LEADER LIGHT s.r.o." @@ -1454,6 +2206,10 @@ manufacturer { manufacturer_id: 30900 manufacturer_name: "LED Flex Limited" } +manufacturer { + manufacturer_id: 476 + manufacturer_name: "LED Linear GmbH" +} manufacturer { manufacturer_id: 19556 manufacturer_name: "LED Team" @@ -1470,6 +2226,10 @@ manufacturer { manufacturer_id: 1887 manufacturer_name: "LEDEngin Inc." } +manufacturer { + manufacturer_id: 132 + manufacturer_name: "LEDIXIS (Exalux brand)" +} manufacturer { manufacturer_id: 19542 manufacturer_name: "LEDValley Technologies Sdn Bhd" @@ -1494,6 +2254,18 @@ manufacturer { manufacturer_id: 19561 manufacturer_name: "LIGHTOLIER" } +manufacturer { + manufacturer_id: 1746 + manufacturer_name: "LIGHTSTAR (BEIJING) ELECTRONIC CORPORATION" +} +manufacturer { + manufacturer_id: 471 + manufacturer_name: "LIMEDIA" +} +manufacturer { + manufacturer_id: 130 + manufacturer_name: "LKE Lasershowtechnik GmbH" +} manufacturer { manufacturer_id: 2462 manufacturer_name: "LLC Lighting Technologies production" @@ -1510,18 +2282,34 @@ manufacturer { manufacturer_id: 9766 manufacturer_name: "LLT Lichttechnik GmbH&CO.KG" } +manufacturer { + manufacturer_id: 135 + manufacturer_name: "LMBD" +} +manufacturer { + manufacturer_id: 1660 + manufacturer_name: "LOTRONIC SA" +} +manufacturer { + manufacturer_id: 140 + manufacturer_name: "LRX Lighting (Dwight Crane Ltd.)" +} manufacturer { manufacturer_id: 19571 manufacturer_name: "LSC Lighting Systems (Aust) Pty. Ltd." } manufacturer { manufacturer_id: 25088 - manufacturer_name: "LUCITAG Ltd. " + manufacturer_name: "LUCITAG Ltd." } manufacturer { manufacturer_id: 19532 manufacturer_name: "LUMINEX Lighting Control Equipment bvba" } +manufacturer { + manufacturer_id: 19524 + manufacturer_name: "LVDIAN PHOTOELECTRIC SCIENCE TECHNOLOGY LIMITED" +} manufacturer { manufacturer_id: 1109 manufacturer_name: "Lamp & Pencil" @@ -1546,14 +2334,26 @@ manufacturer { manufacturer_id: 19521 manufacturer_name: "LaserAnimation Sollinger GmbH" } +manufacturer { + manufacturer_id: 1596 + manufacturer_name: "LaserNet" +} manufacturer { manufacturer_id: 9776 manufacturer_name: "Laservision Pty Ltd" } +manufacturer { + manufacturer_id: 2026 + manufacturer_name: "Le Maitre Ltd" +} manufacturer { manufacturer_id: 775 manufacturer_name: "Ledium Kft." } +manufacturer { + manufacturer_id: 194 + manufacturer_name: "Ledogen" +} manufacturer { manufacturer_id: 19557 manufacturer_name: "Legargeant and Associates" @@ -1566,6 +2366,10 @@ manufacturer { manufacturer_id: 9763 manufacturer_name: "Leonh Hardware Enterprise Inc." } +manufacturer { + manufacturer_id: 30976 + manufacturer_name: "Leprecon / CAE, Inc." +} manufacturer { manufacturer_id: 17763 manufacturer_name: "Les Eclairages Lou Inc." @@ -1574,6 +2378,10 @@ manufacturer { manufacturer_id: 19780 manufacturer_name: "Les Generateurs de brouillard MDG Fog Generators Ltd." } +manufacturer { + manufacturer_id: 284 + manufacturer_name: "Letong Electronic (Guangzhou) Co., Ltd." +} manufacturer { manufacturer_id: 19525 manufacturer_name: "Leviton Manufacturing Co., Inc." @@ -1582,6 +2390,10 @@ manufacturer { manufacturer_id: 19544 manufacturer_name: "Lex Products Corp." } +manufacturer { + manufacturer_id: 121 + manufacturer_name: "Leyard Opto Electronics Co., Ltd." +} manufacturer { manufacturer_id: 19539 manufacturer_name: "Licht-, Steuer- und Schaltanlagenbau GmbH (LSS GmbH)" @@ -1594,6 +2406,10 @@ manufacturer { manufacturer_id: 14295 manufacturer_name: "Lichttechnik & Sonderbau" } +manufacturer { + manufacturer_id: 416 + manufacturer_name: "Light With LED" +} manufacturer { manufacturer_id: 1696 manufacturer_name: "Light.Audio.Design" @@ -1618,10 +2434,18 @@ manufacturer { manufacturer_id: 19543 manufacturer_name: "LightWild LC" } +manufacturer { + manufacturer_id: 433 + manufacturer_name: "Lightcare A/S" +} manufacturer { manufacturer_id: 923 manufacturer_name: "Lightforce Lasertechnik" } +manufacturer { + manufacturer_id: 512 + manufacturer_name: "Lighting Infusion LLC" +} manufacturer { manufacturer_id: 25094 manufacturer_name: "Lighting Innovation Company, LLC" @@ -1638,6 +2462,10 @@ manufacturer { manufacturer_id: 11488 manufacturer_name: "Lighting Services Inc." } +manufacturer { + manufacturer_id: 473 + manufacturer_name: "Lightronics Inc." +} manufacturer { manufacturer_id: 9764 manufacturer_name: "Lisys Fenyrendszer Zrt." @@ -1646,10 +2474,22 @@ manufacturer { manufacturer_id: 5882 manufacturer_name: "Lite Puter Enterprise Co., Ltd." } +manufacturer { + manufacturer_id: 186 + manufacturer_name: "LiteGear Inc." +} manufacturer { manufacturer_id: 9781 manufacturer_name: "LjusDesign AB" } +manufacturer { + manufacturer_id: 2309 + manufacturer_name: "Locimation Pty Ltd" +} +manufacturer { + manufacturer_id: 475 + manufacturer_name: "Logen Ltd." +} manufacturer { manufacturer_id: 9783 manufacturer_name: "Loxone Electronics GmbH" @@ -1678,6 +2518,14 @@ manufacturer { manufacturer_id: 28650 manufacturer_name: "Lumina Visual Productions" } +manufacturer { + manufacturer_id: 147 + manufacturer_name: "Luminous Show Technology Ltd." +} +manufacturer { + manufacturer_id: 1028 + manufacturer_name: "Luminxa" +} manufacturer { manufacturer_id: 13853 manufacturer_name: "Lumishore Ltd. UK" @@ -1694,6 +2542,10 @@ manufacturer { manufacturer_id: 269 manufacturer_name: "Lumos / DMLite" } +manufacturer { + manufacturer_id: 180 + manufacturer_name: "Lumos Design" +} manufacturer { manufacturer_id: 748 manufacturer_name: "Lutron Electronics" @@ -1702,6 +2554,10 @@ manufacturer { manufacturer_id: 826 manufacturer_name: "Lux Lumen" } +manufacturer { + manufacturer_id: 156 + manufacturer_name: "LuxBalance Lighting" +} manufacturer { manufacturer_id: 2433 manufacturer_name: "Luxam, Ltd." @@ -1714,6 +2570,10 @@ manufacturer { manufacturer_id: 19777 manufacturer_name: "MA Lighting Technology GmbH" } +manufacturer { + manufacturer_id: 26221 + manufacturer_name: "MAD-Effects" +} manufacturer { manufacturer_id: 18008 manufacturer_name: "MAGIC FX B.V." @@ -1726,6 +2586,10 @@ manufacturer { manufacturer_id: 19809 manufacturer_name: "MARTINI S.p.A." } +manufacturer { + manufacturer_id: 1605 + manufacturer_name: "MATSUMURA ELECTRIC MFG. CO. , LTD." +} manufacturer { manufacturer_id: 28002 manufacturer_name: "MBN GmbH" @@ -1750,6 +2614,14 @@ manufacturer { manufacturer_id: 1999 manufacturer_name: "MH-Sound" } +manufacturer { + manufacturer_id: 421 + manufacturer_name: "MJ Lighting Co., Ltd." +} +manufacturer { + manufacturer_id: 2142 + manufacturer_name: "MMS Distribution Ltd" +} manufacturer { manufacturer_id: 10465 manufacturer_name: "MTC maintronic GmbH" @@ -1762,14 +2634,30 @@ manufacturer { manufacturer_id: 1938 manufacturer_name: "MY-Semi Inc." } +manufacturer { + manufacturer_id: 11049 + manufacturer_name: "MaNima Technologies BV" +} manufacturer { manufacturer_id: 13192 manufacturer_name: "Macostar International Ltd." } +manufacturer { + manufacturer_id: 2001 + manufacturer_name: "Made By Mouse LTD" +} +manufacturer { + manufacturer_id: 27497 + manufacturer_name: "Magical Fountain SA de CV (Magic Fountain)" +} manufacturer { manufacturer_id: 1205 manufacturer_name: "Major" } +manufacturer { + manufacturer_id: 1365 + manufacturer_name: "Maresch Electronics" +} manufacturer { manufacturer_id: 19792 manufacturer_name: "Martin Professional A/S" @@ -1782,22 +2670,58 @@ manufacturer { manufacturer_id: 2420 manufacturer_name: "Marumo Electric Co., Ltd." } +manufacturer { + manufacturer_id: 2284 + manufacturer_name: "Marvin Nadrowski" +} manufacturer { manufacturer_id: 7887 manufacturer_name: "Masiero s.r.l." } +manufacturer { + manufacturer_id: 286 + manufacturer_name: "Master LED" +} manufacturer { manufacturer_id: 2269 manufacturer_name: "Matthew Tong" } +manufacturer { + manufacturer_id: 2526 + manufacturer_name: "Matthias Bauch Software" +} manufacturer { manufacturer_id: 676 manufacturer_name: "McNicoll Entertainment Systems" } +manufacturer { + manufacturer_id: 2143 + manufacturer_name: "Media Visions, Inc." +} manufacturer { manufacturer_id: 23980 manufacturer_name: "Mediatec Group" } +manufacturer { + manufacturer_id: 25410 + manufacturer_name: "Mega Systems Inc." +} +manufacturer { + manufacturer_id: 22098 + manufacturer_name: "Megapixel Visual Reality" +} +manufacturer { + manufacturer_id: 115 + manufacturer_name: "Meijay Technologies Co., Ltd." +} +manufacturer { + manufacturer_id: 2234 + manufacturer_name: "Meteor Lighting" +} +manufacturer { + manufacturer_id: 2236 + manufacturer_name: "Michael Parkin" +} manufacturer { manufacturer_id: 9908 manufacturer_name: "Milford Instruments Ltd." @@ -1830,14 +2754,30 @@ manufacturer { manufacturer_id: 2508 manufacturer_name: "Motomuto Aps" } +manufacturer { + manufacturer_id: 4611 + manufacturer_name: "Movecat GmbH" +} manufacturer { manufacturer_id: 19831 - manufacturer_name: "Muller Elektronik" + manufacturer_name: "Mueller Elektronik" } manufacturer { manufacturer_id: 5584 manufacturer_name: "Music & Lights S.r.l." } +manufacturer { + manufacturer_id: 1715 + manufacturer_name: "NANOLUMENS, INC." +} +manufacturer { + manufacturer_id: 2132 + manufacturer_name: "NEC Display Solutions, Ltd." +} +manufacturer { + manufacturer_id: 1835 + manufacturer_name: "NEWSUBSTANCE Ltd." +} manufacturer { manufacturer_id: 20042 manufacturer_name: "NJD Electronics" @@ -1856,7 +2796,7 @@ manufacturer { } manufacturer { manufacturer_id: 2063 - manufacturer_name: "Navo Corp." + manufacturer_name: "NavoLabs" } manufacturer { manufacturer_id: 2123 @@ -1870,6 +2810,10 @@ manufacturer { manufacturer_id: 4826 manufacturer_name: "Newlab S.r.l." } +manufacturer { + manufacturer_id: 20560 + manufacturer_name: "Newton Engineering and Design Group LLC" +} manufacturer { manufacturer_id: 13107 manufacturer_name: "NightStarry Electronics Co., LTD." @@ -1882,6 +2826,10 @@ manufacturer { manufacturer_id: 10020 manufacturer_name: "Nila Inc." } +manufacturer { + manufacturer_id: 149 + manufacturer_name: "Ningbo Jeg Lighting Tech Co., Ltd." +} manufacturer { manufacturer_id: 10036 manufacturer_name: "Nixer Ltd." @@ -1890,17 +2838,25 @@ manufacturer { manufacturer_id: 5966 manufacturer_name: "Nordgas SNe-lightingsystem" } +manufacturer { + manufacturer_id: 13623 + manufacturer_name: "Novacorp Inc." +} manufacturer { manufacturer_id: 25089 manufacturer_name: "NuDelta Digital, LLC" } +manufacturer { + manufacturer_id: 117 + manufacturer_name: "ODELI" +} manufacturer { manufacturer_id: 1630 manufacturer_name: "OFilms" } manufacturer { manufacturer_id: 674 - manufacturer_name: "OJSC Kadoshkinsky electrotechnical " + manufacturer_name: "OJSC Kadoshkinsky electrotechnical" } manufacturer { manufacturer_id: 17969 @@ -1927,13 +2883,17 @@ manufacturer { manufacturer_name: "Oase GmbH" } manufacturer { - manufacturer_id: 20291 - manufacturer_name: "Obsidian Controls Ltd." + manufacturer_id: 409 + manufacturer_name: "Ocean LED Marine Ltd." } manufacturer { manufacturer_id: 21315 manufacturer_name: "Ocean Thin Films Inc." } +manufacturer { + manufacturer_id: 20291 + manufacturer_name: "Offstage Controls (formerly Obsidian Control)" +} manufacturer { manufacturer_id: 31344 manufacturer_name: "Open Lighting" @@ -1942,14 +2902,42 @@ manufacturer { manufacturer_id: 749 manufacturer_name: "OpenLX SP Ltd." } +manufacturer { + manufacturer_id: 2083 + manufacturer_name: "Opito Labs GmbH" +} +manufacturer { + manufacturer_id: 2221 + manufacturer_name: "Optical Productions LLC" +} +manufacturer { + manufacturer_id: 139 + manufacturer_name: "Opto Tech Corporation" +} +manufacturer { + manufacturer_id: 2291 + manufacturer_name: "Outdoor Lasers Ltd." +} manufacturer { manufacturer_id: 20341 manufacturer_name: "Outsight Pty Ltd." } +manufacturer { + manufacturer_id: 20561 + manufacturer_name: "PDQ Manufacturing, Inc" +} manufacturer { manufacturer_id: 7089 manufacturer_name: "PH Lightning AB" } +manufacturer { + manufacturer_id: 1828 + manufacturer_name: "PHC Lighting & BMS Sp. z o.o." +} +manufacturer { + manufacturer_id: 2005 + manufacturer_name: "PHIDA Stage Equipment Co., Ltd" +} manufacturer { manufacturer_id: 2266 manufacturer_name: "PLC Intelligent Technology (Shanghai) Co., Ltd." @@ -1962,13 +2950,17 @@ manufacturer { manufacturer_id: 10281 manufacturer_name: "PR-Electronic" } +manufacturer { + manufacturer_id: 4609 + manufacturer_name: "PRICOM Design" +} manufacturer { manufacturer_id: 1375 manufacturer_name: "PRO-SOLUTIONS" } manufacturer { manufacturer_id: 684 - manufacturer_name: "PSL Electronik Sanayi ve Ticaret A.S. " + manufacturer_name: "PSL Electronik Sanayi ve Ticaret A.S." } manufacturer { manufacturer_id: 20568 @@ -1978,13 +2970,17 @@ manufacturer { manufacturer_id: 8319 manufacturer_name: "Padura Elektronik GmbH" } +manufacturer { + manufacturer_id: 6587 + manufacturer_name: "Panalux Ltd." +} manufacturer { manufacturer_id: 1871 manufacturer_name: "Panasonic Corporation" } manufacturer { manufacturer_id: 28912 - manufacturer_name: "Pangolin Laser Systems, Inc. " + manufacturer_name: "Pangolin Laser Systems, Inc." } manufacturer { manufacturer_id: 20547 @@ -2020,7 +3016,7 @@ manufacturer { } manufacturer { manufacturer_id: 10279 - manufacturer_name: "Peternet Electronics BVBA " + manufacturer_name: "Peternet Electronics BVBA" } manufacturer { manufacturer_id: 20582 @@ -2046,10 +3042,18 @@ manufacturer { manufacturer_id: 20563 manufacturer_name: "Philips Selecon" } +manufacturer { + manufacturer_id: 477 + manufacturer_name: "Photonia srl" +} manufacturer { manufacturer_id: 2218 manufacturer_name: "PiXL Factory" } +manufacturer { + manufacturer_id: 129 + manufacturer_name: "Pino Solutions" +} manufacturer { manufacturer_id: 10273 manufacturer_name: "Pioneer Corporation" @@ -2058,6 +3062,10 @@ manufacturer { manufacturer_id: 28792 manufacturer_name: "PixelRange Inc." } +manufacturer { + manufacturer_id: 1804 + manufacturer_name: "Pixout SIA" +} manufacturer { manufacturer_id: 10294 manufacturer_name: "Planungsbuero" @@ -2070,6 +3078,10 @@ manufacturer { manufacturer_id: 460 manufacturer_name: "Portman Custom Lights" } +manufacturer { + manufacturer_id: 2166 + manufacturer_name: "Power Gems LTD" +} manufacturer { manufacturer_id: 28786 manufacturer_name: "Pr-Lighting Ltd." @@ -2106,6 +3118,14 @@ manufacturer { manufacturer_id: 20813 manufacturer_name: "QMAXZ lighting" } +manufacturer { + manufacturer_id: 2219 + manufacturer_name: "Qdot Lighting Limited" +} +manufacturer { + manufacturer_id: 16397 + manufacturer_name: "Quasar Science LLC" +} manufacturer { manufacturer_id: 20819 manufacturer_name: "QuickSilver Controls, Inc." @@ -2114,6 +3134,14 @@ manufacturer { manufacturer_id: 20844 manufacturer_name: "Quicklights" } +manufacturer { + manufacturer_id: 118 + manufacturer_name: "R. S. Schwarze Elektrotechnik Moderne Industrieelektronik GmbH" +} +manufacturer { + manufacturer_id: 1366 + manufacturer_name: "RAYSYS" +} manufacturer { manufacturer_id: 1616 manufacturer_name: "RDC, Inc. d.b.a. LynTec" @@ -2123,67 +3151,67 @@ manufacturer { manufacturer_name: "RE-Engineering" } manufacturer { - manufacturer_id: 32759 + manufacturer_id: 32752 manufacturer_name: "RESERVED FOR PROTOTYPING/EXPERIMENTAL USE ONLY" } manufacturer { - manufacturer_id: 32767 + manufacturer_id: 32760 manufacturer_name: "RESERVED FOR PROTOTYPING/EXPERIMENTAL USE ONLY" } manufacturer { - manufacturer_id: 32763 + manufacturer_id: 32756 manufacturer_name: "RESERVED FOR PROTOTYPING/EXPERIMENTAL USE ONLY" } manufacturer { - manufacturer_id: 32755 + manufacturer_id: 32764 manufacturer_name: "RESERVED FOR PROTOTYPING/EXPERIMENTAL USE ONLY" } manufacturer { - manufacturer_id: 32761 + manufacturer_id: 32754 manufacturer_name: "RESERVED FOR PROTOTYPING/EXPERIMENTAL USE ONLY" } manufacturer { - manufacturer_id: 32753 + manufacturer_id: 32762 manufacturer_name: "RESERVED FOR PROTOTYPING/EXPERIMENTAL USE ONLY" } manufacturer { - manufacturer_id: 32765 + manufacturer_id: 32758 manufacturer_name: "RESERVED FOR PROTOTYPING/EXPERIMENTAL USE ONLY" } manufacturer { - manufacturer_id: 32757 + manufacturer_id: 32766 manufacturer_name: "RESERVED FOR PROTOTYPING/EXPERIMENTAL USE ONLY" } manufacturer { - manufacturer_id: 32760 + manufacturer_id: 32753 manufacturer_name: "RESERVED FOR PROTOTYPING/EXPERIMENTAL USE ONLY" } manufacturer { - manufacturer_id: 32752 + manufacturer_id: 32761 manufacturer_name: "RESERVED FOR PROTOTYPING/EXPERIMENTAL USE ONLY" } manufacturer { - manufacturer_id: 32764 + manufacturer_id: 32757 manufacturer_name: "RESERVED FOR PROTOTYPING/EXPERIMENTAL USE ONLY" } manufacturer { - manufacturer_id: 32756 + manufacturer_id: 32765 manufacturer_name: "RESERVED FOR PROTOTYPING/EXPERIMENTAL USE ONLY" } manufacturer { - manufacturer_id: 32762 + manufacturer_id: 32755 manufacturer_name: "RESERVED FOR PROTOTYPING/EXPERIMENTAL USE ONLY" } manufacturer { - manufacturer_id: 32754 + manufacturer_id: 32763 manufacturer_name: "RESERVED FOR PROTOTYPING/EXPERIMENTAL USE ONLY" } manufacturer { - manufacturer_id: 32766 + manufacturer_id: 32759 manufacturer_name: "RESERVED FOR PROTOTYPING/EXPERIMENTAL USE ONLY" } manufacturer { - manufacturer_id: 32758 + manufacturer_id: 32767 manufacturer_name: "RESERVED FOR PROTOTYPING/EXPERIMENTAL USE ONLY" } manufacturer { @@ -2202,6 +3230,14 @@ manufacturer { manufacturer_id: 10535 manufacturer_name: "ROAL Electronics SpA" } +manufacturer { + manufacturer_id: 2024 + manufacturer_name: "ROCKETSIGN Technology HK Ltd" +} +manufacturer { + manufacturer_id: 1699 + manufacturer_name: "RODLIGHT ALBRECHT SILBERBERGER" +} manufacturer { manufacturer_id: 2438 manufacturer_name: "ROE Visual Co. Ltd." @@ -2226,6 +3262,10 @@ manufacturer { manufacturer_id: 462 manufacturer_name: "Railiks Enterprises" } +manufacturer { + manufacturer_id: 20593 + manufacturer_name: "Raindrop-Media" +} manufacturer { manufacturer_id: 2431 manufacturer_name: "RaumZeitLabor e.V." @@ -2254,9 +3294,13 @@ manufacturer { manufacturer_id: 21060 manufacturer_name: "Revolution Display" } +manufacturer { + manufacturer_id: 435 + manufacturer_name: "Ricardo Dias" +} manufacturer { manufacturer_id: 169 - manufacturer_name: "Richter Lighting Technologies GmbH " + manufacturer_name: "Richter Lighting Technologies GmbH" } manufacturer { manufacturer_id: 683 @@ -2286,6 +3330,22 @@ manufacturer { manufacturer_id: 843 manufacturer_name: "Rosstech Signals Inc." } +manufacturer { + manufacturer_id: 6153 + manufacturer_name: "Rotolight" +} +manufacturer { + manufacturer_id: 4641 + manufacturer_name: "SAGITTER - Proel" +} +manufacturer { + manufacturer_id: 164 + manufacturer_name: "SAKMA Electronica Industrial S.A.U." +} +manufacturer { + manufacturer_id: 107 + manufacturer_name: "SALZBRENNER media GmbH" +} manufacturer { manufacturer_id: 16465 manufacturer_name: "SAN JACK ANALOG HOUSE CO., LTD." @@ -2294,9 +3354,13 @@ manufacturer { manufacturer_id: 21322 manufacturer_name: "SAS Productions" } +manufacturer { + manufacturer_id: 28784 + manufacturer_name: "SBT GmbH" +} manufacturer { manufacturer_id: 455 - manufacturer_name: "SCHIEDERWERK GmbH " + manufacturer_name: "SCHIEDERWERK GmbH" } manufacturer { manufacturer_id: 5216 @@ -2314,6 +3378,10 @@ manufacturer { manufacturer_id: 21319 manufacturer_name: "SGM Technology For Lighting SPA" } +manufacturer { + manufacturer_id: 1686 + manufacturer_name: "SHENZHEN HOION LIGHTING CO.,LTD" +} manufacturer { manufacturer_id: 5418 manufacturer_name: "SHOWTACLE Ltd." @@ -2334,10 +3402,18 @@ manufacturer { manufacturer_id: 21323 manufacturer_name: "SK-Software" } +manufacturer { + manufacturer_id: 4642 + manufacturer_name: "SM International" +} manufacturer { manufacturer_id: 21324 manufacturer_name: "SOUNDLIGHT" } +manufacturer { + manufacturer_id: 367 + manufacturer_name: "SQD Lighting Co. Ltd" +} manufacturer { manufacturer_id: 463 manufacturer_name: "SRM Technik GmbH" @@ -2360,7 +3436,7 @@ manufacturer { } manufacturer { manufacturer_id: 2259 - manufacturer_name: "SVI Public Company Limited " + manufacturer_name: "SVI Public Company Limited" } manufacturer { manufacturer_id: 21367 @@ -2394,6 +3470,14 @@ manufacturer { manufacturer_id: 21331 manufacturer_name: "Sean Sill" } +manufacturer { + manufacturer_id: 522 + manufacturer_name: "Seebacher GmbH" +} +manufacturer { + manufacturer_id: 4608 + manufacturer_name: "Seekway Technology Limited" +} manufacturer { manufacturer_id: 28003 manufacturer_name: "Sein & Schein GmbH" @@ -2410,10 +3494,18 @@ manufacturer { manufacturer_id: 2260 manufacturer_name: "Sensa-Lite Ltd." } +manufacturer { + manufacturer_id: 166 + manufacturer_name: "Sensation Lighting Technology Co., Ltd." +} manufacturer { manufacturer_id: 5902 manufacturer_name: "Serva Transport Systems GmbH" } +manufacturer { + manufacturer_id: 427 + manufacturer_name: "Shanghai Euchips Industrial Co., Ltd." +} manufacturer { manufacturer_id: 771 manufacturer_name: "Shanghai Moons' Automation Control Co., Ltd" @@ -2422,14 +3514,46 @@ manufacturer { manufacturer_id: 464 manufacturer_name: "Shanghai Semping Electronics Co., Ltd." } +manufacturer { + manufacturer_id: 20482 + manufacturer_name: "Shanghai Shylon Optoelectronic Technology Co., Ltd." +} +manufacturer { + manufacturer_id: 2369 + manufacturer_name: "Shenzen Zhuoyang Intelligent Technology Co., Ltd." +} +manufacturer { + manufacturer_id: 128 + manufacturer_name: "Shenzhen AOTO Electronics Co., Ltd." +} manufacturer { manufacturer_id: 25092 manufacturer_name: "Shenzhen Absen Optoelectronic Co., Ltd" } +manufacturer { + manufacturer_id: 22101 + manufacturer_name: "Shenzhen CAS VU Technologies Co., Ltd." +} +manufacturer { + manufacturer_id: 2273 + manufacturer_name: "Shenzhen CLT Electronics Co.,LTD" +} +manufacturer { + manufacturer_id: 778 + manufacturer_name: "Shenzhen Colordreamer Technology Co., Ltd." +} manufacturer { manufacturer_id: 2368 manufacturer_name: "Shenzhen CreateLED Electronics Co., Ltd" } +manufacturer { + manufacturer_id: 160 + manufacturer_name: "Shenzhen Dicolor Optoelectronics Co., Ltd." +} +manufacturer { + manufacturer_id: 2187 + manufacturer_name: "Shenzhen Doit Vision Co., Ltd" +} manufacturer { manufacturer_id: 15240 manufacturer_name: "Shenzhen Eastar Electronic Co., Ltd." @@ -2438,26 +3562,66 @@ manufacturer { manufacturer_id: 2058 manufacturer_name: "Shenzhen FantaLED Electronics Co., Ltd" } +manufacturer { + manufacturer_id: 2209 + manufacturer_name: "Shenzhen Gloshine Technology Co., Ltd" +} manufacturer { manufacturer_id: 2307 manufacturer_name: "Shenzhen INFiLED Electronics, Ltd." } +manufacturer { + manufacturer_id: 27631 + manufacturer_name: "Shenzhen Ifountain Technology Ltd." +} manufacturer { manufacturer_id: 32232 manufacturer_name: "Shenzhen LAMP Technology Co., Ltd." } +manufacturer { + manufacturer_id: 2111 + manufacturer_name: "Shenzhen LeiFei Lighting Technologies Co.,Ltd." +} manufacturer { manufacturer_id: 1451 - manufacturer_name: "Shenzhen Lesan Lighting Co., Ltd. " + manufacturer_name: "Shenzhen Lesan Lighting Co., Ltd." +} +manufacturer { + manufacturer_id: 469 + manufacturer_name: "Shenzhen Liantronics Co., Ltd" +} +manufacturer { + manufacturer_id: 2467 + manufacturer_name: "Shenzhen Lightlink Display Technology Co., Ltd" } manufacturer { manufacturer_id: 2444 - manufacturer_name: "Shenzhen Longrich Energy Sources Technology Co., Ltd. " + manufacturer_name: "Shenzhen Longrich Energy Sources Technology Co., Ltd." +} +manufacturer { + manufacturer_id: 184 + manufacturer_name: "Shenzhen Singba Light Technology Co., Ltd." } manufacturer { manufacturer_id: 20840 manufacturer_name: "Shenzhen Sunricher Technology Co.,Ltd." } +manufacturer { + manufacturer_id: 2320 + manufacturer_name: "Shenzhen Tecnon EXCO-Vision Technology Co., Ltd." +} +manufacturer { + manufacturer_id: 425 + manufacturer_name: "Shenzhen Uniview LED Ltd. Co." +} +manufacturer { + manufacturer_id: 520 + manufacturer_name: "Shenzhen Yuming Vision Technology Co., Ltd." +} +manufacturer { + manufacturer_id: 20592 + manufacturer_name: "Show Light Oy" +} manufacturer { manufacturer_id: 21352 manufacturer_name: "ShowCAD Control Systems Ltd." @@ -2470,6 +3634,18 @@ manufacturer { manufacturer_id: 10676 manufacturer_name: "Showtec (Highlite International B.V.)" } +manufacturer { + manufacturer_id: 2365 + manufacturer_name: "Sichuan Hushan Electric Co. Ltd" +} +manufacturer { + manufacturer_id: 2318 + manufacturer_name: "Sichuan esRadio Technology Co., Ltd" +} +manufacturer { + manufacturer_id: 4371 + manufacturer_name: "SiliconCore Technology, Inc." +} manufacturer { manufacturer_id: 21416 manufacturer_name: "Simon Tech" @@ -2502,6 +3678,10 @@ manufacturer { manufacturer_id: 21347 manufacturer_name: "SpaceCannon vH" } +manufacturer { + manufacturer_id: 2286 + manufacturer_name: "Spacelights" +} manufacturer { manufacturer_id: 10680 manufacturer_name: "Spotlight s.r.l." @@ -2510,6 +3690,10 @@ manufacturer { manufacturer_id: 257 manufacturer_name: "St. Anne Engineering GmbH" } +manufacturer { + manufacturer_id: 2190 + manufacturer_name: "Stage One International Co., Ltd." +} manufacturer { manufacturer_id: 4852 manufacturer_name: "Stage Services Ltd." @@ -2530,6 +3714,14 @@ manufacturer { manufacturer_id: 21332 manufacturer_name: "Stagetronics Ltda" } +manufacturer { + manufacturer_id: 2561 + manufacturer_name: "Star-Reach Corporation" +} +manufacturer { + manufacturer_id: 2315 + manufacturer_name: "StarLighting" +} manufacturer { manufacturer_id: 21316 manufacturer_name: "Stardraw.com Ltd." @@ -2562,6 +3754,10 @@ manufacturer { manufacturer_id: 29548 manufacturer_name: "Strand Lighting Ltd." } +manufacturer { + manufacturer_id: 25957 + manufacturer_name: "Stratus Systems LLC" +} manufacturer { manufacturer_id: 911 manufacturer_name: "Strich Labs" @@ -2582,6 +3778,10 @@ manufacturer { manufacturer_id: 10657 manufacturer_name: "Sturdy Corporation" } +manufacturer { + manufacturer_id: 181 + manufacturer_name: "Suga koubou Co., Ltd." +} manufacturer { manufacturer_id: 10679 manufacturer_name: "Sundrax, LLC" @@ -2590,10 +3790,26 @@ manufacturer { manufacturer_id: 26180 manufacturer_name: "Sunlab Technologies S.L." } +manufacturer { + manufacturer_id: 2542 + manufacturer_name: "Suzhou Pinzong Electronic Technology, CO.,Ltd" +} +manufacturer { + manufacturer_id: 770 + manufacturer_name: "Swefog Technology Group AB" +} +manufacturer { + manufacturer_id: 401 + manufacturer_name: "Sycra Technologies" +} manufacturer { manufacturer_id: 1276 manufacturer_name: "Syncrolite LLC" } +manufacturer { + manufacturer_id: 167 + manufacturer_name: "Syncronorm GmbH" +} manufacturer { manufacturer_id: 21318 manufacturer_name: "Synthe FX, LLC" @@ -2604,7 +3820,7 @@ manufacturer { } manufacturer { manufacturer_id: 1969 - manufacturer_name: "TBF-PyroTec GmbH " + manufacturer_name: "TBF-PyroTec GmbH" } manufacturer { manufacturer_id: 1335 @@ -2618,10 +3834,18 @@ manufacturer { manufacturer_id: 2045 manufacturer_name: "THELIGHT Luminary for Cine and TV S.L." } +manufacturer { + manufacturer_id: 199 + manufacturer_name: "THOR" +} manufacturer { manufacturer_id: 6906 manufacturer_name: "TMB" } +manufacturer { + manufacturer_id: 90 + manufacturer_name: "TPD Lighting" +} manufacturer { manufacturer_id: 737 manufacturer_name: "Tait Towers Manufacturing Inc." @@ -2638,18 +3862,30 @@ manufacturer { manufacturer_id: 1239 manufacturer_name: "Targetti Sankey Spa" } +manufacturer { + manufacturer_id: 2192 + manufacturer_name: "Taurus Light Co.,Limited" +} manufacturer { manufacturer_id: 2426 manufacturer_name: "Teamboyce Limited" } manufacturer { manufacturer_id: 21569 - manufacturer_name: "TecArt Lighting " + manufacturer_name: "TecArt Lighting" +} +manufacturer { + manufacturer_id: 2222 + manufacturer_name: "Technical Audio Group Pty Ltd" } manufacturer { manufacturer_id: 21572 manufacturer_name: "Technographic Displays Ltd." } +manufacturer { + manufacturer_id: 32489 + manufacturer_name: "Technology Kitchen" +} manufacturer { manufacturer_id: 13106 manufacturer_name: "Teclumen s.r.l." @@ -2658,6 +3894,10 @@ manufacturer { manufacturer_id: 21580 manufacturer_name: "Tempest Lighting Inc." } +manufacturer { + manufacturer_id: 190 + manufacturer_name: "The Light Luminary for Cine and TV S.L. (VELVET LIGHT)" +} manufacturer { manufacturer_id: 29009 manufacturer_name: "The Light Source, Inc." @@ -2678,6 +3918,10 @@ manufacturer { manufacturer_id: 713 manufacturer_name: "Theatrixx Technologies" } +manufacturer { + manufacturer_id: 116 + manufacturer_name: "Thomann GmbH" +} manufacturer { manufacturer_id: 10789 manufacturer_name: "Thorn Lighting Limited" @@ -2698,18 +3942,38 @@ manufacturer { manufacturer_id: 26608 manufacturer_name: "Toshiba Lighting & Technology Corporation" } +manufacturer { + manufacturer_id: 2333 + manufacturer_name: "TouchPlate Technologies Inc." +} manufacturer { manufacturer_id: 5852 - manufacturer_name: "Traxon Technologies Ltd. " + manufacturer_name: "Traxon Technologies Ltd." } manufacturer { manufacturer_id: 1461 - manufacturer_name: "Turkowski GmbH " + manufacturer_name: "Turkowski GmbH" +} +manufacturer { + manufacturer_id: 410 + manufacturer_name: "TwoGain Electronics" } manufacturer { manufacturer_id: 21840 manufacturer_name: "UP-LUX Eletronica Ltda." } +manufacturer { + manufacturer_id: 2345 + manufacturer_name: "UPlight stage equipment(GZ) CO., Ltd." +} +manufacturer { + manufacturer_id: 1619 + manufacturer_name: "USAI, LLC" +} +manufacturer { + manufacturer_id: 2552 + manufacturer_name: "UberDisplays" +} manufacturer { manufacturer_id: 19533 manufacturer_name: "Ultratec Special Effects" @@ -2726,14 +3990,30 @@ manufacturer { manufacturer_id: 2393 manufacturer_name: "Urbs Lighting, LLC" } +manufacturer { + manufacturer_id: 2152 + manufacturer_name: "Ushio America, Inc." +} +manufacturer { + manufacturer_id: 4610 + manufacturer_name: "Ushio Lighting, Inc." +} manufacturer { manufacturer_id: 265 manufacturer_name: "V-Productions" } +manufacturer { + manufacturer_id: 18432 + manufacturer_name: "VOD VISUAL.CO. (UK) Ltd." +} manufacturer { manufacturer_id: 4941 manufacturer_name: "VT-Control" } +manufacturer { + manufacturer_id: 6682 + manufacturer_name: "ValDim Waterfountains Ltd." +} manufacturer { manufacturer_id: 22092 manufacturer_name: "Vari-Lite, Inc." @@ -2750,6 +4030,10 @@ manufacturer { manufacturer_id: 280 manufacturer_name: "Vello Light Co., Ltd." } +manufacturer { + manufacturer_id: 2336 + manufacturer_name: "Vexica Technology Limited" +} manufacturer { manufacturer_id: 22097 manufacturer_name: "Vision Quest Lighting Inc." @@ -2770,6 +4054,10 @@ manufacturer { manufacturer_id: 174 manufacturer_name: "Vitrulux Ltd" } +manufacturer { + manufacturer_id: 137 + manufacturer_name: "Vulcan Lighting" +} manufacturer { manufacturer_id: 22340 manufacturer_name: "W-DEV" @@ -2790,10 +4078,18 @@ manufacturer { manufacturer_id: 30564 manufacturer_name: "WET" } +manufacturer { + manufacturer_id: 110 + manufacturer_name: "WHITEvoid GmbH" +} manufacturer { manufacturer_id: 2515 manufacturer_name: "WLPS Wodielite Production Services" } +manufacturer { + manufacturer_id: 22343 + manufacturer_name: "Wenger / JR Clancy" +} manufacturer { manufacturer_id: 22342 manufacturer_name: "Wildfire, Inc." @@ -2810,6 +4106,10 @@ manufacturer { manufacturer_id: 22355 manufacturer_name: "Wireless Solution Sweden AB" } +manufacturer { + manufacturer_id: 400 + manufacturer_name: "Wizlogics Co., Ltd." +} manufacturer { manufacturer_id: 22361 manufacturer_name: "Wybron, Inc." @@ -2830,14 +4130,34 @@ manufacturer { manufacturer_id: 11306 manufacturer_name: "XTBA" } +manufacturer { + manufacturer_id: 2147 + manufacturer_name: "XTEC Industries Pte Ltd" +} manufacturer { manufacturer_id: 2324 manufacturer_name: "Xenio" } +manufacturer { + manufacturer_id: 195 + manufacturer_name: "Xicato" +} manufacturer { manufacturer_id: 22605 manufacturer_name: "Xtraordinary Musical Accolade Systems" } +manufacturer { + manufacturer_id: 285 + manufacturer_name: "Yangzhou Zhituo Lighting Vision Technology Co., Ltd." +} +manufacturer { + manufacturer_id: 465 + manufacturer_name: "Yarilo Pro" +} +manufacturer { + manufacturer_id: 2441 + manufacturer_name: "YeGrin Liteworks" +} manufacturer { manufacturer_id: 14341 manufacturer_name: "Yifeng Lighting Co., Ltd." @@ -2846,26 +4166,46 @@ manufacturer { manufacturer_id: 5968 manufacturer_name: "Yuesheng International Limited" } +manufacturer { + manufacturer_id: 417 + manufacturer_name: "Yuesheng Stage Light Limited" +} +manufacturer { + manufacturer_id: 1711 + manufacturer_name: "ZHEJIANG JINGRI TECHNOLOGY CO.,LTD" +} manufacturer { manufacturer_id: 5292 manufacturer_name: "Zaklad Elektroniczny AGAT s.c." } manufacturer { - manufacturer_id: 2056 - manufacturer_name: "Zero 88" + manufacturer_id: 8201 + manufacturer_name: "Zboxes Intelligent Technology (Shanghai) Co., Ltd." } manufacturer { manufacturer_id: 172 manufacturer_name: "ZhouChuang Industrial Co. Limited" } +manufacturer { + manufacturer_id: 4370 + manufacturer_name: "Zhuhai Bincolor Electronic Technology Co., Ltd." +} manufacturer { manufacturer_id: 25093 manufacturer_name: "Zhuhai Ltech Technology Co., Ltd." } +manufacturer { + manufacturer_id: 2302 + manufacturer_name: "Zhuhai Shengchang Electronics Co., Ltd." +} manufacturer { manufacturer_id: 23123 manufacturer_name: "Zingerli Show Engineering" } +manufacturer { + manufacturer_id: 424 + manufacturer_name: "ZongDa Photoelectricity Science and Technology Co., Ltd." +} manufacturer { manufacturer_id: 27757 manufacturer_name: "Zumtobel Lighting GmbH" @@ -2878,6 +4218,10 @@ manufacturer { manufacturer_id: 2322 manufacturer_name: "ags - Wissenschaftliche Arbeitsgemeinschaft fur Studio- und Senderfragen" } +manufacturer { + manufacturer_id: 123 + manufacturer_name: "alurays lighting technology GmbH" +} manufacturer { manufacturer_id: 5776 manufacturer_name: "awaptec GmbH" @@ -2894,6 +4238,10 @@ manufacturer { manufacturer_id: 2556 manufacturer_name: "deskontrol electronics" } +manufacturer { + manufacturer_id: 146 + manufacturer_name: "digiLED (UK) Ltd." +} manufacturer { manufacturer_id: 25708 manufacturer_name: "dilitronics GmbH" @@ -2926,6 +4274,10 @@ manufacturer { manufacturer_id: 2205 manufacturer_name: "gobo.ws" } +manufacturer { + manufacturer_id: 20480 + manufacturer_name: "http://www.orangepi-dmx.org" +} manufacturer { manufacturer_id: 982 manufacturer_name: "i-Lumen" @@ -2942,10 +4294,18 @@ manufacturer { manufacturer_id: 26956 manufacturer_name: "iLight Technologies Inc" } +manufacturer { + manufacturer_id: 2487 + manufacturer_name: "inCon-trol water systems" +} manufacturer { manufacturer_id: 18753 manufacturer_name: "inoage GmbH" } +manufacturer { + manufacturer_id: 2352 + manufacturer_name: "jiaozuo shengguang film &equipment Co. Ltd" +} manufacturer { manufacturer_id: 2394 manufacturer_name: "kLabs Research UK" @@ -2970,10 +4330,30 @@ manufacturer { manufacturer_id: 19796 manufacturer_name: "medien technik cords" } +manufacturer { + manufacturer_id: 2057 + manufacturer_name: "mumoco GmbH" +} +manufacturer { + manufacturer_id: 32491 + manufacturer_name: "mylaserpage" +} +manufacturer { + manufacturer_id: 2304 + manufacturer_name: "nox multimedia GmbH" +} +manufacturer { + manufacturer_id: 189 + manufacturer_name: "numeo GmbH" +} manufacturer { manufacturer_id: 5658 manufacturer_name: "techKnow Design Ltd." } +manufacturer { + manufacturer_id: 178 + manufacturer_name: "unonovesette srl" +} manufacturer { manufacturer_id: 5382 manufacturer_name: "v2 Lighting Group, Inc." @@ -2982,8 +4362,12 @@ manufacturer { manufacturer_id: 22637 manufacturer_name: "www.doityourselfchristmas.com hobbyists" } +manufacturer { + manufacturer_id: 468 + manufacturer_name: "x-labs" +} manufacturer { manufacturer_id: 15664 manufacturer_name: "zactrack Lighting Technologies Gmbh" } -version: 1505079062 +version: 1582652364 diff --git a/data/rdm/manufacturer_pids.proto b/data/rdm/manufacturer_pids.proto index f59398dba4..7d0343aa7b 100644 --- a/data/rdm/manufacturer_pids.proto +++ b/data/rdm/manufacturer_pids.proto @@ -2496,18 +2496,78 @@ manufacturer { manufacturer_id: 17742 manufacturer_name: "ENTTEC Pty Ltd" pid { - name: "AUTO_MODE" - value: 34559 + name: "PWM_OUTPUT_FREQUENCY" + value: 32770 + get_request { + } + get_response { + field { + type: UINT16 + name: "frequency" + } + } + get_sub_device_range: ROOT_OR_SUBDEVICE + set_request { + field { + type: UINT16 + name: "frequency" + range { + min: 500 + max: 2000 + } + } + } + set_response { + } + set_sub_device_range: ROOT_OR_ALL_SUBDEVICE + } + pid { + name: "FAN_ON_PERCENTAGE" + value: 32771 get_request { } get_response { field { type: UINT8 - name: "program" + name: "percentage" + label { + value: 0 + label: "Auto" + } + } + } + get_sub_device_range: ROOT_DEVICE + set_request { + field { + type: UINT8 + name: "percentage" + label { + value: 0 + label: "Auto" + } range { min: 0 - max: 9 + max: 0 + } + range { + min: 50 + max: 100 } + } + } + set_response { + } + set_sub_device_range: ROOT_DEVICE + } + pid { + name: "AUTO_MODE" + value: 34559 + get_request { + } + get_response { + field { + type: UINT8 + name: "program" label { value: 0 label: "Disabled" @@ -2524,14 +2584,14 @@ manufacturer { value: 8 label: "1 colour chase, 3 chans FW>=1.2" } - } - field { - type: UINT8 - name: "speed" range { min: 0 max: 9 } + } + field { + type: UINT8 + name: "speed" label { value: 0 label: "Fastest" @@ -2540,14 +2600,14 @@ manufacturer { value: 9 label: "Slowest" } - } - field { - type: UINT8 - name: "delay" range { min: 0 max: 9 } + } + field { + type: UINT8 + name: "delay" label { value: 0 label: "Shortest" @@ -2556,17 +2616,17 @@ manufacturer { value: 9 label: "Longest" } + range { + min: 0 + max: 9 + } } } - get_sub_device_range: ROOT_OR_SUBDEVICE + get_sub_device_range: ROOT_DEVICE set_request { field { type: UINT8 name: "program" - range { - min: 0 - max: 9 - } label { value: 0 label: "Disabled" @@ -2583,14 +2643,14 @@ manufacturer { value: 8 label: "1 colour chase, 3 chans FW>=1.2" } - } - field { - type: UINT8 - name: "speed" range { min: 0 max: 9 } + } + field { + type: UINT8 + name: "speed" label { value: 0 label: "Fastest" @@ -2599,85 +2659,25 @@ manufacturer { value: 9 label: "Slowest" } - } - field { - type: UINT8 - name: "delay" range { min: 0 max: 9 } - label { - value: 0 - label: "Shortest" - } - label { - value: 9 - label: "Longest" - } } - } - set_response { - } - set_sub_device_range: ROOT_OR_ALL_SUBDEVICE - } - pid { - name: "PWM_OUTPUT_FREQUENCY" - value: 32770 - get_request { - } - get_response { - field { - type: UINT16 - name: "frequency" - } - } - get_sub_device_range: ROOT_OR_SUBDEVICE - set_request { - field { - type: UINT16 - name: "frequency" - range { - min: 500 - max: 2000 - } - } - } - set_response { - } - set_sub_device_range: ROOT_OR_ALL_SUBDEVICE - } - pid { - name: "FAN_ON_PERCENTAGE" - value: 32771 - get_request { - } - get_response { field { type: UINT8 - name: "percentage" + name: "delay" label { value: 0 - label: "Auto" + label: "Shortest" } - } - } - get_sub_device_range: ROOT_DEVICE - set_request { - field { - type: UINT8 - name: "percentage" label { - value: 0 - label: "Auto" + value: 9 + label: "Longest" } range { min: 0 - max: 0 - } - range { - min: 50 - max: 100 + max: 9 } } } @@ -3339,14 +3339,14 @@ manufacturer { get_response { field { type: UINT16 - name: "enabled" + name: "fixture_id" } } get_sub_device_range: ROOT_DEVICE set_request { field { type: UINT16 - name: "enabled" + name: "fixture_id" } } set_response { @@ -6919,6 +6919,72 @@ manufacturer { } set_sub_device_range: ROOT_OR_ALL_SUBDEVICE } + pid { + name: "PT_FEEDBACK" + value: 40960 + get_request { + } + get_response { + field { + type: BOOL + name: "Pan Tilt Feedback" + } + } + get_sub_device_range: ROOT_OR_SUBDEVICE + set_request { + field { + type: BOOL + name: "Pan Tilt Feedback" + } + } + set_response { + } + set_sub_device_range: ROOT_OR_ALL_SUBDEVICE + } + pid { + name: "OUTPUT_UNIFORMITY" + value: 40969 + get_request { + } + get_response { + field { + type: BOOL + name: "Output Uniformity" + } + } + get_sub_device_range: ROOT_OR_SUBDEVICE + set_request { + field { + type: BOOL + name: "Output Uniformity" + } + } + set_response { + } + set_sub_device_range: ROOT_OR_ALL_SUBDEVICE + } + pid { + name: "DL_COMPATIBLE_MODE" + value: 40973 + get_request { + } + get_response { + field { + type: BOOL + name: "DL Compatible Mode" + } + } + get_sub_device_range: ROOT_OR_SUBDEVICE + set_request { + field { + type: BOOL + name: "DL Compatible Mode" + } + } + set_response { + } + set_sub_device_range: ROOT_OR_ALL_SUBDEVICE + } pid { name: "TOUCHSCREEN_LOCK" value: 40975 @@ -9290,4 +9356,4 @@ manufacturer { set_sub_device_range: ROOT_DEVICE } } -version: 1528709287 +version: 1582652719 diff --git a/data/rdm/pids.proto b/data/rdm/pids.proto index 47b3c77dce..a74cf3df7b 100644 --- a/data/rdm/pids.proto +++ b/data/rdm/pids.proto @@ -4010,6 +4010,1267 @@ pid { } set_sub_device_range: ROOT_OR_ALL_SUBDEVICE } +pid { + name: "COMPONENT_SCOPE" + value: 2048 + get_request { + field { + type: UINT16 + name: "scope_slot" + range { + min: 1 + max: 65535 + } + } + } + get_response { + field { + type: UINT16 + name: "scope_slot" + range { + min: 1 + max: 65535 + } + } + field { + type: STRING + name: "scope_string" + max_size: 63 + } + field { + type: UINT8 + name: "static_config_type" + label { + value: 0 + label: "No static config" + } + label { + value: 1 + label: "Static config IPv4" + } + label { + value: 1 + label: "Static config IPv6" + } + range { + min: 0 + max: 2 + } + } + field { + type: IPV4 + name: "static_broker_ipv4_address" + label { + value: 0 + label: "No static broker IPv4 address" + } + } + field { + type: IPV6 + name: "static_broker_ipv6_address" + label { + value: 0 + label: "No static broker IPv6 address" + } + } + field { + type: UINT16 + name: "static_broker_port" + label { + value: 0 + label: "No static broker port" + } + } + } + get_sub_device_range: ROOT_DEVICE + set_request { + field { + type: UINT16 + name: "scope_slot" + range { + min: 1 + max: 65535 + } + } + field { + type: STRING + name: "scope_string" + max_size: 63 + } + field { + type: UINT8 + name: "static_config_type" + label { + value: 0 + label: "No static config" + } + label { + value: 1 + label: "Static config IPv4" + } + label { + value: 1 + label: "Static config IPv6" + } + range { + min: 0 + max: 2 + } + } + field { + type: IPV4 + name: "static_broker_ipv4_address" + label { + value: 0 + label: "No static broker IPv4 address" + } + } + field { + type: IPV6 + name: "static_broker_ipv6_address" + label { + value: 0 + label: "No static broker IPv6 address" + } + } + field { + type: UINT16 + name: "static_broker_port" + label { + value: 0 + label: "No static broker port" + } + } + } + set_response { + } + set_sub_device_range: ROOT_DEVICE +} +pid { + name: "SEARCH_DOMAIN" + value: 2049 + get_request { + } + get_response { + field { + type: STRING + name: "search_domain" + min_size: 0 + max_size: 231 + } + } + get_sub_device_range: ROOT_DEVICE + set_request { + field { + type: STRING + name: "search_domain" + min_size: 0 + max_size: 231 + } + } + set_response { + } + set_sub_device_range: ROOT_DEVICE +} +pid { + name: "TCP_COMMS_STATUS" + value: 2050 + get_request { + } + get_response { + field { + type: GROUP + name: "comms_statuses" + field { + type: STRING + name: "scope_string" + max_size: 63 + } + field { + type: IPV4 + name: "broker_ipv4_address" + label { + value: 0 + label: "No IPv4 Connection" + } + } + field { + type: IPV6 + name: "broker_ipv6_address" + label { + value: 0 + label: "No IPv6 Connection" + } + } + field { + type: UINT16 + name: "broker_port" + } + field { + type: UINT16 + name: "unhealthy_tcp_events" + } + } + } + get_sub_device_range: ROOT_DEVICE + set_request { + field { + type: STRING + name: "scope_string" + max_size: 63 + } + } + set_response { + } + set_sub_device_range: ROOT_DEVICE +} +pid { + name: "BROKER_STATUS" + value: 2051 + get_request { + } + get_response { + field { + type: BOOL + name: "set_allowed" + } + field { + type: UINT8 + name: "broker_state" + label { + value: 0 + label: "Disabled" + } + label { + value: 1 + label: "Active" + } + label { + value: 2 + label: "Standby" + } + range { + min: 0 + max: 2 + } + } + } + get_sub_device_range: ROOT_DEVICE + set_request { + field { + type: UINT8 + name: "broker_state" + label { + value: 0 + label: "Disabled" + } + label { + value: 1 + label: "Active" + } + range { + min: 0 + max: 1 + } + } + } + set_response { + } + set_sub_device_range: ROOT_DEVICE +} +pid { + name: "ENDPOINT_LIST" + value: 2304 + get_request { + } + get_response { + field { + type: UINT32 + name: "list_change_number" + } + field { + type: GROUP + name: "endpoints" + field { + type: UINT16 + name: "endpoint_id" + range { + min: 1 + max: 63999 + } + } + field { + type: UINT8 + name: "endpoint_type" + label { + value: 0 + label: "Virtual Endpoint" + } + label { + value: 1 + label: "Physical Endpoint" + } + range { + min: 0 + max: 1 + } + } + } + } + get_sub_device_range: ROOT_DEVICE +} +pid { + name: "ENDPOINT_LIST_CHANGE" + value: 2305 + get_request { + } + get_response { + field { + type: UINT32 + name: "list_change_number" + } + } + get_sub_device_range: ROOT_DEVICE +} +pid { + name: "IDENTIFY_ENDPOINT" + value: 2306 + get_request { + field { + type: UINT16 + name: "endpoint_id" + range { + min: 1 + max: 63999 + } + } + } + get_response { + field { + type: UINT16 + name: "endpoint_id" + range { + min: 1 + max: 63999 + } + } + field { + type: BOOL + name: "identify_state" + } + } + get_sub_device_range: ROOT_DEVICE + set_request { + field { + type: UINT16 + name: "endpoint_id" + label { + value: 65535 + label: "All Endpoints" + } + range { + min: 1 + max: 63999 + } + range { + min: 65535 + max: 65535 + } + } + field { + type: BOOL + name: "identify_state" + } + } + set_response { + field { + type: UINT16 + name: "endpoint_id" + label { + value: 65535 + label: "All Endpoints" + } + range { + min: 1 + max: 63999 + } + range { + min: 65535 + max: 65535 + } + } + } + set_sub_device_range: ROOT_DEVICE +} +pid { + name: "ENDPOINT_TO_UNIVERSE" + value: 2307 + get_request { + field { + type: UINT16 + name: "endpoint_id" + range { + min: 1 + max: 63999 + } + } + } + get_response { + field { + type: UINT16 + name: "endpoint_id" + range { + min: 1 + max: 63999 + } + } + field { + type: UINT16 + name: "universe" + label { + value: 0 + label: "Unpatched" + } + label { + value: 65535 + label: "Composite" + } + range { + min: 0 + max: 63999 + } + range { + min: 65535 + max: 65535 + } + } + } + get_sub_device_range: ROOT_DEVICE + set_request { + field { + type: UINT16 + name: "endpoint_id" + label { + value: 65535 + label: "All Endpoints" + } + range { + min: 1 + max: 63999 + } + range { + min: 65535 + max: 65535 + } + } + field { + type: UINT16 + name: "universe" + label { + value: 0 + label: "Unpatch" + } + range { + min: 0 + max: 63999 + } + } + } + set_response { + field { + type: UINT16 + name: "endpoint_id" + label { + value: 65535 + label: "All Endpoints" + } + range { + min: 1 + max: 63999 + } + range { + min: 65535 + max: 65535 + } + } + } + set_sub_device_range: ROOT_DEVICE +} +pid { + name: "ENDPOINT_MODE" + value: 2308 + get_request { + field { + type: UINT16 + name: "endpoint_id" + range { + min: 1 + max: 63999 + } + } + } + get_response { + field { + type: UINT16 + name: "endpoint_id" + range { + min: 1 + max: 63999 + } + } + field { + type: UINT8 + name: "endpoint_mode" + label { + value: 0 + label: "Disabled" + } + label { + value: 1 + label: "Input" + } + label { + value: 2 + label: "Output" + } + } + } + get_sub_device_range: ROOT_DEVICE + set_request { + field { + type: UINT16 + name: "endpoint_id" + label { + value: 65535 + label: "All Endpoints" + } + range { + min: 1 + max: 63999 + } + range { + min: 65535 + max: 65535 + } + } + field { + type: UINT8 + name: "endpoint_mode" + label { + value: 0 + label: "Disable" + } + label { + value: 1 + label: "Input" + } + label { + value: 2 + label: "Output" + } + } + } + set_response { + field { + type: UINT16 + name: "endpoint_id" + label { + value: 65535 + label: "All Endpoints" + } + range { + min: 1 + max: 63999 + } + range { + min: 65535 + max: 65535 + } + } + } + set_sub_device_range: ROOT_DEVICE +} +pid { + name: "ENDPOINT_LABEL" + value: 2309 + get_request { + field { + type: UINT16 + name: "endpoint_id" + range { + min: 1 + max: 63999 + } + } + } + get_response { + field { + type: UINT16 + name: "endpoint_id" + range { + min: 1 + max: 63999 + } + } + field { + type: STRING + name: "endpoint_label" + max_size: 32 + } + } + get_sub_device_range: ROOT_DEVICE + set_request { + field { + type: UINT16 + name: "endpoint_id" + label { + value: 65535 + label: "All Endpoints" + } + range { + min: 1 + max: 63999 + } + range { + min: 65535 + max: 65535 + } + } + field { + type: STRING + name: "endpoint_label" + max_size: 32 + } + } + set_response { + field { + type: UINT16 + name: "endpoint_id" + label { + value: 65535 + label: "All Endpoints" + } + range { + min: 1 + max: 63999 + } + range { + min: 65535 + max: 65535 + } + } + } + set_sub_device_range: ROOT_DEVICE +} +pid { + name: "RDM_TRAFFIC_ENABLE" + value: 2310 + get_request { + field { + type: UINT16 + name: "endpoint_id" + range { + min: 1 + max: 63999 + } + } + } + get_response { + field { + type: UINT16 + name: "endpoint_id" + range { + min: 1 + max: 63999 + } + } + field { + type: BOOL + name: "rdm_enabled" + } + } + get_sub_device_range: ROOT_DEVICE + set_request { + field { + type: UINT16 + name: "endpoint_id" + label { + value: 65535 + label: "All Endpoints" + } + range { + min: 1 + max: 63999 + } + range { + min: 65535 + max: 65535 + } + } + field { + type: BOOL + name: "rdm_enabled" + } + } + set_response { + field { + type: UINT16 + name: "endpoint_id" + label { + value: 65535 + label: "All Endpoints" + } + range { + min: 1 + max: 63999 + } + range { + min: 65535 + max: 65535 + } + } + } + set_sub_device_range: ROOT_DEVICE +} +pid { + name: "DISCOVERY_STATE" + value: 2311 + get_request { + field { + type: UINT16 + name: "endpoint_id" + range { + min: 1 + max: 63999 + } + } + } + get_response { + field { + type: UINT16 + name: "endpoint_id" + range { + min: 1 + max: 63999 + } + } + field { + type: UINT16 + name: "device_count" + label { + value: 0 + label: "Incomplete" + } + label { + value: 65535 + label: "Unknown" + } + range { + min: 0 + max: 65535 + } + } + field { + type: UINT8 + name: "discovery_state" + label { + value: 0 + label: "Incomplete" + } + label { + value: 1 + label: "Incremental" + } + label { + value: 2 + label: "Full" + } + label { + value: 4 + label: "Completed" + } + range { + min: 0 + max: 2 + } + range { + min: 4 + max: 4 + } + range { + min: 128 + max: 223 + } + } + } + get_sub_device_range: ROOT_DEVICE + set_request { + field { + type: UINT16 + name: "endpoint_id" + label { + value: 65535 + label: "All Endpoints" + } + range { + min: 1 + max: 63999 + } + range { + min: 65535 + max: 65535 + } + } + field { + type: UINT8 + name: "discovery_state" + label { + value: 1 + label: "Incremental" + } + label { + value: 2 + label: "Full" + } + label { + value: 4 + label: "Stop" + } + range { + min: 1 + max: 2 + } + range { + min: 4 + max: 4 + } + range { + min: 128 + max: 223 + } + } + } + set_response { + field { + type: UINT16 + name: "endpoint_id" + label { + value: 65535 + label: "All Endpoints" + } + range { + min: 1 + max: 63999 + } + range { + min: 65535 + max: 65535 + } + } + } + set_sub_device_range: ROOT_DEVICE +} +pid { + name: "BACKGROUND_DISCOVERY" + value: 2312 + get_request { + field { + type: UINT16 + name: "endpoint_id" + range { + min: 1 + max: 63999 + } + } + } + get_response { + field { + type: UINT16 + name: "endpoint_id" + range { + min: 1 + max: 63999 + } + } + field { + type: BOOL + name: "background_discovery" + } + } + get_sub_device_range: ROOT_DEVICE + set_request { + field { + type: UINT16 + name: "endpoint_id" + label { + value: 65535 + label: "All Endpoints" + } + range { + min: 1 + max: 63999 + } + range { + min: 65535 + max: 65535 + } + } + field { + type: BOOL + name: "background_discovery" + } + } + set_response { + field { + type: UINT16 + name: "endpoint_id" + label { + value: 65535 + label: "All Endpoints" + } + range { + min: 1 + max: 63999 + } + range { + min: 65535 + max: 65535 + } + } + } + set_sub_device_range: ROOT_DEVICE +} +pid { + name: "ENDPOINT_TIMING" + value: 2313 + get_request { + field { + type: UINT16 + name: "endpoint_id" + range { + min: 1 + max: 63999 + } + } + } + get_response { + field { + type: UINT16 + name: "endpoint_id" + range { + min: 1 + max: 63999 + } + } + field { + type: UINT8 + name: "current_setting" + range { + min: 1 + max: 255 + } + } + field { + type: UINT8 + name: "number_of_settings" + } + } + get_sub_device_range: ROOT_DEVICE + set_request { + field { + type: UINT16 + name: "endpoint_id" + label { + value: 65535 + label: "All Endpoints" + } + range { + min: 1 + max: 63999 + } + range { + min: 65535 + max: 65535 + } + } + field { + type: UINT8 + name: "timing_setting" + range { + min: 1 + max: 255 + } + } + } + set_response { + field { + type: UINT16 + name: "endpoint_id" + label { + value: 65535 + label: "All Endpoints" + } + range { + min: 1 + max: 63999 + } + range { + min: 65535 + max: 65535 + } + } + } + set_sub_device_range: ROOT_DEVICE +} +pid { + name: "ENDPOINT_TIMING_DESCRIPTION" + value: 2314 + get_request { + field { + type: UINT8 + name: "timing_setting" + range { + min: 1 + max: 255 + } + } + } + get_response { + field { + type: UINT8 + name: "timing_setting" + range { + min: 1 + max: 255 + } + } + field { + type: STRING + name: "description" + max_size: 32 + } + } + get_sub_device_range: ROOT_DEVICE +} +pid { + name: "ENDPOINT_RESPONDERS" + value: 2315 + get_request { + field { + type: UINT16 + name: "endpoint_id" + range { + min: 1 + max: 63999 + } + } + } + get_response { + field { + type: UINT16 + name: "endpoint_id" + range { + min: 1 + max: 63999 + } + } + field { + type: UINT32 + name: "list_change_number" + } + field { + type: GROUP + name: "uids" + field { + type: UID + name: "uid" + } + } + } + get_sub_device_range: ROOT_DEVICE +} +pid { + name: "ENDPOINT_RESPONDER_LIST_CHANGE" + value: 2316 + get_request { + field { + type: UINT16 + name: "endpoint_id" + range { + min: 1 + max: 63999 + } + } + } + get_response { + field { + type: UINT16 + name: "endpoint_id" + range { + min: 1 + max: 63999 + } + } + field { + type: UINT32 + name: "list_change_number" + } + } + get_sub_device_range: ROOT_DEVICE +} +pid { + name: "BINDING_CONTROL_FIELDS" + value: 2317 + get_request { + field { + type: UINT16 + name: "endpoint_id" + range { + min: 1 + max: 63999 + } + } + field { + type: UID + name: "uid" + } + } + get_response { + field { + type: UINT16 + name: "endpoint_id" + range { + min: 1 + max: 63999 + } + } + field { + type: UID + name: "uid" + } + field { + type: UINT16 + name: "control_bits" + } + field { + type: UID + name: "binding_uid" + label { + value: 0 + label: "No Information Present" + } + } + } + get_sub_device_range: ROOT_DEVICE +} +pid { + name: "BACKGROUND_QUEUED_STATUS_POLICY" + value: 2318 + get_request { + } + get_response { + field { + type: UINT8 + name: "current_policy_setting" + label { + value: 0 + label: "None" + } + label { + value: 1 + label: "Advisory" + } + label { + value: 2 + label: "Warning" + } + label { + value: 3 + label: "Error" + } + range { + min: 0 + max: 255 + } + } + field { + type: UINT8 + name: "num_policy_settings" + } + } + get_sub_device_range: ROOT_OR_SUBDEVICE + set_request { + field { + type: UINT8 + name: "policy" + label { + value: 0 + label: "None" + } + label { + value: 1 + label: "Advisory" + } + label { + value: 2 + label: "Warning" + } + label { + value: 3 + label: "Error" + } + range { + min: 0 + max: 255 + } + } + } + set_response { + } + set_sub_device_range: ROOT_OR_ALL_SUBDEVICE +} +pid { + name: "BACKGROUND_QUEUED_STATUS_POLICY_DESCRIPTION" + value: 2319 + get_request { + field { + type: UINT8 + name: "policy_setting" + label { + value: 0 + label: "None" + } + label { + value: 1 + label: "Advisory" + } + label { + value: 2 + label: "Warning" + } + label { + value: 3 + label: "Error" + } + range { + min: 0 + max: 255 + } + } + } + get_response { + field { + type: UINT8 + name: "policy_setting" + } + field { + type: STRING + name: "description" + max_size: 32 + } + } + get_sub_device_range: ROOT_OR_SUBDEVICE +} pid { name: "IDENTIFY_DEVICE" value: 4096 @@ -4548,4 +5809,4 @@ pid { } set_sub_device_range: ROOT_OR_ALL_SUBDEVICE } -version: 1521301591 +version: 1582652719 From 2aeaac8f33f3e75eb55e02a2aaa862c899474519 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Wed, 26 Feb 2020 08:43:43 +0000 Subject: [PATCH 42/71] Add initial negative E1.33/E1.37-7 tests. Need to add categories still --- tools/rdm/TestDefinitions.py | 770 +++++++++++++++++++++++++++++++++++ 1 file changed, 770 insertions(+) diff --git a/tools/rdm/TestDefinitions.py b/tools/rdm/TestDefinitions.py index 8071311099..149f75d0e9 100644 --- a/tools/rdm/TestDefinitions.py +++ b/tools/rdm/TestDefinitions.py @@ -7851,6 +7851,776 @@ class SetInterfaceHardwareAddressType1WithData( PID = 'INTERFACE_HARDWARE_ADDRESS_TYPE1' +# E1.33/E1.37-7 PIDS +# ============================================================================= + +class AllSubDevicesGetSearchDomain(TestMixins.AllSubDevicesGetMixin, + OptionalParameterTestFixture): + """Send a get SEARCH_DOMAIN to ALL_SUB_DEVICES.""" + PID = 'SEARCH_DOMAIN' + + +# class GetSearchDomain(TestMixins., +# OptionalParameterTestFixture): +# CATEGORY = TestCategory. +# PID = 'SEARCH_DOMAIN' +# TODO(peter): Test get + + +class GetSearchDomainWithData(TestMixins.GetWithDataMixin, + OptionalParameterTestFixture): + """GET SEARCH_DOMAIN with data.""" + PID = 'SEARCH_DOMAIN' + + +# class SetSearchDomain(TestMixins., +# OptionalParameterTestFixture): +# CATEGORY = TestCategory. +# PID = 'SEARCH_DOMAIN' +# TODO(peter): Test set + + +class SetSearchDomainWithNoData(TestMixins.SetWithNoDataMixin, + OptionalParameterTestFixture): + """Set SEARCH_DOMAIN command with no data.""" + PID = 'SEARCH_DOMAIN' + + +class SetSearchDomainWithExtraData(TestMixins.SetWithDataMixin, + OptionalParameterTestFixture): + """Send a SET SEARCH_DOMAIN command with extra data.""" + PID = 'SEARCH_DOMAIN' + + +class AllSubDevicesGetBrokerStatus(TestMixins.AllSubDevicesGetMixin, + OptionalParameterTestFixture): + """Send a get BROKER_STATUS to ALL_SUB_DEVICES.""" + PID = 'BROKER_STATUS' + + +# class GetBrokerStatus(TestMixins., +# OptionalParameterTestFixture): +# CATEGORY = TestCategory. +# PID = 'BROKER_STATUS' +# TODO(peter): Test get + + +class GetBrokerStatusWithData(TestMixins.GetWithDataMixin, + OptionalParameterTestFixture): + """GET BROKER_STATUS with data.""" + PID = 'BROKER_STATUS' + + +# class SetBrokerStatus(TestMixins., +# OptionalParameterTestFixture): +# CATEGORY = TestCategory. +# PID = 'BROKER_STATUS' +# TODO(peter): Test set + + +class SetBrokerStatusWithNoData(TestMixins.SetWithNoDataMixin, + OptionalParameterTestFixture): + """Set BROKER_STATUS command with no data.""" + PID = 'BROKER_STATUS' + + +class SetBrokerStatusWithExtraData(TestMixins.SetWithDataMixin, + OptionalParameterTestFixture): + """Send a SET BROKER_STATUS command with extra data.""" + PID = 'BROKER_STATUS' + + +class AllSubDevicesGetEndpointMode(TestMixins.AllSubDevicesGetMixin, + OptionalParameterTestFixture): + """Send a get ENDPOINT_MODE to ALL_SUB_DEVICES.""" + PID = 'ENDPOINT_MODE' + DATA = [0x0001] + + +# class GetEndpointMode(TestMixins., +# OptionalParameterTestFixture): +# CATEGORY = TestCategory. +# PID = 'ENDPOINT_MODE' +# TODO(peter): Test get + + +class GetZeroEndpointMode(TestMixins.GetZeroUInt16Mixin, + OptionalParameterTestFixture): + """GET ENDPOINT_MODE for endpoint id 0.""" + PID = 'ENDPOINT_MODE' + + +class GetEndpointModeWithNoData(TestMixins.GetWithNoDataMixin, + OptionalParameterTestFixture): + """GET ENDPOINT_MODE with no argument given.""" + PID = 'ENDPOINT_MODE' + + +class GetEndpointModeWithExtraData(TestMixins.GetWithDataMixin, + OptionalParameterTestFixture): + """GET ENDPOINT_MODE with more than 2 bytes of data.""" + PID = 'ENDPOINT_MODE' + + +# class SetEndpointMode(TestMixins., +# OptionalParameterTestFixture): +# CATEGORY = TestCategory. +# PID = 'ENDPOINT_MODE' +# TODO(peter): Test set + + +# class SetZeroEndpointMode(TestMixins.SetZero, +# OptionalParameterTestFixture): +# """SET ENDPOINT_MODE for endpoint id 0.""" +# PID = 'ENDPOINT_MODE' +# TODO(peter): Test set zero + + +class SetEndpointModeWithNoData(TestMixins.SetWithNoDataMixin, + OptionalParameterTestFixture): + """Set ENDPOINT_MODE command with no data.""" + PID = 'ENDPOINT_MODE' + + +class SetEndpointModeWithExtraData(TestMixins.SetWithDataMixin, + OptionalParameterTestFixture): + """Send a SET ENDPOINT_MODE command with extra data.""" + PID = 'ENDPOINT_MODE' + DATA = 'foobar' + + +class AllSubDevicesGetEndpointLabel(TestMixins.AllSubDevicesGetMixin, + OptionalParameterTestFixture): + """Send a get ENDPOINT_LABEL to ALL_SUB_DEVICES.""" + PID = 'ENDPOINT_LABEL' + DATA = [0x0001] + + +# class GetEndpointLabel(TestMixins., +# OptionalParameterTestFixture): +# CATEGORY = TestCategory. +# PID = 'ENDPOINT_LABEL' +# TODO(peter): Test get + + +class GetZeroEndpointLabel(TestMixins.GetZeroUInt16Mixin, + OptionalParameterTestFixture): + """GET ENDPOINT_LABEL for endpoint id 0.""" + PID = 'ENDPOINT_LABEL' + + +class GetEndpointLabelWithNoData(TestMixins.GetWithNoDataMixin, + OptionalParameterTestFixture): + """GET ENDPOINT_LABEL with no argument given.""" + PID = 'ENDPOINT_LABEL' + + +class GetEndpointLabelWithExtraData(TestMixins.GetWithDataMixin, + OptionalParameterTestFixture): + """GET ENDPOINT_LABEL with more than 2 bytes of data.""" + PID = 'ENDPOINT_LABEL' + + +# class SetEndpointLabel(TestMixins., +# OptionalParameterTestFixture): +# CATEGORY = TestCategory. +# PID = 'ENDPOINT_LABEL' +# TODO(peter): Test set + + +# class SetZeroEndpointLabel(TestMixins.SetZero, +# OptionalParameterTestFixture): +# """SET ENDPOINT_LABEL for endpoint id 0.""" +# PID = 'ENDPOINT_LABEL' +# TODO(peter): Test set zero + + +class SetEndpointLabelWithNoData(TestMixins.SetWithNoDataMixin, + OptionalParameterTestFixture): + """Set ENDPOINT_LABEL command with no data.""" + PID = 'ENDPOINT_LABEL' + + +class SetEndpointLabelWithExtraData(TestMixins.SetWithDataMixin, + OptionalParameterTestFixture): + """Send a SET ENDPOINT_LABEL command with extra data.""" + PID = 'ENDPOINT_LABEL' + + +class AllSubDevicesGetEndpointTiming(TestMixins.AllSubDevicesGetMixin, + OptionalParameterTestFixture): + """Send a get ENDPOINT_TIMING to ALL_SUB_DEVICES.""" + PID = 'ENDPOINT_TIMING' + DATA = [0x0001] + + +# class GetEndpointTiming(TestMixins., +# OptionalParameterTestFixture): +# CATEGORY = TestCategory. +# PID = 'ENDPOINT_TIMING' +# TODO(peter): Test get + + +class GetZeroEndpointTiming(TestMixins.GetZeroUInt16Mixin, + OptionalParameterTestFixture): + """GET ENDPOINT_TIMING for endpoint id 0.""" + PID = 'ENDPOINT_TIMING' + + +class GetEndpointTimingWithNoData(TestMixins.GetWithNoDataMixin, + OptionalParameterTestFixture): + """GET ENDPOINT_TIMING with no argument given.""" + PID = 'ENDPOINT_TIMING' + + +class GetEndpointTimingWithExtraData(TestMixins.GetWithDataMixin, + OptionalParameterTestFixture): + """GET ENDPOINT_TIMING with more than 2 bytes of data.""" + PID = 'ENDPOINT_TIMING' + + +# class SetEndpointTiming(TestMixins., +# OptionalParameterTestFixture): +# CATEGORY = TestCategory. +# PID = 'ENDPOINT_TIMING' +# TODO(peter): Test set + + +# class SetZeroEndpointTiming(TestMixins.SetZero, +# OptionalParameterTestFixture): +# """SET ENDPOINT_TIMING for endpoint id 0.""" +# PID = 'ENDPOINT_TIMING' +# TODO(peter): Test set zero + + +class SetEndpointTimingWithNoData(TestMixins.SetWithNoDataMixin, + OptionalParameterTestFixture): + """Set ENDPOINT_TIMING command with no data.""" + PID = 'ENDPOINT_TIMING' + + +class SetEndpointTimingWithExtraData(TestMixins.SetWithDataMixin, + OptionalParameterTestFixture): + """Send a SET ENDPOINT_TIMING command with extra data.""" + PID = 'ENDPOINT_TIMING' + DATA = 'foobar' + + +class AllSubDevicesGetEndpointTimingDescription( + TestMixins.AllSubDevicesGetMixin, + OptionalParameterTestFixture): + """Send a get ENDPOINT_TIMING_DESCRIPTION to ALL_SUB_DEVICES.""" + PID = 'ENDPOINT_TIMING_DESCRIPTION' + DATA = [0x01] + + +# class GetEndpointTimingDescription(TestMixins., +# OptionalParameterTestFixture): +# CATEGORY = TestCategory. +# PID = 'ENDPOINT_TIMING_DESCRIPTION' +# TODO(peter): Test get + + +class GetZeroEndpointTimingDescription(TestMixins.GetZeroUInt8Mixin, + OptionalParameterTestFixture): + """GET ENDPOINT_TIMING_DESCRIPTION for timing setting 0.""" + PID = 'ENDPOINT_TIMING_DESCRIPTION' + + +class GetEndpointTimingDescriptionWithNoData(TestMixins.GetWithNoDataMixin, + OptionalParameterTestFixture): + """GET ENDPOINT_TIMING_DESCRIPTION with no argument given.""" + PID = 'ENDPOINT_TIMING_DESCRIPTION' + + +class GetEndpointTimingDescriptionWithExtraData(TestMixins.GetWithDataMixin, + OptionalParameterTestFixture): + """GET ENDPOINT_TIMING_DESCRIPTION with more than 1 byte of data.""" + PID = 'ENDPOINT_TIMING_DESCRIPTION' + + +class SetEndpointTimingDescription(TestMixins.UnsupportedSetMixin, + OptionalParameterTestFixture): + """Attempt to SET ENDPOINT_TIMING_DESCRIPTION.""" + PID = 'ENDPOINT_TIMING_DESCRIPTION' + + +class SetEndpointTimingDescriptionWithData( + TestMixins.UnsupportedSetWithDataMixin, + OptionalParameterTestFixture): + """Attempt to SET ENDPOINT_TIMING_DESCRIPTION with data.""" + PID = 'ENDPOINT_TIMING_DESCRIPTION' + + +class AllSubDevicesGetEndpointResponders(TestMixins.AllSubDevicesGetMixin, + OptionalParameterTestFixture): + """Send a get ENDPOINT_RESPONDERS to ALL_SUB_DEVICES.""" + PID = 'ENDPOINT_RESPONDERS' + DATA = [0x0001] + + +# class GetEndpointResponders(TestMixins., +# OptionalParameterTestFixture): +# CATEGORY = TestCategory. +# PID = 'ENDPOINT_RESPONDERS' +# TODO(peter): Test get + + +class GetZeroEndpointResponders(TestMixins.GetZeroUInt16Mixin, + OptionalParameterTestFixture): + """GET ENDPOINT_RESPONDERS for endpoint id 0.""" + PID = 'ENDPOINT_RESPONDERS' + + +class GetEndpointRespondersWithNoData(TestMixins.GetWithNoDataMixin, + OptionalParameterTestFixture): + """GET ENDPOINT_RESPONDERS with no argument given.""" + PID = 'ENDPOINT_RESPONDERS' + + +class GetEndpointRespondersWithExtraData(TestMixins.GetWithDataMixin, + OptionalParameterTestFixture): + """GET ENDPOINT_RESPONDERS with more than 2 bytes of data.""" + PID = 'ENDPOINT_RESPONDERS' + + +class SetEndpointResponders(TestMixins.UnsupportedSetMixin, + OptionalParameterTestFixture): + """Attempt to SET ENDPOINT_RESPONDERS.""" + PID = 'ENDPOINT_RESPONDERS' + + +class SetEndpointRespondersWithData(TestMixins.UnsupportedSetWithDataMixin, + OptionalParameterTestFixture): + """Attempt to SET ENDPOINT_RESPONDERS with data.""" + PID = 'ENDPOINT_RESPONDERS' + + +class AllSubDevicesGetEndpointResponderListChange( + TestMixins.AllSubDevicesGetMixin, + OptionalParameterTestFixture): + """Send a get ENDPOINT_RESPONDER_LIST_CHANGE to ALL_SUB_DEVICES.""" + PID = 'ENDPOINT_RESPONDER_LIST_CHANGE' + DATA = [0x0001] + + +# class GetEndpointResponderListChange(TestMixins., +# OptionalParameterTestFixture): +# CATEGORY = TestCategory. +# PID = 'ENDPOINT_RESPONDER_LIST_CHANGE' +# TODO(peter): Test get + + +class GetZeroEndpointResponderListChange(TestMixins.GetZeroUInt16Mixin, + OptionalParameterTestFixture): + """GET ENDPOINT_RESPONDER_LIST_CHANGE for endpoint id 0.""" + PID = 'ENDPOINT_RESPONDER_LIST_CHANGE' + + +class GetEndpointResponderListChangeWithNoData(TestMixins.GetWithNoDataMixin, + OptionalParameterTestFixture): + """GET ENDPOINT_RESPONDER_LIST_CHANGE with no argument given.""" + PID = 'ENDPOINT_RESPONDER_LIST_CHANGE' + + +class GetEndpointResponderListChangeWithExtraData(TestMixins.GetWithDataMixin, + OptionalParameterTestFixture): + """GET ENDPOINT_RESPONDER_LIST_CHANGE with more than 2 bytes of data.""" + PID = 'ENDPOINT_RESPONDER_LIST_CHANGE' + + +class SetEndpointResponderListChange(TestMixins.UnsupportedSetMixin, + OptionalParameterTestFixture): + """Attempt to SET ENDPOINT_RESPONDER_LIST_CHANGE.""" + PID = 'ENDPOINT_RESPONDER_LIST_CHANGE' + + +class SetEndpointResponderListChangeWithData( + TestMixins.UnsupportedSetWithDataMixin, + OptionalParameterTestFixture): + """Attempt to SET ENDPOINT_RESPONDER_LIST_CHANGE with data.""" + PID = 'ENDPOINT_RESPONDER_LIST_CHANGE' + + +class AllSubDevicesGetEndpointList(TestMixins.AllSubDevicesGetMixin, + OptionalParameterTestFixture): + """Send a get ENDPOINT_LIST to ALL_SUB_DEVICES.""" + PID = 'ENDPOINT_LIST' + + +# class GetEndpointList(TestMixins., +# OptionalParameterTestFixture): +# CATEGORY = TestCategory. +# PID = 'ENDPOINT_LIST' +# TODO(peter): Test get + + +class GetEndpointListWithData(TestMixins.GetWithDataMixin, + OptionalParameterTestFixture): + """GET ENDPOINT_LIST with data.""" + PID = 'ENDPOINT_LIST' + + +class SetEndpointList(TestMixins.UnsupportedSetMixin, + OptionalParameterTestFixture): + """Attempt to SET ENDPOINT_LIST.""" + PID = 'ENDPOINT_LIST' + + +class SetEndpointListWithData(TestMixins.UnsupportedSetWithDataMixin, + OptionalParameterTestFixture): + """Attempt to SET ENDPOINT_LIST with data.""" + PID = 'ENDPOINT_LIST' + + +class AllSubDevicesGetEndpointListChange(TestMixins.AllSubDevicesGetMixin, + OptionalParameterTestFixture): + """Send a get ENDPOINT_LIST_CHANGE to ALL_SUB_DEVICES.""" + PID = 'ENDPOINT_LIST_CHANGE' + + +# class GetEndpointListChange(TestMixins., +# OptionalParameterTestFixture): +# CATEGORY = TestCategory. +# PID = 'ENDPOINT_LIST_CHANGE' +# TODO(peter): Test get + + +class GetEndpointListChangeWithData(TestMixins.GetWithDataMixin, + OptionalParameterTestFixture): + """GET ENDPOINT_LIST_CHANGE with data.""" + PID = 'ENDPOINT_LIST_CHANGE' + + +class SetEndpointListChange(TestMixins.UnsupportedSetMixin, + OptionalParameterTestFixture): + """Attempt to SET ENDPOINT_LIST_CHANGE.""" + PID = 'ENDPOINT_LIST_CHANGE' + + +class SetEndpointListChangeWithData(TestMixins.UnsupportedSetWithDataMixin, + OptionalParameterTestFixture): + """Attempt to SET ENDPOINT_LIST_CHANGE with data.""" + PID = 'ENDPOINT_LIST_CHANGE' + + +class AllSubDevicesGetEndpointToUniverse(TestMixins.AllSubDevicesGetMixin, + OptionalParameterTestFixture): + """Send a get ENDPOINT_TO_UNIVERSE to ALL_SUB_DEVICES.""" + PID = 'ENDPOINT_TO_UNIVERSE' + DATA = [0x0001] + + +# class GetEndpointToUniverse(TestMixins., +# OptionalParameterTestFixture): +# CATEGORY = TestCategory. +# PID = 'ENDPOINT_TO_UNIVERSE' +# TODO(peter): Test get + + +class GetZeroEndpointToUniverse(TestMixins.GetZeroUInt16Mixin, + OptionalParameterTestFixture): + """GET ENDPOINT_TO_UNIVERSE for endpoint id 0.""" + PID = 'ENDPOINT_TO_UNIVERSE' + + +class GetEndpointToUniverseWithNoData(TestMixins.GetWithNoDataMixin, + OptionalParameterTestFixture): + """GET ENDPOINT_TO_UNIVERSE with no argument given.""" + PID = 'ENDPOINT_TO_UNIVERSE' + + +class GetEndpointToUniverseWithExtraData(TestMixins.GetWithDataMixin, + OptionalParameterTestFixture): + """GET ENDPOINT_TO_UNIVERSE with more than 2 bytes of data.""" + PID = 'ENDPOINT_TO_UNIVERSE' + + +# class SetEndpointToUniverse(TestMixins., +# OptionalParameterTestFixture): +# CATEGORY = TestCategory. +# PID = 'ENDPOINT_TO_UNIVERSE' +# TODO(peter): Test set + + +# class SetZeroEndpointToUniverse(TestMixins.SetZero, +# OptionalParameterTestFixture): +# """SET ENDPOINT_TO_UNIVERSE for endpoint id 0.""" +# PID = 'ENDPOINT_TO_UNIVERSE' +# TODO(peter): Test set zero + + +class SetEndpointToUniverseWithNoData(TestMixins.SetWithNoDataMixin, + OptionalParameterTestFixture): + """Set ENDPOINT_TO_UNIVERSE command with no data.""" + PID = 'ENDPOINT_TO_UNIVERSE' + + +class SetEndpointToUniverseWithExtraData(TestMixins.SetWithDataMixin, + OptionalParameterTestFixture): + """Send a SET ENDPOINT_TO_UNIVERSE command with extra data.""" + PID = 'ENDPOINT_TO_UNIVERSE' + DATA = 'foobar' + + +class AllSubDevicesGetRdmTrafficEnable(TestMixins.AllSubDevicesGetMixin, + OptionalParameterTestFixture): + """Send a get RDM_TRAFFIC_ENABLE to ALL_SUB_DEVICES.""" + PID = 'RDM_TRAFFIC_ENABLE' + DATA = [0x0001] + + +# class GetRdmTrafficEnable(TestMixins., +# OptionalParameterTestFixture): +# CATEGORY = TestCategory. +# PID = 'RDM_TRAFFIC_ENABLE' +# TODO(peter): Test get + + +class GetZeroRdmTrafficEnable(TestMixins.GetZeroUInt16Mixin, + OptionalParameterTestFixture): + """GET RDM_TRAFFIC_ENABLE for endpoint id 0.""" + PID = 'RDM_TRAFFIC_ENABLE' + + +class GetRdmTrafficEnableWithNoData(TestMixins.GetWithNoDataMixin, + OptionalParameterTestFixture): + """GET RDM_TRAFFIC_ENABLE with no argument given.""" + PID = 'RDM_TRAFFIC_ENABLE' + + +class GetRdmTrafficEnableWithExtraData(TestMixins.GetWithDataMixin, + OptionalParameterTestFixture): + """GET RDM_TRAFFIC_ENABLE with more than 2 bytes of data.""" + PID = 'RDM_TRAFFIC_ENABLE' + + +# class SetRdmTrafficEnable(TestMixins., +# OptionalParameterTestFixture): +# CATEGORY = TestCategory. +# PID = 'RDM_TRAFFIC_ENABLE' +# TODO(peter): Test set + + +# class SetZeroRdmTrafficEnable(TestMixins.SetZero, +# OptionalParameterTestFixture): +# """SET RDM_TRAFFIC_ENABLE for endpoint id 0.""" +# PID = 'RDM_TRAFFIC_ENABLE' +# TODO(peter): Test set zero + + +class SetRdmTrafficEnableWithNoData(TestMixins.SetWithNoDataMixin, + OptionalParameterTestFixture): + """Set RDM_TRAFFIC_ENABLE command with no data.""" + PID = 'RDM_TRAFFIC_ENABLE' + + +class SetRdmTrafficEnableWithExtraData(TestMixins.SetWithDataMixin, + OptionalParameterTestFixture): + """Send a SET RDM_TRAFFIC_ENABLE command with extra data.""" + PID = 'RDM_TRAFFIC_ENABLE' + DATA = 'foobar' + + +class AllSubDevicesGetDiscoveryState(TestMixins.AllSubDevicesGetMixin, + OptionalParameterTestFixture): + """Send a get DISCOVERY_STATE to ALL_SUB_DEVICES.""" + PID = 'DISCOVERY_STATE' + DATA = [0x0001] + + +# class GetDiscoveryState(TestMixins., +# OptionalParameterTestFixture): +# CATEGORY = TestCategory. +# PID = 'DISCOVERY_STATE' +# TODO(peter): Test get + + +class GetZeroDiscoveryState(TestMixins.GetZeroUInt16Mixin, + OptionalParameterTestFixture): + """GET DISCOVERY_STATE for endpoint id 0.""" + PID = 'DISCOVERY_STATE' + + +class GetDiscoveryStateWithNoData(TestMixins.GetWithNoDataMixin, + OptionalParameterTestFixture): + """GET DISCOVERY_STATE with no argument given.""" + PID = 'DISCOVERY_STATE' + + +class GetDiscoveryStateWithExtraData(TestMixins.GetWithDataMixin, + OptionalParameterTestFixture): + """GET DISCOVERY_STATE with more than 2 bytes of data.""" + PID = 'DISCOVERY_STATE' + + +# class SetDiscoveryState(TestMixins., +# OptionalParameterTestFixture): +# CATEGORY = TestCategory. +# PID = 'DISCOVERY_STATE' +# TODO(peter): Test set + + +# class SetZeroDiscoveryState(TestMixins.SetZero, +# OptionalParameterTestFixture): +# """SET DISCOVERY_STATE for endpoint id 0.""" +# PID = 'DISCOVERY_STATE' +# TODO(peter): Test set zero + + +class SetDiscoveryStateWithNoData(TestMixins.SetWithNoDataMixin, + OptionalParameterTestFixture): + """Set DISCOVERY_STATE command with no data.""" + PID = 'DISCOVERY_STATE' + + +class SetDiscoveryStateWithExtraData(TestMixins.SetWithDataMixin, + OptionalParameterTestFixture): + """Send a SET DISCOVERY_STATE command with extra data.""" + PID = 'DISCOVERY_STATE' + DATA = 'foobar' + + +class AllSubDevicesGetBackgroundDiscovery(TestMixins.AllSubDevicesGetMixin, + OptionalParameterTestFixture): + """Send a get BACKGROUND_DISCOVERY to ALL_SUB_DEVICES.""" + PID = 'BACKGROUND_DISCOVERY' + DATA = [0x0001] + + +# class GetBackgroundDiscovery(TestMixins., +# OptionalParameterTestFixture): +# CATEGORY = TestCategory. +# PID = 'BACKGROUND_DISCOVERY' +# TODO(peter): Test get + + +class GetZeroBackgroundDiscovery(TestMixins.GetZeroUInt16Mixin, + OptionalParameterTestFixture): + """GET BACKGROUND_DISCOVERY for endpoint id 0.""" + PID = 'BACKGROUND_DISCOVERY' + + +class GetBackgroundDiscoveryWithNoData(TestMixins.GetWithNoDataMixin, + OptionalParameterTestFixture): + """GET BACKGROUND_DISCOVERY with no argument given.""" + PID = 'BACKGROUND_DISCOVERY' + + +class GetBackgroundDiscoveryWithExtraData(TestMixins.GetWithDataMixin, + OptionalParameterTestFixture): + """GET BACKGROUND_DISCOVERY with more than 2 bytes of data.""" + PID = 'BACKGROUND_DISCOVERY' + + +# class SetBackgroundDiscovery(TestMixins., +# OptionalParameterTestFixture): +# CATEGORY = TestCategory. +# PID = 'BACKGROUND_DISCOVERY' +# TODO(peter): Test set + + +# class SetZeroBackgroundDiscovery(TestMixins.SetZero, +# OptionalParameterTestFixture): +# """SET BACKGROUND_DISCOVERY for endpoint id 0.""" +# PID = 'BACKGROUND_DISCOVERY' +# TODO(peter): Test set zero + + +class SetBackgroundDiscoveryWithNoData(TestMixins.SetWithNoDataMixin, + OptionalParameterTestFixture): + """Set BACKGROUND_DISCOVERY command with no data.""" + PID = 'BACKGROUND_DISCOVERY' + + +class SetBackgroundDiscoveryWithExtraData(TestMixins.SetWithDataMixin, + OptionalParameterTestFixture): + """Send a SET BACKGROUND_DISCOVERY command with extra data.""" + PID = 'BACKGROUND_DISCOVERY' + DATA = 'foobar' + + +class AllSubDevicesGetBackgroundQueuedStatusPolicy( + TestMixins.AllSubDevicesGetMixin, + OptionalParameterTestFixture): + """Send a get BACKGROUND_QUEUED_STATUS_POLICY to ALL_SUB_DEVICES.""" + PID = 'BACKGROUND_QUEUED_STATUS_POLICY' + + +# class GetBackgroundQueuedStatusPolicy(TestMixins., +# OptionalParameterTestFixture): +# CATEGORY = TestCategory. +# PID = 'BACKGROUND_QUEUED_STATUS_POLICY' +# TODO(peter): Test get + + +class GetBackgroundQueuedStatusPolicyWithData(TestMixins.GetWithDataMixin, + OptionalParameterTestFixture): + """GET BACKGROUND_QUEUED_STATUS_POLICY with data.""" + PID = 'BACKGROUND_QUEUED_STATUS_POLICY' + + +# class SetBackgroundQueuedStatusPolicy(TestMixins., +# OptionalParameterTestFixture): +# CATEGORY = TestCategory. +# PID = 'BACKGROUND_QUEUED_STATUS_POLICY' +# TODO(peter): Test set + + +class SetBackgroundQueuedStatusPolicyWithNoData(TestMixins.SetWithNoDataMixin, + OptionalParameterTestFixture): + """Set BACKGROUND_QUEUED_STATUS_POLICY command with no data.""" + PID = 'BACKGROUND_QUEUED_STATUS_POLICY' + + +class SetBackgroundQueuedStatusPolicyWithExtraData(TestMixins.SetWithDataMixin, + OptionalParameterTestFixture): + """Send a SET BACKGROUND_QUEUED_STATUS_POLICY command with extra data.""" + PID = 'BACKGROUND_QUEUED_STATUS_POLICY' + + +class AllSubDevicesGetBackgroundQueuedStatusPolicyDescription( + TestMixins.AllSubDevicesGetMixin, + OptionalParameterTestFixture): + """Send a get BACKGROUND_QUEUED_STATUS_POLICY_DESCRIPTION to ALL_SUB_DEVICES.""" + PID = 'BACKGROUND_QUEUED_STATUS_POLICY_DESCRIPTION' + DATA = [0x00] + + +# class GetBackgroundQueuedStatusPolicyDescription(TestMixins., +# OptionalParameterTestFixture): +# CATEGORY = TestCategory. +# PID = 'BACKGROUND_QUEUED_STATUS_POLICY_DESCRIPTION' +# TODO(peter): Test get + + +class GetBackgroundQueuedStatusPolicyDescriptionWithNoData( + TestMixins.GetWithNoDataMixin, + OptionalParameterTestFixture): + """GET BACKGROUND_QUEUED_STATUS_POLICY_DESCRIPTION with no argument given.""" + PID = 'BACKGROUND_QUEUED_STATUS_POLICY_DESCRIPTION' + + +class GetBackgroundQueuedStatusPolicyDescriptionWithExtraData( + TestMixins.GetWithDataMixin, + OptionalParameterTestFixture): + """GET BACKGROUND_QUEUED_STATUS_POLICY_DESCRIPTION with more than 1 byte of data.""" + PID = 'BACKGROUND_QUEUED_STATUS_POLICY_DESCRIPTION' + + +class SetBackgroundQueuedStatusPolicyDescription(TestMixins.UnsupportedSetMixin, + OptionalParameterTestFixture): + """Attempt to SET BACKGROUND_QUEUED_STATUS_POLICY_DESCRIPTION.""" + PID = 'BACKGROUND_QUEUED_STATUS_POLICY_DESCRIPTION' + + +class SetBackgroundQueuedStatusPolicyDescriptionWithData( + TestMixins.UnsupportedSetWithDataMixin, + OptionalParameterTestFixture): + """Attempt to SET BACKGROUND_QUEUED_STATUS_POLICY_DESCRIPTION with data.""" + PID = 'BACKGROUND_QUEUED_STATUS_POLICY_DESCRIPTION' + + # Cross check the control fields with various other properties # ----------------------------------------------------------------------------- class SubDeviceControlField(TestFixture): From 68703616d688d41d0f0a6d43e048aa5b806051c7 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Wed, 26 Feb 2020 11:48:27 +0000 Subject: [PATCH 43/71] Add the ability to override the expected NACK for GetZeroMixin --- tools/rdm/TestMixins.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tools/rdm/TestMixins.py b/tools/rdm/TestMixins.py index 3145c95bc1..58c0dc13c8 100644 --- a/tools/rdm/TestMixins.py +++ b/tools/rdm/TestMixins.py @@ -1021,16 +1021,27 @@ def ResetState(self): class GetZeroMixin(ResponderTestFixture): - """Send a get to index 0, expect NR_DATA_OUT_OF_RANGE""" + """Send a get to index 0, normally expect NR_DATA_OUT_OF_RANGE + + If OVERRIDE_NACKS is non-empty, this overrides NR_DATA_OUT_OF_RANGE and adds + a custom NackGetResult to the list of allowed results for each entry. + """ CATEGORY = TestCategory.ERROR_CONDITIONS DATA = None + OVERRIDE_NACKS = [] def Test(self): if self.DATA is None: self.SetBroken('No DATA given for %s' % self.__class__.__name__) return - self.AddIfGetSupported(self.NackGetResult(RDMNack.NR_DATA_OUT_OF_RANGE)) + results = [] + if self.OVERRIDE_NACKS: + for nack in self.OVERRIDE_NACKS: + results.append(self.NackGetResult(nack)) + else: + results.append(self.NackGetResult(RDMNack.NR_DATA_OUT_OF_RANGE)) + self.AddIfGetSupported(results) self.SendRawGet(ROOT_DEVICE, self.pid, self.DATA) From f67491fa6b7a6403788f1bec94e8c03c4d40637d Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Wed, 26 Feb 2020 11:48:54 +0000 Subject: [PATCH 44/71] Correct the expected NACK for some endpoint number checks --- tools/rdm/TestDefinitions.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/rdm/TestDefinitions.py b/tools/rdm/TestDefinitions.py index 149f75d0e9..db6ddce576 100644 --- a/tools/rdm/TestDefinitions.py +++ b/tools/rdm/TestDefinitions.py @@ -7948,6 +7948,7 @@ class GetZeroEndpointMode(TestMixins.GetZeroUInt16Mixin, OptionalParameterTestFixture): """GET ENDPOINT_MODE for endpoint id 0.""" PID = 'ENDPOINT_MODE' + OVERRIDE_NACKS = [RDMNack.NR_ENDPOINT_NUMBER_INVALID] class GetEndpointModeWithNoData(TestMixins.GetWithNoDataMixin, @@ -8007,6 +8008,7 @@ class GetZeroEndpointLabel(TestMixins.GetZeroUInt16Mixin, OptionalParameterTestFixture): """GET ENDPOINT_LABEL for endpoint id 0.""" PID = 'ENDPOINT_LABEL' + OVERRIDE_NACKS = [RDMNack.NR_ENDPOINT_NUMBER_INVALID] class GetEndpointLabelWithNoData(TestMixins.GetWithNoDataMixin, @@ -8065,6 +8067,7 @@ class GetZeroEndpointTiming(TestMixins.GetZeroUInt16Mixin, OptionalParameterTestFixture): """GET ENDPOINT_TIMING for endpoint id 0.""" PID = 'ENDPOINT_TIMING' + OVERRIDE_NACKS = [RDMNack.NR_ENDPOINT_NUMBER_INVALID] class GetEndpointTimingWithNoData(TestMixins.GetWithNoDataMixin, @@ -8170,6 +8173,7 @@ class GetZeroEndpointResponders(TestMixins.GetZeroUInt16Mixin, OptionalParameterTestFixture): """GET ENDPOINT_RESPONDERS for endpoint id 0.""" PID = 'ENDPOINT_RESPONDERS' + OVERRIDE_NACKS = [RDMNack.NR_ENDPOINT_NUMBER_INVALID] class GetEndpointRespondersWithNoData(TestMixins.GetWithNoDataMixin, @@ -8215,6 +8219,7 @@ class GetZeroEndpointResponderListChange(TestMixins.GetZeroUInt16Mixin, OptionalParameterTestFixture): """GET ENDPOINT_RESPONDER_LIST_CHANGE for endpoint id 0.""" PID = 'ENDPOINT_RESPONDER_LIST_CHANGE' + OVERRIDE_NACKS = [RDMNack.NR_ENDPOINT_NUMBER_INVALID] class GetEndpointResponderListChangeWithNoData(TestMixins.GetWithNoDataMixin, @@ -8322,6 +8327,7 @@ class GetZeroEndpointToUniverse(TestMixins.GetZeroUInt16Mixin, OptionalParameterTestFixture): """GET ENDPOINT_TO_UNIVERSE for endpoint id 0.""" PID = 'ENDPOINT_TO_UNIVERSE' + OVERRIDE_NACKS = [RDMNack.NR_ENDPOINT_NUMBER_INVALID] class GetEndpointToUniverseWithNoData(TestMixins.GetWithNoDataMixin, @@ -8381,6 +8387,7 @@ class GetZeroRdmTrafficEnable(TestMixins.GetZeroUInt16Mixin, OptionalParameterTestFixture): """GET RDM_TRAFFIC_ENABLE for endpoint id 0.""" PID = 'RDM_TRAFFIC_ENABLE' + OVERRIDE_NACKS = [RDMNack.NR_ENDPOINT_NUMBER_INVALID] class GetRdmTrafficEnableWithNoData(TestMixins.GetWithNoDataMixin, @@ -8440,6 +8447,7 @@ class GetZeroDiscoveryState(TestMixins.GetZeroUInt16Mixin, OptionalParameterTestFixture): """GET DISCOVERY_STATE for endpoint id 0.""" PID = 'DISCOVERY_STATE' + OVERRIDE_NACKS = [RDMNack.NR_ENDPOINT_NUMBER_INVALID] class GetDiscoveryStateWithNoData(TestMixins.GetWithNoDataMixin, @@ -8499,6 +8507,7 @@ class GetZeroBackgroundDiscovery(TestMixins.GetZeroUInt16Mixin, OptionalParameterTestFixture): """GET BACKGROUND_DISCOVERY for endpoint id 0.""" PID = 'BACKGROUND_DISCOVERY' + OVERRIDE_NACKS = [RDMNack.NR_ENDPOINT_NUMBER_INVALID] class GetBackgroundDiscoveryWithNoData(TestMixins.GetWithNoDataMixin, From e59b0289a7eead8fc440556b628829725693bc63 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Wed, 26 Feb 2020 18:04:40 +0000 Subject: [PATCH 45/71] Support loopback and selecting an interface --- tools/e133/llrp-manager.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/e133/llrp-manager.cpp b/tools/e133/llrp-manager.cpp index 4857919287..aa9f742277 100644 --- a/tools/e133/llrp-manager.cpp +++ b/tools/e133/llrp-manager.cpp @@ -96,11 +96,14 @@ using ola::rdm::UIDSet; DEFINE_string(manager_uid, "7a70:00000002", "The UID of the manager."); DEFINE_default_bool(set, false, "Send a set rather than a get."); +DEFINE_default_bool(allow_loopback, false, "Include the loopback interface."); +DEFINE_s_string(interface, i, "", + "The interface name (e.g. eth0) or IP address of the network " + "interface to use for LLRP messages."); auto_ptr picker( ola::network::InterfacePicker::NewPicker()); ola::network::Interface m_interface; -const std::string m_preferred_ip; ola::network::UDPSocket m_socket; uint8_t *m_recv_buffer; std::auto_ptr manager_uid; @@ -402,8 +405,9 @@ int main(int argc, char* argv[]) { } std::cout << "Bind!" << std::endl; + const std::string m_preferred_ip = FLAGS_interface; ola::network::InterfacePicker::Options options; - options.include_loopback = false; + options.include_loopback = FLAGS_allow_loopback; if (!picker->ChooseInterface(&m_interface, m_preferred_ip, options)) { OLA_INFO << "Failed to find an interface"; return false; From fd26efa54d1476fb45a01363ab45dc0bf7ae51ce Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Sat, 4 Mar 2023 07:37:00 +0000 Subject: [PATCH 46/71] Add some detail on how DMX-TRI error codes are done from its developer --- plugins/usbpro/DmxTriWidget.cpp | 3 +++ plugins/usbpro/DmxTriWidget.h | 2 ++ 2 files changed, 5 insertions(+) diff --git a/plugins/usbpro/DmxTriWidget.cpp b/plugins/usbpro/DmxTriWidget.cpp index e6fdefc6a3..d8b98461df 100644 --- a/plugins/usbpro/DmxTriWidget.cpp +++ b/plugins/usbpro/DmxTriWidget.cpp @@ -950,6 +950,9 @@ bool DmxTriWidgetImpl::TriToOlaReturnCode( /** * Convert a DMX-TRI return code to Nack reason code if appropriate + * + * On the widget, the RDM NACK code is currently bitwise or-ed with 0x20 to + * generate the error code */ bool DmxTriWidgetImpl::ReturnCodeToNackReason( uint8_t return_code, diff --git a/plugins/usbpro/DmxTriWidget.h b/plugins/usbpro/DmxTriWidget.h index 6ec0addb9d..1b9f28a346 100644 --- a/plugins/usbpro/DmxTriWidget.h +++ b/plugins/usbpro/DmxTriWidget.h @@ -201,6 +201,8 @@ class DmxTriWidgetImpl: public BaseUsbProWidget, EC_INVALID_IPV6_ADDRESS = 0x32, // this is a guess EC_INVALID_PORT = 0x33 // this is a guess } dmx_tri_error_codes; + // The RDM NACK code is currently bitwise or-ed with 0x20 to generate the + // error code // TODO(Peter): try and test the guessed values static const unsigned int DATA_OFFSET = 2; // first two bytes are CI & RC From 9d60884097e6ae5cedd05126a82f2fe382ae6c6e Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Sat, 4 Mar 2023 08:16:44 +0000 Subject: [PATCH 47/71] Improve some size calculations, only output SetWithNoData when actually required and improve how and when we set the DATA variable --- tools/rdm/list_rdm_tests.py | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/tools/rdm/list_rdm_tests.py b/tools/rdm/list_rdm_tests.py index 5ea5cdb590..1e4e386438 100755 --- a/tools/rdm/list_rdm_tests.py +++ b/tools/rdm/list_rdm_tests.py @@ -153,10 +153,14 @@ def GetWithExtraData(names, pid, pid_test_base_name, get_size): dummy_data = GenerateDummyData(get_size) if dummy_data is None: print((" #DATA = 'foo' # TODO(%s): Specify extra data if this isn't " - "enough") % (getpass.getuser())) + "enough. Ensure the first %d bytes are sane/valid.") % (getpass.getuser(), get_size)) elif dummy_data != 'foo': - # Doesn't match default - print(" DATA = '%s'" % (dummy_data)) + # Doesn't match default, explicitly set value + print((" DATA = '%s' # TODO(%s): Specify extra data if this isn't " + "enough. Ensure the first %d bytes are sane/valid.") % (dummy_data, getpass.getuser(), get_size)) + else: + print((" #DATA = '%s' # TODO(%s): Specify extra data if this isn't " + "enough. Ensure the first %d bytes are sane/valid.") % (dummy_data, getpass.getuser(), get_size)) print('') print('') @@ -272,10 +276,14 @@ def SetWithExtraData(names, pid, pid_test_base_name, set_size): dummy_data = GenerateDummyData(set_size) if dummy_data is None: print((" #DATA = 'foo' # TODO(%s): Specify extra data if this isn't " - "enough") % (getpass.getuser())) + "enough. Ensure the first %d bytes are sane/valid.") % (getpass.getuser(), set_size)) elif dummy_data != 'foo': - # Doesn't match default - print(" DATA = '%s'" % (dummy_data)) + # Doesn't match default, explicitly set value + print((" DATA = '%s' # TODO(%s): Specify extra data if this isn't " + "enough. Ensure the first %d bytes are sane/valid.") % (dummy_data, getpass.getuser(), set_size)) + else: + print((" #DATA = '%s' # TODO(%s): Specify extra data if this isn't " + "enough. Ensure the first %d bytes are sane/valid.") % (dummy_data, getpass.getuser(), set_size)) print('') print('') @@ -342,8 +350,11 @@ def main(): get_size = 0 if ((pid.RequestSupported(PidStore.RDM_GET)) and (pid.GetRequest(PidStore.RDM_GET).HasAtoms())): - get_size = pid.GetRequest(PidStore.RDM_GET).GetAtoms()[0].size - # print('# Get requires %d bytes' % (get_size)) + for atom in pid.GetRequest(PidStore.RDM_GET).GetAtoms(): + get_size += atom.size + #TODO(Peter): Should we just print this total all the time? + if get_size != pid.GetRequest(PidStore.RDM_GET).GetAtoms()[0].size: + print('# Get requires %d bytes' % (get_size)) AllSubDevicesGet(names, pid, pid_test_base_name, get_size) @@ -381,7 +392,8 @@ def main(): first_atom.ValidateRawValueInRange(1))): SetZero(names, pid, pid_test_base_name, first_atom) - SetWithNoData(names, pid, pid_test_base_name) + if set_size > 0: + SetWithNoData(names, pid, pid_test_base_name) SetWithExtraData(names, pid, pid_test_base_name, set_size) else: From c2126d1d1d686671db65c58bad9acd7b90243514 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Tue, 7 Mar 2023 14:44:52 +0000 Subject: [PATCH 48/71] First attempt at the E1.33 Broker PDU --- libs/acn/BrokerPDU.cpp | 68 ++++++++++++++++++++ libs/acn/BrokerPDU.h | 62 ++++++++++++++++++ libs/acn/BrokerPDUTest.cpp | 127 +++++++++++++++++++++++++++++++++++++ libs/acn/Makefile.mk | 3 + 4 files changed, 260 insertions(+) create mode 100644 libs/acn/BrokerPDU.cpp create mode 100644 libs/acn/BrokerPDU.h create mode 100644 libs/acn/BrokerPDUTest.cpp diff --git a/libs/acn/BrokerPDU.cpp b/libs/acn/BrokerPDU.cpp new file mode 100644 index 0000000000..8dcf9a844e --- /dev/null +++ b/libs/acn/BrokerPDU.cpp @@ -0,0 +1,68 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * BrokerPDU.cpp + * The BrokerPDU + * Copyright (C) 2023 Peter Newman + */ + + +#include "ola/Logging.h" +#include "ola/base/Array.h" +#include "ola/network/NetworkUtils.h" +#include "libs/acn/BrokerPDU.h" + +namespace ola { +namespace acn { + +using ola::io::OutputStream; +using ola::network::HostToNetwork; + +/* + * Size of the data portion + */ +unsigned int BrokerPDU::DataSize() const { + return m_pdu ? m_pdu->Size() : 0; +} + + +/* + * Pack the data portion. + */ +bool BrokerPDU::PackData(uint8_t *data, unsigned int *length) const { + if (m_pdu) + return m_pdu->Pack(data, length); + *length = 0; + return true; +} + + +/* + * Pack the data into a buffer + */ +void BrokerPDU::PackData(OutputStream *stream) const { + if (m_pdu) + m_pdu->Write(stream); +} + + +void BrokerPDU::PrependPDU(ola::io::IOStack *stack, + uint32_t vector) { + vector = HostToNetwork(vector); + stack->Write(reinterpret_cast(&vector), sizeof(vector)); + PrependFlagsAndLength(stack, VFLAG_MASK | HFLAG_MASK | DFLAG_MASK, true); +} +} // namespace acn +} // namespace ola diff --git a/libs/acn/BrokerPDU.h b/libs/acn/BrokerPDU.h new file mode 100644 index 0000000000..788f409b5a --- /dev/null +++ b/libs/acn/BrokerPDU.h @@ -0,0 +1,62 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * BrokerPDU.h + * Interface for the BrokerPDU class + * Copyright (C) 2023 Peter Newman + */ + +#ifndef LIBS_ACN_BROKERPDU_H_ +#define LIBS_ACN_BROKERPDU_H_ + +#include +#include + +#include "libs/acn/PDU.h" +#include "libs/acn/BrokerHeader.h" + +namespace ola { +namespace acn { + +class BrokerPDU: public PDU { + public: + BrokerPDU(unsigned int vector, + const PDU *pdu): + PDU(vector, FOUR_BYTES, true), + m_pdu(pdu) {} + ~BrokerPDU() {} + + 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; + bool PackData(uint8_t *data, unsigned int *length) const; + + void PackData(ola::io::OutputStream *stream) const; + + static void PrependPDU(ola::io::IOStack *stack, + uint32_t vector); + + private: + const PDU *m_pdu; +}; +} // namespace acn +} // namespace ola +#endif // LIBS_ACN_BROKERPDU_H_ diff --git a/libs/acn/BrokerPDUTest.cpp b/libs/acn/BrokerPDUTest.cpp new file mode 100644 index 0000000000..e4c2c6ef60 --- /dev/null +++ b/libs/acn/BrokerPDUTest.cpp @@ -0,0 +1,127 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * BrokerPDUTest.cpp + * Test fixture for the BrokerPDU class + * Copyright (C) 2023 Peter Newman + */ + +#include + +#include "ola/Logging.h" +#include "ola/io/IOQueue.h" +#include "ola/io/OutputStream.h" +#include "ola/network/NetworkUtils.h" +#include "ola/testing/TestUtils.h" +#include "libs/acn/BrokerPDU.h" +#include "libs/acn/PDUTestCommon.h" + + +namespace ola { +namespace acn { + +using ola::io::IOQueue; +using ola::io::OutputStream; +using ola::network::HostToNetwork; + +class BrokerPDUTest: public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(BrokerPDUTest); + CPPUNIT_TEST(testSimpleBrokerPDU); + CPPUNIT_TEST(testSimpleBrokerPDUToOutputStream); + CPPUNIT_TEST_SUITE_END(); + + public: + void testSimpleBrokerPDU(); + void testSimpleBrokerPDUToOutputStream(); + + void setUp() { + ola::InitLogging(ola::OLA_LOG_DEBUG, ola::OLA_LOG_STDERR); + } + + private: + static const unsigned int TEST_VECTOR; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(BrokerPDUTest); + +const unsigned int BrokerPDUTest::TEST_VECTOR = 39; + + +/* + * Test that packing a BrokerPDU without data works. + */ +void BrokerPDUTest::testSimpleBrokerPDU() { + BrokerPDU pdu(TEST_VECTOR, NULL); + + OLA_ASSERT_EQ(0u, pdu.HeaderSize()); + OLA_ASSERT_EQ(0u, pdu.DataSize()); + OLA_ASSERT_EQ(7u, 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]); + unsigned int actual_value; + memcpy(&actual_value, data + 3, sizeof(actual_value)); + OLA_ASSERT_EQ(HostToNetwork(TEST_VECTOR), actual_value); + + // 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 BrokerPDUTest::testSimpleBrokerPDUToOutputStream() { + BrokerPDU pdu(TEST_VECTOR, NULL); + + OLA_ASSERT_EQ(0u, pdu.HeaderSize()); + OLA_ASSERT_EQ(0u, pdu.DataSize()); + OLA_ASSERT_EQ(7u, pdu.Size()); + + IOQueue output; + OutputStream stream(&output); + pdu.Write(&stream); + OLA_ASSERT_EQ(7u, 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, 0x07, + 0, 0, 0, 39 + }; + OLA_ASSERT_DATA_EQUALS(EXPECTED, sizeof(EXPECTED), pdu_data, pdu_size); + output.Pop(output.Size()); + delete[] pdu_data; +} +} // namespace acn +} // namespace ola diff --git a/libs/acn/Makefile.mk b/libs/acn/Makefile.mk index a036a3f55a..82466ec2a3 100644 --- a/libs/acn/Makefile.mk +++ b/libs/acn/Makefile.mk @@ -31,6 +31,8 @@ noinst_LTLIBRARIES += libs/acn/libolae131core.la libs_acn_libolae131core_la_SOURCES = \ libs/acn/BaseInflator.cpp \ libs/acn/BaseInflator.h \ + libs/acn/BrokerPDU.cpp \ + libs/acn/BrokerPDU.h \ libs/acn/DMPAddress.cpp \ libs/acn/DMPAddress.h \ libs/acn/DMPE131Inflator.cpp \ @@ -146,6 +148,7 @@ libs_acn_E131Tester_LDADD = \ $(COMMON_TESTING_LIBS) libs_acn_E133Tester_SOURCES = \ + libs/acn/BrokerPDUTest.cpp \ libs/acn/E133InflatorTest.cpp \ libs/acn/E133PDUTest.cpp \ libs/acn/RDMPDUTest.cpp From 2a43710c8e595911c2981ce08bf0dc47d5888f27 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Tue, 7 Mar 2023 16:23:26 +0000 Subject: [PATCH 49/71] First attempt at BrokerClientEntryPDU --- libs/acn/BrokerClientEntryHeader.h | 63 ++++++++++++ libs/acn/BrokerClientEntryPDU.cpp | 114 +++++++++++++++++++++ libs/acn/BrokerClientEntryPDU.h | 61 +++++++++++ libs/acn/BrokerClientEntryPDUTest.cpp | 141 ++++++++++++++++++++++++++ libs/acn/BrokerPDU.h | 1 - libs/acn/Makefile.mk | 4 + 6 files changed, 383 insertions(+), 1 deletion(-) create mode 100644 libs/acn/BrokerClientEntryHeader.h create mode 100644 libs/acn/BrokerClientEntryPDU.cpp create mode 100644 libs/acn/BrokerClientEntryPDU.h create mode 100644 libs/acn/BrokerClientEntryPDUTest.cpp diff --git a/libs/acn/BrokerClientEntryHeader.h b/libs/acn/BrokerClientEntryHeader.h new file mode 100644 index 0000000000..d2277d9671 --- /dev/null +++ b/libs/acn/BrokerClientEntryHeader.h @@ -0,0 +1,63 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * BrokerClientEntryHeader.h + * The E1.33 Broker Client Entry Header + * Copyright (C) 2023 Peter Newman + */ + +#ifndef LIBS_ACN_BROKERCLIENTENTRYHEADER_H_ +#define LIBS_ACN_BROKERCLIENTENTRYHEADER_H_ + +#include +#include + +#include + +namespace ola { +namespace acn { + +// TODO(Peter): I think technically this probably shouldn't be a header and +// instead is just data at this level! +/* + * Header for the Broker Client Entry level + */ +class BrokerClientEntryHeader { + public: + BrokerClientEntryHeader() {} + + BrokerClientEntryHeader(const ola::acn::CID &client_cid) + : m_client_cid(client_cid) { + } + ~BrokerClientEntryHeader() {} + + const ola::acn::CID ClientCid() const { return m_client_cid; } + + bool operator==(const BrokerClientEntryHeader &other) const { + return m_client_cid == other.m_client_cid; + } + + PACK( + struct broker_client_entry_pdu_header_s { + uint8_t client_cid[CID::CID_LENGTH]; + }); + typedef struct broker_client_entry_pdu_header_s broker_client_entry_pdu_header; + + private: + ola::acn::CID m_client_cid; +}; +} // namespace acn +} // namespace ola +#endif // LIBS_ACN_BROKERCLIENTENTRYHEADER_H_ diff --git a/libs/acn/BrokerClientEntryPDU.cpp b/libs/acn/BrokerClientEntryPDU.cpp new file mode 100644 index 0000000000..521604e742 --- /dev/null +++ b/libs/acn/BrokerClientEntryPDU.cpp @@ -0,0 +1,114 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * BrokerClientEntryPDU.cpp + * The BrokerClientEntryPDU + * Copyright (C) 2023 Peter Newman + */ + + +#include "ola/Logging.h" +#include "ola/base/Array.h" +#include "ola/network/NetworkUtils.h" +#include "libs/acn/BrokerClientEntryPDU.h" + +namespace ola { +namespace acn { + +using ola::io::OutputStream; +using ola::network::HostToNetwork; + +/* + * Size of the header portion. + */ +unsigned int BrokerClientEntryPDU::HeaderSize() const { + return sizeof(BrokerClientEntryHeader::broker_client_entry_pdu_header); +} + + +/* + * Size of the data portion + */ +unsigned int BrokerClientEntryPDU::DataSize() const { + return m_pdu ? m_pdu->Size() : 0; +} + + +/* + * Pack the header portion. + */ +bool BrokerClientEntryPDU::PackHeader(uint8_t *data, unsigned int *length) const { + unsigned int header_size = HeaderSize(); + + if (*length < header_size) { + OLA_WARN << "BrokerClientEntryPDU::PackHeader: buffer too small, got " << *length + << " required " << header_size; + *length = 0; + return false; + } + + BrokerClientEntryHeader::broker_client_entry_pdu_header header; + m_header.ClientCid().Pack(header.client_cid); + *length = sizeof(BrokerClientEntryHeader::broker_client_entry_pdu_header); + memcpy(data, &header, *length); + return true; +} + + +/* + * Pack the data portion. + */ +bool BrokerClientEntryPDU::PackData(uint8_t *data, unsigned int *length) const { + if (m_pdu) + return m_pdu->Pack(data, length); + *length = 0; + return true; +} + + +/* + * Pack the header into a buffer. + */ +void BrokerClientEntryPDU::PackHeader(OutputStream *stream) const { + BrokerClientEntryHeader::broker_client_entry_pdu_header header; + m_header.ClientCid().Pack(header.client_cid); + stream->Write(reinterpret_cast(&header), + sizeof(BrokerClientEntryHeader::broker_client_entry_pdu_header)); +} + + +/* + * Pack the data into a buffer + */ +void BrokerClientEntryPDU::PackData(OutputStream *stream) const { + if (m_pdu) + m_pdu->Write(stream); +} + + +void BrokerClientEntryPDU::PrependPDU(ola::io::IOStack *stack, + uint32_t vector, + const ola::acn::CID &client_cid) { + BrokerClientEntryHeader::broker_client_entry_pdu_header header; + client_cid.Pack(header.client_cid); + stack->Write(reinterpret_cast(&header), + sizeof(BrokerClientEntryHeader::broker_client_entry_pdu_header)); + + vector = HostToNetwork(vector); + stack->Write(reinterpret_cast(&vector), sizeof(vector)); + PrependFlagsAndLength(stack, VFLAG_MASK | HFLAG_MASK | DFLAG_MASK, true); +} +} // namespace acn +} // namespace ola diff --git a/libs/acn/BrokerClientEntryPDU.h b/libs/acn/BrokerClientEntryPDU.h new file mode 100644 index 0000000000..cd6c83b4eb --- /dev/null +++ b/libs/acn/BrokerClientEntryPDU.h @@ -0,0 +1,61 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * BrokerClientEntryPDU.h + * Interface for the BrokerClientEntryPDU class + * Copyright (C) 2023 Peter Newman + */ + +#ifndef LIBS_ACN_BROKERCLIENTENTRYPDU_H_ +#define LIBS_ACN_BROKERCLIENTENTRYPDU_H_ + +#include +#include + +#include "libs/acn/PDU.h" +#include "libs/acn/BrokerClientEntryHeader.h" + +namespace ola { +namespace acn { + +class BrokerClientEntryPDU: public PDU { + public: + BrokerClientEntryPDU(unsigned int vector, + const BrokerClientEntryHeader &header, + const PDU *pdu): + PDU(vector, FOUR_BYTES, true), + m_header(header), + m_pdu(pdu) {} + ~BrokerClientEntryPDU() {} + + unsigned int HeaderSize() const; + unsigned int DataSize() const; + bool PackHeader(uint8_t *data, unsigned int *length) const; + bool PackData(uint8_t *data, unsigned int *length) const; + + void PackHeader(ola::io::OutputStream *stream) const; + void PackData(ola::io::OutputStream *stream) const; + + static void PrependPDU(ola::io::IOStack *stack, + uint32_t vector, + const ola::acn::CID &client_cid); + + private: + BrokerClientEntryHeader m_header; + const PDU *m_pdu; +}; +} // namespace acn +} // namespace ola +#endif // LIBS_ACN_BROKERCLIENTENTRYPDU_H_ diff --git a/libs/acn/BrokerClientEntryPDUTest.cpp b/libs/acn/BrokerClientEntryPDUTest.cpp new file mode 100644 index 0000000000..bdeedc3175 --- /dev/null +++ b/libs/acn/BrokerClientEntryPDUTest.cpp @@ -0,0 +1,141 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * BrokerClientEntryPDUTest.cpp + * Test fixture for the BrokerClientEntryPDU class + * Copyright (C) 2023 Peter Newman + */ + +#include + +#include "ola/Logging.h" +#include "ola/io/IOQueue.h" +#include "ola/io/OutputStream.h" +#include "ola/network/NetworkUtils.h" +#include "ola/testing/TestUtils.h" +#include "libs/acn/BrokerClientEntryPDU.h" +#include "libs/acn/PDUTestCommon.h" + + +namespace ola { +namespace acn { + +using ola::io::IOQueue; +using ola::io::OutputStream; +using ola::network::HostToNetwork; + +class BrokerClientEntryPDUTest: public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(BrokerClientEntryPDUTest); + CPPUNIT_TEST(testSimpleBrokerClientEntryPDU); + CPPUNIT_TEST(testSimpleBrokerClientEntryPDUToOutputStream); + CPPUNIT_TEST_SUITE_END(); + + public: + void testSimpleBrokerClientEntryPDU(); + void testSimpleBrokerClientEntryPDUToOutputStream(); + + void setUp() { + ola::InitLogging(ola::OLA_LOG_DEBUG, ola::OLA_LOG_STDERR); + } + + private: + static const unsigned int TEST_VECTOR; + static const uint8_t TEST_DATA[]; +}; + +const uint8_t BrokerClientEntryPDUTest::TEST_DATA[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15}; + +CPPUNIT_TEST_SUITE_REGISTRATION(BrokerClientEntryPDUTest); + +const unsigned int BrokerClientEntryPDUTest::TEST_VECTOR = 39; + + +/* + * Test that packing a BrokerClientEntryPDU without data works. + */ +void BrokerClientEntryPDUTest::testSimpleBrokerClientEntryPDU() { + const CID client_cid = CID::FromData(TEST_DATA); + BrokerClientEntryHeader header(client_cid); + BrokerClientEntryPDU pdu(TEST_VECTOR, header, NULL); + + OLA_ASSERT_EQ(16u, pdu.HeaderSize()); + OLA_ASSERT_EQ(0u, pdu.DataSize()); + OLA_ASSERT_EQ(23u, 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]); + unsigned int actual_value; + memcpy(&actual_value, data + 3, sizeof(actual_value)); + OLA_ASSERT_EQ(HostToNetwork(TEST_VECTOR), actual_value); + + uint8_t buffer[CID::CID_LENGTH]; + client_cid.Pack(buffer); + OLA_ASSERT_DATA_EQUALS(&data[7], CID::CID_LENGTH, buffer, sizeof(buffer)); + + // 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 BrokerClientEntryPDUTest::testSimpleBrokerClientEntryPDUToOutputStream() { + const ola::acn::CID client_cid = CID::FromData(TEST_DATA); + BrokerClientEntryHeader header(client_cid); + BrokerClientEntryPDU pdu(TEST_VECTOR, header, NULL); + + OLA_ASSERT_EQ(16u, pdu.HeaderSize()); + OLA_ASSERT_EQ(0u, pdu.DataSize()); + OLA_ASSERT_EQ(23u, pdu.Size()); + + IOQueue output; + OutputStream stream(&output); + pdu.Write(&stream); + OLA_ASSERT_EQ(23u, 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, 0x17, + 0, 0, 0, 39, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 + }; + OLA_ASSERT_DATA_EQUALS(EXPECTED, sizeof(EXPECTED), pdu_data, pdu_size); + output.Pop(output.Size()); + delete[] pdu_data; +} +} // namespace acn +} // namespace ola diff --git a/libs/acn/BrokerPDU.h b/libs/acn/BrokerPDU.h index 788f409b5a..9c6b50322b 100644 --- a/libs/acn/BrokerPDU.h +++ b/libs/acn/BrokerPDU.h @@ -25,7 +25,6 @@ #include #include "libs/acn/PDU.h" -#include "libs/acn/BrokerHeader.h" namespace ola { namespace acn { diff --git a/libs/acn/Makefile.mk b/libs/acn/Makefile.mk index 82466ec2a3..965052a1d8 100644 --- a/libs/acn/Makefile.mk +++ b/libs/acn/Makefile.mk @@ -31,6 +31,9 @@ noinst_LTLIBRARIES += libs/acn/libolae131core.la libs_acn_libolae131core_la_SOURCES = \ libs/acn/BaseInflator.cpp \ libs/acn/BaseInflator.h \ + libs/acn/BrokerClientEntryHeader.h \ + libs/acn/BrokerClientEntryPDU.cpp \ + libs/acn/BrokerClientEntryPDU.h \ libs/acn/BrokerPDU.cpp \ libs/acn/BrokerPDU.h \ libs/acn/DMPAddress.cpp \ @@ -148,6 +151,7 @@ libs_acn_E131Tester_LDADD = \ $(COMMON_TESTING_LIBS) libs_acn_E133Tester_SOURCES = \ + libs/acn/BrokerClientEntryPDUTest.cpp \ libs/acn/BrokerPDUTest.cpp \ libs/acn/E133InflatorTest.cpp \ libs/acn/E133PDUTest.cpp \ From 19eca6fd3ad371c010ca32005b78d12082b34e18 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Tue, 7 Mar 2023 23:52:15 +0000 Subject: [PATCH 50/71] First go at BrokerConnectPDU, could do with more tests --- include/ola/acn/ACNVectors.h | 21 ++++ include/ola/rdm/RDMEnums.h | 3 + libs/acn/BrokerConnectPDU.cpp | 123 ++++++++++++++++++ libs/acn/BrokerConnectPDU.h | 84 +++++++++++++ libs/acn/BrokerConnectPDUTest.cpp | 199 ++++++++++++++++++++++++++++++ libs/acn/Makefile.mk | 3 + 6 files changed, 433 insertions(+) create mode 100644 libs/acn/BrokerConnectPDU.cpp create mode 100644 libs/acn/BrokerConnectPDU.h create mode 100644 libs/acn/BrokerConnectPDUTest.cpp diff --git a/include/ola/acn/ACNVectors.h b/include/ola/acn/ACNVectors.h index 72c050ea91..fe75a05a5c 100644 --- a/include/ola/acn/ACNVectors.h +++ b/include/ola/acn/ACNVectors.h @@ -99,6 +99,27 @@ enum LLRPVector { VECTOR_LLRP_RDM_CMD = 3, /**< LLRP RDM Command */ }; +/** + * @brief Vectors used at the E1.33 Broker layer. + */ +enum BrokerVector { + VECTOR_BROKER_CONNECT = 0x0001, /**< Broker Client Connect */ + VECTOR_BROKER_CONNECT_REPLY = 0x0002, /**< Broker Connect Reply */ + VECTOR_BROKER_CLIENT_ENTRY_UPDATE = 0x0003, /**< Broker Client Entry Update */ + VECTOR_BROKER_REDIRECT_V4 = 0x0004, /**< Broker Client Redirect IPv4 */ + VECTOR_BROKER_REDIRECT_V6 = 0x0005, /**< Broker Client Redirect IPv6 */ + VECTOR_BROKER_FETCH_CLIENT_LIST = 0x0006, /**< Broker Fetch Client List */ + VECTOR_BROKER_CONNECTED_CLIENT_LIST = 0x0007, /**< Broker Connected Client List */ + VECTOR_BROKER_CLIENT_ADD = 0x0008, /**< Broker Client Incremental Addition */ + VECTOR_BROKER_CLIENT_REMOVE = 0x0009, /**< Broker Client Incremental Deletion */ + VECTOR_BROKER_CLIENT_ENTRY_CHANGE = 0x000A, /**< Broker Client Entry Change */ + VECTOR_BROKER_REQUEST_DYNAMIC_UIDS = 0x000B, /**< Broker Request Dynamic UID Assignment */ + VECTOR_BROKER_ASSIGNED_DYNAMIC_UIDS = 0x000C, /**< Broker Dynamic UID Assignment List */ + VECTOR_BROKER_FETCH_DYNAMIC_UID_LIST = 0x000D, /**< Broker Fetch Dynamic UID Assignment List */ + VECTOR_BROKER_DISCONNECT = 0x000E, /**< Broker Client Disconnect */ + VECTOR_BROKER_NULL = 0x000F, /**< Broker Client Null */ +}; + /** * @} */ diff --git a/include/ola/rdm/RDMEnums.h b/include/ola/rdm/RDMEnums.h index c57e8f7e97..72bc8aabe0 100644 --- a/include/ola/rdm/RDMEnums.h +++ b/include/ola/rdm/RDMEnums.h @@ -718,6 +718,9 @@ static const uint8_t MAX_RDM_HOSTNAME_LENGTH = 63; static const uint8_t MAX_RDM_DOMAIN_NAME_LENGTH = 231; static const uint8_t DNS_NAME_SERVER_MAX_INDEX = 2; + +// Excluding the mandatory NULL terminator +static const uint8_t MAX_RDM_SCOPE_STRING_LENGTH = 62; } // namespace rdm } // namespace ola #endif // INCLUDE_OLA_RDM_RDMENUMS_H_ diff --git a/libs/acn/BrokerConnectPDU.cpp b/libs/acn/BrokerConnectPDU.cpp new file mode 100644 index 0000000000..753efc0ba0 --- /dev/null +++ b/libs/acn/BrokerConnectPDU.cpp @@ -0,0 +1,123 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * BrokerConnectPDU.cpp + * The BrokerConnectPDU + * Copyright (C) 2023 Peter Newman + */ + +#include + +#include "libs/acn/BrokerConnectPDU.h" + +#include +#include + +namespace ola { +namespace acn { + +using ola::io::OutputStream; +using ola::network::HostToNetwork; +using std::min; +using std::string; + +unsigned int BrokerConnectPDU::DataSize() const { + //broker_connect_pdu_data data; + return static_cast(sizeof(broker_connect_pdu_data)); +} + +bool BrokerConnectPDU::PackData(uint8_t *data, unsigned int *length) const { + broker_connect_pdu_data pdu_data; + + size_t client_scope_str_len = min(m_client_scope.size(), sizeof(pdu_data.client_scope)); + strncpy(pdu_data.client_scope, m_client_scope.c_str(), client_scope_str_len); + memset(pdu_data.client_scope + client_scope_str_len, 0, + (sizeof(pdu_data.client_scope) - client_scope_str_len)); + + pdu_data.e133_version = m_e133_version; + + size_t search_domain_str_len = min(m_search_domain.size(), sizeof(pdu_data.search_domain)); + strncpy(pdu_data.search_domain, m_search_domain.c_str(), search_domain_str_len); + memset(pdu_data.search_domain + search_domain_str_len, 0, + (sizeof(pdu_data.search_domain) - search_domain_str_len)); + + uint8_t connection = 0; + if (m_incremental_updates) { + connection |= CONNECTION_INCREMENTAL_UPDATES; + } + pdu_data.connection = HostToNetwork(connection); + *length = static_cast(sizeof(broker_connect_pdu_data)); + + memcpy(data, &pdu_data, *length); + return true; +} + +void BrokerConnectPDU::PackData(ola::io::OutputStream *stream) const { + broker_connect_pdu_data pdu_data; + + size_t client_scope_str_len = min(m_client_scope.size(), sizeof(pdu_data.client_scope)); + strncpy(pdu_data.client_scope, m_client_scope.c_str(), client_scope_str_len); + memset(pdu_data.client_scope + client_scope_str_len, 0, + (sizeof(pdu_data.client_scope) - client_scope_str_len)); + + pdu_data.e133_version = m_e133_version; + + size_t search_domain_str_len = min(m_search_domain.size(), sizeof(pdu_data.search_domain)); + strncpy(pdu_data.search_domain, m_search_domain.c_str(), search_domain_str_len); + memset(pdu_data.search_domain + search_domain_str_len, 0, + (sizeof(pdu_data.search_domain) - search_domain_str_len)); + + uint8_t connection = 0; + if (m_incremental_updates) { + connection |= CONNECTION_INCREMENTAL_UPDATES; + } + pdu_data.connection = HostToNetwork(connection); + + stream->Write(reinterpret_cast(&pdu_data), + static_cast(sizeof(broker_connect_pdu_data))); +} + +void BrokerConnectPDU::PrependPDU(ola::io::IOStack *stack, + const string &client_scope, + uint16_t e133_version, + const string &search_domain, + bool incremental_updates) { + broker_connect_pdu_data pdu_data; + + size_t client_scope_str_len = min(client_scope.size(), sizeof(pdu_data.client_scope)); + strncpy(pdu_data.client_scope, client_scope.c_str(), client_scope_str_len); + memset(pdu_data.client_scope + client_scope_str_len, 0, + (sizeof(pdu_data.client_scope) - client_scope_str_len)); + + pdu_data.e133_version = e133_version; + + size_t search_domain_str_len = min(search_domain.size(), sizeof(pdu_data.search_domain)); + strncpy(pdu_data.search_domain, search_domain.c_str(), search_domain_str_len); + memset(pdu_data.search_domain + search_domain_str_len, 0, + (sizeof(pdu_data.search_domain) - search_domain_str_len)); + + uint8_t connection = 0; + if (incremental_updates) { + connection |= CONNECTION_INCREMENTAL_UPDATES; + } + pdu_data.connection = HostToNetwork(connection); + stack->Write(reinterpret_cast(&pdu_data), + static_cast(sizeof(broker_connect_pdu_data))); + uint16_t vector = HostToNetwork(static_cast(VECTOR_BROKER_CONNECT)); + stack->Write(reinterpret_cast(&vector), sizeof(vector)); + PrependFlagsAndLength(stack, VFLAG_MASK | HFLAG_MASK | DFLAG_MASK, true); +} +} // namespace acn +} // namespace ola diff --git a/libs/acn/BrokerConnectPDU.h b/libs/acn/BrokerConnectPDU.h new file mode 100644 index 0000000000..8850ed00c8 --- /dev/null +++ b/libs/acn/BrokerConnectPDU.h @@ -0,0 +1,84 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * BrokerConnectPDU.h + * The BrokerConnectPDU class + * Copyright (C) 2023 Peter Newman + */ + +#ifndef LIBS_ACN_BROKERCONNECTPDU_H_ +#define LIBS_ACN_BROKERCONNECTPDU_H_ + +#include +#include + +#include "libs/acn/PDU.h" + +namespace ola { +namespace acn { + +class BrokerConnectPDU : public PDU { + public: + explicit BrokerConnectPDU(unsigned int vector, + const std::string &client_scope, + uint16_t e133_version, + const std::string &search_domain, + bool incremental_updates): + PDU(vector, TWO_BYTES, true), + m_client_scope(client_scope), + m_e133_version(e133_version), + m_search_domain(search_domain), + m_incremental_updates(incremental_updates) {} + + 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; + bool PackData(uint8_t *data, unsigned int *length) const; + void PackData(ola::io::OutputStream *stream) const; + + static void PrependPDU(ola::io::IOStack *stack, + const std::string &client_scope, + uint16_t e133_version, + const std::string &search_domain, + bool incremental_updates); + + // bit masks for connection + static const uint8_t CONNECTION_INCREMENTAL_UPDATES = 0x01; + + PACK( + struct broker_connect_pdu_data_s { + // Plus one to allow for the mandatory null + char client_scope[ola::rdm::MAX_RDM_SCOPE_STRING_LENGTH + 1]; + uint16_t e133_version; + char search_domain[ola::rdm::MAX_RDM_DOMAIN_NAME_LENGTH]; + uint8_t connection; + }); + typedef struct broker_connect_pdu_data_s broker_connect_pdu_data; + + private: + const std::string m_client_scope; + uint16_t m_e133_version; + const std::string m_search_domain; + uint8_t m_incremental_updates; +}; +} // namespace acn +} // namespace ola +#endif // LIBS_ACN_BROKERCONNECTPDU_H_ diff --git a/libs/acn/BrokerConnectPDUTest.cpp b/libs/acn/BrokerConnectPDUTest.cpp new file mode 100644 index 0000000000..d3add5d2c4 --- /dev/null +++ b/libs/acn/BrokerConnectPDUTest.cpp @@ -0,0 +1,199 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * BrokerConnectPDUTest.cpp + * Test fixture for the BrokerConnectPDU class + * Copyright (C) 2023 Peter Newman + */ + +#include +#include +#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/testing/TestUtils.h" +#include "libs/acn/PDUTestCommon.h" +#include "libs/acn/BrokerConnectPDU.h" + +namespace ola { +namespace acn { + +using ola::acn::BrokerConnectPDU; +using ola::io::IOQueue; +using ola::io::IOStack; +using ola::io::OutputStream; +using ola::network::HostToNetwork; + +class BrokerConnectPDUTest: public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(BrokerConnectPDUTest); + CPPUNIT_TEST(testSimpleBrokerConnectPDU); + CPPUNIT_TEST(testSimpleBrokerConnectPDUToOutputStream); + CPPUNIT_TEST(testPrepend); + CPPUNIT_TEST_SUITE_END(); + + public: + void testSimpleBrokerConnectPDU(); + void testSimpleBrokerConnectPDUToOutputStream(); + void testPrepend(); + + private: + static const uint16_t TEST_VECTOR; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(BrokerConnectPDUTest); + +const uint16_t BrokerConnectPDUTest::TEST_VECTOR = 39; + + +/* + * Test that packing a BrokerConnectPDU works. + */ +void BrokerConnectPDUTest::testSimpleBrokerConnectPDU() { + BrokerConnectPDU pdu( + TEST_VECTOR, + "default", + 1, + "local.", + true); + + OLA_ASSERT_EQ(0u, pdu.HeaderSize()); + OLA_ASSERT_EQ(297u, pdu.DataSize()); + OLA_ASSERT_EQ(302u, 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]); + uint16_t actual_value; + memcpy(&actual_value, data + 3, sizeof(actual_value)); + OLA_ASSERT_EQ(HostToNetwork(TEST_VECTOR), actual_value); + + // TODO(Peter): Better spot check the data! + + // 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 BrokerConnectPDUTest::testSimpleBrokerConnectPDUToOutputStream() { + BrokerConnectPDU pdu( + TEST_VECTOR, + "default", + 1, + "local.", + true); + + OLA_ASSERT_EQ(0u, pdu.HeaderSize()); + OLA_ASSERT_EQ(297u, pdu.DataSize()); + OLA_ASSERT_EQ(302u, pdu.Size()); + + IOQueue output; + OutputStream stream(&output); + pdu.Write(&stream); + OLA_ASSERT_EQ(302u, 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, 0x01, 0x2e, + 0, 39, + 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, // default + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0x01, 0, + 0x6c, 0x6f, 0x63, 0x61, 0x6C, 0x2e, // local. + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1 + }; + OLA_ASSERT_DATA_EQUALS(EXPECTED, sizeof(EXPECTED), pdu_data, pdu_size); + output.Pop(output.Size()); + delete[] pdu_data; +} + + +void BrokerConnectPDUTest::testPrepend() { + IOStack stack; + BrokerConnectPDU::PrependPDU(&stack, + "default", + 1, + "local.", + true); + + unsigned int length = stack.Size(); + uint8_t *buffer = new uint8_t[length]; + OLA_ASSERT(stack.Read(buffer, length)); + + const uint8_t expected_data[] = { + 0xf0, 0x01, 0x2e, + 0, 1, + 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, // default + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0x01, 0, + 0x6c, 0x6f, 0x63, 0x61, 0x6C, 0x2e, // local. + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1 + }; + OLA_ASSERT_DATA_EQUALS(expected_data, sizeof(expected_data), buffer, length); + delete[] buffer; +} +} // namespace acn +} // namespace ola diff --git a/libs/acn/Makefile.mk b/libs/acn/Makefile.mk index 965052a1d8..ad9909be42 100644 --- a/libs/acn/Makefile.mk +++ b/libs/acn/Makefile.mk @@ -34,6 +34,8 @@ libs_acn_libolae131core_la_SOURCES = \ libs/acn/BrokerClientEntryHeader.h \ libs/acn/BrokerClientEntryPDU.cpp \ libs/acn/BrokerClientEntryPDU.h \ + libs/acn/BrokerConnectPDU.cpp \ + libs/acn/BrokerConnectPDU.h \ libs/acn/BrokerPDU.cpp \ libs/acn/BrokerPDU.h \ libs/acn/DMPAddress.cpp \ @@ -152,6 +154,7 @@ libs_acn_E131Tester_LDADD = \ libs_acn_E133Tester_SOURCES = \ libs/acn/BrokerClientEntryPDUTest.cpp \ + libs/acn/BrokerConnectPDUTest.cpp \ libs/acn/BrokerPDUTest.cpp \ libs/acn/E133InflatorTest.cpp \ libs/acn/E133PDUTest.cpp \ From d01494b9c3ff3bdec37b072a9029cdb36126cc61 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Wed, 8 Mar 2023 13:29:57 +0000 Subject: [PATCH 51/71] Fix a typo in the DeviceManager stuff --- include/ola/e133/DeviceManager.h | 4 ++-- tools/e133/DeviceManager.cpp | 4 ++-- tools/e133/DeviceManagerImpl.cpp | 4 ++-- tools/e133/DeviceManagerImpl.h | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/ola/e133/DeviceManager.h b/include/ola/e133/DeviceManager.h index 9fada52606..023e8d9f1b 100644 --- a/include/ola/e133/DeviceManager.h +++ b/include/ola/e133/DeviceManager.h @@ -53,7 +53,7 @@ class DeviceManager { * @returns true if the data should be acknowledged, false otherwise. */ typedef ola::Callback3 RDMMesssageCallback; + const string&> RDMMessageCallback; // Run when we acquire designated controller status for a device. typedef ola::Callback1 AcquireDeviceCallback; @@ -66,7 +66,7 @@ class DeviceManager { ~DeviceManager(); // Ownership of the callbacks is transferred. - void SetRDMMessageCallback(RDMMesssageCallback *callback); + void SetRDMMessageCallback(RDMMessageCallback *callback); void SetAcquireDeviceCallback(AcquireDeviceCallback *callback); void SetReleaseDeviceCallback(ReleaseDeviceCallback *callback); diff --git a/tools/e133/DeviceManager.cpp b/tools/e133/DeviceManager.cpp index b91879eddd..3fe1f38874 100644 --- a/tools/e133/DeviceManager.cpp +++ b/tools/e133/DeviceManager.cpp @@ -54,9 +54,9 @@ DeviceManager::~DeviceManager() {} /** * Set the callback to be run when RDMNet data is received from a device. - * @param callback the RDMMesssageCallback to run when data is received. + * @param callback the RDMMessageCallback to run when data is received. */ -void DeviceManager::SetRDMMessageCallback(RDMMesssageCallback *callback) { +void DeviceManager::SetRDMMessageCallback(RDMMessageCallback *callback) { m_impl->SetRDMMessageCallback(callback); } diff --git a/tools/e133/DeviceManagerImpl.cpp b/tools/e133/DeviceManagerImpl.cpp index 86ace1d99c..2e16aa4a94 100644 --- a/tools/e133/DeviceManagerImpl.cpp +++ b/tools/e133/DeviceManagerImpl.cpp @@ -132,9 +132,9 @@ DeviceManagerImpl::~DeviceManagerImpl() { /** * Set the callback to be run when RDMNet data is received from a device. - * @param callback the RDMMesssageCallback to run when data is received. + * @param callback the RDMMessageCallback to run when data is received. */ -void DeviceManagerImpl::SetRDMMessageCallback(RDMMesssageCallback *callback) { +void DeviceManagerImpl::SetRDMMessageCallback(RDMMessageCallback *callback) { m_rdm_callback.reset(callback); } diff --git a/tools/e133/DeviceManagerImpl.h b/tools/e133/DeviceManagerImpl.h index 90bee905ef..5f0c7ad1c4 100644 --- a/tools/e133/DeviceManagerImpl.h +++ b/tools/e133/DeviceManagerImpl.h @@ -70,7 +70,7 @@ class DeviceManagerImpl { * @returns true if the data should be acknowledged, false otherwise. */ typedef ola::Callback3 RDMMesssageCallback; + const string&> RDMMessageCallback; // Run when we acquire designated controller status for a device. typedef ola::Callback1 AcquireDeviceCallback; @@ -83,7 +83,7 @@ class DeviceManagerImpl { ~DeviceManagerImpl(); // Ownership of the callbacks is transferred. - void SetRDMMessageCallback(RDMMesssageCallback *callback); + void SetRDMMessageCallback(RDMMessageCallback *callback); void SetAcquireDeviceCallback(AcquireDeviceCallback *callback); void SetReleaseDeviceCallback(ReleaseDeviceCallback *callback); @@ -98,7 +98,7 @@ class DeviceManagerImpl { DeviceMap; DeviceMap m_device_map; - auto_ptr m_rdm_callback; + auto_ptr m_rdm_callback; auto_ptr m_acquire_device_cb_; auto_ptr m_release_device_cb_; From f49c1f83420634a41309898a7cf327795ec3ed10 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Wed, 8 Mar 2023 16:55:30 +0000 Subject: [PATCH 52/71] Add the BrokerNullPDU and tests --- libs/acn/BrokerNullPDU.cpp | 40 +++++++++ libs/acn/BrokerNullPDU.h | 56 +++++++++++++ libs/acn/BrokerNullPDUTest.cpp | 145 +++++++++++++++++++++++++++++++++ libs/acn/Makefile.mk | 3 + 4 files changed, 244 insertions(+) create mode 100644 libs/acn/BrokerNullPDU.cpp create mode 100644 libs/acn/BrokerNullPDU.h create mode 100644 libs/acn/BrokerNullPDUTest.cpp diff --git a/libs/acn/BrokerNullPDU.cpp b/libs/acn/BrokerNullPDU.cpp new file mode 100644 index 0000000000..5f50bb9a8f --- /dev/null +++ b/libs/acn/BrokerNullPDU.cpp @@ -0,0 +1,40 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * BrokerNullPDU.cpp + * The BrokerNullPDU + * Copyright (C) 2023 Peter Newman + */ + +#include "libs/acn/BrokerNullPDU.h" + +#include +#include + +namespace ola { +namespace acn { + +using ola::io::OutputStream; +using ola::network::HostToNetwork; +using std::min; +using std::string; + +void BrokerNullPDU::PrependPDU(ola::io::IOStack *stack) { + uint16_t vector = HostToNetwork(static_cast(VECTOR_BROKER_NULL)); + stack->Write(reinterpret_cast(&vector), sizeof(vector)); + PrependFlagsAndLength(stack, VFLAG_MASK | HFLAG_MASK | DFLAG_MASK, true); +} +} // namespace acn +} // namespace ola diff --git a/libs/acn/BrokerNullPDU.h b/libs/acn/BrokerNullPDU.h new file mode 100644 index 0000000000..88450f7ad0 --- /dev/null +++ b/libs/acn/BrokerNullPDU.h @@ -0,0 +1,56 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * BrokerNullPDU.h + * The BrokerNullPDU class + * Copyright (C) 2023 Peter Newman + */ + +#ifndef LIBS_ACN_BROKERNULLPDU_H_ +#define LIBS_ACN_BROKERNULLPDU_H_ + +#include + +#include "libs/acn/PDU.h" + +namespace ola { +namespace acn { + +class BrokerNullPDU : public PDU { + public: + explicit BrokerNullPDU(unsigned int vector): + PDU(vector, TWO_BYTES, true) {} + + 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 0; } + bool PackData(OLA_UNUSED uint8_t *data, + unsigned int *length) const { + *length = 0; + return true; + } + void PackData(OLA_UNUSED ola::io::OutputStream *stream) const {}; + + static void PrependPDU(ola::io::IOStack *stack); +}; +} // namespace acn +} // namespace ola +#endif // LIBS_ACN_BROKERNULLPDU_H_ diff --git a/libs/acn/BrokerNullPDUTest.cpp b/libs/acn/BrokerNullPDUTest.cpp new file mode 100644 index 0000000000..46fa712b50 --- /dev/null +++ b/libs/acn/BrokerNullPDUTest.cpp @@ -0,0 +1,145 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * BrokerNullPDUTest.cpp + * Test fixture for the BrokerNullPDU class + * Copyright (C) 2023 Peter Newman + */ + +#include +#include +#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/testing/TestUtils.h" +#include "libs/acn/PDUTestCommon.h" +#include "libs/acn/BrokerNullPDU.h" + +namespace ola { +namespace acn { + +using ola::acn::BrokerNullPDU; +using ola::io::IOQueue; +using ola::io::IOStack; +using ola::io::OutputStream; +using ola::network::HostToNetwork; + +class BrokerNullPDUTest: public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(BrokerNullPDUTest); + CPPUNIT_TEST(testSimpleBrokerNullPDU); + CPPUNIT_TEST(testSimpleBrokerNullPDUToOutputStream); + CPPUNIT_TEST(testPrepend); + CPPUNIT_TEST_SUITE_END(); + + public: + void testSimpleBrokerNullPDU(); + void testSimpleBrokerNullPDUToOutputStream(); + void testPrepend(); + + private: + static const uint16_t TEST_VECTOR; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(BrokerNullPDUTest); + +const uint16_t BrokerNullPDUTest::TEST_VECTOR = 39; + + +/* + * Test that packing a BrokerNullPDU works. + */ +void BrokerNullPDUTest::testSimpleBrokerNullPDU() { + BrokerNullPDU pdu(TEST_VECTOR); + + OLA_ASSERT_EQ(0u, pdu.HeaderSize()); + OLA_ASSERT_EQ(0u, pdu.DataSize()); + OLA_ASSERT_EQ(5u, 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]); + uint16_t actual_value; + memcpy(&actual_value, data + 3, sizeof(actual_value)); + OLA_ASSERT_EQ(HostToNetwork(TEST_VECTOR), actual_value); + + // 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 BrokerNullPDUTest::testSimpleBrokerNullPDUToOutputStream() { + BrokerNullPDU pdu(TEST_VECTOR); + + OLA_ASSERT_EQ(0u, pdu.HeaderSize()); + OLA_ASSERT_EQ(0u, pdu.DataSize()); + OLA_ASSERT_EQ(5u, pdu.Size()); + + IOQueue output; + OutputStream stream(&output); + pdu.Write(&stream); + OLA_ASSERT_EQ(5u, 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, 0x05, + 0, 39 + }; + OLA_ASSERT_DATA_EQUALS(EXPECTED, sizeof(EXPECTED), pdu_data, pdu_size); + output.Pop(output.Size()); + delete[] pdu_data; +} + + +void BrokerNullPDUTest::testPrepend() { + IOStack stack; + BrokerNullPDU::PrependPDU(&stack); + + unsigned int length = stack.Size(); + uint8_t *buffer = new uint8_t[length]; + OLA_ASSERT(stack.Read(buffer, length)); + + const uint8_t expected_data[] = { + 0xf0, 0x00, 0x05, + 0, 0x0f + }; + OLA_ASSERT_DATA_EQUALS(expected_data, sizeof(expected_data), buffer, length); + delete[] buffer; +} +} // namespace acn +} // namespace ola diff --git a/libs/acn/Makefile.mk b/libs/acn/Makefile.mk index ad9909be42..4d89196233 100644 --- a/libs/acn/Makefile.mk +++ b/libs/acn/Makefile.mk @@ -36,6 +36,8 @@ libs_acn_libolae131core_la_SOURCES = \ libs/acn/BrokerClientEntryPDU.h \ libs/acn/BrokerConnectPDU.cpp \ libs/acn/BrokerConnectPDU.h \ + libs/acn/BrokerNullPDU.cpp \ + libs/acn/BrokerNullPDU.h \ libs/acn/BrokerPDU.cpp \ libs/acn/BrokerPDU.h \ libs/acn/DMPAddress.cpp \ @@ -155,6 +157,7 @@ libs_acn_E131Tester_LDADD = \ libs_acn_E133Tester_SOURCES = \ libs/acn/BrokerClientEntryPDUTest.cpp \ libs/acn/BrokerConnectPDUTest.cpp \ + libs/acn/BrokerNullPDUTest.cpp \ libs/acn/BrokerPDUTest.cpp \ libs/acn/E133InflatorTest.cpp \ libs/acn/E133PDUTest.cpp \ From 5b36363f858bb303ddde228328912b70d607dd87 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Thu, 9 Mar 2023 15:52:54 +0000 Subject: [PATCH 53/71] Correct the byte order for the E1.33 version field --- libs/acn/BrokerConnectPDU.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/acn/BrokerConnectPDU.cpp b/libs/acn/BrokerConnectPDU.cpp index 753efc0ba0..8bf3114ace 100644 --- a/libs/acn/BrokerConnectPDU.cpp +++ b/libs/acn/BrokerConnectPDU.cpp @@ -46,7 +46,7 @@ bool BrokerConnectPDU::PackData(uint8_t *data, unsigned int *length) const { memset(pdu_data.client_scope + client_scope_str_len, 0, (sizeof(pdu_data.client_scope) - client_scope_str_len)); - pdu_data.e133_version = m_e133_version; + pdu_data.e133_version = HostToNetwork(m_e133_version); size_t search_domain_str_len = min(m_search_domain.size(), sizeof(pdu_data.search_domain)); strncpy(pdu_data.search_domain, m_search_domain.c_str(), search_domain_str_len); @@ -72,7 +72,7 @@ void BrokerConnectPDU::PackData(ola::io::OutputStream *stream) const { memset(pdu_data.client_scope + client_scope_str_len, 0, (sizeof(pdu_data.client_scope) - client_scope_str_len)); - pdu_data.e133_version = m_e133_version; + pdu_data.e133_version = HostToNetwork(m_e133_version); size_t search_domain_str_len = min(m_search_domain.size(), sizeof(pdu_data.search_domain)); strncpy(pdu_data.search_domain, m_search_domain.c_str(), search_domain_str_len); @@ -101,7 +101,7 @@ void BrokerConnectPDU::PrependPDU(ola::io::IOStack *stack, memset(pdu_data.client_scope + client_scope_str_len, 0, (sizeof(pdu_data.client_scope) - client_scope_str_len)); - pdu_data.e133_version = e133_version; + pdu_data.e133_version = HostToNetwork(e133_version); size_t search_domain_str_len = min(search_domain.size(), sizeof(pdu_data.search_domain)); strncpy(pdu_data.search_domain, search_domain.c_str(), search_domain_str_len); From eb609f384ee363070180f0954801c85b353c4047 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Thu, 9 Mar 2023 15:53:29 +0000 Subject: [PATCH 54/71] Correct the size of the BrokerPDU's vector --- libs/acn/BrokerPDU.cpp | 2 +- libs/acn/BrokerPDU.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/acn/BrokerPDU.cpp b/libs/acn/BrokerPDU.cpp index 8dcf9a844e..50364833ce 100644 --- a/libs/acn/BrokerPDU.cpp +++ b/libs/acn/BrokerPDU.cpp @@ -59,7 +59,7 @@ void BrokerPDU::PackData(OutputStream *stream) const { void BrokerPDU::PrependPDU(ola::io::IOStack *stack, - uint32_t vector) { + uint16_t vector) { vector = HostToNetwork(vector); stack->Write(reinterpret_cast(&vector), sizeof(vector)); PrependFlagsAndLength(stack, VFLAG_MASK | HFLAG_MASK | DFLAG_MASK, true); diff --git a/libs/acn/BrokerPDU.h b/libs/acn/BrokerPDU.h index 9c6b50322b..f77bfe6452 100644 --- a/libs/acn/BrokerPDU.h +++ b/libs/acn/BrokerPDU.h @@ -51,7 +51,7 @@ class BrokerPDU: public PDU { void PackData(ola::io::OutputStream *stream) const; static void PrependPDU(ola::io::IOStack *stack, - uint32_t vector); + uint16_t vector); private: const PDU *m_pdu; From e99ec916eb0d6e739f08c29e8f169959091302d6 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Thu, 9 Mar 2023 15:59:55 +0000 Subject: [PATCH 55/71] Correct a broker endian check for the E1.33 version in our tests --- libs/acn/BrokerConnectPDUTest.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/acn/BrokerConnectPDUTest.cpp b/libs/acn/BrokerConnectPDUTest.cpp index d3add5d2c4..e9d1052e34 100644 --- a/libs/acn/BrokerConnectPDUTest.cpp +++ b/libs/acn/BrokerConnectPDUTest.cpp @@ -135,8 +135,8 @@ void BrokerConnectPDUTest::testSimpleBrokerConnectPDUToOutputStream() { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0x01, 0, - 0x6c, 0x6f, 0x63, 0x61, 0x6C, 0x2e, // local. + 0, 0x01, + 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2e, // local. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -176,8 +176,8 @@ void BrokerConnectPDUTest::testPrepend() { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0x01, 0, - 0x6c, 0x6f, 0x63, 0x61, 0x6C, 0x2e, // local. + 0, 0x01, + 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2e, // local. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, From d40a36a4daa1835cd9a4a3057fc6b18b2e8ed773 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Thu, 9 Mar 2023 17:50:46 +0000 Subject: [PATCH 56/71] Add a testPrepend test for the BrokerClientEntryPDU base class --- libs/acn/BrokerClientEntryPDUTest.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/libs/acn/BrokerClientEntryPDUTest.cpp b/libs/acn/BrokerClientEntryPDUTest.cpp index bdeedc3175..e907d03a33 100644 --- a/libs/acn/BrokerClientEntryPDUTest.cpp +++ b/libs/acn/BrokerClientEntryPDUTest.cpp @@ -22,6 +22,7 @@ #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/testing/TestUtils.h" @@ -33,6 +34,7 @@ namespace ola { namespace acn { using ola::io::IOQueue; +using ola::io::IOStack; using ola::io::OutputStream; using ola::network::HostToNetwork; @@ -40,11 +42,13 @@ class BrokerClientEntryPDUTest: public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(BrokerClientEntryPDUTest); CPPUNIT_TEST(testSimpleBrokerClientEntryPDU); CPPUNIT_TEST(testSimpleBrokerClientEntryPDUToOutputStream); + CPPUNIT_TEST(testPrepend); CPPUNIT_TEST_SUITE_END(); public: void testSimpleBrokerClientEntryPDU(); void testSimpleBrokerClientEntryPDUToOutputStream(); + void testPrepend(); void setUp() { ola::InitLogging(ola::OLA_LOG_DEBUG, ola::OLA_LOG_STDERR); @@ -137,5 +141,27 @@ void BrokerClientEntryPDUTest::testSimpleBrokerClientEntryPDUToOutputStream() { output.Pop(output.Size()); delete[] pdu_data; } + + +void BrokerClientEntryPDUTest::testPrepend() { + const ola::acn::CID client_cid = CID::FromData(TEST_DATA); + IOStack stack; + BrokerClientEntryPDU::PrependPDU(&stack, + TEST_VECTOR, + client_cid); + + unsigned int length = stack.Size(); + uint8_t *buffer = new uint8_t[length]; + OLA_ASSERT(stack.Read(buffer, length)); + + const uint8_t expected_data[] = { + 0xf0, 0x00, 0x17, + 0, 0, 0, 39, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 + }; + OLA_ASSERT_DATA_EQUALS(expected_data, sizeof(expected_data), buffer, length); + delete[] buffer; +} } // namespace acn } // namespace ola From ad9ac0d49f03b6af87947bfc0ab6ab386102ed91 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Fri, 10 Mar 2023 18:42:43 +0000 Subject: [PATCH 57/71] Allow the timeout interval of the HealthCheckedConnection to be customised --- common/network/HealthCheckedConnection.cpp | 17 +++- .../network/HealthCheckedConnectionTest.cpp | 81 ++++++++++++++++++- include/ola/network/HealthCheckedConnection.h | 13 ++- 3 files changed, 100 insertions(+), 11 deletions(-) diff --git a/common/network/HealthCheckedConnection.cpp b/common/network/HealthCheckedConnection.cpp index 6f5cc741de..b39008a608 100644 --- a/common/network/HealthCheckedConnection.cpp +++ b/common/network/HealthCheckedConnection.cpp @@ -26,14 +26,25 @@ namespace network { HealthCheckedConnection::HealthCheckedConnection( ola::thread::SchedulerInterface *scheduler, + const ola::TimeInterval heartbeat_interval, const ola::TimeInterval timeout_interval) : m_scheduler(scheduler), - m_heartbeat_interval(timeout_interval), + m_heartbeat_interval(heartbeat_interval), + m_timeout_interval(timeout_interval), m_send_timeout_id(ola::thread::INVALID_TIMEOUT), m_receive_timeout_id(ola::thread::INVALID_TIMEOUT) { } +HealthCheckedConnection::HealthCheckedConnection( + ola::thread::SchedulerInterface *scheduler, + const ola::TimeInterval heartbeat_interval) + : HealthCheckedConnection(scheduler, + heartbeat_interval, + ola::TimeInterval(static_cast( + 2.5 * heartbeat_interval.AsInt()))) { +} + HealthCheckedConnection::~HealthCheckedConnection() { if (m_send_timeout_id != ola::thread::INVALID_TIMEOUT) m_scheduler->RemoveTimeout(m_send_timeout_id); @@ -101,10 +112,8 @@ bool HealthCheckedConnection::SendNextHeartbeat() { void HealthCheckedConnection::UpdateReceiveTimer() { - TimeInterval timeout_interval(static_cast( - 2.5 * m_heartbeat_interval.AsInt())); m_receive_timeout_id = m_scheduler->RegisterSingleTimeout( - timeout_interval, + m_timeout_interval, NewSingleCallback( this, &HealthCheckedConnection::InternalHeartbeatTimeout)); } diff --git a/common/network/HealthCheckedConnectionTest.cpp b/common/network/HealthCheckedConnectionTest.cpp index 4a6a09d9de..6f07f9e1d7 100644 --- a/common/network/HealthCheckedConnectionTest.cpp +++ b/common/network/HealthCheckedConnectionTest.cpp @@ -56,10 +56,26 @@ class MockHealthCheckedConnection: public HealthCheckedConnection { MockHealthCheckedConnection(ola::io::ConnectedDescriptor *descriptor, SelectServer *scheduler, + const ola::TimeInterval heartbeat_interval, const ola::TimeInterval timeout_interval, const Options &options, MockClock *clock) - : HealthCheckedConnection(scheduler, timeout_interval), + : HealthCheckedConnection(scheduler, heartbeat_interval, timeout_interval), + m_descriptor(descriptor), + m_ss(scheduler), + m_options(options), + m_next_heartbeat(0), + m_expected_heartbeat(0), + m_channel_ok(true), + m_clock(clock) { + } + + MockHealthCheckedConnection(ola::io::ConnectedDescriptor *descriptor, + SelectServer *scheduler, + const ola::TimeInterval heartbeat_interval, + const Options &options, + MockClock *clock) + : HealthCheckedConnection(scheduler, heartbeat_interval), m_descriptor(descriptor), m_ss(scheduler), m_options(options), @@ -70,8 +86,10 @@ class MockHealthCheckedConnection: public HealthCheckedConnection { } void SendHeartbeat() { + OLA_DEBUG << "Maybe send heartbeat"; if (m_options.send_every == 0 || m_next_heartbeat % m_options.send_every == 0) { + OLA_DEBUG << "Sending heartbeat"; m_descriptor->Send(&m_next_heartbeat, sizeof(m_next_heartbeat)); } m_clock->AdvanceTime(0, 180000); @@ -115,13 +133,18 @@ class HealthCheckedConnectionTest: public CppUnit::TestFixture { HealthCheckedConnectionTest() : CppUnit::TestFixture(), m_ss(NULL, &m_clock), - heartbeat_interval(0, 200000) { + heartbeat_interval(0, 200000), + // Allow a little bit of wiggle room so we don't hit timing issues + // when running the tests + timeout_interval(0, 650000) { } CPPUNIT_TEST_SUITE(HealthCheckedConnectionTest); CPPUNIT_TEST(testSimpleChannel); CPPUNIT_TEST(testChannelWithPacketLoss); CPPUNIT_TEST(testChannelWithHeavyPacketLoss); + CPPUNIT_TEST(testChannelWithHeavyPacketLossLongerTimeout); + CPPUNIT_TEST(testChannelWithVeryHeavyPacketLossLongerTimeout); CPPUNIT_TEST(testPauseAndResume); CPPUNIT_TEST_SUITE_END(); @@ -131,6 +154,8 @@ class HealthCheckedConnectionTest: public CppUnit::TestFixture { void testSimpleChannel(); void testChannelWithPacketLoss(); void testChannelWithHeavyPacketLoss(); + void testChannelWithHeavyPacketLossLongerTimeout(); + void testChannelWithVeryHeavyPacketLossLongerTimeout(); void testPauseAndResume(); void PauseReading(MockHealthCheckedConnection *connection) { @@ -148,6 +173,7 @@ class HealthCheckedConnectionTest: public CppUnit::TestFixture { SelectServer m_ss; LoopbackDescriptor socket; TimeInterval heartbeat_interval; + TimeInterval timeout_interval; MockHealthCheckedConnection::Options options; }; @@ -206,7 +232,7 @@ void HealthCheckedConnectionTest::testChannelWithPacketLoss() { /** - * Check the channel works when every 2nd heartbeat is lost + * Check the channel fails when 2 of every 3 heartbeats are lost */ void HealthCheckedConnectionTest::testChannelWithHeavyPacketLoss() { options.send_every = 3; @@ -228,6 +254,55 @@ void HealthCheckedConnectionTest::testChannelWithHeavyPacketLoss() { } +/** + * Check the channel works when 2 of every 3 heartbeats are lost but the + * timeout interval is 3 * heartbeat_interval rather than the default + */ +void HealthCheckedConnectionTest::testChannelWithHeavyPacketLossLongerTimeout() { + options.send_every = 3; + MockHealthCheckedConnection connection(&socket, + &m_ss, + heartbeat_interval, + timeout_interval, + options, + &m_clock); + + socket.SetOnData( + NewCallback(&connection, &MockHealthCheckedConnection::ReadData)); + connection.Setup(); + m_ss.AddReadDescriptor(&socket); + connection.Setup(); + + m_ss.Run(); + OLA_ASSERT_TRUE(connection.ChannelOk()); +} + + +/** + * Check the channel fails when 3 of every 4 heartbeats are lost even though + * the timeout interval is 3 * heartbeat_interval + */ +void HealthCheckedConnectionTest::testChannelWithVeryHeavyPacketLossLongerTimeout() { + options.send_every = 4; + options.abort_on_failure = false; + MockHealthCheckedConnection connection(&socket, + &m_ss, + heartbeat_interval, + timeout_interval, + options, + &m_clock); + + socket.SetOnData( + NewCallback(&connection, &MockHealthCheckedConnection::ReadData)); + connection.Setup(); + m_ss.AddReadDescriptor(&socket); + connection.Setup(); + + m_ss.Run(); + OLA_ASSERT_FALSE(connection.ChannelOk()); +} + + /** * Check pausing doesn't mark the channel as bad. */ diff --git a/include/ola/network/HealthCheckedConnection.h b/include/ola/network/HealthCheckedConnection.h index a4311f51eb..dc6a64b06d 100644 --- a/include/ola/network/HealthCheckedConnection.h +++ b/include/ola/network/HealthCheckedConnection.h @@ -18,16 +18,17 @@ * * This class adds health checking to a connection, which ensures that the * connection is able to transfer data in a timely manner. The implementation - * is pretty simple: we define a heart beat interval I, which *must* be the + * is pretty simple: we define a heartbeat interval I, which *must* be the * same at both ends of the connection. Every I seconds, both ends send a - * heart beat message and if either end doesn't receive a heart beat in - * 2.5 * I, the connection is deemed dead, and the connection is closed. + * heartbeat message and if either end doesn't receive a heartbeat within the + * timeout interval (which defaults to 2.5 * I if not specified), the + * connection is deemed dead, and the connection is closed. * * This class provides the basic health check mechanism, the sub class is left * to define the format of the heartbeat message. * * To use this health checked channel, subclass HealthCheckedConnection, and - * provide the SendHeartbeat() and HeartbeatTimeout methods. + * provide the SendHeartbeat() and HeartbeatTimeout() methods. * * There are some additional features: * - Some receivers may want to stop reading from a connection under some @@ -57,7 +58,10 @@ namespace network { class HealthCheckedConnection { public: HealthCheckedConnection(ola::thread::SchedulerInterface *scheduler, + const ola::TimeInterval heartbeat_interval, const ola::TimeInterval timeout_interval); + HealthCheckedConnection(ola::thread::SchedulerInterface *scheduler, + const ola::TimeInterval heartbeat_interval); virtual ~HealthCheckedConnection(); /** @@ -106,6 +110,7 @@ class HealthCheckedConnection { private: ola::thread::SchedulerInterface *m_scheduler; ola::TimeInterval m_heartbeat_interval; + ola::TimeInterval m_timeout_interval; ola::thread::timeout_id m_send_timeout_id; ola::thread::timeout_id m_receive_timeout_id; From 9fab74913e2d43936a4ce5aa1bb2415a79667f03 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Mon, 3 Jul 2023 17:55:57 +0100 Subject: [PATCH 58/71] Add some more new simple E1.33 inflators Tests still required for these! --- libs/acn/BrokerClientAddInflator.h | 55 ++++++++++++++++++++++ libs/acn/BrokerClientEntryChangeInflator.h | 55 ++++++++++++++++++++++ libs/acn/BrokerClientRemoveInflator.h | 55 ++++++++++++++++++++++ libs/acn/BrokerInflator.h | 55 ++++++++++++++++++++++ libs/acn/BrokerNullInflator.h | 55 ++++++++++++++++++++++ libs/acn/Makefile.mk | 5 ++ 6 files changed, 280 insertions(+) create mode 100644 libs/acn/BrokerClientAddInflator.h create mode 100644 libs/acn/BrokerClientEntryChangeInflator.h create mode 100644 libs/acn/BrokerClientRemoveInflator.h create mode 100644 libs/acn/BrokerInflator.h create mode 100644 libs/acn/BrokerNullInflator.h diff --git a/libs/acn/BrokerClientAddInflator.h b/libs/acn/BrokerClientAddInflator.h new file mode 100644 index 0000000000..14af53fe16 --- /dev/null +++ b/libs/acn/BrokerClientAddInflator.h @@ -0,0 +1,55 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * BrokerClientAddInflator.h + * Interface for the BrokerClientAddInflator class. + * Copyright (C) 2023 Peter Newman + */ + +#ifndef LIBS_ACN_BROKERCLIENTADDINFLATOR_H_ +#define LIBS_ACN_BROKERCLIENTADDINFLATOR_H_ + +#include "ola/acn/ACNVectors.h" +#include "libs/acn/BaseInflator.h" + +namespace ola { +namespace acn { + +class BrokerClientAddInflator: public BaseInflator { + friend class BrokerClientAddInflatorTest; + + public: + BrokerClientAddInflator() + : BaseInflator() { + } + ~BrokerClientAddInflator() {} + + uint32_t Id() const { return ola::acn::VECTOR_BROKER_CLIENT_ADD; } + + protected: + // The 'header' is 0 bytes in length. + bool DecodeHeader(HeaderSet*, + const uint8_t*, + unsigned int, + unsigned int *bytes_used) { + *bytes_used = 0; + return true; + } + + void ResetHeaderField() {} // namespace noop +}; +} // namespace acn +} // namespace ola +#endif // LIBS_ACN_BROKERCLIENTADDINFLATOR_H_ diff --git a/libs/acn/BrokerClientEntryChangeInflator.h b/libs/acn/BrokerClientEntryChangeInflator.h new file mode 100644 index 0000000000..9827a60618 --- /dev/null +++ b/libs/acn/BrokerClientEntryChangeInflator.h @@ -0,0 +1,55 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * BrokerClientEntryChangeInflator.h + * Interface for the BrokerClientEntryChangeInflator class. + * Copyright (C) 2023 Peter Newman + */ + +#ifndef LIBS_ACN_BROKERCLIENTENTRYCHANGEINFLATOR_H_ +#define LIBS_ACN_BROKERCLIENTENTRYCHANGEINFLATOR_H_ + +#include "ola/acn/ACNVectors.h" +#include "libs/acn/BaseInflator.h" + +namespace ola { +namespace acn { + +class BrokerClientEntryChangeInflator: public BaseInflator { + friend class BrokerClientEntryChangeInflatorTest; + + public: + BrokerClientEntryChangeInflator() + : BaseInflator() { + } + ~BrokerClientEntryChangeInflator() {} + + uint32_t Id() const { return ola::acn::VECTOR_BROKER_CLIENT_ENTRY_CHANGE; } + + protected: + // The 'header' is 0 bytes in length. + bool DecodeHeader(HeaderSet*, + const uint8_t*, + unsigned int, + unsigned int *bytes_used) { + *bytes_used = 0; + return true; + } + + void ResetHeaderField() {} // namespace noop +}; +} // namespace acn +} // namespace ola +#endif // LIBS_ACN_BROKERCLIENTENTRYCHANGEINFLATOR_H_ diff --git a/libs/acn/BrokerClientRemoveInflator.h b/libs/acn/BrokerClientRemoveInflator.h new file mode 100644 index 0000000000..4117139350 --- /dev/null +++ b/libs/acn/BrokerClientRemoveInflator.h @@ -0,0 +1,55 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * BrokerClientRemoveInflator.h + * Interface for the BrokerClientRemoveInflator class. + * Copyright (C) 2023 Peter Newman + */ + +#ifndef LIBS_ACN_BROKERCLIENTREMOVEINFLATOR_H_ +#define LIBS_ACN_BROKERCLIENTREMOVEINFLATOR_H_ + +#include "ola/acn/ACNVectors.h" +#include "libs/acn/BaseInflator.h" + +namespace ola { +namespace acn { + +class BrokerClientRemoveInflator: public BaseInflator { + friend class BrokerClientRemoveInflatorTest; + + public: + BrokerClientRemoveInflator() + : BaseInflator() { + } + ~BrokerClientRemoveInflator() {} + + uint32_t Id() const { return ola::acn::VECTOR_BROKER_CLIENT_REMOVE; } + + protected: + // The 'header' is 0 bytes in length. + bool DecodeHeader(HeaderSet*, + const uint8_t*, + unsigned int, + unsigned int *bytes_used) { + *bytes_used = 0; + return true; + } + + void ResetHeaderField() {} // namespace noop +}; +} // namespace acn +} // namespace ola +#endif // LIBS_ACN_BROKERCLIENTREMOVEINFLATOR_H_ diff --git a/libs/acn/BrokerInflator.h b/libs/acn/BrokerInflator.h new file mode 100644 index 0000000000..58da325542 --- /dev/null +++ b/libs/acn/BrokerInflator.h @@ -0,0 +1,55 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * BrokerInflator.h + * Interface for the BrokerInflator class. + * Copyright (C) 2023 Peter Newman + */ + +#ifndef LIBS_ACN_BROKERINFLATOR_H_ +#define LIBS_ACN_BROKERINFLATOR_H_ + +#include "ola/acn/ACNVectors.h" +#include "libs/acn/BaseInflator.h" + +namespace ola { +namespace acn { + +class BrokerInflator: public BaseInflator { + friend class BrokerInflatorTest; + + public: + BrokerInflator() + : BaseInflator(PDU::TWO_BYTES) { + } + ~BrokerInflator() {} + + uint32_t Id() const { return ola::acn::VECTOR_ROOT_BROKER; } + + protected: + // The 'header' is 0 bytes in length. + bool DecodeHeader(HeaderSet*, + const uint8_t*, + unsigned int, + unsigned int *bytes_used) { + *bytes_used = 0; + return true; + } + + void ResetHeaderField() {} // namespace noop +}; +} // namespace acn +} // namespace ola +#endif // LIBS_ACN_BROKERINFLATOR_H_ diff --git a/libs/acn/BrokerNullInflator.h b/libs/acn/BrokerNullInflator.h new file mode 100644 index 0000000000..28a641c722 --- /dev/null +++ b/libs/acn/BrokerNullInflator.h @@ -0,0 +1,55 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * BrokerNullInflator.h + * Interface for the BrokerNullInflator class. + * Copyright (C) 2023 Peter Newman + */ + +#ifndef LIBS_ACN_BROKERNULLINFLATOR_H_ +#define LIBS_ACN_BROKERNULLINFLATOR_H_ + +#include "ola/acn/ACNVectors.h" +#include "libs/acn/BaseInflator.h" + +namespace ola { +namespace acn { + +class BrokerNullInflator: public BaseInflator { + friend class BrokerNullInflatorTest; + + public: + BrokerNullInflator() + : BaseInflator() { + } + ~BrokerNullInflator() {} + + uint32_t Id() const { return ola::acn::VECTOR_BROKER_NULL; } + + protected: + // The 'header' is 0 bytes in length. + bool DecodeHeader(HeaderSet*, + const uint8_t*, + unsigned int, + unsigned int *bytes_used) { + *bytes_used = 0; + return true; + } + + void ResetHeaderField() {} // namespace noop +}; +} // namespace acn +} // namespace ola +#endif // LIBS_ACN_BROKERNULLINFLATOR_H_ diff --git a/libs/acn/Makefile.mk b/libs/acn/Makefile.mk index 4d89196233..7c02570ed9 100644 --- a/libs/acn/Makefile.mk +++ b/libs/acn/Makefile.mk @@ -31,11 +31,16 @@ noinst_LTLIBRARIES += libs/acn/libolae131core.la libs_acn_libolae131core_la_SOURCES = \ libs/acn/BaseInflator.cpp \ libs/acn/BaseInflator.h \ + libs/acn/BrokerClientAddInflator.h \ + libs/acn/BrokerClientEntryChangeInflator.h \ libs/acn/BrokerClientEntryHeader.h \ libs/acn/BrokerClientEntryPDU.cpp \ libs/acn/BrokerClientEntryPDU.h \ + libs/acn/BrokerClientRemoveInflator.h \ libs/acn/BrokerConnectPDU.cpp \ libs/acn/BrokerConnectPDU.h \ + libs/acn/BrokerInflator.h \ + libs/acn/BrokerNullInflator.h \ libs/acn/BrokerNullPDU.cpp \ libs/acn/BrokerNullPDU.h \ libs/acn/BrokerPDU.cpp \ From 6d4d923a37dd575f2991862fb215d0a11b040c6f Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Mon, 3 Jul 2023 18:01:06 +0100 Subject: [PATCH 59/71] More E1.33 vectors --- include/ola/acn/ACNVectors.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/ola/acn/ACNVectors.h b/include/ola/acn/ACNVectors.h index fe75a05a5c..3a1d1cb741 100644 --- a/include/ola/acn/ACNVectors.h +++ b/include/ola/acn/ACNVectors.h @@ -120,6 +120,17 @@ enum BrokerVector { VECTOR_BROKER_NULL = 0x000F, /**< Broker Client Null */ }; +// Table A-21, Client Protocol Codes +// These aren't fully named as vectors in the standard, but are used as such so +// we put them in here +/** + * @brief Vectors used at the E1.33 Broker Client Entry layer. + */ +enum ClientProtocolCode { + CLIENT_PROTOCOL_RPT = 0x00000005, /**< Broker RPT Client Entry */ + CLIENT_PROTOCOL_EPT = 0x0000000b, /**< Broker EPT Client Entry */ +}; + /** * @} */ From 81b8e38432d2720210156f0755b0a1979d929ddd Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Mon, 3 Jul 2023 18:04:15 +0100 Subject: [PATCH 60/71] Fix a minor typo --- libs/acn/LLRPProbeReplyInflator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/acn/LLRPProbeReplyInflator.cpp b/libs/acn/LLRPProbeReplyInflator.cpp index 153433c166..6da01971cf 100644 --- a/libs/acn/LLRPProbeReplyInflator.cpp +++ b/libs/acn/LLRPProbeReplyInflator.cpp @@ -44,7 +44,7 @@ LLRPProbeReplyInflator::LLRPProbeReplyInflator() /** * Set an LLRPProbeReplyHandler to run when receiving an LLRP Probe Reply * message. - * @param handler the callback to invoke when there is and LLRP Probe Reply. + * @param handler the callback to invoke when there is an LLRP Probe Reply. */ void LLRPProbeReplyInflator::SetLLRPProbeReplyHandler( LLRPProbeReplyHandler *handler) { From b23bc6bcd54dcf152e9a4b269401712318c032ee Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Mon, 3 Jul 2023 18:07:06 +0100 Subject: [PATCH 61/71] A few more E1.33 enums --- include/ola/e133/E133Enums.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/ola/e133/E133Enums.h b/include/ola/e133/E133Enums.h index f4c2b4ac06..f8e81767f8 100644 --- a/include/ola/e133/E133Enums.h +++ b/include/ola/e133/E133Enums.h @@ -53,10 +53,21 @@ enum E133StatusCode { SC_E133_BROADCAST_COMPLETE = 0x0009, }; +// Table A-22 E1.33 RPT Client Type Codes +enum E133RPTClientTypeCode { + RPT_CLIENT_TYPE_DEVICE = 0x00, + RPT_CLIENT_TYPE_CONTROLLER = 0x01, +}; + // The max size of an E1.33 Status string. enum { MAX_E133_STATUS_STRING_SIZE = 64 }; + +// The E1.33 version.. +enum { + E133_VERSION = 1 +}; } // namespace e133 } // namespace ola #endif // INCLUDE_OLA_E133_E133ENUMS_H_ From bdb40db292dda2f280db66c738c120d6a7fa5c45 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Mon, 3 Jul 2023 18:17:55 +0100 Subject: [PATCH 62/71] Add the ability to build BrokerNullTCP packets --- include/ola/e133/MessageBuilder.h | 4 ++++ tools/e133/MessageBuilder.cpp | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/include/ola/e133/MessageBuilder.h b/include/ola/e133/MessageBuilder.h index 272a56339a..ebff6ffe58 100644 --- a/include/ola/e133/MessageBuilder.h +++ b/include/ola/e133/MessageBuilder.h @@ -48,6 +48,10 @@ class MessageBuilder { void BuildNullTCPPacket(IOStack *packet); + void BuildBrokerFetchClientListTCPPacket(IOStack *packet); + + void BuildBrokerNullTCPPacket(IOStack *packet); + void BuildTCPE133StatusPDU(IOStack *packet, uint32_t sequence_number, uint16_t endpoint_id, ola::e133::E133StatusCode status_code, diff --git a/tools/e133/MessageBuilder.cpp b/tools/e133/MessageBuilder.cpp index a192b45bf0..eed3b85961 100644 --- a/tools/e133/MessageBuilder.cpp +++ b/tools/e133/MessageBuilder.cpp @@ -25,6 +25,7 @@ #include "ola/e133/MessageBuilder.h" #include "ola/io/IOStack.h" +#include "libs/acn/BrokerPDU.h" #include "libs/acn/E133PDU.h" #include "libs/acn/RDMPDU.h" #include "libs/acn/RootPDU.h" @@ -36,6 +37,7 @@ namespace e133 { using ola::acn::CID; using ola::io::IOStack; +using ola::acn::BrokerPDU; using ola::acn::E133PDU; using ola::acn::PreamblePacker; using ola::acn::RootPDU; @@ -67,6 +69,16 @@ void MessageBuilder::BuildNullTCPPacket(IOStack *packet) { } +/** + * Build a Broker NULL TCP packet. These packets can be used for broker heartbeats. + */ +void MessageBuilder::BuildBrokerNullTCPPacket(IOStack *packet) { + BrokerPDU::PrependPDU(packet, ola::acn::VECTOR_BROKER_NULL); + RootPDU::PrependPDU(packet, ola::acn::VECTOR_ROOT_BROKER, m_cid, true); + PreamblePacker::AddTCPPreamble(packet); +} + + /** * Build a TCP E1.33 Status PDU response. This should really only be used with * SC_E133_ACK. From 847734f7527568c8ad380d60f327e96243f8e10b Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Mon, 3 Jul 2023 18:19:10 +0100 Subject: [PATCH 63/71] Correctly commit only a partial change for now --- include/ola/e133/MessageBuilder.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/ola/e133/MessageBuilder.h b/include/ola/e133/MessageBuilder.h index ebff6ffe58..a94d52200c 100644 --- a/include/ola/e133/MessageBuilder.h +++ b/include/ola/e133/MessageBuilder.h @@ -48,8 +48,6 @@ class MessageBuilder { void BuildNullTCPPacket(IOStack *packet); - void BuildBrokerFetchClientListTCPPacket(IOStack *packet); - void BuildBrokerNullTCPPacket(IOStack *packet); void BuildTCPE133StatusPDU(IOStack *packet, From 4d7049caf766586177248d1fbba0b31b7185633d Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Mon, 3 Jul 2023 18:29:12 +0100 Subject: [PATCH 64/71] Update E133HealthCheckedConnection to work with the new standardised heartbeat behaviour and timing --- tools/e133/E133HealthCheckedConnection.cpp | 8 +++++--- tools/e133/E133HealthCheckedConnection.h | 17 ++++++++++++----- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/tools/e133/E133HealthCheckedConnection.cpp b/tools/e133/E133HealthCheckedConnection.cpp index f03e7e5dc7..c6dd17f663 100644 --- a/tools/e133/E133HealthCheckedConnection.cpp +++ b/tools/e133/E133HealthCheckedConnection.cpp @@ -39,8 +39,9 @@ E133HealthCheckedConnection::E133HealthCheckedConnection( ola::io::NonBlockingSender *message_queue, ola::SingleUseCallback0 *on_timeout, ola::thread::SchedulingExecutorInterface *scheduler, - const ola::TimeInterval heartbeat_interval) - : HealthCheckedConnection(scheduler, heartbeat_interval), + const ola::TimeInterval heartbeat_interval, + const ola::TimeInterval timeout_interval) + : HealthCheckedConnection(scheduler, heartbeat_interval, timeout_interval), m_message_builder(message_builder), m_message_queue(message_queue), m_on_timeout(on_timeout), @@ -52,8 +53,9 @@ E133HealthCheckedConnection::E133HealthCheckedConnection( * Send a E1.33 heartbeat */ void E133HealthCheckedConnection::SendHeartbeat() { + OLA_DEBUG << "Sending heartbeat"; IOStack packet(m_message_builder->pool()); - m_message_builder->BuildNullTCPPacket(&packet); + m_message_builder->BuildBrokerNullTCPPacket(&packet); m_message_queue->SendMessage(&packet); } diff --git a/tools/e133/E133HealthCheckedConnection.h b/tools/e133/E133HealthCheckedConnection.h index 5e7b61453a..3e6712cb30 100644 --- a/tools/e133/E133HealthCheckedConnection.h +++ b/tools/e133/E133HealthCheckedConnection.h @@ -21,9 +21,12 @@ * same health checking logic (and agree on heartbeat intervals) for this to * work correctly. * - * Even though this is called a E1.33 Health Checked Connection, it doesn't - * actually rely on E1.33 at all. You can use it with any ACN based protocol - * since it just sends PDUs with a ROOT_VECTOR_NULL as heartbeat messages. + * This is a E1.33 Health Checked Connection as it sends E1.33 Broker NULL PDUs + * using VECTOR_BROKER_NULL, but it also accepts any ACN root layer PDUs as a + * positive indication the connection is healthy. + * + * You could use it with any ACN based protocol by subclassing it and sending + * heartbeat messages of ROOT_VECTOR_NULL via SendHeartbeat instead. */ #ifndef TOOLS_E133_E133HEALTHCHECKEDCONNECTION_H_ @@ -52,7 +55,9 @@ class E133HealthCheckedConnection ola::SingleUseCallback0 *on_timeout, ola::thread::SchedulingExecutorInterface *scheduler, const ola::TimeInterval heartbeat_interval = - ola::TimeInterval(E133_TCP_HEARTBEAT_INTERVAL, 0)); + ola::TimeInterval(E133_TCP_HEARTBEAT_INTERVAL, 0), + const ola::TimeInterval timeout_interval = + ola::TimeInterval(E133_HEARTBEAT_TIMEOUT, 0)); void SendHeartbeat(); void HeartbeatTimeout(); @@ -64,6 +69,8 @@ class E133HealthCheckedConnection ola::thread::SchedulingExecutorInterface *m_executor; // The default interval in seconds for sending heartbeat messages. - static const unsigned int E133_TCP_HEARTBEAT_INTERVAL = 5; + static const unsigned int E133_TCP_HEARTBEAT_INTERVAL = 15; + // The default interval in seconds before timing out. + static const unsigned int E133_HEARTBEAT_TIMEOUT = 45; }; #endif // TOOLS_E133_E133HEALTHCHECKEDCONNECTION_H_ From a5775352a3d1ff32a042c3d50bdac8257eec6f5d Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Mon, 3 Jul 2023 23:10:20 +0100 Subject: [PATCH 65/71] Fix a lint issue --- common/network/HealthCheckedConnectionTest.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/common/network/HealthCheckedConnectionTest.cpp b/common/network/HealthCheckedConnectionTest.cpp index 6f07f9e1d7..3664d7825e 100644 --- a/common/network/HealthCheckedConnectionTest.cpp +++ b/common/network/HealthCheckedConnectionTest.cpp @@ -60,7 +60,9 @@ class MockHealthCheckedConnection: public HealthCheckedConnection { const ola::TimeInterval timeout_interval, const Options &options, MockClock *clock) - : HealthCheckedConnection(scheduler, heartbeat_interval, timeout_interval), + : HealthCheckedConnection(scheduler, + heartbeat_interval, + timeout_interval), m_descriptor(descriptor), m_ss(scheduler), m_options(options), From 7686be6a02789205cfcab07d88ffddf2941b350b Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Mon, 3 Jul 2023 23:20:11 +0100 Subject: [PATCH 66/71] Temporarily remove the the PIDs with IPV6 type in them until we support it properly --- data/rdm/pids.proto | 188 -------------------------------------------- 1 file changed, 188 deletions(-) diff --git a/data/rdm/pids.proto b/data/rdm/pids.proto index 0ca443ce29..cebb8ef20e 100644 --- a/data/rdm/pids.proto +++ b/data/rdm/pids.proto @@ -4010,142 +4010,6 @@ pid { } set_sub_device_range: ROOT_OR_ALL_SUBDEVICE } -pid { - name: "COMPONENT_SCOPE" - value: 2048 - get_request { - field { - type: UINT16 - name: "scope_slot" - range { - min: 1 - max: 65535 - } - } - } - get_response { - field { - type: UINT16 - name: "scope_slot" - range { - min: 1 - max: 65535 - } - } - field { - type: STRING - name: "scope_string" - max_size: 63 - } - field { - type: UINT8 - name: "static_config_type" - label { - value: 0 - label: "No static config" - } - label { - value: 1 - label: "Static config IPv4" - } - label { - value: 1 - label: "Static config IPv6" - } - range { - min: 0 - max: 2 - } - } - field { - type: IPV4 - name: "static_broker_ipv4_address" - label { - value: 0 - label: "No static broker IPv4 address" - } - } - field { - type: IPV6 - name: "static_broker_ipv6_address" - label { - value: 0 - label: "No static broker IPv6 address" - } - } - field { - type: UINT16 - name: "static_broker_port" - label { - value: 0 - label: "No static broker port" - } - } - } - get_sub_device_range: ROOT_DEVICE - set_request { - field { - type: UINT16 - name: "scope_slot" - range { - min: 1 - max: 65535 - } - } - field { - type: STRING - name: "scope_string" - max_size: 63 - } - field { - type: UINT8 - name: "static_config_type" - label { - value: 0 - label: "No static config" - } - label { - value: 1 - label: "Static config IPv4" - } - label { - value: 1 - label: "Static config IPv6" - } - range { - min: 0 - max: 2 - } - } - field { - type: IPV4 - name: "static_broker_ipv4_address" - label { - value: 0 - label: "No static broker IPv4 address" - } - } - field { - type: IPV6 - name: "static_broker_ipv6_address" - label { - value: 0 - label: "No static broker IPv6 address" - } - } - field { - type: UINT16 - name: "static_broker_port" - label { - value: 0 - label: "No static broker port" - } - } - } - set_response { - } - set_sub_device_range: ROOT_DEVICE -} pid { name: "SEARCH_DOMAIN" value: 2049 @@ -4172,58 +4036,6 @@ pid { } set_sub_device_range: ROOT_DEVICE } -pid { - name: "TCP_COMMS_STATUS" - value: 2050 - get_request { - } - get_response { - field { - type: GROUP - name: "comms_statuses" - field { - type: STRING - name: "scope_string" - max_size: 63 - } - field { - type: IPV4 - name: "broker_ipv4_address" - label { - value: 0 - label: "No IPv4 Connection" - } - } - field { - type: IPV6 - name: "broker_ipv6_address" - label { - value: 0 - label: "No IPv6 Connection" - } - } - field { - type: UINT16 - name: "broker_port" - } - field { - type: UINT16 - name: "unhealthy_tcp_events" - } - } - } - get_sub_device_range: ROOT_DEVICE - set_request { - field { - type: STRING - name: "scope_string" - max_size: 63 - } - } - set_response { - } - set_sub_device_range: ROOT_DEVICE -} pid { name: "BROKER_STATUS" value: 2051 From 1a027aced39d813eb8c0531ff3040ad3d23ab364 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Sat, 8 Jul 2023 21:43:54 +0100 Subject: [PATCH 67/71] Add some more enums --- include/ola/acn/ACNVectors.h | 51 +++++++++++++++++++++++++++++++++++- include/ola/e133/E133Enums.h | 33 +++++++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/include/ola/acn/ACNVectors.h b/include/ola/acn/ACNVectors.h index 3a1d1cb741..8734583e81 100644 --- a/include/ola/acn/ACNVectors.h +++ b/include/ola/acn/ACNVectors.h @@ -120,6 +120,55 @@ enum BrokerVector { VECTOR_BROKER_NULL = 0x000F, /**< Broker Client Null */ }; +// Table A-8, RPT PDU Vector +/** + * @brief Vectors used at the E1.33 RPT layer. + */ +enum RPTVector { + VECTOR_RPT_REQUEST = 1, /**< RPT Request */ + VECTOR_RPT_STATUS = 2, /**< RPT Status */ + VECTOR_RPT_NOTIFICATION = 3, /**< RPT Notification */ +}; + +// Table A-9, RPT Request PDU Vector +/** + * @brief Vectors used at the E1.33 RPT Request layer. + */ +enum RPTRequestVector { + VECTOR_REQUEST_RDM_CMD = 1, /**< RPT Request RDM Command */ +}; + +// Table A-10, RPT Status PDU Vector +/** + * @brief Vectors used at the E1.33 RPT Status layer. + */ +enum RPTStatusVector { + VECTOR_RPT_STATUS_UNKNOWN_RPT_UID = 0x0001, /**< RPT Status Unknown RPT UID */ + VECTOR_RPT_STATUS_RDM_TIMEOUT = 0x0002, /**< RPT Status RDM Timeout */ + VECTOR_RPT_STATUS_RDM_INVALID_RESPONSE = 0x0003, /**< RPT Status RDM Invalid Response */ + VECTOR_RPT_STATUS_UNKNOWN_RDM_UID = 0x0004, /**< RPT Status Unknown RDM UID */ + VECTOR_RPT_STATUS_UNKNOWN_ENDPOINT = 0x0005, /**< RPT Status Unknown Endpoint */ + VECTOR_RPT_STATUS_BROADCAST_COMPLETE = 0x0006, /**< RPT Status Broadcast Complete */ + VECTOR_RPT_STATUS_UNKNOWN_VECTOR = 0x0007, /**< RPT Status Unknown Vector */ + VECTOR_RPT_STATUS_INVALID_MESSAGE = 0x0008, /**< RPT Status Invalid Message */ + VECTOR_RPT_STATUS_INVALID_COMMAND_CLASS = 0x0009, /**< RPT Status Invalid Command Class */ +}; + +// Table A-11, RPT Notification PDU Vector +/** + * @brief Vectors used at the E1.33 RPT Notification layer. + */ +enum RPTNotificationVector { + VECTOR_NOTIFICATION_RDM_CMD = 1, /**< RPT Notification RDM Command */ +}; + +/** + * @brief Vectors used at the E1.33 RDM Command layer. + */ +enum RDMCommandVector { + VECTOR_RDM_CMD_RDM_DATA = 0xCC, /**< E1.33 RDM Command */ +}; + // Table A-21, Client Protocol Codes // These aren't fully named as vectors in the standard, but are used as such so // we put them in here @@ -128,7 +177,7 @@ enum BrokerVector { */ enum ClientProtocolCode { CLIENT_PROTOCOL_RPT = 0x00000005, /**< Broker RPT Client Entry */ - CLIENT_PROTOCOL_EPT = 0x0000000b, /**< Broker EPT Client Entry */ + CLIENT_PROTOCOL_EPT = 0x0000000B, /**< Broker EPT Client Entry */ }; /** diff --git a/include/ola/e133/E133Enums.h b/include/ola/e133/E133Enums.h index f8e81767f8..888ececf35 100644 --- a/include/ola/e133/E133Enums.h +++ b/include/ola/e133/E133Enums.h @@ -39,6 +39,7 @@ enum EndpointMode { ENDPOINT_MODE_OUTPUT = 2, }; +// TODO(Peter): Check that this no longer exists // Table A-9 E1.33 Status Codes enum E133StatusCode { SC_E133_ACK = 0x0000, @@ -53,12 +54,44 @@ enum E133StatusCode { SC_E133_BROADCAST_COMPLETE = 0x0009, }; +// Table A-19 E1.33 Connection Status Codes for Broker Connect +enum E133ConnectStatusCode { + CONNECT_OK = 0x0000, + CONNECT_SCOPE_MISMATCH = 0x0001, + CONNECT_CAPACITY_EXCEEDED = 0x0002, + CONNECT_DUPLICATE_UID = 0x0003, + CONNECT_INVALID_CLIENT_ENTRY = 0x0004, + CONNECT_INVALID_UID = 0x0005, +}; + +// Table A-20 E1.33 Status Codes for Dynamic UID Mapping +enum E133DynamicUIDStatusCode { + DYNAMIC_UID_STATUS_OK = 0x0000, + DYNAMIC_UID_STATUS_INVALID_REQUEST = 0x0001, + DYNAMIC_UID_STATUS_UID_NOT_FOUND = 0x0002, + DYNAMIC_UID_STATUS_DUPLICATE_RID = 0x0003, + DYNAMIC_UID_STATUS_CAPACITY_EXHAUSTED = 0x0004, +}; + // Table A-22 E1.33 RPT Client Type Codes enum E133RPTClientTypeCode { RPT_CLIENT_TYPE_DEVICE = 0x00, RPT_CLIENT_TYPE_CONTROLLER = 0x01, }; +// Table A-24 E1.33 Client Disconnect Reason Codes +enum E133DisconnectStatusCode { + DISCONNECT_SHUTDOWN = 0x0000, + DISCONNECT_CAPACITY_EXHAUSTED = 0x0001, + DISCONNECT_HARDWARE_FAULT = 0x0002, + DISCONNECT_SOFTWARE_FAULT = 0x0003, + DISCONNECT_SOFTWARE_RESET = 0x0004, + DISCONNECT_INCORRECT_SCOPE = 0x0005, + DISCONNECT_RPT_RECONFIGURE = 0x0006, + DISCONNECT_LLRP_RECONFIGURE = 0x0007, + DISCONNECT_USER_RECONFIGURE = 0x0008, +}; + // The max size of an E1.33 Status string. enum { MAX_E133_STATUS_STRING_SIZE = 64 From d1eb7b8ff4f3f8fce4149844d03cbb53a5a42ac7 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Sat, 8 Jul 2023 23:07:14 +0100 Subject: [PATCH 68/71] Update the RDM Inflator to the standardised E1.33 --- libs/acn/RDMInflator.cpp | 4 ++-- libs/acn/RDMInflator.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/acn/RDMInflator.cpp b/libs/acn/RDMInflator.cpp index a4e32166e1..9dba40ba45 100644 --- a/libs/acn/RDMInflator.cpp +++ b/libs/acn/RDMInflator.cpp @@ -74,13 +74,13 @@ bool RDMInflator::DecodeHeader(HeaderSet *, /* - * Handle a DMP PDU for E1.33. + * Handle an RDM PDU for E1.33. */ bool RDMInflator::HandlePDUData(uint32_t vector, const HeaderSet &headers, const uint8_t *data, unsigned int pdu_len) { - if (vector != VECTOR_RDMNET_DATA) { + if (vector != VECTOR_RDM_CMD_RDM_DATA) { OLA_INFO << "Not a RDM message, vector was " << vector; return true; } diff --git a/libs/acn/RDMInflator.h b/libs/acn/RDMInflator.h index 4c37cf6c0c..27b43fb7bb 100644 --- a/libs/acn/RDMInflator.h +++ b/libs/acn/RDMInflator.h @@ -46,6 +46,8 @@ class RDMInflator: public BaseInflator { const std::string& // rdm data > GenericRDMMessageHandler; + // TODO(Peter): Set a better default vector for RDM use (possibly the RPT + // one) RDMInflator(unsigned int vector = ola::acn::VECTOR_FRAMING_RDMNET); ~RDMInflator() {} @@ -54,8 +56,6 @@ class RDMInflator: public BaseInflator { void SetRDMHandler(RDMMessageHandler *handler); void SetGenericRDMHandler(GenericRDMMessageHandler *handler); - static const unsigned int VECTOR_RDMNET_DATA = 0xcc; - protected: bool DecodeHeader(HeaderSet *headers, const uint8_t *data, From 669e2e5fd5c15252223a6a22e5e1840d8d40be6d Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Sat, 8 Jul 2023 23:11:55 +0100 Subject: [PATCH 69/71] Add support inflator for a lot of E1.33 RPT PDUs --- libs/acn/HeaderSet.h | 8 ++- libs/acn/Makefile.mk | 5 ++ libs/acn/RPTHeader.h | 94 ++++++++++++++++++++++++++++++ libs/acn/RPTInflator.cpp | 73 +++++++++++++++++++++++ libs/acn/RPTInflator.h | 58 ++++++++++++++++++ libs/acn/RPTNotificationInflator.h | 55 +++++++++++++++++ libs/acn/RPTRequestInflator.h | 55 +++++++++++++++++ 7 files changed, 347 insertions(+), 1 deletion(-) create mode 100644 libs/acn/RPTHeader.h create mode 100644 libs/acn/RPTInflator.cpp create mode 100644 libs/acn/RPTInflator.h create mode 100644 libs/acn/RPTNotificationInflator.h create mode 100644 libs/acn/RPTRequestInflator.h diff --git a/libs/acn/HeaderSet.h b/libs/acn/HeaderSet.h index 06a56c26aa..ae4925e1b4 100644 --- a/libs/acn/HeaderSet.h +++ b/libs/acn/HeaderSet.h @@ -28,6 +28,7 @@ #include "libs/acn/E133Header.h" #include "libs/acn/LLRPHeader.h" #include "libs/acn/RootHeader.h" +#include "libs/acn/RPTHeader.h" #include "libs/acn/TransportHeader.h" namespace ola { @@ -60,6 +61,9 @@ class HeaderSet { const LLRPHeader &GetLLRPHeader() const { return m_llrp_header; } void SetLLRPHeader(const LLRPHeader &header) { m_llrp_header = header; } + const RPTHeader &GetRPTHeader() const { return m_rpt_header; } + void SetRPTHeader(const RPTHeader &header) { m_rpt_header = header; } + bool operator==(const HeaderSet &other) const { return ( m_transport_header == other.m_transport_header && @@ -67,7 +71,8 @@ class HeaderSet { m_e131_header == other.m_e131_header && m_e133_header == other.m_e133_header && m_dmp_header == other.m_dmp_header && - m_llrp_header == other.m_llrp_header); + m_llrp_header == other.m_llrp_header && + m_rpt_header == other.m_rpt_header); } private: @@ -77,6 +82,7 @@ class HeaderSet { E133Header m_e133_header; DMPHeader m_dmp_header; LLRPHeader m_llrp_header; + RPTHeader m_rpt_header; }; } // namespace acn } // namespace ola diff --git a/libs/acn/Makefile.mk b/libs/acn/Makefile.mk index 7c02570ed9..45c84e1619 100644 --- a/libs/acn/Makefile.mk +++ b/libs/acn/Makefile.mk @@ -104,6 +104,11 @@ libs_acn_libolae131core_la_SOURCES = \ libs/acn/RootPDU.h \ libs/acn/RootSender.cpp \ libs/acn/RootSender.h \ + libs/acn/RPTHeader.h \ + libs/acn/RPTInflator.cpp \ + libs/acn/RPTInflator.h \ + libs/acn/RPTNotificationInflator.h \ + libs/acn/RPTRequestInflator.h \ libs/acn/TCPTransport.cpp \ libs/acn/TCPTransport.h \ libs/acn/Transport.h \ diff --git a/libs/acn/RPTHeader.h b/libs/acn/RPTHeader.h new file mode 100644 index 0000000000..80bb34cb5f --- /dev/null +++ b/libs/acn/RPTHeader.h @@ -0,0 +1,94 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * RPTHeader.h + * The E1.33 RPT Header + * Copyright (C) 2023 Peter Newman + */ + +#ifndef LIBS_ACN_RPTHEADER_H_ +#define LIBS_ACN_RPTHEADER_H_ + +#include +#include + +#include +#include + +namespace ola { +namespace acn { + +/* + * Header for the E133 RPT layer + */ +class RPTHeader { + public: + RPTHeader() + : m_source_uid(0, 0), + m_source_endpoint(0), + m_destination_uid(0, 0), + m_destination_endpoint(0), + m_sequence(0) { + } + + RPTHeader(ola::rdm::UID source_uid, + uint16_t source_endpoint, + ola::rdm::UID destination_uid, + uint16_t destination_endpoint, + uint32_t sequence) + : m_source_uid(source_uid), + m_source_endpoint(source_endpoint), + m_destination_uid(destination_uid), + m_destination_endpoint(destination_endpoint), + m_sequence(sequence) { + } + ~RPTHeader() {} + + ola::rdm::UID SourceUID() const { return m_source_uid; } + uint16_t SourceEndpoint() const { return m_source_endpoint; } + ola::rdm::UID DestinationUID() const { return m_destination_uid; } + uint16_t DestinationEndpoint() const { return m_destination_endpoint; } + // TODO(Peter): Should the sequence number really be part of the header? + uint32_t Sequence() const { return m_sequence; } + + bool operator==(const RPTHeader &other) const { + return m_source_uid == other.m_source_uid && + m_source_endpoint == other.m_source_endpoint && + m_destination_uid == other.m_destination_uid && + m_destination_endpoint == other.m_destination_endpoint && + m_sequence == other.m_sequence; + } + + PACK( + struct rpt_pdu_header_s { + uint8_t source_uid[ola::rdm::UID::LENGTH]; + uint16_t source_endpoint; + uint8_t destination_uid[ola::rdm::UID::LENGTH]; + uint16_t destination_endpoint; + uint32_t sequence; + uint8_t reserved; + }); + typedef struct rpt_pdu_header_s rpt_pdu_header; + + private: + ola::rdm::UID m_source_uid; + uint16_t m_source_endpoint; + ola::rdm::UID m_destination_uid; + uint16_t m_destination_endpoint; + uint32_t m_sequence; +}; +} // namespace acn +} // namespace ola +#endif // LIBS_ACN_RPTHEADER_H_ diff --git a/libs/acn/RPTInflator.cpp b/libs/acn/RPTInflator.cpp new file mode 100644 index 0000000000..5d9cde6f50 --- /dev/null +++ b/libs/acn/RPTInflator.cpp @@ -0,0 +1,73 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * RPTInflator.cpp + * The Inflator for E1.33 RPT + * Copyright (C) 2023 Peter Newman + */ + +#include "ola/Logging.h" +#include "ola/network/NetworkUtils.h" +#include "libs/acn/RPTInflator.h" + +namespace ola { +namespace acn { + +using ola::network::NetworkToHost; + +/* + * Decode the E1.33 RPT headers. If data is null we're expected to use the + * last header we got. + * @param headers the HeaderSet to add to + * @param data a pointer to the data + * @param length length of the data + * @returns true if successful, false otherwise + */ +bool RPTInflator::DecodeHeader(HeaderSet *headers, + const uint8_t *data, + unsigned int length, + unsigned int *bytes_used) { + if (data) { + // the header bit was set, decode it + if (length >= sizeof(RPTHeader::rpt_pdu_header)) { + RPTHeader::rpt_pdu_header raw_header; + memcpy(&raw_header, data, sizeof(RPTHeader::rpt_pdu_header)); + RPTHeader header( + ola::rdm::UID(raw_header.source_uid), + NetworkToHost(raw_header.source_endpoint), + ola::rdm::UID(raw_header.destination_uid), + NetworkToHost(raw_header.destination_endpoint), + NetworkToHost(raw_header.sequence)); + m_last_header = header; + m_last_header_valid = true; + headers->SetRPTHeader(header); + *bytes_used = sizeof(RPTHeader::rpt_pdu_header); + return true; + } + *bytes_used = 0; + return false; + } + + // use the last header if it exists + *bytes_used = 0; + if (!m_last_header_valid) { + OLA_WARN << "Missing E1.33 RPT Header data"; + return false; + } + headers->SetRPTHeader(m_last_header); + return true; +} +} // namespace acn +} // namespace ola diff --git a/libs/acn/RPTInflator.h b/libs/acn/RPTInflator.h new file mode 100644 index 0000000000..1fd4eedaaf --- /dev/null +++ b/libs/acn/RPTInflator.h @@ -0,0 +1,58 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * RPTInflator.h + * Interface for the RPTInflator class. + * Copyright (C) 2023 Peter Newman + */ + +#ifndef LIBS_ACN_RPTINFLATOR_H_ +#define LIBS_ACN_RPTINFLATOR_H_ + +#include "ola/acn/ACNVectors.h" +#include "libs/acn/BaseInflator.h" +#include "libs/acn/RPTHeader.h" + +namespace ola { +namespace acn { + +class RPTInflator: public BaseInflator { + friend class RPTInflatorTest; + + public: + RPTInflator() + : BaseInflator(), + m_last_header_valid(false) { + } + ~RPTInflator() {} + + uint32_t Id() const { return ola::acn::VECTOR_ROOT_RPT; } + + protected: + bool DecodeHeader(HeaderSet *headers, + const uint8_t *data, + unsigned int len, + unsigned int *bytes_used); + + void ResetHeaderField() { + m_last_header_valid = false; + } + private: + RPTHeader m_last_header; + bool m_last_header_valid; +}; +} // namespace acn +} // namespace ola +#endif // LIBS_ACN_RPTINFLATOR_H_ diff --git a/libs/acn/RPTNotificationInflator.h b/libs/acn/RPTNotificationInflator.h new file mode 100644 index 0000000000..532fb45a54 --- /dev/null +++ b/libs/acn/RPTNotificationInflator.h @@ -0,0 +1,55 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * RPTNotificationInflator.h + * Interface for the RPTNotificationInflator class. + * Copyright (C) 2023 Peter Newman + */ + +#ifndef LIBS_ACN_RPTNOTIFICATIONINFLATOR_H_ +#define LIBS_ACN_RPTNOTIFICATIONINFLATOR_H_ + +#include "ola/acn/ACNVectors.h" +#include "libs/acn/BaseInflator.h" + +namespace ola { +namespace acn { + +class RPTNotificationInflator: public BaseInflator { + friend class RPTNotificationInflatorTest; + + public: + RPTNotificationInflator() + : BaseInflator() { + } + ~RPTNotificationInflator() {} + + uint32_t Id() const { return ola::acn::VECTOR_RPT_NOTIFICATION; } + + protected: + // The 'header' is 0 bytes in length. + bool DecodeHeader(HeaderSet*, + const uint8_t*, + unsigned int, + unsigned int *bytes_used) { + *bytes_used = 0; + return true; + } + + void ResetHeaderField() {} // namespace noop +}; +} // namespace acn +} // namespace ola +#endif // LIBS_ACN_RPTNOTIFICATIONINFLATOR_H_ diff --git a/libs/acn/RPTRequestInflator.h b/libs/acn/RPTRequestInflator.h new file mode 100644 index 0000000000..ec2cf38de3 --- /dev/null +++ b/libs/acn/RPTRequestInflator.h @@ -0,0 +1,55 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * RPTRequestInflator.h + * Interface for the RPTRequestInflator class. + * Copyright (C) 2023 Peter Newman + */ + +#ifndef LIBS_ACN_RPTREQUESTINFLATOR_H_ +#define LIBS_ACN_RPTREQUESTINFLATOR_H_ + +#include "ola/acn/ACNVectors.h" +#include "libs/acn/BaseInflator.h" + +namespace ola { +namespace acn { + +class RPTRequestInflator: public BaseInflator { + friend class RPTRequestInflatorTest; + + public: + RPTRequestInflator() + : BaseInflator() { + } + ~RPTRequestInflator() {} + + uint32_t Id() const { return ola::acn::VECTOR_RPT_REQUEST; } + + protected: + // The 'header' is 0 bytes in length. + bool DecodeHeader(HeaderSet*, + const uint8_t*, + unsigned int, + unsigned int *bytes_used) { + *bytes_used = 0; + return true; + } + + void ResetHeaderField() {} // namespace noop +}; +} // namespace acn +} // namespace ola +#endif // LIBS_ACN_RPTREQUESTINFLATOR_H_ From ec58616c7d5631f479c7c82e1e821c4f4145bd02 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Sat, 8 Jul 2023 23:38:51 +0100 Subject: [PATCH 70/71] Add tests for the LLRP and RPT headers in the HeaderSet --- libs/acn/HeaderSetTest.cpp | 76 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/libs/acn/HeaderSetTest.cpp b/libs/acn/HeaderSetTest.cpp index 18fa7141f5..26623b0c1f 100644 --- a/libs/acn/HeaderSetTest.cpp +++ b/libs/acn/HeaderSetTest.cpp @@ -25,6 +25,7 @@ #include "ola/acn/CID.h" #include "ola/network/SocketAddress.h" #include "ola/network/NetworkUtils.h" +#include "ola/rdm/UID.h" #include "libs/acn/HeaderSet.h" #include "ola/testing/TestUtils.h" @@ -36,11 +37,14 @@ using ola::acn::E131Rev2Header; using ola::acn::E133Header; using ola::acn::FOUR_BYTES; using ola::acn::HeaderSet; +using ola::acn::LLRPHeader; using ola::acn::NON_RANGE; using ola::acn::ONE_BYTES; using ola::acn::RANGE_EQUAL; using ola::acn::RootHeader; +using ola::acn::RPTHeader; using ola::acn::TransportHeader; +using ola::rdm::UID; class HeaderSetTest: public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(HeaderSetTest); @@ -49,6 +53,8 @@ class HeaderSetTest: public CppUnit::TestFixture { CPPUNIT_TEST(testE131Header); CPPUNIT_TEST(testE133Header); CPPUNIT_TEST(testDMPHeader); + CPPUNIT_TEST(testLLRPHeader); + CPPUNIT_TEST(testRPTHeader); CPPUNIT_TEST(testHeaderSet); CPPUNIT_TEST_SUITE_END(); @@ -58,6 +64,8 @@ class HeaderSetTest: public CppUnit::TestFixture { void testE131Header(); void testE133Header(); void testDMPHeader(); + void testLLRPHeader(); + void testRPTHeader(); void testHeaderSet(); }; @@ -213,6 +221,59 @@ void HeaderSetTest::testDMPHeader() { } +/* + * test the E1.33 LLRP Header + */ +void HeaderSetTest::testLLRPHeader() { + CID cid = CID::Generate(); + + LLRPHeader header(cid, 9840); + OLA_ASSERT(cid == header.DestinationCid()); + OLA_ASSERT_EQ((uint32_t) 9840, header.TransactionNumber()); + + // test copy and assign + LLRPHeader header2 = header; + OLA_ASSERT(header.DestinationCid() == header2.DestinationCid()); + OLA_ASSERT_EQ(header.TransactionNumber(), header2.TransactionNumber()); + + LLRPHeader header3(header); + OLA_ASSERT(header.DestinationCid() == header3.DestinationCid()); + OLA_ASSERT_EQ(header.TransactionNumber(), header3.TransactionNumber()); + OLA_ASSERT(header == header3); +} + + +/* + * test the RPT Header + */ +void HeaderSetTest::testRPTHeader() { + UID src(1, 2); + UID dest(4, 10); + RPTHeader header(src, 3, dest, 5, 9840); + OLA_ASSERT(src == header.SourceUID()); + OLA_ASSERT_EQ((uint16_t) 3, header.SourceEndpoint()); + OLA_ASSERT(dest == header.DestinationUID()); + OLA_ASSERT_EQ((uint16_t) 5, header.DestinationEndpoint()); + OLA_ASSERT_EQ((uint32_t) 9840, header.Sequence()); + + // test copy and assign + RPTHeader header2 = header; + OLA_ASSERT(header.SourceUID() == header2.SourceUID()); + OLA_ASSERT_EQ(header.SourceEndpoint(), header2.SourceEndpoint()); + OLA_ASSERT(header.DestinationUID() == header2.DestinationUID()); + OLA_ASSERT_EQ(header.DestinationEndpoint(), header2.DestinationEndpoint()); + OLA_ASSERT_EQ(header.Sequence(), header2.Sequence()); + + RPTHeader header3(header); + OLA_ASSERT(header.SourceUID() == header3.SourceUID()); + OLA_ASSERT_EQ(header.SourceEndpoint(), header3.SourceEndpoint()); + OLA_ASSERT(header.DestinationUID() == header3.DestinationUID()); + OLA_ASSERT_EQ(header.DestinationEndpoint(), header3.DestinationEndpoint()); + OLA_ASSERT_EQ(header.Sequence(), header3.Sequence()); + OLA_ASSERT(header == header3); +} + + /* * Check that the header set works */ @@ -222,6 +283,9 @@ void HeaderSetTest::testHeaderSet() { E131Header e131_header("e131", 1, 2, 6001); E133Header e133_header("foo", 1, 2050); DMPHeader dmp_header(false, false, NON_RANGE, ONE_BYTES); + CID destination_cid = CID::Generate(); + LLRPHeader llrp_header(destination_cid, 9840); + RPTHeader rpt_header(UID(1, 2), 3, UID(4, 10), 5, 9840); // test the root header component CID cid = CID::Generate(); @@ -241,12 +305,22 @@ void HeaderSetTest::testHeaderSet() { headers.SetDMPHeader(dmp_header); OLA_ASSERT(dmp_header == headers.GetDMPHeader()); + // test the LLRP headers component + headers.SetLLRPHeader(llrp_header); + OLA_ASSERT(llrp_header == headers.GetLLRPHeader()); + + // test the RPT headers component + headers.SetRPTHeader(rpt_header); + OLA_ASSERT(rpt_header == headers.GetRPTHeader()); + // test assign HeaderSet headers2 = headers; OLA_ASSERT(root_header == headers2.GetRootHeader()); OLA_ASSERT(e131_header == headers2.GetE131Header()); OLA_ASSERT(e133_header == headers2.GetE133Header()); OLA_ASSERT(dmp_header == headers2.GetDMPHeader()); + OLA_ASSERT(llrp_header == headers2.GetLLRPHeader()); + OLA_ASSERT(rpt_header == headers2.GetRPTHeader()); OLA_ASSERT(headers2 == headers); // test copy @@ -255,5 +329,7 @@ void HeaderSetTest::testHeaderSet() { OLA_ASSERT(e131_header == headers3.GetE131Header()); OLA_ASSERT(e133_header == headers3.GetE133Header()); OLA_ASSERT(dmp_header == headers3.GetDMPHeader()); + OLA_ASSERT(llrp_header == headers3.GetLLRPHeader()); + OLA_ASSERT(rpt_header == headers3.GetRPTHeader()); OLA_ASSERT(headers3 == headers); } From 7c44c8b9dd58cb99885082f1a15e5e751310b5aa Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Wed, 27 Dec 2023 00:14:27 +0000 Subject: [PATCH 71/71] Add some ConnectStatusCode helpers --- include/ola/e133/E133StatusHelper.h | 5 ++++ tools/e133/E133StatusHelper.cpp | 46 +++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/include/ola/e133/E133StatusHelper.h b/include/ola/e133/E133StatusHelper.h index cd9680b029..7ca19412df 100644 --- a/include/ola/e133/E133StatusHelper.h +++ b/include/ola/e133/E133StatusHelper.h @@ -30,9 +30,14 @@ namespace e133 { using std::string; using ola::e133::E133StatusCode; +using ola::e133::E133ConnectStatusCode; bool IntToStatusCode(uint16_t input, E133StatusCode *status_code); string StatusCodeToString(E133StatusCode status_code); + +bool IntToConnectStatusCode(uint16_t input, + E133ConnectStatusCode *connect_status_code); +string ConnectStatusCodeToString(E133ConnectStatusCode connect_status_code); } // namespace e133 } // namespace ola #endif // INCLUDE_OLA_E133_E133STATUSHELPER_H_ diff --git a/tools/e133/E133StatusHelper.cpp b/tools/e133/E133StatusHelper.cpp index a87376425a..a1ec71627c 100644 --- a/tools/e133/E133StatusHelper.cpp +++ b/tools/e133/E133StatusHelper.cpp @@ -96,5 +96,51 @@ string StatusCodeToString(E133StatusCode status_code) { } return "Unknown E1.33 Status Code"; } + + +bool IntToConnectStatusCode(uint16_t input, + E133ConnectStatusCode *connect_status_code) { + switch (input) { + case ola::e133::CONNECT_OK: + *connect_status_code = ola::e133::CONNECT_OK; + return true; + case ola::e133::CONNECT_SCOPE_MISMATCH: + *connect_status_code = ola::e133::CONNECT_SCOPE_MISMATCH; + return true; + case ola::e133::CONNECT_CAPACITY_EXCEEDED: + *connect_status_code = ola::e133::CONNECT_CAPACITY_EXCEEDED; + return true; + case ola::e133::CONNECT_DUPLICATE_UID: + *connect_status_code = ola::e133::CONNECT_DUPLICATE_UID; + return true; + case ola::e133::CONNECT_INVALID_CLIENT_ENTRY: + *connect_status_code = ola::e133::CONNECT_INVALID_CLIENT_ENTRY; + return true; + case ola::e133::CONNECT_INVALID_UID: + *connect_status_code = ola::e133::CONNECT_INVALID_UID; + return true; + default: + return false; + } +} + + +string ConnectStatusCodeToString(E133ConnectStatusCode connect_status_code) { + switch (connect_status_code) { + case ola::e133::CONNECT_OK: + return "Ok"; + case ola::e133::CONNECT_SCOPE_MISMATCH: + return "Scope mismatch"; + case ola::e133::CONNECT_CAPACITY_EXCEEDED: + return "Capacity exceeded"; + case ola::e133::CONNECT_DUPLICATE_UID: + return "Duplicate UID"; + case ola::e133::CONNECT_INVALID_CLIENT_ENTRY: + return "Invalid client entry"; + case ola::e133::CONNECT_INVALID_UID: + return "Invalid UID"; + } + return "Unknown E1.33 Connect Status Code"; +} } // namespace e133 } // namespace ola