From 0390e971b13d42bf46aa74dffa657605b986ef4d Mon Sep 17 00:00:00 2001
From: Nicolas Pope <nicolas.pope@utu.fi>
Date: Fri, 10 Jun 2022 09:59:37 +0000
Subject: [PATCH] #50 Add channel name mappings

---
 CMakeLists.txt                        |   1 +
 include/ftl/protocol/channelUtils.hpp |   8 +
 include/ftl/protocol/channels.hpp     |  18 +++
 include/ftl/protocol/node.hpp         |   2 +
 src/channelUtils.cpp                  | 222 ++++++++++++++++++++++++++
 test/CMakeLists.txt                   |  10 ++
 test/utils_unit.cpp                   |  19 +++
 7 files changed, 280 insertions(+)
 create mode 100644 src/channelUtils.cpp
 create mode 100644 test/utils_unit.cpp

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8050737..5261bea 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -191,6 +191,7 @@ add_library(beyond-protocol STATIC
 	src/self.cpp
 	src/protocol.cpp
 	src/rpc.cpp
+    src/channelUtils.cpp
 )
 
 target_include_directories(beyond-protocol PUBLIC
diff --git a/include/ftl/protocol/channelUtils.hpp b/include/ftl/protocol/channelUtils.hpp
index 7c6a061..6606e1d 100644
--- a/include/ftl/protocol/channelUtils.hpp
+++ b/include/ftl/protocol/channelUtils.hpp
@@ -19,6 +19,14 @@ inline bool isData(Channel c) { return static_cast<int>(c) >= 64; }
 /** Obtain a string name for channel. */
 std::string name(Channel c);
 
+/**
+ * @brief Get the channel ID from a name.
+ * 
+ * @param name 
+ * @return Channel 
+ */
+Channel fromName(const std::string &name);
+
 /** Obtain OpenCV type for channel. */
 int type(Channel c);
 
diff --git a/include/ftl/protocol/channels.hpp b/include/ftl/protocol/channels.hpp
index 49a4e17..e4bf601 100644
--- a/include/ftl/protocol/channels.hpp
+++ b/include/ftl/protocol/channels.hpp
@@ -117,6 +117,24 @@ enum struct Channel : int {
     kPipeline_EnableMVMLS     = 501,
     kPipeline_EnableAruco     = 502,
 
+    /* Stereo video settings */
+    kSGMResolution              = 600,
+    kStereoRectify              = 601,
+    kStereoRightPose            = 602,
+    kStereoRectifyCubic         = 603,
+    kVideoOffsetZ               = 604,
+    kVideoSize                  = 605,
+
+    /* Sender settings */
+    kSenderLosslessFloat        = 700,
+    kSenderLosslessColour       = 701,
+    kSenderIFrames              = 702,
+    kSenderCodecFloat           = 703,
+    kSenderCodecColour          = 704,
+    kSenderMaxBitrate           = 705,
+    kSenderFloatBitrateScale    = 706,
+
+
     /* Custom / user data channels */
     kData           = 2048,  // Do not use
     kEndFrame       = 2048,  // Signify the last packet
diff --git a/include/ftl/protocol/node.hpp b/include/ftl/protocol/node.hpp
index b041836..be580ad 100644
--- a/include/ftl/protocol/node.hpp
+++ b/include/ftl/protocol/node.hpp
@@ -173,5 +173,7 @@ class Node {
     ftl::net::PeerPtr peer_;
 };
 
+using NodePtr = std::shared_ptr<Node>;
+
 }  // namespace protocol
 }  // namespace ftl
