From c64f6680a118f538a3f30b585543f4b4dc3bc6f4 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Sat, 18 Mar 2023 23:21:20 +0000 Subject: [PATCH 1/6] Improve one of our example's error handling logging --- doxygen/examples/receiver.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doxygen/examples/receiver.cpp b/doxygen/examples/receiver.cpp index c3864371a9..7071af74c0 100644 --- a/doxygen/examples/receiver.cpp +++ b/doxygen/examples/receiver.cpp @@ -43,8 +43,10 @@ int main() { ola::InitLogging(ola::OLA_LOG_INFO, ola::OLA_LOG_STDERR); ola::client::OlaClientWrapper wrapper; - if (!wrapper.Setup()) + if (!wrapper.Setup()) { + std::cerr << "Setup failed" << std::endl; exit(1); + } ola::client::OlaClient *client = wrapper.GetClient(); // Set the callback and register our interest in this universe From 8790bdf4536739ee66816fe7fbd9f48cbf1b4deb Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Tue, 21 Mar 2023 22:39:58 +0000 Subject: [PATCH 2/6] Fix a comment typo --- include/ola/client/Module.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ola/client/Module.h b/include/ola/client/Module.h index 0c81d2fd8a..7b72d5bce4 100644 --- a/include/ola/client/Module.h +++ b/include/ola/client/Module.h @@ -24,7 +24,7 @@ * Sometimes it's useful for client applications to avoid linking against * libola, say for instance if they install separately from OLA. By deferring * the linking and using libola as a plugin, clients can use OLA if it's - * installed on the system or if not, take some other action like displaing a + * installed on the system or if not, take some other action like displaying a * message or using another output mechanism. * * This file provides plugin interfaces so that a client code can load From ddf953d3c4e6a0d0f8ff36849adbdbba7970b939 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Fri, 24 Mar 2023 02:43:17 +0000 Subject: [PATCH 3/6] First version of UniverseChannelAddress class --- common/dmx/Makefile.mk | 13 ++- common/dmx/UniverseChannelAddress.cpp | 72 ++++++++++++ common/dmx/UniverseChannelAddressTest.cpp | 99 ++++++++++++++++ include/ola/dmx/Makefile.mk | 3 +- include/ola/dmx/UniverseChannelAddress.h | 136 ++++++++++++++++++++++ 5 files changed, 320 insertions(+), 3 deletions(-) create mode 100644 common/dmx/UniverseChannelAddress.cpp create mode 100644 common/dmx/UniverseChannelAddressTest.cpp create mode 100644 include/ola/dmx/UniverseChannelAddress.h diff --git a/common/dmx/Makefile.mk b/common/dmx/Makefile.mk index 123eb4b2f9..e81361bef9 100644 --- a/common/dmx/Makefile.mk +++ b/common/dmx/Makefile.mk @@ -1,11 +1,20 @@ # LIBRARIES ################################################## -common_libolacommon_la_SOURCES += common/dmx/RunLengthEncoder.cpp +common_libolacommon_la_SOURCES += \ + common/dmx/RunLengthEncoder.cpp \ + common/dmx/UniverseChannelAddress.cpp + # TESTS ################################################## -test_programs += common/dmx/RunLengthEncoderTester +test_programs += \ + common/dmx/RunLengthEncoderTester \ + common/dmx/UniverseChannelAddressTester common_dmx_RunLengthEncoderTester_SOURCES = common/dmx/RunLengthEncoderTest.cpp common_dmx_RunLengthEncoderTester_CXXFLAGS = $(COMMON_TESTING_FLAGS) common_dmx_RunLengthEncoderTester_LDADD = $(COMMON_TESTING_LIBS) + +common_dmx_UniverseChannelAddressTester_SOURCES = common/dmx/UniverseChannelAddressTest.cpp +common_dmx_UniverseChannelAddressTester_CXXFLAGS = $(COMMON_TESTING_FLAGS) +common_dmx_UniverseChannelAddressTester_LDADD = $(COMMON_TESTING_LIBS) diff --git a/common/dmx/UniverseChannelAddress.cpp b/common/dmx/UniverseChannelAddress.cpp new file mode 100644 index 0000000000..dd1d48ba7b --- /dev/null +++ b/common/dmx/UniverseChannelAddress.cpp @@ -0,0 +1,72 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * UniverseChannelAddress.cpp + * Represents a universe-channel address pair. + * Copyright (C) 2023 Peter Newman + */ + +#include +#include +#include +#include +#include +#include + +namespace ola { +namespace dmx { + +using std::string; + + +string UniverseChannelAddress::ToString() const { + std::ostringstream str; + str << Universe() << ":" << Channel(); + return str.str(); +} + + +/** + * Extract a UniverseChannelAddress from a string. + */ +bool UniverseChannelAddress::FromString( + const string &input, + UniverseChannelAddress *universe_channel_address) { + size_t pos = input.find_first_of(":"); + if (pos == string::npos) { + return false; + } + + unsigned int universe; + if (!StringToInt(input.substr(0, pos), &universe)) { + return false; + } + uint16_t channel; + if (!StringToInt(input.substr(pos + 1), &channel)) { + return false; + } + *universe_channel_address = UniverseChannelAddress(universe, channel); + return true; +} + + +UniverseChannelAddress UniverseChannelAddress::FromStringOrDie( + const string &address) { + UniverseChannelAddress universe_channel_address; + assert(FromString(address, &universe_channel_address)); + return universe_channel_address; +} +} // namespace dmx +} // namespace ola diff --git a/common/dmx/UniverseChannelAddressTest.cpp b/common/dmx/UniverseChannelAddressTest.cpp new file mode 100644 index 0000000000..3ff797dad6 --- /dev/null +++ b/common/dmx/UniverseChannelAddressTest.cpp @@ -0,0 +1,99 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * UniverseChannelAddressTest.cpp + * Test fixture for the UniverseChannelAddress class + * Copyright (C) 2023 Peter Newman + */ + +#include +#include + +#include "ola/dmx/UniverseChannelAddress.h" +#include "ola/testing/TestUtils.h" + +using ola::dmx::UniverseChannelAddress; +using std::string; + +class UniverseChannelAddressTest: public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(UniverseChannelAddressTest); + CPPUNIT_TEST(testUniverseChannelAddress); + CPPUNIT_TEST(testUniverseChannelAddressFromString); + CPPUNIT_TEST_SUITE_END(); + + public: + void testUniverseChannelAddress(); + void testUniverseChannelAddressFromString(); +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(UniverseChannelAddressTest); + + +/* + * Test the UniverseChannelAddress class works + */ +void UniverseChannelAddressTest::testUniverseChannelAddress() { + UniverseChannelAddress universe_channel_address(10, 500); + OLA_ASSERT_EQ(static_cast(10), universe_channel_address.Universe()); + OLA_ASSERT_EQ(static_cast(500), universe_channel_address.Channel()); + + // TODO(Peter): Test out of range channel values + + // test comparison operators + UniverseChannelAddress universe_channel_address2(10, 499); + UniverseChannelAddress universe_channel_address3(10, 501); + UniverseChannelAddress universe_channel_address4(9, 500); + UniverseChannelAddress universe_channel_address5(11, 500); + + OLA_ASSERT_EQ(universe_channel_address, universe_channel_address); + OLA_ASSERT_NE(universe_channel_address, universe_channel_address2); + OLA_ASSERT_NE(universe_channel_address, universe_channel_address3); + OLA_ASSERT_NE(universe_channel_address, universe_channel_address4); + OLA_ASSERT_NE(universe_channel_address, universe_channel_address5); + + OLA_ASSERT_LT(universe_channel_address2, universe_channel_address); + OLA_ASSERT_LT(universe_channel_address, universe_channel_address3); + OLA_ASSERT_LT(universe_channel_address4, universe_channel_address); + OLA_ASSERT_LT(universe_channel_address4, universe_channel_address3); + + OLA_ASSERT_GT(universe_channel_address, universe_channel_address2); + OLA_ASSERT_GT(universe_channel_address3, universe_channel_address); + OLA_ASSERT_GT(universe_channel_address, universe_channel_address4); + OLA_ASSERT_GT(universe_channel_address3, universe_channel_address4); + + // test assignment & copy constructor + UniverseChannelAddress copy_address(universe_channel_address); + universe_channel_address4 = universe_channel_address; + OLA_ASSERT_EQ(universe_channel_address, copy_address); + OLA_ASSERT_EQ(universe_channel_address, universe_channel_address4); +} + +/** + * Test that FromString() works + */ +void UniverseChannelAddressTest::testUniverseChannelAddressFromString() { + UniverseChannelAddress universe_channel_address; + OLA_ASSERT_TRUE( + UniverseChannelAddress::FromString("127:80", &universe_channel_address)); + OLA_ASSERT_EQ(static_cast(127), universe_channel_address.Universe()); + OLA_ASSERT_EQ(static_cast(80), universe_channel_address.Channel()); + + OLA_ASSERT_FALSE( + UniverseChannelAddress::FromString("127", &universe_channel_address)); + OLA_ASSERT_FALSE( + UniverseChannelAddress::FromString("foo", &universe_channel_address)); + OLA_ASSERT_FALSE( + UniverseChannelAddress::FromString(":80", &universe_channel_address)); +} diff --git a/include/ola/dmx/Makefile.mk b/include/ola/dmx/Makefile.mk index 356298cf55..004f90b3ba 100644 --- a/include/ola/dmx/Makefile.mk +++ b/include/ola/dmx/Makefile.mk @@ -1,4 +1,5 @@ oladmxincludedir = $(pkgincludedir)/dmx/ oladmxinclude_HEADERS = \ include/ola/dmx/RunLengthEncoder.h \ - include/ola/dmx/SourcePriorities.h + include/ola/dmx/SourcePriorities.h \ + include/ola/dmx/UniverseChannelAddress.h diff --git a/include/ola/dmx/UniverseChannelAddress.h b/include/ola/dmx/UniverseChannelAddress.h new file mode 100644 index 0000000000..46ffc80d15 --- /dev/null +++ b/include/ola/dmx/UniverseChannelAddress.h @@ -0,0 +1,136 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * UniverseChannelAddress.h + * Represents a universe-channel address pair. + * Copyright (C) 2023 Peter Newman + */ + +/** + * @addtogroup dmx + * @{ + * @file UniverseChannelAddress.h + * @brief Represents a universe-channel address pair + * @} + */ + +#ifndef INCLUDE_OLA_DMX_UNIVERSECHANNELADDRESS_H_ +#define INCLUDE_OLA_DMX_UNIVERSECHANNELADDRESS_H_ + +#include +#include +#include +#include + +namespace ola { +namespace dmx { + +/** + * @addtogroup dmx + * @{ + */ + +/** + * @brief The UniverseChannelAddress class. + **/ +class UniverseChannelAddress { + public: + UniverseChannelAddress() + : m_universe(0), + m_channel(0) { + } + + UniverseChannelAddress(unsigned int universe, uint16_t channel) + : m_universe(universe), + m_channel(channel) { + } + UniverseChannelAddress(const UniverseChannelAddress &other) + : m_universe(other.m_universe), + m_channel(other.m_channel) { + } + + ~UniverseChannelAddress() {} + + UniverseChannelAddress& operator=(const UniverseChannelAddress &other) { + if (this != &other) { + m_universe = other.m_universe; + m_channel = other.m_channel; + } + return *this; + } + + bool operator==(const UniverseChannelAddress &other) const { + return m_universe == other.m_universe && m_channel == other.m_channel; + } + + bool operator!=(const UniverseChannelAddress &other) const { + return !(*this == other); + } + + /** + * @brief Less than operator for partial ordering. + * + * Sorts by universe, then channel. + */ + bool operator<(const UniverseChannelAddress &other) const { + if (m_universe == other.m_universe) { + return m_channel < other.m_channel; + } else { + return m_universe < other.m_universe; + } + } + + /** + * @brief Greater than operator. + * + * Sorts by universe, then channel. + */ + bool operator>(const UniverseChannelAddress &other) const { + if (m_universe == other.m_universe) { + return m_channel > other.m_channel; + } else { + return m_universe > other.m_universe; + } + } + + unsigned int Universe() const { return m_universe; } + void Universe(const unsigned int universe) { m_universe = universe; } + uint16_t Channel() const { return m_channel; } + void Channel(uint16_t channel) { m_channel = channel; } + + std::string ToString() const; + + static bool FromString(const std::string &str, + UniverseChannelAddress *universe_channel_address); + + // useful for testing + static UniverseChannelAddress FromStringOrDie( + const std::string &universe_channel_address); + + friend std::ostream& operator<<(std::ostream &out, + const UniverseChannelAddress &address) { + return out << address.ToString(); + } + + private: + unsigned int m_universe; + unsigned int m_channel; +}; +/** + * @} + */ +} // namespace dmx +} // namespace ola +#endif // INCLUDE_OLA_DMX_UNIVERSECHANNELADDRESS_H_ From 7066c00b40ddd0d4ccf9f4c7c03845d234761516 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Fri, 24 Mar 2023 13:28:24 +0000 Subject: [PATCH 4/6] Add a one based universe channel class --- common/dmx/UniverseChannelAddress.cpp | 33 ++++++++++++ common/dmx/UniverseChannelAddressTest.cpp | 66 +++++++++++++++++++++-- include/ola/dmx/UniverseChannelAddress.h | 33 +++++++++++- 3 files changed, 127 insertions(+), 5 deletions(-) diff --git a/common/dmx/UniverseChannelAddress.cpp b/common/dmx/UniverseChannelAddress.cpp index dd1d48ba7b..ff0395cce8 100644 --- a/common/dmx/UniverseChannelAddress.cpp +++ b/common/dmx/UniverseChannelAddress.cpp @@ -68,5 +68,38 @@ UniverseChannelAddress UniverseChannelAddress::FromStringOrDie( assert(FromString(address, &universe_channel_address)); return universe_channel_address; } + + +string UniverseChannelAddressOneBased::ToStringZeroBased() const { + std::ostringstream str; + str << Universe() << ":" << ChannelZeroBased(); + return str.str(); +} + + +/** + * Extract a UniverseChannelAddressOneBased from a string. + */ +bool UniverseChannelAddressOneBased::FromString( + const string &input, + UniverseChannelAddressOneBased *universe_channel_address_one_based) { + size_t pos = input.find_first_of(":"); + if (pos == string::npos) { + return false; + } + + unsigned int universe; + if (!StringToInt(input.substr(0, pos), &universe)) { + return false; + } + uint16_t channel; + if (!StringToInt(input.substr(pos + 1), &channel)) { + return false; + } + *universe_channel_address_one_based = UniverseChannelAddressOneBased( + universe, + channel); + return true; +} } // namespace dmx } // namespace ola diff --git a/common/dmx/UniverseChannelAddressTest.cpp b/common/dmx/UniverseChannelAddressTest.cpp index 3ff797dad6..93caa0f7d4 100644 --- a/common/dmx/UniverseChannelAddressTest.cpp +++ b/common/dmx/UniverseChannelAddressTest.cpp @@ -25,6 +25,8 @@ #include "ola/testing/TestUtils.h" using ola::dmx::UniverseChannelAddress; +using ola::dmx::UniverseChannelAddressOneBased; +using std::ostringstream; using std::string; class UniverseChannelAddressTest: public CppUnit::TestFixture { @@ -35,6 +37,7 @@ class UniverseChannelAddressTest: public CppUnit::TestFixture { public: void testUniverseChannelAddress(); + void testUniverseChannelAddressToString(); void testUniverseChannelAddressFromString(); }; @@ -46,8 +49,18 @@ CPPUNIT_TEST_SUITE_REGISTRATION(UniverseChannelAddressTest); */ void UniverseChannelAddressTest::testUniverseChannelAddress() { UniverseChannelAddress universe_channel_address(10, 500); - OLA_ASSERT_EQ(static_cast(10), universe_channel_address.Universe()); - OLA_ASSERT_EQ(static_cast(500), universe_channel_address.Channel()); + OLA_ASSERT_EQ(static_cast(10), + universe_channel_address.Universe()); + OLA_ASSERT_EQ(static_cast(500), + universe_channel_address.Channel()); + + UniverseChannelAddressOneBased universe_channel_address_one_based(10, 501); + OLA_ASSERT_EQ(static_cast(10), + universe_channel_address_one_based.Universe()); + OLA_ASSERT_EQ(static_cast(501), + universe_channel_address_one_based.Channel()); + OLA_ASSERT_EQ(static_cast(500), + universe_channel_address_one_based.ChannelZeroBased()); // TODO(Peter): Test out of range channel values @@ -73,6 +86,10 @@ void UniverseChannelAddressTest::testUniverseChannelAddress() { OLA_ASSERT_GT(universe_channel_address, universe_channel_address4); OLA_ASSERT_GT(universe_channel_address3, universe_channel_address4); + OLA_ASSERT_EQ(universe_channel_address, + static_cast( + universe_channel_address_one_based)); + // test assignment & copy constructor UniverseChannelAddress copy_address(universe_channel_address); universe_channel_address4 = universe_channel_address; @@ -80,6 +97,23 @@ void UniverseChannelAddressTest::testUniverseChannelAddress() { OLA_ASSERT_EQ(universe_channel_address, universe_channel_address4); } +/** + * Test that ToString() works + */ +void UniverseChannelAddressTest::testUniverseChannelAddressToString() { + UniverseChannelAddress universe_channel_address(10, 500); + + OLA_ASSERT_EQ(string("10:500"), universe_channel_address.ToString()); + + universe_channel_address.Universe(100); + universe_channel_address.Channel(50); + OLA_ASSERT_EQ(string("100:50"), universe_channel_address.ToString()); + + ostringstream str; + str << universe_channel_address; + OLA_ASSERT_EQ(string("100:50"), str.str()); +} + /** * Test that FromString() works */ @@ -87,13 +121,39 @@ void UniverseChannelAddressTest::testUniverseChannelAddressFromString() { UniverseChannelAddress universe_channel_address; OLA_ASSERT_TRUE( UniverseChannelAddress::FromString("127:80", &universe_channel_address)); - OLA_ASSERT_EQ(static_cast(127), universe_channel_address.Universe()); + OLA_ASSERT_EQ(static_cast(127), + universe_channel_address.Universe()); OLA_ASSERT_EQ(static_cast(80), universe_channel_address.Channel()); + UniverseChannelAddressOneBased universe_channel_address_one_based; + OLA_ASSERT_TRUE(UniverseChannelAddressOneBased::FromString( + "127:81", &universe_channel_address_one_based)); + OLA_ASSERT_EQ(static_cast(127), + universe_channel_address_one_based.Universe()); + OLA_ASSERT_EQ(static_cast(81), + universe_channel_address_one_based.Channel()); + OLA_ASSERT_EQ(static_cast(80), + universe_channel_address_one_based.ChannelZeroBased()); + OLA_ASSERT_FALSE( UniverseChannelAddress::FromString("127", &universe_channel_address)); OLA_ASSERT_FALSE( UniverseChannelAddress::FromString("foo", &universe_channel_address)); + OLA_ASSERT_FALSE( + UniverseChannelAddress::FromString("127:", &universe_channel_address)); + OLA_ASSERT_FALSE( + UniverseChannelAddress::FromString("foo:", &universe_channel_address)); OLA_ASSERT_FALSE( UniverseChannelAddress::FromString(":80", &universe_channel_address)); + + OLA_ASSERT_FALSE(UniverseChannelAddressOneBased::FromString( + "127", &universe_channel_address_one_based)); + OLA_ASSERT_FALSE(UniverseChannelAddressOneBased::FromString( + "foo", &universe_channel_address_one_based)); + OLA_ASSERT_FALSE(UniverseChannelAddressOneBased::FromString( + "127:", &universe_channel_address_one_based)); + OLA_ASSERT_FALSE(UniverseChannelAddressOneBased::FromString( + "foo:", &universe_channel_address_one_based)); + OLA_ASSERT_FALSE(UniverseChannelAddressOneBased::FromString( + ":80", &universe_channel_address_one_based)); } diff --git a/include/ola/dmx/UniverseChannelAddress.h b/include/ola/dmx/UniverseChannelAddress.h index 46ffc80d15..298899b8b8 100644 --- a/include/ola/dmx/UniverseChannelAddress.h +++ b/include/ola/dmx/UniverseChannelAddress.h @@ -56,6 +56,7 @@ class UniverseChannelAddress { : m_universe(universe), m_channel(channel) { } + UniverseChannelAddress(const UniverseChannelAddress &other) : m_universe(other.m_universe), m_channel(other.m_channel) { @@ -67,7 +68,7 @@ class UniverseChannelAddress { if (this != &other) { m_universe = other.m_universe; m_channel = other.m_channel; - } + } return *this; } @@ -124,10 +125,38 @@ class UniverseChannelAddress { return out << address.ToString(); } - private: + protected: unsigned int m_universe; unsigned int m_channel; }; + +/** + * @brief The UniverseChannelAddressOneBased class. + * @note The channel number here is one based, to suit how users number + * channels. The universe remains zero based throughout. + **/ +class UniverseChannelAddressOneBased : public UniverseChannelAddress { + public: + UniverseChannelAddressOneBased() + : UniverseChannelAddress() { + } + + UniverseChannelAddressOneBased(unsigned int universe, uint16_t channel) + : UniverseChannelAddress(universe, channel - 1) { + } + + uint16_t Channel() const { return m_channel + 1; } + void Channel(uint16_t channel) { m_channel = channel - 1; } + + uint16_t ChannelZeroBased() const { return m_channel; } + void ChannelZeroBased(uint16_t channel) { m_channel = channel; } + + std::string ToStringZeroBased() const; + + static bool FromString( + const std::string &str, + UniverseChannelAddressOneBased *universe_channel_address_one_based); +}; /** * @} */ From 937dccc547bdb533b93194472c969e7d53f06967 Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Fri, 24 Mar 2023 14:04:58 +0000 Subject: [PATCH 5/6] First version of the universe-channel remapper --- .gitignore | 3 + examples/Makefile.mk | 5 + examples/ola-patcher-remap.cpp | 310 +++++++++++++++++++++++++++++++++ 3 files changed, 318 insertions(+) create mode 100644 examples/ola-patcher-remap.cpp diff --git a/.gitignore b/.gitignore index 5909411b90..64ffc83a15 100644 --- a/.gitignore +++ b/.gitignore @@ -132,6 +132,9 @@ examples/ola_latency.exe examples/ola_patch examples/ola_patch.exe examples/ola_ptch.exe +examples/ola_patcher_remap +examples/ola_patcher_remap.exe +examples/ola_ptcher_remap.exe examples/ola_plugin_info examples/ola_plugin_info.exe examples/ola_plugin_state diff --git a/examples/Makefile.mk b/examples/Makefile.mk index cc54a99148..00b6eb33c4 100644 --- a/examples/Makefile.mk +++ b/examples/Makefile.mk @@ -21,6 +21,7 @@ examples_libolaconfig_la_CXXFLAGS = $(COMMON_PROTOBUF_CXXFLAGS) ################################################## bin_PROGRAMS += \ examples/ola_dev_info \ + examples/ola_patcher_remap \ examples/ola_rdm_discover \ examples/ola_rdm_get \ examples/ola_recorder \ @@ -61,6 +62,10 @@ endif examples_ola_dev_info_SOURCES = examples/ola-client.cpp examples_ola_dev_info_LDADD = $(EXAMPLE_COMMON_LIBS) +examples_ola_patcher_remap_SOURCES = examples/ola-patcher-remap.cpp +examples_ola_patcher_remap_LDADD = $(EXAMPLE_COMMON_LIBS) \ + olad/plugin_api/libolaserverplugininterface.la + examples_ola_streaming_client_SOURCES = examples/ola-streaming-client.cpp examples_ola_streaming_client_LDADD = $(EXAMPLE_COMMON_LIBS) diff --git a/examples/ola-patcher-remap.cpp b/examples/ola-patcher-remap.cpp new file mode 100644 index 0000000000..e661228356 --- /dev/null +++ b/examples/ola-patcher-remap.cpp @@ -0,0 +1,310 @@ +/* + * 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. + * + * ola-patcher-remap.cpp + * A simple tool to remap channels from one universe to another. + * Copyright (C) 2023 Peter Newman + */ + +/* +{ + 100 => { + 1 => [1:1, 2:1, 1:3], + 1 => [4:1], + 2 => [5:1, 6:1, 6:2], + }, + 101 => { + 1 => [11:1, 12:1], + 2 => [15:1, 16:1], + } +} + +Remap internally to (sets): +{ + 100 => { + 1 => { + 1 => [1, 3], + 2 => [1], + 4 => [1], + } + 2 => { + 5 => [1], + 6 => [1, 2], + } + }, + 101 => { + 1 => { + 11 => [1], + 12 => [1], + } + 2 => { + 15 => [1], + 16 => [1], + } + } +} +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using ola::DmxBuffer; +using ola::client::OlaClient; +using ola::client::OlaClientWrapper; +using ola::client::Result; +using ola::StringSplit; +using ola::StringTrim; +using ola::STLFindOrNull; +using ola::STLLookupOrInsertNew; +using ola::dmx::UniverseChannelAddressOneBased; +using ola::io::SelectServer; +using std::string; +using std::vector; + +DEFINE_s_string(config, c, "ola-patcher-remap.conf", "The config file to use."); + +/* + * The remap class which responds to data + */ +class DmxRemap { + public: + typedef std::set ChansSet; + typedef std::map OutUniChansMap; + typedef std::map + InChanOutUniChansMap; + typedef std::map + InUniInChanOutUniChansMap; + + explicit DmxRemap( + const DmxRemap::InUniInChanOutUniChansMap universe_remaps) + : m_universe_remaps(universe_remaps) { + } + + ~DmxRemap() { + // TODO(Peter): Delete everything + } + + bool Init(); + void Run() { m_client.GetSelectServer()->Run(); } + void NewDmx(const ola::client::DMXMetadata &meta, + const ola::DmxBuffer &buffer); + void RegisterComplete(const Result &result); + + InUniInChanOutUniChansMap m_universe_remaps; + + private: + OlaClientWrapper m_client; + typedef std::map OutBufferMap; + OutBufferMap m_out_universes; +}; + +bool DmxRemap::Init() { + /* set up ola connection */ + if (!m_client.Setup()) { + printf("error: %s", strerror(errno)); + return false; + } + + InUniInChanOutUniChansMap::iterator in_uni_iter = m_universe_remaps.begin(); + for (; in_uni_iter != m_universe_remaps.end(); ++in_uni_iter) { + OLA_DEBUG << "Have mapping for input universe " << in_uni_iter->first; + + InChanOutUniChansMap::iterator in_chan_iter = in_uni_iter->second->begin(); + for (; in_chan_iter != in_uni_iter->second->end(); ++in_chan_iter) { + OLA_DEBUG << "\tHave mapping for input channel " << in_chan_iter->first; + + OutUniChansMap::iterator out_uni_iter = in_chan_iter->second->begin(); + for (; out_uni_iter != in_chan_iter->second->end(); ++out_uni_iter) { + OLA_DEBUG << "\t\tHave mapping for output universe " + << out_uni_iter->first << " to channel(s) " + << ola::StringJoin(", ", *(out_uni_iter->second)); + STLLookupOrInsertNew(&m_out_universes, out_uni_iter->first); + } + } + } + + OutBufferMap::iterator out_buffer_iter = m_out_universes.begin(); + for (; out_buffer_iter != m_out_universes.end(); ++out_buffer_iter) { + OLA_DEBUG << "Blacking out output buffer for universe " + << out_buffer_iter->first; + out_buffer_iter->second->Blackout(); + } + + OlaClient *client = m_client.GetClient(); + client->SetDMXCallback(ola::NewCallback(this, &DmxRemap::NewDmx)); + in_uni_iter = m_universe_remaps.begin(); + for (; in_uni_iter != m_universe_remaps.end(); ++in_uni_iter) { + OLA_DEBUG << "Registering input universe " << in_uni_iter->first; + client->RegisterUniverse( + in_uni_iter->first, + ola::client::REGISTER, + ola::NewSingleCallback(this, &DmxRemap::RegisterComplete)); + } + + return true; +} + +// Called when universe registration completes. +void DmxRemap::RegisterComplete(const ola::client::Result& result) { + if (!result.Success()) { + OLA_WARN << "Failed to register universe: " << result.Error(); + } +} + +// Called when new DMX data arrives. +void DmxRemap::NewDmx(const ola::client::DMXMetadata &metadata, + const ola::DmxBuffer &data) { + OLA_DEBUG << "Received " << data.Size() + << " channels for universe " << metadata.universe; + + InChanOutUniChansMap *in_chan_map = STLFindOrNull(m_universe_remaps, + metadata.universe); + if (in_chan_map) { + OLA_DEBUG << "Successfully found mapping for input universe " + << metadata.universe; + + InChanOutUniChansMap::iterator in_chan_iter = in_chan_map->begin(); + for (; in_chan_iter != in_chan_map->end(); ++in_chan_iter) { + OLA_DEBUG << "\tApplying mapping for input channel " + << in_chan_iter->first; + + OutUniChansMap::iterator out_uni_iter = in_chan_iter->second->begin(); + for (; out_uni_iter != in_chan_iter->second->end(); ++out_uni_iter) { + OLA_DEBUG << "\t\tApplying mapping for output universe " + << out_uni_iter->first; + ChansSet::iterator out_chan_iter = out_uni_iter->second->begin(); + for (; out_chan_iter != out_uni_iter->second->end(); ++out_chan_iter) { + OLA_DEBUG << "\t\t\tApplying mapping for output channel " + << *out_chan_iter; + DmxBuffer *buffer = STLFindOrNull(m_out_universes, + out_uni_iter->first); + if (!buffer) { + OLA_WARN << "Failed to find buffer for universe " + << out_uni_iter->first; + delete buffer; + } + buffer->SetChannel(*out_chan_iter, data.Get(in_chan_iter->first)); + } + } + } + } else { + OLA_WARN << "Couldn't find mapping for input universe " + << metadata.universe; + } + + OlaClient *client = m_client.GetClient(); + OutBufferMap::iterator out_iter = m_out_universes.begin(); + for (; out_iter != m_out_universes.end(); ++out_iter) { + OLA_DEBUG << "Sending universe " << out_iter->first; + client->SendDMX(out_iter->first, + *out_iter->second, + ola::client::SendDMXArgs()); + } +} + + +int main(int argc, char *argv[]) { + ola::AppInit(&argc, argv, "[options]", + "Remap DMX512 channel data within OLA."); + + ola::client::OlaClientWrapper wrapper; + if (!wrapper.Setup()) { + std::cerr << "Setup failed" << std::endl; + exit(1); + } + + ola::FileBackedPreferences *preferences = new ola::FileBackedPreferences( + "", "patcher-remap", NULL); + preferences->Clear(); + preferences->LoadFromFile(FLAGS_config.str()); + + vector values = preferences->GetMultipleValue("remap-channel"); + OLA_DEBUG << "Got " << values.size() << " remap-channel options"; + + DmxRemap::InUniInChanOutUniChansMap universe_remaps; + + vector::iterator pref_iter = values.begin(); + for (; pref_iter != values.end(); ++pref_iter) { + OLA_DEBUG << "Found base config " << *pref_iter; + vector tokens; + StringSplit(*pref_iter, &tokens, "-"); + + if (tokens.size() != 2) { + OLA_WARN << "Skipping config section, incorrect number of tokens: " + << *pref_iter; + continue; + } + + string key = tokens[0]; + string value = tokens[1]; + StringTrim(&key); + StringTrim(&value); + OLA_DEBUG << "Got raw remap from " << key << " to " << value; + UniverseChannelAddressOneBased source; + UniverseChannelAddressOneBased::FromString(key, &source); + OLA_DEBUG << "Got remap from " << source.Universe() << "\\" + << source.Channel(); + + DmxRemap::InUniInChanOutUniChansMap::iterator in_uni_map_iter = + STLLookupOrInsertNew(&universe_remaps, source.Universe()); + + DmxRemap::InChanOutUniChansMap::iterator in_chan_map_iter = + STLLookupOrInsertNew(in_uni_map_iter->second, source.ChannelZeroBased()); + + vector value_tokens; + StringSplit(value, &value_tokens, ","); + + vector::iterator pref_value_iter = value_tokens.begin(); + for (; pref_value_iter != value_tokens.end(); ++pref_value_iter) { + string value_token = *pref_value_iter; + StringTrim(&value_token); + UniverseChannelAddressOneBased destination; + UniverseChannelAddressOneBased::FromString(value_token, &destination); + OLA_DEBUG << "\tGot remap to " << destination.Universe() << "\\" + << destination.Channel(); + DmxRemap::OutUniChansMap::iterator out_uni_map_iter = + STLLookupOrInsertNew(in_chan_map_iter->second, + destination.Universe()); + out_uni_map_iter->second->insert(destination.ChannelZeroBased()); + } + } + + delete preferences; + + DmxRemap *dmx_remap = new DmxRemap(universe_remaps); + if (!dmx_remap->Init()) { + std::cerr << "Failed to initialise DmxRemap" << std::endl; + return 1; + } + + dmx_remap->Run(); + delete dmx_remap; + dmx_remap = NULL; + return 0; +} From d36610cfa80a5c25f614b992331ab5e80178c6fd Mon Sep 17 00:00:00 2001 From: Peter Newman Date: Fri, 24 Mar 2023 14:26:06 +0000 Subject: [PATCH 6/6] Fix a lint error --- examples/ola-patcher-remap.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/ola-patcher-remap.cpp b/examples/ola-patcher-remap.cpp index e661228356..a522c51bb4 100644 --- a/examples/ola-patcher-remap.cpp +++ b/examples/ola-patcher-remap.cpp @@ -275,7 +275,8 @@ int main(int argc, char *argv[]) { STLLookupOrInsertNew(&universe_remaps, source.Universe()); DmxRemap::InChanOutUniChansMap::iterator in_chan_map_iter = - STLLookupOrInsertNew(in_uni_map_iter->second, source.ChannelZeroBased()); + STLLookupOrInsertNew(in_uni_map_iter->second, + source.ChannelZeroBased()); vector value_tokens; StringSplit(value, &value_tokens, ",");