From ae70341365e27d766c8530924209fc4826036aea Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Fri, 31 Mar 2023 14:31:32 +0200 Subject: Add JSON output to RC --- src/OfdmGenerator.h | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'src/OfdmGenerator.h') diff --git a/src/OfdmGenerator.h b/src/OfdmGenerator.h index 30fdff4..90e562a 100644 --- a/src/OfdmGenerator.h +++ b/src/OfdmGenerator.h @@ -2,7 +2,7 @@ Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Her Majesty the Queen in Right of Canada (Communications Research Center Canada) - Copyright (C) 2017 + Copyright (C) 2023 Matthias P. Braendli, matthias.braendli@mpb.li http://opendigitalradio.org @@ -59,14 +59,9 @@ class OfdmGenerator : public ModCodec, public RemoteControllable const char* name() override { return "OfdmGenerator"; } /* Functions for the remote control */ - /* Base function to set parameters. */ - virtual void set_parameter( - const std::string& parameter, - const std::string& value) override; - - /* Getting a parameter always returns a string. */ - virtual const std::string get_parameter( - const std::string& parameter) const override; + virtual void set_parameter(const std::string& parameter, const std::string& value) override; + virtual const std::string get_parameter(const std::string& parameter) const override; + virtual const RemoteControllable::map_t get_all_values() const override; protected: struct cfr_iter_stat_t { -- cgit v1.2.3 From d521d4f0c5ad3b663a322453c5798626081cb1f3 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Wed, 19 Jul 2023 20:26:36 +0200 Subject: Change RC showjson command --- Makefile.am | 2 + lib/Json.cpp | 102 ++++++++++++++++++++++++++++++++++++++++++ lib/Json.h | 66 +++++++++++++++++++++++++++ lib/RemoteControl.cpp | 94 ++++++++------------------------------ lib/RemoteControl.h | 8 ++-- src/DabModulator.cpp | 4 +- src/DabModulator.h | 2 +- src/FIRFilter.cpp | 4 +- src/FIRFilter.h | 2 +- src/GainControl.cpp | 4 +- src/GainControl.h | 2 +- src/GuardIntervalInserter.cpp | 4 +- src/GuardIntervalInserter.h | 2 +- src/MemlessPoly.cpp | 4 +- src/MemlessPoly.h | 2 +- src/OfdmGenerator.cpp | 4 +- src/OfdmGenerator.h | 2 +- src/TII.cpp | 4 +- src/TII.h | 2 +- src/TimestampDecoder.cpp | 4 +- src/TimestampDecoder.h | 2 +- src/output/SDR.cpp | 6 +-- src/output/SDR.h | 2 +- src/output/SDRDevice.h | 2 +- 24 files changed, 220 insertions(+), 110 deletions(-) create mode 100644 lib/Json.cpp create mode 100644 lib/Json.h (limited to 'src/OfdmGenerator.h') diff --git a/Makefile.am b/Makefile.am index 0e09236..6e7c9ce 100644 --- a/Makefile.am +++ b/Makefile.am @@ -98,6 +98,8 @@ odr_dabmod_SOURCES = src/DabMod.cpp \ lib/RemoteControl.h \ lib/Log.cpp \ lib/Log.h \ + lib/Json.h \ + lib/Json.cpp \ lib/Globals.cpp \ lib/INIReader.h \ lib/crc.h \ diff --git a/lib/Json.cpp b/lib/Json.cpp new file mode 100644 index 0000000..9bda8c3 --- /dev/null +++ b/lib/Json.cpp @@ -0,0 +1,102 @@ +/* + Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 + Her Majesty the Queen in Right of Canada (Communications Research + Center Canada) + + Copyright (C) 2023 + Matthias P. Braendli, matthias.braendli@mpb.li + + http://www.opendigitalradio.org + */ +/* + 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 3 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ +#include +#include +#include +#include +#include +#include +#include + +#include "Json.h" + +namespace json { + static std::string escape_json(const std::string &s) { + std::ostringstream o; + for (auto c = s.cbegin(); c != s.cend(); c++) { + switch (*c) { + case '"': o << "\\\""; break; + case '\\': o << "\\\\"; break; + case '\b': o << "\\b"; break; + case '\f': o << "\\f"; break; + case '\n': o << "\\n"; break; + case '\r': o << "\\r"; break; + case '\t': o << "\\t"; break; + default: + if ('\x00' <= *c && *c <= '\x1f') { + o << "\\u" + << std::hex << std::setw(4) << std::setfill('0') << static_cast(*c); + } else { + o << *c; + } + } + } + return o.str(); + } + + std::string map_to_json(const map_t& values) { + std::ostringstream ss; + ss << "{ "; + size_t ix = 0; + for (const auto& element : values) { + if (ix > 0) { + ss << ","; + } + + ss << "\"" << escape_json(element.first) << "\": "; + + const auto& value = element.second.data; + if (std::holds_alternative(value)) { + ss << "\"" << escape_json(std::get(value)) << "\""; + } + else if (std::holds_alternative(value)) { + ss << std::defaultfloat << std::get(value); + } + else if (std::holds_alternative(value)) { + ss << std::get(value); + } + else if (std::holds_alternative(value)) { + ss << std::get(value); + } + else if (std::holds_alternative(value)) { + ss << (std::get(value) ? "true" : "false"); + } + else if (std::holds_alternative(value)) { + ss << "null"; + } + else if (std::holds_alternative(value)) { + ss << map_to_json(std::get(value)); + } + else { + throw std::logic_error("variant alternative not handled"); + } + + ix++; + } + ss << " }"; + + return ss.str(); + } +} diff --git a/lib/Json.h b/lib/Json.h new file mode 100644 index 0000000..26da9a8 --- /dev/null +++ b/lib/Json.h @@ -0,0 +1,66 @@ +/* + Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 + Her Majesty the Queen in Right of Canada (Communications Research + Center Canada) + + Copyright (C) 2023 + Matthias P. Braendli, matthias.braendli@mpb.li + + http://www.opendigitalradio.org + + This module adds remote-control capability to some of the dabmux/dabmod modules. + */ +/* + 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 3 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#pragma once + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include + +namespace json { + + using map_t = std::unordered_map; + + struct value_t { + std::variant< + map_t, + std::string, + double, + size_t, + ssize_t, + bool, + std::nullopt_t> data; + + template + value_t operator=(const T& map) { + value_t v; + v.data = map; + return v; + } + + }; + + std::string map_to_json(const map_t& values); +} diff --git a/lib/RemoteControl.cpp b/lib/RemoteControl.cpp index fd0ea77..b544461 100644 --- a/lib/RemoteControl.cpp +++ b/lib/RemoteControl.cpp @@ -105,71 +105,14 @@ std::list< std::vector > RemoteControllers::get_param_list_values(c } -static std::string escape_json(const std::string &s) { - std::ostringstream o; - for (auto c = s.cbegin(); c != s.cend(); c++) { - switch (*c) { - case '"': o << "\\\""; break; - case '\\': o << "\\\\"; break; - case '\b': o << "\\b"; break; - case '\f': o << "\\f"; break; - case '\n': o << "\\n"; break; - case '\r': o << "\\r"; break; - case '\t': o << "\\t"; break; - default: - if ('\x00' <= *c && *c <= '\x1f') { - o << "\\u" - << std::hex << std::setw(4) << std::setfill('0') << static_cast(*c); - } else { - o << *c; - } - } - } - return o.str(); -} - -std::string RemoteControllers::get_params_json(const std::string& name) { - RemoteControllable* controllable = get_controllable_(name); - const auto& values = controllable->get_all_values(); - - std::ostringstream ss; - ss << "{ "; - size_t ix = 0; - for (const auto& element : values) { - if (ix > 0) { - ss << ","; - } - - ss << "\"" << escape_json(element.first) << "\": "; - - const auto& value = element.second; - if (std::holds_alternative(value)) { - ss << "\"" << escape_json(std::get(value)) << "\""; - } - else if (std::holds_alternative(value)) { - ss << std::defaultfloat << std::get(value); - } - else if (std::holds_alternative(value)) { - ss << std::get(value); - } - else if (std::holds_alternative(value)) { - ss << std::get(value); - } - else if (std::holds_alternative(value)) { - ss << (std::get(value) ? "true" : "false"); - } - else if (std::holds_alternative(value)) { - ss << "null"; - } - else { - throw std::logic_error("variant alternative not handled"); - } - ix++; +std::string RemoteControllers::get_showjson() { + json::map_t root; + for (auto &controllable : rcs.controllables) { + root[controllable->get_rc_name()].data = controllable->get_all_values(); } - ss << " }"; - return ss.str(); + return json::map_to_json(root); } std::string RemoteControllers::get_param(const std::string& name, const std::string& param) { @@ -590,6 +533,19 @@ void RemoteControllerZmq::process() repSocket.send(zmsg, (--cohort_size > 0) ? zmq::send_flags::sndmore : zmq::send_flags::none); } } + else if (msg.size() == 1 && command == "showjson") { + try { + std::string json = rcs.get_showjson(); + + zmq::message_t zmsg(json.size()); + memcpy(zmsg.data(), json.data(), json.size()); + + repSocket.send(zmsg, zmq::send_flags::none); + } + catch (const ParameterError &err) { + send_fail_reply(repSocket, err.what()); + } + } else if (msg.size() == 2 && command == "show") { const std::string module((char*) msg[1].data(), msg[1].size()); try { @@ -608,20 +564,6 @@ void RemoteControllerZmq::process() send_fail_reply(repSocket, err.what()); } } - else if (msg.size() == 2 && command == "showjson") { - const std::string module((char*) msg[1].data(), msg[1].size()); - try { - std::string json = rcs.get_params_json(module); - - zmq::message_t zmsg(json.size()); - memcpy(zmsg.data(), json.data(), json.size()); - - repSocket.send(zmsg, zmq::send_flags::none); - } - catch (const ParameterError &err) { - send_fail_reply(repSocket, err.what()); - } - } else if (msg.size() == 3 && command == "get") { const std::string module((char*) msg[1].data(), msg[1].size()); const std::string parameter((char*) msg[2].data(), msg[2].size()); diff --git a/lib/RemoteControl.h b/lib/RemoteControl.h index 4bc3b68..26f30d9 100644 --- a/lib/RemoteControl.h +++ b/lib/RemoteControl.h @@ -48,6 +48,7 @@ #include "Log.h" #include "Socket.h" +#include "Json.h" #define RC_ADD_PARAMETER(p, desc) { \ std::vector p; \ @@ -120,10 +121,7 @@ class RemoteControllable { /* Getting a parameter always returns a string. */ virtual const std::string get_parameter(const std::string& parameter) const = 0; - using value_t = std::variant; - using map_t = std::unordered_map; - - virtual const map_t get_all_values() const = 0; + virtual const json::map_t get_all_values() const = 0; protected: std::string m_rc_name; @@ -140,7 +138,7 @@ class RemoteControllers { void check_faults(); std::list< std::vector > get_param_list_values(const std::string& name); std::string get_param(const std::string& name, const std::string& param); - std::string get_params_json(const std::string& name); + std::string get_showjson(); void set_param( const std::string& name, diff --git a/src/DabModulator.cpp b/src/DabModulator.cpp index 5213d8d..0fe9c6d 100644 --- a/src/DabModulator.cpp +++ b/src/DabModulator.cpp @@ -435,9 +435,9 @@ const string DabModulator::get_parameter(const string& parameter) const return ss.str(); } -const RemoteControllable::map_t DabModulator::get_all_values() const +const json::map_t DabModulator::get_all_values() const { - map_t map; + json::map_t map; map["rate"] = m_settings.outputRate; map["num_clipped_samples"] = m_formatConverter ? m_formatConverter->get_num_clipped_samples() : 0; return map; diff --git a/src/DabModulator.h b/src/DabModulator.h index 6381252..140f313 100644 --- a/src/DabModulator.h +++ b/src/DabModulator.h @@ -64,7 +64,7 @@ public: /******* REMOTE CONTROL ********/ virtual void set_parameter(const std::string& parameter, const std::string& value) override; virtual const std::string get_parameter(const std::string& parameter) const override; - virtual const RemoteControllable::map_t get_all_values() const override; + virtual const json::map_t get_all_values() const override; protected: void setMode(unsigned mode); diff --git a/src/FIRFilter.cpp b/src/FIRFilter.cpp index 523d405..d2a6121 100644 --- a/src/FIRFilter.cpp +++ b/src/FIRFilter.cpp @@ -347,9 +347,9 @@ const string FIRFilter::get_parameter(const string& parameter) const return ss.str(); } -const RemoteControllable::map_t FIRFilter::get_all_values() const +const json::map_t FIRFilter::get_all_values() const { - map_t map; + json::map_t map; map["ntaps"] = m_taps.size(); map["tapsfile"] = m_taps_file; return map; diff --git a/src/FIRFilter.h b/src/FIRFilter.h index 2a469aa..a4effa1 100644 --- a/src/FIRFilter.h +++ b/src/FIRFilter.h @@ -61,7 +61,7 @@ public: /******* REMOTE CONTROL ********/ virtual void set_parameter(const std::string& parameter, const std::string& value) override; virtual const std::string get_parameter(const std::string& parameter) const override; - virtual const RemoteControllable::map_t get_all_values() const override; + virtual const json::map_t get_all_values() const override; protected: virtual int internal_process(Buffer* const dataIn, Buffer* dataOut) override; diff --git a/src/GainControl.cpp b/src/GainControl.cpp index d90da45..beb93f6 100644 --- a/src/GainControl.cpp +++ b/src/GainControl.cpp @@ -583,9 +583,9 @@ const string GainControl::get_parameter(const string& parameter) const return ss.str(); } -const RemoteControllable::map_t GainControl::get_all_values() const +const json::map_t GainControl::get_all_values() const { - map_t map; + json::map_t map; map["digital"] = m_digGain; switch (m_gainmode) { case GainMode::GAIN_FIX: diff --git a/src/GainControl.h b/src/GainControl.h index f024fa2..04f6b58 100644 --- a/src/GainControl.h +++ b/src/GainControl.h @@ -66,7 +66,7 @@ class GainControl : public PipelinedModCodec, public RemoteControllable /* Functions for the remote control */ virtual void set_parameter(const std::string& parameter, const std::string& value) override; virtual const std::string get_parameter(const std::string& parameter) const override; - virtual const RemoteControllable::map_t get_all_values() const override; + virtual const json::map_t get_all_values() const override; protected: virtual int internal_process( diff --git a/src/GuardIntervalInserter.cpp b/src/GuardIntervalInserter.cpp index d5c71fb..80394b7 100644 --- a/src/GuardIntervalInserter.cpp +++ b/src/GuardIntervalInserter.cpp @@ -303,9 +303,9 @@ const std::string GuardIntervalInserter::get_parameter(const std::string& parame return ss.str(); } -const RemoteControllable::map_t GuardIntervalInserter::get_all_values() const +const json::map_t GuardIntervalInserter::get_all_values() const { - map_t map; + json::map_t map; map["windowlen"] = d_windowOverlap; return map; } diff --git a/src/GuardIntervalInserter.h b/src/GuardIntervalInserter.h index f88bdac..5aaad2b 100644 --- a/src/GuardIntervalInserter.h +++ b/src/GuardIntervalInserter.h @@ -58,7 +58,7 @@ class GuardIntervalInserter : public ModCodec, public RemoteControllable /******* REMOTE CONTROL ********/ virtual void set_parameter(const std::string& parameter, const std::string& value) override; virtual const std::string get_parameter(const std::string& parameter) const override; - virtual const RemoteControllable::map_t get_all_values() const override; + virtual const json::map_t get_all_values() const override; protected: void update_window(size_t new_window_overlap); diff --git a/src/MemlessPoly.cpp b/src/MemlessPoly.cpp index a2b0082..30d4ce9 100644 --- a/src/MemlessPoly.cpp +++ b/src/MemlessPoly.cpp @@ -467,9 +467,9 @@ const string MemlessPoly::get_parameter(const string& parameter) const return ss.str(); } -const RemoteControllable::map_t MemlessPoly::get_all_values() const +const json::map_t MemlessPoly::get_all_values() const { - map_t map; + json::map_t map; map["ncoefs"] = m_coefs_am.size(); map["coefs"] = serialise_coefficients(); map["coeffile"] = m_coefs_file; diff --git a/src/MemlessPoly.h b/src/MemlessPoly.h index 09adc13..91e6860 100644 --- a/src/MemlessPoly.h +++ b/src/MemlessPoly.h @@ -68,7 +68,7 @@ public: /******* REMOTE CONTROL ********/ virtual void set_parameter(const std::string& parameter, const std::string& value) override; virtual const std::string get_parameter(const std::string& parameter) const override; - virtual const RemoteControllable::map_t get_all_values() const override; + virtual const json::map_t get_all_values() const override; private: int internal_process(Buffer* const dataIn, Buffer* dataOut) override; diff --git a/src/OfdmGenerator.cpp b/src/OfdmGenerator.cpp index d161861..cb799d3 100644 --- a/src/OfdmGenerator.cpp +++ b/src/OfdmGenerator.cpp @@ -458,9 +458,9 @@ const std::string OfdmGenerator::get_parameter(const std::string& parameter) con return ss.str(); } -const RemoteControllable::map_t OfdmGenerator::get_all_values() const +const json::map_t OfdmGenerator::get_all_values() const { - map_t map; + json::map_t map; // TODO needs rework of the values return map; } diff --git a/src/OfdmGenerator.h b/src/OfdmGenerator.h index 90e562a..dc1ad46 100644 --- a/src/OfdmGenerator.h +++ b/src/OfdmGenerator.h @@ -61,7 +61,7 @@ class OfdmGenerator : public ModCodec, public RemoteControllable /* Functions for the remote control */ virtual void set_parameter(const std::string& parameter, const std::string& value) override; virtual const std::string get_parameter(const std::string& parameter) const override; - virtual const RemoteControllable::map_t get_all_values() const override; + virtual const json::map_t get_all_values() const override; protected: struct cfr_iter_stat_t { diff --git a/src/TII.cpp b/src/TII.cpp index b329cdb..9068630 100644 --- a/src/TII.cpp +++ b/src/TII.cpp @@ -385,9 +385,9 @@ const std::string TII::get_parameter(const std::string& parameter) const return ss.str(); } -const RemoteControllable::map_t TII::get_all_values() const +const json::map_t TII::get_all_values() const { - map_t map; + json::map_t map; map["enable"] = m_conf.enable; map["pattern"] = m_conf.pattern; map["comb"] = m_conf.comb; diff --git a/src/TII.h b/src/TII.h index b0ba646..a8d0ca9 100644 --- a/src/TII.h +++ b/src/TII.h @@ -89,7 +89,7 @@ class TII : public ModCodec, public RemoteControllable /******* REMOTE CONTROL ********/ virtual void set_parameter(const std::string& parameter, const std::string& value) override; virtual const std::string get_parameter(const std::string& parameter) const override; - virtual const RemoteControllable::map_t get_all_values() const override; + virtual const json::map_t get_all_values() const override; protected: // Fill m_Acp with the correct carriers for the pattern/comb diff --git a/src/TimestampDecoder.cpp b/src/TimestampDecoder.cpp index 149cd50..4277e55 100644 --- a/src/TimestampDecoder.cpp +++ b/src/TimestampDecoder.cpp @@ -301,9 +301,9 @@ const std::string TimestampDecoder::get_parameter( return ss.str(); } -const RemoteControllable::map_t TimestampDecoder::get_all_values() const +const json::map_t TimestampDecoder::get_all_values() const { - map_t map; + json::map_t map; map["offset"] = timestamp_offset; if (full_timestamp_received) { map["timestamp"] = time_secs + ((double)time_pps / 16384000.0); diff --git a/src/TimestampDecoder.h b/src/TimestampDecoder.h index dc5aa78..b90c328 100644 --- a/src/TimestampDecoder.h +++ b/src/TimestampDecoder.h @@ -120,7 +120,7 @@ class TimestampDecoder : public RemoteControllable /* Base function to set parameters. */ virtual void set_parameter(const std::string& parameter, const std::string& value) override; virtual const std::string get_parameter(const std::string& parameter) const override; - virtual const RemoteControllable::map_t get_all_values() const override; + virtual const json::map_t get_all_values() const override; const char* name() { return "TS"; } diff --git a/src/output/SDR.cpp b/src/output/SDR.cpp index 11321f2..4fc3277 100644 --- a/src/output/SDR.cpp +++ b/src/output/SDR.cpp @@ -450,7 +450,7 @@ const string SDR::get_parameter(const string& parameter) const if (m_device) { const auto stat = m_device->get_run_statistics(); try { - const auto& value = stat.at(parameter); + const auto& value = stat.at(parameter).data; if (std::holds_alternative(value)) { ss << std::get(value); } @@ -485,9 +485,9 @@ const string SDR::get_parameter(const string& parameter) const return ss.str(); } -const RemoteControllable::map_t SDR::get_all_values() const +const json::map_t SDR::get_all_values() const { - map_t stat = m_device->get_run_statistics(); + json::map_t stat = m_device->get_run_statistics(); stat["txgain"] = m_config.txgain; stat["rxgain"] = m_config.rxgain; diff --git a/src/output/SDR.h b/src/output/SDR.h index 94c972b..960de0c 100644 --- a/src/output/SDR.h +++ b/src/output/SDR.h @@ -67,7 +67,7 @@ class SDR : public ModOutput, public ModMetadata, public RemoteControllable { virtual const std::string get_parameter( const std::string& parameter) const override; - virtual const RemoteControllable::map_t get_all_values() const override; + virtual const json::map_t get_all_values() const override; private: void process_thread_entry(void); diff --git a/src/output/SDRDevice.h b/src/output/SDRDevice.h index f84b340..f728d8b 100644 --- a/src/output/SDRDevice.h +++ b/src/output/SDRDevice.h @@ -116,7 +116,7 @@ struct FrameData { // All SDR Devices must implement the SDRDevice interface class SDRDevice { public: - using run_statistics_t = RemoteControllable::map_t; + using run_statistics_t = json::map_t; virtual void tune(double lo_offset, double frequency) = 0; virtual double get_tx_freq(void) const = 0; -- cgit v1.2.3