diff --git a/src/channelUtils.cpp b/src/channelUtils.cpp
new file mode 100644
index 0000000..50dabb7
--- /dev/null
+++ b/src/channelUtils.cpp
@@ -0,0 +1,222 @@
+/**
+ * @file channelUtils.cpp
+ * @copyright Copyright (c) 2022 University of Turku, MIT License
+ * @author Nicolas Pope
+ */
+
+#include <ftl/protocol/config.h>
+#include <string>
+#include <unordered_map>
+#include <ftl/protocol/channelUtils.hpp>
+
+using ftl::protocol::Channel;
+
+#ifndef CV_8U
+#define CV_CN_SHIFT   3
+#define CV_DEPTH_MAX  (1 << CV_CN_SHIFT)
+
+#define CV_8U   0
+#define CV_8S   1
+#define CV_16U  2
+#define CV_16S  3
+#define CV_32S  4
+#define CV_32F  5
+#define CV_64F  6
+#define CV_16F  7
+
+#define CV_MAT_DEPTH_MASK       (CV_DEPTH_MAX - 1)
+#define CV_MAT_DEPTH(flags)     ((flags) & CV_MAT_DEPTH_MASK)
+
+#define CV_MAKETYPE(depth,cn) (CV_MAT_DEPTH(depth) + (((cn)-1) << CV_CN_SHIFT))
+#define CV_MAKE_TYPE CV_MAKETYPE
+
+#define CV_8UC1 CV_MAKETYPE(CV_8U,1)
+#define CV_8UC2 CV_MAKETYPE(CV_8U,2)
+#define CV_8UC3 CV_MAKETYPE(CV_8U,3)
+#define CV_8UC4 CV_MAKETYPE(CV_8U,4)
+#define CV_8UC(n) CV_MAKETYPE(CV_8U,(n))
+
+#define CV_8SC1 CV_MAKETYPE(CV_8S,1)
+#define CV_8SC2 CV_MAKETYPE(CV_8S,2)
+#define CV_8SC3 CV_MAKETYPE(CV_8S,3)
+#define CV_8SC4 CV_MAKETYPE(CV_8S,4)
+#define CV_8SC(n) CV_MAKETYPE(CV_8S,(n))
+
+#define CV_16UC1 CV_MAKETYPE(CV_16U,1)
+#define CV_16UC2 CV_MAKETYPE(CV_16U,2)
+#define CV_16UC3 CV_MAKETYPE(CV_16U,3)
+#define CV_16UC4 CV_MAKETYPE(CV_16U,4)
+#define CV_16UC(n) CV_MAKETYPE(CV_16U,(n))
+
+#define CV_16SC1 CV_MAKETYPE(CV_16S,1)
+#define CV_16SC2 CV_MAKETYPE(CV_16S,2)
+#define CV_16SC3 CV_MAKETYPE(CV_16S,3)
+#define CV_16SC4 CV_MAKETYPE(CV_16S,4)
+#define CV_16SC(n) CV_MAKETYPE(CV_16S,(n))
+
+#define CV_32SC1 CV_MAKETYPE(CV_32S,1)
+#define CV_32SC2 CV_MAKETYPE(CV_32S,2)
+#define CV_32SC3 CV_MAKETYPE(CV_32S,3)
+#define CV_32SC4 CV_MAKETYPE(CV_32S,4)
+#define CV_32SC(n) CV_MAKETYPE(CV_32S,(n))
+
+#define CV_32FC1 CV_MAKETYPE(CV_32F,1)
+#define CV_32FC2 CV_MAKETYPE(CV_32F,2)
+#define CV_32FC3 CV_MAKETYPE(CV_32F,3)
+#define CV_32FC4 CV_MAKETYPE(CV_32F,4)
+#define CV_32FC(n) CV_MAKETYPE(CV_32F,(n))
+
+#define CV_64FC1 CV_MAKETYPE(CV_64F,1)
+#define CV_64FC2 CV_MAKETYPE(CV_64F,2)
+#define CV_64FC3 CV_MAKETYPE(CV_64F,3)
+#define CV_64FC4 CV_MAKETYPE(CV_64F,4)
+#define CV_64FC(n) CV_MAKETYPE(CV_64F,(n))
+
+#define CV_16FC1 CV_MAKETYPE(CV_16F,1)
+#define CV_16FC2 CV_MAKETYPE(CV_16F,2)
+#define CV_16FC3 CV_MAKETYPE(CV_16F,3)
+#define CV_16FC4 CV_MAKETYPE(CV_16F,4)
+#define CV_16FC(n) CV_MAKETYPE(CV_16F,(n))
+#endif
+
+struct ChannelInfo {
+    const char *name;
+    int cvtype = -1;
+};
+
+/* Name and type lookup table for channels */
+static const std::unordered_map<Channel,ChannelInfo> info = {
+    {Channel::kColour,              {"Left",                CV_8UC4}},
+    {Channel::kDepth,               {"Depth",               CV_32F}},
+    {Channel::kRight,               {"Right",               CV_8UC4}},
+    {Channel::kDepth2,              {"Depth Right",         CV_32F}},
+    {Channel::kDeviation,           {"Deviation",           CV_32F}},
+    {Channel::kNormals,             {"Normals",             CV_32FC4}},
+    {Channel::kWeights,             {"Weights",             CV_32F}},
+    {Channel::kConfidence,          {"Confidence",          CV_32F}},
+    {Channel::kEnergyVector,        {"Energy Vector",       CV_32FC4}},
+    {Channel::kFlow,                {"Flow",                CV_32F}},
+    {Channel::kEnergy,              {"Energy",              CV_32F}},
+    {Channel::kMask,                {"Mask",                CV_8U}},
+    {Channel::kDensity,             {"Density",             CV_32F}},
+    {Channel::kSupport1,            {"Support1",            CV_8UC4}},
+    {Channel::kSupport2,            {"Support2",            CV_8UC4}},
+    {Channel::kSegmentation,        {"Segmentation",        CV_8U}},
+    {Channel::kNormals2,            {"Normals Right",       CV_32FC4}},
+    {Channel::kUNUSED1,             {"Unused",              CV_8UC4}},
+    {Channel::kDisparity,           {"Disparity",           CV_16S}},
+    {Channel::kSmoothing,           {"Smoothing",           CV_32F}},
+    {Channel::kUNUSED2,             {"Unused",              CV_8UC4}},
+    {Channel::kOverlay,             {"Overlay",             CV_8UC4}},
+    {Channel::kGroundTruth,         {"Ground Truth",        CV_32F}},
+
+    {Channel::kAudioMono,           {"Audio (Mono)",        -1}},
+    {Channel::kAudioStereo,         {"Audio (Stereo)",      -1}},
+
+    {Channel::kConfiguration,       {"Configuration",       -1}},
+    {Channel::kCalibration,         {"Calibration",         -1}},
+    {Channel::kPose,                {"Pose",                -1}},
+    {Channel::kCalibration2,        {"CalibrationHR",       -1}},
+    {Channel::kMetaData,            {"Meta Data",           -1}},
+    {Channel::kCapabilities,        {"Capabilities",        -1}},
+    {Channel::kCalibrationData,     {"CalibrationData",     -1}},
+    {Channel::kThumbnail,           {"Thumbnail",           -1}},
+    {Channel::kOverlaySelect,       {"OverlaySelect",       -1}},
+    {Channel::kStartTime,           {"StartTime",           -1}},
+    {Channel::kUser,                {"User",                -1}},
+
+    {Channel::kBrightness,          {"Brightness",          -1}},
+    {Channel::kContrast,            {"Contrast",            -1}},
+    {Channel::kExposure,            {"Exposure",            -1}},
+    {Channel::kGain,                {"Gain",                -1}},
+    {Channel::kWhiteBalance,        {"WhiteBalance",        -1}},
+    {Channel::kAutoExposure,        {"AutoExposure",        -1}},
+    {Channel::kAutoWhiteBalance,    {"AutoWhiteBalance",    -1}},
+    {Channel::kCameraTemperature,   {"CameraTemperature",   -1}},
+
+    {Channel::kRS2_LaserPower,      {"RS2LaserPower",       -1}},
+    {Channel::kRS2_MinDistance,     {"RS2MinDistance",      -1}},
+    {Channel::kRS2_MaxDistance,     {"RS2MaxDistance",      -1}},
+    {Channel::kRS2_InterCamSync,    {"RS2InterCamSync",     -1}},
+    {Channel::kRS2_PostSharpening,  {"RS2PostSharpening",   -1}},
+
+    {Channel::kRenderer_CameraType,             {"RenderCameraType",            -1}},
+    {Channel::kRenderer_Visualisation,          {"RenderVisualisation",         -1}},
+    {Channel::kRenderer_Engine,                 {"RenderEngine",                -1}},
+    {Channel::kRenderer_FPS,                    {"RenderFPS",                   -1}},
+    {Channel::kRenderer_View,                   {"RenderView",                  -1}},
+    {Channel::kRenderer_Channel,                {"RenderChannel",               -1}},
+    {Channel::kRenderer_Opacity,                {"RenderOpacity",               -1}},
+    {Channel::kRenderer_Sources,                {"RenderSources",               -1}},
+    {Channel::kRenderer_Projection,             {"RenderProjection",            -1}},
+    {Channel::kRenderer_Background,             {"RenderBackground",            -1}},
+    {Channel::kRenderer_ShowBadColour,          {"RenderShowBadColour",         -1}},
+    {Channel::kRenderer_CoolEffect,             {"RenderCoolEffect",            -1}},
+    {Channel::kRenderer_EffectColour,           {"RenderEffectColour",          -1}},
+    {Channel::kRenderer_ShowColourWeights,      {"RenderShowColourWeights",     -1}},
+    {Channel::kRenderer_TriangleLimit,          {"RenderTriangleLimit",         -1}},
+    {Channel::kRenderer_DisconDisparities,      {"RenderDisconDisparities",     -1}},
+    {Channel::kRenderer_NormalWeightColour,     {"RenderNormalWeightColour",    -1}},
+    {Channel::kRenderer_ChannelWeights,         {"RenderChannelWeights",        -1}},
+    {Channel::kRenderer_AccumFunc,              {"RenderAccumFunc",             -1}},
+
+    {Channel::kSGMResolution,       {"SGMResolution",       -1}},
+    {Channel::kStereoRectify,       {"StereoRectify",       -1}},
+    {Channel::kStereoRightPose,     {"StereoRightPose",     -1}},
+    {Channel::kStereoRectifyCubic,  {"StereoRectifyCubic",  -1}},
+    {Channel::kVideoOffsetZ,        {"VideoOffsetZ",        -1}},
+    {Channel::kVideoSize,           {"VideoSize",           -1}},
+
+    {Channel::kSenderLosslessFloat,     {"SenderLosslessFloat",     -1}},
+    {Channel::kSenderLosslessColour,    {"SenderLosslessColour",    -1}},
+    {Channel::kSenderIFrames,           {"SenderIFrames",           -1}},
+    {Channel::kSenderCodecFloat,        {"SenderCodecFloat",        -1}},
+    {Channel::kSenderCodecColour,       {"SenderCodecColour",       -1}},
+    {Channel::kSenderMaxBitrate,        {"SenderMaxBitrate",        -1}},
+    {Channel::kSenderFloatBitrateScale, {"SenderFloatBitrateScale", -1}},
+
+    {Channel::kData,                {"Generic Data",        -1}},
+    {Channel::kFaces,               {"Faces",               -1}},
+    {Channel::kShapes3D,            {"Shapes 3D",           -1}},
+    {Channel::kMessages,            {"Messages",            -1}},
+    {Channel::kTouch,               {"Touch",               -1}}
+};
+
+static std::unordered_map<std::string, Channel> indexNames() {
+    std::unordered_map<std::string, Channel> result;
+    for (const auto &i : info) {
+        result[std::string(i.second.name)] = i.first;
+    }
+    return result;
+}
+
+static const std::unordered_map<std::string, Channel> nameIndex = indexNames();
+
+std::string ftl::protocol::name(Channel c) {
+    if (c == Channel::kNone) return "None";
+    auto i = info.find(c);
+    if (i != info.end()) {
+        return i->second.name;
+    } else {
+        return "Unknown";
+    }
+}
+
+Channel ftl::protocol::fromName(const std::string &name) {
+    auto i = nameIndex.find(name);
+    if (i != nameIndex.end()) {
+        return i->second;
+    } else {
+        return Channel::kNone;
+    }
+}
+
+int ftl::protocol::type(Channel c) {
+    if (c == Channel::kNone) return -1;
+    auto i = info.find(c);
+    if (i != info.end()) {
+        return i->second.cvtype;
+    } else {
+        return -1;
+    }
+}
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 17aed1c..5788d79 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -17,6 +17,16 @@ target_link_libraries(uri_unit beyond-protocol
 
 add_test(URIUnitTest uri_unit)
 
+### Util #######################################################################
+add_executable(util_unit
+	$<TARGET_OBJECTS:CatchTest>
+	./utils_unit.cpp)
+target_include_directories(util_unit PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../include")
+target_link_libraries(util_unit beyond-protocol
+	Threads::Threads ${OS_LIBS})
+
+add_test(UtilUnitTest util_unit)
+
 ### Handle Unit ################################################################
 add_executable(handle_unit
 	$<TARGET_OBJECTS:CatchTest>
diff --git a/test/utils_unit.cpp b/test/utils_unit.cpp
new file mode 100644
index 0000000..e2bc869
--- /dev/null
+++ b/test/utils_unit.cpp
@@ -0,0 +1,19 @@
+#include "catch.hpp"
+#include <ftl/protocol/channelUtils.hpp>
+
+using ftl::protocol::Channel;
+using std::string;
+
+SCENARIO( "Channel names", "[utility]" ) {
+    GIVEN( "a valid channel name" ) {
+        REQUIRE( ftl::protocol::fromName("User") == Channel::kUser );
+    }
+
+    GIVEN( "an invalid channel name" ) {
+        REQUIRE( ftl::protocol::fromName("RandomWord") == Channel::kNone );
+    }
+
+    GIVEN( "a channel, get a name" ) {
+        REQUIRE( ftl::protocol::name(Channel::kUser) == "User" );
+    }
+}
\ No newline at end of file
-- 
GitLab