From 71f13f0ab8c44ab3932fae882b0e6100e5676053 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 9 May 2023 16:43:33 +0100 Subject: [PATCH 001/106] Create IS-12 websocket server --- Development/cmake/NmosCppLibraries.cmake | 3 + Development/nmos/control_protocol_ws_api.cpp | 84 ++++++++++++++++++++ Development/nmos/control_protocol_ws_api.h | 33 ++++++++ Development/nmos/is12_versions.h | 26 ++++++ Development/nmos/node_resources.cpp | 21 +++++ Development/nmos/node_server.cpp | 15 +++- Development/nmos/settings.cpp | 3 + Development/nmos/settings.h | 4 + 8 files changed, 187 insertions(+), 2 deletions(-) create mode 100644 Development/nmos/control_protocol_ws_api.cpp create mode 100644 Development/nmos/control_protocol_ws_api.h create mode 100644 Development/nmos/is12_versions.h diff --git a/Development/cmake/NmosCppLibraries.cmake b/Development/cmake/NmosCppLibraries.cmake index b6d6d972a..e3e365cf8 100644 --- a/Development/cmake/NmosCppLibraries.cmake +++ b/Development/cmake/NmosCppLibraries.cmake @@ -757,6 +757,7 @@ set(NMOS_CPP_NMOS_SOURCES nmos/connection_api.cpp nmos/connection_events_activation.cpp nmos/connection_resources.cpp + nmos/control_protocol_ws_api.cpp nmos/did_sdid.cpp nmos/events_api.cpp nmos/events_resources.cpp @@ -828,6 +829,7 @@ set(NMOS_CPP_NMOS_HEADERS nmos/connection_api.h nmos/connection_events_activation.h nmos/connection_resources.h + nmos/control_protocol_ws_api.h nmos/device_type.h nmos/did_sdid.h nmos/event_type.h @@ -846,6 +848,7 @@ set(NMOS_CPP_NMOS_HEADERS nmos/is07_versions.h nmos/is08_versions.h nmos/is09_versions.h + nmos/is12_versions.h nmos/json_fields.h nmos/json_schema.h nmos/lldp_handler.h diff --git a/Development/nmos/control_protocol_ws_api.cpp b/Development/nmos/control_protocol_ws_api.cpp new file mode 100644 index 000000000..0a067d524 --- /dev/null +++ b/Development/nmos/control_protocol_ws_api.cpp @@ -0,0 +1,84 @@ +#include "nmos/control_protocol_ws_api.h" + +#include "nmos/slog.h" + +namespace nmos +{ + // IS-12 Control Protocol WebSocket API + + web::websockets::experimental::listener::validate_handler make_control_protocol_ws_validate_handler(nmos::node_model& model, slog::base_gate& gate_) + { + return [&model, &gate_](web::http::http_request req) + { + nmos::ws_api_gate gate(gate_, req.request_uri()); + + // RFC 6750 defines two methods of sending bearer access tokens which are applicable to WebSocket + // Clients SHOULD use the "Authorization Request Header Field" method. + // Clients MAY use a "URI Query Parameter". + // See https://tools.ietf.org/html/rfc6750#section-2 + + // For now just return true + const auto& ws_ncp_path = req.request_uri().path(); + slog::log(gate, SLOG_FLF) << "Validating websocket connection to: " << ws_ncp_path; + + return true; + }; + } + + web::websockets::experimental::listener::open_handler make_control_protocol_ws_open_handler(nmos::node_model& model, nmos::websockets& websockets, slog::base_gate& gate_) + { + return [&model, &websockets, &gate_](const web::uri& connection_uri, const web::websockets::experimental::listener::connection_id& connection_id) + { + nmos::ws_api_gate gate(gate_, connection_uri); + + const auto& ws_ncp_path = connection_uri.path(); + slog::log(gate, SLOG_FLF) << "Opening websocket connection to: " << ws_ncp_path; + { + // create a websocket connection resource + + nmos::id id = nmos::make_id(); + websockets.insert({ id, connection_id }); + + slog::log(gate, SLOG_FLF) << "Creating websocket connection: " << id; + } + }; + } + + web::websockets::experimental::listener::close_handler make_control_protocol_ws_close_handler(nmos::node_model& model, nmos::websockets& websockets, slog::base_gate& gate_) + { + return [&model, &websockets, &gate_](const web::uri& connection_uri, const web::websockets::experimental::listener::connection_id& connection_id, web::websockets::websocket_close_status close_status, const utility::string_t& close_reason) + { + nmos::ws_api_gate gate(gate_, connection_uri); + + const auto& ws_ncp_path = connection_uri.path(); + slog::log(gate, SLOG_FLF) << "Closing websocket connection to: " << ws_ncp_path << " [" << (int)close_status << ": " << close_reason << "]"; + + auto websocket = websockets.right.find(connection_id); + if (websockets.right.end() != websocket) + { + slog::log(gate, SLOG_FLF) << "Deleting websocket connection"; + + websockets.right.erase(websocket); + } + }; + } + + web::websockets::experimental::listener::message_handler make_control_protocol_ws_message_handler(nmos::node_model& model, nmos::websockets& websockets, slog::base_gate& gate_) + { + return [&model, &websockets, &gate_](const web::uri& connection_uri, const web::websockets::experimental::listener::connection_id& connection_id, const web::websockets::websocket_incoming_message& msg_) + { + nmos::ws_api_gate gate(gate_, connection_uri); + // theoretically blocking, but in fact not + auto msg = msg_.extract_string().get(); + + const auto& ws_ncp_path = connection_uri.path(); + slog::log(gate, SLOG_FLF) << "Received websocket message: " << msg << " on connection to: " << ws_ncp_path; + + auto websocket = websockets.right.find(connection_id); + if (websockets.right.end() != websocket) + { + // hmm, todo message handling.... + } + }; + } +} diff --git a/Development/nmos/control_protocol_ws_api.h b/Development/nmos/control_protocol_ws_api.h new file mode 100644 index 000000000..1469666f0 --- /dev/null +++ b/Development/nmos/control_protocol_ws_api.h @@ -0,0 +1,33 @@ +#ifndef NMOS_CONTROL_PROTOCOL_WS_API_H +#define NMOS_CONTROL_PROTOCOL_WS_API_H + +#include "nmos/websockets.h" + +namespace slog +{ + class base_gate; +} + +// Events API websocket implementation +// See https://specs.amwa.tv/is-07/releases/v1.0.1/docs/5.2._Transport_-_Websocket.html +namespace nmos +{ + struct node_model; + + web::websockets::experimental::listener::validate_handler make_control_protocol_ws_validate_handler(nmos::node_model& model, slog::base_gate& gate); + web::websockets::experimental::listener::open_handler make_control_protocol_ws_open_handler(nmos::node_model& model, nmos::websockets& websockets, slog::base_gate& gate); + web::websockets::experimental::listener::close_handler make_control_protocol_ws_close_handler(nmos::node_model& model, nmos::websockets& websockets, slog::base_gate& gate); + web::websockets::experimental::listener::message_handler make_control_protocol_ws_message_handler(nmos::node_model& model, nmos::websockets& websockets, slog::base_gate& gate); + + inline web::websockets::experimental::listener::websocket_listener_handlers make_control_protocol_ws_api(nmos::node_model& model, nmos::websockets& websockets, slog::base_gate& gate) + { + return{ + nmos::make_control_protocol_ws_validate_handler(model, gate), + nmos::make_control_protocol_ws_open_handler(model, websockets, gate), + nmos::make_control_protocol_ws_close_handler(model, websockets, gate), + nmos::make_control_protocol_ws_message_handler(model, websockets, gate) + }; + } +} + +#endif diff --git a/Development/nmos/is12_versions.h b/Development/nmos/is12_versions.h new file mode 100644 index 000000000..06dfc1d59 --- /dev/null +++ b/Development/nmos/is12_versions.h @@ -0,0 +1,26 @@ +#ifndef NMOS_IS12_VERSIONS_H +#define NMOS_IS12_VERSIONS_H + +#include +#include +#include "nmos/api_version.h" +#include "nmos/settings.h" + +namespace nmos +{ + namespace is12_versions + { + const api_version v1_0{ 1, 0 }; + + const std::set all{ nmos::is12_versions::v1_0 }; + + inline std::set from_settings(const nmos::settings& settings) + { + return settings.has_field(nmos::fields::is12_versions) + ? boost::copy_range>(nmos::fields::is12_versions(settings) | boost::adaptors::transformed([](const web::json::value& v) { return nmos::parse_api_version(v.as_string()); })) + : nmos::is12_versions::all; + } + } +} + +#endif diff --git a/Development/nmos/node_resources.cpp b/Development/nmos/node_resources.cpp index 7c75cf01a..8daa2975d 100644 --- a/Development/nmos/node_resources.cpp +++ b/Development/nmos/node_resources.cpp @@ -16,6 +16,7 @@ #include "nmos/is05_versions.h" #include "nmos/is07_versions.h" #include "nmos/is08_versions.h" +#include "nmos/is12_versions.h" #include "nmos/media_type.h" #include "nmos/resource.h" #include "nmos/sdp_utils.h" // for nmos::make_components @@ -125,6 +126,26 @@ namespace nmos } } + if (0 <= nmos::fields::control_protocol_ws_port(settings)) + { + for (const auto& version : nmos::is12_versions::from_settings(settings)) + { + auto ncp_uri = web::uri_builder() + .set_scheme(nmos::ws_scheme(settings)) + .set_port(nmos::fields::control_protocol_ws_port(settings)) + .set_path(U("/x-nmos/ncp/") + make_api_version(version)); + auto type = U("urn:x-nmos:control:ncp/") + make_api_version(version); + + for (const auto& host : hosts) + { + web::json::push_back(data[U("controls")], value_of({ + { U("href"), ncp_uri.set_host(host).to_uri().to_string() }, + { U("type"), type } + })); + } + } + } + return{ is04_versions::v1_3, types::device, std::move(data), false }; } diff --git a/Development/nmos/node_server.cpp b/Development/nmos/node_server.cpp index ecc75c461..1f38c1a73 100644 --- a/Development/nmos/node_server.cpp +++ b/Development/nmos/node_server.cpp @@ -3,6 +3,7 @@ #include "cpprest/ws_utils.h" #include "nmos/api_utils.h" #include "nmos/channelmapping_activation.h" +#include "nmos/control_protocol_ws_api.h" #include "nmos/events_api.h" #include "nmos/events_ws_api.h" #include "nmos/logging_api.h" @@ -63,9 +64,16 @@ namespace nmos // Configure the Channel Mapping API node_server.api_routers[{ {}, nmos::fields::channelmapping_port(node_model.settings) }].mount({}, nmos::make_channelmapping_api(node_model, node_implementation.validate_map, gate)); - auto& events_ws_api = node_server.ws_handlers[{ {}, nmos::fields::events_ws_port(node_model.settings) }]; + const auto& events_ws_port = nmos::fields::events_ws_port(node_model.settings); + auto& events_ws_api = node_server.ws_handlers[{ {}, events_ws_port }]; events_ws_api.first = nmos::make_events_ws_api(node_model, events_ws_api.second, gate); + // can't share a port between the events ws and the control protocol ws + const auto& control_protocol_ws_port = nmos::fields::control_protocol_ws_port(node_model.settings); + if (control_protocol_ws_port == events_ws_port) throw std::runtime_error("Same port used for events and control protocol websockets are not supported"); + auto& control_protocol_ws_api = node_server.ws_handlers[{ {}, control_protocol_ws_port }]; + control_protocol_ws_api.first = nmos::make_control_protocol_ws_api(node_model, control_protocol_ws_api.second, gate); + // Set up the listeners for each HTTP API port auto http_config = nmos::make_http_listener_config(node_model.settings, node_implementation.load_server_certificates, node_implementation.load_dh_param, node_implementation.get_ocsp_response, gate); @@ -84,6 +92,7 @@ namespace nmos auto websocket_config = nmos::make_websocket_listener_config(node_model.settings, node_implementation.load_server_certificates, node_implementation.load_dh_param, node_implementation.get_ocsp_response, gate); websocket_config.set_log_callback(nmos::make_slog_logging_callback(gate)); + size_t event_ws_pos{ 0 }; for (auto& ws_handler : node_server.ws_handlers) { // if IP address isn't specified for this router, use default server address or wildcard address @@ -91,9 +100,11 @@ namespace nmos // map the configured client port to the server port on which to listen // hmm, this should probably also take account of the address node_server.ws_listeners.push_back(nmos::make_ws_api_listener(server_secure, host, nmos::experimental::server_port(ws_handler.first.second, node_model.settings), ws_handler.second.first, websocket_config, gate)); + + event_ws_pos = (ws_handler.first.second == events_ws_port) ? event_ws_pos : ++event_ws_pos; } - auto& events_ws_listener = node_server.ws_listeners.back(); + auto& events_ws_listener = node_server.ws_listeners.at(event_ws_pos); // Set up node operation (including the DNS-SD advertisements) diff --git a/Development/nmos/settings.cpp b/Development/nmos/settings.cpp index c8943c93e..7e6010d30 100644 --- a/Development/nmos/settings.cpp +++ b/Development/nmos/settings.cpp @@ -66,6 +66,8 @@ namespace nmos const auto http_port = nmos::fields::http_port(settings); // can't share a port between an http_listener and a websocket_listener, so use next higher port const auto ws_port = http_port + 1; + // can't share a port between the events ws and the control protocol ws + const auto ncp_ws_port = ws_port + 1; if (registry) web::json::insert(settings, std::make_pair(nmos::fields::query_port, http_port)); if (registry) web::json::insert(settings, std::make_pair(nmos::fields::query_ws_port, ws_port)); if (registry) web::json::insert(settings, std::make_pair(nmos::fields::registration_port, http_port)); @@ -81,6 +83,7 @@ namespace nmos if (registry) web::json::insert(settings, std::make_pair(nmos::experimental::fields::admin_port, http_port)); if (registry) web::json::insert(settings, std::make_pair(nmos::experimental::fields::mdns_port, http_port)); if (registry) web::json::insert(settings, std::make_pair(nmos::experimental::fields::schemas_port, http_port)); + if (!registry) web::json::insert(settings, std::make_pair(nmos::fields::control_protocol_ws_port, ncp_ws_port)); } } } diff --git a/Development/nmos/settings.h b/Development/nmos/settings.h index cf55267fd..1f240e21f 100644 --- a/Development/nmos/settings.h +++ b/Development/nmos/settings.h @@ -101,6 +101,9 @@ namespace nmos // is09_versions [registry, node]: used to specify the enabled API versions for a version-locked configuration const web::json::field_as_array is09_versions{ U("is09_versions") }; // when omitted, nmos::is09_versions::all is used + // is12_versions [node]: used to specify the enabled API versions for a version-locked configuration + const web::json::field_as_array is12_versions{ U("is12_versions") }; // when omitted, nmos::is12_versions::all is used + // pri [registry, node]: used for the 'pri' TXT record; specifying nmos::service_priorities::no_priority (maximum value) disables advertisement completely const web::json::field_as_integer_or pri{ U("pri"), 100 }; // default to highest_development_priority @@ -136,6 +139,7 @@ namespace nmos const web::json::field_as_integer_or channelmapping_port{ U("channelmapping_port"), 3215 }; // system_port [node]: used to construct request URLs for the System API (if not discovered via DNS-SD) const web::json::field_as_integer_or system_port{ U("system_port"), 10641 }; + const web::json::field_as_integer_or control_protocol_ws_port{ U("control_protocol_ws_port"), 3218 }; // listen_backlog [registry, node]: the maximum length of the queue of pending connections, or zero for the implementation default (the implementation may not honour this value) const web::json::field_as_integer_or listen_backlog{ U("listen_backlog"), 0 }; From c3d363793a20c191e6041c49b9bd08b14422811c Mon Sep 17 00:00:00 2001 From: lo-simon Date: Wed, 10 May 2023 01:36:00 +0100 Subject: [PATCH 002/106] Remove incorrect comment --- Development/nmos/control_protocol_ws_api.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/Development/nmos/control_protocol_ws_api.h b/Development/nmos/control_protocol_ws_api.h index 1469666f0..71772961f 100644 --- a/Development/nmos/control_protocol_ws_api.h +++ b/Development/nmos/control_protocol_ws_api.h @@ -8,8 +8,6 @@ namespace slog class base_gate; } -// Events API websocket implementation -// See https://specs.amwa.tv/is-07/releases/v1.0.1/docs/5.2._Transport_-_Websocket.html namespace nmos { struct node_model; From 4728d7cbc0bae4f56893ba393d4d10ab5d9d0c75 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Wed, 10 May 2023 01:37:42 +0100 Subject: [PATCH 003/106] Add `control_protocol_ws_port` to node example config --- Development/nmos-cpp-node/config.json | 1 + 1 file changed, 1 insertion(+) diff --git a/Development/nmos-cpp-node/config.json b/Development/nmos-cpp-node/config.json index 5bf63a9ff..087db3683 100644 --- a/Development/nmos-cpp-node/config.json +++ b/Development/nmos-cpp-node/config.json @@ -134,6 +134,7 @@ //"channelmapping_port": 3215, // system_port [node]: used to construct request URLs for the System API (if not discovered via DNS-SD) //"system_port": 10641, + //"control_protocol_ws_port": 3218, // listen_backlog [registry, node]: the maximum length of the queue of pending connections, or zero for the implementation default (the implementation may not honour this value) //"listen_backlog": 0, From 549dd0ef5e0b0c94e6b23fe270741a72cdd98aa7 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Mon, 15 May 2023 19:09:11 +0100 Subject: [PATCH 004/106] Use lock to protect websockets --- Development/nmos/control_protocol_ws_api.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Development/nmos/control_protocol_ws_api.cpp b/Development/nmos/control_protocol_ws_api.cpp index 0a067d524..89e11721a 100644 --- a/Development/nmos/control_protocol_ws_api.cpp +++ b/Development/nmos/control_protocol_ws_api.cpp @@ -1,5 +1,6 @@ #include "nmos/control_protocol_ws_api.h" +#include "nmos/model.h" #include "nmos/slog.h" namespace nmos @@ -30,6 +31,7 @@ namespace nmos return [&model, &websockets, &gate_](const web::uri& connection_uri, const web::websockets::experimental::listener::connection_id& connection_id) { nmos::ws_api_gate gate(gate_, connection_uri); + auto lock = model.write_lock(); const auto& ws_ncp_path = connection_uri.path(); slog::log(gate, SLOG_FLF) << "Opening websocket connection to: " << ws_ncp_path; @@ -49,6 +51,7 @@ namespace nmos return [&model, &websockets, &gate_](const web::uri& connection_uri, const web::websockets::experimental::listener::connection_id& connection_id, web::websockets::websocket_close_status close_status, const utility::string_t& close_reason) { nmos::ws_api_gate gate(gate_, connection_uri); + auto lock = model.write_lock(); const auto& ws_ncp_path = connection_uri.path(); slog::log(gate, SLOG_FLF) << "Closing websocket connection to: " << ws_ncp_path << " [" << (int)close_status << ": " << close_reason << "]"; @@ -68,7 +71,9 @@ namespace nmos return [&model, &websockets, &gate_](const web::uri& connection_uri, const web::websockets::experimental::listener::connection_id& connection_id, const web::websockets::websocket_incoming_message& msg_) { nmos::ws_api_gate gate(gate_, connection_uri); - // theoretically blocking, but in fact not + auto lock = model.read_lock(); + + // theoretically blocking, but in fact not auto msg = msg_.extract_string().get(); const auto& ws_ncp_path = connection_uri.path(); From 599a5f5635b22f5ee75376f6d4ac67282daaf97c Mon Sep 17 00:00:00 2001 From: lo-simon Date: Mon, 15 May 2023 19:11:52 +0100 Subject: [PATCH 005/106] Fix to obtain the event_ws position from the ws_handlers --- Development/nmos/node_server.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Development/nmos/node_server.cpp b/Development/nmos/node_server.cpp index 1f38c1a73..293784adc 100644 --- a/Development/nmos/node_server.cpp +++ b/Development/nmos/node_server.cpp @@ -93,6 +93,7 @@ namespace nmos websocket_config.set_log_callback(nmos::make_slog_logging_callback(gate)); size_t event_ws_pos{ 0 }; + bool found_event_ws{ false }; for (auto& ws_handler : node_server.ws_handlers) { // if IP address isn't specified for this router, use default server address or wildcard address @@ -101,7 +102,11 @@ namespace nmos // hmm, this should probably also take account of the address node_server.ws_listeners.push_back(nmos::make_ws_api_listener(server_secure, host, nmos::experimental::server_port(ws_handler.first.second, node_model.settings), ws_handler.second.first, websocket_config, gate)); - event_ws_pos = (ws_handler.first.second == events_ws_port) ? event_ws_pos : ++event_ws_pos; + if (!found_event_ws) + { + if (ws_handler.first.second == events_ws_port) { found_event_ws = true; } + else { ++event_ws_pos; } + } } auto& events_ws_listener = node_server.ws_listeners.at(event_ws_pos); From fae85fbfd500f4b8071708864be934fbe9c5a42d Mon Sep 17 00:00:00 2001 From: lo-simon Date: Thu, 3 Aug 2023 22:47:44 +0100 Subject: [PATCH 006/106] Create Root block, Device manager and Class manager nmos resources --- Development/cmake/NmosCppLibraries.cmake | 77 ++ Development/nmos-cpp-node/config.json | 14 + .../nmos-cpp-node/node_implementation.cpp | 12 + .../nmos/control_protocol_resources.cpp | 960 ++++++++++++++++++ Development/nmos/control_protocol_resources.h | 147 +++ Development/nmos/control_protocol_ws_api.cpp | 657 +++++++++++- Development/nmos/control_protocol_ws_api.h | 2 + Development/nmos/is12_schemas/is12_schemas.h | 25 + Development/nmos/json_fields.h | 88 ++ Development/nmos/json_schema.cpp | 56 + Development/nmos/json_schema.h | 4 + Development/nmos/model.h | 4 + Development/nmos/node_server.cpp | 12 +- Development/nmos/settings.h | 14 + Development/nmos/slog.h | 1 + Development/nmos/type.h | 7 + Development/third_party/is-12/README.md | 1 + .../v1.0.x/APIs/schemas/base-message.json | 23 + .../v1.0.x/APIs/schemas/command-message.json | 79 ++ .../schemas/command-response-message.json | 69 ++ .../v1.0.x/APIs/schemas/error-message.json | 38 + .../is-12/v1.0.x/APIs/schemas/event-data.json | 11 + .../APIs/schemas/notification-message.json | 72 ++ .../schemas/property-changed-event-data.json | 60 ++ .../APIs/schemas/subscription-message.json | 34 + .../subscription-response-message.json | 34 + 26 files changed, 2495 insertions(+), 6 deletions(-) create mode 100644 Development/nmos/control_protocol_resources.cpp create mode 100644 Development/nmos/control_protocol_resources.h create mode 100644 Development/nmos/is12_schemas/is12_schemas.h create mode 100644 Development/third_party/is-12/README.md create mode 100644 Development/third_party/is-12/v1.0.x/APIs/schemas/base-message.json create mode 100644 Development/third_party/is-12/v1.0.x/APIs/schemas/command-message.json create mode 100644 Development/third_party/is-12/v1.0.x/APIs/schemas/command-response-message.json create mode 100644 Development/third_party/is-12/v1.0.x/APIs/schemas/error-message.json create mode 100644 Development/third_party/is-12/v1.0.x/APIs/schemas/event-data.json create mode 100644 Development/third_party/is-12/v1.0.x/APIs/schemas/notification-message.json create mode 100644 Development/third_party/is-12/v1.0.x/APIs/schemas/property-changed-event-data.json create mode 100644 Development/third_party/is-12/v1.0.x/APIs/schemas/subscription-message.json create mode 100644 Development/third_party/is-12/v1.0.x/APIs/schemas/subscription-response-message.json diff --git a/Development/cmake/NmosCppLibraries.cmake b/Development/cmake/NmosCppLibraries.cmake index 001b7a17d..3265205c5 100644 --- a/Development/cmake/NmosCppLibraries.cmake +++ b/Development/cmake/NmosCppLibraries.cmake @@ -686,6 +686,80 @@ target_include_directories(nmos_is09_schemas PUBLIC list(APPEND NMOS_CPP_TARGETS nmos_is09_schemas) add_library(nmos-cpp::nmos_is09_schemas ALIAS nmos_is09_schemas) +# nmos_is12_schemas library + +set(NMOS_IS12_SCHEMAS_HEADERS + nmos/is12_schemas/is12_schemas.h + ) + +set(NMOS_IS12_V1_0_TAG v1.0.x) + +set(NMOS_IS12_V1_0_SCHEMAS_JSON + third_party/is-12/${NMOS_IS12_V1_0_TAG}/APIs/schemas/base-message.json + third_party/is-12/${NMOS_IS12_V1_0_TAG}/APIs/schemas/command-message.json + third_party/is-12/${NMOS_IS12_V1_0_TAG}/APIs/schemas/command-response-message.json + third_party/is-12/${NMOS_IS12_V1_0_TAG}/APIs/schemas/error-message.json + third_party/is-12/${NMOS_IS12_V1_0_TAG}/APIs/schemas/event-data.json + third_party/is-12/${NMOS_IS12_V1_0_TAG}/APIs/schemas/notification-message.json + third_party/is-12/${NMOS_IS12_V1_0_TAG}/APIs/schemas/property-changed-event-data.json + third_party/is-12/${NMOS_IS12_V1_0_TAG}/APIs/schemas/subscription-message.json + third_party/is-12/${NMOS_IS12_V1_0_TAG}/APIs/schemas/subscription-response-message.json + ) + +set(NMOS_IS12_SCHEMAS_JSON_MATCH "third_party/is-12/([^/]+)/APIs/schemas/([^;]+)\\.json") +set(NMOS_IS12_SCHEMAS_SOURCE_REPLACE "${CMAKE_CURRENT_BINARY_DIR_REPLACE}/nmos/is12_schemas/\\1/\\2.cpp") +string(REGEX REPLACE "${NMOS_IS12_SCHEMAS_JSON_MATCH}(;|$)" "${NMOS_IS12_SCHEMAS_SOURCE_REPLACE}\\3" NMOS_IS12_V1_0_SCHEMAS_SOURCES "${NMOS_IS12_V1_0_SCHEMAS_JSON}") + +foreach(JSON ${NMOS_IS12_V1_0_SCHEMAS_JSON}) + string(REGEX REPLACE "${NMOS_IS12_SCHEMAS_JSON_MATCH}" "${NMOS_IS12_SCHEMAS_SOURCE_REPLACE}" SOURCE "${JSON}") + string(REGEX REPLACE "${NMOS_IS12_SCHEMAS_JSON_MATCH}" "\\1" NS "${JSON}") + string(REGEX REPLACE "${NMOS_IS12_SCHEMAS_JSON_MATCH}" "\\2" VAR "${JSON}") + string(MAKE_C_IDENTIFIER "${NS}" NS) + string(MAKE_C_IDENTIFIER "${VAR}" VAR) + + file(WRITE "${SOURCE}.in" "\ +// Auto-generated from: ${JSON}\n\ +\n\ +namespace nmos\n\ +{\n\ + namespace is12_schemas\n\ + {\n\ + namespace ${NS}\n\ + {\n\ + const char* ${VAR} = R\"-auto-generated-(") + + file(READ "${JSON}" RAW) + file(APPEND "${SOURCE}.in" "${RAW}") + + file(APPEND "${SOURCE}.in" ")-auto-generated-\";\n\ + }\n\ + }\n\ +}\n") + + configure_file("${SOURCE}.in" "${SOURCE}" COPYONLY) +endforeach() + +add_library( + nmos_is12_schemas STATIC + ${NMOS_IS12_SCHEMAS_HEADERS} + ${NMOS_IS12_V1_0_SCHEMAS_SOURCES} + ) + +source_group("nmos\\is12_schemas\\Header Files" FILES ${NMOS_IS12_SCHEMAS_HEADERS}) +source_group("nmos\\is12_schemas\\${NMOS_IS12_V1_0_TAG}\\Source Files" FILES ${NMOS_IS12_V1_0_SCHEMAS_SOURCES}) + +target_link_libraries( + nmos_is12_schemas PRIVATE + nmos-cpp::compile-settings + ) +target_include_directories(nmos_is12_schemas PUBLIC + $ + $ + ) + +list(APPEND NMOS_CPP_TARGETS nmos_is12_schemas) +add_library(nmos-cpp::nmos_is12_schemas ALIAS nmos_is12_schemas) + # nmos-cpp library set(NMOS_CPP_BST_SOURCES @@ -757,6 +831,7 @@ set(NMOS_CPP_NMOS_SOURCES nmos/connection_api.cpp nmos/connection_events_activation.cpp nmos/connection_resources.cpp + nmos/control_protocol_resources.cpp nmos/control_protocol_ws_api.cpp nmos/did_sdid.cpp nmos/events_api.cpp @@ -830,6 +905,7 @@ set(NMOS_CPP_NMOS_HEADERS nmos/connection_api.h nmos/connection_events_activation.h nmos/connection_resources.h + nmos/control_protocol_resources.h nmos/control_protocol_ws_api.h nmos/device_type.h nmos/did_sdid.h @@ -988,6 +1064,7 @@ target_link_libraries( nmos-cpp::nmos_is05_schemas nmos-cpp::nmos_is08_schemas nmos-cpp::nmos_is09_schemas + nmos-cpp::nmos_is12_schemas nmos-cpp::mdns nmos-cpp::slog nmos-cpp::OpenSSL diff --git a/Development/nmos-cpp-node/config.json b/Development/nmos-cpp-node/config.json index 087db3683..bd42405ac 100644 --- a/Development/nmos-cpp-node/config.json +++ b/Development/nmos-cpp-node/config.json @@ -283,5 +283,19 @@ // ocsp_request_max [registry, node]: timeout for interactions with the OCSP server //"ocsp_request_max": 30, + // manufacturer_name [node]: the manufacturer name of the NcDeviceManager used for NMOS Control Protocol + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager + //"manufacturer_name": "", + + // product_name/product_key/product_revision_level [node]: the product description of the NcDeviceManager used for NMOS Control Protocol + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncproduct + //"product_name": "", + //"product_key": "", + //"product_revision_level": "", + + // serial_number [node]: the serial number of the NcDeviceManager used for NMOS Control Protocol + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager + //"serial_number": "", + "don't worry": "about trailing commas" } diff --git a/Development/nmos-cpp-node/node_implementation.cpp b/Development/nmos-cpp-node/node_implementation.cpp index dc3ee9d26..e72dcc24b 100644 --- a/Development/nmos-cpp-node/node_implementation.cpp +++ b/Development/nmos-cpp-node/node_implementation.cpp @@ -21,6 +21,7 @@ #include "nmos/colorspace.h" #include "nmos/connection_resources.h" #include "nmos/connection_events_activation.h" +#include "nmos/control_protocol_resources.h" #include "nmos/events_resources.h" #include "nmos/format.h" #include "nmos/group_hint.h" @@ -894,6 +895,17 @@ void node_implementation_init(nmos::node_model& model, slog::base_gate& gate) auto channelmapping_output = nmos::make_channelmapping_output(id, name, description, source_id, channel_labels, routable_inputs); if (!insert_resource_after(delay_millis, model.channelmapping_resources, std::move(channelmapping_output), gate)) throw node_implementation_init_exception(); } + + // example root block + auto root_block = nmos::make_root_block(); + // example device manager + auto device_manager = nmos::make_device_manager(2, root_block, model.settings); + if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(device_manager), gate)) throw node_implementation_init_exception(); + // example class manager + auto class_manager = nmos::make_class_manager(3, root_block); + if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(class_manager), gate)) throw node_implementation_init_exception(); + // insert root block to model + if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(root_block), gate)) throw node_implementation_init_exception(); } void node_implementation_run(nmos::node_model& model, slog::base_gate& gate) diff --git a/Development/nmos/control_protocol_resources.cpp b/Development/nmos/control_protocol_resources.cpp new file mode 100644 index 000000000..1fa4316b8 --- /dev/null +++ b/Development/nmos/control_protocol_resources.cpp @@ -0,0 +1,960 @@ +#include "nmos/control_protocol_resources.h" + +#include "nmos/resource.h" +#include "nmos/is12_versions.h" + +namespace nmos +{ + namespace details + { + web::json::value make_control_protocol_result(const nc_method_result& method_result) + { + using web::json::value_of; + + return value_of({ + { nmos::fields::nc::status, method_result.status } + }); + } + + web::json::value make_control_protocol_error_result(const nc_method_result& method_result, const utility::string_t& error_message) + { + auto result = make_control_protocol_result(method_result); + if (!error_message.empty()) { result[nmos::fields::nc::error_message] = web::json::value::string(error_message); } + return result; + } + + web::json::value make_control_protocol_result(const nc_method_result& method_result, const web::json::value& value) + { + auto result = make_control_protocol_result(method_result); + result[nmos::fields::nc::value] = value; + return result; + } + + web::json::value make_control_protocol_error_response(int32_t handle, const nc_method_result& method_result, const utility::string_t& error_message) + { + using web::json::value_of; + + return value_of({ + { nmos::fields::nc::handle, handle }, + { nmos::fields::nc::result, make_control_protocol_error_result(method_result, error_message) } + }, true); + } + + web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result) + { + using web::json::value_of; + + return value_of({ + { nmos::fields::nc::handle, handle }, + { nmos::fields::nc::result, make_control_protocol_result(method_result) } + }, true); + } + + web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result, const web::json::value& value) + { + using web::json::value_of; + + return value_of({ + { nmos::fields::nc::handle, handle }, + { nmos::fields::nc::result, make_control_protocol_result(method_result, value) } + }, true); + } + + // message response + // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#command-message-type + web::json::value make_control_protocol_message_response(nc_message_type::type type, const web::json::value& responses) + { + using web::json::value_of; + + return value_of({ + { nmos::fields::nc::message_type, type }, + { nmos::fields::nc::responses, responses } + }, true); + }; + + // error message + // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#error-messages + web::json::value make_control_protocol_error_message(const nc_method_result& method_result, const utility::string_t& error_message) + { + using web::json::value_of; + + return value_of({ + { nmos::fields::nc::message_type, nc_message_type::error }, + { nmos::fields::nc::status, method_result.status}, + { nmos::fields::nc::error_message, error_message } + }, true); + }; + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassid + web::json::value make_nc_class_id(const nc_class_id& class_id) + { + using web::json::value; + + auto nc_class_id = value::array(); + for (const auto class_id_item : class_id) { web::json::push_back(nc_class_id, class_id_item); } + return nc_class_id; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncelementid + web::json::value make_nc_element_id(uint16_t level, uint16_t index) + { + using web::json::value_of; + + return value_of({ + { nmos::fields::nc::level, level }, + { nmos::fields::nc::index, index } + }); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#nceventid + web::json::value make_nc_event_id(uint16_t level, uint16_t index) + { + return make_nc_element_id(level, index); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmethodid + web::json::value make_nc_method_id(uint16_t level, uint16_t index) + { + return make_nc_element_id(level, index); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncpropertyid + web::json::value make_nc_property_id(uint16_t level, uint16_t index) + { + return make_nc_element_id(level, index); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanufacturer + web::json::value make_nc_manufacturer(const utility::string_t& name, const web::json::value& organization_id = web::json::value::null(), const web::json::value& website = web::json::value::null()) + { + using web::json::value_of; + + return value_of({ + { nmos::fields::nc::name, name }, + { nmos::fields::nc::organization_id, organization_id }, + { nmos::fields::nc::website, website } + }, true); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncproduct + // brand_name can be null + // uuid can be null + // description can be null + web::json::value make_nc_product(const utility::string_t& name, const utility::string_t& key, const utility::string_t& revision_level, + const web::json::value& brand_name = web::json::value::null(), const web::json::value& uuid = web::json::value::null(), const web::json::value& description = web::json::value::null()) + { + using web::json::value_of; + + return value_of({ + { nmos::fields::nc::name, name }, + { nmos::fields::nc::key, key }, + { nmos::fields::nc::revision_level, revision_level }, + { nmos::fields::nc::brand_name, brand_name }, + { nmos::fields::nc::uuid, uuid }, + { nmos::fields::nc::description, description } + }, true); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdeviceoperationalstate + // device_specific_details can be null + web::json::value make_nc_device_operational_state(nc_device_generic_state::state generic_state, const web::json::value& device_specific_details) + { + using web::json::value_of; + + return value_of({ + { nmos::fields::nc::generic_state, generic_state }, + { nmos::fields::nc::device_specific_details, device_specific_details } + }, true); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdescriptor + // description can be null + web::json::value make_nc_descriptor(const web::json::value& description) + { + using web::json::value_of; + + return value_of({ { nmos::fields::nc::description, description } }); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblockmemberdescriptor + // description can be null + // user_label can be null + web::json::value make_nc_block_member_descriptor(const web::json::value& description, const utility::string_t& role, nc_oid oid, bool constant_oid, const web::json::value& class_id, const web::json::value& user_label, nc_oid owner) + { + using web::json::value; + + auto data = make_nc_descriptor(description); + data[nmos::fields::nc::role] = value::string(role); + data[nmos::fields::nc::oid] = oid; + data[nmos::fields::nc::constant_oid] = value::boolean(constant_oid); + data[nmos::fields::nc::class_id] = class_id; + data[nmos::fields::nc::user_label] = user_label; + data[nmos::fields::nc::owner] = owner; + + return data; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassdescriptor + // description can be null + // fixedRole can be null + web::json::value make_nc_class_descriptor(const web::json::value& description, const web::json::value& class_id, const utility::string_t& name, const web::json::value& fixed_role, const web::json::value& properties, const web::json::value& methods, const web::json::value& events) + { + using web::json::value; + + auto data = make_nc_descriptor(description); + data[nmos::fields::nc::class_id] = class_id; + data[nmos::fields::nc::name] = value::string(name); + data[nmos::fields::nc::fixed_role] = fixed_role; + data[nmos::fields::nc::properties] = properties; + data[nmos::fields::nc::methods] = methods; + data[nmos::fields::nc::events] = events; + + return data; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncenumitemdescriptor + // description can be null + web::json::value make_nc_enum_item_descriptor(const web::json::value& description, const utility::string_t& name, uint16_t val) + { + using web::json::value; + + auto data = make_nc_descriptor(description); + data[nmos::fields::nc::name] = value::string(name); + data[nmos::fields::nc::value] = val; + + return data; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#nceventdescriptor + // description can be null + // id = make_nc_event_id(level, index) + web::json::value make_nc_event_descriptor(const web::json::value& description, const web::json::value& id, const utility::string_t& name, const utility::string_t& event_datatype, bool is_deprecated) + { + using web::json::value; + + auto data = make_nc_descriptor(description); + data[nmos::fields::nc::id] = id; + data[nmos::fields::nc::name] = value::string(name); + data[nmos::fields::nc::event_datatype] = value::string(event_datatype); + data[nmos::fields::nc::is_deprecated] = value::boolean(is_deprecated); + + return data; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncfielddescriptor + // description can be null + // type_name can be null + // constraints can be null + web::json::value make_nc_field_descriptor(const web::json::value& description, const utility::string_t& name, const web::json::value& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints) + { + using web::json::value; + + auto data = make_nc_descriptor(description); + data[nmos::fields::nc::name] = value::string(name); + data[nmos::fields::nc::type_name] = type_name; + data[nmos::fields::nc::is_nullable] = value::boolean(is_nullable); + data[nmos::fields::nc::is_sequence] = value::boolean(is_sequence); + data[nmos::fields::nc::constraints] = constraints; + + return data; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmethoddescriptor + // description can be null + // id = make_nc_method_id(level, index) + // sequence parameters + web::json::value make_nc_method_descriptor(const web::json::value& description, const web::json::value& id, const utility::string_t& name, const utility::string_t& result_datatype, const web::json::value& parameters, bool is_deprecated) + { + using web::json::value; + + auto data = make_nc_descriptor(description); + data[nmos::fields::nc::id] = id; + data[nmos::fields::nc::name] = value::string(name); + data[nmos::fields::nc::result_datatype] = value::string(result_datatype); + data[nmos::fields::nc::parameters] = parameters; + data[nmos::fields::nc::is_deprecated] = value::boolean(is_deprecated); + + return data; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncparameterdescriptor + // description can be null + // type_name can be null + web::json::value make_nc_parameter_descriptor(const web::json::value& description, const utility::string_t& name, const web::json::value& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints) + { + using web::json::value; + + auto data = make_nc_descriptor(description); + data[nmos::fields::nc::name] = value::string(name); + data[nmos::fields::nc::type_name] = type_name; + data[nmos::fields::nc::is_nullable] = value::boolean(is_nullable); + data[nmos::fields::nc::is_sequence] = value::boolean(is_sequence); + data[nmos::fields::nc::constraints] = constraints; + + return data; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncpropertydescriptor + // description can be null + // id = make_nc_property_id(level, index); + // type_name can be null + // constraints can be null + web::json::value make_nc_property_descriptor(const web::json::value& description, const web::json::value& id, const utility::string_t& name, const web::json::value& type_name, + bool is_read_only, bool is_nullable, bool is_sequence, bool is_deprecated, const web::json::value& constraints) + { + using web::json::value; + + auto data = make_nc_descriptor(description); + data[nmos::fields::nc::id] = id; + data[nmos::fields::nc::name] = value::string(name); + data[nmos::fields::nc::type_name] = type_name; + data[nmos::fields::nc::is_read_only] = value::boolean(is_read_only); + data[nmos::fields::nc::is_nullable] = value::boolean(is_nullable); + data[nmos::fields::nc::is_sequence] = value::boolean(is_sequence); + data[nmos::fields::nc::is_deprecated] = value::boolean(is_deprecated); + data[nmos::fields::nc::constraints] = constraints; + + return data; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptor + // description can be null + // constraints can be null + web::json::value make_nc_datatype_descriptor(const web::json::value& description, const utility::string_t& name, nc_datatype_type::type type, const web::json::value& constraints) + { + using web::json::value; + + auto data = make_nc_descriptor(description); + data[nmos::fields::nc::name] = value::string(name); + data[nmos::fields::nc::type] = type; + data[nmos::fields::nc::constraints] = constraints; + + return data; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptorenum + // description can be null + // constraints can be null + // items: sequence + web::json::value make_nc_datatype_descriptor_enum(const web::json::value& description, const utility::string_t& name, const web::json::value& constraints, const web::json::value& items) + { + auto data = make_nc_datatype_descriptor(description, name, nc_datatype_type::Enum, constraints); + data[nmos::fields::nc::items] = items; + + return data; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptorprimitive + // description can be null + // constraints can be null + web::json::value make_nc_datatype_descriptor_primitive(const web::json::value& description, const utility::string_t& name, const web::json::value& constraints) + { + return make_nc_datatype_descriptor(description, name, nc_datatype_type::Primitive, constraints); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptorstruct + // description can be null + // constraints can be null + // fields: sequence + // parent_type can be null + web::json::value make_nc_datatype_descriptor_struct(const web::json::value& description, const utility::string_t& name, const web::json::value& constraints, const web::json::value& fields, const web::json::value& parent_type) + { + auto data = make_nc_datatype_descriptor(description, name, nc_datatype_type::Struct, constraints); + data[nmos::fields::nc::fields] = fields; + data[nmos::fields::nc::parent_type] = parent_type; + + return data; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptortypedef + // description can be null + // constraints can be null + web::json::value make_nc_datatype_typedef(const web::json::value& description, const utility::string_t& name, const web::json::value& constraints, const utility::string_t& parent_type, bool is_sequence) + { + using web::json::value; + + auto data = make_nc_datatype_descriptor(description, name, nc_datatype_type::Typedef, constraints); + data[nmos::fields::nc::parent_type] = value::string(parent_type); + data[nmos::fields::nc::is_sequence] = value::boolean(is_sequence); + + return data; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject + web::json::value make_nc_object(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints) + { + using web::json::value; + + const auto id = utility::conversions::details::to_string_t(oid); + auto data = make_resource_core(id, user_label.is_null() ? U("") : user_label.as_string(), {}); + data[nmos::fields::nc::class_id] = make_nc_class_id(class_id); + data[nmos::fields::nc::oid] = oid; + data[nmos::fields::nc::constant_oid] = value::boolean(constant_oid); + data[nmos::fields::nc::owner] = owner; + data[nmos::fields::nc::role] = value::string(role); + data[nmos::fields::nc::user_label] = user_label; + data[nmos::fields::nc::touchpoints] = touchpoints; + data[nmos::fields::nc::runtime_property_constraints] = runtime_property_constraints; + + return data; + }; + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock + web::json::value make_nc_block(nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled, const web::json::value& members) + { + using web::json::value; + + auto data = details::make_nc_object({ 1, 1 }, oid, constant_oid, owner, role, user_label, touchpoints, runtime_property_constraints); + data[nmos::fields::nc::enabled] = value::boolean(enabled); + data[nmos::fields::nc::members] = members; + + return data; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanager + web::json::value make_nc_manager(nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null()) + { + return make_nc_object({ 1, 3 }, oid, constant_oid, owner, role, user_label, touchpoints, runtime_property_constraints); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager + web::json::value make_nc_device_manager(nc_oid oid, nc_oid owner, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, + const web::json::value& manufacturer, const web::json::value& product, const utility::string_t& serial_number, + const web::json::value& user_inventory_code, const web::json::value& device_name, const web::json::value& device_role, const web::json::value& operational_state, nc_reset_cause::cause reset_cause) + { + using web::json::value; + + auto data = details::make_nc_manager(oid, true, owner, U("DeviceManager"), user_label, touchpoints, runtime_property_constraints); + data[nmos::fields::nc::class_id] = details::make_nc_class_id({ 1, 3, 1 }); + data[nmos::fields::nc::nc_version] = value::string(U("v1.0")); + data[nmos::fields::nc::manufacturer] = manufacturer; + data[nmos::fields::nc::product] = product; + data[nmos::fields::nc::serial_number] = value::string(serial_number); + data[nmos::fields::nc::user_inventory_code] = user_inventory_code; + data[nmos::fields::nc::device_name] = device_name; + data[nmos::fields::nc::device_role] = device_role; + data[nmos::fields::nc::operational_state] = operational_state; + data[nmos::fields::nc::reset_cause] = reset_cause; + data[nmos::fields::nc::message] = value::null(); + + return data; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager + web::json::value make_nc_class_manager(details::nc_oid oid, nc_oid owner, const web::json::value& user_label) + { + using web::json::value; + + auto data = details::make_nc_manager(oid, true, owner, U("ClassManager"), user_label); + data[nmos::fields::nc::class_id] = details::make_nc_class_id({ 1, 3, 2 }); + + // load the minimal control classes + data[nmos::fields::nc::control_classes] = value::array(); + auto& control_classes = data[nmos::fields::nc::control_classes]; + + // NcObject control class + { + auto properties = value::array(); + web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Static value. All instances of the same class will have the same identity value")), details::make_nc_property_id(1, 1), nmos::fields::nc::class_id, value::string(U("NcClassId")), true, false, false, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Object identifier")), details::make_nc_property_id(1, 2), nmos::fields::nc::oid, value::string(U("NcOid")), true, false, false, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("TRUE iff OID is hardwired into device")), details::make_nc_property_id(1, 3), nmos::fields::nc::constant_oid, value::string(U("NcBoolean")), true, false, false, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("OID of containing block. Can only ever be null for the root block")), details::make_nc_property_id(1, 4), nmos::fields::nc::owner, value::string(U("NcOid")), true, true, false, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Role of object in the containing block")), details::make_nc_property_id(1, 5), nmos::fields::nc::role, value::string(U("NcString")), true, false, false, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Scribble strip")), details::make_nc_property_id(1, 6), nmos::fields::nc::user_label, value::string(U("NcString")), false, true, false, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Touchpoints to other contexts")), details::make_nc_property_id(1, 7), nmos::fields::nc::touchpoints, value::string(U("NcTouchpoint")), true, true, true, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Runtime property constraints")), details::make_nc_property_id(1, 8), nmos::fields::nc::runtime_property_constraints, value::string(U("NcPropertyConstraints")), true, true, true, false, value::null())); + auto methods = value::array(); + { + auto parameters = value::array(); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); + web::json::push_back(methods, details::make_nc_method_descriptor(value::string(U("Get property value")), details::make_nc_method_id(1, 1), U("Get"), U("NcMethodResultPropertyValue"), parameters, false)); + } + { + auto parameters = value::array(); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Property value")), nmos::fields::nc::value, value::null(), true, false, value::null())); + web::json::push_back(methods, details::make_nc_method_descriptor(value::string(U("Set property value")), details::make_nc_method_id(1, 2), U("Set"), U("NcMethodResult"), parameters, false)); + } + { + auto parameters = value::array(); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Index of item in the sequence")), nmos::fields::nc::index, value::string(U("NcId")), false, false, value::null())); + web::json::push_back(methods, details::make_nc_method_descriptor(value::string(U("Get sequence item")), details::make_nc_method_id(1, 3), U("GetSequenceItem"), U("NcMethodResultPropertyValue"), parameters, false)); + } + { + auto parameters = value::array(); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Index of item in the sequence")), nmos::fields::nc::index, value::string(U("NcId")), false, false, value::null())); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Value")), nmos::fields::nc::value, value::null(), true, false, value::null())); + web::json::push_back(methods, details::make_nc_method_descriptor(value::string(U("Set sequence item value")), details::make_nc_method_id(1, 4), U("SetSequenceItem"), U("NcMethodResult"), parameters, false)); + } + { + auto parameters = value::array(); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Value")), nmos::fields::nc::value, value::null(), true, false, value::null())); + web::json::push_back(methods, details::make_nc_method_descriptor(value::string(U("Add item to sequence")), details::make_nc_method_id(1, 5), U("AddSequenceItem"), U("NcMethodResultId"), parameters, false)); + } + { + auto parameters = value::array(); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Index of item in the sequence")), nmos::fields::nc::index, value::string(U("NcId")), false, false, value::null())); + web::json::push_back(methods, details::make_nc_method_descriptor(value::string(U("Delete sequence item")), details::make_nc_method_id(1, 6), U("RemoveSequenceItem"), U("NcMethodResult"), parameters, false)); + } + { + auto parameters = value::array(); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); + web::json::push_back(methods, details::make_nc_method_descriptor(value::string(U("Get sequence length")), details::make_nc_method_id(1, 7), U("GetSequenceLength"), U("NcMethodResultLength"), parameters, false)); + } + auto events = value::array(); + web::json::push_back(events, details::make_nc_event_descriptor(value::string(U("Property changed event")), details::make_nc_event_id(1, 1), U("PropertyChanged"), U("NcPropertyChangedEventData"), false)); + + web::json::push_back(control_classes, details::make_nc_class_descriptor(value::string(U("NcObject class descriptor")), details::make_nc_class_id({ 1 }), U("NcObject"), value::null(), properties, methods, events)); + } + + // NcBlock control class + { + auto properties = value::array(); + web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("TRUE if block is functional")), details::make_nc_property_id(2, 1), nmos::fields::nc::enabled, value::string(U("NcBoolean")), true, false, false, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Descriptors of this block's members")), details::make_nc_property_id(2, 2), nmos::fields::nc::members, value::string(U("NcBlockMemberDescriptor")), true, false, true, false, value::null())); + auto methods = value::array(); + { + auto parameters = value::array(); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("If recurse is set to true, nested members can be retrieved")), nmos::fields::nc::recurse, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(methods, details::make_nc_method_descriptor(value::string(U("Gets descriptors of members of the block")), details::make_nc_method_id(2, 1), U("GetMemberDescriptors"), U("NcMethodResultBlockMemberDescriptors"), parameters, false)); + } + { + auto parameters = value::array(); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Relative path to search for (MUST not include the role of the block targeted by oid)")), nmos::fields::nc::path, value::string(U("NcRolePath")), false, false, value::null())); + web::json::push_back(methods, details::make_nc_method_descriptor(value::string(U("Finds member(s) by path")), details::make_nc_method_id(2, 2), U("FindMembersByPath"), U("NcMethodResultBlockMemberDescriptors"), parameters, false)); + } + { + auto parameters = value::array(); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Role text to search for")), nmos::fields::nc::role, value::string(U("NcString")), false, false, value::null())); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Signals if the comparison should be case sensitive")), nmos::fields::nc::case_sensitive, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("TRUE to only return exact matches")), nmos::fields::nc::match_whole_string, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("TRUE to search nested blocks")), nmos::fields::nc::recurse, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(methods, details::make_nc_method_descriptor(value::string(U("Finds members with given role name or fragment")), details::make_nc_method_id(2, 3), U("FindMembersByRole"), U("NcMethodResultBlockMemberDescriptors"), parameters, false)); + } + { + auto parameters = value::array(); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Class id to search for")), nmos::fields::nc::class_id, value::string(U("NcClassId")), false, false, value::null())); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("If TRUE it will also include derived class descriptors")), nmos::fields::nc::include_derived, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("TRUE to search nested blocks")), nmos::fields::nc::recurse, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(methods, details::make_nc_method_descriptor(value::string(U("Finds members with given class id")), details::make_nc_method_id(2, 4), U("FindMembersByClassId"), U("NcMethodResultBlockMemberDescriptors"), parameters, false)); + } + auto events = value::array(); + + web::json::push_back(control_classes, details::make_nc_class_descriptor(value::string(U("NcBlock class descriptor")), details::make_nc_class_id({ 1, 1 }), U("NcBlock"), value::null(), properties, methods, events)); + } + + // NcWorker control class + { + auto properties = value::array(); + web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("TRUE iff worker is enabled")), details::make_nc_property_id(2, 1), nmos::fields::nc::enabled, value::string(U("NcBoolean")), false, false, false, false, value::null())); + auto methods = value::array(); + auto events = value::array(); + + web::json::push_back(control_classes, details::make_nc_class_descriptor(value::string(U("NcWorker class descriptor")), details::make_nc_class_id({ 1, 2 }), U("NcWorker"), value::null(), properties, methods, events)); + } + + // NcManager control class + { + auto properties = value::array(); + auto methods = value::array(); + auto events = value::array(); + + web::json::push_back(control_classes, details::make_nc_class_descriptor(value::string(U("NcManager class descriptor")), details::make_nc_class_id({ 1, 3 }), U("NcManager"), value::null(), properties, methods, events)); + } + + // NcDeviceManager control class + { + auto properties = value::array(); + web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Version of MS-05-02 that this device uses")), details::make_nc_property_id(3, 1), nmos::fields::nc::nc_version, value::string(U("NcVersionCode")), true, false, false, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Manufacturer descriptor")), details::make_nc_property_id(3, 2), nmos::fields::nc::manufacturer, value::string(U("NcManufacturer")), true, false, false, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Product descriptor")), details::make_nc_property_id(3, 3), nmos::fields::nc::product, value::string(U("NcProduct")), true, false, false, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Serial number")), details::make_nc_property_id(3, 4), nmos::fields::nc::serial_number, value::string(U("NcString")), true, false, false, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Asset tracking identifier (user specified)")), details::make_nc_property_id(3, 5), nmos::fields::nc::user_inventory_code, value::string(U("NcString")), false, true, false, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Name of this device in the application. Instance name, not product name")), details::make_nc_property_id(3, 6), nmos::fields::nc::device_name, value::string(U("NcString")), false, true, false, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Role of this device in the application")), details::make_nc_property_id(3, 7), nmos::fields::nc::device_role, value::string(U("NcString")), false, true, false, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Device operational state")), details::make_nc_property_id(3, 8), nmos::fields::nc::operational_state, value::string(U("NcDeviceOperationalState")), true, false, false, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Reason for most recent reset")), details::make_nc_property_id(3, 9), nmos::fields::nc::reset_cause, value::string(U("NcResetCause")), true, false, false, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Arbitrary message from dev to controller")), details::make_nc_property_id(3, 10), nmos::fields::nc::message, value::string(U("NcString")), true, true, false, false, value::null())); + auto methods = value::array(); + auto events = value::array(); + + web::json::push_back(control_classes, details::make_nc_class_descriptor(value::string(U("NcDeviceManager class descriptor")), details::make_nc_class_id({ 1, 3, 1 }), U("NcDeviceManager"), value::string(U("DeviceManager")), properties, methods, events)); + } + + // NcClassManager control class + { + auto properties = value::array(); + web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Descriptions of all control classes in the device (descriptors do not contain inherited elements)")), details::make_nc_property_id(3, 1), nmos::fields::nc::control_classes, value::string(U("NcClassDescriptor")), true, false, true, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Descriptions of all data types in the device (descriptors do not contain inherited elements)")), details::make_nc_property_id(3, 2), nmos::fields::nc::datatypes, value::string(U("NcDatatypeDescriptor")), true, false, true, false, value::null())); + auto methods = value::array(); + { + auto parameters = value::array(); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("class ID")), nmos::fields::nc::class_id, value::string(U("NcClassId")), false, false, value::null())); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("If set the descriptor would contain all inherited elements")), nmos::fields::nc::include_inherited, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(methods, details::make_nc_method_descriptor(value::string(U("Get a single class descriptor")), details::make_nc_method_id(3, 1), U("GetControlClass"), U("NcMethodResultClassDescriptor"), parameters, false)); + } + { + auto parameters = value::array(); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("name of datatype")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("If set the descriptor would contain all inherited elements")), nmos::fields::nc::include_inherited, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(methods, details::make_nc_method_descriptor(value::string(U("Get a single datatype descriptor")), details::make_nc_method_id(3, 2), U("GetDatatype"), U("NcMethodResultDatatypeDescriptor"), parameters, false)); + } + auto events = value::array(); + + web::json::push_back(control_classes, details::make_nc_class_descriptor(value::string(U("NcClassManager class descriptor")), details::make_nc_class_id({ 1, 3, 2 }), U("NcClassManager"), value::string(U("ClassManager")), properties, methods, events)); + } + + // load the minimal datatypes + data[nmos::fields::nc::datatypes] = value::array(); + auto& datatypes = data[nmos::fields::nc::datatypes]; + + // NcObject datatypes + // NcClassId + web::json::push_back(datatypes, details::make_nc_datatype_typedef(value::string(U("Sequence of class ID fields")), U("NcClassId"), value::null(), U("NcInt32"), true)); + // NcOid + web::json::push_back(datatypes, details::make_nc_datatype_typedef(value::string(U("Object id")), U("NcOid"), value::null(), U("NcUint32"), false)); + // NcTouchpoint + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Context namespace")), nmos::fields::nc::context_namespace, value::string(U("NcString")), false, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Base touchpoint class")), U("NcTouchpoint"), value::null(), fields, value::null())); + } + // NcElementId + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Level of the element")), nmos::fields::nc::level, value::string(U("NcUint16")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Index of the element")), nmos::fields::nc::index, value::string(U("NcUint16")), false, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Class element id which contains the level and index")), U("NcElementId"), value::null(), fields, value::null())); + } + // NcPropertyId + { + auto fields = value::array(); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Property id which contains the level and index")), U("NcPropertyId"), value::null(), fields, value::string(U("NcElementId")))); + } + // NcPropertyConstraints + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("The id of the property being constrained")), nmos::fields::nc::property_id, value::string(U("NcPropertyId")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional default value")), nmos::fields::nc::default_value, value::null(), true, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Property constraints class")), U("NcPropertyConstraints"), value::null(), fields, value::null())); + } + // NcMethodResultPropertyValue + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Getter method value for the associated property")), nmos::fields::nc::value, value::null(), true, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Result when invoking the getter method associated with a property")), U("NcMethodResultPropertyValue"), value::null(), fields, value::string(U("NcMethodResult")))); + } + // NcMethodStatus + { + auto items = value::array(); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method call was successful")), U("Ok"), 200)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method call was successful but targeted property is deprecated")), U("PropertyDeprecated"), 298)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method call was successful but method is deprecated")), U("MethodDeprecated"), 299)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Badly-formed command (e.g. the incoming command has invalid message encoding and cannot be parsed by the underlying protocol)")), U("BadCommandFormat"), 400)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Client is not authorized")), U("Unauthorized"), 401)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Command addresses a nonexistent object")), U("BadOid"), 404)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Attempt to change read-only state")), U("Readonly"), 405)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method call is invalid in current operating context (e.g. attempting to invoke a method when the object is disabled)")), U("InvalidRequest"), 406)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("There is a conflict with the current state of the device")), U("Conflict"), 409)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Something was too big")), U("BufferOverflow"), 413)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Index is outside the available range")), U("IndexOutOfBounds"), 414)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method parameter does not meet expectations (e.g. attempting to invoke a method with an invalid type for one of its parameters)")), U("ParameterError"), 417)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Addressed object is locked")), U("Locked"), 423)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Internal device error")), U("DeviceError"), 500)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Addressed method is not implemented by the addressed object")), U("MethodNotImplemented"), 501)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Addressed property is not implemented by the addressed object")), U("PropertyNotImplemented"), 502)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("The device is not ready to handle any commands")), U("NotReady"), 503)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method call did not finish within the allotted time")), U("Timeout"), 504)); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_enum(value::string(U("Method invokation status")), U("NcMethodStatus"), value::null(), items)); + } + // NcMethodResult + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Status for the invoked method")), nmos::fields::nc::status, value::string(U("NcMethodStatus")), false, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Base result of the invoked method")), U("NcMethodResult"), value::null(), fields, value::null())); + } + // NcId + web::json::push_back(datatypes, details::make_nc_datatype_typedef(value::string(U("Identity handler")), U("NcId"), value::null(), U("NcUint32"), false)); + // NcMethodResultId + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Id result value")), nmos::fields::nc::value, value::string(U("NcId")), false, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Id method result")), U("NcMethodResultId"), value::null(), fields, value::string(U("NcMethodResult")))); + } + // NcMethodResultLength + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Length result value")), nmos::fields::nc::value, value::string(U("NcUint32")), false, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Length method result")), U("NcMethodResultLength"), value::null(), fields, value::string(U("NcMethodResult")))); + } + // NcPropertyChangeType + { + auto items = value::array(); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Current value changed")), U("ValueChanged"), 0)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Sequence item added")), U("SequenceItemAdded"), 1)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Sequence item changed")), U("SequenceItemChanged"), 2)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Sequence item removed")), U("SequenceItemRemoved"), 3)); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_enum(value::string(U("Type of property change")), U("NcPropertyChangeType"), value::null(), items)); + } + // NcPropertyChangedEventData + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("The id of the property that changed")), nmos::fields::nc::property_id, value::string(U("NcPropertyId")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Information regarding the change type")), nmos::fields::nc::change_type, value::string(U("NcPropertyChangeType")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Property-type specific value")), nmos::fields::nc::value, value::null(), true, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Index of sequence item if the property is a sequence")), nmos::fields::nc::sequence_item_index, value::string(U("NcId")), true, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Payload of property-changed event")), U("NcPropertyChangedEventData"), value::null(), fields, value::null())); + } + + // NcBlock datatypes + // NcDescriptor + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional user facing description")), nmos::fields::nc::description, value::string(U("NcString")), true, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Base descriptor")), U("NcDescriptor"), value::null(), fields, value::null())); + } + // NcBlockMemberDescriptor + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Role of member in its containing block")), nmos::fields::nc::role, value::string(U("NcString")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("OID of member")), nmos::fields::nc::oid, value::string(U("NcOid")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff member's OID is hardwired into device")), nmos::fields::nc::constant_oid, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Class ID")), nmos::fields::nc::class_id, value::string(U("NcClassId")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("User label")), nmos::fields::nc::user_label, value::string(U("NcString")), true, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Containing block's OID")), nmos::fields::nc::owner, value::string(U("NcOid")), false, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor which is specific to a block member")), U("NcBlockMemberDescriptor"), value::null(), fields, value::string(U("NcDescriptor")))); + } + // NcMethodResultBlockMemberDescriptors + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Block member descriptors method result value")), nmos::fields::nc::value, value::string(U("NcBlockMemberDescriptor")), false, true, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Method result containing block member descriptors as the value")), U("NcMethodResultBlockMemberDescriptors"), value::null(), fields, value::string(U("NcMethodResult")))); + } + + // NcWorker has no datatypes + + // NcManager has no datatypes + + // NcDeviceManager datatypes + // NcVersionCode + web::json::push_back(datatypes, details::make_nc_datatype_typedef(value::string(U("Version code in semantic versioning format")), U("NcVersionCode"), value::null(), U("NcString"), false)); + // NcOrganizationId + web::json::push_back(datatypes, details::make_nc_datatype_typedef(value::string(U("Unique 24-bit organization id")), U("NcOrganizationId"), value::null(), U("NcInt32"), false)); + // NcUri + web::json::push_back(datatypes, details::make_nc_datatype_typedef(value::string(U("Uniform resource identifier")), U("NcUri"), value::null(), U("NcString"), false)); + // NcManufacturer + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Manufacturer's name")), nmos::fields::nc::name, value::string(U("NcString")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("IEEE OUI or CID of manufacturer")), nmos::fields::nc::organization_id, value::string(U("NcOrganizationId")), true, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("URL of the manufacturer's website")), nmos::fields::nc::website, value::string(U("NcUri")), true, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Manufacturer descriptor")), U("NcManufacturer"), value::null(), fields, value::null())); + } + // NcUuid + web::json::push_back(datatypes, details::make_nc_datatype_typedef(value::string(U("UUID")), U("NcUuid"), value::null(), U("NcString"), false)); + // NcProduct + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Product name")), nmos::fields::nc::name, value::string(U("NcString")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Manufacturer's unique key to product - model number, SKU, etc")), nmos::fields::nc::key, value::string(U("NcString")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Manufacturer's product revision level code")), nmos::fields::nc::revision_level, value::string(U("NcString")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Brand name under which product is sold")), nmos::fields::nc::brand_name, value::string(U("NcString")), true, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Unique UUID of product (not product instance)")), nmos::fields::nc::uuid, value::string(U("NcUuid")), true, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Text description of product")), nmos::fields::nc::description, value::string(U("NcString")), true, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Product descriptor")), U("NcProduct"), value::null(), fields, value::null())); + } + // NcDeviceGenericState + { + auto items = value::array(); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Unknown")), U("Unknown"), 0)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Normal operation")), U("NormalOperation"), 1)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Device is initializing")), U("Initializing"), 2)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Device is performing a software or firmware update")), U("Updating"), 3)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Device is experiencing a licensing error")), U("LicensingError"), 4)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Device is experiencing an internal error")), U("InternalError"), 5)); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_enum(value::string(U("Device generic operational state")), U("NcDeviceGenericState"), value::null(), items)); + } + // NcDeviceOperationalState + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Generic operational state")), nmos::fields::nc::generic_state, value::string(U("NcDeviceGenericState")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Specific device details")), nmos::fields::nc::device_specific_details, value::string(U("NcString")), true, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Device operational state")), U("NcDeviceOperationalState"), value::null(), fields, value::null())); + } + // NcResetCause + { + auto items = value::array(); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Unknown")), U("Unknown"), 0)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Power on")), U("PowerOn"), 1)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Internal error")), U("InternalError"), 2)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Upgrade")), U("Upgrade"), 3)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Controller request")), U("ControllerRequest"), 4)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Manual request from the front panel")), U("ManualReset"), 5)); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_enum(value::string(U("Reset cause enum")), U("NcResetCause"), value::null(), items)); + } + + // NcClassManager datatypes + // NcName + web::json::push_back(datatypes, details::make_nc_datatype_typedef(value::string(U("Programmatically significant name, alphanumerics + underscore, no spaces")), U("NcName"), value::null(), U("NcString"), false)); + // NcPropertyDescriptor + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Property id with level and index")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of property")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of property's datatype. Can only ever be null if the type is any")), nmos::fields::nc::type_name, value::string(U("NcName")), true, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is read-only")), nmos::fields::nc::is_read_only, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is nullable")), nmos::fields::nc::is_nullable, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is a sequence")), nmos::fields::nc::is_sequence, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is marked as deprecated")), nmos::fields::nc::is_deprecated, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional constraints on top of the underlying data type")), nmos::fields::nc::constraints, value::string(U("NcParameterConstraints")), true, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class property")), U("NcPropertyDescriptor"), value::null(), fields, value::string(U("NcDescriptor")))); + } + // NcMethodId + { + auto fields = value::array(); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Method id which contains the level and index")), U("NcMethodId"), value::null(), fields, value::string(U("NcElementId")))); + } + // NcParameterDescriptor + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of parameter")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of parameter's datatype. Can only ever be null if the type is any")), nmos::fields::nc::type_name, value::string(U("NcName")), true, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is nullable")), nmos::fields::nc::is_nullable, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is a sequence")), nmos::fields::nc::is_sequence, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional constraints on top of the underlying data type")), nmos::fields::nc::constraints, value::string(U("NcParameterConstraints")), true, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a method parameter")), U("NcParameterDescriptor"), value::null(), fields, value::string(U("NcDescriptor")))); + } + // NcMethodDescriptor + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Method id with level and index")), nmos::fields::nc::id, value::string(U("NcMethodId")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of method")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of method result's datatype")), nmos::fields::nc::result_datatype, value::string(U("NcName")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Parameter descriptors if any")), nmos::fields::nc::parameters, value::string(U("NcParameterDescriptor")), false, true, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is marked as deprecated")), nmos::fields::nc::is_deprecated, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class method")), U("NcMethodDescriptor"), value::null(), fields, value::string(U("NcDescriptor")))); + } + // NcEventId + { + auto fields = value::array(); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Event id which contains the level and index")), U("NcEventId"), value::null(), fields, value::string(U("NcElementId")))); + } + // NcEventDescriptor + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Event id with level and index")), nmos::fields::nc::id, value::string(U("NcEventId")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of event")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of event data's datatype")), nmos::fields::nc::event_datatype, value::string(U("NcName")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is marked as deprecated")), nmos::fields::nc::is_deprecated, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class event")), U("NcEventDescriptor"), value::null(), fields, value::string(U("NcDescriptor")))); + } + // NcClassDescriptor + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Identity of the class")), nmos::fields::nc::class_id, value::string(U("NcClassId")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of the class")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Role if the class has fixed role (manager classes)")), nmos::fields::nc::fixed_role, value::string(U("NcString")), true, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Property descriptors")), nmos::fields::nc::properties, value::string(U("NcPropertyDescriptor")), false, true, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Method descriptors")), nmos::fields::nc::methods, value::string(U("NcMethodDescriptor")), false, true, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Event descriptors")), nmos::fields::nc::events, value::string(U("NcEventDescriptor")), false, true, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class")), U("NcClassDescriptor"), value::null(), fields, value::string(U("NcDescriptor")))); + } + // NcParameterConstraints + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Default value")), nmos::fields::nc::default_value, value::null(), true, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Abstract parameter constraints class")), U("NcParameterConstraints"), value::null(), fields, value::null())); + } + // NcDatatypeType + { + auto items = value::array(); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Primitive datatype")), U("Primitive"), 0)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Simple alias of another datatype")), U("Typedef"), 1)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Data structure")), U("Struct"), 2)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Enum datatype")), U("Enum"), 3)); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_enum(value::string(U("Datatype type")), U("NcDatatypeType"), value::null(), items)); + } + // NcDatatypeDescriptor + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Datatype name")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Type: Primitive, Typedef, Struct, Enum")), nmos::fields::nc::type, value::string(U("NcDatatypeType")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional constraints on top of the underlying data type")), nmos::fields::nc::constraints, value::string(U("NcParameterConstraints")), true, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Base datatype descriptor")), U("NcDatatypeDescriptor"), value::null(), fields, value::string(U("NcDescriptor")))); + } + // NcMethodResultClassDescriptor + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Class descriptor method result value")), nmos::fields::nc::value, value::string(U("NcClassDescriptor")), false, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Method result containing a class descriptor as the value")), U("NcMethodResultClassDescriptor"), value::null(), fields, value::string(U("NcMethodResult")))); + } + // NcMethodResultDatatypeDescriptor + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Datatype descriptor method result value")), nmos::fields::nc::value, value::string(U("NcDatatypeDescriptor")), false, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Method result containing a datatype descriptor as the value")), U("NcMethodResultDatatypeDescriptor"), value::null(), fields, value::string(U("NcMethodResult")))); + } + + return data; + } + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager + nmos::resource make_device_manager(details::nc_oid oid, nmos::resource& root_block, const nmos::settings& settings) + { + using web::json::value; + + auto& root_block_data = root_block.data; + const auto& owner = nmos::fields::nc::oid(root_block_data); + const auto user_label = value::string(U("Device manager")); + const auto description = value::string(U("The device manager offers information about the product this device is representing")); + const auto& manufacturer = details::make_nc_manufacturer(nmos::experimental::fields::manufacturer_name(settings)); + const auto& product = details::make_nc_product(nmos::experimental::fields::product_name(settings), nmos::experimental::fields::product_key(settings), nmos::experimental::fields::product_key(settings)); + const auto& serial_number = nmos::experimental::fields::serial_number(settings); + const auto device_name = value::null(); + const auto device_role = value::null(); + const auto& operational_state = details::make_nc_device_operational_state(details::nc_device_generic_state::NormalOperation, value::null()); + + auto data = details::make_nc_device_manager(oid, owner, user_label, value::null(), value::null(), + manufacturer, product, serial_number, value::null(), device_name, device_role, operational_state, details::nc_reset_cause::Unknown); + + // add NcDeviceManager block_member_descriptor to root block members + web::json::push_back(root_block_data[nmos::fields::nc::members], details::make_nc_block_member_descriptor( + description, nmos::fields::nc::role(data), oid, nmos::fields::nc::constant_oid(data), data.at(nmos::fields::nc::class_id), user_label, owner)); + + return{ is12_versions::v1_0, types::nc_device_manager, std::move(data), true }; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager + nmos::resource make_class_manager(details::nc_oid oid, nmos::resource& root_block) + { + using web::json::value; + + auto& root_block_data = root_block.data; + const auto& owner = nmos::fields::nc::oid(root_block_data); + const auto user_label = value::string(U("Class manager")); + const auto description = value::string(U("The class manager offers access to control class and data type descriptors")); + + auto data = details::make_nc_class_manager(oid, owner, user_label); + + // add NcClassManager block_member_descriptor to root block members + web::json::push_back(root_block_data[nmos::fields::nc::members], details::make_nc_block_member_descriptor( + description, nmos::fields::nc::role(data), oid, nmos::fields::nc::constant_oid(data), data.at(nmos::fields::nc::class_id), user_label, owner)); + + return{ is12_versions::v1_0, types::nc_class_manager, std::move(data), true }; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock + nmos::resource make_root_block() + { + using web::json::value; + + auto data = details::make_nc_block(1, true, value::null(), U("root"), value::string(U("Root")), value::null(), value::null(), true, value::array()); + + return{ is12_versions::v1_0, types::nc_block, std::move(data), true }; + } +} diff --git a/Development/nmos/control_protocol_resources.h b/Development/nmos/control_protocol_resources.h new file mode 100644 index 000000000..f7683c2ae --- /dev/null +++ b/Development/nmos/control_protocol_resources.h @@ -0,0 +1,147 @@ +#ifndef NMOS_CONTROL_PROTOCOL_RESOURCES_H +#define NMOS_CONTROL_PROTOCOL_RESOURCES_H + +#include +#include "nmos/settings.h" + +namespace web +{ + namespace json + { + class value; + } +} + +namespace nmos +{ + struct resource; + + namespace details + { + namespace nc_message_type + { + enum type + { + command = 0, + command_response = 1, + notification = 2, + subscription = 3, + subscription_response = 4, + error = 5 + }; + } + + // Method invokation status + namespace nc_method_status + { + enum status + { + ok = 200, // Method call was successful + property_deprecated = 298, // Method call was successful but targeted property is deprecated + method_deprecated = 299, // Method call was successful but method is deprecated + bad_command_format = 400, // Badly-formed command + unathorized = 401, // Client is not authorized + bad_oid = 404, // Command addresses a nonexistent object + read_only = 405, // Attempt to change read-only state + invalid_request = 406, // Method call is invalid in current operating context + conflict = 409, // There is a conflict with the current state of the device + buffer_overflow = 413, // Something was too big + parameter_error = 417, // Method parameter does not meet expectations + locked = 423, // Addressed object is locked + device_error = 500, // Internal device error + method_not_implemented = 501, // Addressed method is not implemented by the addressed object + property_not_implemented = 502, // Addressed property is not implemented by the addressed object + not_ready = 503, // The device is not ready to handle any commands + timeout = 504, // Method call did not finish within the allotted time + property_version_error = 505 // Incompatible protocol version + }; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmethodresult + struct nc_method_result + { + nc_method_status::status status; + }; + + // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#command-response-message-type + web::json::value make_control_protocol_error_response(int32_t handle, const nc_method_result& method_result, const utility::string_t& error_message); + web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result); + web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result, const web::json::value& value); + + // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#command-message-type + web::json::value make_control_protocol_message_response(nc_message_type::type type, const web::json::value& responses); + // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#error-messages + web::json::value make_control_protocol_error_message(const nc_method_result& method_result, const utility::string_t& error_message); + + // Datatype type + namespace nc_datatype_type + { + enum type + { + Primitive = 0, + Typedef = 1, + Struct = 2, + Enum = 3 + }; + } + + // Device generic operational state + namespace nc_device_generic_state + { + enum state + { + Unknown = 0, // Unknown + NormalOperation = 1, // Normal operation + Initializing = 2, // Device is initializing + Updating = 3, // Device is performing a software or firmware update + LicensingError = 4, // Device is experiencing a licensing error + InternalError = 5 // Device is experiencing an internal error + }; + } + + // Reset cause enum + namespace nc_reset_cause + { + enum cause + { + Unknown = 0, // 0 Unknown + Power_on = 1, // 1 Power on + InternalError = 2, // 2 Internal error + Upgrade = 3, // 3 Upgrade + Controller_request = 4, // 4 Controller request + ManualReset = 5 // 5 Manual request from the front panel + }; + } + + // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncid + typedef uint32_t nc_id; + + // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncoid + typedef uint32_t nc_oid; + + // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncuri + typedef utility::string_t nc_uri; + + // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncuuid + typedef utility::string_t nc_uuid; + + // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassid + typedef std::vector nc_class_id; + + // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#nctouchpoint + typedef utility::string_t nc_touch_point; + + typedef std::map properties; + + typedef std::function method; + typedef std::map methods; // method_id vs method handler + } + + nmos::resource make_device_manager(details::nc_oid oid, nmos::resource& root_block, const nmos::settings& settings); + + nmos::resource make_class_manager(details::nc_oid oid, nmos::resource& root_block); + + nmos::resource make_root_block(); +} + +#endif diff --git a/Development/nmos/control_protocol_ws_api.cpp b/Development/nmos/control_protocol_ws_api.cpp index 89e11721a..6bb263468 100644 --- a/Development/nmos/control_protocol_ws_api.cpp +++ b/Development/nmos/control_protocol_ws_api.cpp @@ -1,10 +1,52 @@ #include "nmos/control_protocol_ws_api.h" +#include +#include "cpprest/json_validator.h" +#include "cpprest/regex_utils.h" +#include "nmos/api_utils.h" +#include "nmos/control_protocol_resources.h" +#include "nmos/is12_versions.h" +#include "nmos/json_schema.h" #include "nmos/model.h" +#include "nmos/query_utils.h" #include "nmos/slog.h" +#include "nmos/resources.h" namespace nmos { + namespace details + { + static const web::json::experimental::json_validator& controlprotocol_validator() + { + // hmm, could be based on supported API versions from settings, like other APIs' validators? + static const web::json::experimental::json_validator validator + { + nmos::experimental::load_json_schema, + boost::copy_range>(boost::join(boost::join( + is12_versions::all | boost::adaptors::transformed(experimental::make_controlprotocolapi_base_message_schema_uri), + is12_versions::all | boost::adaptors::transformed(experimental::make_controlprotocolapi_command_message_schema_uri)), + is12_versions::all | boost::adaptors::transformed(experimental::make_controlprotocolapi_subscription_message_schema_uri) + )) + }; + return validator; + } + + // Validate against specification schema + // throws web::json::json_exception on failure, which results in a 400 Badly-formed command + void validate_controlprotocolapi_base_message_schema(const nmos::api_version& version, const web::json::value& request_data) + { + controlprotocol_validator().validate(request_data, experimental::make_controlprotocolapi_base_message_schema_uri(version)); + } + void validate_controlprotocolapi_command_message_schema(const nmos::api_version& version, const web::json::value& request_data) + { + controlprotocol_validator().validate(request_data, experimental::make_controlprotocolapi_command_message_schema_uri(version)); + } + void validate_controlprotocolapi_subscription_message_schema(const nmos::api_version& version, const web::json::value& request_data) + { + controlprotocol_validator().validate(request_data, experimental::make_controlprotocolapi_subscription_message_schema_uri(version)); + } + } + // IS-12 Control Protocol WebSocket API web::websockets::experimental::listener::validate_handler make_control_protocol_ws_validate_handler(nmos::node_model& model, slog::base_gate& gate_) @@ -28,20 +70,72 @@ namespace nmos web::websockets::experimental::listener::open_handler make_control_protocol_ws_open_handler(nmos::node_model& model, nmos::websockets& websockets, slog::base_gate& gate_) { + using web::json::value; + using web::json::value_of; + return [&model, &websockets, &gate_](const web::uri& connection_uri, const web::websockets::experimental::listener::connection_id& connection_id) { nmos::ws_api_gate gate(gate_, connection_uri); auto lock = model.write_lock(); + auto& resources = model.control_protocol_resources; const auto& ws_ncp_path = connection_uri.path(); slog::log(gate, SLOG_FLF) << "Opening websocket connection to: " << ws_ncp_path; + + // create a subscription (1-1 relationship with the connection) + resources::const_iterator subscription; + + { + const bool secure = nmos::experimental::fields::client_secure(model.settings); + + const auto ws_href = web::uri_builder() + .set_scheme(web::ws_scheme(secure)) + .set_host(nmos::get_host(model.settings)) + .set_port(nmos::fields::events_ws_port(model.settings)) + .set_path(ws_ncp_path) + .to_uri(); + + const bool non_persistent = false; + value data = value_of({ + { nmos::fields::id, nmos::make_id() }, + { nmos::fields::max_update_rate_ms, 0 }, + { nmos::fields::resource_path, U('/') + nmos::resourceType_from_type(nmos::types::source) }, + { nmos::fields::params, value_of({ { U("query.rql"), U("in(id,())") } }) }, + { nmos::fields::persist, non_persistent }, + { nmos::fields::secure, secure }, + { nmos::fields::ws_href, ws_href.to_string() } + }, true); + + // hm, could version be determined from ws_resource_path? + nmos::resource subscription_{ is12_versions::v1_0, nmos::types::subscription, std::move(data), non_persistent }; + + subscription = insert_resource(resources, std::move(subscription_)).first; + } + { // create a websocket connection resource + value data; nmos::id id = nmos::make_id(); + data[nmos::fields::id] = value::string(id); + data[nmos::fields::subscription_id] = value::string(subscription->id); + + // create an initial websocket message with no data + + const auto resource_path = nmos::fields::resource_path(subscription->data); + const auto topic = resource_path + U('/'); + // source_id and flow_id are set per-message depending on the source, unlike Query WebSocket API + data[nmos::fields::message] = details::make_grain({}, {}, topic); + + resource grain{ is12_versions::v1_0, nmos::types::grain, std::move(data), false }; + insert_resource(resources, std::move(grain)); + websockets.insert({ id, connection_id }); slog::log(gate, SLOG_FLF) << "Creating websocket connection: " << id; + + slog::log(gate, SLOG_FLF) << "Notifying control protocol websockets thread"; // and anyone else who cares... + model.notify(); } }; } @@ -52,6 +146,7 @@ namespace nmos { nmos::ws_api_gate gate(gate_, connection_uri); auto lock = model.write_lock(); + auto& resources = model.control_protocol_resources; const auto& ws_ncp_path = connection_uri.path(); slog::log(gate, SLOG_FLF) << "Closing websocket connection to: " << ws_ncp_path << " [" << (int)close_status << ": " << close_reason << "]"; @@ -59,31 +154,583 @@ namespace nmos auto websocket = websockets.right.find(connection_id); if (websockets.right.end() != websocket) { - slog::log(gate, SLOG_FLF) << "Deleting websocket connection"; + auto grain = find_resource(resources, { websocket->second, nmos::types::grain }); + + if (resources.end() != grain) + { + slog::log(gate, SLOG_FLF) << "Deleting websocket connection"; + + // subscriptions have a 1-1 relationship with the websocket connection and both should now be erased immediately + auto subscription = find_resource(resources, { nmos::fields::subscription_id(grain->data), nmos::types::subscription }); + + if (resources.end() != subscription) + { + // this should erase grain too, as a subscription's subresource + erase_resource(resources, subscription->id); + } + else + { + // a grain without a subscription shouldn't be possible, but let's be tidy + erase_resource(resources, grain->id); + } + //erase_resource(resources, grain->id); + } websockets.right.erase(websocket); + + model.notify(); } }; } web::websockets::experimental::listener::message_handler make_control_protocol_ws_message_handler(nmos::node_model& model, nmos::websockets& websockets, slog::base_gate& gate_) { - return [&model, &websockets, &gate_](const web::uri& connection_uri, const web::websockets::experimental::listener::connection_id& connection_id, const web::websockets::websocket_incoming_message& msg_) + using web::json::value; + using web::json::value_of; + + // NcObject properties + // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject + const details::properties nc_object_properties = + { + // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject + { value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 1 } }), nmos::fields::nc::class_id }, + { value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 2 } }), nmos::fields::nc::oid }, + { value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 3 } }), nmos::fields::nc::constant_oid }, + { value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 4 } }), nmos::fields::nc::owner }, + { value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 5 } }), nmos::fields::nc::role }, + { value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 6 } }), nmos::fields::nc::user_label }, + { value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 7 } }), nmos::fields::nc::touchpoints }, + { value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 8 } }), nmos::fields::nc::runtime_property_constraints } + }; + + // NcBlock properties + // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock + const details::properties nc_block_properties = + { + // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock + { value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 1 } }), nmos::fields::nc::enabled }, + { value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 2 } }), nmos::fields::nc::members } + }; + + // NcWorker properties + // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncworker + const details::properties nc_worker_properties = + { + // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncworker + { value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 1 } }), nmos::fields::nc::enabled } + }; + + // NcManager has no property + // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanager + const details::properties nc_manager_properties; + + // NcDeviceManager properties + // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager + const details::properties nc_device_manager_properties = + { + // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager + { value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 1 } }), nmos::fields::nc::nc_version }, + { value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 2 } }), nmos::fields::nc::manufacturer }, + { value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 3 } }), nmos::fields::nc::product }, + { value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 4 } }), nmos::fields::nc::serial_number }, + { value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 5 } }), nmos::fields::nc::user_inventory_code }, + { value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 6 } }), nmos::fields::nc::device_name }, + { value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 7 } }), nmos::fields::nc::device_role }, + { value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 8 } }), nmos::fields::nc::operational_state }, + { value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 9 } }), nmos::fields::nc::reset_cause }, + { value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 10 } }), nmos::fields::nc::message } + }; + + // NcClassManager properties + // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager + const details::properties nc_class_manager_properties = + { + // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager + { value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 1 } }), nmos::fields::nc::control_classes }, + { value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 2 } }), nmos::fields::nc::datatypes } + }; + + // method handlers for the different classes + details::methods nc_object_method_handlers; // method_id vs NcObject method_handler + details::methods nc_block_method_handlers; // method_id vs NcBlock method_handler + details::methods nc_worker_method_handlers; // method_id vs NcWorker method_handler + details::methods nc_manager_method_handlers; // method_id vs NcManager method_handler + details::methods nc_device_manager_method_handlers; // method_id vs NcDeviceManager method_handler + details::methods nc_class_manager_method_handlers; // method_id vs NcClassManager method_handler + + // NcObject methods implementation + // get property + auto get = [&model](const details::properties& properties, int32_t handle, int32_t oid, const value& arguments) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + auto& resources = model.control_protocol_resources; + auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); + if (resources.end() != resource) + { + // where arguments is the property id = (level, index) + const auto& property_id = nmos::fields::nc::id(arguments); + + // is property_id defined in properties map + auto property_found = properties.find(property_id); + if (property_found != properties.end()) + { + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, resource->data.at(property_found->second)); + } + + // unknown property + utility::stringstream_t ss; + ss << U("unknown property: ") << property_id.serialize() << " to do get"; + return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); + } + + // resource not found for the given oid + utility::stringstream_t ss; + ss << U("unknown oid: ") << oid << " to do get"; + return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); + }; + // set property + auto set = [&model](const details::properties& properties, int32_t handle, int32_t oid, const value& arguments) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + auto& resources = model.control_protocol_resources; + auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); + if (resources.end() != resource) + { + const auto& property_id = nmos::fields::nc::id(arguments); + const auto& val = nmos::fields::nc::value(arguments); + + // hmm, todo check property_id allowed in resource's class_id + + // is property_id defined in properties map + auto property_found = properties.find(property_id); + if (property_found != properties.end()) + { + resources.modify(resource, [&](nmos::resource& resource) + { + resource.data[property_found->second] = val; + + resource.updated = strictly_increasing_update(resources); + }); + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }); + } + else + { + // hmm, find property function from user properties map + } + + // unknown property + utility::stringstream_t ss; + ss << U("unknown property: ") << property_id.serialize() << " to do set"; + return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); + } + + // resource not found for the given oid + utility::stringstream_t ss; + ss << U("unknown oid: ") << oid << " to do set"; + return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); + }; + + // NcBlock methods implementation + // get descriptors of members of the block + auto get_member_descriptors = [&model](const details::properties& properties, int32_t handle, int32_t oid, const value& arguments) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + auto& resources = model.control_protocol_resources; + auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); + if (resources.end() != resource) + { + // where arguments is the boolean recurse value + // hmm, If recurse is set to true, nested members is to be retrieved + const auto& recurse = nmos::fields::nc::recurse(arguments); + + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, resource->data.at(nmos::fields::nc::members)); + } + + // resource not found for the given oid + utility::stringstream_t ss; + ss << U("unknown oid: ") << oid << " to get member descriptors"; + return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); + }; + + // NcClassManager methods implementation + auto get_control_class = [&model](const details::properties& properties, int32_t handle, int32_t oid, const value& arguments) + { + // resource not found for the given oid + utility::stringstream_t ss; + ss << U("unknown oid: ") << oid << " to get control class"; + return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); + }; + + // NcObject methods + // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject + nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 1 } })] = get; + nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 2 } })] = set; + //nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 3 } })] = get_sequence_item; + //nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 4 } })] = set_sequence_item; + //nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 5 } })] = add_sequence_item; + //nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 6 } })] = remove_sequence_item; + //nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 7 } })] = get_sequence_length; + + // NcBlock methods + // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock + nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 1 } })] = get_member_descriptors; + //nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 2 } })] = find_members_by_path; + //nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 3 } })] = find_members_by_role; + //nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 4 } })] = find_members_by_class_id; + + // NcWorker has no extended method + // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncworker + + // NcManager has no extended method + // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanager + + // NcDeviceManger has no extended method + // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager + + // NcClassManager methods + // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager + //nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 1 } })] = get_control_class; + //nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 2 } })] = get_datatype; + + // create properties and method handlers based on resource type + auto create_properties_methods = [=](const nmos::type& type) + { + details::properties properties; + details::methods methods; + + // all start from NcObject + properties.insert(nc_object_properties.begin(), nc_object_properties.end()); + methods.insert(nc_object_method_handlers.begin(), nc_object_method_handlers.end()); + if (type == nmos::types::nc_block) + { + properties.insert(nc_block_properties.begin(), nc_block_properties.end()); + methods.insert(nc_block_method_handlers.begin(), nc_block_method_handlers.end()); + } + else if (type == nmos::types::nc_worker) + { + properties.insert(nc_worker_properties.begin(), nc_worker_properties.end()); + methods.insert(nc_worker_method_handlers.begin(), nc_worker_method_handlers.end()); + } + else if (type == nmos::types::nc_manager) + { + properties.insert(nc_manager_properties.begin(), nc_manager_properties.end()); + methods.insert(nc_manager_method_handlers.begin(), nc_manager_method_handlers.end()); + } + else if (type == nmos::types::nc_device_manager) + { + properties.insert(nc_manager_properties.begin(), nc_manager_properties.end()); + properties.insert(nc_device_manager_properties.begin(), nc_device_manager_properties.end()); + methods.insert(nc_manager_method_handlers.begin(), nc_manager_method_handlers.end()); + methods.insert(nc_device_manager_method_handlers.begin(), nc_device_manager_method_handlers.end()); + } + else if (type == nmos::types::nc_class_manager) + { + properties.insert(nc_manager_properties.begin(), nc_manager_properties.end()); + properties.insert(nc_class_manager_properties.begin(), nc_class_manager_properties.end()); + methods.insert(nc_manager_method_handlers.begin(), nc_manager_method_handlers.end()); + methods.insert(nc_class_manager_method_handlers.begin(), nc_class_manager_method_handlers.end()); + } + + // hmm, add user properties + //if (!user_properties.empty()) + //{ + // properties.insert(user_properties.begin(), user_properties.end()); + //} + + // hmm, add user method handlers + //if (!user_methods.empty()) + //{ + // methods.insert(user_methods.begin(), user_methods.end()); + //} + + return std::pair(properties, methods); + }; + + return [&model, &websockets, create_properties_methods, &gate_](const web::uri& connection_uri, const web::websockets::experimental::listener::connection_id& connection_id, const web::websockets::websocket_incoming_message& msg_) { nmos::ws_api_gate gate(gate_, connection_uri); - auto lock = model.read_lock(); + + auto lock = model.write_lock(); + auto& resources = model.control_protocol_resources; // theoretically blocking, but in fact not auto msg = msg_.extract_string().get(); const auto& ws_ncp_path = connection_uri.path(); - slog::log(gate, SLOG_FLF) << "Received websocket message: " << msg << " on connection to: " << ws_ncp_path; + slog::log(gate, SLOG_FLF) << "Received websocket message: " << msg << " on connection: " << ws_ncp_path; + + // hmm todo: extract the version from the ws_ncp_path + const nmos::api_version version = is12_versions::v1_0; + //const nmos::api_version version = nmos::parse_api_version(ws_ncp_path(nmos::patterns::version.name)); auto websocket = websockets.right.find(connection_id); if (websockets.right.end() != websocket) { - // hmm, todo message handling.... + auto grain = find_resource(resources, { websocket->second, nmos::types::grain }); + + if (resources.end() != grain) + { + auto subscription = find_resource(resources, { nmos::fields::subscription_id(grain->data), nmos::types::subscription }); + + if (resources.end() != subscription) + { + try + { + const auto message = value::parse(utility::conversions::to_string_t(msg)); + + // validate the base-message + details::validate_controlprotocolapi_base_message_schema(version, message); + + const auto msg_type = nmos::fields::nc::message_type(message); + switch (msg_type) + { + case details::nc_message_type::command: + { + // validate command-message + details::validate_controlprotocolapi_command_message_schema(version, message); + + auto responses = value::array(); + auto& commands = nmos::fields::nc::commands(message); + for (const auto& cmd : commands) + { + const auto handle = nmos::fields::nc::handle(cmd); + const auto oid = nmos::fields::nc::oid(cmd); + + // get methodId + const auto& method_id = nmos::fields::nc::method_id(cmd); + + // get arguments + const auto& arguments = nmos::fields::nc::arguments(cmd); + + auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); + if (resources.end() != resource) + { + // create properties and method handlers based on resource type + auto properties_methods = create_properties_methods(resource->type); + auto& properties = properties_methods.first; + auto& methods = properties_methods.second; + + // find the relevent method handler to execute + auto method = methods.find(method_id); + if (method != methods.end()) + { + // execute the relevant method handler, then accumulating up their response to reponses + web::json::push_back(responses, method->second(properties, handle, oid, arguments)); + } + else + { + utility::stringstream_t ss; + ss << U("unsupported method id: ") << method_id.serialize(); + web::json::push_back(responses, + details::make_control_protocol_error_response(handle, { details::nc_method_status::method_not_implemented }, ss.str())); + } + } + else + { + // resource not found for the given oid + utility::stringstream_t ss; + ss << U("unknown oid: ") << oid; + web::json::push_back(responses, + details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str())); + } + } + + // add command_response for the control protocol response thread to return to the client + resources.modify(grain, [&](nmos::resource& grain) + { + web::json::push_back(nmos::fields::message_grain_data(grain.data), + details::make_control_protocol_message_response(details::nc_message_type::command_response, responses)); + + grain.updated = strictly_increasing_update(resources); + }); + } + break; + case details::nc_message_type::subscription: + { + // hmm, todo... + } + break; + default: + // unexpected message type + break; + } + + } + catch (const web::json::json_exception& e) + { + slog::log(gate, SLOG_FLF) << "JSON error: " << e.what(); + + resources.modify(grain, [&](nmos::resource& grain) + { + web::json::push_back(nmos::fields::message_grain_data(grain.data), + details::make_control_protocol_error_message({ details::nc_method_status::bad_command_format }, utility::s2us(e.what()))); + + grain.updated = strictly_increasing_update(resources); + }); + } + catch (const std::exception& e) + { + slog::log(gate, SLOG_FLF) << "Unexpected exception while handing control protocol command: " << e.what(); + + resources.modify(grain, [&](nmos::resource& grain) + { + web::json::push_back(nmos::fields::message_grain_data(grain.data), + details::make_control_protocol_error_message({ details::nc_method_status::bad_command_format }, + utility::s2us(std::string("Unexpected exception while handing control protocol command : ") + e.what()))); + + grain.updated = strictly_increasing_update(resources); + }); + } + catch (...) + { + slog::log(gate, SLOG_FLF) << "Unexpected unknown exception for handing control protocol command"; + + resources.modify(grain, [&](nmos::resource& grain) + { + web::json::push_back(nmos::fields::message_grain_data(grain.data), + details::make_control_protocol_error_message({ details::nc_method_status::bad_command_format }, + U("Unexpected unknown exception while handing control protocol command"))); + + grain.updated = strictly_increasing_update(resources); + }); + } + model.notify(); + } + } + } + }; + } + + // observe_websocket_exception is the same as the one defined in events_ws_api + namespace details + { + struct observe_websocket_exception + { + observe_websocket_exception(slog::base_gate& gate) : gate(gate) {} + + void operator()(pplx::task finally) + { + try + { + finally.get(); + } + catch (const web::websockets::websocket_exception& e) + { + slog::log(gate, SLOG_FLF) << "WebSocket error: " << e.what() << " [" << e.error_code() << "]"; + } } + + slog::base_gate& gate; }; } + + void send_control_protocol_ws_messages_thread(web::websockets::experimental::listener::websocket_listener& listener, nmos::node_model& model, nmos::websockets& websockets, slog::base_gate& gate_) + { + nmos::details::omanip_gate gate(gate_, nmos::stash_category(nmos::categories::send_control_protocol_ws_messages)); + + using web::json::value; + using web::json::value_of; + + // could start out as a shared/read lock, only upgraded to an exclusive/write lock when a grain in the resources is actually modified + auto lock = model.write_lock(); + auto& condition = model.condition; + auto& shutdown = model.shutdown; + auto& resources = model.control_protocol_resources; + + tai most_recent_message{}; + auto earliest_necessary_update = (tai_clock::time_point::max)(); + + for (;;) + { + // wait for the thread to be interrupted either because there are resource changes, or because the server is being shut down + // or because message sending was throttled earlier + details::wait_until(condition, lock, earliest_necessary_update, [&] { return shutdown || most_recent_message < most_recent_update(resources); }); + if (shutdown) break; + most_recent_message = most_recent_update(resources); + + slog::log(gate, SLOG_FLF) << "Got notification on control protocol websockets thread"; + + earliest_necessary_update = (tai_clock::time_point::max)(); + + std::vector> outgoing_messages; + + for (auto wit = websockets.left.begin(); websockets.left.end() != wit;) + { + const auto& websocket = *wit; + + // for each websocket connection that has valid grain and subscription resources + const auto grain = find_resource(resources, { websocket.first, nmos::types::grain }); + if (resources.end() == grain) + { + auto close = listener.close(websocket.second, web::websockets::websocket_close_status::server_terminate, U("Expired")) + .then(details::observe_websocket_exception(gate)); + // theoretically blocking, but in fact not + close.wait(); + + wit = websockets.left.erase(wit); + continue; + } + const auto subscription = find_resource(resources, { nmos::fields::subscription_id(grain->data), nmos::types::subscription }); + if (resources.end() == subscription) + { + // a grain without a subscription shouldn't be possible, but let's be tidy + erase_resource(resources, grain->id); + + auto close = listener.close(websocket.second, web::websockets::websocket_close_status::server_terminate, U("Expired")) + .then(details::observe_websocket_exception(gate)); + // theoretically blocking, but in fact not + close.wait(); + + wit = websockets.left.erase(wit); + continue; + } + // and has events to send + if (0 == nmos::fields::message_grain_data(grain->data).size()) + { + ++wit; + continue; + } + + slog::log(gate, SLOG_FLF) << "Preparing to send " << nmos::fields::message_grain_data(grain->data).size() << " events on websocket connection: " << grain->id; + + for (const auto& event : nmos::fields::message_grain_data(grain->data).as_array()) + { + web::websockets::websocket_outgoing_message message; + + slog::log(gate, SLOG_FLF) << "outgoing_message: " << event.serialize(); + message.set_utf8_message(utility::us2s(event.serialize())); + outgoing_messages.push_back({ websocket.second, message }); + } + + // reset the grain for next time + resources.modify(grain, [&resources](nmos::resource& grain) + { + // all messages have now been prepared + nmos::fields::message_grain_data(grain.data) = value::array(); + grain.updated = strictly_increasing_update(resources); + }); + + ++wit; + } + + // send the messages without the lock on resources + details::reverse_lock_guard unlock{ lock }; + + if (!outgoing_messages.empty()) slog::log(gate, SLOG_FLF) << "Sending " << outgoing_messages.size() << " websocket messages"; + + for (auto& outgoing_message : outgoing_messages) + { + // hmmm, no way to cancel this currently... + + auto send = listener.send(outgoing_message.first, outgoing_message.second) + .then(details::observe_websocket_exception(gate)); + // current websocket_listener implementation is synchronous in any case, but just to make clear... + // for now, wait for the message to be sent + send.wait(); + } + } + } } diff --git a/Development/nmos/control_protocol_ws_api.h b/Development/nmos/control_protocol_ws_api.h index 71772961f..2371616d1 100644 --- a/Development/nmos/control_protocol_ws_api.h +++ b/Development/nmos/control_protocol_ws_api.h @@ -26,6 +26,8 @@ namespace nmos nmos::make_control_protocol_ws_message_handler(model, websockets, gate) }; } + + void send_control_protocol_ws_messages_thread(web::websockets::experimental::listener::websocket_listener& listener, nmos::node_model& model, nmos::websockets& websockets, slog::base_gate& gate_); } #endif diff --git a/Development/nmos/is12_schemas/is12_schemas.h b/Development/nmos/is12_schemas/is12_schemas.h new file mode 100644 index 000000000..392b57648 --- /dev/null +++ b/Development/nmos/is12_schemas/is12_schemas.h @@ -0,0 +1,25 @@ +#ifndef NMOS_IS12_SCHEMAS_H +#define NMOS_IS12_SCHEMAS_H + +// Extern declarations for auto-generated constants +// could be auto-generated, but isn't currently! +namespace nmos +{ + namespace is12_schemas + { + namespace v1_0_x + { + extern const char* base_message; + extern const char* command_message; + extern const char* command_response_message; + extern const char* error_message; + extern const char* event_data; + extern const char* notification_message; + extern const char* property_changed_event_data; + extern const char* subscription_message; + extern const char* subscription_response_message; + } + } +} + +#endif diff --git a/Development/nmos/json_fields.h b/Development/nmos/json_fields.h index d04d57923..a18242e7c 100644 --- a/Development/nmos/json_fields.h +++ b/Development/nmos/json_fields.h @@ -230,6 +230,94 @@ namespace nmos const web::json::field_as_string hostname{ U("hostname") }; // hostname, ipv4 or ipv6 const web::json::field_as_integer port{ U("port") }; // 1..65535 + // IS-12 Control Protocol + namespace nc + { + // for control_protocol_ws_api + const web::json::field_as_integer message_type{ U("messageType") }; + + // for control_protocol_ws_api commands + const web::json::field_as_array commands{ U("commands") }; + const web::json::field_as_integer oid{ U("oid") }; + const web::json::field_as_value method_id{ U("methodId") }; + const web::json::field_as_value arguments{ U("arguments") }; + const web::json::field_as_value id{ U("id") }; + const web::json::field_as_integer level{ U("level") }; + const web::json::field_as_integer index{ U("index") }; + + // for control_protocol_ws_api responses & errors + const web::json::field_as_value responses{ U("responses") }; + const web::json::field_as_value result{ U("result") }; + const web::json::field_as_integer status{ U("status") }; + const web::json::field_as_value value{ U("value") }; + const web::json::field_as_string error_message{ U("errorMessage") }; + + // for control_protocol_ws_api commands & responses + const web::json::field_as_integer handle{ U("handle") }; + + const web::json::field_as_array class_id{ U("classId") }; + const web::json::field_as_bool constant_oid{ U("constantOid") }; + const web::json::field_as_integer owner{ U("owner") }; + const web::json::field_as_string role{ U("role") }; + const web::json::field_as_string user_label{ U("userLabel") }; + const web::json::field_as_array touchpoints{ U("touchpoints") }; + const web::json::field_as_array runtime_property_constraints{ U("runtimePropertyConstraints") }; + const web::json::field_as_bool recurse{ U("recurse") }; + const web::json::field_as_bool enabled{ U("enabled") }; + const web::json::field_as_array members{ U("members") }; + const web::json::field_as_string description{ U("description") }; // can be null + const web::json::field_as_string nc_version{ U("ncVersion") }; // NcVersionCode, string + const web::json::field_as_value manufacturer{ U("manufacturer") }; // NcManufacturer + const web::json::field_as_value product{ U("product") }; // NcProduct + const web::json::field_as_string serial_number{ U("serialNumber") }; + const web::json::field_as_string user_inventory_code{ U("userInventoryCode") }; // string, can be null + const web::json::field_as_string device_name{ U("deviceName") }; // string, can be null + const web::json::field_as_string device_role{ U("deviceRole") }; // string, can be null + const web::json::field_as_value operational_state{ U("operationalState") }; // NcDeviceOperationalState + const web::json::field_as_integer reset_cause{ U("resetCause") }; // NcResetCause + const web::json::field_as_string message{ U("message") }; // string, can be null + const web::json::field_as_array control_classes{ U("controlClasses") }; // sequence + const web::json::field_as_array datatypes{ U("datatypes") }; // sequence + const web::json::field_as_string name{ U("name")}; + const web::json::field_as_string fixed_role{ U("fixedRole") }; // string, can be null + const web::json::field_as_array properties{ U("properties") }; // sequence + const web::json::field_as_array methods{ U("methods") }; // sequence + const web::json::field_as_array events{ U("events") }; // sequence + const web::json::field_as_integer type{ U("type") }; // NcDatatypeType + const web::json::field_as_value constraints{ U("constraints") }; // NcParameterConstraints, can be null + const web::json::field_as_integer organization_id{ U("organizationId") }; + const web::json::field_as_string website{ U("website") }; + const web::json::field_as_string key{ U("key") }; + const web::json::field_as_string revision_level{ U("revisionLevel") }; + const web::json::field_as_string brand_name{ U("brandName") }; // string, can be null + const web::json::field_as_string uuid{ U("uuid") }; // string, can be null + const web::json::field_as_string type_name{ U("typeName") }; // string, can be null + const web::json::field_as_bool is_read_only{ U("isReadOnly") }; + const web::json::field_as_bool is_persistent{ U("isPersistent") }; + const web::json::field_as_bool is_nullable{ U("isNullable") }; + const web::json::field_as_bool is_sequence{ U("isSequence") }; + const web::json::field_as_bool is_deprecated{ U("isDeprecated") }; + const web::json::field_as_bool is_constant{ U("isConstant") }; // bool, can be null + const web::json::field_as_string parent_type{ U("parentType") }; + const web::json::field_as_string event_datatype{ U("eventDatatype") }; + const web::json::field_as_string result_datatype{ U("resultDatatype") }; + const web::json::field_as_array parameters{ U("parameters") }; + const web::json::field_as_array items{ U("items") }; // sequence + const web::json::field_as_array fields{ U("fields") }; // sequence + const web::json::field_as_integer generic_state{ U("generic") }; // NcDeviceGenericState + const web::json::field_as_string device_specific_details{ U("deviceSpecificDetails") }; // string, can be null + const web::json::field_as_array path{ U("path") }; // NcRolePath + const web::json::field_as_bool case_sensitive{ U("caseSensitive") }; + const web::json::field_as_bool match_whole_string{ U("matchWholeString") }; + const web::json::field_as_bool include_derived{ U("includeDerived") }; + const web::json::field_as_bool include_inherited{ U("includeInherited") }; + const web::json::field_as_string context_namespace{ U("contextNamespace") }; + const web::json::field_as_value default_value{ U("defaultValue") }; + const web::json::field_as_integer change_type{ U("changeType") }; // NcPropertyChangeType + const web::json::field_as_integer sequence_item_index{ U("sequenceItemIndex") }; // NcId, can be null + const web::json::field_as_value property_id{ U("propertyId") }; + } + // NMOS Parameter Registers // Sender Attributes Register diff --git a/Development/nmos/json_schema.cpp b/Development/nmos/json_schema.cpp index fdd70581d..774b9e179 100644 --- a/Development/nmos/json_schema.cpp +++ b/Development/nmos/json_schema.cpp @@ -9,6 +9,8 @@ #include "nmos/is08_schemas/is08_schemas.h" #include "nmos/is09_versions.h" #include "nmos/is09_schemas/is09_schemas.h" +#include "nmos/is12_versions.h" +#include "nmos/is12_schemas/is12_schemas.h" #include "nmos/type.h" namespace nmos @@ -126,6 +128,25 @@ namespace nmos const web::uri systemapi_global_schema_uri = make_schema_uri(tag, _XPLATSTR("global.json")); } } + + namespace is12_schemas + { + web::uri make_schema_uri(const utility::string_t& tag, const utility::string_t& ref = {}) + { + return{ _XPLATSTR("https://github.com/AMWA-TV/is-12/raw/") + tag + _XPLATSTR("/APIs/schemas/") + ref }; + } + + // See https://github.com/AMWA-TV/is-12/tree/v1.0-dev/APIs/schemas/ + namespace v1_0 + { + using namespace nmos::is12_schemas::v1_0_x; + const utility::string_t tag(_XPLATSTR("v1.0.x")); + + const web::uri controlprotocolapi_base_message_schema_uri = make_schema_uri(tag, _XPLATSTR("base-message.json")); + const web::uri controlprotocolapi_command_message_schema_uri = make_schema_uri(tag, _XPLATSTR("command-message.json")); + const web::uri controlprotocolapi_subscription_message_schema_uri = make_schema_uri(tag, _XPLATSTR("subscription-message.json")); + } + } } namespace nmos @@ -310,6 +331,25 @@ namespace nmos }; } + static std::map make_is12_schemas() + { + using namespace nmos::is12_schemas; + + return + { + // v1.0 + { make_schema_uri(v1_0::tag, _XPLATSTR("base-message.json")), make_schema(v1_0::base_message) }, + { make_schema_uri(v1_0::tag, _XPLATSTR("command-message.json")), make_schema(v1_0::command_message) }, + { make_schema_uri(v1_0::tag, _XPLATSTR("command-response-message.json")), make_schema(v1_0::command_response_message) }, + { make_schema_uri(v1_0::tag, _XPLATSTR("error-message.json")), make_schema(v1_0::error_message) }, + { make_schema_uri(v1_0::tag, _XPLATSTR("event-data.json")), make_schema(v1_0::event_data) }, + { make_schema_uri(v1_0::tag, _XPLATSTR("notification-message.json")), make_schema(v1_0::notification_message) }, + { make_schema_uri(v1_0::tag, _XPLATSTR("property-changed-event-data.json")), make_schema(v1_0::property_changed_event_data) }, + { make_schema_uri(v1_0::tag, _XPLATSTR("subscription-message.json")), make_schema(v1_0::subscription_message) }, + { make_schema_uri(v1_0::tag, _XPLATSTR("subscription-response-message.json")), make_schema(v1_0::subscription_response_message) } + }; + } + inline void merge(std::map& to, std::map&& from) { to.insert(from.begin(), from.end()); // std::map::merge in C++17 @@ -321,6 +361,7 @@ namespace nmos merge(result, make_is05_schemas()); merge(result, make_is08_schemas()); merge(result, make_is09_schemas()); + merge(result, make_is12_schemas()); return result; } @@ -382,6 +423,21 @@ namespace nmos return is08_schemas::v1_0::map_activations_post_request_uri; } + web::uri make_controlprotocolapi_base_message_schema_uri(const nmos::api_version& version) + { + return is12_schemas::v1_0::controlprotocolapi_base_message_schema_uri; + } + + web::uri make_controlprotocolapi_command_message_schema_uri(const nmos::api_version& version) + { + return is12_schemas::v1_0::controlprotocolapi_command_message_schema_uri; + } + + web::uri make_controlprotocolapi_subscription_message_schema_uri(const nmos::api_version& version) + { + return is12_schemas::v1_0::controlprotocolapi_subscription_message_schema_uri; + } + // load the json schema for the specified base URI web::json::value load_json_schema(const web::uri& id) { diff --git a/Development/nmos/json_schema.h b/Development/nmos/json_schema.h index e938a513e..e09b3de82 100644 --- a/Development/nmos/json_schema.h +++ b/Development/nmos/json_schema.h @@ -29,6 +29,10 @@ namespace nmos web::uri make_channelmappingapi_map_activations_post_request_schema_uri(const nmos::api_version& version); + web::uri make_controlprotocolapi_base_message_schema_uri(const nmos::api_version& version); + web::uri make_controlprotocolapi_command_message_schema_uri(const nmos::api_version& version); + web::uri make_controlprotocolapi_subscription_message_schema_uri(const nmos::api_version& version); + // load the json schema for the specified base URI web::json::value load_json_schema(const web::uri& id); } diff --git a/Development/nmos/model.h b/Development/nmos/model.h index d5c6b9f99..d9c25559c 100644 --- a/Development/nmos/model.h +++ b/Development/nmos/model.h @@ -101,6 +101,10 @@ namespace nmos // IS-08 inputs and outputs for this node // see nmos/channelmapping_resources.h nmos::resources channelmapping_resources; + + // IS-12 resources for this node + // see nmos/control_protocol_resources.h + nmos::resources control_protocol_resources; }; struct registry_model : model diff --git a/Development/nmos/node_server.cpp b/Development/nmos/node_server.cpp index 293784adc..2de24d450 100644 --- a/Development/nmos/node_server.cpp +++ b/Development/nmos/node_server.cpp @@ -94,6 +94,8 @@ namespace nmos size_t event_ws_pos{ 0 }; bool found_event_ws{ false }; + size_t control_protocol_ws_pos{ 0 }; + bool found_control_protocol_ws{ false }; for (auto& ws_handler : node_server.ws_handlers) { // if IP address isn't specified for this router, use default server address or wildcard address @@ -107,9 +109,16 @@ namespace nmos if (ws_handler.first.second == events_ws_port) { found_event_ws = true; } else { ++event_ws_pos; } } + + if (!found_control_protocol_ws) + { + if (ws_handler.first.second == control_protocol_ws_port) { found_control_protocol_ws = true; } + else { ++control_protocol_ws_pos; } + } } auto& events_ws_listener = node_server.ws_listeners.at(event_ws_pos); + auto& control_protocol_ws_listener = node_server.ws_listeners.at(control_protocol_ws_pos); // Set up node operation (including the DNS-SD advertisements) @@ -124,7 +133,8 @@ namespace nmos [&] { nmos::send_events_ws_messages_thread(events_ws_listener, node_model, events_ws_api.second, gate); }, [&] { nmos::erase_expired_events_resources_thread(node_model, gate); }, [&, resolve_auto, set_transportfile, connection_activated] { nmos::connection_activation_thread(node_model, resolve_auto, set_transportfile, connection_activated, gate); }, - [&, channelmapping_activated] { nmos::channelmapping_activation_thread(node_model, channelmapping_activated, gate); } + [&, channelmapping_activated] { nmos::channelmapping_activation_thread(node_model, channelmapping_activated, gate); }, + [&] { nmos::send_control_protocol_ws_messages_thread(control_protocol_ws_listener, node_model, control_protocol_ws_api.second, gate); } }); auto system_changed = node_implementation.system_changed; diff --git a/Development/nmos/settings.h b/Development/nmos/settings.h index 1f240e21f..0790506e3 100644 --- a/Development/nmos/settings.h +++ b/Development/nmos/settings.h @@ -360,6 +360,20 @@ namespace nmos // ocsp_request_max [registry, node]: timeout for interactions with the OCSP server const web::json::field_as_integer_or ocsp_request_max{ U("ocsp_request_max"), 30 }; + + // manufacturer_name [node]: the manufacturer name of the NcDeviceManager used for NMOS Control Protocol + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager + const web::json::field_as_string_or manufacturer_name{ U("manufacturer_name"), U("") }; + + // product_name/product_key/product_revision_level [node]: the product description of the NcDeviceManager used for NMOS Control Protocol + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncproduct + const web::json::field_as_string_or product_name{ U("product_name"), U("") }; + const web::json::field_as_string_or product_key{ U("product_key"), U("") }; + const web::json::field_as_string_or product_revision_level{ U("product_revision_level"), U("") }; + + // serial_number [node]: the serial number of the NcDeviceManager used for NMOS Control Protocol + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager + const web::json::field_as_string_or serial_number{ U("serial_number"), U("") }; } } } diff --git a/Development/nmos/slog.h b/Development/nmos/slog.h index d3fc150fd..3a50d1059 100644 --- a/Development/nmos/slog.h +++ b/Development/nmos/slog.h @@ -44,6 +44,7 @@ namespace nmos const category send_events_ws_commands{ "send_events_ws_commands" }; const category node_system_behaviour{ "node_system_behaviour" }; const category ocsp_behaviour{ "ocsp_behaviour" }; + const category send_control_protocol_ws_messages{ "send_control_protocol_ws_messages" }; // other categories may be defined ad-hoc } diff --git a/Development/nmos/type.h b/Development/nmos/type.h index d58734f81..4fcf54f97 100644 --- a/Development/nmos/type.h +++ b/Development/nmos/type.h @@ -39,6 +39,13 @@ namespace nmos // the System API global configuration resource type, see nmos/system_resources.h const type global{ U("global") }; + + // the Control Protocol API resource types, see nmos/control_protcol_resources.h + const type nc_block{ U("nc_block") }; + const type nc_worker{ U("nc_worker") }; + const type nc_manager{ U("nc_manager") }; + const type nc_device_manager{ U("nc_device_manager") }; + const type nc_class_manager{ U("nc_class_manager") }; } } diff --git a/Development/third_party/is-12/README.md b/Development/third_party/is-12/README.md new file mode 100644 index 000000000..84e840adb --- /dev/null +++ b/Development/third_party/is-12/README.md @@ -0,0 +1 @@ +This directory is for JSON Schemas diff --git a/Development/third_party/is-12/v1.0.x/APIs/schemas/base-message.json b/Development/third_party/is-12/v1.0.x/APIs/schemas/base-message.json new file mode 100644 index 000000000..1ecd16c6b --- /dev/null +++ b/Development/third_party/is-12/v1.0.x/APIs/schemas/base-message.json @@ -0,0 +1,23 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "description": "Base protocol message structure", + "title": "Base protocol message", + "required": [ + "messageType" + ], + "properties": { + "messageType": { + "description": "Protocol message type", + "type": "integer", + "enum": [ + 0, + 1, + 2, + 3, + 4, + 5 + ] + } + } +} \ No newline at end of file diff --git a/Development/third_party/is-12/v1.0.x/APIs/schemas/command-message.json b/Development/third_party/is-12/v1.0.x/APIs/schemas/command-message.json new file mode 100644 index 000000000..cce540fa0 --- /dev/null +++ b/Development/third_party/is-12/v1.0.x/APIs/schemas/command-message.json @@ -0,0 +1,79 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "description": "Command protocol message structure", + "title": "Command protocol message", + "allOf": [ + { + "$ref": "base-message.json" + }, + { + "type": "object", + "required": [ + "commands", + "messageType" + ], + "properties": { + "commands": { + "description": "Commands being transmited in this transaction", + "type": "array", + "items": { + "type": "object", + "required": [ + "handle", + "oid", + "methodId" + ], + "properties": { + "handle": { + "type": "integer", + "description": "Integer value used for pairing with the response", + "minimum": 1, + "maximum": 65535 + }, + "oid": { + "type": "integer", + "description": "Object id containing the method", + "minimum": 1, + "maximum": 65535 + }, + "methodId": { + "type": "object", + "description": "ID structure for the target method", + "required": [ + "level", + "index" + ], + "properties": { + "level": { + "type": "integer", + "description": "Level component of the method ID", + "minimum": 0, + "maximum": 65535 + }, + "index": { + "type": "integer", + "description": "Index component of the method ID", + "minimum": 1, + "maximum": 65535 + } + } + }, + "arguments": { + "type": "object", + "description": "Method arguments" + } + } + } + }, + "messageType": { + "description": "Protocol message type", + "type": "integer", + "enum": [ + 0 + ] + } + } + } + ] +} \ No newline at end of file diff --git a/Development/third_party/is-12/v1.0.x/APIs/schemas/command-response-message.json b/Development/third_party/is-12/v1.0.x/APIs/schemas/command-response-message.json new file mode 100644 index 000000000..93711f583 --- /dev/null +++ b/Development/third_party/is-12/v1.0.x/APIs/schemas/command-response-message.json @@ -0,0 +1,69 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "description": "Command response protocol message structure", + "title": "Command response protocol message", + "allOf": [ + { + "$ref": "base-message.json" + }, + { + "type": "object", + "required": [ + "responses", + "messageType" + ], + "properties": { + "responses": { + "description": "Responses being transmited in this transaction", + "type": "array", + "items": { + "type": "object", + "required": [ + "handle", + "result" + ], + "properties": { + "handle": { + "type": "integer", + "description": "Integer value used for pairing with the command", + "minimum": 1, + "maximum": 65535 + }, + "result": { + "type": "object", + "description": "Response result", + "required": [ + "status" + ], + "properties": { + "status": { + "type": "integer", + "description": "Status of the command response. Must include the numeric values for NcMethodStatus or other types which inherit from it. 200 must be returned if the command was successful", + "minimum": 0, + "maximum": 65535 + }, + "value": { + "type": ["string", "number", "object", "array", "boolean", "null" ], + "description": "Method return value as described in the MS-05-02 Type definition or in a private Type definition" + }, + "errorMessage": { + "description": "Error message associated with the failure of the command (optional)", + "type": "string" + } + } + } + } + } + }, + "messageType": { + "description": "Protocol message type", + "type": "integer", + "enum": [ + 1 + ] + } + } + } + ] +} \ No newline at end of file diff --git a/Development/third_party/is-12/v1.0.x/APIs/schemas/error-message.json b/Development/third_party/is-12/v1.0.x/APIs/schemas/error-message.json new file mode 100644 index 000000000..139c77ffc --- /dev/null +++ b/Development/third_party/is-12/v1.0.x/APIs/schemas/error-message.json @@ -0,0 +1,38 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "description": "Error protocol message structure - used by devices to return general error messages for example when incoming messages do not have messageType, handles or contain invalid JSON", + "title": "Error protocol message", + "allOf": [ + { + "$ref": "base-message.json" + }, + { + "type": "object", + "required": [ + "status", + "errorMessage", + "messageType" + ], + "properties": { + "status": { + "type": "integer", + "description": "Status of the message response. Must include the numeric values for NcMethodStatus or other types which inherit from it.", + "minimum": 0, + "maximum": 65535 + }, + "errorMessage": { + "description": "Error details associated with the failure", + "type": "string" + }, + "messageType": { + "description": "Protocol message type", + "type": "integer", + "enum": [ + 5 + ] + } + } + } + ] +} diff --git a/Development/third_party/is-12/v1.0.x/APIs/schemas/event-data.json b/Development/third_party/is-12/v1.0.x/APIs/schemas/event-data.json new file mode 100644 index 000000000..9b644871c --- /dev/null +++ b/Development/third_party/is-12/v1.0.x/APIs/schemas/event-data.json @@ -0,0 +1,11 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "description": "Event data structure", + "title": "Event data", + "oneOf": [ + { + "$ref": "property-changed-event-data.json" + } + ] +} diff --git a/Development/third_party/is-12/v1.0.x/APIs/schemas/notification-message.json b/Development/third_party/is-12/v1.0.x/APIs/schemas/notification-message.json new file mode 100644 index 000000000..c8a64e81d --- /dev/null +++ b/Development/third_party/is-12/v1.0.x/APIs/schemas/notification-message.json @@ -0,0 +1,72 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "description": "Notification protocol message structure", + "title": "Notification protocol message", + "allOf": [ + { + "$ref": "base-message.json" + }, + { + "type": "object", + "required": [ + "notifications", + "messageType" + ], + "properties": { + "notifications": { + "description": "Notifications being transmited in this transaction", + "type": "array", + "items": { + "type": "object", + "required": [ + "oid", + "eventId", + "eventData" + ], + "properties": { + "oid": { + "type": "integer", + "description": "Emitter object id", + "minimum": 1, + "maximum": 65535 + }, + "eventId": { + "type": "object", + "description": "Event ID structure", + "required": [ + "level", + "index" + ], + "properties": { + "level": { + "type": "integer", + "description": "Level component of the event ID", + "minimum": 0, + "maximum": 65535 + }, + "index": { + "type": "integer", + "description": "Index component of the event ID", + "minimum": 1, + "maximum": 65535 + } + } + }, + "eventData": { + "$ref": "event-data.json" + } + } + } + }, + "messageType": { + "description": "Protocol message type", + "type": "integer", + "enum": [ + 2 + ] + } + } + } + ] +} \ No newline at end of file diff --git a/Development/third_party/is-12/v1.0.x/APIs/schemas/property-changed-event-data.json b/Development/third_party/is-12/v1.0.x/APIs/schemas/property-changed-event-data.json new file mode 100644 index 000000000..62249e306 --- /dev/null +++ b/Development/third_party/is-12/v1.0.x/APIs/schemas/property-changed-event-data.json @@ -0,0 +1,60 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "description": "Property changed event data structure", + "title": "Property changed event data", + "properties": { + "propertyId": { + "type": "object", + "description": "Property ID structure", + "required": [ + "level", + "index" + ], + "properties": { + "level": { + "type": "integer", + "description": "Level component of the property ID", + "minimum": 0, + "maximum": 65535 + }, + "index": { + "type": "integer", + "description": "Index component of the property ID", + "minimum": 1, + "maximum": 65535 + } + } + }, + "changeType": { + "type": "integer", + "description": "Event change type numeric value. Must include the numeric values for NcPropertyChangeType", + "minimum": 0, + "maximum": 65535 + }, + "value": { + "type": [ + "string", + "number", + "object", + "array", + "boolean", + "null" + ], + "description": "Property value as described in the MS-05-02 Class definition or in a private Class definition" + }, + "sequenceItemIndex": { + "type": [ + "number", + "null" + ], + "description": "Index of sequence item if the property is a sequence" + } + }, + "required": [ + "propertyId", + "changeType", + "value", + "sequenceItemIndex" + ] +} diff --git a/Development/third_party/is-12/v1.0.x/APIs/schemas/subscription-message.json b/Development/third_party/is-12/v1.0.x/APIs/schemas/subscription-message.json new file mode 100644 index 000000000..290ccd903 --- /dev/null +++ b/Development/third_party/is-12/v1.0.x/APIs/schemas/subscription-message.json @@ -0,0 +1,34 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "description": "Subscription protocol message structure", + "title": "Subscription protocol message", + "allOf": [ + { + "$ref": "base-message.json" + }, + { + "type": "object", + "required": [ + "subscriptions", + "messageType" + ], + "properties": { + "subscriptions": { + "description": "Array of OIDs desired for subscription", + "type": "array", + "items": { + "type": "integer" + } + }, + "messageType": { + "description": "Protocol message type", + "type": "integer", + "enum": [ + 3 + ] + } + } + } + ] +} diff --git a/Development/third_party/is-12/v1.0.x/APIs/schemas/subscription-response-message.json b/Development/third_party/is-12/v1.0.x/APIs/schemas/subscription-response-message.json new file mode 100644 index 000000000..587cdd62a --- /dev/null +++ b/Development/third_party/is-12/v1.0.x/APIs/schemas/subscription-response-message.json @@ -0,0 +1,34 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "description": "Subscription response protocol message structure", + "title": "Subscription response protocol message", + "allOf": [ + { + "$ref": "base-message.json" + }, + { + "type": "object", + "required": [ + "subscriptions", + "messageType" + ], + "properties": { + "subscriptions": { + "description": "Array of OIDs which have successfully been added to the subscription list.", + "type": "array", + "items": { + "type": "integer" + } + }, + "messageType": { + "description": "Protocol message type", + "type": "integer", + "enum": [ + 4 + ] + } + } + } + ] +} From bb6db52ca509ff9069519e4c38bd820b894c544c Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 8 Aug 2023 15:37:17 +0100 Subject: [PATCH 007/106] Add readonly on Get propertry support. Add callback to retrieve control classes from control_protocol_state --- Development/cmake/NmosCppLibraries.cmake | 6 + Development/nmos-cpp-node/main.cpp | 5 + .../nmos/control_protocol_handlers.cpp | 64 ++ Development/nmos/control_protocol_handlers.h | 44 + .../nmos/control_protocol_resource.cpp | 1018 +++++++++++++++++ Development/nmos/control_protocol_resource.h | 309 +++++ .../nmos/control_protocol_resources.cpp | 905 +-------------- Development/nmos/control_protocol_resources.h | 130 +-- Development/nmos/control_protocol_state.cpp | 23 + Development/nmos/control_protocol_state.h | 36 + Development/nmos/control_protocol_ws_api.cpp | 493 ++++---- Development/nmos/control_protocol_ws_api.h | 7 +- Development/nmos/node_server.cpp | 2 +- Development/nmos/node_server.h | 7 +- 14 files changed, 1747 insertions(+), 1302 deletions(-) create mode 100644 Development/nmos/control_protocol_handlers.cpp create mode 100644 Development/nmos/control_protocol_handlers.h create mode 100644 Development/nmos/control_protocol_resource.cpp create mode 100644 Development/nmos/control_protocol_resource.h create mode 100644 Development/nmos/control_protocol_state.cpp create mode 100644 Development/nmos/control_protocol_state.h diff --git a/Development/cmake/NmosCppLibraries.cmake b/Development/cmake/NmosCppLibraries.cmake index 06206a740..cce8c420b 100644 --- a/Development/cmake/NmosCppLibraries.cmake +++ b/Development/cmake/NmosCppLibraries.cmake @@ -831,7 +831,10 @@ set(NMOS_CPP_NMOS_SOURCES nmos/connection_api.cpp nmos/connection_events_activation.cpp nmos/connection_resources.cpp + nmos/control_protocol_handlers.cpp + nmos/control_protocol_resource.cpp nmos/control_protocol_resources.cpp + nmos/control_protocol_state.cpp nmos/control_protocol_ws_api.cpp nmos/did_sdid.cpp nmos/events_api.cpp @@ -906,7 +909,10 @@ set(NMOS_CPP_NMOS_HEADERS nmos/connection_api.h nmos/connection_events_activation.h nmos/connection_resources.h + nmos/control_protocol_handlers.h + nmos/control_protocol_resource.h nmos/control_protocol_resources.h + nmos/control_protocol_state.h nmos/control_protocol_ws_api.h nmos/device_type.h nmos/did_sdid.h diff --git a/Development/nmos-cpp-node/main.cpp b/Development/nmos-cpp-node/main.cpp index d2b65923f..60b0cc56b 100644 --- a/Development/nmos-cpp-node/main.cpp +++ b/Development/nmos-cpp-node/main.cpp @@ -10,6 +10,8 @@ #include "nmos/server.h" #include "node_implementation.h" +#include "nmos/control_protocol_state.h" + int main(int argc, char* argv[]) { // Construct our data models including mutexes to protect them @@ -107,6 +109,9 @@ int main(int argc, char* argv[]) } #endif + nmos::experimental::control_protocol_state control_protocol_state; + node_implementation.on_get_control_classes(nmos::make_get_control_protocol_classes_handler(control_protocol_state, gate)); + // Set up the node server auto node_server = nmos::experimental::make_node_server(node_model, node_implementation, log_model, gate); diff --git a/Development/nmos/control_protocol_handlers.cpp b/Development/nmos/control_protocol_handlers.cpp new file mode 100644 index 000000000..3f1738c1e --- /dev/null +++ b/Development/nmos/control_protocol_handlers.cpp @@ -0,0 +1,64 @@ +#include "nmos/control_protocol_handlers.h" + +#include "cpprest/basic_utils.h" +#include "nmos/control_protocol_state.h" +#include "nmos/slog.h" + +namespace nmos +{ + get_control_protocol_classes_handler make_get_control_protocol_classes_handler(nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate) + { + return [&]() + { + slog::log(gate, SLOG_FLF) << "Retrieve all control classes from cache"; + + auto lock = control_protocol_state.read_lock(); + + return control_protocol_state.control_classes; + }; + } + + get_control_protocol_class_handler make_get_control_protocol_class_handler(nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate) + { + return [&](const details::nc_class_id& class_id) + { + using web::json::value; + + slog::log(gate, SLOG_FLF) << "Retrieve control class from cache"; + + auto lock = control_protocol_state.read_lock(); + + auto class_id_data = details::make_nc_class_id(class_id); + + auto& control_classes = control_protocol_state.control_classes; + auto found = control_classes.find(class_id_data); + if (control_classes.end() != found) + { + return found->second; + } + + return experimental::control_class{ value::array(), value::array(), value::array() }; + }; + } + + add_control_protocol_class_handler make_add_control_protocol_class_handler(nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate) + { + return [&](const details::nc_class_id& class_id, const experimental::control_class& control_class) + { + slog::log(gate, SLOG_FLF) << "Add control class to cache"; + + auto lock = control_protocol_state.write_lock(); + + auto class_id_data = details::make_nc_class_id(class_id); + + auto& control_classes = control_protocol_state.control_classes; + if (control_classes.end() == control_classes.find(class_id_data)) + { + return false; + } + + control_classes[class_id_data] = control_class; + return true; + }; + } +} diff --git a/Development/nmos/control_protocol_handlers.h b/Development/nmos/control_protocol_handlers.h new file mode 100644 index 000000000..1478235b4 --- /dev/null +++ b/Development/nmos/control_protocol_handlers.h @@ -0,0 +1,44 @@ +#ifndef NMOS_CONTROL_PROTOCOL_HANDLERS_H +#define NMOS_CONTROL_PROTOCOL_HANDLERS_H + +#include +#include +#include "nmos/control_protocol_resource.h" +#include "nmos/control_protocol_state.h" + +namespace slog +{ + class base_gate; +} + +namespace nmos +{ + namespace experimental + { + struct control_class; + struct control_protocol_state; + } + + // callback to retrieve all control protocol classes + // this callback should not throw exceptions + typedef std::function get_control_protocol_classes_handler; + + // callback to retrieve a specific control protocol class + // this callback should not throw exceptions + typedef std::function get_control_protocol_class_handler; + + // callback to add user control protocol class + // this callback should not throw exceptions + typedef std::function add_control_protocol_class_handler; + + // construct callback to retrieve all control protocol classes + get_control_protocol_classes_handler make_get_control_protocol_classes_handler(nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate); + + // construct callback to retrieve control protocol class + get_control_protocol_class_handler make_get_control_protocol_class_handler(nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate); + + // construct callback to add control protocol class + add_control_protocol_class_handler make_add_control_protocol_class_handler(nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate); +} + +#endif diff --git a/Development/nmos/control_protocol_resource.cpp b/Development/nmos/control_protocol_resource.cpp new file mode 100644 index 000000000..68f0273f4 --- /dev/null +++ b/Development/nmos/control_protocol_resource.cpp @@ -0,0 +1,1018 @@ +#include "nmos/control_protocol_resource.h" + +//#include "nmos/resource.h" +#include "nmos/json_fields.h" + +namespace nmos +{ + namespace details + { + web::json::value make_control_protocol_result(const nc_method_result& method_result) + { + using web::json::value_of; + + return value_of({ + { nmos::fields::nc::status, method_result.status } + }); + } + + web::json::value make_control_protocol_error_result(const nc_method_result& method_result, const utility::string_t& error_message) + { + auto result = make_control_protocol_result(method_result); + if (!error_message.empty()) { result[nmos::fields::nc::error_message] = web::json::value::string(error_message); } + return result; + } + + web::json::value make_control_protocol_result(const nc_method_result& method_result, const web::json::value& value) + { + auto result = make_control_protocol_result(method_result); + result[nmos::fields::nc::value] = value; + return result; + } + + web::json::value make_control_protocol_error_response(int32_t handle, const nc_method_result& method_result, const utility::string_t& error_message) + { + using web::json::value_of; + + return value_of({ + { nmos::fields::nc::handle, handle }, + { nmos::fields::nc::result, make_control_protocol_error_result(method_result, error_message) } + }); + } + + web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result) + { + using web::json::value_of; + + return value_of({ + { nmos::fields::nc::handle, handle }, + { nmos::fields::nc::result, make_control_protocol_result(method_result) } + }); + } + + web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result, const web::json::value& value) + { + using web::json::value_of; + + return value_of({ + { nmos::fields::nc::handle, handle }, + { nmos::fields::nc::result, make_control_protocol_result(method_result, value) } + }); + } + + // message response + // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#command-message-type + web::json::value make_control_protocol_message_response(nc_message_type::type type, const web::json::value& responses) + { + using web::json::value_of; + + return value_of({ + { nmos::fields::nc::message_type, type }, + { nmos::fields::nc::responses, responses } + }); + }; + + // error message + // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#error-messages + web::json::value make_control_protocol_error_message(const nc_method_result& method_result, const utility::string_t& error_message) + { + using web::json::value_of; + + return value_of({ + { nmos::fields::nc::message_type, nc_message_type::error }, + { nmos::fields::nc::status, method_result.status}, + { nmos::fields::nc::error_message, error_message } + }); + }; + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassid + web::json::value make_nc_class_id(const nc_class_id& class_id) + { + using web::json::value; + + auto nc_class_id = value::array(); + for (const auto class_id_item : class_id) { web::json::push_back(nc_class_id, class_id_item); } + return nc_class_id; + } + + nc_class_id parse_nc_class_id(const web::json::value& class_id_) + { + nc_class_id class_id; + for (auto& element : class_id_.as_array()) + { + class_id.push_back(element.as_integer()); + } + return class_id; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncelementid + web::json::value make_nc_element_id(uint16_t level, uint16_t index) + { + using web::json::value_of; + + return value_of({ + { nmos::fields::nc::level, level }, + { nmos::fields::nc::index, index } + }); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#nceventid + web::json::value make_nc_event_id(uint16_t level, uint16_t index) + { + return make_nc_element_id(level, index); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmethodid + web::json::value make_nc_method_id(uint16_t level, uint16_t index) + { + return make_nc_element_id(level, index); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncpropertyid + web::json::value make_nc_property_id(uint16_t level, uint16_t index) + { + return make_nc_element_id(level, index); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanufacturer + web::json::value make_nc_manufacturer(const utility::string_t& name, const web::json::value& organization_id, const web::json::value& website) + { + using web::json::value_of; + + return value_of({ + { nmos::fields::nc::name, name }, + { nmos::fields::nc::organization_id, organization_id }, + { nmos::fields::nc::website, website } + }); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncproduct + // brand_name can be null + // uuid can be null + // description can be null + web::json::value make_nc_product(const utility::string_t& name, const utility::string_t& key, const utility::string_t& revision_level, + const web::json::value& brand_name, const web::json::value& uuid, const web::json::value& description) + { + using web::json::value_of; + + return value_of({ + { nmos::fields::nc::name, name }, + { nmos::fields::nc::key, key }, + { nmos::fields::nc::revision_level, revision_level }, + { nmos::fields::nc::brand_name, brand_name }, + { nmos::fields::nc::uuid, uuid }, + { nmos::fields::nc::description, description } + }); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdeviceoperationalstate + // device_specific_details can be null + web::json::value make_nc_device_operational_state(nc_device_generic_state::state generic_state, const web::json::value& device_specific_details) + { + using web::json::value_of; + + return value_of({ + { nmos::fields::nc::generic_state, generic_state }, + { nmos::fields::nc::device_specific_details, device_specific_details } + }); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdescriptor + // description can be null + web::json::value make_nc_descriptor(const web::json::value& description) + { + using web::json::value_of; + + return value_of({ { nmos::fields::nc::description, description } }); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblockmemberdescriptor + // description can be null + // user_label can be null + web::json::value make_nc_block_member_descriptor(const web::json::value& description, const utility::string_t& role, nc_oid oid, bool constant_oid, const web::json::value& class_id, const web::json::value& user_label, nc_oid owner) + { + using web::json::value; + + auto data = make_nc_descriptor(description); + data[nmos::fields::nc::role] = value::string(role); + data[nmos::fields::nc::oid] = oid; + data[nmos::fields::nc::constant_oid] = value::boolean(constant_oid); + data[nmos::fields::nc::class_id] = class_id; + data[nmos::fields::nc::user_label] = user_label; + data[nmos::fields::nc::owner] = owner; + + return data; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassdescriptor + // description can be null + // fixedRole can be null + web::json::value make_nc_class_descriptor(const web::json::value& description, const nc_class_id& class_id, const utility::string_t& name, const web::json::value& fixed_role, const web::json::value& properties, const web::json::value& methods, const web::json::value& events) + { + using web::json::value; + + auto data = make_nc_descriptor(description); + data[nmos::fields::nc::class_id] = make_nc_class_id(class_id); + data[nmos::fields::nc::name] = value::string(name); + data[nmos::fields::nc::fixed_role] = fixed_role; + data[nmos::fields::nc::properties] = properties; + data[nmos::fields::nc::methods] = methods; + data[nmos::fields::nc::events] = events; + + return data; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncenumitemdescriptor + // description can be null + web::json::value make_nc_enum_item_descriptor(const web::json::value& description, const utility::string_t& name, uint16_t val) + { + using web::json::value; + + auto data = make_nc_descriptor(description); + data[nmos::fields::nc::name] = value::string(name); + data[nmos::fields::nc::value] = val; + + return data; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#nceventdescriptor + // description can be null + // id = make_nc_event_id(level, index) + web::json::value make_nc_event_descriptor(const web::json::value& description, const web::json::value& id, const utility::string_t& name, const utility::string_t& event_datatype, bool is_deprecated) + { + using web::json::value; + + auto data = make_nc_descriptor(description); + data[nmos::fields::nc::id] = id; + data[nmos::fields::nc::name] = value::string(name); + data[nmos::fields::nc::event_datatype] = value::string(event_datatype); + data[nmos::fields::nc::is_deprecated] = value::boolean(is_deprecated); + + return data; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncfielddescriptor + // description can be null + // type_name can be null + // constraints can be null + web::json::value make_nc_field_descriptor(const web::json::value& description, const utility::string_t& name, const web::json::value& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints) + { + using web::json::value; + + auto data = make_nc_descriptor(description); + data[nmos::fields::nc::name] = value::string(name); + data[nmos::fields::nc::type_name] = type_name; + data[nmos::fields::nc::is_nullable] = value::boolean(is_nullable); + data[nmos::fields::nc::is_sequence] = value::boolean(is_sequence); + data[nmos::fields::nc::constraints] = constraints; + + return data; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmethoddescriptor + // description can be null + // id = make_nc_method_id(level, index) + // sequence parameters + web::json::value make_nc_method_descriptor(const web::json::value& description, const web::json::value& id, const utility::string_t& name, const utility::string_t& result_datatype, const web::json::value& parameters, bool is_deprecated) + { + using web::json::value; + + auto data = make_nc_descriptor(description); + data[nmos::fields::nc::id] = id; + data[nmos::fields::nc::name] = value::string(name); + data[nmos::fields::nc::result_datatype] = value::string(result_datatype); + data[nmos::fields::nc::parameters] = parameters; + data[nmos::fields::nc::is_deprecated] = value::boolean(is_deprecated); + + return data; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncparameterdescriptor + // description can be null + // type_name can be null + web::json::value make_nc_parameter_descriptor(const web::json::value& description, const utility::string_t& name, const web::json::value& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints) + { + using web::json::value; + + auto data = make_nc_descriptor(description); + data[nmos::fields::nc::name] = value::string(name); + data[nmos::fields::nc::type_name] = type_name; + data[nmos::fields::nc::is_nullable] = value::boolean(is_nullable); + data[nmos::fields::nc::is_sequence] = value::boolean(is_sequence); + data[nmos::fields::nc::constraints] = constraints; + + return data; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncpropertydescriptor + // description can be null + // id = make_nc_property_id(level, index); + // type_name can be null + // constraints can be null + web::json::value make_nc_property_descriptor(const web::json::value& description, const web::json::value& id, const utility::string_t& name, const web::json::value& type_name, + bool is_read_only, bool is_nullable, bool is_sequence, bool is_deprecated, const web::json::value& constraints) + { + using web::json::value; + + auto data = make_nc_descriptor(description); + data[nmos::fields::nc::id] = id; + data[nmos::fields::nc::name] = value::string(name); + data[nmos::fields::nc::type_name] = type_name; + data[nmos::fields::nc::is_read_only] = value::boolean(is_read_only); + data[nmos::fields::nc::is_nullable] = value::boolean(is_nullable); + data[nmos::fields::nc::is_sequence] = value::boolean(is_sequence); + data[nmos::fields::nc::is_deprecated] = value::boolean(is_deprecated); + data[nmos::fields::nc::constraints] = constraints; + + return data; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptor + // description can be null + // constraints can be null + web::json::value make_nc_datatype_descriptor(const web::json::value& description, const utility::string_t& name, nc_datatype_type::type type, const web::json::value& constraints) + { + using web::json::value; + + auto data = make_nc_descriptor(description); + data[nmos::fields::nc::name] = value::string(name); + data[nmos::fields::nc::type] = type; + data[nmos::fields::nc::constraints] = constraints; + + return data; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptorenum + // description can be null + // constraints can be null + // items: sequence + web::json::value make_nc_datatype_descriptor_enum(const web::json::value& description, const utility::string_t& name, const web::json::value& constraints, const web::json::value& items) + { + auto data = make_nc_datatype_descriptor(description, name, nc_datatype_type::Enum, constraints); + data[nmos::fields::nc::items] = items; + + return data; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptorprimitive + // description can be null + // constraints can be null + web::json::value make_nc_datatype_descriptor_primitive(const web::json::value& description, const utility::string_t& name, const web::json::value& constraints) + { + return make_nc_datatype_descriptor(description, name, nc_datatype_type::Primitive, constraints); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptorstruct + // description can be null + // constraints can be null + // fields: sequence + // parent_type can be null + web::json::value make_nc_datatype_descriptor_struct(const web::json::value& description, const utility::string_t& name, const web::json::value& constraints, const web::json::value& fields, const web::json::value& parent_type) + { + auto data = make_nc_datatype_descriptor(description, name, nc_datatype_type::Struct, constraints); + data[nmos::fields::nc::fields] = fields; + data[nmos::fields::nc::parent_type] = parent_type; + + return data; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptortypedef + // description can be null + // constraints can be null + web::json::value make_nc_datatype_typedef(const web::json::value& description, const utility::string_t& name, const web::json::value& constraints, const utility::string_t& parent_type, bool is_sequence) + { + using web::json::value; + + auto data = make_nc_datatype_descriptor(description, name, nc_datatype_type::Typedef, constraints); + data[nmos::fields::nc::parent_type] = value::string(parent_type); + data[nmos::fields::nc::is_sequence] = value::boolean(is_sequence); + + return data; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject + web::json::value make_nc_object(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints) + { + using web::json::value; + + const auto id = utility::conversions::details::to_string_t(oid); +// auto data = make_resource_core(id, user_label.is_null() ? U("") : user_label.as_string(), {}); + value data; + data[nmos::fields::id] = value::string(id); // required for nmos::resource + data[nmos::fields::nc::class_id] = make_nc_class_id(class_id); + data[nmos::fields::nc::oid] = oid; + data[nmos::fields::nc::constant_oid] = value::boolean(constant_oid); + data[nmos::fields::nc::owner] = owner; + data[nmos::fields::nc::role] = value::string(role); + data[nmos::fields::nc::user_label] = user_label; + data[nmos::fields::nc::touchpoints] = touchpoints; + data[nmos::fields::nc::runtime_property_constraints] = runtime_property_constraints; + + return data; + }; + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock + web::json::value make_nc_block(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled, const web::json::value& members) + { + using web::json::value; + + auto data = details::make_nc_object(class_id, oid, constant_oid, owner, role, user_label, touchpoints, runtime_property_constraints); + data[nmos::fields::nc::enabled] = value::boolean(enabled); + data[nmos::fields::nc::members] = members; + + return data; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanager + web::json::value make_nc_manager(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints) + { + return make_nc_object(class_id, oid, constant_oid, owner, role, user_label, touchpoints, runtime_property_constraints); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager + web::json::value make_nc_device_manager(nc_oid oid, nc_oid owner, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, + const web::json::value& manufacturer, const web::json::value& product, const utility::string_t& serial_number, + const web::json::value& user_inventory_code, const web::json::value& device_name, const web::json::value& device_role, const web::json::value& operational_state, nc_reset_cause::cause reset_cause) + { + using web::json::value; + + auto data = details::make_nc_manager(nc_device_manager_class_id, oid, true, owner, U("DeviceManager"), user_label, touchpoints, runtime_property_constraints); + data[nmos::fields::nc::nc_version] = value::string(U("v1.0")); + data[nmos::fields::nc::manufacturer] = manufacturer; + data[nmos::fields::nc::product] = product; + data[nmos::fields::nc::serial_number] = value::string(serial_number); + data[nmos::fields::nc::user_inventory_code] = user_inventory_code; + data[nmos::fields::nc::device_name] = device_name; + data[nmos::fields::nc::device_role] = device_role; + data[nmos::fields::nc::operational_state] = operational_state; + data[nmos::fields::nc::reset_cause] = reset_cause; + data[nmos::fields::nc::message] = value::null(); + + return data; + } + + web::json::value make_nc_object_properties() + { + using web::json::value; + + auto properties = value::array(); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Static value. All instances of the same class will have the same identity value")), make_nc_property_id(1, 1), nmos::fields::nc::class_id, value::string(U("NcClassId")), true, false, false, false, value::null())); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Object identifier")), make_nc_property_id(1, 2), nmos::fields::nc::oid, value::string(U("NcOid")), true, false, false, false, value::null())); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("TRUE iff OID is hardwired into device")), make_nc_property_id(1, 3), nmos::fields::nc::constant_oid, value::string(U("NcBoolean")), true, false, false, false, value::null())); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("OID of containing block. Can only ever be null for the root block")), make_nc_property_id(1, 4), nmos::fields::nc::owner, value::string(U("NcOid")), true, true, false, false, value::null())); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Role of object in the containing block")), make_nc_property_id(1, 5), nmos::fields::nc::role, value::string(U("NcString")), true, false, false, false, value::null())); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Scribble strip")), make_nc_property_id(1, 6), nmos::fields::nc::user_label, value::string(U("NcString")), false, true, false, false, value::null())); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Touchpoints to other contexts")), make_nc_property_id(1, 7), nmos::fields::nc::touchpoints, value::string(U("NcTouchpoint")), true, true, true, false, value::null())); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Runtime property constraints")), make_nc_property_id(1, 8), nmos::fields::nc::runtime_property_constraints, value::string(U("NcPropertyConstraints")), true, true, true, false, value::null())); + + return properties; + } + + web::json::value make_nc_object_methods() + { + using web::json::value; + + auto methods = value::array(); + { + auto parameters = value::array(); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); + web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Get property value")), make_nc_method_id(1, 1), U("Get"), U("NcMethodResultPropertyValue"), parameters, false)); + } + { + auto parameters = value::array(); + web::json::push_back(parameters,make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); + web::json::push_back(parameters,make_nc_parameter_descriptor(value::string(U("Property value")), nmos::fields::nc::value, value::null(), true, false, value::null())); + web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Set property value")), make_nc_method_id(1, 2), U("Set"), U("NcMethodResult"), parameters, false)); + } + { + auto parameters = value::array(); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Index of item in the sequence")), nmos::fields::nc::index, value::string(U("NcId")), false, false, value::null())); + web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Get sequence item")), make_nc_method_id(1, 3), U("GetSequenceItem"), U("NcMethodResultPropertyValue"), parameters, false)); + } + { + auto parameters = value::array(); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Index of item in the sequence")), nmos::fields::nc::index, value::string(U("NcId")), false, false, value::null())); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Value")), nmos::fields::nc::value, value::null(), true, false, value::null())); + web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Set sequence item value")), make_nc_method_id(1, 4), U("SetSequenceItem"), U("NcMethodResult"), parameters, false)); + } + { + auto parameters = value::array(); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Value")), nmos::fields::nc::value, value::null(), true, false, value::null())); + web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Add item to sequence")), make_nc_method_id(1, 5), U("AddSequenceItem"), U("NcMethodResultId"), parameters, false)); + } + { + auto parameters = value::array(); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Index of item in the sequence")), nmos::fields::nc::index, value::string(U("NcId")), false, false, value::null())); + web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Delete sequence item")), make_nc_method_id(1, 6), U("RemoveSequenceItem"), U("NcMethodResult"), parameters, false)); + } + { + auto parameters = value::array(); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); + web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Get sequence length")), make_nc_method_id(1, 7), U("GetSequenceLength"), U("NcMethodResultLength"), parameters, false)); + } + + return methods; + } + + web::json::value make_nc_object_events() + { + using web::json::value; + + auto events = value::array(); + web::json::push_back(events, make_nc_event_descriptor(value::string(U("Property changed event")), make_nc_event_id(1, 1), U("PropertyChanged"), U("NcPropertyChangedEventData"), false)); + + return events; + } + + web::json::value make_nc_block_properties() + { + using web::json::value; + + auto properties = value::array(); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("TRUE if block is functional")), make_nc_property_id(2, 1), nmos::fields::nc::enabled, value::string(U("NcBoolean")), true, false, false, false, value::null())); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Descriptors of this block's members")), make_nc_property_id(2, 2), nmos::fields::nc::members, value::string(U("NcBlockMemberDescriptor")), true, false, true, false, value::null())); + + return properties; + } + + web::json::value make_nc_block_methods() + { + using web::json::value; + + auto methods = value::array(); + { + auto parameters = value::array(); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("If recurse is set to true, nested members can be retrieved")), nmos::fields::nc::recurse, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Gets descriptors of members of the block")), make_nc_method_id(2, 1), U("GetMemberDescriptors"), U("NcMethodResultBlockMemberDescriptors"), parameters, false)); + } + { + auto parameters = value::array(); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Relative path to search for (MUST not include the role of the block targeted by oid)")), nmos::fields::nc::path, value::string(U("NcRolePath")), false, false, value::null())); + web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Finds member(s) by path")), make_nc_method_id(2, 2), U("FindMembersByPath"), U("NcMethodResultBlockMemberDescriptors"), parameters, false)); + } + { + auto parameters = value::array(); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Role text to search for")), nmos::fields::nc::role, value::string(U("NcString")), false, false, value::null())); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Signals if the comparison should be case sensitive")), nmos::fields::nc::case_sensitive, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("TRUE to only return exact matches")), nmos::fields::nc::match_whole_string, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("TRUE to search nested blocks")), nmos::fields::nc::recurse, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Finds members with given role name or fragment")), make_nc_method_id(2, 3), U("FindMembersByRole"), U("NcMethodResultBlockMemberDescriptors"), parameters, false)); + } + { + auto parameters = value::array(); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Class id to search for")), nmos::fields::nc::class_id, value::string(U("NcClassId")), false, false, value::null())); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("If TRUE it will also include derived class descriptors")), nmos::fields::nc::include_derived, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("TRUE to search nested blocks")), nmos::fields::nc::recurse, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(methods, details::make_nc_method_descriptor(value::string(U("Finds members with given class id")), details::make_nc_method_id(2, 4), U("FindMembersByClassId"), U("NcMethodResultBlockMemberDescriptors"), parameters, false)); + } + + return methods; + } + + web::json::value make_nc_block_events() + { + using web::json::value; + + return value::array(); + } + + web::json::value make_nc_worker_properties() + { + using web::json::value; + + auto properties = value::array(); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("TRUE iff worker is enabled")), make_nc_property_id(2, 1), nmos::fields::nc::enabled, value::string(U("NcBoolean")), false, false, false, false, value::null())); + + return properties; + } + + web::json::value make_nc_worker_methods() + { + using web::json::value; + + return value::array(); + } + + web::json::value make_nc_worker_events() + { + using web::json::value; + + return value::array(); + } + + web::json::value make_nc_manager_properties() + { + using web::json::value; + + return value::array(); + } + + web::json::value make_nc_manager_methods() + { + using web::json::value; + + return value::array(); + } + + web::json::value make_nc_manager_events() + { + using web::json::value; + + return value::array(); + } + + web::json::value make_nc_device_manager_properties() + { + using web::json::value; + + auto properties = value::array(); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Version of MS-05-02 that this device uses")), make_nc_property_id(3, 1), nmos::fields::nc::nc_version, value::string(U("NcVersionCode")), true, false, false, false, value::null())); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Manufacturer descriptor")), make_nc_property_id(3, 2), nmos::fields::nc::manufacturer, value::string(U("NcManufacturer")), true, false, false, false, value::null())); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Product descriptor")), make_nc_property_id(3, 3), nmos::fields::nc::product, value::string(U("NcProduct")), true, false, false, false, value::null())); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Serial number")), make_nc_property_id(3, 4), nmos::fields::nc::serial_number, value::string(U("NcString")), true, false, false, false, value::null())); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Asset tracking identifier (user specified)")), make_nc_property_id(3, 5), nmos::fields::nc::user_inventory_code, value::string(U("NcString")), false, true, false, false, value::null())); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Name of this device in the application. Instance name, not product name")), make_nc_property_id(3, 6), nmos::fields::nc::device_name, value::string(U("NcString")), false, true, false, false, value::null())); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Role of this device in the application")), make_nc_property_id(3, 7), nmos::fields::nc::device_role, value::string(U("NcString")), false, true, false, false, value::null())); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Device operational state")), make_nc_property_id(3, 8), nmos::fields::nc::operational_state, value::string(U("NcDeviceOperationalState")), true, false, false, false, value::null())); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Reason for most recent reset")), make_nc_property_id(3, 9), nmos::fields::nc::reset_cause, value::string(U("NcResetCause")), true, false, false, false, value::null())); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Arbitrary message from dev to controller")), make_nc_property_id(3, 10), nmos::fields::nc::message, value::string(U("NcString")), true, true, false, false, value::null())); + + return properties; + } + + web::json::value make_nc_device_manager_methods() + { + using web::json::value; + + return value::array(); + } + + web::json::value make_nc_device_manager_events() + { + using web::json::value; + + return value::array(); + } + + web::json::value make_nc_class_manager_properties() + { + using web::json::value; + + auto properties = value::array(); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Descriptions of all control classes in the device (descriptors do not contain inherited elements)")), make_nc_property_id(3, 1), nmos::fields::nc::control_classes, value::string(U("NcClassDescriptor")), true, false, true, false, value::null())); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Descriptions of all data types in the device (descriptors do not contain inherited elements)")), make_nc_property_id(3, 2), nmos::fields::nc::datatypes, value::string(U("NcDatatypeDescriptor")), true, false, true, false, value::null())); + + return properties; + } + + web::json::value make_nc_class_manager_methods() + { + using web::json::value; + + auto methods = value::array(); + { + auto parameters = value::array(); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("class ID")), nmos::fields::nc::class_id, value::string(U("NcClassId")), false, false, value::null())); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("If set the descriptor would contain all inherited elements")), nmos::fields::nc::include_inherited, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Get a single class descriptor")), make_nc_method_id(3, 1), U("GetControlClass"), U("NcMethodResultClassDescriptor"), parameters, false)); + } + { + auto parameters = value::array(); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("name of datatype")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("If set the descriptor would contain all inherited elements")), nmos::fields::nc::include_inherited, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Get a single datatype descriptor")), make_nc_method_id(3, 2), U("GetDatatype"), U("NcMethodResultDatatypeDescriptor"), parameters, false)); + } + + return methods; + } + + web::json::value make_nc_class_manager_events() + { + using web::json::value; + + return value::array(); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager + web::json::value make_nc_class_manager(nc_oid oid, nc_oid owner, const web::json::value& user_label) + { + using web::json::value; + + auto data = make_nc_manager(nc_class_manager_class_id, oid, true, owner, U("ClassManager"), user_label); + + // load the minimal control classes + data[nmos::fields::nc::control_classes] = value::array(); + auto& control_classes = data[nmos::fields::nc::control_classes]; + + // NcObject control class + web::json::push_back(control_classes, details::make_nc_class_descriptor(value::string(U("NcObject class descriptor")), nc_object_class_id, U("NcObject"), value::null(), make_nc_object_properties(), make_nc_object_methods(), make_nc_object_events())); + // NcBlock control class + web::json::push_back(control_classes, details::make_nc_class_descriptor(value::string(U("NcBlock class descriptor")), nc_block_class_id, U("NcBlock"), value::null(), make_nc_block_properties(), make_nc_block_methods(), make_nc_block_events())); + // NcWorker control class + web::json::push_back(control_classes, details::make_nc_class_descriptor(value::string(U("NcWorker class descriptor")), nc_worker_class_id, U("NcWorker"), value::null(), make_nc_worker_properties(), make_nc_worker_methods(), make_nc_worker_events())); + // NcManager control class + web::json::push_back(control_classes, details::make_nc_class_descriptor(value::string(U("NcManager class descriptor")), nc_manager_class_id, U("NcManager"), value::null(), make_nc_manager_properties(), make_nc_manager_methods(), make_nc_manager_events())); + // NcDeviceManager control class + web::json::push_back(control_classes, details::make_nc_class_descriptor(value::string(U("NcDeviceManager class descriptor")), nc_device_manager_class_id, U("NcDeviceManager"), value::string(U("DeviceManager")), make_nc_device_manager_properties(), make_nc_device_manager_methods(), make_nc_device_manager_events())); + // NcClassManager control class + web::json::push_back(control_classes, details::make_nc_class_descriptor(value::string(U("NcClassManager class descriptor")), nc_class_manager_class_id, U("NcClassManager"), value::string(U("ClassManager")), make_nc_class_manager_properties(), make_nc_class_manager_methods(), make_nc_class_manager_events())); + + // load the minimal datatypes + data[nmos::fields::nc::datatypes] = value::array(); + auto& datatypes = data[nmos::fields::nc::datatypes]; + + // NcObject datatypes + // NcClassId + web::json::push_back(datatypes, details::make_nc_datatype_typedef(value::string(U("Sequence of class ID fields")), U("NcClassId"), value::null(), U("NcInt32"), true)); + // NcOid + web::json::push_back(datatypes, details::make_nc_datatype_typedef(value::string(U("Object id")), U("NcOid"), value::null(), U("NcUint32"), false)); + // NcTouchpoint + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Context namespace")), nmos::fields::nc::context_namespace, value::string(U("NcString")), false, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Base touchpoint class")), U("NcTouchpoint"), value::null(), fields, value::null())); + } + // NcElementId + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Level of the element")), nmos::fields::nc::level, value::string(U("NcUint16")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Index of the element")), nmos::fields::nc::index, value::string(U("NcUint16")), false, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Class element id which contains the level and index")), U("NcElementId"), value::null(), fields, value::null())); + } + // NcPropertyId + { + auto fields = value::array(); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Property id which contains the level and index")), U("NcPropertyId"), value::null(), fields, value::string(U("NcElementId")))); + } + // NcPropertyConstraints + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("The id of the property being constrained")), nmos::fields::nc::property_id, value::string(U("NcPropertyId")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional default value")), nmos::fields::nc::default_value, value::null(), true, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Property constraints class")), U("NcPropertyConstraints"), value::null(), fields, value::null())); + } + // NcMethodResultPropertyValue + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Getter method value for the associated property")), nmos::fields::nc::value, value::null(), true, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Result when invoking the getter method associated with a property")), U("NcMethodResultPropertyValue"), value::null(), fields, value::string(U("NcMethodResult")))); + } + // NcMethodStatus + { + auto items = value::array(); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method call was successful")), U("Ok"), 200)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method call was successful but targeted property is deprecated")), U("PropertyDeprecated"), 298)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method call was successful but method is deprecated")), U("MethodDeprecated"), 299)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Badly-formed command (e.g. the incoming command has invalid message encoding and cannot be parsed by the underlying protocol)")), U("BadCommandFormat"), 400)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Client is not authorized")), U("Unauthorized"), 401)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Command addresses a nonexistent object")), U("BadOid"), 404)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Attempt to change read-only state")), U("Readonly"), 405)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method call is invalid in current operating context (e.g. attempting to invoke a method when the object is disabled)")), U("InvalidRequest"), 406)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("There is a conflict with the current state of the device")), U("Conflict"), 409)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Something was too big")), U("BufferOverflow"), 413)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Index is outside the available range")), U("IndexOutOfBounds"), 414)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method parameter does not meet expectations (e.g. attempting to invoke a method with an invalid type for one of its parameters)")), U("ParameterError"), 417)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Addressed object is locked")), U("Locked"), 423)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Internal device error")), U("DeviceError"), 500)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Addressed method is not implemented by the addressed object")), U("MethodNotImplemented"), 501)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Addressed property is not implemented by the addressed object")), U("PropertyNotImplemented"), 502)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("The device is not ready to handle any commands")), U("NotReady"), 503)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method call did not finish within the allotted time")), U("Timeout"), 504)); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_enum(value::string(U("Method invokation status")), U("NcMethodStatus"), value::null(), items)); + } + // NcMethodResult + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Status for the invoked method")), nmos::fields::nc::status, value::string(U("NcMethodStatus")), false, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Base result of the invoked method")), U("NcMethodResult"), value::null(), fields, value::null())); + } + // NcId + web::json::push_back(datatypes, details::make_nc_datatype_typedef(value::string(U("Identity handler")), U("NcId"), value::null(), U("NcUint32"), false)); + // NcMethodResultId + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Id result value")), nmos::fields::nc::value, value::string(U("NcId")), false, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Id method result")), U("NcMethodResultId"), value::null(), fields, value::string(U("NcMethodResult")))); + } + // NcMethodResultLength + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Length result value")), nmos::fields::nc::value, value::string(U("NcUint32")), true, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Length method result")), U("NcMethodResultLength"), value::null(), fields, value::string(U("NcMethodResult")))); + } + // NcPropertyChangeType + { + auto items = value::array(); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Current value changed")), U("ValueChanged"), 0)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Sequence item added")), U("SequenceItemAdded"), 1)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Sequence item changed")), U("SequenceItemChanged"), 2)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Sequence item removed")), U("SequenceItemRemoved"), 3)); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_enum(value::string(U("Type of property change")), U("NcPropertyChangeType"), value::null(), items)); + } + // NcPropertyChangedEventData + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("The id of the property that changed")), nmos::fields::nc::property_id, value::string(U("NcPropertyId")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Information regarding the change type")), nmos::fields::nc::change_type, value::string(U("NcPropertyChangeType")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Property-type specific value")), nmos::fields::nc::value, value::null(), true, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Index of sequence item if the property is a sequence")), nmos::fields::nc::sequence_item_index, value::string(U("NcId")), true, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Payload of property-changed event")), U("NcPropertyChangedEventData"), value::null(), fields, value::null())); + } + + // NcBlock datatypes + // NcDescriptor + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional user facing description")), nmos::fields::nc::description, value::string(U("NcString")), true, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Base descriptor")), U("NcDescriptor"), value::null(), fields, value::null())); + } + // NcBlockMemberDescriptor + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Role of member in its containing block")), nmos::fields::nc::role, value::string(U("NcString")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("OID of member")), nmos::fields::nc::oid, value::string(U("NcOid")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff member's OID is hardwired into device")), nmos::fields::nc::constant_oid, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Class ID")), nmos::fields::nc::class_id, value::string(U("NcClassId")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("User label")), nmos::fields::nc::user_label, value::string(U("NcString")), true, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Containing block's OID")), nmos::fields::nc::owner, value::string(U("NcOid")), false, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor which is specific to a block member")), U("NcBlockMemberDescriptor"), value::null(), fields, value::string(U("NcDescriptor")))); + } + // NcMethodResultBlockMemberDescriptors + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Block member descriptors method result value")), nmos::fields::nc::value, value::string(U("NcBlockMemberDescriptor")), false, true, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Method result containing block member descriptors as the value")), U("NcMethodResultBlockMemberDescriptors"), value::null(), fields, value::string(U("NcMethodResult")))); + } + + // NcWorker has no datatypes + + // NcManager has no datatypes + + // NcDeviceManager datatypes + // NcVersionCode + web::json::push_back(datatypes, details::make_nc_datatype_typedef(value::string(U("Version code in semantic versioning format")), U("NcVersionCode"), value::null(), U("NcString"), false)); + // NcOrganizationId + web::json::push_back(datatypes, details::make_nc_datatype_typedef(value::string(U("Unique 24-bit organization id")), U("NcOrganizationId"), value::null(), U("NcInt32"), false)); + // NcUri + web::json::push_back(datatypes, details::make_nc_datatype_typedef(value::string(U("Uniform resource identifier")), U("NcUri"), value::null(), U("NcString"), false)); + // NcManufacturer + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Manufacturer's name")), nmos::fields::nc::name, value::string(U("NcString")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("IEEE OUI or CID of manufacturer")), nmos::fields::nc::organization_id, value::string(U("NcOrganizationId")), true, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("URL of the manufacturer's website")), nmos::fields::nc::website, value::string(U("NcUri")), true, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Manufacturer descriptor")), U("NcManufacturer"), value::null(), fields, value::null())); + } + // NcUuid + web::json::push_back(datatypes, details::make_nc_datatype_typedef(value::string(U("UUID")), U("NcUuid"), value::null(), U("NcString"), false)); + // NcProduct + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Product name")), nmos::fields::nc::name, value::string(U("NcString")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Manufacturer's unique key to product - model number, SKU, etc")), nmos::fields::nc::key, value::string(U("NcString")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Manufacturer's product revision level code")), nmos::fields::nc::revision_level, value::string(U("NcString")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Brand name under which product is sold")), nmos::fields::nc::brand_name, value::string(U("NcString")), true, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Unique UUID of product (not product instance)")), nmos::fields::nc::uuid, value::string(U("NcUuid")), true, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Text description of product")), nmos::fields::nc::description, value::string(U("NcString")), true, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Product descriptor")), U("NcProduct"), value::null(), fields, value::null())); + } + // NcDeviceGenericState + { + auto items = value::array(); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Unknown")), U("Unknown"), 0)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Normal operation")), U("NormalOperation"), 1)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Device is initializing")), U("Initializing"), 2)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Device is performing a software or firmware update")), U("Updating"), 3)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Device is experiencing a licensing error")), U("LicensingError"), 4)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Device is experiencing an internal error")), U("InternalError"), 5)); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_enum(value::string(U("Device generic operational state")), U("NcDeviceGenericState"), value::null(), items)); + } + // NcDeviceOperationalState + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Generic operational state")), nmos::fields::nc::generic_state, value::string(U("NcDeviceGenericState")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Specific device details")), nmos::fields::nc::device_specific_details, value::string(U("NcString")), true, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Device operational state")), U("NcDeviceOperationalState"), value::null(), fields, value::null())); + } + // NcResetCause + { + auto items = value::array(); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Unknown")), U("Unknown"), 0)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Power on")), U("PowerOn"), 1)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Internal error")), U("InternalError"), 2)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Upgrade")), U("Upgrade"), 3)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Controller request")), U("ControllerRequest"), 4)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Manual request from the front panel")), U("ManualReset"), 5)); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_enum(value::string(U("Reset cause enum")), U("NcResetCause"), value::null(), items)); + } + + // NcClassManager datatypes + // NcName + web::json::push_back(datatypes, details::make_nc_datatype_typedef(value::string(U("Programmatically significant name, alphanumerics + underscore, no spaces")), U("NcName"), value::null(), U("NcString"), false)); + // NcPropertyDescriptor + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Property id with level and index")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of property")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of property's datatype. Can only ever be null if the type is any")), nmos::fields::nc::type_name, value::string(U("NcName")), true, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is read-only")), nmos::fields::nc::is_read_only, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is nullable")), nmos::fields::nc::is_nullable, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is a sequence")), nmos::fields::nc::is_sequence, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is marked as deprecated")), nmos::fields::nc::is_deprecated, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional constraints on top of the underlying data type")), nmos::fields::nc::constraints, value::string(U("NcParameterConstraints")), true, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class property")), U("NcPropertyDescriptor"), value::null(), fields, value::string(U("NcDescriptor")))); + } + // NcMethodId + { + auto fields = value::array(); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Method id which contains the level and index")), U("NcMethodId"), value::null(), fields, value::string(U("NcElementId")))); + } + // NcParameterDescriptor + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of parameter")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of parameter's datatype. Can only ever be null if the type is any")), nmos::fields::nc::type_name, value::string(U("NcName")), true, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is nullable")), nmos::fields::nc::is_nullable, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is a sequence")), nmos::fields::nc::is_sequence, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional constraints on top of the underlying data type")), nmos::fields::nc::constraints, value::string(U("NcParameterConstraints")), true, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a method parameter")), U("NcParameterDescriptor"), value::null(), fields, value::string(U("NcDescriptor")))); + } + // NcMethodDescriptor + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Method id with level and index")), nmos::fields::nc::id, value::string(U("NcMethodId")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of method")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of method result's datatype")), nmos::fields::nc::result_datatype, value::string(U("NcName")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Parameter descriptors if any")), nmos::fields::nc::parameters, value::string(U("NcParameterDescriptor")), false, true, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is marked as deprecated")), nmos::fields::nc::is_deprecated, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class method")), U("NcMethodDescriptor"), value::null(), fields, value::string(U("NcDescriptor")))); + } + // NcEventId + { + auto fields = value::array(); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Event id which contains the level and index")), U("NcEventId"), value::null(), fields, value::string(U("NcElementId")))); + } + // NcEventDescriptor + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Event id with level and index")), nmos::fields::nc::id, value::string(U("NcEventId")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of event")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of event data's datatype")), nmos::fields::nc::event_datatype, value::string(U("NcName")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is marked as deprecated")), nmos::fields::nc::is_deprecated, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class event")), U("NcEventDescriptor"), value::null(), fields, value::string(U("NcDescriptor")))); + } + // NcClassDescriptor + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Identity of the class")), nmos::fields::nc::class_id, value::string(U("NcClassId")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of the class")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Role if the class has fixed role (manager classes)")), nmos::fields::nc::fixed_role, value::string(U("NcString")), true, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Property descriptors")), nmos::fields::nc::properties, value::string(U("NcPropertyDescriptor")), false, true, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Method descriptors")), nmos::fields::nc::methods, value::string(U("NcMethodDescriptor")), false, true, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Event descriptors")), nmos::fields::nc::events, value::string(U("NcEventDescriptor")), false, true, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class")), U("NcClassDescriptor"), value::null(), fields, value::string(U("NcDescriptor")))); + } + // NcParameterConstraints + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Default value")), nmos::fields::nc::default_value, value::null(), true, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Abstract parameter constraints class")), U("NcParameterConstraints"), value::null(), fields, value::null())); + } + // NcDatatypeType + { + auto items = value::array(); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Primitive datatype")), U("Primitive"), 0)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Simple alias of another datatype")), U("Typedef"), 1)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Data structure")), U("Struct"), 2)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Enum datatype")), U("Enum"), 3)); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_enum(value::string(U("Datatype type")), U("NcDatatypeType"), value::null(), items)); + } + // NcDatatypeDescriptor + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Datatype name")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Type: Primitive, Typedef, Struct, Enum")), nmos::fields::nc::type, value::string(U("NcDatatypeType")), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional constraints on top of the underlying data type")), nmos::fields::nc::constraints, value::string(U("NcParameterConstraints")), true, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Base datatype descriptor")), U("NcDatatypeDescriptor"), value::null(), fields, value::string(U("NcDescriptor")))); + } + // NcMethodResultClassDescriptor + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Class descriptor method result value")), nmos::fields::nc::value, value::string(U("NcClassDescriptor")), false, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Method result containing a class descriptor as the value")), U("NcMethodResultClassDescriptor"), value::null(), fields, value::string(U("NcMethodResult")))); + } + // NcMethodResultDatatypeDescriptor + { + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Datatype descriptor method result value")), nmos::fields::nc::value, value::string(U("NcDatatypeDescriptor")), false, false, value::null())); + web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Method result containing a datatype descriptor as the value")), U("NcMethodResultDatatypeDescriptor"), value::null(), fields, value::string(U("NcMethodResult")))); + } + + return data; + } + } +} diff --git a/Development/nmos/control_protocol_resource.h b/Development/nmos/control_protocol_resource.h new file mode 100644 index 000000000..bfecdd8e0 --- /dev/null +++ b/Development/nmos/control_protocol_resource.h @@ -0,0 +1,309 @@ +#ifndef NMOS_CONTROL_PROTOCOL_RESOURCE_H +#define NMOS_CONTROL_PROTOCOL_RESOURCE_H + +#include +#include "cpprest/json_utils.h" + +namespace web +{ + namespace json + { + class value; + } +} + +namespace nmos +{ + namespace details + { + namespace nc_message_type + { + enum type + { + command = 0, + command_response = 1, + notification = 2, + subscription = 3, + subscription_response = 4, + error = 5 + }; + } + + // Method invokation status + namespace nc_method_status + { + enum status + { + ok = 200, // Method call was successful + property_deprecated = 298, // Method call was successful but targeted property is deprecated + method_deprecated = 299, // Method call was successful but method is deprecated + bad_command_format = 400, // Badly-formed command + unathorized = 401, // Client is not authorized + bad_oid = 404, // Command addresses a nonexistent object + read_only = 405, // Attempt to change read-only state + invalid_request = 406, // Method call is invalid in current operating context + conflict = 409, // There is a conflict with the current state of the device + buffer_overflow = 413, // Something was too big + parameter_error = 417, // Method parameter does not meet expectations + locked = 423, // Addressed object is locked + device_error = 500, // Internal device error + method_not_implemented = 501, // Addressed method is not implemented by the addressed object + property_not_implemented = 502, // Addressed property is not implemented by the addressed object + not_ready = 503, // The device is not ready to handle any commands + timeout = 504, // Method call did not finish within the allotted time + property_version_error = 505 // Incompatible protocol version + }; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmethodresult + struct nc_method_result + { + nc_method_status::status status; + }; + + // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#command-response-message-type + web::json::value make_control_protocol_error_response(int32_t handle, const nc_method_result& method_result, const utility::string_t& error_message); + web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result); + web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result, const web::json::value& value); + + // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#command-message-type + web::json::value make_control_protocol_message_response(nc_message_type::type type, const web::json::value& responses); + // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#error-messages + web::json::value make_control_protocol_error_message(const nc_method_result& method_result, const utility::string_t& error_message); + + // Datatype type + namespace nc_datatype_type + { + enum type + { + Primitive = 0, + Typedef = 1, + Struct = 2, + Enum = 3 + }; + } + + // Device generic operational state + namespace nc_device_generic_state + { + enum state + { + Unknown = 0, // Unknown + NormalOperation = 1, // Normal operation + Initializing = 2, // Device is initializing + Updating = 3, // Device is performing a software or firmware update + LicensingError = 4, // Device is experiencing a licensing error + InternalError = 5 // Device is experiencing an internal error + }; + } + + // Reset cause enum + namespace nc_reset_cause + { + enum cause + { + Unknown = 0, // 0 Unknown + Power_on = 1, // 1 Power on + InternalError = 2, // 2 Internal error + Upgrade = 3, // 3 Upgrade + Controller_request = 4, // 4 Controller request + ManualReset = 5 // 5 Manual request from the front panel + }; + } + + // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncid + typedef uint32_t nc_id; + + // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncoid + typedef uint32_t nc_oid; + + // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncuri + typedef utility::string_t nc_uri; + + // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncuuid + typedef utility::string_t nc_uuid; + + // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassid + typedef std::vector nc_class_id; + const nc_class_id nc_object_class_id({ 1 }); + const nc_class_id nc_block_class_id({ 1, 1 }); + const nc_class_id nc_worker_class_id({ 1, 2 }); + const nc_class_id nc_manager_class_id({ 1, 3 }); + const nc_class_id nc_device_manager_class_id({ 1, 3, 1 }); + const nc_class_id nc_class_manager_class_id({ 1, 3, 2 }); + + // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#nctouchpoint + typedef utility::string_t nc_touch_point; + + typedef std::map properties; + +// typedef std::function method; +// typedef std::map methods; // method_id vs method handler + + typedef std::function method; + typedef std::map methods; // method_id vs method handler + + web::json::value make_control_protocol_result(const nc_method_result& method_result); + web::json::value make_control_protocol_error_result(const nc_method_result& method_result, const utility::string_t& error_message); + + web::json::value make_control_protocol_result(const nc_method_result& method_result, const web::json::value& value); + web::json::value make_control_protocol_error_response(int32_t handle, const nc_method_result& method_result, const utility::string_t& error_message); + + web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result); + + web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result, const web::json::value& value); + + // message response + // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#command-message-type + web::json::value make_control_protocol_message_response(nc_message_type::type type, const web::json::value& responses); + + // error message + // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#error-messages + web::json::value make_control_protocol_error_message(const nc_method_result& method_result, const utility::string_t& error_message); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassid + web::json::value make_nc_class_id(const nc_class_id& class_id); + nc_class_id parse_nc_class_id(const web::json::value& class_id); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncelementid + web::json::value make_nc_element_id(uint16_t level, uint16_t index); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#nceventid + web::json::value make_nc_event_id(uint16_t level, uint16_t index); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmethodid + web::json::value make_nc_method_id(uint16_t level, uint16_t index); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncpropertyid + web::json::value make_nc_property_id(uint16_t level, uint16_t index); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanufacturer + web::json::value make_nc_manufacturer(const utility::string_t& name, const web::json::value& organization_id = web::json::value::null(), const web::json::value& website = web::json::value::null()); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncproduct + // brand_name can be null + // uuid can be null + // description can be null + web::json::value make_nc_product(const utility::string_t& name, const utility::string_t& key, const utility::string_t& revision_level, + const web::json::value& brand_name = web::json::value::null(), const web::json::value& uuid = web::json::value::null(), const web::json::value& description = web::json::value::null()); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdeviceoperationalstate + // device_specific_details can be null + web::json::value make_nc_device_operational_state(nc_device_generic_state::state generic_state, const web::json::value& device_specific_details); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdescriptor + // description can be null + web::json::value make_nc_descriptor(const web::json::value& description); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblockmemberdescriptor + // description can be null + // user_label can be null + web::json::value make_nc_block_member_descriptor(const web::json::value& description, const utility::string_t& role, nc_oid oid, bool constant_oid, const web::json::value& class_id, const web::json::value& user_label, nc_oid owner); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassdescriptor + // description can be null + // fixedRole can be null + web::json::value make_nc_class_descriptor(const web::json::value& description, const web::json::value& class_id, const utility::string_t& name, const web::json::value& fixed_role, const web::json::value& properties, const web::json::value& methods, const web::json::value& events); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncenumitemdescriptor + // description can be null + web::json::value make_nc_enum_item_descriptor(const web::json::value& description, const utility::string_t& name, uint16_t val); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#nceventdescriptor + // description can be null + // id = make_nc_event_id(level, index) + web::json::value make_nc_event_descriptor(const web::json::value& description, const web::json::value& id, const utility::string_t& name, const utility::string_t& event_datatype, bool is_deprecated); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncfielddescriptor + // description can be null + // type_name can be null + // constraints can be null + web::json::value make_nc_field_descriptor(const web::json::value& description, const utility::string_t& name, const web::json::value& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmethoddescriptor + // description can be null + // id = make_nc_method_id(level, index) + // sequence parameters + web::json::value make_nc_method_descriptor(const web::json::value& description, const web::json::value& id, const utility::string_t& name, const utility::string_t& result_datatype, const web::json::value& parameters, bool is_deprecated); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncparameterdescriptor + // description can be null + // type_name can be null + web::json::value make_nc_parameter_descriptor(const web::json::value& description, const utility::string_t& name, const web::json::value& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncpropertydescriptor + // description can be null + // id = make_nc_property_id(level, index); + // type_name can be null + // constraints can be null + web::json::value make_nc_property_descriptor(const web::json::value& description, const web::json::value& id, const utility::string_t& name, const web::json::value& type_name, + bool is_read_only, bool is_nullable, bool is_sequence, bool is_deprecated, const web::json::value& constraints); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptor + // description can be null + // constraints can be null + web::json::value make_nc_datatype_descriptor(const web::json::value& description, const utility::string_t& name, nc_datatype_type::type type, const web::json::value& constraints); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptorenum + // description can be null + // constraints can be null + // items: sequence + web::json::value make_nc_datatype_descriptor_enum(const web::json::value& description, const utility::string_t& name, const web::json::value& constraints, const web::json::value& items); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptorprimitive + // description can be null + // constraints can be null + web::json::value make_nc_datatype_descriptor_primitive(const web::json::value& description, const utility::string_t& name, const web::json::value& constraints); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptorstruct + // description can be null + // constraints can be null + // fields: sequence + // parent_type can be null + web::json::value make_nc_datatype_descriptor_struct(const web::json::value& description, const utility::string_t& name, const web::json::value& constraints, const web::json::value& fields, const web::json::value& parent_type); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptortypedef + // description can be null + // constraints can be null + web::json::value make_nc_datatype_typedef(const web::json::value& description, const utility::string_t& name, const web::json::value& constraints, const utility::string_t& parent_type, bool is_sequence); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject + web::json::value make_nc_object(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock + web::json::value make_nc_block(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled, const web::json::value& members); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanager + web::json::value make_nc_manager(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null()); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager + web::json::value make_nc_device_manager(nc_oid oid, nc_oid owner, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, + const web::json::value& manufacturer, const web::json::value& product, const utility::string_t& serial_number, + const web::json::value& user_inventory_code, const web::json::value& device_name, const web::json::value& device_role, const web::json::value& operational_state, nc_reset_cause::cause reset_cause); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager + web::json::value make_nc_class_manager(details::nc_oid oid, nc_oid owner, const web::json::value& user_label); + + // make the core classes proprties/methods/events + web::json::value make_nc_object_properties(); + web::json::value make_nc_object_methods(); + web::json::value make_nc_object_events(); + web::json::value make_nc_block_properties(); + web::json::value make_nc_block_methods(); + web::json::value make_nc_block_events(); + web::json::value make_nc_worker_properties(); + web::json::value make_nc_worker_methods(); + web::json::value make_nc_worker_events(); + web::json::value make_nc_manager_properties(); + web::json::value make_nc_manager_methods(); + web::json::value make_nc_manager_events(); + web::json::value make_nc_device_manager_properties(); + web::json::value make_nc_device_manager_methods(); + web::json::value make_nc_device_manager_events(); + web::json::value make_nc_class_manager_properties(); + web::json::value make_nc_class_manager_methods(); + web::json::value make_nc_class_manager_events(); + } +} + +#endif diff --git a/Development/nmos/control_protocol_resources.cpp b/Development/nmos/control_protocol_resources.cpp index 1fa4316b8..f5e2754b4 100644 --- a/Development/nmos/control_protocol_resources.cpp +++ b/Development/nmos/control_protocol_resources.cpp @@ -1,908 +1,11 @@ #include "nmos/control_protocol_resources.h" +#include "nmos/control_protocol_resource.h" #include "nmos/resource.h" #include "nmos/is12_versions.h" namespace nmos { - namespace details - { - web::json::value make_control_protocol_result(const nc_method_result& method_result) - { - using web::json::value_of; - - return value_of({ - { nmos::fields::nc::status, method_result.status } - }); - } - - web::json::value make_control_protocol_error_result(const nc_method_result& method_result, const utility::string_t& error_message) - { - auto result = make_control_protocol_result(method_result); - if (!error_message.empty()) { result[nmos::fields::nc::error_message] = web::json::value::string(error_message); } - return result; - } - - web::json::value make_control_protocol_result(const nc_method_result& method_result, const web::json::value& value) - { - auto result = make_control_protocol_result(method_result); - result[nmos::fields::nc::value] = value; - return result; - } - - web::json::value make_control_protocol_error_response(int32_t handle, const nc_method_result& method_result, const utility::string_t& error_message) - { - using web::json::value_of; - - return value_of({ - { nmos::fields::nc::handle, handle }, - { nmos::fields::nc::result, make_control_protocol_error_result(method_result, error_message) } - }, true); - } - - web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result) - { - using web::json::value_of; - - return value_of({ - { nmos::fields::nc::handle, handle }, - { nmos::fields::nc::result, make_control_protocol_result(method_result) } - }, true); - } - - web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result, const web::json::value& value) - { - using web::json::value_of; - - return value_of({ - { nmos::fields::nc::handle, handle }, - { nmos::fields::nc::result, make_control_protocol_result(method_result, value) } - }, true); - } - - // message response - // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#command-message-type - web::json::value make_control_protocol_message_response(nc_message_type::type type, const web::json::value& responses) - { - using web::json::value_of; - - return value_of({ - { nmos::fields::nc::message_type, type }, - { nmos::fields::nc::responses, responses } - }, true); - }; - - // error message - // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#error-messages - web::json::value make_control_protocol_error_message(const nc_method_result& method_result, const utility::string_t& error_message) - { - using web::json::value_of; - - return value_of({ - { nmos::fields::nc::message_type, nc_message_type::error }, - { nmos::fields::nc::status, method_result.status}, - { nmos::fields::nc::error_message, error_message } - }, true); - }; - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassid - web::json::value make_nc_class_id(const nc_class_id& class_id) - { - using web::json::value; - - auto nc_class_id = value::array(); - for (const auto class_id_item : class_id) { web::json::push_back(nc_class_id, class_id_item); } - return nc_class_id; - } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncelementid - web::json::value make_nc_element_id(uint16_t level, uint16_t index) - { - using web::json::value_of; - - return value_of({ - { nmos::fields::nc::level, level }, - { nmos::fields::nc::index, index } - }); - } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#nceventid - web::json::value make_nc_event_id(uint16_t level, uint16_t index) - { - return make_nc_element_id(level, index); - } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmethodid - web::json::value make_nc_method_id(uint16_t level, uint16_t index) - { - return make_nc_element_id(level, index); - } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncpropertyid - web::json::value make_nc_property_id(uint16_t level, uint16_t index) - { - return make_nc_element_id(level, index); - } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanufacturer - web::json::value make_nc_manufacturer(const utility::string_t& name, const web::json::value& organization_id = web::json::value::null(), const web::json::value& website = web::json::value::null()) - { - using web::json::value_of; - - return value_of({ - { nmos::fields::nc::name, name }, - { nmos::fields::nc::organization_id, organization_id }, - { nmos::fields::nc::website, website } - }, true); - } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncproduct - // brand_name can be null - // uuid can be null - // description can be null - web::json::value make_nc_product(const utility::string_t& name, const utility::string_t& key, const utility::string_t& revision_level, - const web::json::value& brand_name = web::json::value::null(), const web::json::value& uuid = web::json::value::null(), const web::json::value& description = web::json::value::null()) - { - using web::json::value_of; - - return value_of({ - { nmos::fields::nc::name, name }, - { nmos::fields::nc::key, key }, - { nmos::fields::nc::revision_level, revision_level }, - { nmos::fields::nc::brand_name, brand_name }, - { nmos::fields::nc::uuid, uuid }, - { nmos::fields::nc::description, description } - }, true); - } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdeviceoperationalstate - // device_specific_details can be null - web::json::value make_nc_device_operational_state(nc_device_generic_state::state generic_state, const web::json::value& device_specific_details) - { - using web::json::value_of; - - return value_of({ - { nmos::fields::nc::generic_state, generic_state }, - { nmos::fields::nc::device_specific_details, device_specific_details } - }, true); - } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdescriptor - // description can be null - web::json::value make_nc_descriptor(const web::json::value& description) - { - using web::json::value_of; - - return value_of({ { nmos::fields::nc::description, description } }); - } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblockmemberdescriptor - // description can be null - // user_label can be null - web::json::value make_nc_block_member_descriptor(const web::json::value& description, const utility::string_t& role, nc_oid oid, bool constant_oid, const web::json::value& class_id, const web::json::value& user_label, nc_oid owner) - { - using web::json::value; - - auto data = make_nc_descriptor(description); - data[nmos::fields::nc::role] = value::string(role); - data[nmos::fields::nc::oid] = oid; - data[nmos::fields::nc::constant_oid] = value::boolean(constant_oid); - data[nmos::fields::nc::class_id] = class_id; - data[nmos::fields::nc::user_label] = user_label; - data[nmos::fields::nc::owner] = owner; - - return data; - } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassdescriptor - // description can be null - // fixedRole can be null - web::json::value make_nc_class_descriptor(const web::json::value& description, const web::json::value& class_id, const utility::string_t& name, const web::json::value& fixed_role, const web::json::value& properties, const web::json::value& methods, const web::json::value& events) - { - using web::json::value; - - auto data = make_nc_descriptor(description); - data[nmos::fields::nc::class_id] = class_id; - data[nmos::fields::nc::name] = value::string(name); - data[nmos::fields::nc::fixed_role] = fixed_role; - data[nmos::fields::nc::properties] = properties; - data[nmos::fields::nc::methods] = methods; - data[nmos::fields::nc::events] = events; - - return data; - } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncenumitemdescriptor - // description can be null - web::json::value make_nc_enum_item_descriptor(const web::json::value& description, const utility::string_t& name, uint16_t val) - { - using web::json::value; - - auto data = make_nc_descriptor(description); - data[nmos::fields::nc::name] = value::string(name); - data[nmos::fields::nc::value] = val; - - return data; - } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#nceventdescriptor - // description can be null - // id = make_nc_event_id(level, index) - web::json::value make_nc_event_descriptor(const web::json::value& description, const web::json::value& id, const utility::string_t& name, const utility::string_t& event_datatype, bool is_deprecated) - { - using web::json::value; - - auto data = make_nc_descriptor(description); - data[nmos::fields::nc::id] = id; - data[nmos::fields::nc::name] = value::string(name); - data[nmos::fields::nc::event_datatype] = value::string(event_datatype); - data[nmos::fields::nc::is_deprecated] = value::boolean(is_deprecated); - - return data; - } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncfielddescriptor - // description can be null - // type_name can be null - // constraints can be null - web::json::value make_nc_field_descriptor(const web::json::value& description, const utility::string_t& name, const web::json::value& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints) - { - using web::json::value; - - auto data = make_nc_descriptor(description); - data[nmos::fields::nc::name] = value::string(name); - data[nmos::fields::nc::type_name] = type_name; - data[nmos::fields::nc::is_nullable] = value::boolean(is_nullable); - data[nmos::fields::nc::is_sequence] = value::boolean(is_sequence); - data[nmos::fields::nc::constraints] = constraints; - - return data; - } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmethoddescriptor - // description can be null - // id = make_nc_method_id(level, index) - // sequence parameters - web::json::value make_nc_method_descriptor(const web::json::value& description, const web::json::value& id, const utility::string_t& name, const utility::string_t& result_datatype, const web::json::value& parameters, bool is_deprecated) - { - using web::json::value; - - auto data = make_nc_descriptor(description); - data[nmos::fields::nc::id] = id; - data[nmos::fields::nc::name] = value::string(name); - data[nmos::fields::nc::result_datatype] = value::string(result_datatype); - data[nmos::fields::nc::parameters] = parameters; - data[nmos::fields::nc::is_deprecated] = value::boolean(is_deprecated); - - return data; - } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncparameterdescriptor - // description can be null - // type_name can be null - web::json::value make_nc_parameter_descriptor(const web::json::value& description, const utility::string_t& name, const web::json::value& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints) - { - using web::json::value; - - auto data = make_nc_descriptor(description); - data[nmos::fields::nc::name] = value::string(name); - data[nmos::fields::nc::type_name] = type_name; - data[nmos::fields::nc::is_nullable] = value::boolean(is_nullable); - data[nmos::fields::nc::is_sequence] = value::boolean(is_sequence); - data[nmos::fields::nc::constraints] = constraints; - - return data; - } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncpropertydescriptor - // description can be null - // id = make_nc_property_id(level, index); - // type_name can be null - // constraints can be null - web::json::value make_nc_property_descriptor(const web::json::value& description, const web::json::value& id, const utility::string_t& name, const web::json::value& type_name, - bool is_read_only, bool is_nullable, bool is_sequence, bool is_deprecated, const web::json::value& constraints) - { - using web::json::value; - - auto data = make_nc_descriptor(description); - data[nmos::fields::nc::id] = id; - data[nmos::fields::nc::name] = value::string(name); - data[nmos::fields::nc::type_name] = type_name; - data[nmos::fields::nc::is_read_only] = value::boolean(is_read_only); - data[nmos::fields::nc::is_nullable] = value::boolean(is_nullable); - data[nmos::fields::nc::is_sequence] = value::boolean(is_sequence); - data[nmos::fields::nc::is_deprecated] = value::boolean(is_deprecated); - data[nmos::fields::nc::constraints] = constraints; - - return data; - } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptor - // description can be null - // constraints can be null - web::json::value make_nc_datatype_descriptor(const web::json::value& description, const utility::string_t& name, nc_datatype_type::type type, const web::json::value& constraints) - { - using web::json::value; - - auto data = make_nc_descriptor(description); - data[nmos::fields::nc::name] = value::string(name); - data[nmos::fields::nc::type] = type; - data[nmos::fields::nc::constraints] = constraints; - - return data; - } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptorenum - // description can be null - // constraints can be null - // items: sequence - web::json::value make_nc_datatype_descriptor_enum(const web::json::value& description, const utility::string_t& name, const web::json::value& constraints, const web::json::value& items) - { - auto data = make_nc_datatype_descriptor(description, name, nc_datatype_type::Enum, constraints); - data[nmos::fields::nc::items] = items; - - return data; - } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptorprimitive - // description can be null - // constraints can be null - web::json::value make_nc_datatype_descriptor_primitive(const web::json::value& description, const utility::string_t& name, const web::json::value& constraints) - { - return make_nc_datatype_descriptor(description, name, nc_datatype_type::Primitive, constraints); - } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptorstruct - // description can be null - // constraints can be null - // fields: sequence - // parent_type can be null - web::json::value make_nc_datatype_descriptor_struct(const web::json::value& description, const utility::string_t& name, const web::json::value& constraints, const web::json::value& fields, const web::json::value& parent_type) - { - auto data = make_nc_datatype_descriptor(description, name, nc_datatype_type::Struct, constraints); - data[nmos::fields::nc::fields] = fields; - data[nmos::fields::nc::parent_type] = parent_type; - - return data; - } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptortypedef - // description can be null - // constraints can be null - web::json::value make_nc_datatype_typedef(const web::json::value& description, const utility::string_t& name, const web::json::value& constraints, const utility::string_t& parent_type, bool is_sequence) - { - using web::json::value; - - auto data = make_nc_datatype_descriptor(description, name, nc_datatype_type::Typedef, constraints); - data[nmos::fields::nc::parent_type] = value::string(parent_type); - data[nmos::fields::nc::is_sequence] = value::boolean(is_sequence); - - return data; - } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject - web::json::value make_nc_object(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints) - { - using web::json::value; - - const auto id = utility::conversions::details::to_string_t(oid); - auto data = make_resource_core(id, user_label.is_null() ? U("") : user_label.as_string(), {}); - data[nmos::fields::nc::class_id] = make_nc_class_id(class_id); - data[nmos::fields::nc::oid] = oid; - data[nmos::fields::nc::constant_oid] = value::boolean(constant_oid); - data[nmos::fields::nc::owner] = owner; - data[nmos::fields::nc::role] = value::string(role); - data[nmos::fields::nc::user_label] = user_label; - data[nmos::fields::nc::touchpoints] = touchpoints; - data[nmos::fields::nc::runtime_property_constraints] = runtime_property_constraints; - - return data; - }; - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock - web::json::value make_nc_block(nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled, const web::json::value& members) - { - using web::json::value; - - auto data = details::make_nc_object({ 1, 1 }, oid, constant_oid, owner, role, user_label, touchpoints, runtime_property_constraints); - data[nmos::fields::nc::enabled] = value::boolean(enabled); - data[nmos::fields::nc::members] = members; - - return data; - } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanager - web::json::value make_nc_manager(nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null()) - { - return make_nc_object({ 1, 3 }, oid, constant_oid, owner, role, user_label, touchpoints, runtime_property_constraints); - } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager - web::json::value make_nc_device_manager(nc_oid oid, nc_oid owner, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, - const web::json::value& manufacturer, const web::json::value& product, const utility::string_t& serial_number, - const web::json::value& user_inventory_code, const web::json::value& device_name, const web::json::value& device_role, const web::json::value& operational_state, nc_reset_cause::cause reset_cause) - { - using web::json::value; - - auto data = details::make_nc_manager(oid, true, owner, U("DeviceManager"), user_label, touchpoints, runtime_property_constraints); - data[nmos::fields::nc::class_id] = details::make_nc_class_id({ 1, 3, 1 }); - data[nmos::fields::nc::nc_version] = value::string(U("v1.0")); - data[nmos::fields::nc::manufacturer] = manufacturer; - data[nmos::fields::nc::product] = product; - data[nmos::fields::nc::serial_number] = value::string(serial_number); - data[nmos::fields::nc::user_inventory_code] = user_inventory_code; - data[nmos::fields::nc::device_name] = device_name; - data[nmos::fields::nc::device_role] = device_role; - data[nmos::fields::nc::operational_state] = operational_state; - data[nmos::fields::nc::reset_cause] = reset_cause; - data[nmos::fields::nc::message] = value::null(); - - return data; - } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager - web::json::value make_nc_class_manager(details::nc_oid oid, nc_oid owner, const web::json::value& user_label) - { - using web::json::value; - - auto data = details::make_nc_manager(oid, true, owner, U("ClassManager"), user_label); - data[nmos::fields::nc::class_id] = details::make_nc_class_id({ 1, 3, 2 }); - - // load the minimal control classes - data[nmos::fields::nc::control_classes] = value::array(); - auto& control_classes = data[nmos::fields::nc::control_classes]; - - // NcObject control class - { - auto properties = value::array(); - web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Static value. All instances of the same class will have the same identity value")), details::make_nc_property_id(1, 1), nmos::fields::nc::class_id, value::string(U("NcClassId")), true, false, false, false, value::null())); - web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Object identifier")), details::make_nc_property_id(1, 2), nmos::fields::nc::oid, value::string(U("NcOid")), true, false, false, false, value::null())); - web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("TRUE iff OID is hardwired into device")), details::make_nc_property_id(1, 3), nmos::fields::nc::constant_oid, value::string(U("NcBoolean")), true, false, false, false, value::null())); - web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("OID of containing block. Can only ever be null for the root block")), details::make_nc_property_id(1, 4), nmos::fields::nc::owner, value::string(U("NcOid")), true, true, false, false, value::null())); - web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Role of object in the containing block")), details::make_nc_property_id(1, 5), nmos::fields::nc::role, value::string(U("NcString")), true, false, false, false, value::null())); - web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Scribble strip")), details::make_nc_property_id(1, 6), nmos::fields::nc::user_label, value::string(U("NcString")), false, true, false, false, value::null())); - web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Touchpoints to other contexts")), details::make_nc_property_id(1, 7), nmos::fields::nc::touchpoints, value::string(U("NcTouchpoint")), true, true, true, false, value::null())); - web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Runtime property constraints")), details::make_nc_property_id(1, 8), nmos::fields::nc::runtime_property_constraints, value::string(U("NcPropertyConstraints")), true, true, true, false, value::null())); - auto methods = value::array(); - { - auto parameters = value::array(); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); - web::json::push_back(methods, details::make_nc_method_descriptor(value::string(U("Get property value")), details::make_nc_method_id(1, 1), U("Get"), U("NcMethodResultPropertyValue"), parameters, false)); - } - { - auto parameters = value::array(); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Property value")), nmos::fields::nc::value, value::null(), true, false, value::null())); - web::json::push_back(methods, details::make_nc_method_descriptor(value::string(U("Set property value")), details::make_nc_method_id(1, 2), U("Set"), U("NcMethodResult"), parameters, false)); - } - { - auto parameters = value::array(); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Index of item in the sequence")), nmos::fields::nc::index, value::string(U("NcId")), false, false, value::null())); - web::json::push_back(methods, details::make_nc_method_descriptor(value::string(U("Get sequence item")), details::make_nc_method_id(1, 3), U("GetSequenceItem"), U("NcMethodResultPropertyValue"), parameters, false)); - } - { - auto parameters = value::array(); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Index of item in the sequence")), nmos::fields::nc::index, value::string(U("NcId")), false, false, value::null())); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Value")), nmos::fields::nc::value, value::null(), true, false, value::null())); - web::json::push_back(methods, details::make_nc_method_descriptor(value::string(U("Set sequence item value")), details::make_nc_method_id(1, 4), U("SetSequenceItem"), U("NcMethodResult"), parameters, false)); - } - { - auto parameters = value::array(); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Value")), nmos::fields::nc::value, value::null(), true, false, value::null())); - web::json::push_back(methods, details::make_nc_method_descriptor(value::string(U("Add item to sequence")), details::make_nc_method_id(1, 5), U("AddSequenceItem"), U("NcMethodResultId"), parameters, false)); - } - { - auto parameters = value::array(); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Index of item in the sequence")), nmos::fields::nc::index, value::string(U("NcId")), false, false, value::null())); - web::json::push_back(methods, details::make_nc_method_descriptor(value::string(U("Delete sequence item")), details::make_nc_method_id(1, 6), U("RemoveSequenceItem"), U("NcMethodResult"), parameters, false)); - } - { - auto parameters = value::array(); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); - web::json::push_back(methods, details::make_nc_method_descriptor(value::string(U("Get sequence length")), details::make_nc_method_id(1, 7), U("GetSequenceLength"), U("NcMethodResultLength"), parameters, false)); - } - auto events = value::array(); - web::json::push_back(events, details::make_nc_event_descriptor(value::string(U("Property changed event")), details::make_nc_event_id(1, 1), U("PropertyChanged"), U("NcPropertyChangedEventData"), false)); - - web::json::push_back(control_classes, details::make_nc_class_descriptor(value::string(U("NcObject class descriptor")), details::make_nc_class_id({ 1 }), U("NcObject"), value::null(), properties, methods, events)); - } - - // NcBlock control class - { - auto properties = value::array(); - web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("TRUE if block is functional")), details::make_nc_property_id(2, 1), nmos::fields::nc::enabled, value::string(U("NcBoolean")), true, false, false, false, value::null())); - web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Descriptors of this block's members")), details::make_nc_property_id(2, 2), nmos::fields::nc::members, value::string(U("NcBlockMemberDescriptor")), true, false, true, false, value::null())); - auto methods = value::array(); - { - auto parameters = value::array(); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("If recurse is set to true, nested members can be retrieved")), nmos::fields::nc::recurse, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(methods, details::make_nc_method_descriptor(value::string(U("Gets descriptors of members of the block")), details::make_nc_method_id(2, 1), U("GetMemberDescriptors"), U("NcMethodResultBlockMemberDescriptors"), parameters, false)); - } - { - auto parameters = value::array(); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Relative path to search for (MUST not include the role of the block targeted by oid)")), nmos::fields::nc::path, value::string(U("NcRolePath")), false, false, value::null())); - web::json::push_back(methods, details::make_nc_method_descriptor(value::string(U("Finds member(s) by path")), details::make_nc_method_id(2, 2), U("FindMembersByPath"), U("NcMethodResultBlockMemberDescriptors"), parameters, false)); - } - { - auto parameters = value::array(); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Role text to search for")), nmos::fields::nc::role, value::string(U("NcString")), false, false, value::null())); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Signals if the comparison should be case sensitive")), nmos::fields::nc::case_sensitive, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("TRUE to only return exact matches")), nmos::fields::nc::match_whole_string, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("TRUE to search nested blocks")), nmos::fields::nc::recurse, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(methods, details::make_nc_method_descriptor(value::string(U("Finds members with given role name or fragment")), details::make_nc_method_id(2, 3), U("FindMembersByRole"), U("NcMethodResultBlockMemberDescriptors"), parameters, false)); - } - { - auto parameters = value::array(); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Class id to search for")), nmos::fields::nc::class_id, value::string(U("NcClassId")), false, false, value::null())); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("If TRUE it will also include derived class descriptors")), nmos::fields::nc::include_derived, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("TRUE to search nested blocks")), nmos::fields::nc::recurse, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(methods, details::make_nc_method_descriptor(value::string(U("Finds members with given class id")), details::make_nc_method_id(2, 4), U("FindMembersByClassId"), U("NcMethodResultBlockMemberDescriptors"), parameters, false)); - } - auto events = value::array(); - - web::json::push_back(control_classes, details::make_nc_class_descriptor(value::string(U("NcBlock class descriptor")), details::make_nc_class_id({ 1, 1 }), U("NcBlock"), value::null(), properties, methods, events)); - } - - // NcWorker control class - { - auto properties = value::array(); - web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("TRUE iff worker is enabled")), details::make_nc_property_id(2, 1), nmos::fields::nc::enabled, value::string(U("NcBoolean")), false, false, false, false, value::null())); - auto methods = value::array(); - auto events = value::array(); - - web::json::push_back(control_classes, details::make_nc_class_descriptor(value::string(U("NcWorker class descriptor")), details::make_nc_class_id({ 1, 2 }), U("NcWorker"), value::null(), properties, methods, events)); - } - - // NcManager control class - { - auto properties = value::array(); - auto methods = value::array(); - auto events = value::array(); - - web::json::push_back(control_classes, details::make_nc_class_descriptor(value::string(U("NcManager class descriptor")), details::make_nc_class_id({ 1, 3 }), U("NcManager"), value::null(), properties, methods, events)); - } - - // NcDeviceManager control class - { - auto properties = value::array(); - web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Version of MS-05-02 that this device uses")), details::make_nc_property_id(3, 1), nmos::fields::nc::nc_version, value::string(U("NcVersionCode")), true, false, false, false, value::null())); - web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Manufacturer descriptor")), details::make_nc_property_id(3, 2), nmos::fields::nc::manufacturer, value::string(U("NcManufacturer")), true, false, false, false, value::null())); - web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Product descriptor")), details::make_nc_property_id(3, 3), nmos::fields::nc::product, value::string(U("NcProduct")), true, false, false, false, value::null())); - web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Serial number")), details::make_nc_property_id(3, 4), nmos::fields::nc::serial_number, value::string(U("NcString")), true, false, false, false, value::null())); - web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Asset tracking identifier (user specified)")), details::make_nc_property_id(3, 5), nmos::fields::nc::user_inventory_code, value::string(U("NcString")), false, true, false, false, value::null())); - web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Name of this device in the application. Instance name, not product name")), details::make_nc_property_id(3, 6), nmos::fields::nc::device_name, value::string(U("NcString")), false, true, false, false, value::null())); - web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Role of this device in the application")), details::make_nc_property_id(3, 7), nmos::fields::nc::device_role, value::string(U("NcString")), false, true, false, false, value::null())); - web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Device operational state")), details::make_nc_property_id(3, 8), nmos::fields::nc::operational_state, value::string(U("NcDeviceOperationalState")), true, false, false, false, value::null())); - web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Reason for most recent reset")), details::make_nc_property_id(3, 9), nmos::fields::nc::reset_cause, value::string(U("NcResetCause")), true, false, false, false, value::null())); - web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Arbitrary message from dev to controller")), details::make_nc_property_id(3, 10), nmos::fields::nc::message, value::string(U("NcString")), true, true, false, false, value::null())); - auto methods = value::array(); - auto events = value::array(); - - web::json::push_back(control_classes, details::make_nc_class_descriptor(value::string(U("NcDeviceManager class descriptor")), details::make_nc_class_id({ 1, 3, 1 }), U("NcDeviceManager"), value::string(U("DeviceManager")), properties, methods, events)); - } - - // NcClassManager control class - { - auto properties = value::array(); - web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Descriptions of all control classes in the device (descriptors do not contain inherited elements)")), details::make_nc_property_id(3, 1), nmos::fields::nc::control_classes, value::string(U("NcClassDescriptor")), true, false, true, false, value::null())); - web::json::push_back(properties, details::make_nc_property_descriptor(value::string(U("Descriptions of all data types in the device (descriptors do not contain inherited elements)")), details::make_nc_property_id(3, 2), nmos::fields::nc::datatypes, value::string(U("NcDatatypeDescriptor")), true, false, true, false, value::null())); - auto methods = value::array(); - { - auto parameters = value::array(); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("class ID")), nmos::fields::nc::class_id, value::string(U("NcClassId")), false, false, value::null())); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("If set the descriptor would contain all inherited elements")), nmos::fields::nc::include_inherited, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(methods, details::make_nc_method_descriptor(value::string(U("Get a single class descriptor")), details::make_nc_method_id(3, 1), U("GetControlClass"), U("NcMethodResultClassDescriptor"), parameters, false)); - } - { - auto parameters = value::array(); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("name of datatype")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("If set the descriptor would contain all inherited elements")), nmos::fields::nc::include_inherited, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(methods, details::make_nc_method_descriptor(value::string(U("Get a single datatype descriptor")), details::make_nc_method_id(3, 2), U("GetDatatype"), U("NcMethodResultDatatypeDescriptor"), parameters, false)); - } - auto events = value::array(); - - web::json::push_back(control_classes, details::make_nc_class_descriptor(value::string(U("NcClassManager class descriptor")), details::make_nc_class_id({ 1, 3, 2 }), U("NcClassManager"), value::string(U("ClassManager")), properties, methods, events)); - } - - // load the minimal datatypes - data[nmos::fields::nc::datatypes] = value::array(); - auto& datatypes = data[nmos::fields::nc::datatypes]; - - // NcObject datatypes - // NcClassId - web::json::push_back(datatypes, details::make_nc_datatype_typedef(value::string(U("Sequence of class ID fields")), U("NcClassId"), value::null(), U("NcInt32"), true)); - // NcOid - web::json::push_back(datatypes, details::make_nc_datatype_typedef(value::string(U("Object id")), U("NcOid"), value::null(), U("NcUint32"), false)); - // NcTouchpoint - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Context namespace")), nmos::fields::nc::context_namespace, value::string(U("NcString")), false, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Base touchpoint class")), U("NcTouchpoint"), value::null(), fields, value::null())); - } - // NcElementId - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Level of the element")), nmos::fields::nc::level, value::string(U("NcUint16")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Index of the element")), nmos::fields::nc::index, value::string(U("NcUint16")), false, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Class element id which contains the level and index")), U("NcElementId"), value::null(), fields, value::null())); - } - // NcPropertyId - { - auto fields = value::array(); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Property id which contains the level and index")), U("NcPropertyId"), value::null(), fields, value::string(U("NcElementId")))); - } - // NcPropertyConstraints - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("The id of the property being constrained")), nmos::fields::nc::property_id, value::string(U("NcPropertyId")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional default value")), nmos::fields::nc::default_value, value::null(), true, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Property constraints class")), U("NcPropertyConstraints"), value::null(), fields, value::null())); - } - // NcMethodResultPropertyValue - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Getter method value for the associated property")), nmos::fields::nc::value, value::null(), true, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Result when invoking the getter method associated with a property")), U("NcMethodResultPropertyValue"), value::null(), fields, value::string(U("NcMethodResult")))); - } - // NcMethodStatus - { - auto items = value::array(); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method call was successful")), U("Ok"), 200)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method call was successful but targeted property is deprecated")), U("PropertyDeprecated"), 298)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method call was successful but method is deprecated")), U("MethodDeprecated"), 299)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Badly-formed command (e.g. the incoming command has invalid message encoding and cannot be parsed by the underlying protocol)")), U("BadCommandFormat"), 400)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Client is not authorized")), U("Unauthorized"), 401)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Command addresses a nonexistent object")), U("BadOid"), 404)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Attempt to change read-only state")), U("Readonly"), 405)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method call is invalid in current operating context (e.g. attempting to invoke a method when the object is disabled)")), U("InvalidRequest"), 406)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("There is a conflict with the current state of the device")), U("Conflict"), 409)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Something was too big")), U("BufferOverflow"), 413)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Index is outside the available range")), U("IndexOutOfBounds"), 414)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method parameter does not meet expectations (e.g. attempting to invoke a method with an invalid type for one of its parameters)")), U("ParameterError"), 417)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Addressed object is locked")), U("Locked"), 423)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Internal device error")), U("DeviceError"), 500)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Addressed method is not implemented by the addressed object")), U("MethodNotImplemented"), 501)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Addressed property is not implemented by the addressed object")), U("PropertyNotImplemented"), 502)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("The device is not ready to handle any commands")), U("NotReady"), 503)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method call did not finish within the allotted time")), U("Timeout"), 504)); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_enum(value::string(U("Method invokation status")), U("NcMethodStatus"), value::null(), items)); - } - // NcMethodResult - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Status for the invoked method")), nmos::fields::nc::status, value::string(U("NcMethodStatus")), false, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Base result of the invoked method")), U("NcMethodResult"), value::null(), fields, value::null())); - } - // NcId - web::json::push_back(datatypes, details::make_nc_datatype_typedef(value::string(U("Identity handler")), U("NcId"), value::null(), U("NcUint32"), false)); - // NcMethodResultId - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Id result value")), nmos::fields::nc::value, value::string(U("NcId")), false, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Id method result")), U("NcMethodResultId"), value::null(), fields, value::string(U("NcMethodResult")))); - } - // NcMethodResultLength - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Length result value")), nmos::fields::nc::value, value::string(U("NcUint32")), false, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Length method result")), U("NcMethodResultLength"), value::null(), fields, value::string(U("NcMethodResult")))); - } - // NcPropertyChangeType - { - auto items = value::array(); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Current value changed")), U("ValueChanged"), 0)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Sequence item added")), U("SequenceItemAdded"), 1)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Sequence item changed")), U("SequenceItemChanged"), 2)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Sequence item removed")), U("SequenceItemRemoved"), 3)); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_enum(value::string(U("Type of property change")), U("NcPropertyChangeType"), value::null(), items)); - } - // NcPropertyChangedEventData - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("The id of the property that changed")), nmos::fields::nc::property_id, value::string(U("NcPropertyId")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Information regarding the change type")), nmos::fields::nc::change_type, value::string(U("NcPropertyChangeType")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Property-type specific value")), nmos::fields::nc::value, value::null(), true, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Index of sequence item if the property is a sequence")), nmos::fields::nc::sequence_item_index, value::string(U("NcId")), true, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Payload of property-changed event")), U("NcPropertyChangedEventData"), value::null(), fields, value::null())); - } - - // NcBlock datatypes - // NcDescriptor - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional user facing description")), nmos::fields::nc::description, value::string(U("NcString")), true, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Base descriptor")), U("NcDescriptor"), value::null(), fields, value::null())); - } - // NcBlockMemberDescriptor - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Role of member in its containing block")), nmos::fields::nc::role, value::string(U("NcString")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("OID of member")), nmos::fields::nc::oid, value::string(U("NcOid")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff member's OID is hardwired into device")), nmos::fields::nc::constant_oid, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Class ID")), nmos::fields::nc::class_id, value::string(U("NcClassId")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("User label")), nmos::fields::nc::user_label, value::string(U("NcString")), true, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Containing block's OID")), nmos::fields::nc::owner, value::string(U("NcOid")), false, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor which is specific to a block member")), U("NcBlockMemberDescriptor"), value::null(), fields, value::string(U("NcDescriptor")))); - } - // NcMethodResultBlockMemberDescriptors - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Block member descriptors method result value")), nmos::fields::nc::value, value::string(U("NcBlockMemberDescriptor")), false, true, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Method result containing block member descriptors as the value")), U("NcMethodResultBlockMemberDescriptors"), value::null(), fields, value::string(U("NcMethodResult")))); - } - - // NcWorker has no datatypes - - // NcManager has no datatypes - - // NcDeviceManager datatypes - // NcVersionCode - web::json::push_back(datatypes, details::make_nc_datatype_typedef(value::string(U("Version code in semantic versioning format")), U("NcVersionCode"), value::null(), U("NcString"), false)); - // NcOrganizationId - web::json::push_back(datatypes, details::make_nc_datatype_typedef(value::string(U("Unique 24-bit organization id")), U("NcOrganizationId"), value::null(), U("NcInt32"), false)); - // NcUri - web::json::push_back(datatypes, details::make_nc_datatype_typedef(value::string(U("Uniform resource identifier")), U("NcUri"), value::null(), U("NcString"), false)); - // NcManufacturer - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Manufacturer's name")), nmos::fields::nc::name, value::string(U("NcString")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("IEEE OUI or CID of manufacturer")), nmos::fields::nc::organization_id, value::string(U("NcOrganizationId")), true, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("URL of the manufacturer's website")), nmos::fields::nc::website, value::string(U("NcUri")), true, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Manufacturer descriptor")), U("NcManufacturer"), value::null(), fields, value::null())); - } - // NcUuid - web::json::push_back(datatypes, details::make_nc_datatype_typedef(value::string(U("UUID")), U("NcUuid"), value::null(), U("NcString"), false)); - // NcProduct - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Product name")), nmos::fields::nc::name, value::string(U("NcString")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Manufacturer's unique key to product - model number, SKU, etc")), nmos::fields::nc::key, value::string(U("NcString")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Manufacturer's product revision level code")), nmos::fields::nc::revision_level, value::string(U("NcString")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Brand name under which product is sold")), nmos::fields::nc::brand_name, value::string(U("NcString")), true, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Unique UUID of product (not product instance)")), nmos::fields::nc::uuid, value::string(U("NcUuid")), true, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Text description of product")), nmos::fields::nc::description, value::string(U("NcString")), true, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Product descriptor")), U("NcProduct"), value::null(), fields, value::null())); - } - // NcDeviceGenericState - { - auto items = value::array(); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Unknown")), U("Unknown"), 0)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Normal operation")), U("NormalOperation"), 1)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Device is initializing")), U("Initializing"), 2)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Device is performing a software or firmware update")), U("Updating"), 3)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Device is experiencing a licensing error")), U("LicensingError"), 4)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Device is experiencing an internal error")), U("InternalError"), 5)); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_enum(value::string(U("Device generic operational state")), U("NcDeviceGenericState"), value::null(), items)); - } - // NcDeviceOperationalState - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Generic operational state")), nmos::fields::nc::generic_state, value::string(U("NcDeviceGenericState")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Specific device details")), nmos::fields::nc::device_specific_details, value::string(U("NcString")), true, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Device operational state")), U("NcDeviceOperationalState"), value::null(), fields, value::null())); - } - // NcResetCause - { - auto items = value::array(); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Unknown")), U("Unknown"), 0)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Power on")), U("PowerOn"), 1)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Internal error")), U("InternalError"), 2)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Upgrade")), U("Upgrade"), 3)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Controller request")), U("ControllerRequest"), 4)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Manual request from the front panel")), U("ManualReset"), 5)); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_enum(value::string(U("Reset cause enum")), U("NcResetCause"), value::null(), items)); - } - - // NcClassManager datatypes - // NcName - web::json::push_back(datatypes, details::make_nc_datatype_typedef(value::string(U("Programmatically significant name, alphanumerics + underscore, no spaces")), U("NcName"), value::null(), U("NcString"), false)); - // NcPropertyDescriptor - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Property id with level and index")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of property")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of property's datatype. Can only ever be null if the type is any")), nmos::fields::nc::type_name, value::string(U("NcName")), true, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is read-only")), nmos::fields::nc::is_read_only, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is nullable")), nmos::fields::nc::is_nullable, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is a sequence")), nmos::fields::nc::is_sequence, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is marked as deprecated")), nmos::fields::nc::is_deprecated, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional constraints on top of the underlying data type")), nmos::fields::nc::constraints, value::string(U("NcParameterConstraints")), true, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class property")), U("NcPropertyDescriptor"), value::null(), fields, value::string(U("NcDescriptor")))); - } - // NcMethodId - { - auto fields = value::array(); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Method id which contains the level and index")), U("NcMethodId"), value::null(), fields, value::string(U("NcElementId")))); - } - // NcParameterDescriptor - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of parameter")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of parameter's datatype. Can only ever be null if the type is any")), nmos::fields::nc::type_name, value::string(U("NcName")), true, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is nullable")), nmos::fields::nc::is_nullable, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is a sequence")), nmos::fields::nc::is_sequence, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional constraints on top of the underlying data type")), nmos::fields::nc::constraints, value::string(U("NcParameterConstraints")), true, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a method parameter")), U("NcParameterDescriptor"), value::null(), fields, value::string(U("NcDescriptor")))); - } - // NcMethodDescriptor - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Method id with level and index")), nmos::fields::nc::id, value::string(U("NcMethodId")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of method")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of method result's datatype")), nmos::fields::nc::result_datatype, value::string(U("NcName")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Parameter descriptors if any")), nmos::fields::nc::parameters, value::string(U("NcParameterDescriptor")), false, true, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is marked as deprecated")), nmos::fields::nc::is_deprecated, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class method")), U("NcMethodDescriptor"), value::null(), fields, value::string(U("NcDescriptor")))); - } - // NcEventId - { - auto fields = value::array(); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Event id which contains the level and index")), U("NcEventId"), value::null(), fields, value::string(U("NcElementId")))); - } - // NcEventDescriptor - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Event id with level and index")), nmos::fields::nc::id, value::string(U("NcEventId")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of event")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of event data's datatype")), nmos::fields::nc::event_datatype, value::string(U("NcName")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is marked as deprecated")), nmos::fields::nc::is_deprecated, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class event")), U("NcEventDescriptor"), value::null(), fields, value::string(U("NcDescriptor")))); - } - // NcClassDescriptor - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Identity of the class")), nmos::fields::nc::class_id, value::string(U("NcClassId")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of the class")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Role if the class has fixed role (manager classes)")), nmos::fields::nc::fixed_role, value::string(U("NcString")), true, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Property descriptors")), nmos::fields::nc::properties, value::string(U("NcPropertyDescriptor")), false, true, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Method descriptors")), nmos::fields::nc::methods, value::string(U("NcMethodDescriptor")), false, true, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Event descriptors")), nmos::fields::nc::events, value::string(U("NcEventDescriptor")), false, true, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class")), U("NcClassDescriptor"), value::null(), fields, value::string(U("NcDescriptor")))); - } - // NcParameterConstraints - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Default value")), nmos::fields::nc::default_value, value::null(), true, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Abstract parameter constraints class")), U("NcParameterConstraints"), value::null(), fields, value::null())); - } - // NcDatatypeType - { - auto items = value::array(); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Primitive datatype")), U("Primitive"), 0)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Simple alias of another datatype")), U("Typedef"), 1)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Data structure")), U("Struct"), 2)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Enum datatype")), U("Enum"), 3)); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_enum(value::string(U("Datatype type")), U("NcDatatypeType"), value::null(), items)); - } - // NcDatatypeDescriptor - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Datatype name")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Type: Primitive, Typedef, Struct, Enum")), nmos::fields::nc::type, value::string(U("NcDatatypeType")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional constraints on top of the underlying data type")), nmos::fields::nc::constraints, value::string(U("NcParameterConstraints")), true, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Base datatype descriptor")), U("NcDatatypeDescriptor"), value::null(), fields, value::string(U("NcDescriptor")))); - } - // NcMethodResultClassDescriptor - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Class descriptor method result value")), nmos::fields::nc::value, value::string(U("NcClassDescriptor")), false, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Method result containing a class descriptor as the value")), U("NcMethodResultClassDescriptor"), value::null(), fields, value::string(U("NcMethodResult")))); - } - // NcMethodResultDatatypeDescriptor - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Datatype descriptor method result value")), nmos::fields::nc::value, value::string(U("NcDatatypeDescriptor")), false, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Method result containing a datatype descriptor as the value")), U("NcMethodResultDatatypeDescriptor"), value::null(), fields, value::string(U("NcMethodResult")))); - } - - return data; - } - } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager nmos::resource make_device_manager(details::nc_oid oid, nmos::resource& root_block, const nmos::settings& settings) { @@ -942,8 +45,8 @@ namespace nmos auto data = details::make_nc_class_manager(oid, owner, user_label); // add NcClassManager block_member_descriptor to root block members - web::json::push_back(root_block_data[nmos::fields::nc::members], details::make_nc_block_member_descriptor( - description, nmos::fields::nc::role(data), oid, nmos::fields::nc::constant_oid(data), data.at(nmos::fields::nc::class_id), user_label, owner)); + web::json::push_back(root_block_data[nmos::fields::nc::members], + details::make_nc_block_member_descriptor(description, nmos::fields::nc::role(data), oid, nmos::fields::nc::constant_oid(data), data.at(nmos::fields::nc::class_id), user_label, owner)); return{ is12_versions::v1_0, types::nc_class_manager, std::move(data), true }; } @@ -953,7 +56,7 @@ namespace nmos { using web::json::value; - auto data = details::make_nc_block(1, true, value::null(), U("root"), value::string(U("Root")), value::null(), value::null(), true, value::array()); + auto data = details::make_nc_block(details::nc_block_class_id, 1, true, value::null(), U("root"), value::string(U("Root")), value::null(), value::null(), true, value::array()); return{ is12_versions::v1_0, types::nc_block, std::move(data), true }; } diff --git a/Development/nmos/control_protocol_resources.h b/Development/nmos/control_protocol_resources.h index f7683c2ae..ca16c8d9b 100644 --- a/Development/nmos/control_protocol_resources.h +++ b/Development/nmos/control_protocol_resources.h @@ -2,141 +2,13 @@ #define NMOS_CONTROL_PROTOCOL_RESOURCES_H #include +#include "nmos/control_protocol_resource.h" // for details::nc_oid definition #include "nmos/settings.h" -namespace web -{ - namespace json - { - class value; - } -} - namespace nmos { struct resource; - namespace details - { - namespace nc_message_type - { - enum type - { - command = 0, - command_response = 1, - notification = 2, - subscription = 3, - subscription_response = 4, - error = 5 - }; - } - - // Method invokation status - namespace nc_method_status - { - enum status - { - ok = 200, // Method call was successful - property_deprecated = 298, // Method call was successful but targeted property is deprecated - method_deprecated = 299, // Method call was successful but method is deprecated - bad_command_format = 400, // Badly-formed command - unathorized = 401, // Client is not authorized - bad_oid = 404, // Command addresses a nonexistent object - read_only = 405, // Attempt to change read-only state - invalid_request = 406, // Method call is invalid in current operating context - conflict = 409, // There is a conflict with the current state of the device - buffer_overflow = 413, // Something was too big - parameter_error = 417, // Method parameter does not meet expectations - locked = 423, // Addressed object is locked - device_error = 500, // Internal device error - method_not_implemented = 501, // Addressed method is not implemented by the addressed object - property_not_implemented = 502, // Addressed property is not implemented by the addressed object - not_ready = 503, // The device is not ready to handle any commands - timeout = 504, // Method call did not finish within the allotted time - property_version_error = 505 // Incompatible protocol version - }; - } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmethodresult - struct nc_method_result - { - nc_method_status::status status; - }; - - // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#command-response-message-type - web::json::value make_control_protocol_error_response(int32_t handle, const nc_method_result& method_result, const utility::string_t& error_message); - web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result); - web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result, const web::json::value& value); - - // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#command-message-type - web::json::value make_control_protocol_message_response(nc_message_type::type type, const web::json::value& responses); - // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#error-messages - web::json::value make_control_protocol_error_message(const nc_method_result& method_result, const utility::string_t& error_message); - - // Datatype type - namespace nc_datatype_type - { - enum type - { - Primitive = 0, - Typedef = 1, - Struct = 2, - Enum = 3 - }; - } - - // Device generic operational state - namespace nc_device_generic_state - { - enum state - { - Unknown = 0, // Unknown - NormalOperation = 1, // Normal operation - Initializing = 2, // Device is initializing - Updating = 3, // Device is performing a software or firmware update - LicensingError = 4, // Device is experiencing a licensing error - InternalError = 5 // Device is experiencing an internal error - }; - } - - // Reset cause enum - namespace nc_reset_cause - { - enum cause - { - Unknown = 0, // 0 Unknown - Power_on = 1, // 1 Power on - InternalError = 2, // 2 Internal error - Upgrade = 3, // 3 Upgrade - Controller_request = 4, // 4 Controller request - ManualReset = 5 // 5 Manual request from the front panel - }; - } - - // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncid - typedef uint32_t nc_id; - - // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncoid - typedef uint32_t nc_oid; - - // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncuri - typedef utility::string_t nc_uri; - - // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncuuid - typedef utility::string_t nc_uuid; - - // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassid - typedef std::vector nc_class_id; - - // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#nctouchpoint - typedef utility::string_t nc_touch_point; - - typedef std::map properties; - - typedef std::function method; - typedef std::map methods; // method_id vs method handler - } - nmos::resource make_device_manager(details::nc_oid oid, nmos::resource& root_block, const nmos::settings& settings); nmos::resource make_class_manager(details::nc_oid oid, nmos::resource& root_block); diff --git a/Development/nmos/control_protocol_state.cpp b/Development/nmos/control_protocol_state.cpp new file mode 100644 index 000000000..c420072be --- /dev/null +++ b/Development/nmos/control_protocol_state.cpp @@ -0,0 +1,23 @@ +#include "nmos/control_protocol_state.h" + +#include "nmos/control_protocol_resource.h" + +namespace nmos +{ + namespace experimental + { + control_protocol_state::control_protocol_state() + { + // setup the core control classes (properties/methods/events) + control_classes = + { + { details::make_nc_class_id(details::nc_object_class_id), { details::make_nc_object_properties(), details::make_nc_object_methods(), details::make_nc_object_events() } }, + { details::make_nc_class_id(details::nc_block_class_id), { details::make_nc_block_properties(), details::make_nc_block_methods(), details::make_nc_block_events() } }, + { details::make_nc_class_id(details::nc_worker_class_id), { details::make_nc_worker_properties(), details::make_nc_worker_methods(), details::make_nc_worker_events() } }, + { details::make_nc_class_id(details::nc_manager_class_id), { details::make_nc_manager_properties(), details::make_nc_manager_methods(), details::make_nc_manager_events() } }, + { details::make_nc_class_id(details::nc_device_manager_class_id), { details::make_nc_device_manager_properties(), details::make_nc_device_manager_methods(), details::make_nc_device_manager_events() } }, + { details::make_nc_class_id(details::nc_class_manager_class_id), { details::make_nc_class_manager_properties(), details::make_nc_class_manager_methods(), details::make_nc_class_manager_events() } } + }; + } + } +} \ No newline at end of file diff --git a/Development/nmos/control_protocol_state.h b/Development/nmos/control_protocol_state.h new file mode 100644 index 000000000..5a8b5e1ca --- /dev/null +++ b/Development/nmos/control_protocol_state.h @@ -0,0 +1,36 @@ +#ifndef NMOS_CONTROL_PROTOCOL_STATE_H +#define NMOS_CONTROL_PROTOCOL_STATE_H + +#include +#include "cpprest/json_utils.h" +#include "nmos/mutex.h" + +namespace nmos +{ + namespace experimental + { + struct control_class + { + web::json::value properties; // array of nc_property_descriptor + web::json::value methods; // array of nc_method_descriptor + web::json::value events; // array of nc_event_descriptor + }; + + typedef std::map control_classes; + + struct control_protocol_state + { + // mutex to be used to protect the members from simultaneous access by multiple threads + mutable nmos::mutex mutex; + + control_classes control_classes; + + nmos::read_lock read_lock() const { return nmos::read_lock{ mutex }; } + nmos::write_lock write_lock() const { return nmos::write_lock{ mutex }; } + + control_protocol_state(); + }; + } +} + +#endif diff --git a/Development/nmos/control_protocol_ws_api.cpp b/Development/nmos/control_protocol_ws_api.cpp index 6bb263468..6639bcc93 100644 --- a/Development/nmos/control_protocol_ws_api.cpp +++ b/Development/nmos/control_protocol_ws_api.cpp @@ -45,6 +45,226 @@ namespace nmos { controlprotocol_validator().validate(request_data, experimental::make_controlprotocolapi_subscription_message_schema_uri(version)); } + + std::pair create_properties_methods(nmos::node_model& model, const nc_class_id& class_id_, const nmos::experimental::control_classes& control_classes) + { + using web::json::value; + using web::json::value_of; + + // hmm, methods should also be passing in via the control_class::methods + + // NcObject methods implementation + // get property + auto get = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + auto& resources = model.control_protocol_resources; + auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); + if (resources.end() != resource) + { + // where arguments is the property id = (level, index) + const auto& property_id = nmos::fields::nc::id(arguments); + + // find the relevant nc_property_descriptor + auto property_found = std::find_if(properties.begin(), properties.end(), [property_id](const web::json::value& property) + { + return property_id == nmos::fields::nc::id(property); + }); + + if (property_found != properties.end()) + { + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, resource->data.at(nmos::fields::nc::name(*property_found))); + } + + // unknown property + utility::stringstream_t ss; + ss << U("unknown property: ") << property_id.serialize() << " to do get"; + return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); + } + + // resource not found for the given oid + utility::stringstream_t ss; + ss << U("unknown oid: ") << oid << " to do get"; + return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); + }; + // set property + auto set = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + auto& resources = model.control_protocol_resources; + auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); + if (resources.end() != resource) + { + const auto& property_id = nmos::fields::nc::id(arguments); + const auto& val = nmos::fields::nc::value(arguments); + + // find the relevant nc_property_descriptor + auto property_found = std::find_if(properties.begin(), properties.end(), [property_id](const web::json::value& property) + { + return property_id == nmos::fields::nc::id(property); + }); + if (property_found != properties.end()) + { + if (!nmos::fields::nc::is_read_only(*property_found)) + { + resources.modify(resource, [&](nmos::resource& resource) + { + resource.data[nmos::fields::nc::name(*property_found)] = val; + + resource.updated = strictly_increasing_update(resources); + }); + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }); + } + else + { + return details::make_control_protocol_response(handle, { details::nc_method_status::read_only }); + } + } + + // unknown property + utility::stringstream_t ss; + ss << U("unknown property: ") << property_id.serialize() << " to do set"; + return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); + } + + // resource not found for the given oid + utility::stringstream_t ss; + ss << U("unknown oid: ") << oid << " to do set"; + return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); + }; + + // NcBlock methods implementation + // get descriptors of members of the block + auto get_member_descriptors = [&model](const web::json::array&, int32_t handle, int32_t oid, const value& arguments) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + auto& resources = model.control_protocol_resources; + auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); + if (resources.end() != resource) + { + // where arguments is the boolean recurse value + // hmm, If recurse is set to true, nested members is to be retrieved + const auto& recurse = nmos::fields::nc::recurse(arguments); + + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, resource->data.at(nmos::fields::nc::members)); + } + + // resource not found for the given oid + utility::stringstream_t ss; + ss << U("unknown oid: ") << oid << " to get member descriptors"; + return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); + }; + + // NcClassManager methods implementation + auto get_control_class = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments) + { + // hmm, todo + + // resource not found for the given oid + utility::stringstream_t ss; + ss << U("unknown oid: ") << oid << " to get control class"; + return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); + }; + + // method handlers for the different classes + details::methods nc_object_method_handlers; // method_id vs NcObject method_handler + details::methods nc_block_method_handlers; // method_id vs NcBlock method_handler + details::methods nc_worker_method_handlers; // method_id vs NcWorker method_handler + details::methods nc_manager_method_handlers; // method_id vs NcManager method_handler + details::methods nc_device_manager_method_handlers; // method_id vs NcDeviceManager method_handler + details::methods nc_class_manager_method_handlers; // method_id vs NcClassManager method_handler + + // NcObject methods + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject + nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 1 } })] = get; + nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 2 } })] = set; + //nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 3 } })] = get_sequence_item; + //nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 4 } })] = set_sequence_item; + //nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 5 } })] = add_sequence_item; + //nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 6 } })] = remove_sequence_item; + //nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 7 } })] = get_sequence_length; + + // NcBlock methods + // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock + nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 1 } })] = get_member_descriptors; + //nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 2 } })] = find_members_by_path; + //nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 3 } })] = find_members_by_role; + //nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 4 } })] = find_members_by_class_id; + + // NcWorker has no extended method + // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncworker + + // NcManager has no extended method + // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanager + + // NcDeviceManger has no extended method + // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager + + // NcClassManager methods + // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager + //nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 1 } })] = get_control_class; + //nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 2 } })] = get_datatype; + + value properties = value::array(); // combined base classes nc_property_descriptor(s) for the required class_id + details::methods methods; // list of combined base classes method handlers + + auto found_class = control_classes.find(make_nc_class_id(class_id_)); + if (control_classes.end() != found_class) + { + // hmm, update the array of properties, will be updated the list of method handlers + auto insert_properties = [&properties, &control_classes](const nc_class_id& class_id_) + { + auto class_id = make_nc_class_id(class_id_); + auto found = control_classes.find(class_id); + if (control_classes.end() != found) + { + auto& nc_class_properties = found->second.properties.as_array(); + for (auto& nc_class_property : nc_class_properties) + { + web::json::push_back(properties, nc_class_property); + } + } + }; + + auto class_id = class_id_; + while (class_id.size()) + { + insert_properties(class_id); + + // hmm, to be deleted, once the methods are passed in + if (details::nc_object_class_id == class_id) + { + methods.insert(nc_object_method_handlers.begin(), nc_object_method_handlers.end()); + } + else if (details::nc_block_class_id == class_id) + { + methods.insert(nc_block_method_handlers.begin(), nc_block_method_handlers.end()); + } + else if (details::nc_device_manager_class_id == class_id) + { + methods.insert(nc_manager_method_handlers.begin(), nc_manager_method_handlers.end()); + } + else if (details::nc_device_manager_class_id == class_id) + { + methods.insert(nc_device_manager_method_handlers.begin(), nc_device_manager_method_handlers.end()); + } + else if (details::nc_class_manager_class_id == class_id) + { + methods.insert(nc_class_manager_method_handlers.begin(), nc_class_manager_method_handlers.end()); + } + class_id.pop_back(); + } + } + else + { + throw std::runtime_error("unknown control class"); + } + + return { properties, methods }; + } } // IS-12 Control Protocol WebSocket API @@ -183,273 +403,11 @@ namespace nmos }; } - web::websockets::experimental::listener::message_handler make_control_protocol_ws_message_handler(nmos::node_model& model, nmos::websockets& websockets, slog::base_gate& gate_) + web::websockets::experimental::listener::message_handler make_control_protocol_ws_message_handler(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_classes_handler get_control_protocol_classes, slog::base_gate& gate_) { using web::json::value; - using web::json::value_of; - - // NcObject properties - // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject - const details::properties nc_object_properties = - { - // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject - { value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 1 } }), nmos::fields::nc::class_id }, - { value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 2 } }), nmos::fields::nc::oid }, - { value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 3 } }), nmos::fields::nc::constant_oid }, - { value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 4 } }), nmos::fields::nc::owner }, - { value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 5 } }), nmos::fields::nc::role }, - { value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 6 } }), nmos::fields::nc::user_label }, - { value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 7 } }), nmos::fields::nc::touchpoints }, - { value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 8 } }), nmos::fields::nc::runtime_property_constraints } - }; - - // NcBlock properties - // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock - const details::properties nc_block_properties = - { - // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock - { value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 1 } }), nmos::fields::nc::enabled }, - { value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 2 } }), nmos::fields::nc::members } - }; - - // NcWorker properties - // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncworker - const details::properties nc_worker_properties = - { - // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncworker - { value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 1 } }), nmos::fields::nc::enabled } - }; - - // NcManager has no property - // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanager - const details::properties nc_manager_properties; - - // NcDeviceManager properties - // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager - const details::properties nc_device_manager_properties = - { - // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager - { value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 1 } }), nmos::fields::nc::nc_version }, - { value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 2 } }), nmos::fields::nc::manufacturer }, - { value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 3 } }), nmos::fields::nc::product }, - { value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 4 } }), nmos::fields::nc::serial_number }, - { value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 5 } }), nmos::fields::nc::user_inventory_code }, - { value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 6 } }), nmos::fields::nc::device_name }, - { value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 7 } }), nmos::fields::nc::device_role }, - { value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 8 } }), nmos::fields::nc::operational_state }, - { value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 9 } }), nmos::fields::nc::reset_cause }, - { value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 10 } }), nmos::fields::nc::message } - }; - - // NcClassManager properties - // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager - const details::properties nc_class_manager_properties = - { - // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager - { value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 1 } }), nmos::fields::nc::control_classes }, - { value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 2 } }), nmos::fields::nc::datatypes } - }; - - // method handlers for the different classes - details::methods nc_object_method_handlers; // method_id vs NcObject method_handler - details::methods nc_block_method_handlers; // method_id vs NcBlock method_handler - details::methods nc_worker_method_handlers; // method_id vs NcWorker method_handler - details::methods nc_manager_method_handlers; // method_id vs NcManager method_handler - details::methods nc_device_manager_method_handlers; // method_id vs NcDeviceManager method_handler - details::methods nc_class_manager_method_handlers; // method_id vs NcClassManager method_handler - - // NcObject methods implementation - // get property - auto get = [&model](const details::properties& properties, int32_t handle, int32_t oid, const value& arguments) - { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - - auto& resources = model.control_protocol_resources; - auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); - if (resources.end() != resource) - { - // where arguments is the property id = (level, index) - const auto& property_id = nmos::fields::nc::id(arguments); - - // is property_id defined in properties map - auto property_found = properties.find(property_id); - if (property_found != properties.end()) - { - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, resource->data.at(property_found->second)); - } - - // unknown property - utility::stringstream_t ss; - ss << U("unknown property: ") << property_id.serialize() << " to do get"; - return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); - } - - // resource not found for the given oid - utility::stringstream_t ss; - ss << U("unknown oid: ") << oid << " to do get"; - return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); - }; - // set property - auto set = [&model](const details::properties& properties, int32_t handle, int32_t oid, const value& arguments) - { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - - auto& resources = model.control_protocol_resources; - auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); - if (resources.end() != resource) - { - const auto& property_id = nmos::fields::nc::id(arguments); - const auto& val = nmos::fields::nc::value(arguments); - - // hmm, todo check property_id allowed in resource's class_id - - // is property_id defined in properties map - auto property_found = properties.find(property_id); - if (property_found != properties.end()) - { - resources.modify(resource, [&](nmos::resource& resource) - { - resource.data[property_found->second] = val; - - resource.updated = strictly_increasing_update(resources); - }); - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }); - } - else - { - // hmm, find property function from user properties map - } - - // unknown property - utility::stringstream_t ss; - ss << U("unknown property: ") << property_id.serialize() << " to do set"; - return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); - } - - // resource not found for the given oid - utility::stringstream_t ss; - ss << U("unknown oid: ") << oid << " to do set"; - return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); - }; - - // NcBlock methods implementation - // get descriptors of members of the block - auto get_member_descriptors = [&model](const details::properties& properties, int32_t handle, int32_t oid, const value& arguments) - { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - - auto& resources = model.control_protocol_resources; - auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); - if (resources.end() != resource) - { - // where arguments is the boolean recurse value - // hmm, If recurse is set to true, nested members is to be retrieved - const auto& recurse = nmos::fields::nc::recurse(arguments); - - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, resource->data.at(nmos::fields::nc::members)); - } - - // resource not found for the given oid - utility::stringstream_t ss; - ss << U("unknown oid: ") << oid << " to get member descriptors"; - return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); - }; - - // NcClassManager methods implementation - auto get_control_class = [&model](const details::properties& properties, int32_t handle, int32_t oid, const value& arguments) - { - // resource not found for the given oid - utility::stringstream_t ss; - ss << U("unknown oid: ") << oid << " to get control class"; - return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); - }; - - // NcObject methods - // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject - nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 1 } })] = get; - nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 2 } })] = set; - //nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 3 } })] = get_sequence_item; - //nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 4 } })] = set_sequence_item; - //nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 5 } })] = add_sequence_item; - //nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 6 } })] = remove_sequence_item; - //nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 7 } })] = get_sequence_length; - - // NcBlock methods - // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock - nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 1 } })] = get_member_descriptors; - //nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 2 } })] = find_members_by_path; - //nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 3 } })] = find_members_by_role; - //nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 4 } })] = find_members_by_class_id; - - // NcWorker has no extended method - // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncworker - - // NcManager has no extended method - // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanager - - // NcDeviceManger has no extended method - // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager - - // NcClassManager methods - // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager - //nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 1 } })] = get_control_class; - //nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 2 } })] = get_datatype; - - // create properties and method handlers based on resource type - auto create_properties_methods = [=](const nmos::type& type) - { - details::properties properties; - details::methods methods; - - // all start from NcObject - properties.insert(nc_object_properties.begin(), nc_object_properties.end()); - methods.insert(nc_object_method_handlers.begin(), nc_object_method_handlers.end()); - if (type == nmos::types::nc_block) - { - properties.insert(nc_block_properties.begin(), nc_block_properties.end()); - methods.insert(nc_block_method_handlers.begin(), nc_block_method_handlers.end()); - } - else if (type == nmos::types::nc_worker) - { - properties.insert(nc_worker_properties.begin(), nc_worker_properties.end()); - methods.insert(nc_worker_method_handlers.begin(), nc_worker_method_handlers.end()); - } - else if (type == nmos::types::nc_manager) - { - properties.insert(nc_manager_properties.begin(), nc_manager_properties.end()); - methods.insert(nc_manager_method_handlers.begin(), nc_manager_method_handlers.end()); - } - else if (type == nmos::types::nc_device_manager) - { - properties.insert(nc_manager_properties.begin(), nc_manager_properties.end()); - properties.insert(nc_device_manager_properties.begin(), nc_device_manager_properties.end()); - methods.insert(nc_manager_method_handlers.begin(), nc_manager_method_handlers.end()); - methods.insert(nc_device_manager_method_handlers.begin(), nc_device_manager_method_handlers.end()); - } - else if (type == nmos::types::nc_class_manager) - { - properties.insert(nc_manager_properties.begin(), nc_manager_properties.end()); - properties.insert(nc_class_manager_properties.begin(), nc_class_manager_properties.end()); - methods.insert(nc_manager_method_handlers.begin(), nc_manager_method_handlers.end()); - methods.insert(nc_class_manager_method_handlers.begin(), nc_class_manager_method_handlers.end()); - } - - // hmm, add user properties - //if (!user_properties.empty()) - //{ - // properties.insert(user_properties.begin(), user_properties.end()); - //} - - // hmm, add user method handlers - //if (!user_methods.empty()) - //{ - // methods.insert(user_methods.begin(), user_methods.end()); - //} - - return std::pair(properties, methods); - }; - return [&model, &websockets, create_properties_methods, &gate_](const web::uri& connection_uri, const web::websockets::experimental::listener::connection_id& connection_id, const web::websockets::websocket_incoming_message& msg_) + return [&model, &websockets, get_control_protocol_classes, &gate_](const web::uri& connection_uri, const web::websockets::experimental::listener::connection_id& connection_id, const web::websockets::websocket_incoming_message& msg_) { nmos::ws_api_gate gate(gate_, connection_uri); @@ -508,8 +466,9 @@ namespace nmos auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); if (resources.end() != resource) { - // create properties and method handlers based on resource type - auto properties_methods = create_properties_methods(resource->type); + // create the combined properties and method handlers based on class_id + auto class_id = details::parse_nc_class_id(resource->data.at(nmos::fields::nc::class_id)); + auto properties_methods = details::create_properties_methods(model, class_id, get_control_protocol_classes()); auto& properties = properties_methods.first; auto& methods = properties_methods.second; @@ -518,7 +477,7 @@ namespace nmos if (method != methods.end()) { // execute the relevant method handler, then accumulating up their response to reponses - web::json::push_back(responses, method->second(properties, handle, oid, arguments)); + web::json::push_back(responses, method->second(properties.as_array(), handle, oid, arguments)); } else { diff --git a/Development/nmos/control_protocol_ws_api.h b/Development/nmos/control_protocol_ws_api.h index 2371616d1..61c434f38 100644 --- a/Development/nmos/control_protocol_ws_api.h +++ b/Development/nmos/control_protocol_ws_api.h @@ -1,6 +1,7 @@ #ifndef NMOS_CONTROL_PROTOCOL_WS_API_H #define NMOS_CONTROL_PROTOCOL_WS_API_H +#include "nmos/control_protocol_handlers.h" #include "nmos/websockets.h" namespace slog @@ -15,15 +16,15 @@ namespace nmos web::websockets::experimental::listener::validate_handler make_control_protocol_ws_validate_handler(nmos::node_model& model, slog::base_gate& gate); web::websockets::experimental::listener::open_handler make_control_protocol_ws_open_handler(nmos::node_model& model, nmos::websockets& websockets, slog::base_gate& gate); web::websockets::experimental::listener::close_handler make_control_protocol_ws_close_handler(nmos::node_model& model, nmos::websockets& websockets, slog::base_gate& gate); - web::websockets::experimental::listener::message_handler make_control_protocol_ws_message_handler(nmos::node_model& model, nmos::websockets& websockets, slog::base_gate& gate); + web::websockets::experimental::listener::message_handler make_control_protocol_ws_message_handler(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_classes_handler get_control_protocol_classes, slog::base_gate& gate); - inline web::websockets::experimental::listener::websocket_listener_handlers make_control_protocol_ws_api(nmos::node_model& model, nmos::websockets& websockets, slog::base_gate& gate) + inline web::websockets::experimental::listener::websocket_listener_handlers make_control_protocol_ws_api(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_classes_handler get_control_protocol_classes, slog::base_gate& gate) { return{ nmos::make_control_protocol_ws_validate_handler(model, gate), nmos::make_control_protocol_ws_open_handler(model, websockets, gate), nmos::make_control_protocol_ws_close_handler(model, websockets, gate), - nmos::make_control_protocol_ws_message_handler(model, websockets, gate) + nmos::make_control_protocol_ws_message_handler(model, websockets, get_control_protocol_classes, gate) }; } diff --git a/Development/nmos/node_server.cpp b/Development/nmos/node_server.cpp index 2de24d450..0ac70ee42 100644 --- a/Development/nmos/node_server.cpp +++ b/Development/nmos/node_server.cpp @@ -72,7 +72,7 @@ namespace nmos const auto& control_protocol_ws_port = nmos::fields::control_protocol_ws_port(node_model.settings); if (control_protocol_ws_port == events_ws_port) throw std::runtime_error("Same port used for events and control protocol websockets are not supported"); auto& control_protocol_ws_api = node_server.ws_handlers[{ {}, control_protocol_ws_port }]; - control_protocol_ws_api.first = nmos::make_control_protocol_ws_api(node_model, control_protocol_ws_api.second, gate); + control_protocol_ws_api.first = nmos::make_control_protocol_ws_api(node_model, control_protocol_ws_api.second, node_implementation.get_control_protocol_classes, gate); // Set up the listeners for each HTTP API port diff --git a/Development/nmos/node_server.h b/Development/nmos/node_server.h index dc8f4efa8..eb1b95bc7 100644 --- a/Development/nmos/node_server.h +++ b/Development/nmos/node_server.h @@ -6,6 +6,7 @@ #include "nmos/channelmapping_activation.h" #include "nmos/connection_api.h" #include "nmos/connection_activation.h" +#include "nmos/control_protocol_handlers.h" #include "nmos/node_behaviour.h" #include "nmos/node_system_behaviour.h" #include "nmos/ocsp_response_handler.h" @@ -24,7 +25,7 @@ namespace nmos // underlying implementation into the server instance for the NMOS Node struct node_implementation { - node_implementation(nmos::load_server_certificates_handler load_server_certificates, nmos::load_dh_param_handler load_dh_param, nmos::load_ca_certificates_handler load_ca_certificates, nmos::system_global_handler system_changed, nmos::registration_handler registration_changed, nmos::transport_file_parser parse_transport_file, nmos::details::connection_resource_patch_validator validate_staged, nmos::connection_resource_auto_resolver resolve_auto, nmos::connection_sender_transportfile_setter set_transportfile, nmos::connection_activation_handler connection_activated, nmos::ocsp_response_handler get_ocsp_response) + node_implementation(nmos::load_server_certificates_handler load_server_certificates, nmos::load_dh_param_handler load_dh_param, nmos::load_ca_certificates_handler load_ca_certificates, nmos::system_global_handler system_changed, nmos::registration_handler registration_changed, nmos::transport_file_parser parse_transport_file, nmos::details::connection_resource_patch_validator validate_staged, nmos::connection_resource_auto_resolver resolve_auto, nmos::connection_sender_transportfile_setter set_transportfile, nmos::connection_activation_handler connection_activated, nmos::ocsp_response_handler get_ocsp_response, nmos::get_control_protocol_classes_handler get_control_protocol_classes) : load_server_certificates(std::move(load_server_certificates)) , load_dh_param(std::move(load_dh_param)) , load_ca_certificates(std::move(load_ca_certificates)) @@ -36,6 +37,7 @@ namespace nmos , set_transportfile(std::move(set_transportfile)) , connection_activated(std::move(connection_activated)) , get_ocsp_response(std::move(get_ocsp_response)) + , get_control_protocol_classes(std::move(get_control_protocol_classes)) {} // use the default constructor and chaining member functions for fluent initialization @@ -57,6 +59,7 @@ namespace nmos node_implementation& on_validate_channelmapping_output_map(nmos::details::channelmapping_output_map_validator validate_map) { this->validate_map = std::move(validate_map); return *this; } node_implementation& on_channelmapping_activated(nmos::channelmapping_activation_handler channelmapping_activated) { this->channelmapping_activated = std::move(channelmapping_activated); return *this; } node_implementation& on_get_ocsp_response(nmos::ocsp_response_handler get_ocsp_response) { this->get_ocsp_response = std::move(get_ocsp_response); return *this; } + node_implementation& on_get_control_classes(nmos::get_control_protocol_classes_handler get_control_protocol_classes) { this->get_control_protocol_classes = std::move(get_control_protocol_classes); return* this; } // deprecated, use on_validate_connection_resource_patch node_implementation& on_validate_merged(nmos::details::connection_resource_patch_validator validate_merged) { return on_validate_connection_resource_patch(std::move(validate_merged)); } @@ -86,6 +89,8 @@ namespace nmos nmos::channelmapping_activation_handler channelmapping_activated; nmos::ocsp_response_handler get_ocsp_response; + + nmos::get_control_protocol_classes_handler get_control_protocol_classes; }; // Construct a server instance for an NMOS Node, implementing the IS-04 Node API, IS-05 Connection API, IS-07 Events API From eb71ebd85a85474aa2bd9ef039bd940c4818a11e Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 8 Aug 2023 16:45:50 +0100 Subject: [PATCH 008/106] Fix declaration of nmos::experimental::control_classes for Linux --- Development/nmos/control_protocol_state.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Development/nmos/control_protocol_state.h b/Development/nmos/control_protocol_state.h index 5a8b5e1ca..ad884733c 100644 --- a/Development/nmos/control_protocol_state.h +++ b/Development/nmos/control_protocol_state.h @@ -23,7 +23,7 @@ namespace nmos // mutex to be used to protect the members from simultaneous access by multiple threads mutable nmos::mutex mutex; - control_classes control_classes; + experimental::control_classes control_classes; nmos::read_lock read_lock() const { return nmos::read_lock{ mutex }; } nmos::write_lock write_lock() const { return nmos::write_lock{ mutex }; } From 212bdf41eff2c00a9f1fe02cf92fddc8e3f0d4ab Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 8 Aug 2023 16:46:45 +0100 Subject: [PATCH 009/106] Move functions around --- .../nmos/control_protocol_resource.cpp | 130 +++++++++--------- Development/nmos/control_protocol_resource.h | 37 +++-- 2 files changed, 82 insertions(+), 85 deletions(-) diff --git a/Development/nmos/control_protocol_resource.cpp b/Development/nmos/control_protocol_resource.cpp index 68f0273f4..3fddd49a4 100644 --- a/Development/nmos/control_protocol_resource.cpp +++ b/Development/nmos/control_protocol_resource.cpp @@ -70,7 +70,7 @@ namespace nmos { nmos::fields::nc::message_type, type }, { nmos::fields::nc::responses, responses } }); - }; + } // error message // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#error-messages @@ -83,7 +83,7 @@ namespace nmos { nmos::fields::nc::status, method_result.status}, { nmos::fields::nc::error_message, error_message } }); - }; + } // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassid web::json::value make_nc_class_id(const nc_class_id& class_id) @@ -390,67 +390,6 @@ namespace nmos return data; } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject - web::json::value make_nc_object(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints) - { - using web::json::value; - - const auto id = utility::conversions::details::to_string_t(oid); -// auto data = make_resource_core(id, user_label.is_null() ? U("") : user_label.as_string(), {}); - value data; - data[nmos::fields::id] = value::string(id); // required for nmos::resource - data[nmos::fields::nc::class_id] = make_nc_class_id(class_id); - data[nmos::fields::nc::oid] = oid; - data[nmos::fields::nc::constant_oid] = value::boolean(constant_oid); - data[nmos::fields::nc::owner] = owner; - data[nmos::fields::nc::role] = value::string(role); - data[nmos::fields::nc::user_label] = user_label; - data[nmos::fields::nc::touchpoints] = touchpoints; - data[nmos::fields::nc::runtime_property_constraints] = runtime_property_constraints; - - return data; - }; - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock - web::json::value make_nc_block(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled, const web::json::value& members) - { - using web::json::value; - - auto data = details::make_nc_object(class_id, oid, constant_oid, owner, role, user_label, touchpoints, runtime_property_constraints); - data[nmos::fields::nc::enabled] = value::boolean(enabled); - data[nmos::fields::nc::members] = members; - - return data; - } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanager - web::json::value make_nc_manager(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints) - { - return make_nc_object(class_id, oid, constant_oid, owner, role, user_label, touchpoints, runtime_property_constraints); - } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager - web::json::value make_nc_device_manager(nc_oid oid, nc_oid owner, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, - const web::json::value& manufacturer, const web::json::value& product, const utility::string_t& serial_number, - const web::json::value& user_inventory_code, const web::json::value& device_name, const web::json::value& device_role, const web::json::value& operational_state, nc_reset_cause::cause reset_cause) - { - using web::json::value; - - auto data = details::make_nc_manager(nc_device_manager_class_id, oid, true, owner, U("DeviceManager"), user_label, touchpoints, runtime_property_constraints); - data[nmos::fields::nc::nc_version] = value::string(U("v1.0")); - data[nmos::fields::nc::manufacturer] = manufacturer; - data[nmos::fields::nc::product] = product; - data[nmos::fields::nc::serial_number] = value::string(serial_number); - data[nmos::fields::nc::user_inventory_code] = user_inventory_code; - data[nmos::fields::nc::device_name] = device_name; - data[nmos::fields::nc::device_role] = device_role; - data[nmos::fields::nc::operational_state] = operational_state; - data[nmos::fields::nc::reset_cause] = reset_cause; - data[nmos::fields::nc::message] = value::null(); - - return data; - } - web::json::value make_nc_object_properties() { using web::json::value; @@ -480,8 +419,8 @@ namespace nmos } { auto parameters = value::array(); - web::json::push_back(parameters,make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); - web::json::push_back(parameters,make_nc_parameter_descriptor(value::string(U("Property value")), nmos::fields::nc::value, value::null(), true, false, value::null())); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Property value")), nmos::fields::nc::value, value::null(), true, false, value::null())); web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Set property value")), make_nc_method_id(1, 2), U("Set"), U("NcMethodResult"), parameters, false)); } { @@ -697,6 +636,67 @@ namespace nmos return value::array(); } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject + web::json::value make_nc_object(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints) + { + using web::json::value; + + const auto id = utility::conversions::details::to_string_t(oid); +// auto data = make_resource_core(id, user_label.is_null() ? U("") : user_label.as_string(), {}); + value data; + data[nmos::fields::id] = value::string(id); // required for nmos::resource + data[nmos::fields::nc::class_id] = make_nc_class_id(class_id); + data[nmos::fields::nc::oid] = oid; + data[nmos::fields::nc::constant_oid] = value::boolean(constant_oid); + data[nmos::fields::nc::owner] = owner; + data[nmos::fields::nc::role] = value::string(role); + data[nmos::fields::nc::user_label] = user_label; + data[nmos::fields::nc::touchpoints] = touchpoints; + data[nmos::fields::nc::runtime_property_constraints] = runtime_property_constraints; + + return data; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock + web::json::value make_nc_block(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled, const web::json::value& members) + { + using web::json::value; + + auto data = details::make_nc_object(class_id, oid, constant_oid, owner, role, user_label, touchpoints, runtime_property_constraints); + data[nmos::fields::nc::enabled] = value::boolean(enabled); + data[nmos::fields::nc::members] = members; + + return data; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanager + web::json::value make_nc_manager(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints) + { + return make_nc_object(class_id, oid, constant_oid, owner, role, user_label, touchpoints, runtime_property_constraints); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager + web::json::value make_nc_device_manager(nc_oid oid, nc_oid owner, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, + const web::json::value& manufacturer, const web::json::value& product, const utility::string_t& serial_number, + const web::json::value& user_inventory_code, const web::json::value& device_name, const web::json::value& device_role, const web::json::value& operational_state, nc_reset_cause::cause reset_cause) + { + using web::json::value; + + auto data = details::make_nc_manager(nc_device_manager_class_id, oid, true, owner, U("DeviceManager"), user_label, touchpoints, runtime_property_constraints); + data[nmos::fields::nc::nc_version] = value::string(U("v1.0")); + data[nmos::fields::nc::manufacturer] = manufacturer; + data[nmos::fields::nc::product] = product; + data[nmos::fields::nc::serial_number] = value::string(serial_number); + data[nmos::fields::nc::user_inventory_code] = user_inventory_code; + data[nmos::fields::nc::device_name] = device_name; + data[nmos::fields::nc::device_role] = device_role; + data[nmos::fields::nc::operational_state] = operational_state; + data[nmos::fields::nc::reset_cause] = reset_cause; + data[nmos::fields::nc::message] = value::null(); + + return data; + } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager web::json::value make_nc_class_manager(nc_oid oid, nc_oid owner, const web::json::value& user_label) { diff --git a/Development/nmos/control_protocol_resource.h b/Development/nmos/control_protocol_resource.h index bfecdd8e0..dc1d7673c 100644 --- a/Development/nmos/control_protocol_resource.h +++ b/Development/nmos/control_protocol_resource.h @@ -137,9 +137,6 @@ namespace nmos typedef std::map properties; -// typedef std::function method; -// typedef std::map methods; // method_id vs method handler - typedef std::function method; typedef std::map methods; // method_id vs method handler @@ -267,23 +264,6 @@ namespace nmos // constraints can be null web::json::value make_nc_datatype_typedef(const web::json::value& description, const utility::string_t& name, const web::json::value& constraints, const utility::string_t& parent_type, bool is_sequence); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject - web::json::value make_nc_object(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints); - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock - web::json::value make_nc_block(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled, const web::json::value& members); - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanager - web::json::value make_nc_manager(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null()); - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager - web::json::value make_nc_device_manager(nc_oid oid, nc_oid owner, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, - const web::json::value& manufacturer, const web::json::value& product, const utility::string_t& serial_number, - const web::json::value& user_inventory_code, const web::json::value& device_name, const web::json::value& device_role, const web::json::value& operational_state, nc_reset_cause::cause reset_cause); - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager - web::json::value make_nc_class_manager(details::nc_oid oid, nc_oid owner, const web::json::value& user_label); - // make the core classes proprties/methods/events web::json::value make_nc_object_properties(); web::json::value make_nc_object_methods(); @@ -303,6 +283,23 @@ namespace nmos web::json::value make_nc_class_manager_properties(); web::json::value make_nc_class_manager_methods(); web::json::value make_nc_class_manager_events(); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject + web::json::value make_nc_object(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock + web::json::value make_nc_block(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled, const web::json::value& members); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanager + web::json::value make_nc_manager(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null()); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager + web::json::value make_nc_device_manager(nc_oid oid, nc_oid owner, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, + const web::json::value& manufacturer, const web::json::value& product, const utility::string_t& serial_number, + const web::json::value& user_inventory_code, const web::json::value& device_name, const web::json::value& device_role, const web::json::value& operational_state, nc_reset_cause::cause reset_cause); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager + web::json::value make_nc_class_manager(details::nc_oid oid, nc_oid owner, const web::json::value& user_label); } } From bb873477e48442597b9bf96ded4b91df4ed3d3ee Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 8 Aug 2023 17:18:48 +0100 Subject: [PATCH 010/106] Update IS-12 schemas --- .../is-12/v1.0.x/APIs/schemas/command-message.json | 9 +++------ .../is-12/v1.0.x/APIs/schemas/notification-message.json | 9 +++------ .../v1.0.x/APIs/schemas/property-changed-event-data.json | 6 ++---- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/Development/third_party/is-12/v1.0.x/APIs/schemas/command-message.json b/Development/third_party/is-12/v1.0.x/APIs/schemas/command-message.json index cce540fa0..093b69eda 100644 --- a/Development/third_party/is-12/v1.0.x/APIs/schemas/command-message.json +++ b/Development/third_party/is-12/v1.0.x/APIs/schemas/command-message.json @@ -34,8 +34,7 @@ "oid": { "type": "integer", "description": "Object id containing the method", - "minimum": 1, - "maximum": 65535 + "minimum": 1 }, "methodId": { "type": "object", @@ -48,14 +47,12 @@ "level": { "type": "integer", "description": "Level component of the method ID", - "minimum": 0, - "maximum": 65535 + "minimum": 1 }, "index": { "type": "integer", "description": "Index component of the method ID", - "minimum": 1, - "maximum": 65535 + "minimum": 1 } } }, diff --git a/Development/third_party/is-12/v1.0.x/APIs/schemas/notification-message.json b/Development/third_party/is-12/v1.0.x/APIs/schemas/notification-message.json index c8a64e81d..860770eb4 100644 --- a/Development/third_party/is-12/v1.0.x/APIs/schemas/notification-message.json +++ b/Development/third_party/is-12/v1.0.x/APIs/schemas/notification-message.json @@ -28,8 +28,7 @@ "oid": { "type": "integer", "description": "Emitter object id", - "minimum": 1, - "maximum": 65535 + "minimum": 1 }, "eventId": { "type": "object", @@ -42,14 +41,12 @@ "level": { "type": "integer", "description": "Level component of the event ID", - "minimum": 0, - "maximum": 65535 + "minimum": 1 }, "index": { "type": "integer", "description": "Index component of the event ID", - "minimum": 1, - "maximum": 65535 + "minimum": 1 } } }, diff --git a/Development/third_party/is-12/v1.0.x/APIs/schemas/property-changed-event-data.json b/Development/third_party/is-12/v1.0.x/APIs/schemas/property-changed-event-data.json index 62249e306..7d6be6f1a 100644 --- a/Development/third_party/is-12/v1.0.x/APIs/schemas/property-changed-event-data.json +++ b/Development/third_party/is-12/v1.0.x/APIs/schemas/property-changed-event-data.json @@ -15,14 +15,12 @@ "level": { "type": "integer", "description": "Level component of the property ID", - "minimum": 0, - "maximum": 65535 + "minimum": 1 }, "index": { "type": "integer", "description": "Index component of the property ID", - "minimum": 1, - "maximum": 65535 + "minimum": 1 } } }, From 2aba14ac7a168c34e7a0478e6d3525288356dc74 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 8 Aug 2023 20:13:55 +0100 Subject: [PATCH 011/106] Tidy up make_nc_class_manager --- .../nmos/control_protocol_resource.cpp | 738 ++++++++++++------ 1 file changed, 494 insertions(+), 244 deletions(-) diff --git a/Development/nmos/control_protocol_resource.cpp b/Development/nmos/control_protocol_resource.cpp index 3fddd49a4..b46dbcdf0 100644 --- a/Development/nmos/control_protocol_resource.cpp +++ b/Development/nmos/control_protocol_resource.cpp @@ -636,6 +636,453 @@ namespace nmos return value::array(); } + web::json::value make_nc_object_class() + { + using web::json::value; + + return make_nc_class_descriptor(value::string(U("NcObject class descriptor")), nc_object_class_id, U("NcObject"), value::null(), make_nc_object_properties(), make_nc_object_methods(), make_nc_object_events()); + } + + web::json::value make_nc_block_class() + { + using web::json::value; + + return make_nc_class_descriptor(value::string(U("NcBlock class descriptor")), nc_block_class_id, U("NcBlock"), value::null(), make_nc_block_properties(), make_nc_block_methods(), make_nc_block_events()); + } + + web::json::value make_nc_worker_class() + { + using web::json::value; + + return make_nc_class_descriptor(value::string(U("NcWorker class descriptor")), nc_worker_class_id, U("NcWorker"), value::null(), make_nc_worker_properties(), make_nc_worker_methods(), make_nc_worker_events()); + } + + web::json::value make_nc_manager_class() + { + using web::json::value; + + return make_nc_class_descriptor(value::string(U("NcManager class descriptor")), nc_manager_class_id, U("NcManager"), value::null(), make_nc_manager_properties(), make_nc_manager_methods(), make_nc_manager_events()); + } + + web::json::value make_nc_device_manager_class() + { + using web::json::value; + + return make_nc_class_descriptor(value::string(U("NcDeviceManager class descriptor")), nc_device_manager_class_id, U("NcDeviceManager"), value::string(U("DeviceManager")), make_nc_device_manager_properties(), make_nc_device_manager_methods(), make_nc_device_manager_events()); + } + + web::json::value make_nc_class_manager_class() + { + using web::json::value; + + return make_nc_class_descriptor(value::string(U("NcClassManager class descriptor")), nc_class_manager_class_id, U("NcClassManager"), value::string(U("ClassManager")), make_nc_class_manager_properties(), make_nc_class_manager_methods(), make_nc_class_manager_events()); + } + + web::json::value make_nc_class_id_datatype() + { + using web::json::value; + + return make_nc_datatype_typedef(value::string(U("Sequence of class ID fields")), U("NcClassId"), value::null(), U("NcInt32"), true); + } + + web::json::value make_nc_oid_datatype() + { + using web::json::value; + + return make_nc_datatype_typedef(value::string(U("Object id")), U("NcOid"), value::null(), U("NcUint32"), false); + } + + web::json::value make_nc_touchpoint_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Context namespace")), nmos::fields::nc::context_namespace, value::string(U("NcString")), false, false, value::null())); + return make_nc_datatype_descriptor_struct(value::string(U("Base touchpoint class")), U("NcTouchpoint"), value::null(), fields, value::null()); + } + + web::json::value make_nc_element_id_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Level of the element")), nmos::fields::nc::level, value::string(U("NcUint16")), false, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Index of the element")), nmos::fields::nc::index, value::string(U("NcUint16")), false, false, value::null())); + return make_nc_datatype_descriptor_struct(value::string(U("Class element id which contains the level and index")), U("NcElementId"), value::null(), fields, value::null()); + } + + web::json::value make_nc_property_id_datatype() + { + using web::json::value; + + return make_nc_datatype_descriptor_struct(value::string(U("Property id which contains the level and index")), U("NcPropertyId"), value::null(), value::array(), value::string(U("NcElementId"))); + } + + web::json::value make_nc_property_contraints_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("The id of the property being constrained")), nmos::fields::nc::property_id, value::string(U("NcPropertyId")), false, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Optional default value")), nmos::fields::nc::default_value, value::null(), true, false, value::null())); + return make_nc_datatype_descriptor_struct(value::string(U("Property constraints class")), U("NcPropertyConstraints"), value::null(), fields, value::null()); + } + + web::json::value make_nc_method_result_property_value_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Getter method value for the associated property")), nmos::fields::nc::value, value::null(), true, false, value::null())); + return make_nc_datatype_descriptor_struct(value::string(U("Result when invoking the getter method associated with a property")), U("NcMethodResultPropertyValue"), value::null(), fields, value::string(U("NcMethodResult"))); + } + + web::json::value make_nc_method_status_datatype() + { + using web::json::value; + + auto items = value::array(); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Method call was successful")), U("Ok"), 200)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Method call was successful but targeted property is deprecated")), U("PropertyDeprecated"), 298)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Method call was successful but method is deprecated")), U("MethodDeprecated"), 299)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Badly-formed command (e.g. the incoming command has invalid message encoding and cannot be parsed by the underlying protocol)")), U("BadCommandFormat"), 400)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Client is not authorized")), U("Unauthorized"), 401)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Command addresses a nonexistent object")), U("BadOid"), 404)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Attempt to change read-only state")), U("Readonly"), 405)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Method call is invalid in current operating context (e.g. attempting to invoke a method when the object is disabled)")), U("InvalidRequest"), 406)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("There is a conflict with the current state of the device")), U("Conflict"), 409)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Something was too big")), U("BufferOverflow"), 413)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Index is outside the available range")), U("IndexOutOfBounds"), 414)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Method parameter does not meet expectations (e.g. attempting to invoke a method with an invalid type for one of its parameters)")), U("ParameterError"), 417)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Addressed object is locked")), U("Locked"), 423)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Internal device error")), U("DeviceError"), 500)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Addressed method is not implemented by the addressed object")), U("MethodNotImplemented"), 501)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Addressed property is not implemented by the addressed object")), U("PropertyNotImplemented"), 502)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("The device is not ready to handle any commands")), U("NotReady"), 503)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Method call did not finish within the allotted time")), U("Timeout"), 504)); + return make_nc_datatype_descriptor_enum(value::string(U("Method invokation status")), U("NcMethodStatus"), value::null(), items); + } + + web::json::value make_nc_method_result_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Status for the invoked method")), nmos::fields::nc::status, value::string(U("NcMethodStatus")), false, false, value::null())); + return make_nc_datatype_descriptor_struct(value::string(U("Base result of the invoked method")), U("NcMethodResult"), value::null(), fields, value::null()); + } + + web::json::value make_nc_id_datatype() + { + using web::json::value; + + return make_nc_datatype_typedef(value::string(U("Identity handler")), U("NcId"), value::null(), U("NcUint32"), false); + } + + web::json::value make_nc_method_result_id_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Id result value")), nmos::fields::nc::value, value::string(U("NcId")), false, false, value::null())); + return make_nc_datatype_descriptor_struct(value::string(U("Id method result")), U("NcMethodResultId"), value::null(), fields, value::string(U("NcMethodResult"))); + } + + web::json::value make_method_result_length_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Length result value")), nmos::fields::nc::value, value::string(U("NcUint32")), true, false, value::null())); + return make_nc_datatype_descriptor_struct(value::string(U("Length method result")), U("NcMethodResultLength"), value::null(), fields, value::string(U("NcMethodResult"))); + } + + web::json::value make_nc_property_change_type_datatype() + { + using web::json::value; + + auto items = value::array(); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Current value changed")), U("ValueChanged"), 0)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Sequence item added")), U("SequenceItemAdded"), 1)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Sequence item changed")), U("SequenceItemChanged"), 2)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Sequence item removed")), U("SequenceItemRemoved"), 3)); + return make_nc_datatype_descriptor_enum(value::string(U("Type of property change")), U("NcPropertyChangeType"), value::null(), items); + } + + web::json::value make_nc_property_changed_event_data_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("The id of the property that changed")), nmos::fields::nc::property_id, value::string(U("NcPropertyId")), false, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Information regarding the change type")), nmos::fields::nc::change_type, value::string(U("NcPropertyChangeType")), false, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Property-type specific value")), nmos::fields::nc::value, value::null(), true, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Index of sequence item if the property is a sequence")), nmos::fields::nc::sequence_item_index, value::string(U("NcId")), true, false, value::null())); + return make_nc_datatype_descriptor_struct(value::string(U("Payload of property-changed event")), U("NcPropertyChangedEventData"), value::null(), fields, value::null()); + } + + web::json::value make_nc_descriptor_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Optional user facing description")), nmos::fields::nc::description, value::string(U("NcString")), true, false, value::null())); + return make_nc_datatype_descriptor_struct(value::string(U("Base descriptor")), U("NcDescriptor"), value::null(), fields, value::null()); + } + + web::json::value make_nc_block_member_descriptor_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Role of member in its containing block")), nmos::fields::nc::role, value::string(U("NcString")), false, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("OID of member")), nmos::fields::nc::oid, value::string(U("NcOid")), false, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff member's OID is hardwired into device")), nmos::fields::nc::constant_oid, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Class ID")), nmos::fields::nc::class_id, value::string(U("NcClassId")), false, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("User label")), nmos::fields::nc::user_label, value::string(U("NcString")), true, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Containing block's OID")), nmos::fields::nc::owner, value::string(U("NcOid")), false, false, value::null())); + return make_nc_datatype_descriptor_struct(value::string(U("Descriptor which is specific to a block member")), U("NcBlockMemberDescriptor"), value::null(), fields, value::string(U("NcDescriptor"))); + } + + web::json::value make_nc_method_result_block_member_descriptors_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Block member descriptors method result value")), nmos::fields::nc::value, value::string(U("NcBlockMemberDescriptor")), false, true, value::null())); + return make_nc_datatype_descriptor_struct(value::string(U("Method result containing block member descriptors as the value")), U("NcMethodResultBlockMemberDescriptors"), value::null(), fields, value::string(U("NcMethodResult"))); + } + + web::json::value make_nc_version_code_datatype() + { + using web::json::value; + + return make_nc_datatype_typedef(value::string(U("Version code in semantic versioning format")), U("NcVersionCode"), value::null(), U("NcString"), false); + } + + web::json::value make_nc_organization_id_datatype() + { + using web::json::value; + + return make_nc_datatype_typedef(value::string(U("Unique 24-bit organization id")), U("NcOrganizationId"), value::null(), U("NcInt32"), false); + } + + web::json::value make_nc_uri_datatype() + { + using web::json::value; + + return make_nc_datatype_typedef(value::string(U("Uniform resource identifier")), U("NcUri"), value::null(), U("NcString"), false); + } + + web::json::value make_nc_manufacturer_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Manufacturer's name")), nmos::fields::nc::name, value::string(U("NcString")), false, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("IEEE OUI or CID of manufacturer")), nmos::fields::nc::organization_id, value::string(U("NcOrganizationId")), true, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("URL of the manufacturer's website")), nmos::fields::nc::website, value::string(U("NcUri")), true, false, value::null())); + return make_nc_datatype_descriptor_struct(value::string(U("Manufacturer descriptor")), U("NcManufacturer"), value::null(), fields, value::null()); + } + + web::json::value make_nc_uuid_datatype() + { + using web::json::value; + + return make_nc_datatype_typedef(value::string(U("UUID")), U("NcUuid"), value::null(), U("NcString"), false); + } + + web::json::value make_nc_product_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Product name")), nmos::fields::nc::name, value::string(U("NcString")), false, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Manufacturer's unique key to product - model number, SKU, etc")), nmos::fields::nc::key, value::string(U("NcString")), false, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Manufacturer's product revision level code")), nmos::fields::nc::revision_level, value::string(U("NcString")), false, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Brand name under which product is sold")), nmos::fields::nc::brand_name, value::string(U("NcString")), true, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Unique UUID of product (not product instance)")), nmos::fields::nc::uuid, value::string(U("NcUuid")), true, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Text description of product")), nmos::fields::nc::description, value::string(U("NcString")), true, false, value::null())); + return make_nc_datatype_descriptor_struct(value::string(U("Product descriptor")), U("NcProduct"), value::null(), fields, value::null()); + } + + web::json::value make_nc_device_generic_state_datatype() + { + using web::json::value; + + auto items = value::array(); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Unknown")), U("Unknown"), 0)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Normal operation")), U("NormalOperation"), 1)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Device is initializing")), U("Initializing"), 2)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Device is performing a software or firmware update")), U("Updating"), 3)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Device is experiencing a licensing error")), U("LicensingError"), 4)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Device is experiencing an internal error")), U("InternalError"), 5)); + return make_nc_datatype_descriptor_enum(value::string(U("Device generic operational state")), U("NcDeviceGenericState"), value::null(), items); + } + + web::json::value make_nc_device_operational_state_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Generic operational state")), nmos::fields::nc::generic_state, value::string(U("NcDeviceGenericState")), false, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Specific device details")), nmos::fields::nc::device_specific_details, value::string(U("NcString")), true, false, value::null())); + return make_nc_datatype_descriptor_struct(value::string(U("Device operational state")), U("NcDeviceOperationalState"), value::null(), fields, value::null()); + } + + web::json::value make_nc_reset_cause_datatype() + { + using web::json::value; + + auto items = value::array(); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Unknown")), U("Unknown"), 0)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Power on")), U("PowerOn"), 1)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Internal error")), U("InternalError"), 2)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Upgrade")), U("Upgrade"), 3)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Controller request")), U("ControllerRequest"), 4)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Manual request from the front panel")), U("ManualReset"), 5)); + return make_nc_datatype_descriptor_enum(value::string(U("Reset cause enum")), U("NcResetCause"), value::null(), items); + } + + web::json::value make_nc_name_datatype() + { + using web::json::value; + + return make_nc_datatype_typedef(value::string(U("Programmatically significant name, alphanumerics + underscore, no spaces")), U("NcName"), value::null(), U("NcString"), false); + } + + web::json::value make_nc_property_descriptor_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Property id with level and index")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of property")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of property's datatype. Can only ever be null if the type is any")), nmos::fields::nc::type_name, value::string(U("NcName")), true, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff property is read-only")), nmos::fields::nc::is_read_only, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff property is nullable")), nmos::fields::nc::is_nullable, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff property is a sequence")), nmos::fields::nc::is_sequence, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff property is marked as deprecated")), nmos::fields::nc::is_deprecated, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Optional constraints on top of the underlying data type")), nmos::fields::nc::constraints, value::string(U("NcParameterConstraints")), true, false, value::null())); + return make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class property")), U("NcPropertyDescriptor"), value::null(), fields, value::string(U("NcDescriptor"))); + } + + web::json::value make_nc_parameter_descriptor_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of parameter")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of parameter's datatype. Can only ever be null if the type is any")), nmos::fields::nc::type_name, value::string(U("NcName")), true, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff property is nullable")), nmos::fields::nc::is_nullable, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff property is a sequence")), nmos::fields::nc::is_sequence, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Optional constraints on top of the underlying data type")), nmos::fields::nc::constraints, value::string(U("NcParameterConstraints")), true, false, value::null())); + return make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a method parameter")), U("NcParameterDescriptor"), value::null(), fields, value::string(U("NcDescriptor"))); + } + + web::json::value make_nc_method_id_datatype() + { + using web::json::value; + + return make_nc_datatype_descriptor_struct(value::string(U("Method id which contains the level and index")), U("NcMethodId"), value::null(), value::array(), value::string(U("NcElementId"))); + } + + web::json::value make_nc_method_descriptor_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Method id with level and index")), nmos::fields::nc::id, value::string(U("NcMethodId")), false, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of method")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of method result's datatype")), nmos::fields::nc::result_datatype, value::string(U("NcName")), false, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Parameter descriptors if any")), nmos::fields::nc::parameters, value::string(U("NcParameterDescriptor")), false, true, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff property is marked as deprecated")), nmos::fields::nc::is_deprecated, value::string(U("NcBoolean")), false, false, value::null())); + return make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class method")), U("NcMethodDescriptor"), value::null(), fields, value::string(U("NcDescriptor"))); + } + + web::json::value make_nc_event_id_datatype() + { + using web::json::value; + + return make_nc_datatype_descriptor_struct(value::string(U("Event id which contains the level and index")), U("NcEventId"), value::null(), value::array(), value::string(U("NcElementId"))); + } + + web::json::value make_nc_event_descriptor_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Event id with level and index")), nmos::fields::nc::id, value::string(U("NcEventId")), false, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of event")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of event data's datatype")), nmos::fields::nc::event_datatype, value::string(U("NcName")), false, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff property is marked as deprecated")), nmos::fields::nc::is_deprecated, value::string(U("NcBoolean")), false, false, value::null())); + return make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class event")), U("NcEventDescriptor"), value::null(), fields, value::string(U("NcDescriptor"))); + } + + web::json::value make_nc_class_descriptor_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Identity of the class")), nmos::fields::nc::class_id, value::string(U("NcClassId")), false, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of the class")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Role if the class has fixed role (manager classes)")), nmos::fields::nc::fixed_role, value::string(U("NcString")), true, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Property descriptors")), nmos::fields::nc::properties, value::string(U("NcPropertyDescriptor")), false, true, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Method descriptors")), nmos::fields::nc::methods, value::string(U("NcMethodDescriptor")), false, true, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Event descriptors")), nmos::fields::nc::events, value::string(U("NcEventDescriptor")), false, true, value::null())); + return make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class")), U("NcClassDescriptor"), value::null(), fields, value::string(U("NcDescriptor"))); + } + + web::json::value make_nc_parameter_constraints_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Default value")), nmos::fields::nc::default_value, value::null(), true, false, value::null())); + return make_nc_datatype_descriptor_struct(value::string(U("Abstract parameter constraints class")), U("NcParameterConstraints"), value::null(), fields, value::null()); + } + + web::json::value make_nc_datatype_type_datatype() + { + using web::json::value; + + auto items = value::array(); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Primitive datatype")), U("Primitive"), 0)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Simple alias of another datatype")), U("Typedef"), 1)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Data structure")), U("Struct"), 2)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Enum datatype")), U("Enum"), 3)); + return make_nc_datatype_descriptor_enum(value::string(U("Datatype type")), U("NcDatatypeType"), value::null(), items); + } + + web::json::value make_nc_datatype_descriptor_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Datatype name")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Type: Primitive, Typedef, Struct, Enum")), nmos::fields::nc::type, value::string(U("NcDatatypeType")), false, false, value::null())); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Optional constraints on top of the underlying data type")), nmos::fields::nc::constraints, value::string(U("NcParameterConstraints")), true, false, value::null())); + return make_nc_datatype_descriptor_struct(value::string(U("Base datatype descriptor")), U("NcDatatypeDescriptor"), value::null(), fields, value::string(U("NcDescriptor"))); + } + + web::json::value make_nc_method_result_class_descriptor_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Class descriptor method result value")), nmos::fields::nc::value, value::string(U("NcClassDescriptor")), false, false, value::null())); + return make_nc_datatype_descriptor_struct(value::string(U("Method result containing a class descriptor as the value")), U("NcMethodResultClassDescriptor"), value::null(), fields, value::string(U("NcMethodResult"))); + } + + web::json::value make_nc_method_result_datatype_descriptor_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Datatype descriptor method result value")), nmos::fields::nc::value, value::string(U("NcDatatypeDescriptor")), false, false, value::null())); + return make_nc_datatype_descriptor_struct(value::string(U("Method result containing a datatype descriptor as the value")), U("NcMethodResultDatatypeDescriptor"), value::null(), fields, value::string(U("NcMethodResult"))); + } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject web::json::value make_nc_object(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints) { @@ -704,149 +1151,64 @@ namespace nmos auto data = make_nc_manager(nc_class_manager_class_id, oid, true, owner, U("ClassManager"), user_label); - // load the minimal control classes + // minimal control classes data[nmos::fields::nc::control_classes] = value::array(); auto& control_classes = data[nmos::fields::nc::control_classes]; // NcObject control class - web::json::push_back(control_classes, details::make_nc_class_descriptor(value::string(U("NcObject class descriptor")), nc_object_class_id, U("NcObject"), value::null(), make_nc_object_properties(), make_nc_object_methods(), make_nc_object_events())); + web::json::push_back(control_classes, make_nc_object_class()); // NcBlock control class - web::json::push_back(control_classes, details::make_nc_class_descriptor(value::string(U("NcBlock class descriptor")), nc_block_class_id, U("NcBlock"), value::null(), make_nc_block_properties(), make_nc_block_methods(), make_nc_block_events())); + web::json::push_back(control_classes, make_nc_block_class()); // NcWorker control class - web::json::push_back(control_classes, details::make_nc_class_descriptor(value::string(U("NcWorker class descriptor")), nc_worker_class_id, U("NcWorker"), value::null(), make_nc_worker_properties(), make_nc_worker_methods(), make_nc_worker_events())); + web::json::push_back(control_classes, make_nc_worker_class()); // NcManager control class - web::json::push_back(control_classes, details::make_nc_class_descriptor(value::string(U("NcManager class descriptor")), nc_manager_class_id, U("NcManager"), value::null(), make_nc_manager_properties(), make_nc_manager_methods(), make_nc_manager_events())); + web::json::push_back(control_classes, make_nc_manager_class()); // NcDeviceManager control class - web::json::push_back(control_classes, details::make_nc_class_descriptor(value::string(U("NcDeviceManager class descriptor")), nc_device_manager_class_id, U("NcDeviceManager"), value::string(U("DeviceManager")), make_nc_device_manager_properties(), make_nc_device_manager_methods(), make_nc_device_manager_events())); + web::json::push_back(control_classes, make_nc_device_manager_class()); // NcClassManager control class - web::json::push_back(control_classes, details::make_nc_class_descriptor(value::string(U("NcClassManager class descriptor")), nc_class_manager_class_id, U("NcClassManager"), value::string(U("ClassManager")), make_nc_class_manager_properties(), make_nc_class_manager_methods(), make_nc_class_manager_events())); + web::json::push_back(control_classes, make_nc_class_manager_class()); - // load the minimal datatypes + // minimal datatypes data[nmos::fields::nc::datatypes] = value::array(); auto& datatypes = data[nmos::fields::nc::datatypes]; // NcObject datatypes // NcClassId - web::json::push_back(datatypes, details::make_nc_datatype_typedef(value::string(U("Sequence of class ID fields")), U("NcClassId"), value::null(), U("NcInt32"), true)); + web::json::push_back(datatypes, make_nc_class_id_datatype()); // NcOid - web::json::push_back(datatypes, details::make_nc_datatype_typedef(value::string(U("Object id")), U("NcOid"), value::null(), U("NcUint32"), false)); + web::json::push_back(datatypes, make_nc_oid_datatype()); // NcTouchpoint - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Context namespace")), nmos::fields::nc::context_namespace, value::string(U("NcString")), false, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Base touchpoint class")), U("NcTouchpoint"), value::null(), fields, value::null())); - } + web::json::push_back(datatypes, make_nc_touchpoint_datatype()); // NcElementId - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Level of the element")), nmos::fields::nc::level, value::string(U("NcUint16")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Index of the element")), nmos::fields::nc::index, value::string(U("NcUint16")), false, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Class element id which contains the level and index")), U("NcElementId"), value::null(), fields, value::null())); - } + web::json::push_back(datatypes, make_nc_element_id_datatype()); // NcPropertyId - { - auto fields = value::array(); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Property id which contains the level and index")), U("NcPropertyId"), value::null(), fields, value::string(U("NcElementId")))); - } + web::json::push_back(datatypes, make_nc_property_id_datatype()); // NcPropertyConstraints - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("The id of the property being constrained")), nmos::fields::nc::property_id, value::string(U("NcPropertyId")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional default value")), nmos::fields::nc::default_value, value::null(), true, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Property constraints class")), U("NcPropertyConstraints"), value::null(), fields, value::null())); - } + web::json::push_back(datatypes, make_nc_property_contraints_datatype()); // NcMethodResultPropertyValue - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Getter method value for the associated property")), nmos::fields::nc::value, value::null(), true, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Result when invoking the getter method associated with a property")), U("NcMethodResultPropertyValue"), value::null(), fields, value::string(U("NcMethodResult")))); - } + web::json::push_back(datatypes, make_nc_method_result_property_value_datatype()); // NcMethodStatus - { - auto items = value::array(); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method call was successful")), U("Ok"), 200)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method call was successful but targeted property is deprecated")), U("PropertyDeprecated"), 298)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method call was successful but method is deprecated")), U("MethodDeprecated"), 299)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Badly-formed command (e.g. the incoming command has invalid message encoding and cannot be parsed by the underlying protocol)")), U("BadCommandFormat"), 400)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Client is not authorized")), U("Unauthorized"), 401)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Command addresses a nonexistent object")), U("BadOid"), 404)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Attempt to change read-only state")), U("Readonly"), 405)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method call is invalid in current operating context (e.g. attempting to invoke a method when the object is disabled)")), U("InvalidRequest"), 406)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("There is a conflict with the current state of the device")), U("Conflict"), 409)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Something was too big")), U("BufferOverflow"), 413)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Index is outside the available range")), U("IndexOutOfBounds"), 414)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method parameter does not meet expectations (e.g. attempting to invoke a method with an invalid type for one of its parameters)")), U("ParameterError"), 417)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Addressed object is locked")), U("Locked"), 423)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Internal device error")), U("DeviceError"), 500)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Addressed method is not implemented by the addressed object")), U("MethodNotImplemented"), 501)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Addressed property is not implemented by the addressed object")), U("PropertyNotImplemented"), 502)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("The device is not ready to handle any commands")), U("NotReady"), 503)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method call did not finish within the allotted time")), U("Timeout"), 504)); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_enum(value::string(U("Method invokation status")), U("NcMethodStatus"), value::null(), items)); - } + web::json::push_back(datatypes, make_nc_method_status_datatype()); // NcMethodResult - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Status for the invoked method")), nmos::fields::nc::status, value::string(U("NcMethodStatus")), false, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Base result of the invoked method")), U("NcMethodResult"), value::null(), fields, value::null())); - } + web::json::push_back(datatypes, make_nc_method_result_datatype()); // NcId - web::json::push_back(datatypes, details::make_nc_datatype_typedef(value::string(U("Identity handler")), U("NcId"), value::null(), U("NcUint32"), false)); + web::json::push_back(datatypes, make_nc_id_datatype()); // NcMethodResultId - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Id result value")), nmos::fields::nc::value, value::string(U("NcId")), false, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Id method result")), U("NcMethodResultId"), value::null(), fields, value::string(U("NcMethodResult")))); - } + web::json::push_back(datatypes, make_nc_method_result_id_datatype()); // NcMethodResultLength - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Length result value")), nmos::fields::nc::value, value::string(U("NcUint32")), true, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Length method result")), U("NcMethodResultLength"), value::null(), fields, value::string(U("NcMethodResult")))); - } + web::json::push_back(datatypes, make_method_result_length_datatype()); // NcPropertyChangeType - { - auto items = value::array(); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Current value changed")), U("ValueChanged"), 0)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Sequence item added")), U("SequenceItemAdded"), 1)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Sequence item changed")), U("SequenceItemChanged"), 2)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Sequence item removed")), U("SequenceItemRemoved"), 3)); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_enum(value::string(U("Type of property change")), U("NcPropertyChangeType"), value::null(), items)); - } + web::json::push_back(datatypes, make_nc_property_change_type_datatype()); // NcPropertyChangedEventData - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("The id of the property that changed")), nmos::fields::nc::property_id, value::string(U("NcPropertyId")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Information regarding the change type")), nmos::fields::nc::change_type, value::string(U("NcPropertyChangeType")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Property-type specific value")), nmos::fields::nc::value, value::null(), true, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Index of sequence item if the property is a sequence")), nmos::fields::nc::sequence_item_index, value::string(U("NcId")), true, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Payload of property-changed event")), U("NcPropertyChangedEventData"), value::null(), fields, value::null())); - } + web::json::push_back(datatypes, make_nc_property_changed_event_data_datatype()); // NcBlock datatypes // NcDescriptor - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional user facing description")), nmos::fields::nc::description, value::string(U("NcString")), true, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Base descriptor")), U("NcDescriptor"), value::null(), fields, value::null())); - } + web::json::push_back(datatypes, make_nc_descriptor_datatype()); // NcBlockMemberDescriptor - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Role of member in its containing block")), nmos::fields::nc::role, value::string(U("NcString")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("OID of member")), nmos::fields::nc::oid, value::string(U("NcOid")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff member's OID is hardwired into device")), nmos::fields::nc::constant_oid, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Class ID")), nmos::fields::nc::class_id, value::string(U("NcClassId")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("User label")), nmos::fields::nc::user_label, value::string(U("NcString")), true, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Containing block's OID")), nmos::fields::nc::owner, value::string(U("NcOid")), false, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor which is specific to a block member")), U("NcBlockMemberDescriptor"), value::null(), fields, value::string(U("NcDescriptor")))); - } + web::json::push_back(datatypes, make_nc_block_member_descriptor_datatype()); // NcMethodResultBlockMemberDescriptors - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Block member descriptors method result value")), nmos::fields::nc::value, value::string(U("NcBlockMemberDescriptor")), false, true, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Method result containing block member descriptors as the value")), U("NcMethodResultBlockMemberDescriptors"), value::null(), fields, value::string(U("NcMethodResult")))); - } + web::json::push_back(datatypes, make_nc_method_result_block_member_descriptors_datatype()); // NcWorker has no datatypes @@ -854,163 +1216,51 @@ namespace nmos // NcDeviceManager datatypes // NcVersionCode - web::json::push_back(datatypes, details::make_nc_datatype_typedef(value::string(U("Version code in semantic versioning format")), U("NcVersionCode"), value::null(), U("NcString"), false)); + web::json::push_back(datatypes, make_nc_version_code_datatype()); // NcOrganizationId - web::json::push_back(datatypes, details::make_nc_datatype_typedef(value::string(U("Unique 24-bit organization id")), U("NcOrganizationId"), value::null(), U("NcInt32"), false)); + web::json::push_back(datatypes, make_nc_organization_id_datatype()); // NcUri - web::json::push_back(datatypes, details::make_nc_datatype_typedef(value::string(U("Uniform resource identifier")), U("NcUri"), value::null(), U("NcString"), false)); + web::json::push_back(datatypes, make_nc_uri_datatype()); // NcManufacturer - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Manufacturer's name")), nmos::fields::nc::name, value::string(U("NcString")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("IEEE OUI or CID of manufacturer")), nmos::fields::nc::organization_id, value::string(U("NcOrganizationId")), true, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("URL of the manufacturer's website")), nmos::fields::nc::website, value::string(U("NcUri")), true, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Manufacturer descriptor")), U("NcManufacturer"), value::null(), fields, value::null())); - } + web::json::push_back(datatypes, make_nc_manufacturer_datatype()); // NcUuid - web::json::push_back(datatypes, details::make_nc_datatype_typedef(value::string(U("UUID")), U("NcUuid"), value::null(), U("NcString"), false)); + web::json::push_back(datatypes, make_nc_uuid_datatype()); // NcProduct - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Product name")), nmos::fields::nc::name, value::string(U("NcString")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Manufacturer's unique key to product - model number, SKU, etc")), nmos::fields::nc::key, value::string(U("NcString")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Manufacturer's product revision level code")), nmos::fields::nc::revision_level, value::string(U("NcString")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Brand name under which product is sold")), nmos::fields::nc::brand_name, value::string(U("NcString")), true, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Unique UUID of product (not product instance)")), nmos::fields::nc::uuid, value::string(U("NcUuid")), true, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Text description of product")), nmos::fields::nc::description, value::string(U("NcString")), true, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Product descriptor")), U("NcProduct"), value::null(), fields, value::null())); - } + web::json::push_back(datatypes, make_nc_product_datatype()); // NcDeviceGenericState - { - auto items = value::array(); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Unknown")), U("Unknown"), 0)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Normal operation")), U("NormalOperation"), 1)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Device is initializing")), U("Initializing"), 2)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Device is performing a software or firmware update")), U("Updating"), 3)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Device is experiencing a licensing error")), U("LicensingError"), 4)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Device is experiencing an internal error")), U("InternalError"), 5)); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_enum(value::string(U("Device generic operational state")), U("NcDeviceGenericState"), value::null(), items)); - } + web::json::push_back(datatypes, make_nc_device_generic_state_datatype()); // NcDeviceOperationalState - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Generic operational state")), nmos::fields::nc::generic_state, value::string(U("NcDeviceGenericState")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Specific device details")), nmos::fields::nc::device_specific_details, value::string(U("NcString")), true, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Device operational state")), U("NcDeviceOperationalState"), value::null(), fields, value::null())); - } + web::json::push_back(datatypes, make_nc_device_operational_state_datatype()); // NcResetCause - { - auto items = value::array(); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Unknown")), U("Unknown"), 0)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Power on")), U("PowerOn"), 1)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Internal error")), U("InternalError"), 2)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Upgrade")), U("Upgrade"), 3)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Controller request")), U("ControllerRequest"), 4)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Manual request from the front panel")), U("ManualReset"), 5)); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_enum(value::string(U("Reset cause enum")), U("NcResetCause"), value::null(), items)); - } + web::json::push_back(datatypes, make_nc_reset_cause_datatype()); // NcClassManager datatypes // NcName - web::json::push_back(datatypes, details::make_nc_datatype_typedef(value::string(U("Programmatically significant name, alphanumerics + underscore, no spaces")), U("NcName"), value::null(), U("NcString"), false)); + web::json::push_back(datatypes, make_nc_name_datatype()); // NcPropertyDescriptor - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Property id with level and index")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of property")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of property's datatype. Can only ever be null if the type is any")), nmos::fields::nc::type_name, value::string(U("NcName")), true, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is read-only")), nmos::fields::nc::is_read_only, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is nullable")), nmos::fields::nc::is_nullable, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is a sequence")), nmos::fields::nc::is_sequence, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is marked as deprecated")), nmos::fields::nc::is_deprecated, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional constraints on top of the underlying data type")), nmos::fields::nc::constraints, value::string(U("NcParameterConstraints")), true, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class property")), U("NcPropertyDescriptor"), value::null(), fields, value::string(U("NcDescriptor")))); - } + web::json::push_back(datatypes, make_nc_property_descriptor_datatype()); // NcMethodId - { - auto fields = value::array(); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Method id which contains the level and index")), U("NcMethodId"), value::null(), fields, value::string(U("NcElementId")))); - } + web::json::push_back(datatypes, make_nc_method_id_datatype()); // NcParameterDescriptor - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of parameter")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of parameter's datatype. Can only ever be null if the type is any")), nmos::fields::nc::type_name, value::string(U("NcName")), true, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is nullable")), nmos::fields::nc::is_nullable, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is a sequence")), nmos::fields::nc::is_sequence, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional constraints on top of the underlying data type")), nmos::fields::nc::constraints, value::string(U("NcParameterConstraints")), true, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a method parameter")), U("NcParameterDescriptor"), value::null(), fields, value::string(U("NcDescriptor")))); - } + web::json::push_back(datatypes, make_nc_parameter_descriptor_datatype()); // NcMethodDescriptor - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Method id with level and index")), nmos::fields::nc::id, value::string(U("NcMethodId")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of method")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of method result's datatype")), nmos::fields::nc::result_datatype, value::string(U("NcName")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Parameter descriptors if any")), nmos::fields::nc::parameters, value::string(U("NcParameterDescriptor")), false, true, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is marked as deprecated")), nmos::fields::nc::is_deprecated, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class method")), U("NcMethodDescriptor"), value::null(), fields, value::string(U("NcDescriptor")))); - } + web::json::push_back(datatypes, make_nc_method_descriptor_datatype()); // NcEventId - { - auto fields = value::array(); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Event id which contains the level and index")), U("NcEventId"), value::null(), fields, value::string(U("NcElementId")))); - } + web::json::push_back(datatypes, make_nc_event_id_datatype()); // NcEventDescriptor - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Event id with level and index")), nmos::fields::nc::id, value::string(U("NcEventId")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of event")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of event data's datatype")), nmos::fields::nc::event_datatype, value::string(U("NcName")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is marked as deprecated")), nmos::fields::nc::is_deprecated, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class event")), U("NcEventDescriptor"), value::null(), fields, value::string(U("NcDescriptor")))); - } + web::json::push_back(datatypes, make_nc_event_descriptor_datatype()); // NcClassDescriptor - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Identity of the class")), nmos::fields::nc::class_id, value::string(U("NcClassId")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of the class")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Role if the class has fixed role (manager classes)")), nmos::fields::nc::fixed_role, value::string(U("NcString")), true, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Property descriptors")), nmos::fields::nc::properties, value::string(U("NcPropertyDescriptor")), false, true, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Method descriptors")), nmos::fields::nc::methods, value::string(U("NcMethodDescriptor")), false, true, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Event descriptors")), nmos::fields::nc::events, value::string(U("NcEventDescriptor")), false, true, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class")), U("NcClassDescriptor"), value::null(), fields, value::string(U("NcDescriptor")))); - } + web::json::push_back(datatypes, make_nc_class_descriptor_datatype()); // NcParameterConstraints - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Default value")), nmos::fields::nc::default_value, value::null(), true, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Abstract parameter constraints class")), U("NcParameterConstraints"), value::null(), fields, value::null())); - } + web::json::push_back(datatypes, make_nc_parameter_constraints_datatype()); // NcDatatypeType - { - auto items = value::array(); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Primitive datatype")), U("Primitive"), 0)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Simple alias of another datatype")), U("Typedef"), 1)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Data structure")), U("Struct"), 2)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Enum datatype")), U("Enum"), 3)); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_enum(value::string(U("Datatype type")), U("NcDatatypeType"), value::null(), items)); - } + web::json::push_back(datatypes, make_nc_datatype_type_datatype()); // NcDatatypeDescriptor - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Datatype name")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Type: Primitive, Typedef, Struct, Enum")), nmos::fields::nc::type, value::string(U("NcDatatypeType")), false, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional constraints on top of the underlying data type")), nmos::fields::nc::constraints, value::string(U("NcParameterConstraints")), true, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Base datatype descriptor")), U("NcDatatypeDescriptor"), value::null(), fields, value::string(U("NcDescriptor")))); - } + web::json::push_back(datatypes, make_nc_datatype_descriptor_datatype()); // NcMethodResultClassDescriptor - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Class descriptor method result value")), nmos::fields::nc::value, value::string(U("NcClassDescriptor")), false, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Method result containing a class descriptor as the value")), U("NcMethodResultClassDescriptor"), value::null(), fields, value::string(U("NcMethodResult")))); - } + web::json::push_back(datatypes, make_nc_method_result_class_descriptor_datatype()); // NcMethodResultDatatypeDescriptor - { - auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Datatype descriptor method result value")), nmos::fields::nc::value, value::string(U("NcDatatypeDescriptor")), false, false, value::null())); - web::json::push_back(datatypes, details::make_nc_datatype_descriptor_struct(value::string(U("Method result containing a datatype descriptor as the value")), U("NcMethodResultDatatypeDescriptor"), value::null(), fields, value::string(U("NcMethodResult")))); - } + web::json::push_back(datatypes, make_nc_method_result_datatype_descriptor_datatype()); return data; } From 71f97b5b22ac371df09750cce8083345e246a074 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 8 Aug 2023 21:25:59 +0100 Subject: [PATCH 012/106] Add NcObject's GetSequenceItem --- Development/nmos/control_protocol_ws_api.cpp | 78 +++++++++++++++++--- 1 file changed, 66 insertions(+), 12 deletions(-) diff --git a/Development/nmos/control_protocol_ws_api.cpp b/Development/nmos/control_protocol_ws_api.cpp index 6639bcc93..a8a6965ed 100644 --- a/Development/nmos/control_protocol_ws_api.cpp +++ b/Development/nmos/control_protocol_ws_api.cpp @@ -54,7 +54,7 @@ namespace nmos // hmm, methods should also be passing in via the control_class::methods // NcObject methods implementation - // get property + // Get property auto get = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -79,16 +79,16 @@ namespace nmos // unknown property utility::stringstream_t ss; - ss << U("unknown property: ") << property_id.serialize() << " to do get"; + ss << U("unknown property: ") << property_id.serialize() << " to do Get"; return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); } // resource not found for the given oid utility::stringstream_t ss; - ss << U("unknown oid: ") << oid << " to do get"; + ss << U("unknown oid: ") << oid << " to do Get"; return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; - // set property + // Set property auto set = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -125,13 +125,67 @@ namespace nmos // unknown property utility::stringstream_t ss; - ss << U("unknown property: ") << property_id.serialize() << " to do set"; + ss << U("unknown property: ") << property_id.serialize() << " to do Set"; return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); } // resource not found for the given oid utility::stringstream_t ss; - ss << U("unknown oid: ") << oid << " to do set"; + ss << U("unknown oid: ") << oid << " to do Set"; + return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); + }; + // GetSequenceItem + auto get_sequence_item = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + auto& resources = model.control_protocol_resources; + auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); + if (resources.end() != resource) + { + const auto& property_id = nmos::fields::nc::id(arguments); + const auto& index = nmos::fields::nc::index(arguments); + + // find the relevant nc_property_descriptor + auto property_found = std::find_if(properties.begin(), properties.end(), [property_id](const web::json::value& property) + { + return property_id == nmos::fields::nc::id(property); + }); + + if (property_found != properties.end()) + { + if (nmos::fields::nc::is_sequence(*property_found)) + { + auto& data = resource->data.at(nmos::fields::nc::name(*property_found)); + + if (!data.is_null() && data.as_array().size() > index) + { + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, data.at(index)); + } + + // out of bound + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << " is outside the available range to do GetSequenceItem"; + return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); + } + else + { + // property is not a sequence + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << " is not a sequence to do GetSequenceItem"; + return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); + } + } + + // unknown property + utility::stringstream_t ss; + ss << U("unknown property: ") << property_id.serialize() << " to do GetSequenceItem"; + return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); + } + + // resource not found for the given oid + utility::stringstream_t ss; + ss << U("unknown oid: ") << oid << " to do get"; return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; @@ -181,30 +235,30 @@ namespace nmos // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 1 } })] = get; nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 2 } })] = set; - //nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 3 } })] = get_sequence_item; + nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 3 } })] = get_sequence_item; //nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 4 } })] = set_sequence_item; //nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 5 } })] = add_sequence_item; //nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 6 } })] = remove_sequence_item; //nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 7 } })] = get_sequence_length; // NcBlock methods - // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 1 } })] = get_member_descriptors; //nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 2 } })] = find_members_by_path; //nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 3 } })] = find_members_by_role; //nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 4 } })] = find_members_by_class_id; // NcWorker has no extended method - // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncworker + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncworker // NcManager has no extended method - // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanager + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanager // NcDeviceManger has no extended method - // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager // NcClassManager methods - // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager //nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 1 } })] = get_control_class; //nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 2 } })] = get_datatype; From 6e1640f002602570774473af6b507c0d0f9d9561 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 8 Aug 2023 22:56:28 +0100 Subject: [PATCH 013/106] Fix GetSequenceItem and add GetSequenceLength --- Development/nmos/control_protocol_resource.h | 1 + Development/nmos/control_protocol_ws_api.cpp | 78 ++++++++++++++++++-- 2 files changed, 73 insertions(+), 6 deletions(-) diff --git a/Development/nmos/control_protocol_resource.h b/Development/nmos/control_protocol_resource.h index dc1d7673c..a3a13b8cd 100644 --- a/Development/nmos/control_protocol_resource.h +++ b/Development/nmos/control_protocol_resource.h @@ -44,6 +44,7 @@ namespace nmos invalid_request = 406, // Method call is invalid in current operating context conflict = 409, // There is a conflict with the current state of the device buffer_overflow = 413, // Something was too big + index_out_of_bounds = 414, // Index is outside the available range parameter_error = 417, // Method parameter does not meet expectations locked = 423, // Addressed object is locked device_error = 500, // Internal device error diff --git a/Development/nmos/control_protocol_ws_api.cpp b/Development/nmos/control_protocol_ws_api.cpp index a8a6965ed..036030bd9 100644 --- a/Development/nmos/control_protocol_ws_api.cpp +++ b/Development/nmos/control_protocol_ws_api.cpp @@ -54,7 +54,7 @@ namespace nmos // hmm, methods should also be passing in via the control_class::methods // NcObject methods implementation - // Get property + // Get property value auto get = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -88,7 +88,7 @@ namespace nmos ss << U("unknown oid: ") << oid << " to do Get"; return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; - // Set property + // Set property value auto set = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -134,7 +134,7 @@ namespace nmos ss << U("unknown oid: ") << oid << " to do Set"; return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; - // GetSequenceItem + // Get sequence item auto get_sequence_item = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -166,7 +166,7 @@ namespace nmos // out of bound utility::stringstream_t ss; ss << U("property: ") << property_id.serialize() << " is outside the available range to do GetSequenceItem"; - return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); + return details::make_control_protocol_error_response(handle, { details::nc_method_status::index_out_of_bounds }, ss.str()); } else { @@ -188,9 +188,74 @@ namespace nmos ss << U("unknown oid: ") << oid << " to do get"; return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; + // Get sequence length + auto get_sequence_length = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + auto& resources = model.control_protocol_resources; + auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); + if (resources.end() != resource) + { + const auto& property_id = nmos::fields::nc::id(arguments); + + // find the relevant nc_property_descriptor + auto property_found = std::find_if(properties.begin(), properties.end(), [property_id](const web::json::value& property) + { + return property_id == nmos::fields::nc::id(property); + }); + + if (property_found != properties.end()) + { + if (nmos::fields::nc::is_sequence(*property_found)) + { + auto& data = resource->data.at(nmos::fields::nc::name(*property_found)); + + if (nmos::fields::nc::is_nullable(*property_found)) + { + // can be null + if (data.is_null()) + { + // null + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, value::null()); + } + } + else + { + // cannot be null + if (data.is_null()) + { + // null + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << " is a null sequence to do GetSequenceLength"; + return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); + } + } + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, data.as_array().size()); + } + else + { + // property is not a sequence + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << " is not a sequence to do GetSequenceLength"; + return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); + } + } + + // unknown property + utility::stringstream_t ss; + ss << U("unknown property: ") << property_id.serialize() << " to do GetSequenceItem"; + return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); + } + + // resource not found for the given oid + utility::stringstream_t ss; + ss << U("unknown oid: ") << oid << " to do get"; + return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); + }; // NcBlock methods implementation - // get descriptors of members of the block + // Gets descriptors of members of the block auto get_member_descriptors = [&model](const web::json::array&, int32_t handle, int32_t oid, const value& arguments) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -213,6 +278,7 @@ namespace nmos }; // NcClassManager methods implementation + // Get a single class descriptor auto get_control_class = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments) { // hmm, todo @@ -239,7 +305,7 @@ namespace nmos //nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 4 } })] = set_sequence_item; //nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 5 } })] = add_sequence_item; //nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 6 } })] = remove_sequence_item; - //nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 7 } })] = get_sequence_length; + nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 7 } })] = get_sequence_length; // NcBlock methods // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock From a4455bc0be716fbc7ed2af790706a9b9dd4f1e98 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Wed, 9 Aug 2023 17:42:15 +0100 Subject: [PATCH 014/106] Code tidy up --- Development/nmos/control_protocol_resource.cpp | 16 ++++++++-------- Development/nmos/control_protocol_resource.h | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Development/nmos/control_protocol_resource.cpp b/Development/nmos/control_protocol_resource.cpp index b46dbcdf0..3377f1682 100644 --- a/Development/nmos/control_protocol_resource.cpp +++ b/Development/nmos/control_protocol_resource.cpp @@ -7,7 +7,7 @@ namespace nmos { namespace details { - web::json::value make_control_protocol_result(const nc_method_result& method_result) + web::json::value make_nc_method_result(const nc_method_result& method_result) { using web::json::value_of; @@ -16,16 +16,16 @@ namespace nmos }); } - web::json::value make_control_protocol_error_result(const nc_method_result& method_result, const utility::string_t& error_message) + web::json::value make_nc_method_result_error(const nc_method_result& method_result, const utility::string_t& error_message) { - auto result = make_control_protocol_result(method_result); + auto result = make_nc_method_result(method_result); if (!error_message.empty()) { result[nmos::fields::nc::error_message] = web::json::value::string(error_message); } return result; } - web::json::value make_control_protocol_result(const nc_method_result& method_result, const web::json::value& value) + web::json::value make_nc_method_result(const nc_method_result& method_result, const web::json::value& value) { - auto result = make_control_protocol_result(method_result); + auto result = make_nc_method_result(method_result); result[nmos::fields::nc::value] = value; return result; } @@ -36,7 +36,7 @@ namespace nmos return value_of({ { nmos::fields::nc::handle, handle }, - { nmos::fields::nc::result, make_control_protocol_error_result(method_result, error_message) } + { nmos::fields::nc::result, make_nc_method_result_error(method_result, error_message) } }); } @@ -46,7 +46,7 @@ namespace nmos return value_of({ { nmos::fields::nc::handle, handle }, - { nmos::fields::nc::result, make_control_protocol_result(method_result) } + { nmos::fields::nc::result, make_nc_method_result(method_result) } }); } @@ -56,7 +56,7 @@ namespace nmos return value_of({ { nmos::fields::nc::handle, handle }, - { nmos::fields::nc::result, make_control_protocol_result(method_result, value) } + { nmos::fields::nc::result, make_nc_method_result(method_result, value) } }); } diff --git a/Development/nmos/control_protocol_resource.h b/Development/nmos/control_protocol_resource.h index a3a13b8cd..458178d7b 100644 --- a/Development/nmos/control_protocol_resource.h +++ b/Development/nmos/control_protocol_resource.h @@ -141,14 +141,14 @@ namespace nmos typedef std::function method; typedef std::map methods; // method_id vs method handler - web::json::value make_control_protocol_result(const nc_method_result& method_result); - web::json::value make_control_protocol_error_result(const nc_method_result& method_result, const utility::string_t& error_message); - - web::json::value make_control_protocol_result(const nc_method_result& method_result, const web::json::value& value); web::json::value make_control_protocol_error_response(int32_t handle, const nc_method_result& method_result, const utility::string_t& error_message); web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result); + // value can be + // sequence + // NcClassDescriptor + // NcDatatypeDescriptor web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result, const web::json::value& value); // message response From bbf260496a88cb003d2a8c826a8111c340fa76bd Mon Sep 17 00:00:00 2001 From: lo-simon Date: Wed, 9 Aug 2023 17:44:20 +0100 Subject: [PATCH 015/106] Add SetSequenceItem, AddSequenceItem, RemoveSequenceItem, FindMembersByPath --- Development/nmos/control_protocol_ws_api.cpp | 293 ++++++++++++++++--- 1 file changed, 253 insertions(+), 40 deletions(-) diff --git a/Development/nmos/control_protocol_ws_api.cpp b/Development/nmos/control_protocol_ws_api.cpp index 036030bd9..6b0d6d157 100644 --- a/Development/nmos/control_protocol_ws_api.cpp +++ b/Development/nmos/control_protocol_ws_api.cpp @@ -55,7 +55,7 @@ namespace nmos // NcObject methods implementation // Get property value - auto get = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments) + const auto get = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -89,7 +89,7 @@ namespace nmos return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; // Set property value - auto set = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments) + const auto set = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -107,20 +107,24 @@ namespace nmos }); if (property_found != properties.end()) { - if (!nmos::fields::nc::is_read_only(*property_found)) + if (nmos::fields::nc::is_read_only(*property_found)) { - resources.modify(resource, [&](nmos::resource& resource) - { - resource.data[nmos::fields::nc::name(*property_found)] = val; - - resource.updated = strictly_increasing_update(resources); - }); - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }); + return details::make_control_protocol_response(handle, { details::nc_method_status::read_only }); } - else + + if ((val.is_null() && !nmos::fields::nc::is_nullable(*property_found)) + || (val.is_array() && !nmos::fields::nc::is_sequence(*property_found))) { - return details::make_control_protocol_response(handle, { details::nc_method_status::read_only }); + return details::make_control_protocol_response(handle, { details::nc_method_status::parameter_error }); } + + resources.modify(resource, [&](nmos::resource& resource) + { + resource.data[nmos::fields::nc::name(*property_found)] = val; + + resource.updated = strictly_increasing_update(resources); + }); + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }); } // unknown property @@ -135,7 +139,7 @@ namespace nmos return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; // Get sequence item - auto get_sequence_item = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments) + const auto get_sequence_item = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -154,42 +158,187 @@ namespace nmos if (property_found != properties.end()) { - if (nmos::fields::nc::is_sequence(*property_found)) - { - auto& data = resource->data.at(nmos::fields::nc::name(*property_found)); - - if (!data.is_null() && data.as_array().size() > index) - { - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, data.at(index)); - } - - // out of bound - utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << " is outside the available range to do GetSequenceItem"; - return details::make_control_protocol_error_response(handle, { details::nc_method_status::index_out_of_bounds }, ss.str()); - } - else + if (!nmos::fields::nc::is_sequence(*property_found)) { // property is not a sequence utility::stringstream_t ss; ss << U("property: ") << property_id.serialize() << " is not a sequence to do GetSequenceItem"; return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); } + + auto& data = resource->data.at(nmos::fields::nc::name(*property_found)); + + if (!data.is_null() && data.as_array().size() > index) + { + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, data.at(index)); + } + + // out of bound + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << " is outside the available range to do GetSequenceItem"; + return details::make_control_protocol_error_response(handle, { details::nc_method_status::index_out_of_bounds }, ss.str()); } // unknown property utility::stringstream_t ss; - ss << U("unknown property: ") << property_id.serialize() << " to do GetSequenceItem"; + ss << U("unknown property: ") << property_id.serialize( + ) << " to do GetSequenceItem"; return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); } // resource not found for the given oid utility::stringstream_t ss; - ss << U("unknown oid: ") << oid << " to do get"; + ss << U("unknown oid: ") << oid << " to do GetSequenceItem"; + return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); + }; + // Set sequence item + const auto set_sequence_item = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + auto& resources = model.control_protocol_resources; + auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); + if (resources.end() != resource) + { + const auto& property_id = nmos::fields::nc::id(arguments); + const auto& index = nmos::fields::nc::index(arguments); + const auto& val = nmos::fields::nc::value(arguments); + + // find the relevant nc_property_descriptor + auto property_found = std::find_if(properties.begin(), properties.end(), [property_id](const web::json::value& property) + { + return property_id == nmos::fields::nc::id(property); + }); + + if (!nmos::fields::nc::is_sequence(*property_found)) + { + // property is not a sequence + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << " is not a sequence to do SetSequenceItem"; + return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); + } + + auto& data = resource->data.at(nmos::fields::nc::name(*property_found)); + + if (!data.is_null() && data.as_array().size() > index) + { + resources.modify(resource, [&](nmos::resource& resource) + { + resource.data[nmos::fields::nc::name(*property_found)][index] = val; + + resource.updated = strictly_increasing_update(resources); + }); + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }); + } + + // out of bound + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << " is outside the available range to do SetSequenceItem"; + return details::make_control_protocol_error_response(handle, { details::nc_method_status::index_out_of_bounds }, ss.str()); + } + + // resource not found for the given oid + utility::stringstream_t ss; + ss << U("unknown oid: ") << oid << " to do SetSequenceItem"; + return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); + }; + // Add item to sequence + const auto add_sequence_item = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + auto& resources = model.control_protocol_resources; + auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); + if (resources.end() != resource) + { + const auto& property_id = nmos::fields::nc::id(arguments); + const auto& val = nmos::fields::nc::value(arguments); + + // find the relevant nc_property_descriptor + auto property_found = std::find_if(properties.begin(), properties.end(), [property_id](const web::json::value& property) + { + return property_id == nmos::fields::nc::id(property); + }); + + if (!nmos::fields::nc::is_sequence(*property_found)) + { + // property is not a sequence + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << " is not a sequence to do AddSequenceItem"; + return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); + } + + auto& data = resource->data.at(nmos::fields::nc::name(*property_found)); + + resources.modify(resource, [&](nmos::resource& resource) + { + auto& sequence = resource.data[nmos::fields::nc::name(*property_found)]; + if (data.is_null()) { sequence = value::array(); } + web::json::push_back(sequence, val); + + resource.updated = strictly_increasing_update(resources); + }); + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, data.as_array().size() - 1); + } + + // resource not found for the given oid + utility::stringstream_t ss; + ss << U("unknown oid: ") << oid << " to do AddSequenceItem"; + return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); + }; + // Delete sequence item + const auto remove_sequence_item = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + auto& resources = model.control_protocol_resources; + auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); + if (resources.end() != resource) + { + const auto& property_id = nmos::fields::nc::id(arguments); + const auto& index = nmos::fields::nc::index(arguments); + + // find the relevant nc_property_descriptor + auto property_found = std::find_if(properties.begin(), properties.end(), [property_id](const web::json::value& property) + { + return property_id == nmos::fields::nc::id(property); + }); + + if (!nmos::fields::nc::is_sequence(*property_found)) + { + // property is not a sequence + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << " is not a sequence to do RemoveSequenceItem"; + return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); + } + + auto& data = resource->data.at(nmos::fields::nc::name(*property_found)); + + if (!data.is_null() && data.as_array().size() > index) + { + resources.modify(resource, [&](nmos::resource& resource) + { + auto& sequence = resource.data[nmos::fields::nc::name(*property_found)].as_array(); + sequence.erase(index); + + resource.updated = strictly_increasing_update(resources); + }); + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }); + } + + // out of bound + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << " is outside the available range to do RemoveSequenceItem"; + return details::make_control_protocol_error_response(handle, { details::nc_method_status::index_out_of_bounds }, ss.str()); + } + + // resource not found for the given oid + utility::stringstream_t ss; + ss << U("unknown oid: ") << oid << " to do RemoveSequenceItem"; return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; // Get sequence length - auto get_sequence_length = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments) + const auto get_sequence_length = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -244,19 +393,19 @@ namespace nmos // unknown property utility::stringstream_t ss; - ss << U("unknown property: ") << property_id.serialize() << " to do GetSequenceItem"; + ss << U("unknown property: ") << property_id.serialize() << " to do GetSequenceLength"; return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); } // resource not found for the given oid utility::stringstream_t ss; - ss << U("unknown oid: ") << oid << " to do get"; + ss << U("unknown oid: ") << oid << " to do GetSequenceLength"; return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; // NcBlock methods implementation // Gets descriptors of members of the block - auto get_member_descriptors = [&model](const web::json::array&, int32_t handle, int32_t oid, const value& arguments) + const auto get_member_descriptors = [&model](const web::json::array&, int32_t handle, int32_t oid, const value& arguments) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -273,13 +422,77 @@ namespace nmos // resource not found for the given oid utility::stringstream_t ss; - ss << U("unknown oid: ") << oid << " to get member descriptors"; + ss << U("unknown oid: ") << oid << " to do GetMemberDescriptors"; + return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); + }; + // Finds member(s) by path + const auto find_members_by_path = [&model](const web::json::array&, int32_t handle, int32_t oid, const value& arguments) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + auto& resources = model.control_protocol_resources; + + auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); + if (resources.end() != resource) + { + // Relative path to search for (MUST not include the role of the block targeted by oid) + const auto& path = nmos::fields::nc::path(arguments); + + if (0 == path.size()) + { + // empty path + return details::make_control_protocol_error_response(handle, { details::nc_method_status::parameter_error }, U("empty path to do FindMembersByPath")); + } + + value nc_block_member_descriptor; + + for (const auto& role : path) + { + // look for the role in members + if (resource->data.has_field(nmos::fields::nc::members)) + { + auto& members = nmos::fields::nc::members(resource->data); + auto member_found = std::find_if(members.begin(), members.end(), [&](const web::json::value& nc_block_member_descriptor) + { + return role.as_string() == nmos::fields::nc::role(nc_block_member_descriptor); + }); + + if (members.end() != member_found) + { + nc_block_member_descriptor = *member_found; + + // use oid to look for next resource + resource = nmos::find_resource(resources, utility::s2us(std::to_string(nmos::fields::nc::oid(*member_found)))); + } + else + { + // should + // no role + utility::stringstream_t ss; + ss << U("role: ") << role.as_string() << U(" not found to do FindMembersByPath"); + return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); + } + } + else + { + // should + // no members + return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, U("no members to do FindMembersByPath")); + } + } + + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, nc_block_member_descriptor); + } + + // resource not found for the given oid + utility::stringstream_t ss; + ss << U("unknown oid: ") << oid << " to do FindMembersByPath"; return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; // NcClassManager methods implementation // Get a single class descriptor - auto get_control_class = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments) + const auto get_control_class = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments) { // hmm, todo @@ -302,15 +515,15 @@ namespace nmos nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 1 } })] = get; nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 2 } })] = set; nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 3 } })] = get_sequence_item; - //nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 4 } })] = set_sequence_item; - //nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 5 } })] = add_sequence_item; - //nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 6 } })] = remove_sequence_item; + nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 4 } })] = set_sequence_item; + nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 5 } })] = add_sequence_item; + nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 6 } })] = remove_sequence_item; nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 7 } })] = get_sequence_length; // NcBlock methods // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 1 } })] = get_member_descriptors; - //nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 2 } })] = find_members_by_path; + nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 2 } })] = find_members_by_path; //nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 3 } })] = find_members_by_role; //nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 4 } })] = find_members_by_class_id; From b5cbfc765adaac460ab216115252ab1246da681f Mon Sep 17 00:00:00 2001 From: lo-simon Date: Wed, 9 Aug 2023 22:23:18 +0100 Subject: [PATCH 016/106] Fix AddSequenceItem --- Development/nmos/control_protocol_resource.cpp | 7 +++++++ Development/nmos/control_protocol_resource.h | 1 + Development/nmos/control_protocol_ws_api.cpp | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Development/nmos/control_protocol_resource.cpp b/Development/nmos/control_protocol_resource.cpp index 3377f1682..974c51aba 100644 --- a/Development/nmos/control_protocol_resource.cpp +++ b/Development/nmos/control_protocol_resource.cpp @@ -60,6 +60,13 @@ namespace nmos }); } + web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result, uint32_t value_) + { + using web::json::value; + + return make_control_protocol_response(handle, method_result, value(value_)); + } + // message response // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#command-message-type web::json::value make_control_protocol_message_response(nc_message_type::type type, const web::json::value& responses) diff --git a/Development/nmos/control_protocol_resource.h b/Development/nmos/control_protocol_resource.h index 458178d7b..dca604afa 100644 --- a/Development/nmos/control_protocol_resource.h +++ b/Development/nmos/control_protocol_resource.h @@ -66,6 +66,7 @@ namespace nmos web::json::value make_control_protocol_error_response(int32_t handle, const nc_method_result& method_result, const utility::string_t& error_message); web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result); web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result, const web::json::value& value); + web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result, uint32_t value); // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#command-message-type web::json::value make_control_protocol_message_response(nc_message_type::type type, const web::json::value& responses); diff --git a/Development/nmos/control_protocol_ws_api.cpp b/Development/nmos/control_protocol_ws_api.cpp index 6b0d6d157..30ff1e4c7 100644 --- a/Development/nmos/control_protocol_ws_api.cpp +++ b/Development/nmos/control_protocol_ws_api.cpp @@ -278,7 +278,7 @@ namespace nmos resource.updated = strictly_increasing_update(resources); }); - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, data.as_array().size() - 1); + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, uint32_t(data.as_array().size() - 1)); } // resource not found for the given oid From 4eab0e0e59a5a58f9214a655893d751aa10eaf22 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Thu, 10 Aug 2023 11:04:16 +0100 Subject: [PATCH 017/106] Fix FindMembersByPath --- Development/nmos/control_protocol_ws_api.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Development/nmos/control_protocol_ws_api.cpp b/Development/nmos/control_protocol_ws_api.cpp index 30ff1e4c7..a92e73fc9 100644 --- a/Development/nmos/control_protocol_ws_api.cpp +++ b/Development/nmos/control_protocol_ws_api.cpp @@ -1,6 +1,8 @@ #include "nmos/control_protocol_ws_api.h" +#include #include +#include "bst/regex.h" #include "cpprest/json_validator.h" #include "cpprest/regex_utils.h" #include "nmos/api_utils.h" @@ -380,7 +382,7 @@ namespace nmos return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); } } - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, data.as_array().size()); + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, uint32_t(data.as_array().size())); } else { @@ -417,6 +419,7 @@ namespace nmos // hmm, If recurse is set to true, nested members is to be retrieved const auto& recurse = nmos::fields::nc::recurse(arguments); + // return the descriptors of members of the block return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, resource->data.at(nmos::fields::nc::members)); } @@ -444,7 +447,7 @@ namespace nmos return details::make_control_protocol_error_response(handle, { details::nc_method_status::parameter_error }, U("empty path to do FindMembersByPath")); } - value nc_block_member_descriptor; + auto nc_block_member_descriptors = value::array(); for (const auto& role : path) { @@ -459,14 +462,13 @@ namespace nmos if (members.end() != member_found) { - nc_block_member_descriptor = *member_found; + web::json::push_back(nc_block_member_descriptors, *member_found); - // use oid to look for next resource + // use oid to look for the next resource resource = nmos::find_resource(resources, utility::s2us(std::to_string(nmos::fields::nc::oid(*member_found)))); } else { - // should // no role utility::stringstream_t ss; ss << U("role: ") << role.as_string() << U(" not found to do FindMembersByPath"); @@ -475,13 +477,12 @@ namespace nmos } else { - // should // no members return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, U("no members to do FindMembersByPath")); } } - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, nc_block_member_descriptor); + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, nc_block_member_descriptors); } // resource not found for the given oid From 5eeaa3b7e4734c83f4685cac8c50697b702547de Mon Sep 17 00:00:00 2001 From: lo-simon Date: Fri, 11 Aug 2023 14:34:33 +0100 Subject: [PATCH 018/106] Add FindMembersByRole and FindMembersByClassId --- Development/cmake/NmosCppLibraries.cmake | 2 + .../nmos/control_protocol_resource.cpp | 4 +- Development/nmos/control_protocol_resource.h | 2 +- Development/nmos/control_protocol_utils.cpp | 170 ++++++++++++++++++ Development/nmos/control_protocol_utils.h | 17 ++ Development/nmos/control_protocol_ws_api.cpp | 122 +++++++++---- 6 files changed, 283 insertions(+), 34 deletions(-) create mode 100644 Development/nmos/control_protocol_utils.cpp create mode 100644 Development/nmos/control_protocol_utils.h diff --git a/Development/cmake/NmosCppLibraries.cmake b/Development/cmake/NmosCppLibraries.cmake index cce8c420b..07a7b4df1 100644 --- a/Development/cmake/NmosCppLibraries.cmake +++ b/Development/cmake/NmosCppLibraries.cmake @@ -835,6 +835,7 @@ set(NMOS_CPP_NMOS_SOURCES nmos/control_protocol_resource.cpp nmos/control_protocol_resources.cpp nmos/control_protocol_state.cpp + nmos/control_protocol_utils.cpp nmos/control_protocol_ws_api.cpp nmos/did_sdid.cpp nmos/events_api.cpp @@ -913,6 +914,7 @@ set(NMOS_CPP_NMOS_HEADERS nmos/control_protocol_resource.h nmos/control_protocol_resources.h nmos/control_protocol_state.h + nmos/control_protocol_utils.h nmos/control_protocol_ws_api.h nmos/device_type.h nmos/did_sdid.h diff --git a/Development/nmos/control_protocol_resource.cpp b/Development/nmos/control_protocol_resource.cpp index 974c51aba..be029d7f5 100644 --- a/Development/nmos/control_protocol_resource.cpp +++ b/Development/nmos/control_protocol_resource.cpp @@ -102,10 +102,10 @@ namespace nmos return nc_class_id; } - nc_class_id parse_nc_class_id(const web::json::value& class_id_) + nc_class_id parse_nc_class_id(const web::json::array& class_id_) { nc_class_id class_id; - for (auto& element : class_id_.as_array()) + for (auto& element : class_id_) { class_id.push_back(element.as_integer()); } diff --git a/Development/nmos/control_protocol_resource.h b/Development/nmos/control_protocol_resource.h index dca604afa..3aa7e7429 100644 --- a/Development/nmos/control_protocol_resource.h +++ b/Development/nmos/control_protocol_resource.h @@ -162,7 +162,7 @@ namespace nmos // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassid web::json::value make_nc_class_id(const nc_class_id& class_id); - nc_class_id parse_nc_class_id(const web::json::value& class_id); + nc_class_id parse_nc_class_id(const web::json::array& class_id); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncelementid web::json::value make_nc_element_id(uint16_t level, uint16_t index); diff --git a/Development/nmos/control_protocol_utils.cpp b/Development/nmos/control_protocol_utils.cpp new file mode 100644 index 000000000..0b8326f0d --- /dev/null +++ b/Development/nmos/control_protocol_utils.cpp @@ -0,0 +1,170 @@ +#include "nmos/control_protocol_utils.h" + +#include +#include +#include +#include "cpprest/json_utils.h" +#include "nmos/json_fields.h" +#include "nmos/resources.h" + +#include "nmos/control_protocol_resource.h" // for nc_class_id + +namespace nmos +{ + namespace details + { + bool is_control_class(const nc_class_id& control_class_id, const nc_class_id& class_id_) + { + nc_class_id class_id{ class_id_ }; + if (control_class_id.size() < class_id.size()) + { + // truncate test class_id to relevant class_id + class_id.resize(control_class_id.size()); + } + return control_class_id == class_id; + } + + bool is_nc_block(const nc_class_id& class_id) + { + return is_control_class(nc_object_class_id, class_id); + } + + bool is_nc_manager(const nc_class_id& class_id) + { + return is_control_class(nc_manager_class_id, class_id); + } + + bool is_nc_device_manager(const nc_class_id& class_id) + { + return is_control_class(nc_device_manager_class_id, class_id); + } + + bool is_nc_class_manager(const nc_class_id& class_id) + { + return is_control_class(nc_class_manager_class_id, class_id); + } + } + + void get_member_descriptors(const resources& resources, resources::iterator resource, bool recurse, web::json::array& descriptors) + { + if (resource->data.has_field(nmos::fields::nc::members)) + { + const auto& members = nmos::fields::nc::members(resource->data); + + // hmm, maybe an easier way to apeend array to array + for (const auto& member : members) + { + web::json::push_back(descriptors, member); + } + + if (recurse) + { + // get members on all NcBlock(s) + for (const auto& member : members) + { + if (details::is_nc_block(details::parse_nc_class_id(nmos::fields::nc::class_id(member)))) + { + // get resource based on the oid + const auto& oid = nmos::fields::nc::oid(member); + + get_member_descriptors(resources, find_resource(resources, utility::s2us(std::to_string(oid))), recurse, descriptors); + } + } + } + } + } + + void find_members_by_role(const resources& resources, resources::iterator resource, const utility::string_t& role, bool match_whole_string, bool case_sensitive, bool recurse, web::json::array& descriptors) + { + auto find_members_by_matching_role = [&](const web::json::array& members) + { + using web::json::value; + + auto match = [&](const web::json::value& descriptor) + { + if (match_whole_string) + { + if (case_sensitive) { return role == nmos::fields::nc::role(descriptor); } + else { return boost::algorithm::to_upper_copy(role) == boost::algorithm::to_upper_copy(nmos::fields::nc::role(descriptor)); } + } + else + { + if (case_sensitive) { return !boost::find_first(nmos::fields::nc::role(descriptor), role).empty(); } + else { return !boost::ifind_first(nmos::fields::nc::role(descriptor), role).empty(); } + } + }; + + return boost::make_iterator_range(boost::make_filter_iterator(match, members.begin(), members.end()), boost::make_filter_iterator(match, members.end(), members.end())); + }; + + if (resource->data.has_field(nmos::fields::nc::members)) + { + const auto& members = nmos::fields::nc::members(resource->data); + + auto members_found = find_members_by_matching_role(members); + for (const auto& member : members_found) + { + web::json::push_back(descriptors, member); + } + + if (recurse) + { + // do role match on all NcBlock(s) + for (const auto& member : members) + { + if (details::is_nc_block(details::parse_nc_class_id(nmos::fields::nc::class_id(member)))) + { + // get resource based on the oid + const auto& oid = nmos::fields::nc::oid(member); + + find_members_by_role(resources, find_resource(resources, utility::s2us(std::to_string(oid))), role, match_whole_string, case_sensitive, recurse, descriptors); + } + } + } + } + } + + void find_members_by_class_id(const resources& resources, resources::iterator resource, const details::nc_class_id& class_id_, bool include_derived, bool recurse, web::json::array& descriptors) + { + auto find_members_by_matching_class_id = [&](const web::json::array& members) + { + using web::json::value; + + auto match = [&](const web::json::value& descriptor) + { + const auto& class_id = details::parse_nc_class_id(nmos::fields::nc::class_id(descriptor)); + + if (include_derived) { return !boost::find_first(class_id, class_id_).empty(); } + else { return class_id == class_id_; } + }; + + return boost::make_iterator_range(boost::make_filter_iterator(match, members.begin(), members.end()), boost::make_filter_iterator(match, members.end(), members.end())); + }; + + if (resource->data.has_field(nmos::fields::nc::members)) + { + auto& members = nmos::fields::nc::members(resource->data); + + auto members_found = find_members_by_matching_class_id(members); + for (const auto& member : members_found) + { + web::json::push_back(descriptors, member); + } + + if (recurse) + { + // do class_id match on all NcBlock(s) + for (const auto& member : members) + { + if (details::is_nc_block(details::parse_nc_class_id(nmos::fields::nc::class_id(member)))) + { + // get resource based on the oid + const auto& oid = nmos::fields::nc::oid(member); + + find_members_by_class_id(resources, find_resource(resources, utility::s2us(std::to_string(oid))), class_id_, include_derived, recurse, descriptors); + } + } + } + } + } +} diff --git a/Development/nmos/control_protocol_utils.h b/Development/nmos/control_protocol_utils.h new file mode 100644 index 000000000..fa9766aaf --- /dev/null +++ b/Development/nmos/control_protocol_utils.h @@ -0,0 +1,17 @@ +#ifndef NMOS_CONTROL_PROTOCOL_UTILS_H +#define NMOS_CONTROL_PROTOCOL_UTILS_H + +#include "cpprest/basic_utils.h" +#include "nmos/control_protocol_resource.h" // for nc_class_id definition +#include "nmos/resources.h" + +namespace nmos +{ + void get_member_descriptors(const resources& resources, resources::iterator resource, bool recurse, web::json::array& descriptors); + + void find_members_by_role(const resources& resources, resources::iterator resource, const utility::string_t& role, bool match_whole_string, bool case_sensitive, bool recurse, web::json::array& nc_block_member_descriptors); + + void find_members_by_class_id(const resources& resources, resources::iterator resource, const details::nc_class_id& class_id, bool include_derived, bool recurse, web::json::array& descriptors); +} + +#endif diff --git a/Development/nmos/control_protocol_ws_api.cpp b/Development/nmos/control_protocol_ws_api.cpp index a92e73fc9..091b7dce9 100644 --- a/Development/nmos/control_protocol_ws_api.cpp +++ b/Development/nmos/control_protocol_ws_api.cpp @@ -1,18 +1,16 @@ #include "nmos/control_protocol_ws_api.h" -#include #include -#include "bst/regex.h" #include "cpprest/json_validator.h" #include "cpprest/regex_utils.h" #include "nmos/api_utils.h" #include "nmos/control_protocol_resources.h" +#include "nmos/control_protocol_utils.h" #include "nmos/is12_versions.h" #include "nmos/json_schema.h" #include "nmos/model.h" #include "nmos/query_utils.h" #include "nmos/slog.h" -#include "nmos/resources.h" namespace nmos { @@ -81,13 +79,13 @@ namespace nmos // unknown property utility::stringstream_t ss; - ss << U("unknown property: ") << property_id.serialize() << " to do Get"; + ss << U("unknown property: ") << property_id.serialize() << U(" to do Get"); return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); } // resource not found for the given oid utility::stringstream_t ss; - ss << U("unknown oid: ") << oid << " to do Get"; + ss << U("unknown oid: ") << oid << U(" to do Get"); return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; // Set property value @@ -164,33 +162,32 @@ namespace nmos { // property is not a sequence utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << " is not a sequence to do GetSequenceItem"; + ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do GetSequenceItem"); return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); } auto& data = resource->data.at(nmos::fields::nc::name(*property_found)); - if (!data.is_null() && data.as_array().size() > index) + if (!data.is_null() && data.as_array().size() > (size_t)index) { return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, data.at(index)); } // out of bound utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << " is outside the available range to do GetSequenceItem"; + ss << U("property: ") << property_id.serialize() << U(" is outside the available range to do GetSequenceItem"); return details::make_control_protocol_error_response(handle, { details::nc_method_status::index_out_of_bounds }, ss.str()); } // unknown property utility::stringstream_t ss; - ss << U("unknown property: ") << property_id.serialize( - ) << " to do GetSequenceItem"; + ss << U("unknown property: ") << property_id.serialize() << U(" to do GetSequenceItem"); return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); } // resource not found for the given oid utility::stringstream_t ss; - ss << U("unknown oid: ") << oid << " to do GetSequenceItem"; + ss << U("unknown oid: ") << oid << U(" to do GetSequenceItem"); return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; // Set sequence item @@ -216,13 +213,13 @@ namespace nmos { // property is not a sequence utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << " is not a sequence to do SetSequenceItem"; + ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do SetSequenceItem"); return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); } auto& data = resource->data.at(nmos::fields::nc::name(*property_found)); - if (!data.is_null() && data.as_array().size() > index) + if (!data.is_null() && data.as_array().size() > (size_t)index) { resources.modify(resource, [&](nmos::resource& resource) { @@ -235,13 +232,13 @@ namespace nmos // out of bound utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << " is outside the available range to do SetSequenceItem"; + ss << U("property: ") << property_id.serialize() << U(" is outside the available range to do SetSequenceItem"); return details::make_control_protocol_error_response(handle, { details::nc_method_status::index_out_of_bounds }, ss.str()); } // resource not found for the given oid utility::stringstream_t ss; - ss << U("unknown oid: ") << oid << " to do SetSequenceItem"; + ss << U("unknown oid: ") << oid << U(" to do SetSequenceItem"); return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; // Add item to sequence @@ -266,7 +263,7 @@ namespace nmos { // property is not a sequence utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << " is not a sequence to do AddSequenceItem"; + ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do AddSequenceItem"); return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); } @@ -285,7 +282,7 @@ namespace nmos // resource not found for the given oid utility::stringstream_t ss; - ss << U("unknown oid: ") << oid << " to do AddSequenceItem"; + ss << U("unknown oid: ") << oid << U(" to do AddSequenceItem"); return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; // Delete sequence item @@ -310,13 +307,13 @@ namespace nmos { // property is not a sequence utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << " is not a sequence to do RemoveSequenceItem"; + ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do RemoveSequenceItem"); return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); } auto& data = resource->data.at(nmos::fields::nc::name(*property_found)); - if (!data.is_null() && data.as_array().size() > index) + if (!data.is_null() && data.as_array().size() > (size_t)index) { resources.modify(resource, [&](nmos::resource& resource) { @@ -330,13 +327,13 @@ namespace nmos // out of bound utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << " is outside the available range to do RemoveSequenceItem"; + ss << U("property: ") << property_id.serialize() << U(" is outside the available range to do RemoveSequenceItem"); return details::make_control_protocol_error_response(handle, { details::nc_method_status::index_out_of_bounds }, ss.str()); } // resource not found for the given oid utility::stringstream_t ss; - ss << U("unknown oid: ") << oid << " to do RemoveSequenceItem"; + ss << U("unknown oid: ") << oid << U(" to do RemoveSequenceItem"); return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; // Get sequence length @@ -409,23 +406,23 @@ namespace nmos // Gets descriptors of members of the block const auto get_member_descriptors = [&model](const web::json::array&, int32_t handle, int32_t oid, const value& arguments) { + const auto& recurse = nmos::fields::nc::recurse(arguments); // If recurse is set to true, nested members is to be retrieved + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... auto& resources = model.control_protocol_resources; auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); if (resources.end() != resource) { - // where arguments is the boolean recurse value - // hmm, If recurse is set to true, nested members is to be retrieved - const auto& recurse = nmos::fields::nc::recurse(arguments); + auto descriptors = value::array(); + nmos::get_member_descriptors(resources, nmos::find_resource(resources, utility::s2us(std::to_string(oid))), recurse, descriptors.as_array()); - // return the descriptors of members of the block - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, resource->data.at(nmos::fields::nc::members)); + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, descriptors); } // resource not found for the given oid utility::stringstream_t ss; - ss << U("unknown oid: ") << oid << " to do GetMemberDescriptors"; + ss << U("unknown oid: ") << oid << U(" to do GetMemberDescriptors"); return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; // Finds member(s) by path @@ -490,6 +487,69 @@ namespace nmos ss << U("unknown oid: ") << oid << " to do FindMembersByPath"; return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; + // Finds members with given role name or fragment + const auto find_members_by_role = [&model](const web::json::array&, int32_t handle, int32_t oid, const value& arguments) + { + const auto& role = nmos::fields::nc::role(arguments); // Role text to search for + const auto& case_sensitive = nmos::fields::nc::case_sensitive(arguments); // Signals if the comparison should be case sensitive + const auto& match_whole_string = nmos::fields::nc::match_whole_string(arguments); // TRUE to only return exact matches + const auto& recurse = nmos::fields::nc::recurse(arguments); // TRUE to search nested blocks + + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + auto& resources = model.control_protocol_resources; + + auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); + if (resources.end() != resource) + { + if (role.empty()) + { + // empty role + return details::make_control_protocol_error_response(handle, { details::nc_method_status::parameter_error }, U("empty role to do FindMembersByRole")); + } + + auto descriptors = value::array(); + nmos::find_members_by_role(resources, nmos::find_resource(resources, utility::s2us(std::to_string(oid))), role, match_whole_string, case_sensitive, recurse, descriptors.as_array()); + + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, descriptors); + } + + // resource not found for the given oid + utility::stringstream_t ss; + ss << U("unknown oid: ") << oid << U(" to do FindMembersByRole"); + return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); + }; + // Finds members with given class id + const auto find_members_by_class_id = [&model](const web::json::array&, int32_t handle, int32_t oid, const value& arguments) + { + const auto& class_id = details::parse_nc_class_id(nmos::fields::nc::class_id(arguments)); // Class id to search for + const auto& include_derived = nmos::fields::nc::include_derived(arguments); // If TRUE it will also include derived class descriptors + const auto& recurse = nmos::fields::nc::recurse(arguments); // TRUE to search nested blocks + + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + auto& resources = model.control_protocol_resources; + + auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); + if (resources.end() != resource) + { + if (class_id.empty()) + { + // empty class_id + return details::make_control_protocol_error_response(handle, { details::nc_method_status::parameter_error }, U("empty classId to do FindMembersByClassId")); + } + + auto descriptors = value::array(); + nmos::find_members_by_class_id(resources, nmos::find_resource(resources, utility::s2us(std::to_string(oid))), class_id, include_derived, recurse, descriptors.as_array()); + + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, descriptors); + } + + // resource not found for the given oid + utility::stringstream_t ss; + ss << U("unknown oid: ") << oid << U(" to do FindMembersByClassId"); + return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); + }; // NcClassManager methods implementation // Get a single class descriptor @@ -499,7 +559,7 @@ namespace nmos // resource not found for the given oid utility::stringstream_t ss; - ss << U("unknown oid: ") << oid << " to get control class"; + ss << U("unknown oid: ") << oid << U(" to get control class"); return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; @@ -525,8 +585,8 @@ namespace nmos // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 1 } })] = get_member_descriptors; nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 2 } })] = find_members_by_path; - //nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 3 } })] = find_members_by_role; - //nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 4 } })] = find_members_by_class_id; + nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 3 } })] = find_members_by_role; + nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 4 } })] = find_members_by_class_id; // NcWorker has no extended method // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncworker @@ -801,7 +861,7 @@ namespace nmos if (resources.end() != resource) { // create the combined properties and method handlers based on class_id - auto class_id = details::parse_nc_class_id(resource->data.at(nmos::fields::nc::class_id)); + auto class_id = details::parse_nc_class_id(nmos::fields::nc::class_id(resource->data)); auto properties_methods = details::create_properties_methods(model, class_id, get_control_protocol_classes()); auto& properties = properties_methods.first; auto& methods = properties_methods.second; From 5d5e2b8d0b91a106f43e5c070dd362499c6173bb Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 15 Aug 2023 18:22:11 +0100 Subject: [PATCH 019/106] Add GetControlClass, and GetDataType --- Development/cmake/NmosCppLibraries.cmake | 2 + Development/nmos-cpp-node/main.cpp | 1 + .../nmos/control_protocol_class_id.cpp | 27 ++ Development/nmos/control_protocol_class_id.h | 19 + .../nmos/control_protocol_handlers.cpp | 48 ++- Development/nmos/control_protocol_handlers.h | 15 +- .../nmos/control_protocol_resource.cpp | 29 +- Development/nmos/control_protocol_resource.h | 60 ++- .../nmos/control_protocol_resources.cpp | 6 +- Development/nmos/control_protocol_state.cpp | 62 ++- Development/nmos/control_protocol_state.h | 38 +- Development/nmos/control_protocol_utils.cpp | 3 +- Development/nmos/control_protocol_utils.h | 13 +- Development/nmos/control_protocol_ws_api.cpp | 372 ++++++++++++------ Development/nmos/control_protocol_ws_api.h | 6 +- Development/nmos/node_server.cpp | 2 +- Development/nmos/node_server.h | 5 +- 17 files changed, 509 insertions(+), 199 deletions(-) create mode 100644 Development/nmos/control_protocol_class_id.cpp create mode 100644 Development/nmos/control_protocol_class_id.h diff --git a/Development/cmake/NmosCppLibraries.cmake b/Development/cmake/NmosCppLibraries.cmake index 07a7b4df1..a135f74d5 100644 --- a/Development/cmake/NmosCppLibraries.cmake +++ b/Development/cmake/NmosCppLibraries.cmake @@ -831,6 +831,7 @@ set(NMOS_CPP_NMOS_SOURCES nmos/connection_api.cpp nmos/connection_events_activation.cpp nmos/connection_resources.cpp + nmos/control_protocol_class_id.cpp nmos/control_protocol_handlers.cpp nmos/control_protocol_resource.cpp nmos/control_protocol_resources.cpp @@ -910,6 +911,7 @@ set(NMOS_CPP_NMOS_HEADERS nmos/connection_api.h nmos/connection_events_activation.h nmos/connection_resources.h + nmos/control_protocol_class_id.h nmos/control_protocol_handlers.h nmos/control_protocol_resource.h nmos/control_protocol_resources.h diff --git a/Development/nmos-cpp-node/main.cpp b/Development/nmos-cpp-node/main.cpp index 60b0cc56b..159ef35da 100644 --- a/Development/nmos-cpp-node/main.cpp +++ b/Development/nmos-cpp-node/main.cpp @@ -111,6 +111,7 @@ int main(int argc, char* argv[]) nmos::experimental::control_protocol_state control_protocol_state; node_implementation.on_get_control_classes(nmos::make_get_control_protocol_classes_handler(control_protocol_state, gate)); + node_implementation.on_get_control_datatypes(nmos::make_get_control_protocol_datatypes_handler(control_protocol_state, gate)); // Set up the node server diff --git a/Development/nmos/control_protocol_class_id.cpp b/Development/nmos/control_protocol_class_id.cpp new file mode 100644 index 000000000..8ca0ec90c --- /dev/null +++ b/Development/nmos/control_protocol_class_id.cpp @@ -0,0 +1,27 @@ +#include "nmos/control_protocol_class_id.h" + +namespace nmos +{ + namespace details + { + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassid + web::json::value make_nc_class_id(const nc_class_id& class_id) + { + using web::json::value; + + auto nc_class_id = value::array(); + for (const auto class_id_item : class_id) { web::json::push_back(nc_class_id, class_id_item); } + return nc_class_id; + } + + nc_class_id parse_nc_class_id(const web::json::array& class_id_) + { + nc_class_id class_id; + for (auto& element : class_id_) + { + class_id.push_back(element.as_integer()); + } + return class_id; + } + } +} diff --git a/Development/nmos/control_protocol_class_id.h b/Development/nmos/control_protocol_class_id.h new file mode 100644 index 000000000..f48bbe731 --- /dev/null +++ b/Development/nmos/control_protocol_class_id.h @@ -0,0 +1,19 @@ +#ifndef NMOS_CONTROL_PROTOCOL_CLASS_ID_H +#define NMOS_CONTROL_PROTOCOL_CLASS_ID_H + +#include "cpprest/json_utils.h" + +namespace nmos +{ + namespace details + { + // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassid + typedef std::vector nc_class_id; + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassid + web::json::value make_nc_class_id(const nc_class_id& class_id); + nc_class_id parse_nc_class_id(const web::json::array& class_id); + } +} + +#endif diff --git a/Development/nmos/control_protocol_handlers.cpp b/Development/nmos/control_protocol_handlers.cpp index 3f1738c1e..609053ea4 100644 --- a/Development/nmos/control_protocol_handlers.cpp +++ b/Development/nmos/control_protocol_handlers.cpp @@ -1,7 +1,5 @@ #include "nmos/control_protocol_handlers.h" -#include "cpprest/basic_utils.h" -#include "nmos/control_protocol_state.h" #include "nmos/slog.h" namespace nmos @@ -18,28 +16,28 @@ namespace nmos }; } - get_control_protocol_class_handler make_get_control_protocol_class_handler(nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate) - { - return [&](const details::nc_class_id& class_id) - { - using web::json::value; + //get_control_protocol_class_handler make_get_control_protocol_class_handler(nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate) + //{ + // return [&](const details::nc_class_id& class_id) + // { + // using web::json::value; - slog::log(gate, SLOG_FLF) << "Retrieve control class from cache"; + // slog::log(gate, SLOG_FLF) << "Retrieve control class from cache"; - auto lock = control_protocol_state.read_lock(); + // auto lock = control_protocol_state.read_lock(); - auto class_id_data = details::make_nc_class_id(class_id); + // auto class_id_data = details::make_nc_class_id(class_id); - auto& control_classes = control_protocol_state.control_classes; - auto found = control_classes.find(class_id_data); - if (control_classes.end() != found) - { - return found->second; - } + // auto& control_classes = control_protocol_state.control_classes; + // auto found = control_classes.find(class_id_data); + // if (control_classes.end() != found) + // { + // return found->second; + // } - return experimental::control_class{ value::array(), value::array(), value::array() }; - }; - } + // return experimental::control_class{ value::array(), value::array(), value::array() }; + // }; + //} add_control_protocol_class_handler make_add_control_protocol_class_handler(nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate) { @@ -61,4 +59,16 @@ namespace nmos return true; }; } + + get_control_protocol_datatypes_handler make_get_control_protocol_datatypes_handler(nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate) + { + return [&]() + { + slog::log(gate, SLOG_FLF) << "Retrieve all datatypes from cache"; + + auto lock = control_protocol_state.read_lock(); + + return control_protocol_state.datatypes; + }; + } } diff --git a/Development/nmos/control_protocol_handlers.h b/Development/nmos/control_protocol_handlers.h index 1478235b4..d0af0c30e 100644 --- a/Development/nmos/control_protocol_handlers.h +++ b/Development/nmos/control_protocol_handlers.h @@ -1,9 +1,7 @@ #ifndef NMOS_CONTROL_PROTOCOL_HANDLERS_H #define NMOS_CONTROL_PROTOCOL_HANDLERS_H -#include #include -#include "nmos/control_protocol_resource.h" #include "nmos/control_protocol_state.h" namespace slog @@ -15,8 +13,8 @@ namespace nmos { namespace experimental { - struct control_class; struct control_protocol_state; + struct control_class; } // callback to retrieve all control protocol classes @@ -25,20 +23,27 @@ namespace nmos // callback to retrieve a specific control protocol class // this callback should not throw exceptions - typedef std::function get_control_protocol_class_handler; +// typedef std::function get_control_protocol_class_handler; // callback to add user control protocol class // this callback should not throw exceptions typedef std::function add_control_protocol_class_handler; + // callback to retrieve all control protocol datatypes + // this callback should not throw exceptions + typedef std::function get_control_protocol_datatypes_handler; + // construct callback to retrieve all control protocol classes get_control_protocol_classes_handler make_get_control_protocol_classes_handler(nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate); // construct callback to retrieve control protocol class - get_control_protocol_class_handler make_get_control_protocol_class_handler(nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate); +// get_control_protocol_class_handler make_get_control_protocol_class_handler(nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate); // construct callback to add control protocol class add_control_protocol_class_handler make_add_control_protocol_class_handler(nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate); + + // construct callback to retrieve all datatypes + get_control_protocol_datatypes_handler make_get_control_protocol_datatypes_handler(nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate); } #endif diff --git a/Development/nmos/control_protocol_resource.cpp b/Development/nmos/control_protocol_resource.cpp index be029d7f5..9a98eb4cf 100644 --- a/Development/nmos/control_protocol_resource.cpp +++ b/Development/nmos/control_protocol_resource.cpp @@ -1,6 +1,7 @@ #include "nmos/control_protocol_resource.h" //#include "nmos/resource.h" +#include "nmos/control_protocol_state.h" // for nmos::experimental::control_classes definitions #include "nmos/json_fields.h" namespace nmos @@ -92,26 +93,6 @@ namespace nmos }); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassid - web::json::value make_nc_class_id(const nc_class_id& class_id) - { - using web::json::value; - - auto nc_class_id = value::array(); - for (const auto class_id_item : class_id) { web::json::push_back(nc_class_id, class_id_item); } - return nc_class_id; - } - - nc_class_id parse_nc_class_id(const web::json::array& class_id_) - { - nc_class_id class_id; - for (auto& element : class_id_) - { - class_id.push_back(element.as_integer()); - } - return class_id; - } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncelementid web::json::value make_nc_element_id(uint16_t level, uint16_t index) { @@ -795,7 +776,7 @@ namespace nmos return make_nc_datatype_descriptor_struct(value::string(U("Id method result")), U("NcMethodResultId"), value::null(), fields, value::string(U("NcMethodResult"))); } - web::json::value make_method_result_length_datatype() + web::json::value make_nc_method_result_length_datatype() { using web::json::value; @@ -1152,11 +1133,11 @@ namespace nmos } // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager - web::json::value make_nc_class_manager(nc_oid oid, nc_oid owner, const web::json::value& user_label) + web::json::value make_nc_class_manager(nc_oid oid, nc_oid owner, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints) { using web::json::value; - auto data = make_nc_manager(nc_class_manager_class_id, oid, true, owner, U("ClassManager"), user_label); + auto data = make_nc_manager(nc_class_manager_class_id, oid, true, owner, U("ClassManager"), user_label, touchpoints, runtime_property_constraints); // minimal control classes data[nmos::fields::nc::control_classes] = value::array(); @@ -1203,7 +1184,7 @@ namespace nmos // NcMethodResultId web::json::push_back(datatypes, make_nc_method_result_id_datatype()); // NcMethodResultLength - web::json::push_back(datatypes, make_method_result_length_datatype()); + web::json::push_back(datatypes, make_nc_method_result_length_datatype()); // NcPropertyChangeType web::json::push_back(datatypes, make_nc_property_change_type_datatype()); // NcPropertyChangedEventData diff --git a/Development/nmos/control_protocol_resource.h b/Development/nmos/control_protocol_resource.h index 3aa7e7429..999e37aff 100644 --- a/Development/nmos/control_protocol_resource.h +++ b/Development/nmos/control_protocol_resource.h @@ -3,6 +3,8 @@ #include #include "cpprest/json_utils.h" +#include "nmos/control_protocol_class_id.h" +#include "nmos/control_protocol_state.h" // for nmos::experimental::control_classes definitions namespace web { @@ -126,7 +128,6 @@ namespace nmos typedef utility::string_t nc_uuid; // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassid - typedef std::vector nc_class_id; const nc_class_id nc_object_class_id({ 1 }); const nc_class_id nc_block_class_id({ 1, 1 }); const nc_class_id nc_worker_class_id({ 1, 2 }); @@ -137,9 +138,7 @@ namespace nmos // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#nctouchpoint typedef utility::string_t nc_touch_point; - typedef std::map properties; - - typedef std::function method; + typedef std::function method; typedef std::map methods; // method_id vs method handler web::json::value make_control_protocol_error_response(int32_t handle, const nc_method_result& method_result, const utility::string_t& error_message); @@ -160,10 +159,6 @@ namespace nmos // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#error-messages web::json::value make_control_protocol_error_message(const nc_method_result& method_result, const utility::string_t& error_message); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassid - web::json::value make_nc_class_id(const nc_class_id& class_id); - nc_class_id parse_nc_class_id(const web::json::array& class_id); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncelementid web::json::value make_nc_element_id(uint16_t level, uint16_t index); @@ -202,7 +197,7 @@ namespace nmos // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassdescriptor // description can be null // fixedRole can be null - web::json::value make_nc_class_descriptor(const web::json::value& description, const web::json::value& class_id, const utility::string_t& name, const web::json::value& fixed_role, const web::json::value& properties, const web::json::value& methods, const web::json::value& events); + web::json::value make_nc_class_descriptor(const web::json::value& description, const nc_class_id& class_id, const utility::string_t& name, const web::json::value& fixed_role, const web::json::value& properties, const web::json::value& methods, const web::json::value& events); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncenumitemdescriptor // description can be null @@ -266,7 +261,7 @@ namespace nmos // constraints can be null web::json::value make_nc_datatype_typedef(const web::json::value& description, const utility::string_t& name, const web::json::value& constraints, const utility::string_t& parent_type, bool is_sequence); - // make the core classes proprties/methods/events + // make the core control classes proprties/methods/events web::json::value make_nc_object_properties(); web::json::value make_nc_object_methods(); web::json::value make_nc_object_events(); @@ -286,6 +281,47 @@ namespace nmos web::json::value make_nc_class_manager_methods(); web::json::value make_nc_class_manager_events(); + // make the core datatypes + web::json::value make_nc_class_id_datatype(); + web::json::value make_nc_oid_datatype(); + web::json::value make_nc_touchpoint_datatype(); + web::json::value make_nc_element_id_datatype(); + web::json::value make_nc_property_id_datatype(); + web::json::value make_nc_property_contraints_datatype(); + web::json::value make_nc_method_result_property_value_datatype(); + web::json::value make_nc_method_status_datatype(); + web::json::value make_nc_method_result_datatype(); + web::json::value make_nc_id_datatype(); + web::json::value make_nc_method_result_id_datatype(); + web::json::value make_nc_method_result_length_datatype(); + web::json::value make_nc_property_change_type_datatype(); + web::json::value make_nc_property_changed_event_data_datatype(); + web::json::value make_nc_descriptor_datatype(); + web::json::value make_nc_block_member_descriptor_datatype(); + web::json::value make_nc_method_result_block_member_descriptors_datatype(); + web::json::value make_nc_version_code_datatype(); + web::json::value make_nc_organization_id_datatype(); + web::json::value make_nc_uri_datatype(); + web::json::value make_nc_manufacturer_datatype(); + web::json::value make_nc_uuid_datatype(); + web::json::value make_nc_product_datatype(); + web::json::value make_nc_device_generic_state_datatype(); + web::json::value make_nc_device_operational_state_datatype(); + web::json::value make_nc_reset_cause_datatype(); + web::json::value make_nc_name_datatype(); + web::json::value make_nc_property_descriptor_datatype(); + web::json::value make_nc_parameter_descriptor_datatype(); + web::json::value make_nc_method_id_datatype(); + web::json::value make_nc_method_descriptor_datatype(); + web::json::value make_nc_event_id_datatype(); + web::json::value make_nc_event_descriptor_datatype(); + web::json::value make_nc_class_descriptor_datatype(); + web::json::value make_nc_parameter_constraints_datatype(); + web::json::value make_nc_datatype_type_datatype(); + web::json::value make_nc_datatype_descriptor_datatype(); + web::json::value make_nc_method_result_class_descriptor_datatype(); + web::json::value make_nc_method_result_datatype_descriptor_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject web::json::value make_nc_object(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints); @@ -293,7 +329,7 @@ namespace nmos web::json::value make_nc_block(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled, const web::json::value& members); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanager - web::json::value make_nc_manager(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null()); + web::json::value make_nc_manager(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager web::json::value make_nc_device_manager(nc_oid oid, nc_oid owner, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, @@ -301,7 +337,7 @@ namespace nmos const web::json::value& user_inventory_code, const web::json::value& device_name, const web::json::value& device_role, const web::json::value& operational_state, nc_reset_cause::cause reset_cause); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager - web::json::value make_nc_class_manager(details::nc_oid oid, nc_oid owner, const web::json::value& user_label); + web::json::value make_nc_class_manager(details::nc_oid oid, nc_oid owner, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints); } } diff --git a/Development/nmos/control_protocol_resources.cpp b/Development/nmos/control_protocol_resources.cpp index f5e2754b4..6c89b6f5a 100644 --- a/Development/nmos/control_protocol_resources.cpp +++ b/Development/nmos/control_protocol_resources.cpp @@ -26,8 +26,8 @@ namespace nmos manufacturer, product, serial_number, value::null(), device_name, device_role, operational_state, details::nc_reset_cause::Unknown); // add NcDeviceManager block_member_descriptor to root block members - web::json::push_back(root_block_data[nmos::fields::nc::members], details::make_nc_block_member_descriptor( - description, nmos::fields::nc::role(data), oid, nmos::fields::nc::constant_oid(data), data.at(nmos::fields::nc::class_id), user_label, owner)); + web::json::push_back(root_block_data[nmos::fields::nc::members], + details::make_nc_block_member_descriptor(description, nmos::fields::nc::role(data), oid, nmos::fields::nc::constant_oid(data), data.at(nmos::fields::nc::class_id), user_label, owner)); return{ is12_versions::v1_0, types::nc_device_manager, std::move(data), true }; } @@ -42,7 +42,7 @@ namespace nmos const auto user_label = value::string(U("Class manager")); const auto description = value::string(U("The class manager offers access to control class and data type descriptors")); - auto data = details::make_nc_class_manager(oid, owner, user_label); + auto data = details::make_nc_class_manager(oid, owner, user_label, value::null(), value::null()); // add NcClassManager block_member_descriptor to root block members web::json::push_back(root_block_data[nmos::fields::nc::members], diff --git a/Development/nmos/control_protocol_state.cpp b/Development/nmos/control_protocol_state.cpp index c420072be..7270591a3 100644 --- a/Development/nmos/control_protocol_state.cpp +++ b/Development/nmos/control_protocol_state.cpp @@ -1,6 +1,6 @@ #include "nmos/control_protocol_state.h" -#include "nmos/control_protocol_resource.h" +#include "nmos/control_protocol_resource.h" // for nc_object_class_id, nc_block_class_id, nc_worker_class_id, nc_manager_class_id, nc_device_manager_class_id, nc_class_manager_class_id definitions namespace nmos { @@ -8,15 +8,61 @@ namespace nmos { control_protocol_state::control_protocol_state() { - // setup the core control classes (properties/methods/events) + using web::json::value; + + // setup the core control classes control_classes = { - { details::make_nc_class_id(details::nc_object_class_id), { details::make_nc_object_properties(), details::make_nc_object_methods(), details::make_nc_object_events() } }, - { details::make_nc_class_id(details::nc_block_class_id), { details::make_nc_block_properties(), details::make_nc_block_methods(), details::make_nc_block_events() } }, - { details::make_nc_class_id(details::nc_worker_class_id), { details::make_nc_worker_properties(), details::make_nc_worker_methods(), details::make_nc_worker_events() } }, - { details::make_nc_class_id(details::nc_manager_class_id), { details::make_nc_manager_properties(), details::make_nc_manager_methods(), details::make_nc_manager_events() } }, - { details::make_nc_class_id(details::nc_device_manager_class_id), { details::make_nc_device_manager_properties(), details::make_nc_device_manager_methods(), details::make_nc_device_manager_events() } }, - { details::make_nc_class_id(details::nc_class_manager_class_id), { details::make_nc_class_manager_properties(), details::make_nc_class_manager_methods(), details::make_nc_class_manager_events() } } + { details::make_nc_class_id(details::nc_object_class_id), { value::string(U("NcObject class descriptor")), details::nc_object_class_id, U("NcObject"), value::null(), details::make_nc_object_properties(), details::make_nc_object_methods(), details::make_nc_object_events() } }, + { details::make_nc_class_id(details::nc_block_class_id), { value::string(U("NcBlock class descriptor")), details::nc_block_class_id, U("NcBlock"), value::null(), details::make_nc_block_properties(), details::make_nc_block_methods(), details::make_nc_block_events() } }, + { details::make_nc_class_id(details::nc_worker_class_id), { value::string(U("NcWorker class descriptor")), details::nc_worker_class_id, U("NcWorker"), value::null(), details::make_nc_worker_properties(), details::make_nc_worker_methods(), details::make_nc_worker_events() } }, + { details::make_nc_class_id(details::nc_manager_class_id), { value::string(U("NcManager class descriptor")), details::nc_manager_class_id, U("NcManager"), value::null(), details::make_nc_manager_properties(), details::make_nc_manager_methods(), details::make_nc_manager_events() } }, + { details::make_nc_class_id(details::nc_device_manager_class_id), { value::string(U("NcDeviceManager class descriptor")), details::nc_device_manager_class_id, U("NcDeviceManager"), value::string(U("DeviceManager")), details::make_nc_device_manager_properties(), details::make_nc_device_manager_methods(), details::make_nc_device_manager_events() } }, + { details::make_nc_class_id(details::nc_class_manager_class_id), { value::string(U("NcClassManager class descriptor")), details::nc_class_manager_class_id, U("NcClassManager"), value::string(U("ClassManager")), details::make_nc_class_manager_properties(), details::make_nc_class_manager_methods(), details::make_nc_class_manager_events() } } + }; + + // setup the core datatypes + datatypes = + { + { U("NcClassId"), {details::make_nc_class_id_datatype()} }, + { U("NcOid"), {details::make_nc_oid_datatype()} }, + { U("NcTouchpoint"), {details::make_nc_touchpoint_datatype()} }, + { U("NcElementId"), {details::make_nc_element_id_datatype()} }, + { U("NcPropertyId"), {details::make_nc_property_id_datatype()} }, + { U("NcPropertyConstraints"), {details::make_nc_property_contraints_datatype()} }, + { U("NcMethodResultPropertyValue"), {details::make_nc_method_result_property_value_datatype()} }, + { U("NcMethodStatus"), {details::make_nc_method_status_datatype()} }, + { U("NcMethodResult"), {details::make_nc_method_result_datatype()} }, + { U("NcId"), {details::make_nc_id_datatype()} }, + { U("NcMethodResultId"), {details::make_nc_method_result_id_datatype()} }, + { U("NcMethodResultLength"), {details::make_nc_method_result_length_datatype()} }, + { U("NcPropertyChangeType"), {details::make_nc_property_change_type_datatype()} }, + { U("NcPropertyChangedEventData"), {details::make_nc_property_changed_event_data_datatype()} }, + { U("NcDescriptor"), {details::make_nc_descriptor_datatype()} }, + { U("NcBlockMemberDescriptor"), {details::make_nc_block_member_descriptor_datatype()} }, + { U("NcMethodResultBlockMemberDescriptors"), {details::make_nc_method_result_block_member_descriptors_datatype()} }, + { U("NcVersionCode"), {details::make_nc_version_code_datatype()} }, + { U("NcOrganizationId"), {details::make_nc_organization_id_datatype()} }, + { U("NcUri"), {details::make_nc_uri_datatype()} }, + { U("NcManufacturer"), {details::make_nc_manufacturer_datatype()} }, + { U("NcUuid"), {details::make_nc_uuid_datatype()} }, + { U("NcProduct"), {details::make_nc_product_datatype()} }, + { U("NcDeviceGenericState"), {details::make_nc_device_generic_state_datatype()} }, + { U("NcDeviceOperationalState"), {details::make_nc_device_operational_state_datatype()} }, + { U("NcResetCause"), {details::make_nc_reset_cause_datatype()} }, + { U("NcName"), {details::make_nc_name_datatype()} }, + { U("NcPropertyDescriptor"), {details::make_nc_property_descriptor_datatype()} }, + { U("NcParameterDescriptor"), {details::make_nc_parameter_descriptor_datatype()} }, + { U("NcMethodId"), {details::make_nc_method_id_datatype()} }, + { U("NcMethodDescriptor"), {details::make_nc_method_descriptor_datatype()} }, + { U("NcEventId"), {details::make_nc_event_id_datatype()} }, + { U("NcEventDescriptor"), {details::make_nc_event_descriptor_datatype()} }, + { U("NcClassDescriptor"), {details::make_nc_class_descriptor_datatype()} }, + { U("NcParameterConstraints"), {details::make_nc_parameter_constraints_datatype()} }, + { U("NcDatatypeType"), {details::make_nc_datatype_type_datatype()} }, + { U("NcDatatypeDescriptor"), {details::make_nc_datatype_descriptor_datatype()} }, + { U("NcMethodResultClassDescriptor"), {details::make_nc_method_result_class_descriptor_datatype()} }, + { U("NcMethodResultDatatypeDescriptor"), {details::make_nc_method_result_datatype_descriptor_datatype()} } }; } } diff --git a/Development/nmos/control_protocol_state.h b/Development/nmos/control_protocol_state.h index ad884733c..0dfde5990 100644 --- a/Development/nmos/control_protocol_state.h +++ b/Development/nmos/control_protocol_state.h @@ -3,20 +3,55 @@ #include #include "cpprest/json_utils.h" +#include "nmos/control_protocol_class_id.h" // for nmos::details::nc_class_id definitions #include "nmos/mutex.h" namespace nmos { namespace experimental { - struct control_class + struct control_class // NcClassDescriptor { + web::json::value description; + nmos::details::nc_class_id class_id; + utility::string_t name; + web::json::value fixed_role; + web::json::value properties; // array of nc_property_descriptor web::json::value methods; // array of nc_method_descriptor web::json::value events; // array of nc_event_descriptor + + //control_class(details::nc_class_id class_id, utility::string_t name, web::json::value fixed_role, web::json::value properties, web::json::value methods, web::json::value events) + // : description(web::json::value::null()) + // , class_id(std::move(class_id)) + // , name(std::move(name)) + // , fixed_role(std::move(fixed_role)) + // , properties(std::move(properties)) + // , methods(std::move(methods)) + // , events(std::move(events)) + //{} + + //control_class(const utility::string_t& description, details::nc_class_id class_id, utility::string_t name, web::json::value fixed_role, web::json::value properties, web::json::value methods, web::json::value events) + // : description(web::json::value::string(description)) + // , class_id(std::move(class_id)) + // , name(std::move(name)) + // , fixed_role(std::move(fixed_role)) + // , properties(std::move(properties)) + // , methods(std::move(methods)) + // , events(std::move(events)) + //{} + + }; + + struct datatype // NcDatatypeDescriptorEnum/NcDatatypeDescriptorPrimitive/NcDatatypeDescriptorStruct/NcDatatypeDescriptorTypeDef + { + web::json::value descriptor; }; + // nc_class_id vs control_class typedef std::map control_classes; + // nc_name vs datatype + typedef std::map datatypes; struct control_protocol_state { @@ -24,6 +59,7 @@ namespace nmos mutable nmos::mutex mutex; experimental::control_classes control_classes; + experimental::datatypes datatypes; nmos::read_lock read_lock() const { return nmos::read_lock{ mutex }; } nmos::write_lock write_lock() const { return nmos::write_lock{ mutex }; } diff --git a/Development/nmos/control_protocol_utils.cpp b/Development/nmos/control_protocol_utils.cpp index 0b8326f0d..106a55a7d 100644 --- a/Development/nmos/control_protocol_utils.cpp +++ b/Development/nmos/control_protocol_utils.cpp @@ -4,11 +4,10 @@ #include #include #include "cpprest/json_utils.h" +#include "nmos/control_protocol_resource.h" // for nc_object_class_id, nc_manager_class_id, nc_device_manager_class_id, nc_class_manager_class_id #include "nmos/json_fields.h" #include "nmos/resources.h" -#include "nmos/control_protocol_resource.h" // for nc_class_id - namespace nmos { namespace details diff --git a/Development/nmos/control_protocol_utils.h b/Development/nmos/control_protocol_utils.h index fa9766aaf..b90f63574 100644 --- a/Development/nmos/control_protocol_utils.h +++ b/Development/nmos/control_protocol_utils.h @@ -2,11 +2,22 @@ #define NMOS_CONTROL_PROTOCOL_UTILS_H #include "cpprest/basic_utils.h" -#include "nmos/control_protocol_resource.h" // for nc_class_id definition +#include "nmos/control_protocol_class_id.h" // for nc_class_id definition #include "nmos/resources.h" namespace nmos { + namespace details + { + bool is_nc_block(const nc_class_id& class_id); + + bool is_nc_manager(const nc_class_id& class_id); + + bool is_nc_device_manager(const nc_class_id& class_id); + + bool is_nc_class_manager(const nc_class_id& class_id); + } + void get_member_descriptors(const resources& resources, resources::iterator resource, bool recurse, web::json::array& descriptors); void find_members_by_role(const resources& resources, resources::iterator resource, const utility::string_t& role, bool match_whole_string, bool case_sensitive, bool recurse, web::json::array& nc_block_member_descriptors); diff --git a/Development/nmos/control_protocol_ws_api.cpp b/Development/nmos/control_protocol_ws_api.cpp index 091b7dce9..c51b90655 100644 --- a/Development/nmos/control_protocol_ws_api.cpp +++ b/Development/nmos/control_protocol_ws_api.cpp @@ -55,7 +55,7 @@ namespace nmos // NcObject methods implementation // Get property value - const auto get = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments) + const auto get = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -71,8 +71,7 @@ namespace nmos { return property_id == nmos::fields::nc::id(property); }); - - if (property_found != properties.end()) + if (properties.end() != property_found) { return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, resource->data.at(nmos::fields::nc::name(*property_found))); } @@ -89,7 +88,7 @@ namespace nmos return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; // Set property value - const auto set = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments) + const auto set = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -105,7 +104,7 @@ namespace nmos { return property_id == nmos::fields::nc::id(property); }); - if (property_found != properties.end()) + if (properties.end() != property_found) { if (nmos::fields::nc::is_read_only(*property_found)) { @@ -139,7 +138,7 @@ namespace nmos return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; // Get sequence item - const auto get_sequence_item = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments) + const auto get_sequence_item = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -155,8 +154,7 @@ namespace nmos { return property_id == nmos::fields::nc::id(property); }); - - if (property_found != properties.end()) + if (properties.end() != property_found) { if (!nmos::fields::nc::is_sequence(*property_found)) { @@ -191,7 +189,7 @@ namespace nmos return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; // Set sequence item - const auto set_sequence_item = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments) + const auto set_sequence_item = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -208,32 +206,39 @@ namespace nmos { return property_id == nmos::fields::nc::id(property); }); - - if (!nmos::fields::nc::is_sequence(*property_found)) + if (properties.end() != property_found) { - // property is not a sequence - utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do SetSequenceItem"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); - } + if (!nmos::fields::nc::is_sequence(*property_found)) + { + // property is not a sequence + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do SetSequenceItem"); + return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); + } - auto& data = resource->data.at(nmos::fields::nc::name(*property_found)); + auto& data = resource->data.at(nmos::fields::nc::name(*property_found)); - if (!data.is_null() && data.as_array().size() > (size_t)index) - { - resources.modify(resource, [&](nmos::resource& resource) + if (!data.is_null() && data.as_array().size() > (size_t)index) { - resource.data[nmos::fields::nc::name(*property_found)][index] = val; + resources.modify(resource, [&](nmos::resource& resource) + { + resource.data[nmos::fields::nc::name(*property_found)][index] = val; - resource.updated = strictly_increasing_update(resources); - }); - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }); + resource.updated = strictly_increasing_update(resources); + }); + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }); + } + + // out of bound + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << U(" is outside the available range to do SetSequenceItem"); + return details::make_control_protocol_error_response(handle, { details::nc_method_status::index_out_of_bounds }, ss.str()); } - // out of bound + // unknown property utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << U(" is outside the available range to do SetSequenceItem"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::index_out_of_bounds }, ss.str()); + ss << U("unknown property: ") << property_id.serialize() << U(" to do SetSequenceItem"); + return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); } // resource not found for the given oid @@ -242,7 +247,7 @@ namespace nmos return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; // Add item to sequence - const auto add_sequence_item = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments) + const auto add_sequence_item = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -258,26 +263,33 @@ namespace nmos { return property_id == nmos::fields::nc::id(property); }); - - if (!nmos::fields::nc::is_sequence(*property_found)) + if (properties.end() != property_found) { - // property is not a sequence - utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do AddSequenceItem"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); - } + if (!nmos::fields::nc::is_sequence(*property_found)) + { + // property is not a sequence + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do AddSequenceItem"); + return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); + } - auto& data = resource->data.at(nmos::fields::nc::name(*property_found)); + auto& data = resource->data.at(nmos::fields::nc::name(*property_found)); - resources.modify(resource, [&](nmos::resource& resource) - { - auto& sequence = resource.data[nmos::fields::nc::name(*property_found)]; - if (data.is_null()) { sequence = value::array(); } - web::json::push_back(sequence, val); + resources.modify(resource, [&](nmos::resource& resource) + { + auto& sequence = resource.data[nmos::fields::nc::name(*property_found)]; + if (data.is_null()) { sequence = value::array(); } + web::json::push_back(sequence, val); - resource.updated = strictly_increasing_update(resources); - }); - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, uint32_t(data.as_array().size() - 1)); + resource.updated = strictly_increasing_update(resources); + }); + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, uint32_t(data.as_array().size() - 1)); + } + + // unknown property + utility::stringstream_t ss; + ss << U("unknown property: ") << property_id.serialize() << U(" to do AddSequenceItem"); + return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); } // resource not found for the given oid @@ -286,7 +298,7 @@ namespace nmos return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; // Delete sequence item - const auto remove_sequence_item = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments) + const auto remove_sequence_item = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -302,33 +314,40 @@ namespace nmos { return property_id == nmos::fields::nc::id(property); }); - - if (!nmos::fields::nc::is_sequence(*property_found)) + if (properties.end() != property_found) { - // property is not a sequence - utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do RemoveSequenceItem"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); - } + if (!nmos::fields::nc::is_sequence(*property_found)) + { + // property is not a sequence + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do RemoveSequenceItem"); + return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); + } - auto& data = resource->data.at(nmos::fields::nc::name(*property_found)); + auto& data = resource->data.at(nmos::fields::nc::name(*property_found)); - if (!data.is_null() && data.as_array().size() > (size_t)index) - { - resources.modify(resource, [&](nmos::resource& resource) + if (!data.is_null() && data.as_array().size() > (size_t)index) { - auto& sequence = resource.data[nmos::fields::nc::name(*property_found)].as_array(); - sequence.erase(index); + resources.modify(resource, [&](nmos::resource& resource) + { + auto& sequence = resource.data[nmos::fields::nc::name(*property_found)].as_array(); + sequence.erase(index); - resource.updated = strictly_increasing_update(resources); - }); - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }); + resource.updated = strictly_increasing_update(resources); + }); + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }); + } + + // out of bound + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << U(" is outside the available range to do RemoveSequenceItem"); + return details::make_control_protocol_error_response(handle, { details::nc_method_status::index_out_of_bounds }, ss.str()); } - // out of bound + // unknown property utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << U(" is outside the available range to do RemoveSequenceItem"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::index_out_of_bounds }, ss.str()); + ss << U("unknown property: ") << property_id.serialize() << U(" to do RemoveSequenceItem"); + return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); } // resource not found for the given oid @@ -337,7 +356,7 @@ namespace nmos return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; // Get sequence length - const auto get_sequence_length = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments) + const auto get_sequence_length = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -355,39 +374,37 @@ namespace nmos if (property_found != properties.end()) { - if (nmos::fields::nc::is_sequence(*property_found)) + if (!nmos::fields::nc::is_sequence(*property_found)) { - auto& data = resource->data.at(nmos::fields::nc::name(*property_found)); + // property is not a sequence + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do GetSequenceLength"); + return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); + } - if (nmos::fields::nc::is_nullable(*property_found)) - { - // can be null - if (data.is_null()) - { - // null - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, value::null()); - } - } - else + auto& data = resource->data.at(nmos::fields::nc::name(*property_found)); + + if (nmos::fields::nc::is_nullable(*property_found)) + { + // can be null + if (data.is_null()) { - // cannot be null - if (data.is_null()) - { - // null - utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << " is a null sequence to do GetSequenceLength"; - return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); - } + // null + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, value::null()); } - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, uint32_t(data.as_array().size())); } else { - // property is not a sequence - utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << " is not a sequence to do GetSequenceLength"; - return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); + // cannot be null + if (data.is_null()) + { + // null + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << " is a null sequence to do GetSequenceLength"; + return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); + } } + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, uint32_t(data.as_array().size())); } // unknown property @@ -404,16 +421,16 @@ namespace nmos // NcBlock methods implementation // Gets descriptors of members of the block - const auto get_member_descriptors = [&model](const web::json::array&, int32_t handle, int32_t oid, const value& arguments) + const auto get_member_descriptors = [&model](const web::json::array&, int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) { - const auto& recurse = nmos::fields::nc::recurse(arguments); // If recurse is set to true, nested members is to be retrieved - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... auto& resources = model.control_protocol_resources; auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); if (resources.end() != resource) { + const auto& recurse = nmos::fields::nc::recurse(arguments); // If recurse is set to true, nested members is to be retrieved + auto descriptors = value::array(); nmos::get_member_descriptors(resources, nmos::find_resource(resources, utility::s2us(std::to_string(oid))), recurse, descriptors.as_array()); @@ -426,12 +443,11 @@ namespace nmos return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; // Finds member(s) by path - const auto find_members_by_path = [&model](const web::json::array&, int32_t handle, int32_t oid, const value& arguments) + const auto find_members_by_path = [&model](const web::json::array&, int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... auto& resources = model.control_protocol_resources; - auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); if (resources.end() != resource) { @@ -488,7 +504,7 @@ namespace nmos return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; // Finds members with given role name or fragment - const auto find_members_by_role = [&model](const web::json::array&, int32_t handle, int32_t oid, const value& arguments) + const auto find_members_by_role = [&model](const web::json::array&, int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) { const auto& role = nmos::fields::nc::role(arguments); // Role text to search for const auto& case_sensitive = nmos::fields::nc::case_sensitive(arguments); // Signals if the comparison should be case sensitive @@ -520,12 +536,18 @@ namespace nmos return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; // Finds members with given class id - const auto find_members_by_class_id = [&model](const web::json::array&, int32_t handle, int32_t oid, const value& arguments) + const auto find_members_by_class_id = [&model](const web::json::array&, int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) { const auto& class_id = details::parse_nc_class_id(nmos::fields::nc::class_id(arguments)); // Class id to search for const auto& include_derived = nmos::fields::nc::include_derived(arguments); // If TRUE it will also include derived class descriptors const auto& recurse = nmos::fields::nc::recurse(arguments); // TRUE to search nested blocks + if (class_id.empty()) + { + // empty class_id + return details::make_control_protocol_error_response(handle, { details::nc_method_status::parameter_error }, U("empty classId to do FindMembersByClassId")); + } + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... auto& resources = model.control_protocol_resources; @@ -533,12 +555,6 @@ namespace nmos auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); if (resources.end() != resource) { - if (class_id.empty()) - { - // empty class_id - return details::make_control_protocol_error_response(handle, { details::nc_method_status::parameter_error }, U("empty classId to do FindMembersByClassId")); - } - auto descriptors = value::array(); nmos::find_members_by_class_id(resources, nmos::find_resource(resources, utility::s2us(std::to_string(oid))), class_id, include_derived, recurse, descriptors.as_array()); @@ -553,13 +569,131 @@ namespace nmos // NcClassManager methods implementation // Get a single class descriptor - const auto get_control_class = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments) + const auto get_control_class = [&model](const web::json::array&, int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + { + const auto& class_id = details::parse_nc_class_id(nmos::fields::nc::class_id(arguments)); // Class id to search for + const auto& include_inherited = nmos::fields::nc::include_inherited(arguments); // If set the descriptor would contain all inherited elements + + if (class_id.empty()) + { + // empty class_id + return details::make_control_protocol_error_response(handle, { details::nc_method_status::parameter_error }, U("empty classId to do GetControlClass")); + } + + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + auto& resources = model.control_protocol_resources; + + auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); + if (resources.end() != resource) + { + auto class_found = control_classes.find(make_nc_class_id(class_id)); + + if (control_classes.end() != class_found) + { + auto id = class_id; + + auto description = class_found->second.description; + auto name = class_found->second.name; + auto fixed_role = class_found->second.fixed_role; + auto properties = class_found->second.properties; + auto methods = class_found->second.methods; + auto events = class_found->second.events; + + id.pop_back(); + + if (include_inherited) + { + while (!id.empty()) + { + auto found = control_classes.find(make_nc_class_id(id)); + if (control_classes.end() != found) + { + for (const auto& property : found->second.properties.as_array()) { web::json::push_back(properties, property); } + for (const auto& method : found->second.methods.as_array()) { web::json::push_back(methods, method); } + for (const auto& event : found->second.events.as_array()) { web::json::push_back(events, event); } + } + id.pop_back(); + } + } + auto descriptor = details::make_nc_class_descriptor(description, class_id, name, fixed_role, properties, methods, events); + + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, descriptor); + } + + return details::make_control_protocol_error_response(handle, { details::nc_method_status::parameter_error }, U("classId not found")); + } + + // resource not found for the given oid + utility::stringstream_t ss; + ss << U("unknown oid: ") << oid << U(" to do GetControlClass"); + return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); + }; + // Get a single datatype descriptor + const auto get_datatype = [&model](const web::json::array&, int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) { - // hmm, todo + const auto& name = nmos::fields::nc::name(arguments); // name of datatype + const auto& include_inherited = nmos::fields::nc::include_inherited(arguments); // If set the descriptor would contain all inherited elements + + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + auto& resources = model.control_protocol_resources; + + auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); + if (resources.end() != resource) + { + if (name.empty()) + { + // empty name + return details::make_control_protocol_error_response(handle, { details::nc_method_status::parameter_error }, U("empty name to do GetDatatype")); + } + + auto datatype_found = datatypes.find(name); + + if (datatypes.end() != datatype_found) + { + auto descriptor = datatype_found->second.descriptor; + + if (include_inherited) + { + const auto& type = nmos::fields::nc::type(descriptor); + if(details::nc_datatype_type::Struct == type) + { + auto descriptor_ = descriptor; + + for (;;) + { + const auto& parent_type = descriptor_.at(nmos::fields::nc::parent_type); + if (!parent_type.is_null()) + { + auto datatype_found_ = datatypes.find(parent_type.as_string()); + if (datatypes.end() != datatype_found_) + { + descriptor_ = datatype_found_->second.descriptor; + const auto& fields = nmos::fields::nc::fields(descriptor_); + for (const auto& field : fields) + { + web::json::push_back(descriptor.at(nmos::fields::nc::fields), field); + } + } + } + else + { + break; + } + } + } + } + + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, descriptor); + } + + return details::make_control_protocol_error_response(handle, { details::nc_method_status::parameter_error }, U("name not found")); + } // resource not found for the given oid utility::stringstream_t ss; - ss << U("unknown oid: ") << oid << U(" to get control class"); + ss << U("unknown oid: ") << oid << U(" to do GetDatatype"); return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; @@ -599,23 +733,23 @@ namespace nmos // NcClassManager methods // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager - //nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 1 } })] = get_control_class; - //nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 2 } })] = get_datatype; + nc_class_manager_method_handlers[value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 1 } })] = get_control_class; + nc_class_manager_method_handlers[value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 2 } })] = get_datatype; value properties = value::array(); // combined base classes nc_property_descriptor(s) for the required class_id details::methods methods; // list of combined base classes method handlers - auto found_class = control_classes.find(make_nc_class_id(class_id_)); - if (control_classes.end() != found_class) + auto class_found = control_classes.find(make_nc_class_id(class_id_)); + if (control_classes.end() != class_found) { // hmm, update the array of properties, will be updated the list of method handlers auto insert_properties = [&properties, &control_classes](const nc_class_id& class_id_) { auto class_id = make_nc_class_id(class_id_); - auto found = control_classes.find(class_id); - if (control_classes.end() != found) + auto class_id_found = control_classes.find(class_id); + if (control_classes.end() != class_id_found) { - auto& nc_class_properties = found->second.properties.as_array(); + auto& nc_class_properties = class_id_found->second.properties.as_array(); for (auto& nc_class_property : nc_class_properties) { web::json::push_back(properties, nc_class_property); @@ -637,7 +771,7 @@ namespace nmos { methods.insert(nc_block_method_handlers.begin(), nc_block_method_handlers.end()); } - else if (details::nc_device_manager_class_id == class_id) + else if (details::nc_manager_class_id == class_id) { methods.insert(nc_manager_method_handlers.begin(), nc_manager_method_handlers.end()); } @@ -797,11 +931,11 @@ namespace nmos }; } - web::websockets::experimental::listener::message_handler make_control_protocol_ws_message_handler(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_classes_handler get_control_protocol_classes, slog::base_gate& gate_) + web::websockets::experimental::listener::message_handler make_control_protocol_ws_message_handler(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_classes_handler get_control_protocol_classes, nmos::get_control_protocol_datatypes_handler get_control_protocol_datatypes, slog::base_gate& gate_) { using web::json::value; - return [&model, &websockets, get_control_protocol_classes, &gate_](const web::uri& connection_uri, const web::websockets::experimental::listener::connection_id& connection_id, const web::websockets::websocket_incoming_message& msg_) + return [&model, &websockets, get_control_protocol_classes, get_control_protocol_datatypes, &gate_](const web::uri& connection_uri, const web::websockets::experimental::listener::connection_id& connection_id, const web::websockets::websocket_incoming_message& msg_) { nmos::ws_api_gate gate(gate_, connection_uri); @@ -867,11 +1001,11 @@ namespace nmos auto& methods = properties_methods.second; // find the relevent method handler to execute - auto method = methods.find(method_id); - if (method != methods.end()) + auto method_found = methods.find(method_id); + if (method_found != methods.end()) { // execute the relevant method handler, then accumulating up their response to reponses - web::json::push_back(responses, method->second(properties.as_array(), handle, oid, arguments)); + web::json::push_back(responses, method_found->second(properties.as_array(), handle, oid, arguments, get_control_protocol_classes(), get_control_protocol_datatypes())); } else { diff --git a/Development/nmos/control_protocol_ws_api.h b/Development/nmos/control_protocol_ws_api.h index 61c434f38..6f0494ae1 100644 --- a/Development/nmos/control_protocol_ws_api.h +++ b/Development/nmos/control_protocol_ws_api.h @@ -16,15 +16,15 @@ namespace nmos web::websockets::experimental::listener::validate_handler make_control_protocol_ws_validate_handler(nmos::node_model& model, slog::base_gate& gate); web::websockets::experimental::listener::open_handler make_control_protocol_ws_open_handler(nmos::node_model& model, nmos::websockets& websockets, slog::base_gate& gate); web::websockets::experimental::listener::close_handler make_control_protocol_ws_close_handler(nmos::node_model& model, nmos::websockets& websockets, slog::base_gate& gate); - web::websockets::experimental::listener::message_handler make_control_protocol_ws_message_handler(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_classes_handler get_control_protocol_classes, slog::base_gate& gate); + web::websockets::experimental::listener::message_handler make_control_protocol_ws_message_handler(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_classes_handler get_control_protocol_classes, nmos::get_control_protocol_datatypes_handler get_control_protocol_datatypes, slog::base_gate& gate); - inline web::websockets::experimental::listener::websocket_listener_handlers make_control_protocol_ws_api(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_classes_handler get_control_protocol_classes, slog::base_gate& gate) + inline web::websockets::experimental::listener::websocket_listener_handlers make_control_protocol_ws_api(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_classes_handler get_control_protocol_classes, nmos::get_control_protocol_datatypes_handler get_control_protocol_datatypes, slog::base_gate& gate) { return{ nmos::make_control_protocol_ws_validate_handler(model, gate), nmos::make_control_protocol_ws_open_handler(model, websockets, gate), nmos::make_control_protocol_ws_close_handler(model, websockets, gate), - nmos::make_control_protocol_ws_message_handler(model, websockets, get_control_protocol_classes, gate) + nmos::make_control_protocol_ws_message_handler(model, websockets, get_control_protocol_classes, get_control_protocol_datatypes, gate) }; } diff --git a/Development/nmos/node_server.cpp b/Development/nmos/node_server.cpp index 0ac70ee42..d163fdea8 100644 --- a/Development/nmos/node_server.cpp +++ b/Development/nmos/node_server.cpp @@ -72,7 +72,7 @@ namespace nmos const auto& control_protocol_ws_port = nmos::fields::control_protocol_ws_port(node_model.settings); if (control_protocol_ws_port == events_ws_port) throw std::runtime_error("Same port used for events and control protocol websockets are not supported"); auto& control_protocol_ws_api = node_server.ws_handlers[{ {}, control_protocol_ws_port }]; - control_protocol_ws_api.first = nmos::make_control_protocol_ws_api(node_model, control_protocol_ws_api.second, node_implementation.get_control_protocol_classes, gate); + control_protocol_ws_api.first = nmos::make_control_protocol_ws_api(node_model, control_protocol_ws_api.second, node_implementation.get_control_protocol_classes, node_implementation.get_control_protocol_datatypes, gate); // Set up the listeners for each HTTP API port diff --git a/Development/nmos/node_server.h b/Development/nmos/node_server.h index eb1b95bc7..4f897a8e0 100644 --- a/Development/nmos/node_server.h +++ b/Development/nmos/node_server.h @@ -25,7 +25,7 @@ namespace nmos // underlying implementation into the server instance for the NMOS Node struct node_implementation { - node_implementation(nmos::load_server_certificates_handler load_server_certificates, nmos::load_dh_param_handler load_dh_param, nmos::load_ca_certificates_handler load_ca_certificates, nmos::system_global_handler system_changed, nmos::registration_handler registration_changed, nmos::transport_file_parser parse_transport_file, nmos::details::connection_resource_patch_validator validate_staged, nmos::connection_resource_auto_resolver resolve_auto, nmos::connection_sender_transportfile_setter set_transportfile, nmos::connection_activation_handler connection_activated, nmos::ocsp_response_handler get_ocsp_response, nmos::get_control_protocol_classes_handler get_control_protocol_classes) + node_implementation(nmos::load_server_certificates_handler load_server_certificates, nmos::load_dh_param_handler load_dh_param, nmos::load_ca_certificates_handler load_ca_certificates, nmos::system_global_handler system_changed, nmos::registration_handler registration_changed, nmos::transport_file_parser parse_transport_file, nmos::details::connection_resource_patch_validator validate_staged, nmos::connection_resource_auto_resolver resolve_auto, nmos::connection_sender_transportfile_setter set_transportfile, nmos::connection_activation_handler connection_activated, nmos::ocsp_response_handler get_ocsp_response, nmos::get_control_protocol_classes_handler get_control_protocol_classes, nmos::get_control_protocol_datatypes_handler get_control_protocol_datatypes) : load_server_certificates(std::move(load_server_certificates)) , load_dh_param(std::move(load_dh_param)) , load_ca_certificates(std::move(load_ca_certificates)) @@ -38,6 +38,7 @@ namespace nmos , connection_activated(std::move(connection_activated)) , get_ocsp_response(std::move(get_ocsp_response)) , get_control_protocol_classes(std::move(get_control_protocol_classes)) + , get_control_protocol_datatypes(std::move(get_control_protocol_datatypes)) {} // use the default constructor and chaining member functions for fluent initialization @@ -60,6 +61,7 @@ namespace nmos node_implementation& on_channelmapping_activated(nmos::channelmapping_activation_handler channelmapping_activated) { this->channelmapping_activated = std::move(channelmapping_activated); return *this; } node_implementation& on_get_ocsp_response(nmos::ocsp_response_handler get_ocsp_response) { this->get_ocsp_response = std::move(get_ocsp_response); return *this; } node_implementation& on_get_control_classes(nmos::get_control_protocol_classes_handler get_control_protocol_classes) { this->get_control_protocol_classes = std::move(get_control_protocol_classes); return* this; } + node_implementation& on_get_control_datatypes(nmos::get_control_protocol_datatypes_handler get_control_protocol_datatypes) { this->get_control_protocol_datatypes = std::move(get_control_protocol_datatypes); return*this; } // deprecated, use on_validate_connection_resource_patch node_implementation& on_validate_merged(nmos::details::connection_resource_patch_validator validate_merged) { return on_validate_connection_resource_patch(std::move(validate_merged)); } @@ -91,6 +93,7 @@ namespace nmos nmos::ocsp_response_handler get_ocsp_response; nmos::get_control_protocol_classes_handler get_control_protocol_classes; + nmos::get_control_protocol_datatypes_handler get_control_protocol_datatypes; }; // Construct a server instance for an NMOS Node, implementing the IS-04 Node API, IS-05 Connection API, IS-07 Events API From 6eddf4ed68b7c22a802a8fa4c49e8d00da50267c Mon Sep 17 00:00:00 2001 From: lo-simon Date: Wed, 16 Aug 2023 11:09:45 +0100 Subject: [PATCH 020/106] Bump up ubuntu 14.04 to use python 3.7 to overcome ERROR: module 'asyncio' has no attribute 'get_running_loop' and CryptographyDeprecationWarning: Python 3.6 is no longer supported by the Python core team --- .github/workflows/build-test.yml | 10 +++++----- .github/workflows/src/build-test.yml | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index ed8737899..c5e35acd4 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -579,13 +579,13 @@ jobs: apt-get --allow-unauthenticated install -y curl g++ git make patch zlib1g-dev libssl-dev bsdmainutils dnsutils unzip # ubuntu-14.04 ca-certificates are out of date git config --global http.sslVerify false - curl -sS https://www.python.org/ftp/python/3.6.9/Python-3.6.9.tar.xz | tar -xJ - cd Python-3.6.9 + curl -sS https://www.python.org/ftp/python/3.7.0/Python-3.7.0.tar.xz | tar -xJ + cd Python-3.7.0 ./configure make -j8 make install - update-alternatives --install /usr/bin/python3 python3 /usr/local/bin/python3.6 3 - ln -s /usr/local/bin/python3.6 /usr/bin/python + update-alternatives --install /usr/bin/python3 python3 /usr/local/bin/python3.7 3 + ln -s /usr/local/bin/python3.7 /usr/bin/python curl -sS https://bootstrap.pypa.io/pip/3.6/get-pip.py | python curl -sS https://nodejs.org/dist/v12.16.2/node-v12.16.2-linux-x64.tar.xz | tar -xJ echo "`pwd`/node-v12.16.2-linux-x64/bin" >> $GITHUB_PATH @@ -1075,4 +1075,4 @@ jobs: git config --global user.name 'test-results-uploader' git config --global user.email 'test-results-uploader@nmos-cpp.iam.gserviceaccount.com' git commit -qm "Badges for README at ${{ env.GITHUB_COMMIT }}" - git push -f `git remote` badges-${{ env.GITHUB_COMMIT }}:badges + git push -f `git remote` badges-${{ env.GITHUB_COMMIT }}:badges \ No newline at end of file diff --git a/.github/workflows/src/build-test.yml b/.github/workflows/src/build-test.yml index 0b5663ff3..9e3c26b5c 100644 --- a/.github/workflows/src/build-test.yml +++ b/.github/workflows/src/build-test.yml @@ -129,13 +129,13 @@ jobs: apt-get --allow-unauthenticated install -y curl g++ git make patch zlib1g-dev libssl-dev bsdmainutils dnsutils unzip # ubuntu-14.04 ca-certificates are out of date git config --global http.sslVerify false - curl -sS https://www.python.org/ftp/python/3.6.9/Python-3.6.9.tar.xz | tar -xJ - cd Python-3.6.9 + curl -sS https://www.python.org/ftp/python/3.7.0/Python-3.7.0.tar.xz | tar -xJ + cd Python-3.7.0 ./configure make -j8 make install - update-alternatives --install /usr/bin/python3 python3 /usr/local/bin/python3.6 3 - ln -s /usr/local/bin/python3.6 /usr/bin/python + update-alternatives --install /usr/bin/python3 python3 /usr/local/bin/python3.7 3 + ln -s /usr/local/bin/python3.7 /usr/bin/python curl -sS https://bootstrap.pypa.io/pip/3.6/get-pip.py | python curl -sS https://nodejs.org/dist/v12.16.2/node-v12.16.2-linux-x64.tar.xz | tar -xJ echo "`pwd`/node-v12.16.2-linux-x64/bin" >> $GITHUB_PATH From fa17cd110ab69d986b3bb4f8c58d0a5ea424e482 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Wed, 16 Aug 2023 11:26:58 +0100 Subject: [PATCH 021/106] Fix ModuleNotFoundError: No module named '_ctypes' --- .github/workflows/build-test.yml | 2 +- .github/workflows/src/build-test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index c5e35acd4..27490c47e 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -576,7 +576,7 @@ jobs: apt-get update -q apt-get install -y software-properties-common apt-get --allow-unauthenticated update -q - apt-get --allow-unauthenticated install -y curl g++ git make patch zlib1g-dev libssl-dev bsdmainutils dnsutils unzip + apt-get --allow-unauthenticated install -y curl g++ git make patch zlib1g-dev libssl-dev bsdmainutils dnsutils unzip libffi-dev # ubuntu-14.04 ca-certificates are out of date git config --global http.sslVerify false curl -sS https://www.python.org/ftp/python/3.7.0/Python-3.7.0.tar.xz | tar -xJ diff --git a/.github/workflows/src/build-test.yml b/.github/workflows/src/build-test.yml index 9e3c26b5c..2cd99001d 100644 --- a/.github/workflows/src/build-test.yml +++ b/.github/workflows/src/build-test.yml @@ -126,7 +126,7 @@ jobs: apt-get update -q apt-get install -y software-properties-common apt-get --allow-unauthenticated update -q - apt-get --allow-unauthenticated install -y curl g++ git make patch zlib1g-dev libssl-dev bsdmainutils dnsutils unzip + apt-get --allow-unauthenticated install -y curl g++ git make patch zlib1g-dev libssl-dev bsdmainutils dnsutils unzip libffi-dev # ubuntu-14.04 ca-certificates are out of date git config --global http.sslVerify false curl -sS https://www.python.org/ftp/python/3.7.0/Python-3.7.0.tar.xz | tar -xJ From a356f3efa15bd0adc6690ce8fadc705dffa451bb Mon Sep 17 00:00:00 2001 From: lo-simon Date: Wed, 16 Aug 2023 11:42:54 +0100 Subject: [PATCH 022/106] Fixing python3.7 install --- .github/workflows/build-test.yml | 2 +- .github/workflows/src/build-test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 27490c47e..117ab340d 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -576,7 +576,7 @@ jobs: apt-get update -q apt-get install -y software-properties-common apt-get --allow-unauthenticated update -q - apt-get --allow-unauthenticated install -y curl g++ git make patch zlib1g-dev libssl-dev bsdmainutils dnsutils unzip libffi-dev + apt-get --allow-unauthenticated install -y curl g++ git make patch zlib1g-dev libssl-dev bsdmainutils dnsutils unzip libffi-dev libreadline-gplv2-dev libncursesw5-dev libsqlite3-dev tk-dev libgdbm-dev libc6-dev libbz2-dev # ubuntu-14.04 ca-certificates are out of date git config --global http.sslVerify false curl -sS https://www.python.org/ftp/python/3.7.0/Python-3.7.0.tar.xz | tar -xJ diff --git a/.github/workflows/src/build-test.yml b/.github/workflows/src/build-test.yml index 2cd99001d..e4f254f23 100644 --- a/.github/workflows/src/build-test.yml +++ b/.github/workflows/src/build-test.yml @@ -126,7 +126,7 @@ jobs: apt-get update -q apt-get install -y software-properties-common apt-get --allow-unauthenticated update -q - apt-get --allow-unauthenticated install -y curl g++ git make patch zlib1g-dev libssl-dev bsdmainutils dnsutils unzip libffi-dev + apt-get --allow-unauthenticated install -y curl g++ git make patch zlib1g-dev libssl-dev bsdmainutils dnsutils unzip libffi-dev libreadline-gplv2-dev libncursesw5-dev libsqlite3-dev tk-dev libgdbm-dev libc6-dev libbz2-dev # ubuntu-14.04 ca-certificates are out of date git config --global http.sslVerify false curl -sS https://www.python.org/ftp/python/3.7.0/Python-3.7.0.tar.xz | tar -xJ From 15a4e19dbdf518f5d2a222fc2776e1fb69a8dbe0 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Wed, 16 Aug 2023 11:56:49 +0100 Subject: [PATCH 023/106] Bump up to python3.8 --- .github/workflows/build-test.yml | 10 +++++----- .github/workflows/src/build-test.yml | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 117ab340d..4df6c575d 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -576,16 +576,16 @@ jobs: apt-get update -q apt-get install -y software-properties-common apt-get --allow-unauthenticated update -q - apt-get --allow-unauthenticated install -y curl g++ git make patch zlib1g-dev libssl-dev bsdmainutils dnsutils unzip libffi-dev libreadline-gplv2-dev libncursesw5-dev libsqlite3-dev tk-dev libgdbm-dev libc6-dev libbz2-dev + apt-get --allow-unauthenticated install -y curl g++ git make patch zlib1g-dev libssl-dev bsdmainutils dnsutils unzip libffi-dev # ubuntu-14.04 ca-certificates are out of date git config --global http.sslVerify false - curl -sS https://www.python.org/ftp/python/3.7.0/Python-3.7.0.tar.xz | tar -xJ - cd Python-3.7.0 + curl -sS https://www.python.org/ftp/python/3.8.0/Python-3.8.0.tar.xz | tar -xJ + cd Python-3.8.0 ./configure make -j8 make install - update-alternatives --install /usr/bin/python3 python3 /usr/local/bin/python3.7 3 - ln -s /usr/local/bin/python3.7 /usr/bin/python + update-alternatives --install /usr/bin/python3 python3 /usr/local/bin/python3.8 3 + ln -s /usr/local/bin/python3.8 /usr/bin/python curl -sS https://bootstrap.pypa.io/pip/3.6/get-pip.py | python curl -sS https://nodejs.org/dist/v12.16.2/node-v12.16.2-linux-x64.tar.xz | tar -xJ echo "`pwd`/node-v12.16.2-linux-x64/bin" >> $GITHUB_PATH diff --git a/.github/workflows/src/build-test.yml b/.github/workflows/src/build-test.yml index e4f254f23..be9e9d513 100644 --- a/.github/workflows/src/build-test.yml +++ b/.github/workflows/src/build-test.yml @@ -126,16 +126,16 @@ jobs: apt-get update -q apt-get install -y software-properties-common apt-get --allow-unauthenticated update -q - apt-get --allow-unauthenticated install -y curl g++ git make patch zlib1g-dev libssl-dev bsdmainutils dnsutils unzip libffi-dev libreadline-gplv2-dev libncursesw5-dev libsqlite3-dev tk-dev libgdbm-dev libc6-dev libbz2-dev + apt-get --allow-unauthenticated install -y curl g++ git make patch zlib1g-dev libssl-dev bsdmainutils dnsutils unzip libffi-dev # ubuntu-14.04 ca-certificates are out of date git config --global http.sslVerify false - curl -sS https://www.python.org/ftp/python/3.7.0/Python-3.7.0.tar.xz | tar -xJ - cd Python-3.7.0 + curl -sS https://www.python.org/ftp/python/3.8.0/Python-3.8.0.tar.xz | tar -xJ + cd Python-3.8.0 ./configure make -j8 make install - update-alternatives --install /usr/bin/python3 python3 /usr/local/bin/python3.7 3 - ln -s /usr/local/bin/python3.7 /usr/bin/python + update-alternatives --install /usr/bin/python3 python3 /usr/local/bin/python3.8 3 + ln -s /usr/local/bin/python3.8 /usr/bin/python curl -sS https://bootstrap.pypa.io/pip/3.6/get-pip.py | python curl -sS https://nodejs.org/dist/v12.16.2/node-v12.16.2-linux-x64.tar.xz | tar -xJ echo "`pwd`/node-v12.16.2-linux-x64/bin" >> $GITHUB_PATH From 70155a41a6e77b20bd651091581caa36c8507b8c Mon Sep 17 00:00:00 2001 From: lo-simon Date: Fri, 18 Aug 2023 10:43:03 +0100 Subject: [PATCH 024/106] Add NcIdentBeacon, NcReceiverMonitor and NcReceiverMonitorProtected --- Development/nmos-cpp-node/main.cpp | 2 +- .../nmos-cpp-node/node_implementation.cpp | 11 +- .../nmos-cpp-node/node_implementation.h | 3 +- .../nmos/control_protocol_resource.cpp | 921 +++++++++++------- Development/nmos/control_protocol_resource.h | 270 +++-- .../nmos/control_protocol_resources.cpp | 4 +- Development/nmos/control_protocol_resources.h | 7 +- Development/nmos/control_protocol_state.cpp | 38 +- Development/nmos/control_protocol_state.h | 26 +- Development/nmos/control_protocol_ws_api.cpp | 717 ++++++++++++-- Development/nmos/json_fields.h | 14 + 11 files changed, 1504 insertions(+), 509 deletions(-) diff --git a/Development/nmos-cpp-node/main.cpp b/Development/nmos-cpp-node/main.cpp index 159ef35da..5b17eebb5 100644 --- a/Development/nmos-cpp-node/main.cpp +++ b/Development/nmos-cpp-node/main.cpp @@ -129,7 +129,7 @@ int main(int argc, char* argv[]) // Add the underlying implementation, which will set up the node resources, etc. - node_server.thread_functions.push_back([&] { node_implementation_thread(node_model, gate); }); + node_server.thread_functions.push_back([&] { node_implementation_thread(node_model, control_protocol_state, gate); }); // only implement communication with OCSP server if http_listener supports OCSP stapling // cf. preprocessor conditions in nmos::make_http_listener_config diff --git a/Development/nmos-cpp-node/node_implementation.cpp b/Development/nmos-cpp-node/node_implementation.cpp index e72dcc24b..d232d3bf3 100644 --- a/Development/nmos-cpp-node/node_implementation.cpp +++ b/Development/nmos-cpp-node/node_implementation.cpp @@ -22,6 +22,7 @@ #include "nmos/connection_resources.h" #include "nmos/connection_events_activation.h" #include "nmos/control_protocol_resources.h" +#include "nmos/control_protocol_state.h" #include "nmos/events_resources.h" #include "nmos/format.h" #include "nmos/group_hint.h" @@ -187,7 +188,7 @@ namespace impl } // forward declarations for node_implementation_thread -void node_implementation_init(nmos::node_model& model, slog::base_gate& gate); +void node_implementation_init(nmos::node_model& model, const nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate); void node_implementation_run(nmos::node_model& model, slog::base_gate& gate); nmos::connection_resource_auto_resolver make_node_implementation_auto_resolver(const nmos::settings& settings); nmos::connection_sender_transportfile_setter make_node_implementation_transportfile_setter(const nmos::resources& node_resources, const nmos::settings& settings); @@ -197,13 +198,13 @@ struct node_implementation_init_exception {}; // This is an example of how to integrate the nmos-cpp library with a device-specific underlying implementation. // It constructs and inserts a node resource and some sub-resources into the model, based on the model settings, // starts background tasks to emit regular events from the temperature event source, and then waits for shutdown. -void node_implementation_thread(nmos::node_model& model, slog::base_gate& gate_) +void node_implementation_thread(nmos::node_model& model, const nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate_) { nmos::details::omanip_gate gate{ gate_, nmos::stash_category(impl::categories::node_implementation) }; try { - node_implementation_init(model, gate); + node_implementation_init(model, control_protocol_state, gate); node_implementation_run(model, gate); } catch (const node_implementation_init_exception&) @@ -233,7 +234,7 @@ void node_implementation_thread(nmos::node_model& model, slog::base_gate& gate_) } } -void node_implementation_init(nmos::node_model& model, slog::base_gate& gate) +void node_implementation_init(nmos::node_model& model, const nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate) { using web::json::value; using web::json::value_from_elements; @@ -902,7 +903,7 @@ void node_implementation_init(nmos::node_model& model, slog::base_gate& gate) auto device_manager = nmos::make_device_manager(2, root_block, model.settings); if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(device_manager), gate)) throw node_implementation_init_exception(); // example class manager - auto class_manager = nmos::make_class_manager(3, root_block); + auto class_manager = nmos::make_class_manager(3, root_block, control_protocol_state); if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(class_manager), gate)) throw node_implementation_init_exception(); // insert root block to model if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(root_block), gate)) throw node_implementation_init_exception(); diff --git a/Development/nmos-cpp-node/node_implementation.h b/Development/nmos-cpp-node/node_implementation.h index 421769f38..c5d6504da 100644 --- a/Development/nmos-cpp-node/node_implementation.h +++ b/Development/nmos-cpp-node/node_implementation.h @@ -13,13 +13,14 @@ namespace nmos namespace experimental { struct node_implementation; + struct control_protocol_state; } } // This is an example of how to integrate the nmos-cpp library with a device-specific underlying implementation. // It constructs and inserts a node resource and some sub-resources into the model, based on the model settings, // starts background tasks to emit regular events from the temperature event source, and then waits for shutdown. -void node_implementation_thread(nmos::node_model& model, slog::base_gate& gate); +void node_implementation_thread(nmos::node_model& model, const nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate); // This constructs all the callbacks used to integrate the example device-specific underlying implementation // into the server instance for the NMOS Node. diff --git a/Development/nmos/control_protocol_resource.cpp b/Development/nmos/control_protocol_resource.cpp index 9a98eb4cf..b456443f7 100644 --- a/Development/nmos/control_protocol_resource.cpp +++ b/Development/nmos/control_protocol_resource.cpp @@ -334,7 +334,7 @@ namespace nmos // description can be null // constraints can be null // items: sequence - web::json::value make_nc_datatype_descriptor_enum(const web::json::value& description, const utility::string_t& name, const web::json::value& constraints, const web::json::value& items) + web::json::value make_nc_datatype_descriptor_enum(const web::json::value& description, const utility::string_t& name, const web::json::value& items, const web::json::value& constraints) { auto data = make_nc_datatype_descriptor(description, name, nc_datatype_type::Enum, constraints); data[nmos::fields::nc::items] = items; @@ -355,7 +355,7 @@ namespace nmos // constraints can be null // fields: sequence // parent_type can be null - web::json::value make_nc_datatype_descriptor_struct(const web::json::value& description, const utility::string_t& name, const web::json::value& constraints, const web::json::value& fields, const web::json::value& parent_type) + web::json::value make_nc_datatype_descriptor_struct(const web::json::value& description, const utility::string_t& name, const web::json::value& fields, const web::json::value& parent_type, const web::json::value& constraints) { auto data = make_nc_datatype_descriptor(description, name, nc_datatype_type::Struct, constraints); data[nmos::fields::nc::fields] = fields; @@ -367,7 +367,7 @@ namespace nmos // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptortypedef // description can be null // constraints can be null - web::json::value make_nc_datatype_typedef(const web::json::value& description, const utility::string_t& name, const web::json::value& constraints, const utility::string_t& parent_type, bool is_sequence) + web::json::value make_nc_datatype_typedef(const web::json::value& description, const utility::string_t& name, bool is_sequence, const utility::string_t& parent_type, const web::json::value& constraints) { using web::json::value; @@ -378,23 +378,23 @@ namespace nmos return data; } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject web::json::value make_nc_object_properties() { using web::json::value; auto properties = value::array(); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Static value. All instances of the same class will have the same identity value")), make_nc_property_id(1, 1), nmos::fields::nc::class_id, value::string(U("NcClassId")), true, false, false, false, value::null())); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Object identifier")), make_nc_property_id(1, 2), nmos::fields::nc::oid, value::string(U("NcOid")), true, false, false, false, value::null())); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("TRUE iff OID is hardwired into device")), make_nc_property_id(1, 3), nmos::fields::nc::constant_oid, value::string(U("NcBoolean")), true, false, false, false, value::null())); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("OID of containing block. Can only ever be null for the root block")), make_nc_property_id(1, 4), nmos::fields::nc::owner, value::string(U("NcOid")), true, true, false, false, value::null())); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Role of object in the containing block")), make_nc_property_id(1, 5), nmos::fields::nc::role, value::string(U("NcString")), true, false, false, false, value::null())); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Scribble strip")), make_nc_property_id(1, 6), nmos::fields::nc::user_label, value::string(U("NcString")), false, true, false, false, value::null())); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Touchpoints to other contexts")), make_nc_property_id(1, 7), nmos::fields::nc::touchpoints, value::string(U("NcTouchpoint")), true, true, true, false, value::null())); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Runtime property constraints")), make_nc_property_id(1, 8), nmos::fields::nc::runtime_property_constraints, value::string(U("NcPropertyConstraints")), true, true, true, false, value::null())); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Static value. All instances of the same class will have the same identity value")), make_nc_property_id(1, 1), nmos::fields::nc::class_id, value::string(U("NcClassId")), true, false, false, false)); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Object identifier")), make_nc_property_id(1, 2), nmos::fields::nc::oid, value::string(U("NcOid")), true, false, false, false)); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("TRUE iff OID is hardwired into device")), make_nc_property_id(1, 3), nmos::fields::nc::constant_oid, value::string(U("NcBoolean")), true, false, false, false)); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("OID of containing block. Can only ever be null for the root block")), make_nc_property_id(1, 4), nmos::fields::nc::owner, value::string(U("NcOid")), true, true, false, false)); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Role of object in the containing block")), make_nc_property_id(1, 5), nmos::fields::nc::role, value::string(U("NcString")), true, false, false, false)); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Scribble strip")), make_nc_property_id(1, 6), nmos::fields::nc::user_label, value::string(U("NcString")), false, true, false, false)); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Touchpoints to other contexts")), make_nc_property_id(1, 7), nmos::fields::nc::touchpoints, value::string(U("NcTouchpoint")), true, true, true, false)); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Runtime property constraints")), make_nc_property_id(1, 8), nmos::fields::nc::runtime_property_constraints, value::string(U("NcPropertyConstraints")), true, true, true, false)); return properties; } - web::json::value make_nc_object_methods() { using web::json::value; @@ -402,49 +402,48 @@ namespace nmos auto methods = value::array(); { auto parameters = value::array(); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false)); web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Get property value")), make_nc_method_id(1, 1), U("Get"), U("NcMethodResultPropertyValue"), parameters, false)); } { auto parameters = value::array(); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Property value")), nmos::fields::nc::value, value::null(), true, false, value::null())); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false)); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Property value")), nmos::fields::nc::value, value::null(), true, false)); web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Set property value")), make_nc_method_id(1, 2), U("Set"), U("NcMethodResult"), parameters, false)); } { auto parameters = value::array(); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Index of item in the sequence")), nmos::fields::nc::index, value::string(U("NcId")), false, false, value::null())); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false)); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Index of item in the sequence")), nmos::fields::nc::index, value::string(U("NcId")), false, false)); web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Get sequence item")), make_nc_method_id(1, 3), U("GetSequenceItem"), U("NcMethodResultPropertyValue"), parameters, false)); } { auto parameters = value::array(); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Index of item in the sequence")), nmos::fields::nc::index, value::string(U("NcId")), false, false, value::null())); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Value")), nmos::fields::nc::value, value::null(), true, false, value::null())); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false)); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Index of item in the sequence")), nmos::fields::nc::index, value::string(U("NcId")), false, false)); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Value")), nmos::fields::nc::value, value::null(), true, false)); web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Set sequence item value")), make_nc_method_id(1, 4), U("SetSequenceItem"), U("NcMethodResult"), parameters, false)); } { auto parameters = value::array(); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Value")), nmos::fields::nc::value, value::null(), true, false, value::null())); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false)); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Value")), nmos::fields::nc::value, value::null(), true, false)); web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Add item to sequence")), make_nc_method_id(1, 5), U("AddSequenceItem"), U("NcMethodResultId"), parameters, false)); } { auto parameters = value::array(); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Index of item in the sequence")), nmos::fields::nc::index, value::string(U("NcId")), false, false, value::null())); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false)); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Index of item in the sequence")), nmos::fields::nc::index, value::string(U("NcId")), false, false)); web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Delete sequence item")), make_nc_method_id(1, 6), U("RemoveSequenceItem"), U("NcMethodResult"), parameters, false)); } { auto parameters = value::array(); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false)); web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Get sequence length")), make_nc_method_id(1, 7), U("GetSequenceLength"), U("NcMethodResultLength"), parameters, false)); } return methods; } - web::json::value make_nc_object_events() { using web::json::value; @@ -455,17 +454,17 @@ namespace nmos return events; } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock web::json::value make_nc_block_properties() { using web::json::value; auto properties = value::array(); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("TRUE if block is functional")), make_nc_property_id(2, 1), nmos::fields::nc::enabled, value::string(U("NcBoolean")), true, false, false, false, value::null())); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Descriptors of this block's members")), make_nc_property_id(2, 2), nmos::fields::nc::members, value::string(U("NcBlockMemberDescriptor")), true, false, true, false, value::null())); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("TRUE if block is functional")), make_nc_property_id(2, 1), nmos::fields::nc::enabled, value::string(U("NcBoolean")), true, false, false, false)); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Descriptors of this block's members")), make_nc_property_id(2, 2), nmos::fields::nc::members, value::string(U("NcBlockMemberDescriptor")), true, false, true, false)); return properties; } - web::json::value make_nc_block_methods() { using web::json::value; @@ -473,33 +472,32 @@ namespace nmos auto methods = value::array(); { auto parameters = value::array(); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("If recurse is set to true, nested members can be retrieved")), nmos::fields::nc::recurse, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("If recurse is set to true, nested members can be retrieved")), nmos::fields::nc::recurse, value::string(U("NcBoolean")), false, false)); web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Gets descriptors of members of the block")), make_nc_method_id(2, 1), U("GetMemberDescriptors"), U("NcMethodResultBlockMemberDescriptors"), parameters, false)); } { auto parameters = value::array(); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Relative path to search for (MUST not include the role of the block targeted by oid)")), nmos::fields::nc::path, value::string(U("NcRolePath")), false, false, value::null())); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Relative path to search for (MUST not include the role of the block targeted by oid)")), nmos::fields::nc::path, value::string(U("NcRolePath")), false, false)); web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Finds member(s) by path")), make_nc_method_id(2, 2), U("FindMembersByPath"), U("NcMethodResultBlockMemberDescriptors"), parameters, false)); } { auto parameters = value::array(); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Role text to search for")), nmos::fields::nc::role, value::string(U("NcString")), false, false, value::null())); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Signals if the comparison should be case sensitive")), nmos::fields::nc::case_sensitive, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("TRUE to only return exact matches")), nmos::fields::nc::match_whole_string, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("TRUE to search nested blocks")), nmos::fields::nc::recurse, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Role text to search for")), nmos::fields::nc::role, value::string(U("NcString")), false, false)); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Signals if the comparison should be case sensitive")), nmos::fields::nc::case_sensitive, value::string(U("NcBoolean")), false, false)); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("TRUE to only return exact matches")), nmos::fields::nc::match_whole_string, value::string(U("NcBoolean")), false, false)); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("TRUE to search nested blocks")), nmos::fields::nc::recurse, value::string(U("NcBoolean")), false, false)); web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Finds members with given role name or fragment")), make_nc_method_id(2, 3), U("FindMembersByRole"), U("NcMethodResultBlockMemberDescriptors"), parameters, false)); } { auto parameters = value::array(); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Class id to search for")), nmos::fields::nc::class_id, value::string(U("NcClassId")), false, false, value::null())); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("If TRUE it will also include derived class descriptors")), nmos::fields::nc::include_derived, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("TRUE to search nested blocks")), nmos::fields::nc::recurse, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Class id to search for")), nmos::fields::nc::class_id, value::string(U("NcClassId")), false, false)); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("If TRUE it will also include derived class descriptors")), nmos::fields::nc::include_derived, value::string(U("NcBoolean")), false, false)); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("TRUE to search nested blocks")), nmos::fields::nc::recurse, value::string(U("NcBoolean")), false, false)); web::json::push_back(methods, details::make_nc_method_descriptor(value::string(U("Finds members with given class id")), details::make_nc_method_id(2, 4), U("FindMembersByClassId"), U("NcMethodResultBlockMemberDescriptors"), parameters, false)); } return methods; } - web::json::value make_nc_block_events() { using web::json::value; @@ -507,23 +505,22 @@ namespace nmos return value::array(); } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncworker web::json::value make_nc_worker_properties() { using web::json::value; auto properties = value::array(); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("TRUE iff worker is enabled")), make_nc_property_id(2, 1), nmos::fields::nc::enabled, value::string(U("NcBoolean")), false, false, false, false, value::null())); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("TRUE iff worker is enabled")), make_nc_property_id(2, 1), nmos::fields::nc::enabled, value::string(U("NcBoolean")), false, false, false, false)); return properties; } - web::json::value make_nc_worker_methods() { using web::json::value; return value::array(); } - web::json::value make_nc_worker_events() { using web::json::value; @@ -531,20 +528,19 @@ namespace nmos return value::array(); } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanager web::json::value make_nc_manager_properties() { using web::json::value; return value::array(); } - web::json::value make_nc_manager_methods() { using web::json::value; return value::array(); } - web::json::value make_nc_manager_events() { using web::json::value; @@ -552,32 +548,31 @@ namespace nmos return value::array(); } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager web::json::value make_nc_device_manager_properties() { using web::json::value; auto properties = value::array(); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Version of MS-05-02 that this device uses")), make_nc_property_id(3, 1), nmos::fields::nc::nc_version, value::string(U("NcVersionCode")), true, false, false, false, value::null())); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Manufacturer descriptor")), make_nc_property_id(3, 2), nmos::fields::nc::manufacturer, value::string(U("NcManufacturer")), true, false, false, false, value::null())); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Product descriptor")), make_nc_property_id(3, 3), nmos::fields::nc::product, value::string(U("NcProduct")), true, false, false, false, value::null())); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Serial number")), make_nc_property_id(3, 4), nmos::fields::nc::serial_number, value::string(U("NcString")), true, false, false, false, value::null())); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Asset tracking identifier (user specified)")), make_nc_property_id(3, 5), nmos::fields::nc::user_inventory_code, value::string(U("NcString")), false, true, false, false, value::null())); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Name of this device in the application. Instance name, not product name")), make_nc_property_id(3, 6), nmos::fields::nc::device_name, value::string(U("NcString")), false, true, false, false, value::null())); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Role of this device in the application")), make_nc_property_id(3, 7), nmos::fields::nc::device_role, value::string(U("NcString")), false, true, false, false, value::null())); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Device operational state")), make_nc_property_id(3, 8), nmos::fields::nc::operational_state, value::string(U("NcDeviceOperationalState")), true, false, false, false, value::null())); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Reason for most recent reset")), make_nc_property_id(3, 9), nmos::fields::nc::reset_cause, value::string(U("NcResetCause")), true, false, false, false, value::null())); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Arbitrary message from dev to controller")), make_nc_property_id(3, 10), nmos::fields::nc::message, value::string(U("NcString")), true, true, false, false, value::null())); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Version of MS-05-02 that this device uses")), make_nc_property_id(3, 1), nmos::fields::nc::nc_version, value::string(U("NcVersionCode")), true, false, false, false)); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Manufacturer descriptor")), make_nc_property_id(3, 2), nmos::fields::nc::manufacturer, value::string(U("NcManufacturer")), true, false, false, false)); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Product descriptor")), make_nc_property_id(3, 3), nmos::fields::nc::product, value::string(U("NcProduct")), true, false, false, false)); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Serial number")), make_nc_property_id(3, 4), nmos::fields::nc::serial_number, value::string(U("NcString")), true, false, false, false)); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Asset tracking identifier (user specified)")), make_nc_property_id(3, 5), nmos::fields::nc::user_inventory_code, value::string(U("NcString")), false, true, false, false)); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Name of this device in the application. Instance name, not product name")), make_nc_property_id(3, 6), nmos::fields::nc::device_name, value::string(U("NcString")), false, true, false, false)); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Role of this device in the application")), make_nc_property_id(3, 7), nmos::fields::nc::device_role, value::string(U("NcString")), false, true, false, false)); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Device operational state")), make_nc_property_id(3, 8), nmos::fields::nc::operational_state, value::string(U("NcDeviceOperationalState")), true, false, false, false)); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Reason for most recent reset")), make_nc_property_id(3, 9), nmos::fields::nc::reset_cause, value::string(U("NcResetCause")), true, false, false, false)); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Arbitrary message from dev to controller")), make_nc_property_id(3, 10), nmos::fields::nc::message, value::string(U("NcString")), true, true, false, false)); return properties; } - web::json::value make_nc_device_manager_methods() { using web::json::value; return value::array(); } - web::json::value make_nc_device_manager_events() { using web::json::value; @@ -585,17 +580,17 @@ namespace nmos return value::array(); } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager web::json::value make_nc_class_manager_properties() { using web::json::value; auto properties = value::array(); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Descriptions of all control classes in the device (descriptors do not contain inherited elements)")), make_nc_property_id(3, 1), nmos::fields::nc::control_classes, value::string(U("NcClassDescriptor")), true, false, true, false, value::null())); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Descriptions of all data types in the device (descriptors do not contain inherited elements)")), make_nc_property_id(3, 2), nmos::fields::nc::datatypes, value::string(U("NcDatatypeDescriptor")), true, false, true, false, value::null())); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Descriptions of all control classes in the device (descriptors do not contain inherited elements)")), make_nc_property_id(3, 1), nmos::fields::nc::control_classes, value::string(U("NcClassDescriptor")), true, false, true, false)); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Descriptions of all data types in the device (descriptors do not contain inherited elements)")), make_nc_property_id(3, 2), nmos::fields::nc::datatypes, value::string(U("NcDatatypeDescriptor")), true, false, true, false)); return properties; } - web::json::value make_nc_class_manager_methods() { using web::json::value; @@ -603,20 +598,19 @@ namespace nmos auto methods = value::array(); { auto parameters = value::array(); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("class ID")), nmos::fields::nc::class_id, value::string(U("NcClassId")), false, false, value::null())); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("If set the descriptor would contain all inherited elements")), nmos::fields::nc::include_inherited, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("class ID")), nmos::fields::nc::class_id, value::string(U("NcClassId")), false, false)); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("If set the descriptor would contain all inherited elements")), nmos::fields::nc::include_inherited, value::string(U("NcBoolean")), false, false)); web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Get a single class descriptor")), make_nc_method_id(3, 1), U("GetControlClass"), U("NcMethodResultClassDescriptor"), parameters, false)); } { auto parameters = value::array(); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("name of datatype")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("If set the descriptor would contain all inherited elements")), nmos::fields::nc::include_inherited, value::string(U("NcBoolean")), false, false, value::null())); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("name of datatype")), nmos::fields::nc::name, value::string(U("NcName")), false, false)); + web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("If set the descriptor would contain all inherited elements")), nmos::fields::nc::include_inherited, value::string(U("NcBoolean")), false, false)); web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Get a single datatype descriptor")), make_nc_method_id(3, 2), U("GetDatatype"), U("NcMethodResultDatatypeDescriptor"), parameters, false)); } return methods; } - web::json::value make_nc_class_manager_events() { using web::json::value; @@ -624,6 +618,79 @@ namespace nmos return value::array(); } + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitor + web::json::value make_nc_receiver_monitor_properties() + { + using web::json::value; + + auto properties = value::array(); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Connection status property")), make_nc_property_id(3, 1), nmos::fields::nc::connection_status, value::string(U("NcConnectionStatus")), true, false, false, false)); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Connection status message property")), make_nc_property_id(3, 2), nmos::fields::nc::connection_status_message, value::string(U("NcString")), true, true, false, false)); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Payload status property")), make_nc_property_id(3, 3), nmos::fields::nc::payload_status, value::string(U("NcPayloadStatus")), true, false, false, false)); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Payload status message property")), make_nc_property_id(3, 4), nmos::fields::nc::payload_status_message, value::string(U("NcString")), true, true, false, false)); + + return properties; + } + web::json::value make_nc_receiver_monitor_methods() + { + using web::json::value; + + return value::array(); + } + web::json::value make_nc_receiver_monitor_events() + { + using web::json::value; + + return value::array(); + } + + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitorprotected + web::json::value make_nc_receiver_monitor_protected_properties() + { + using web::json::value; + + auto properties = value::array(); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Indicates if signal protection is active")), make_nc_property_id(4, 1), nmos::fields::nc::signal_protection_status, value::string(U("NcBoolean")), true, false, false, false)); + + return properties; + } + web::json::value make_nc_receiver_monitor_protected_methods() + { + using web::json::value; + + return value::array(); + } + web::json::value make_nc_receiver_monitor_protected_events() + { + using web::json::value; + + return value::array(); + } + + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/identification/#ncidentbeacon + web::json::value make_nc_ident_beacon_properties() + { + using web::json::value; + + auto properties = value::array(); + web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Indicator active state")), make_nc_property_id(3, 1), nmos::fields::nc::active, value::string(U("NcBoolean")), false, false, false, false)); + + return properties; + } + web::json::value make_nc_ident_beacon_methods() + { + using web::json::value; + + return value::array(); + } + web::json::value make_nc_ident_beacon_events() + { + using web::json::value; + + return value::array(); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.html web::json::value make_nc_object_class() { using web::json::value; @@ -631,6 +698,7 @@ namespace nmos return make_nc_class_descriptor(value::string(U("NcObject class descriptor")), nc_object_class_id, U("NcObject"), value::null(), make_nc_object_properties(), make_nc_object_methods(), make_nc_object_events()); } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.1.html web::json::value make_nc_block_class() { using web::json::value; @@ -638,6 +706,7 @@ namespace nmos return make_nc_class_descriptor(value::string(U("NcBlock class descriptor")), nc_block_class_id, U("NcBlock"), value::null(), make_nc_block_properties(), make_nc_block_methods(), make_nc_block_events()); } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.2.html web::json::value make_nc_worker_class() { using web::json::value; @@ -645,6 +714,7 @@ namespace nmos return make_nc_class_descriptor(value::string(U("NcWorker class descriptor")), nc_worker_class_id, U("NcWorker"), value::null(), make_nc_worker_properties(), make_nc_worker_methods(), make_nc_worker_events()); } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.3.html web::json::value make_nc_manager_class() { using web::json::value; @@ -652,6 +722,7 @@ namespace nmos return make_nc_class_descriptor(value::string(U("NcManager class descriptor")), nc_manager_class_id, U("NcManager"), value::null(), make_nc_manager_properties(), make_nc_manager_methods(), make_nc_manager_events()); } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.3.1.html web::json::value make_nc_device_manager_class() { using web::json::value; @@ -659,6 +730,7 @@ namespace nmos return make_nc_class_descriptor(value::string(U("NcDeviceManager class descriptor")), nc_device_manager_class_id, U("NcDeviceManager"), value::string(U("DeviceManager")), make_nc_device_manager_properties(), make_nc_device_manager_methods(), make_nc_device_manager_events()); } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.3.2.html web::json::value make_nc_class_manager_class() { using web::json::value; @@ -666,65 +738,326 @@ namespace nmos return make_nc_class_descriptor(value::string(U("NcClassManager class descriptor")), nc_class_manager_class_id, U("NcClassManager"), value::string(U("ClassManager")), make_nc_class_manager_properties(), make_nc_class_manager_methods(), make_nc_class_manager_events()); } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcBlockMemberDescriptor.html + web::json::value make_nc_block_member_descriptor_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Role of member in its containing block")), nmos::fields::nc::role, value::string(U("NcString")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("OID of member")), nmos::fields::nc::oid, value::string(U("NcOid")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff member's OID is hardwired into device")), nmos::fields::nc::constant_oid, value::string(U("NcBoolean")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Class ID")), nmos::fields::nc::class_id, value::string(U("NcClassId")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("User label")), nmos::fields::nc::user_label, value::string(U("NcString")), true, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Containing block's OID")), nmos::fields::nc::owner, value::string(U("NcOid")), false, false)); + return make_nc_datatype_descriptor_struct(value::string(U("Descriptor which is specific to a block member")), U("NcBlockMemberDescriptor"), fields, value::string(U("NcDescriptor"))); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcClassDescriptor.html + web::json::value make_nc_class_descriptor_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Identity of the class")), nmos::fields::nc::class_id, value::string(U("NcClassId")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of the class")), nmos::fields::nc::name, value::string(U("NcName")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Role if the class has fixed role (manager classes)")), nmos::fields::nc::fixed_role, value::string(U("NcString")), true, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Property descriptors")), nmos::fields::nc::properties, value::string(U("NcPropertyDescriptor")), false, true)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Method descriptors")), nmos::fields::nc::methods, value::string(U("NcMethodDescriptor")), false, true)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Event descriptors")), nmos::fields::nc::events, value::string(U("NcEventDescriptor")), false, true)); + return make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class")), U("NcClassDescriptor"), fields, value::string(U("NcDescriptor"))); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcClassId.html web::json::value make_nc_class_id_datatype() { using web::json::value; - return make_nc_datatype_typedef(value::string(U("Sequence of class ID fields")), U("NcClassId"), value::null(), U("NcInt32"), true); + return make_nc_datatype_typedef(value::string(U("Sequence of class ID fields")), U("NcClassId"), true, U("NcInt32")); } - web::json::value make_nc_oid_datatype() + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptor.html + web::json::value make_nc_datatype_descriptor_datatype() { using web::json::value; - return make_nc_datatype_typedef(value::string(U("Object id")), U("NcOid"), value::null(), U("NcUint32"), false); + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Datatype name")), nmos::fields::nc::name, value::string(U("NcName")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Type: Primitive, Typedef, Struct, Enum")), nmos::fields::nc::type, value::string(U("NcDatatypeType")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Optional constraints on top of the underlying data type")), nmos::fields::nc::constraints, value::string(U("NcParameterConstraints")), true, false)); + return make_nc_datatype_descriptor_struct(value::string(U("Base datatype descriptor")), U("NcDatatypeDescriptor"), fields, value::string(U("NcDescriptor"))); } - web::json::value make_nc_touchpoint_datatype() + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptorEnum.html + web::json::value make_nc_datatype_descriptor_enum_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("One item descriptor per enum option")), nmos::fields::nc::items, value::string(U("NcEnumItemDescriptor")), false, true)); + return make_nc_datatype_descriptor_struct(value::string(U("Enum datatype descriptor")), U("NcDatatypeDescriptorEnum"), fields, value::string(U("NcDatatypeDescriptor"))); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptorPrimitive.html + web::json::value make_nc_datatype_descriptor_primitive_datatype() + { + using web::json::value; + + auto fields = value::array(); + return make_nc_datatype_descriptor_struct(value::string(U("Primitive datatype descriptor")), U("NcDatatypeDescriptorPrimitive"), fields, value::string(U("NcDatatypeDescriptor"))); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptorStruct.html + web::json::value make_nc_datatype_descriptor_struct_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("One item descriptor per field of the struct")), nmos::fields::nc::fields, value::string(U("NcFieldDescriptor")), false, true)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of the parent type if any or null if it has no parent")), nmos::fields::nc::parent_type, value::string(U("NcName")), true, false)); + return make_nc_datatype_descriptor_struct(value::string(U("Struct datatype descriptor")), U("NcDatatypeDescriptorStruct"), fields, value::string(U("NcDatatypeDescriptor"))); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptorTypeDef.html + web::json::value make_nc_datatype_descriptor_type_def_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Original typedef datatype name")), nmos::fields::nc::parent_type, value::string(U("NcName")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff type is a typedef sequence of another type")), nmos::fields::nc::is_sequence, value::string(U("NcBoolean")), false, false)); + return make_nc_datatype_descriptor_struct(value::string(U("Type def datatype descriptor")), U("NcDatatypeDescriptorTypeDef"), fields, value::string(U("NcDatatypeDescriptor"))); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeType.html + web::json::value make_nc_datatype_type_datatype() + { + using web::json::value; + + auto items = value::array(); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Primitive datatype")), U("Primitive"), 0)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Simple alias of another datatype")), U("Typedef"), 1)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Data structure")), U("Struct"), 2)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Enum datatype")), U("Enum"), 3)); + return make_nc_datatype_descriptor_enum(value::string(U("Datatype type")), U("NcDatatypeType"), items); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDescriptor.html + web::json::value make_nc_descriptor_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Optional user facing description")), nmos::fields::nc::description, value::string(U("NcString")), true, false)); + return make_nc_datatype_descriptor_struct(value::string(U("Base descriptor")), U("NcDescriptor"), fields, value::null()); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDeviceGenericState.html + web::json::value make_nc_device_generic_state_datatype() + { + using web::json::value; + + auto items = value::array(); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Unknown")), U("Unknown"), 0)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Normal operation")), U("NormalOperation"), 1)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Device is initializing")), U("Initializing"), 2)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Device is performing a software or firmware update")), U("Updating"), 3)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Device is experiencing a licensing error")), U("LicensingError"), 4)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Device is experiencing an internal error")), U("InternalError"), 5)); + return make_nc_datatype_descriptor_enum(value::string(U("Device generic operational state")), U("NcDeviceGenericState"), items); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDeviceOperationalState.html + web::json::value make_nc_device_operational_state_datatype() { using web::json::value; auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Context namespace")), nmos::fields::nc::context_namespace, value::string(U("NcString")), false, false, value::null())); - return make_nc_datatype_descriptor_struct(value::string(U("Base touchpoint class")), U("NcTouchpoint"), value::null(), fields, value::null()); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Generic operational state")), nmos::fields::nc::generic_state, value::string(U("NcDeviceGenericState")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Specific device details")), nmos::fields::nc::device_specific_details, value::string(U("NcString")), true, false)); + return make_nc_datatype_descriptor_struct(value::string(U("Device operational state")), U("NcDeviceOperationalState"), fields, value::null()); } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcElementId.html web::json::value make_nc_element_id_datatype() { using web::json::value; auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Level of the element")), nmos::fields::nc::level, value::string(U("NcUint16")), false, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Index of the element")), nmos::fields::nc::index, value::string(U("NcUint16")), false, false, value::null())); - return make_nc_datatype_descriptor_struct(value::string(U("Class element id which contains the level and index")), U("NcElementId"), value::null(), fields, value::null()); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Level of the element")), nmos::fields::nc::level, value::string(U("NcUint16")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Index of the element")), nmos::fields::nc::index, value::string(U("NcUint16")), false, false)); + return make_nc_datatype_descriptor_struct(value::string(U("Class element id which contains the level and index")), U("NcElementId"), fields, value::null()); } - web::json::value make_nc_property_id_datatype() + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcEnumItemDescriptor.html + web::json::value make_nc_enum_item_descriptor_datatype() { using web::json::value; - return make_nc_datatype_descriptor_struct(value::string(U("Property id which contains the level and index")), U("NcPropertyId"), value::null(), value::array(), value::string(U("NcElementId"))); + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of option")), nmos::fields::nc::name, value::string(U("NcName")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Enum item numerical value")), nmos::fields::nc::value, value::string(U("NcUint16")), false, false)); + return make_nc_datatype_descriptor_struct(value::string(U("Descriptor of an enum item")), U("NcEnumItemDescriptor"), fields, value::string(U("NcDescriptor"))); } - web::json::value make_nc_property_contraints_datatype() + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcEventDescriptor.html + web::json::value make_nc_event_descriptor_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Event id with level and index")), nmos::fields::nc::id, value::string(U("NcEventId")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of event")), nmos::fields::nc::name, value::string(U("NcName")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of event data's datatype")), nmos::fields::nc::event_datatype, value::string(U("NcName")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff property is marked as deprecated")), nmos::fields::nc::is_deprecated, value::string(U("NcBoolean")), false, false)); + return make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class event")), U("NcEventDescriptor"), fields, value::string(U("NcDescriptor"))); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcEventId.html + web::json::value make_nc_event_id_datatype() + { + using web::json::value; + + return make_nc_datatype_descriptor_struct(value::string(U("Event id which contains the level and index")), U("NcEventId"), value::array(), value::string(U("NcElementId"))); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcFieldDescriptor.html + web::json::value make_nc_field_descriptor_datatype() { using web::json::value; auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("The id of the property being constrained")), nmos::fields::nc::property_id, value::string(U("NcPropertyId")), false, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Optional default value")), nmos::fields::nc::default_value, value::null(), true, false, value::null())); - return make_nc_datatype_descriptor_struct(value::string(U("Property constraints class")), U("NcPropertyConstraints"), value::null(), fields, value::null()); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of field")), nmos::fields::nc::name, value::string(U("NcName")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of field's datatype. Can only ever be null if the type is any")), nmos::fields::nc::type_name, value::string(U("NcName")), true, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff field is nullable")), nmos::fields::nc::is_nullable, value::string(U("NcBoolean")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff field is a sequence")), nmos::fields::nc::is_sequence, value::string(U("NcBoolean")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Optional constraints on top of the underlying data type")), nmos::fields::nc::constraints, value::string(U("NcParameterConstraints")), true, false)); + return make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a field of a struct")), U("NcFieldDescriptor"), fields, value::string(U("NcDescriptor"))); } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcId.html + web::json::value make_nc_id_datatype() + { + using web::json::value; + + return make_nc_datatype_typedef(value::string(U("Identity handler")), U("NcId"), false, U("NcUint32")); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcManufacturer.html + web::json::value make_nc_manufacturer_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Manufacturer's name")), nmos::fields::nc::name, value::string(U("NcString")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("IEEE OUI or CID of manufacturer")), nmos::fields::nc::organization_id, value::string(U("NcOrganizationId")), true, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("URL of the manufacturer's website")), nmos::fields::nc::website, value::string(U("NcUri")), true, false)); + return make_nc_datatype_descriptor_struct(value::string(U("Manufacturer descriptor")), U("NcManufacturer"), fields, value::null()); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodDescriptor.html + web::json::value make_nc_method_descriptor_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Method id with level and index")), nmos::fields::nc::id, value::string(U("NcMethodId")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of method")), nmos::fields::nc::name, value::string(U("NcName")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of method result's datatype")), nmos::fields::nc::result_datatype, value::string(U("NcName")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Parameter descriptors if any")), nmos::fields::nc::parameters, value::string(U("NcParameterDescriptor")), false, true)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff property is marked as deprecated")), nmos::fields::nc::is_deprecated, value::string(U("NcBoolean")), false, false)); + return make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class method")), U("NcMethodDescriptor"), fields, value::string(U("NcDescriptor"))); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodId.html + web::json::value make_nc_method_id_datatype() + { + using web::json::value; + + return make_nc_datatype_descriptor_struct(value::string(U("Method id which contains the level and index")), U("NcMethodId"), value::array(), value::string(U("NcElementId"))); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResult.html + web::json::value make_nc_method_result_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Status for the invoked method")), nmos::fields::nc::status, value::string(U("NcMethodStatus")), false, false)); + return make_nc_datatype_descriptor_struct(value::string(U("Base result of the invoked method")), U("NcMethodResult"), fields, value::null()); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultBlockMemberDescriptors.html + web::json::value make_nc_method_result_block_member_descriptors_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Block member descriptors method result value")), nmos::fields::nc::value, value::string(U("NcBlockMemberDescriptor")), false, true)); + return make_nc_datatype_descriptor_struct(value::string(U("Method result containing block member descriptors as the value")), U("NcMethodResultBlockMemberDescriptors"), fields, value::string(U("NcMethodResult"))); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultClassDescriptor.html + web::json::value make_nc_method_result_class_descriptor_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Class descriptor method result value")), nmos::fields::nc::value, value::string(U("NcClassDescriptor")), false, false)); + return make_nc_datatype_descriptor_struct(value::string(U("Method result containing a class descriptor as the value")), U("NcMethodResultClassDescriptor"), fields, value::string(U("NcMethodResult"))); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultDatatypeDescriptor.html + web::json::value make_nc_method_result_datatype_descriptor_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Datatype descriptor method result value")), nmos::fields::nc::value, value::string(U("NcDatatypeDescriptor")), false, false)); + return make_nc_datatype_descriptor_struct(value::string(U("Method result containing a datatype descriptor as the value")), U("NcMethodResultDatatypeDescriptor"), fields, value::string(U("NcMethodResult"))); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultError.html + web::json::value make_nc_method_result_error_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Error message")), nmos::fields::nc::error_message, value::string(U("NcString")), false, false)); + return make_nc_datatype_descriptor_struct(value::string(U("Error result - to be used when the method call encounters an error")), U("NcMethodResultError"), fields, value::string(U("NcMethodResult"))); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultId.html + web::json::value make_nc_method_result_id_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Id result value")), nmos::fields::nc::value, value::string(U("NcId")), false, false)); + return make_nc_datatype_descriptor_struct(value::string(U("Id method result")), U("NcMethodResultId"), fields, value::string(U("NcMethodResult"))); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultLength.html + web::json::value make_nc_method_result_length_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Length result value")), nmos::fields::nc::value, value::string(U("NcUint32")), true, false)); + return make_nc_datatype_descriptor_struct(value::string(U("Length method result")), U("NcMethodResultLength"), fields, value::string(U("NcMethodResult"))); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultPropertyValue.html web::json::value make_nc_method_result_property_value_datatype() { using web::json::value; auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Getter method value for the associated property")), nmos::fields::nc::value, value::null(), true, false, value::null())); - return make_nc_datatype_descriptor_struct(value::string(U("Result when invoking the getter method associated with a property")), U("NcMethodResultPropertyValue"), value::null(), fields, value::string(U("NcMethodResult"))); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Getter method value for the associated property")), nmos::fields::nc::value, value::null(), true, false)); + return make_nc_datatype_descriptor_struct(value::string(U("Result when invoking the getter method associated with a property")), U("NcMethodResultPropertyValue"), fields, value::string(U("NcMethodResult"))); } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodStatus.html web::json::value make_nc_method_status_datatype() { using web::json::value; @@ -748,176 +1081,189 @@ namespace nmos web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Addressed property is not implemented by the addressed object")), U("PropertyNotImplemented"), 502)); web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("The device is not ready to handle any commands")), U("NotReady"), 503)); web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Method call did not finish within the allotted time")), U("Timeout"), 504)); - return make_nc_datatype_descriptor_enum(value::string(U("Method invokation status")), U("NcMethodStatus"), value::null(), items); + return make_nc_datatype_descriptor_enum(value::string(U("Method invokation status")), U("NcMethodStatus"), items); } - web::json::value make_nc_method_result_datatype() + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcName.html + web::json::value make_nc_name_datatype() { using web::json::value; - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Status for the invoked method")), nmos::fields::nc::status, value::string(U("NcMethodStatus")), false, false, value::null())); - return make_nc_datatype_descriptor_struct(value::string(U("Base result of the invoked method")), U("NcMethodResult"), value::null(), fields, value::null()); + return make_nc_datatype_typedef(value::string(U("Programmatically significant name, alphanumerics + underscore, no spaces")), U("NcName"), false, U("NcString")); } - web::json::value make_nc_id_datatype() + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcOid.html + web::json::value make_nc_oid_datatype() { using web::json::value; - return make_nc_datatype_typedef(value::string(U("Identity handler")), U("NcId"), value::null(), U("NcUint32"), false); + return make_nc_datatype_typedef(value::string(U("Object id")), U("NcOid"), false, U("NcUint32")); } - web::json::value make_nc_method_result_id_datatype() + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcOrganizationId.html + web::json::value make_nc_organization_id_datatype() { using web::json::value; - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Id result value")), nmos::fields::nc::value, value::string(U("NcId")), false, false, value::null())); - return make_nc_datatype_descriptor_struct(value::string(U("Id method result")), U("NcMethodResultId"), value::null(), fields, value::string(U("NcMethodResult"))); + return make_nc_datatype_typedef(value::string(U("Unique 24-bit organization id")), U("NcOrganizationId"), false, U("NcInt32")); } - web::json::value make_nc_method_result_length_datatype() + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcParameterConstraints.html + web::json::value make_nc_parameter_constraints_datatype() { using web::json::value; auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Length result value")), nmos::fields::nc::value, value::string(U("NcUint32")), true, false, value::null())); - return make_nc_datatype_descriptor_struct(value::string(U("Length method result")), U("NcMethodResultLength"), value::null(), fields, value::string(U("NcMethodResult"))); - } - - web::json::value make_nc_property_change_type_datatype() - { - using web::json::value; - - auto items = value::array(); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Current value changed")), U("ValueChanged"), 0)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Sequence item added")), U("SequenceItemAdded"), 1)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Sequence item changed")), U("SequenceItemChanged"), 2)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Sequence item removed")), U("SequenceItemRemoved"), 3)); - return make_nc_datatype_descriptor_enum(value::string(U("Type of property change")), U("NcPropertyChangeType"), value::null(), items); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Default value")), nmos::fields::nc::default_value, value::null(), true, false)); + return make_nc_datatype_descriptor_struct(value::string(U("Abstract parameter constraints class")), U("NcParameterConstraints"), fields, value::null()); } - web::json::value make_nc_property_changed_event_data_datatype() + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcParameterConstraintsNumber.html + web::json::value make_nc_parameter_constraints_number_datatype() { using web::json::value; auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("The id of the property that changed")), nmos::fields::nc::property_id, value::string(U("NcPropertyId")), false, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Information regarding the change type")), nmos::fields::nc::change_type, value::string(U("NcPropertyChangeType")), false, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Property-type specific value")), nmos::fields::nc::value, value::null(), true, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Index of sequence item if the property is a sequence")), nmos::fields::nc::sequence_item_index, value::string(U("NcId")), true, false, value::null())); - return make_nc_datatype_descriptor_struct(value::string(U("Payload of property-changed event")), U("NcPropertyChangedEventData"), value::null(), fields, value::null()); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Optional maximum")), nmos::fields::nc::maximum, value::null(), true, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Optional minimum")), nmos::fields::nc::minimum, value::null(), true, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Optional step")), nmos::fields::nc::step, value::null(), true, false)); + return make_nc_datatype_descriptor_struct(value::string(U("Number parameter constraints class")), U("NcParameterConstraintsNumber"), fields, value::string(U("NcParameterConstraints"))); } - web::json::value make_nc_descriptor_datatype() + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcParameterConstraintsString.html + web::json::value make_nc_parameter_constraints_string_datatype() { using web::json::value; auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Optional user facing description")), nmos::fields::nc::description, value::string(U("NcString")), true, false, value::null())); - return make_nc_datatype_descriptor_struct(value::string(U("Base descriptor")), U("NcDescriptor"), value::null(), fields, value::null()); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Maximum characters allowed")), nmos::fields::nc::max_characters, value::string(U("NcUint32")), true, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Regex pattern")), nmos::fields::nc::pattern, value::string(U("NcRegex")), true, false)); + return make_nc_datatype_descriptor_struct(value::string(U("String parameter constraints class")), U("NcParameterConstraintsString"), fields, value::string(U("NcParameterConstraints"))); } - web::json::value make_nc_block_member_descriptor_datatype() + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcParameterDescriptor.html + web::json::value make_nc_parameter_descriptor_datatype() { using web::json::value; auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Role of member in its containing block")), nmos::fields::nc::role, value::string(U("NcString")), false, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("OID of member")), nmos::fields::nc::oid, value::string(U("NcOid")), false, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff member's OID is hardwired into device")), nmos::fields::nc::constant_oid, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Class ID")), nmos::fields::nc::class_id, value::string(U("NcClassId")), false, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("User label")), nmos::fields::nc::user_label, value::string(U("NcString")), true, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Containing block's OID")), nmos::fields::nc::owner, value::string(U("NcOid")), false, false, value::null())); - return make_nc_datatype_descriptor_struct(value::string(U("Descriptor which is specific to a block member")), U("NcBlockMemberDescriptor"), value::null(), fields, value::string(U("NcDescriptor"))); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of parameter")), nmos::fields::nc::name, value::string(U("NcName")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of parameter's datatype. Can only ever be null if the type is any")), nmos::fields::nc::type_name, value::string(U("NcName")), true, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff property is nullable")), nmos::fields::nc::is_nullable, value::string(U("NcBoolean")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff property is a sequence")), nmos::fields::nc::is_sequence, value::string(U("NcBoolean")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Optional constraints on top of the underlying data type")), nmos::fields::nc::constraints, value::string(U("NcParameterConstraints")), true, false)); + return make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a method parameter")), U("NcParameterDescriptor"), fields, value::string(U("NcDescriptor"))); } - web::json::value make_nc_method_result_block_member_descriptors_datatype() + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcProduct.html + web::json::value make_nc_product_datatype() { using web::json::value; auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Block member descriptors method result value")), nmos::fields::nc::value, value::string(U("NcBlockMemberDescriptor")), false, true, value::null())); - return make_nc_datatype_descriptor_struct(value::string(U("Method result containing block member descriptors as the value")), U("NcMethodResultBlockMemberDescriptors"), value::null(), fields, value::string(U("NcMethodResult"))); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Product name")), nmos::fields::nc::name, value::string(U("NcString")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Manufacturer's unique key to product - model number, SKU, etc")), nmos::fields::nc::key, value::string(U("NcString")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Manufacturer's product revision level code")), nmos::fields::nc::revision_level, value::string(U("NcString")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Brand name under which product is sold")), nmos::fields::nc::brand_name, value::string(U("NcString")), true, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Unique UUID of product (not product instance)")), nmos::fields::nc::uuid, value::string(U("NcUuid")), true, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Text description of product")), nmos::fields::nc::description, value::string(U("NcString")), true, false)); + return make_nc_datatype_descriptor_struct(value::string(U("Product descriptor")), U("NcProduct"), fields, value::null()); } - web::json::value make_nc_version_code_datatype() + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyChangeType.html + web::json::value make_nc_property_change_type_datatype() { using web::json::value; - return make_nc_datatype_typedef(value::string(U("Version code in semantic versioning format")), U("NcVersionCode"), value::null(), U("NcString"), false); + auto items = value::array(); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Current value changed")), U("ValueChanged"), 0)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Sequence item added")), U("SequenceItemAdded"), 1)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Sequence item changed")), U("SequenceItemChanged"), 2)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Sequence item removed")), U("SequenceItemRemoved"), 3)); + return make_nc_datatype_descriptor_enum(value::string(U("Type of property change")), U("NcPropertyChangeType"), items); } - web::json::value make_nc_organization_id_datatype() + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyChangedEventData.html + web::json::value make_nc_property_changed_event_data_datatype() { using web::json::value; - return make_nc_datatype_typedef(value::string(U("Unique 24-bit organization id")), U("NcOrganizationId"), value::null(), U("NcInt32"), false); + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("The id of the property that changed")), nmos::fields::nc::property_id, value::string(U("NcPropertyId")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Information regarding the change type")), nmos::fields::nc::change_type, value::string(U("NcPropertyChangeType")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Property-type specific value")), nmos::fields::nc::value, value::null(), true, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Index of sequence item if the property is a sequence")), nmos::fields::nc::sequence_item_index, value::string(U("NcId")), true, false)); + return make_nc_datatype_descriptor_struct(value::string(U("Payload of property-changed event")), U("NcPropertyChangedEventData"), fields, value::null()); } - web::json::value make_nc_uri_datatype() + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyConstraints.html + web::json::value make_nc_property_contraints_datatype() { using web::json::value; - return make_nc_datatype_typedef(value::string(U("Uniform resource identifier")), U("NcUri"), value::null(), U("NcString"), false); + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("The id of the property being constrained")), nmos::fields::nc::property_id, value::string(U("NcPropertyId")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Optional default value")), nmos::fields::nc::default_value, value::null(), true, false)); + return make_nc_datatype_descriptor_struct(value::string(U("Property constraints class")), U("NcPropertyConstraints"), fields, value::null()); } - web::json::value make_nc_manufacturer_datatype() + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyConstraintsNumber.html + web::json::value make_nc_property_constraints_number_datatype() { using web::json::value; auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Manufacturer's name")), nmos::fields::nc::name, value::string(U("NcString")), false, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("IEEE OUI or CID of manufacturer")), nmos::fields::nc::organization_id, value::string(U("NcOrganizationId")), true, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("URL of the manufacturer's website")), nmos::fields::nc::website, value::string(U("NcUri")), true, false, value::null())); - return make_nc_datatype_descriptor_struct(value::string(U("Manufacturer descriptor")), U("NcManufacturer"), value::null(), fields, value::null()); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Optional maximum")), nmos::fields::nc::maximum, value::null(), true, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Optional minimum")), nmos::fields::nc::minimum, value::null(), true, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Optional step")), nmos::fields::nc::step, value::null(), true, false)); + return make_nc_datatype_descriptor_struct(value::string(U("Number property constraints class")), U("NcPropertyConstraintsNumber"), fields, value::string(U("NcPropertyConstraints"))); } - web::json::value make_nc_uuid_datatype() + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyConstraintsString.html + web::json::value make_nc_property_constraints_string_datatype() { using web::json::value; - return make_nc_datatype_typedef(value::string(U("UUID")), U("NcUuid"), value::null(), U("NcString"), false); + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Maximum characters allowed")), nmos::fields::nc::max_characters, value::string(U("NcUint32")), true, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Regex pattern")), nmos::fields::nc::pattern, value::string(U("NcRegex")), true, false)); + return make_nc_datatype_descriptor_struct(value::string(U("String property constraints class")), U("NcPropertyConstraintsString"), fields, value::string(U("NcPropertyConstraints"))); } - web::json::value make_nc_product_datatype() + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyDescriptor.html + web::json::value make_nc_property_descriptor_datatype() { using web::json::value; auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Product name")), nmos::fields::nc::name, value::string(U("NcString")), false, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Manufacturer's unique key to product - model number, SKU, etc")), nmos::fields::nc::key, value::string(U("NcString")), false, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Manufacturer's product revision level code")), nmos::fields::nc::revision_level, value::string(U("NcString")), false, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Brand name under which product is sold")), nmos::fields::nc::brand_name, value::string(U("NcString")), true, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Unique UUID of product (not product instance)")), nmos::fields::nc::uuid, value::string(U("NcUuid")), true, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Text description of product")), nmos::fields::nc::description, value::string(U("NcString")), true, false, value::null())); - return make_nc_datatype_descriptor_struct(value::string(U("Product descriptor")), U("NcProduct"), value::null(), fields, value::null()); - } - - web::json::value make_nc_device_generic_state_datatype() + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Property id with level and index")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of property")), nmos::fields::nc::name, value::string(U("NcName")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of property's datatype. Can only ever be null if the type is any")), nmos::fields::nc::type_name, value::string(U("NcName")), true, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff property is read-only")), nmos::fields::nc::is_read_only, value::string(U("NcBoolean")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff property is nullable")), nmos::fields::nc::is_nullable, value::string(U("NcBoolean")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff property is a sequence")), nmos::fields::nc::is_sequence, value::string(U("NcBoolean")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff property is marked as deprecated")), nmos::fields::nc::is_deprecated, value::string(U("NcBoolean")), false, false)); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Optional constraints on top of the underlying data type")), nmos::fields::nc::constraints, value::string(U("NcParameterConstraints")), true, false)); + return make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class property")), U("NcPropertyDescriptor"), fields, value::string(U("NcDescriptor"))); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyId.html + web::json::value make_nc_property_id_datatype() { using web::json::value; - auto items = value::array(); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Unknown")), U("Unknown"), 0)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Normal operation")), U("NormalOperation"), 1)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Device is initializing")), U("Initializing"), 2)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Device is performing a software or firmware update")), U("Updating"), 3)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Device is experiencing a licensing error")), U("LicensingError"), 4)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Device is experiencing an internal error")), U("InternalError"), 5)); - return make_nc_datatype_descriptor_enum(value::string(U("Device generic operational state")), U("NcDeviceGenericState"), value::null(), items); + return make_nc_datatype_descriptor_struct(value::string(U("Property id which contains the level and index")), U("NcPropertyId"), value::array(), value::string(U("NcElementId"))); } - web::json::value make_nc_device_operational_state_datatype() + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcRegex.html + web::json::value make_nc_regex_datatype() { using web::json::value; - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Generic operational state")), nmos::fields::nc::generic_state, value::string(U("NcDeviceGenericState")), false, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Specific device details")), nmos::fields::nc::device_specific_details, value::string(U("NcString")), true, false, value::null())); - return make_nc_datatype_descriptor_struct(value::string(U("Device operational state")), U("NcDeviceOperationalState"), value::null(), fields, value::null()); + return make_nc_datatype_typedef(value::string(U("Regex pattern")), U("NcRegex"), false, U("NcString")); } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcResetCause.html web::json::value make_nc_reset_cause_datatype() { using web::json::value; @@ -929,146 +1275,133 @@ namespace nmos web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Upgrade")), U("Upgrade"), 3)); web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Controller request")), U("ControllerRequest"), 4)); web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Manual request from the front panel")), U("ManualReset"), 5)); - return make_nc_datatype_descriptor_enum(value::string(U("Reset cause enum")), U("NcResetCause"), value::null(), items); + return make_nc_datatype_descriptor_enum(value::string(U("Reset cause enum")), U("NcResetCause"), items); } - web::json::value make_nc_name_datatype() + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcRolePath.html + web::json::value make_nc_role_path_datatype() { using web::json::value; - return make_nc_datatype_typedef(value::string(U("Programmatically significant name, alphanumerics + underscore, no spaces")), U("NcName"), value::null(), U("NcString"), false); + return make_nc_datatype_typedef(value::string(U("Role path")), U("NcRolePath"), true, U("NcString")); } - web::json::value make_nc_property_descriptor_datatype() + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTimeInterval.html + web::json::value make_nc_time_interval_datatype() { using web::json::value; - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Property id with level and index")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of property")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of property's datatype. Can only ever be null if the type is any")), nmos::fields::nc::type_name, value::string(U("NcName")), true, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff property is read-only")), nmos::fields::nc::is_read_only, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff property is nullable")), nmos::fields::nc::is_nullable, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff property is a sequence")), nmos::fields::nc::is_sequence, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff property is marked as deprecated")), nmos::fields::nc::is_deprecated, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Optional constraints on top of the underlying data type")), nmos::fields::nc::constraints, value::string(U("NcParameterConstraints")), true, false, value::null())); - return make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class property")), U("NcPropertyDescriptor"), value::null(), fields, value::string(U("NcDescriptor"))); + return make_nc_datatype_typedef(value::string(U("Time interval described in nanoseconds")), U("NcTimeInterval"), false, U("NcInt64")); } - web::json::value make_nc_parameter_descriptor_datatype() + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpoint.html + web::json::value make_nc_touchpoint_datatype() { using web::json::value; auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of parameter")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of parameter's datatype. Can only ever be null if the type is any")), nmos::fields::nc::type_name, value::string(U("NcName")), true, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff property is nullable")), nmos::fields::nc::is_nullable, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff property is a sequence")), nmos::fields::nc::is_sequence, value::string(U("NcBoolean")), false, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Optional constraints on top of the underlying data type")), nmos::fields::nc::constraints, value::string(U("NcParameterConstraints")), true, false, value::null())); - return make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a method parameter")), U("NcParameterDescriptor"), value::null(), fields, value::string(U("NcDescriptor"))); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Context namespace")), nmos::fields::nc::context_namespace, value::string(U("NcString")), false, false)); + return make_nc_datatype_descriptor_struct(value::string(U("Base touchpoint class")), U("NcTouchpoint"), fields, value::null()); } - web::json::value make_nc_method_id_datatype() + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointNmos.html + web::json::value make_nc_touchpoint_nmos_datatype() { using web::json::value; - return make_nc_datatype_descriptor_struct(value::string(U("Method id which contains the level and index")), U("NcMethodId"), value::null(), value::array(), value::string(U("NcElementId"))); + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Context NMOS resource")), nmos::fields::nc::resource, value::string(U("NcTouchpointResourceNmos")), false, false)); + return make_nc_datatype_descriptor_struct(value::string(U("Touchpoint class for NMOS resources")), U("NcTouchpointNmos"), fields, value::string(U("NcTouchpoint"))); } - web::json::value make_nc_method_descriptor_datatype() + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointNmosChannelMapping.html + web::json::value make_nc_touchpoint_nmos_channel_mapping_datatype() { using web::json::value; auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Method id with level and index")), nmos::fields::nc::id, value::string(U("NcMethodId")), false, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of method")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of method result's datatype")), nmos::fields::nc::result_datatype, value::string(U("NcName")), false, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Parameter descriptors if any")), nmos::fields::nc::parameters, value::string(U("NcParameterDescriptor")), false, true, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff property is marked as deprecated")), nmos::fields::nc::is_deprecated, value::string(U("NcBoolean")), false, false, value::null())); - return make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class method")), U("NcMethodDescriptor"), value::null(), fields, value::string(U("NcDescriptor"))); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Context Channel Mapping resource")), nmos::fields::nc::resource, value::string(U("NcTouchpointResourceNmosChannelMapping")), false, false)); + return make_nc_datatype_descriptor_struct(value::string(U("Touchpoint class for NMOS IS-08 resources")), U("NcTouchpointNmosChannelMapping"), fields, value::string(U("NcTouchpoint"))); } - web::json::value make_nc_event_id_datatype() + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointResource.html + web::json::value make_nc_touchpoint_resource_datatype() { using web::json::value; - return make_nc_datatype_descriptor_struct(value::string(U("Event id which contains the level and index")), U("NcEventId"), value::null(), value::array(), value::string(U("NcElementId"))); + auto fields = value::array(); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("The type of the resource")), nmos::fields::nc::resource_type, value::string(U("NcString")), false, false)); + return make_nc_datatype_descriptor_struct(value::string(U("Touchpoint resource class")), U("NcTouchpointResource"), fields, value::null()); } - web::json::value make_nc_event_descriptor_datatype() + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointResourceNmos.html + web::json::value make_nc_touchpoint_resource_nmos_datatype() { using web::json::value; auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Event id with level and index")), nmos::fields::nc::id, value::string(U("NcEventId")), false, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of event")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of event data's datatype")), nmos::fields::nc::event_datatype, value::string(U("NcName")), false, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff property is marked as deprecated")), nmos::fields::nc::is_deprecated, value::string(U("NcBoolean")), false, false, value::null())); - return make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class event")), U("NcEventDescriptor"), value::null(), fields, value::string(U("NcDescriptor"))); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("NMOS resource UUID")), nmos::fields::nc::id, value::string(U("NcUuid")), false, false)); + return make_nc_datatype_descriptor_struct(value::string(U("Touchpoint resource class for NMOS resources")), U("NcTouchpointResourceNmos"), fields, value::string(U("NcTouchpointResource"))); } - web::json::value make_nc_class_descriptor_datatype() + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointResourceNmosChannelMapping.html + web::json::value make_nc_touchpoint_resource_nmos_channel_mapping_datatype() { using web::json::value; auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Identity of the class")), nmos::fields::nc::class_id, value::string(U("NcClassId")), false, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of the class")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Role if the class has fixed role (manager classes)")), nmos::fields::nc::fixed_role, value::string(U("NcString")), true, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Property descriptors")), nmos::fields::nc::properties, value::string(U("NcPropertyDescriptor")), false, true, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Method descriptors")), nmos::fields::nc::methods, value::string(U("NcMethodDescriptor")), false, true, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Event descriptors")), nmos::fields::nc::events, value::string(U("NcEventDescriptor")), false, true, value::null())); - return make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class")), U("NcClassDescriptor"), value::null(), fields, value::string(U("NcDescriptor"))); + web::json::push_back(fields, make_nc_field_descriptor(value::string(U("IS-08 Audio Channel Mapping input or output id")), nmos::fields::nc::io_id, value::string(U("NcString")), false, false)); + return make_nc_datatype_descriptor_struct(value::string(U("Touchpoint resource class for NMOS resources")), U("NcTouchpointResourceNmosChannelMapping"), fields, value::string(U("NcTouchpointResourceNmos"))); } - web::json::value make_nc_parameter_constraints_datatype() + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcUri.html + web::json::value make_nc_uri_datatype() { using web::json::value; - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Default value")), nmos::fields::nc::default_value, value::null(), true, false, value::null())); - return make_nc_datatype_descriptor_struct(value::string(U("Abstract parameter constraints class")), U("NcParameterConstraints"), value::null(), fields, value::null()); + return make_nc_datatype_typedef(value::string(U("Uniform resource identifier")), U("NcUri"), false, U("NcString")); } - web::json::value make_nc_datatype_type_datatype() + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcUuid.html + web::json::value make_nc_uuid_datatype() { using web::json::value; - auto items = value::array(); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Primitive datatype")), U("Primitive"), 0)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Simple alias of another datatype")), U("Typedef"), 1)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Data structure")), U("Struct"), 2)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Enum datatype")), U("Enum"), 3)); - return make_nc_datatype_descriptor_enum(value::string(U("Datatype type")), U("NcDatatypeType"), value::null(), items); + return make_nc_datatype_typedef(value::string(U("UUID")), U("NcUuid"), false, U("NcString")); } - web::json::value make_nc_datatype_descriptor_datatype() + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcVersionCode.html + web::json::value make_nc_version_code_datatype() { using web::json::value; - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Datatype name")), nmos::fields::nc::name, value::string(U("NcName")), false, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Type: Primitive, Typedef, Struct, Enum")), nmos::fields::nc::type, value::string(U("NcDatatypeType")), false, false, value::null())); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Optional constraints on top of the underlying data type")), nmos::fields::nc::constraints, value::string(U("NcParameterConstraints")), true, false, value::null())); - return make_nc_datatype_descriptor_struct(value::string(U("Base datatype descriptor")), U("NcDatatypeDescriptor"), value::null(), fields, value::string(U("NcDescriptor"))); + return make_nc_datatype_typedef(value::string(U("Version code in semantic versioning format")), U("NcVersionCode"), false, U("NcString")); } - web::json::value make_nc_method_result_class_descriptor_datatype() + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncconnectionstatus + web::json::value make_nc_connection_status_datatype() { using web::json::value; - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Class descriptor method result value")), nmos::fields::nc::value, value::string(U("NcClassDescriptor")), false, false, value::null())); - return make_nc_datatype_descriptor_struct(value::string(U("Method result containing a class descriptor as the value")), U("NcMethodResultClassDescriptor"), value::null(), fields, value::string(U("NcMethodResult"))); + auto items = value::array(); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("This is the value when there is no receiver")), U("Undefined"), 0)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Connected to a stream")), U("Connected"), 1)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Not connected to a stream")), U("Disconnected"), 2)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("A connection error was encountered")), U("ConnectionError"), 3)); + return make_nc_datatype_descriptor_enum(value::string(U("Connection status enum data typee")), U("NcConnectionStatus"), items); } - web::json::value make_nc_method_result_datatype_descriptor_datatype() + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncpayloadstatus + web::json::value make_nc_payload_status_datatype() { using web::json::value; - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Datatype descriptor method result value")), nmos::fields::nc::value, value::string(U("NcDatatypeDescriptor")), false, false, value::null())); - return make_nc_datatype_descriptor_struct(value::string(U("Method result containing a datatype descriptor as the value")), U("NcMethodResultDatatypeDescriptor"), value::null(), fields, value::string(U("NcMethodResult"))); + auto items = value::array(); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("This is the value when there's no connection")), U("Undefined"), 0)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Payload is being received without errors and is the correct type")), U("PayloadOK"), 1)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Payload is being received but is of an unsupported type")), U("PayloadFormatUnsupported"), 2)); + web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("A payload error was encountered")), U("PayloadError"), 3)); + return make_nc_datatype_descriptor_enum(value::string(U("Connection status enum data typee")), U("NcPayloadStatus"), items); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject @@ -1133,122 +1466,28 @@ namespace nmos } // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager - web::json::value make_nc_class_manager(nc_oid oid, nc_oid owner, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints) + web::json::value make_nc_class_manager(nc_oid oid, nc_oid owner, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, const nmos::experimental::control_protocol_state& control_protocol_state) { using web::json::value; auto data = make_nc_manager(nc_class_manager_class_id, oid, true, owner, U("ClassManager"), user_label, touchpoints, runtime_property_constraints); - // minimal control classes + // core control classes data[nmos::fields::nc::control_classes] = value::array(); auto& control_classes = data[nmos::fields::nc::control_classes]; + for (const auto& control_class : control_protocol_state.control_classes) + { + auto& ctl_class = control_class.second; + web::json::push_back(control_classes, make_nc_class_descriptor(ctl_class.description, ctl_class.class_id, ctl_class.name, ctl_class.fixed_role, ctl_class.properties, ctl_class.methods, ctl_class.events)); + } - // NcObject control class - web::json::push_back(control_classes, make_nc_object_class()); - // NcBlock control class - web::json::push_back(control_classes, make_nc_block_class()); - // NcWorker control class - web::json::push_back(control_classes, make_nc_worker_class()); - // NcManager control class - web::json::push_back(control_classes, make_nc_manager_class()); - // NcDeviceManager control class - web::json::push_back(control_classes, make_nc_device_manager_class()); - // NcClassManager control class - web::json::push_back(control_classes, make_nc_class_manager_class()); - - // minimal datatypes + // core datatypes data[nmos::fields::nc::datatypes] = value::array(); auto& datatypes = data[nmos::fields::nc::datatypes]; - - // NcObject datatypes - // NcClassId - web::json::push_back(datatypes, make_nc_class_id_datatype()); - // NcOid - web::json::push_back(datatypes, make_nc_oid_datatype()); - // NcTouchpoint - web::json::push_back(datatypes, make_nc_touchpoint_datatype()); - // NcElementId - web::json::push_back(datatypes, make_nc_element_id_datatype()); - // NcPropertyId - web::json::push_back(datatypes, make_nc_property_id_datatype()); - // NcPropertyConstraints - web::json::push_back(datatypes, make_nc_property_contraints_datatype()); - // NcMethodResultPropertyValue - web::json::push_back(datatypes, make_nc_method_result_property_value_datatype()); - // NcMethodStatus - web::json::push_back(datatypes, make_nc_method_status_datatype()); - // NcMethodResult - web::json::push_back(datatypes, make_nc_method_result_datatype()); - // NcId - web::json::push_back(datatypes, make_nc_id_datatype()); - // NcMethodResultId - web::json::push_back(datatypes, make_nc_method_result_id_datatype()); - // NcMethodResultLength - web::json::push_back(datatypes, make_nc_method_result_length_datatype()); - // NcPropertyChangeType - web::json::push_back(datatypes, make_nc_property_change_type_datatype()); - // NcPropertyChangedEventData - web::json::push_back(datatypes, make_nc_property_changed_event_data_datatype()); - - // NcBlock datatypes - // NcDescriptor - web::json::push_back(datatypes, make_nc_descriptor_datatype()); - // NcBlockMemberDescriptor - web::json::push_back(datatypes, make_nc_block_member_descriptor_datatype()); - // NcMethodResultBlockMemberDescriptors - web::json::push_back(datatypes, make_nc_method_result_block_member_descriptors_datatype()); - - // NcWorker has no datatypes - - // NcManager has no datatypes - - // NcDeviceManager datatypes - // NcVersionCode - web::json::push_back(datatypes, make_nc_version_code_datatype()); - // NcOrganizationId - web::json::push_back(datatypes, make_nc_organization_id_datatype()); - // NcUri - web::json::push_back(datatypes, make_nc_uri_datatype()); - // NcManufacturer - web::json::push_back(datatypes, make_nc_manufacturer_datatype()); - // NcUuid - web::json::push_back(datatypes, make_nc_uuid_datatype()); - // NcProduct - web::json::push_back(datatypes, make_nc_product_datatype()); - // NcDeviceGenericState - web::json::push_back(datatypes, make_nc_device_generic_state_datatype()); - // NcDeviceOperationalState - web::json::push_back(datatypes, make_nc_device_operational_state_datatype()); - // NcResetCause - web::json::push_back(datatypes, make_nc_reset_cause_datatype()); - - // NcClassManager datatypes - // NcName - web::json::push_back(datatypes, make_nc_name_datatype()); - // NcPropertyDescriptor - web::json::push_back(datatypes, make_nc_property_descriptor_datatype()); - // NcMethodId - web::json::push_back(datatypes, make_nc_method_id_datatype()); - // NcParameterDescriptor - web::json::push_back(datatypes, make_nc_parameter_descriptor_datatype()); - // NcMethodDescriptor - web::json::push_back(datatypes, make_nc_method_descriptor_datatype()); - // NcEventId - web::json::push_back(datatypes, make_nc_event_id_datatype()); - // NcEventDescriptor - web::json::push_back(datatypes, make_nc_event_descriptor_datatype()); - // NcClassDescriptor - web::json::push_back(datatypes, make_nc_class_descriptor_datatype()); - // NcParameterConstraints - web::json::push_back(datatypes, make_nc_parameter_constraints_datatype()); - // NcDatatypeType - web::json::push_back(datatypes, make_nc_datatype_type_datatype()); - // NcDatatypeDescriptor - web::json::push_back(datatypes, make_nc_datatype_descriptor_datatype()); - // NcMethodResultClassDescriptor - web::json::push_back(datatypes, make_nc_method_result_class_descriptor_datatype()); - // NcMethodResultDatatypeDescriptor - web::json::push_back(datatypes, make_nc_method_result_datatype_descriptor_datatype()); + for (const auto& datatype : control_protocol_state.datatypes) + { + web::json::push_back(datatypes, datatype.second.descriptor); + } return data; } diff --git a/Development/nmos/control_protocol_resource.h b/Development/nmos/control_protocol_resource.h index 999e37aff..8b1b4a892 100644 --- a/Development/nmos/control_protocol_resource.h +++ b/Development/nmos/control_protocol_resource.h @@ -1,10 +1,8 @@ #ifndef NMOS_CONTROL_PROTOCOL_RESOURCE_H #define NMOS_CONTROL_PROTOCOL_RESOURCE_H -#include #include "cpprest/json_utils.h" #include "nmos/control_protocol_class_id.h" -#include "nmos/control_protocol_state.h" // for nmos::experimental::control_classes definitions namespace web { @@ -16,6 +14,11 @@ namespace web namespace nmos { + namespace experimental + { + struct control_protocol_state; + } + namespace details { namespace nc_message_type @@ -106,41 +109,67 @@ namespace nmos { enum cause { - Unknown = 0, // 0 Unknown - Power_on = 1, // 1 Power on - InternalError = 2, // 2 Internal error - Upgrade = 3, // 3 Upgrade - Controller_request = 4, // 4 Controller request - ManualReset = 5 // 5 Manual request from the front panel + Unknown = 0, // Unknown + Power_on = 1, // Power on + InternalError = 2, // Internal error + Upgrade = 3, // Upgrade + Controller_request = 4, // Controller request + ManualReset = 5 // Manual request from the front panel + }; + } + + // NcConnectionStatus + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncconnectionstatus + namespace nc_connection_status + { + enum status + { + Undefined = 0, // This is the value when there is no receiver + Connected = 1, // Connected to a stream + Disconnected = 2, // Not connected to a stream + ConnectionError = 3 // A connection error was encountered + }; + } + + // NcPayloadStatus + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncpayloadstatus + namespace nc_payload_status + { + enum status + { + Undefined = 0, // This is the value when there's no connection. + PayloadOK = 1, // Payload is being received without errors and is the correct type + PayloadFormatUnsupported = 2, // Payload is being received but is of an unsupported type + PayloadError = 3 // A payload error was encountered }; } - // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncid + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncid typedef uint32_t nc_id; - // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncoid + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncoid typedef uint32_t nc_oid; - // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncuri + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncuri typedef utility::string_t nc_uri; - // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncuuid + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncuuid typedef utility::string_t nc_uuid; - // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassid + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassid const nc_class_id nc_object_class_id({ 1 }); const nc_class_id nc_block_class_id({ 1, 1 }); const nc_class_id nc_worker_class_id({ 1, 2 }); const nc_class_id nc_manager_class_id({ 1, 3 }); const nc_class_id nc_device_manager_class_id({ 1, 3, 1 }); const nc_class_id nc_class_manager_class_id({ 1, 3, 2 }); + const nc_class_id nc_ident_beacon_class_id({ 1, 2, 2 }); + const nc_class_id nc_receiver_monitor_class_id({ 1, 2, 3 }); + const nc_class_id nc_receiver_monitor_protected_class_id({ 1, 2, 3, 1 }); - // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#nctouchpoint + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#nctouchpoint typedef utility::string_t nc_touch_point; - typedef std::function method; - typedef std::map methods; // method_id vs method handler - web::json::value make_control_protocol_error_response(int32_t handle, const nc_method_result& method_result, const utility::string_t& error_message); web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result); @@ -212,7 +241,7 @@ namespace nmos // description can be null // type_name can be null // constraints can be null - web::json::value make_nc_field_descriptor(const web::json::value& description, const utility::string_t& name, const web::json::value& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints); + web::json::value make_nc_field_descriptor(const web::json::value& description, const utility::string_t& name, const web::json::value& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints = web::json::value::null()); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmethoddescriptor // description can be null @@ -223,7 +252,7 @@ namespace nmos // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncparameterdescriptor // description can be null // type_name can be null - web::json::value make_nc_parameter_descriptor(const web::json::value& description, const utility::string_t& name, const web::json::value& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints); + web::json::value make_nc_parameter_descriptor(const web::json::value& description, const utility::string_t& name, const web::json::value& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints = web::json::value::null()); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncpropertydescriptor // description can be null @@ -231,96 +260,217 @@ namespace nmos // type_name can be null // constraints can be null web::json::value make_nc_property_descriptor(const web::json::value& description, const web::json::value& id, const utility::string_t& name, const web::json::value& type_name, - bool is_read_only, bool is_nullable, bool is_sequence, bool is_deprecated, const web::json::value& constraints); + bool is_read_only, bool is_nullable, bool is_sequence, bool is_deprecated, const web::json::value& constraints = web::json::value::null()); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptor // description can be null // constraints can be null - web::json::value make_nc_datatype_descriptor(const web::json::value& description, const utility::string_t& name, nc_datatype_type::type type, const web::json::value& constraints); + web::json::value make_nc_datatype_descriptor(const web::json::value& description, const utility::string_t& name, nc_datatype_type::type type, const web::json::value& constraints = web::json::value::null()); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptorenum // description can be null // constraints can be null // items: sequence - web::json::value make_nc_datatype_descriptor_enum(const web::json::value& description, const utility::string_t& name, const web::json::value& constraints, const web::json::value& items); + web::json::value make_nc_datatype_descriptor_enum(const web::json::value& description, const utility::string_t& name, const web::json::value& items, const web::json::value& constraints = web::json::value::null()); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptorprimitive // description can be null // constraints can be null - web::json::value make_nc_datatype_descriptor_primitive(const web::json::value& description, const utility::string_t& name, const web::json::value& constraints); + web::json::value make_nc_datatype_descriptor_primitive(const web::json::value& description, const utility::string_t& name, const web::json::value& constraints = web::json::value::null()); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptorstruct // description can be null // constraints can be null // fields: sequence // parent_type can be null - web::json::value make_nc_datatype_descriptor_struct(const web::json::value& description, const utility::string_t& name, const web::json::value& constraints, const web::json::value& fields, const web::json::value& parent_type); + web::json::value make_nc_datatype_descriptor_struct(const web::json::value& description, const utility::string_t& name, const web::json::value& fields, const web::json::value& parent_type, const web::json::value& constraints = web::json::value::null()); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptortypedef // description can be null // constraints can be null - web::json::value make_nc_datatype_typedef(const web::json::value& description, const utility::string_t& name, const web::json::value& constraints, const utility::string_t& parent_type, bool is_sequence); - - // make the core control classes proprties/methods/events + web::json::value make_nc_datatype_typedef(const web::json::value& description, const utility::string_t& name, bool is_sequence, const utility::string_t& parent_type, const web::json::value& constraints = web::json::value::null()); + + // Control class models + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/#control-class-models-for-branch-v10-dev + // + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.html + web::json::value make_nc_object_class(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.1.html + web::json::value make_nc_block_class(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.2.html + web::json::value make_nc_worker_class(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.3.html + web::json::value make_nc_manager_class(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.3.1.html + web::json::value make_nc_device_manager_class(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.3.2.html + web::json::value make_nc_class_manager_class(); + + // control classes proprties/methods/events + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject web::json::value make_nc_object_properties(); web::json::value make_nc_object_methods(); web::json::value make_nc_object_events(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock web::json::value make_nc_block_properties(); web::json::value make_nc_block_methods(); web::json::value make_nc_block_events(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncworker web::json::value make_nc_worker_properties(); web::json::value make_nc_worker_methods(); web::json::value make_nc_worker_events(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanager web::json::value make_nc_manager_properties(); web::json::value make_nc_manager_methods(); web::json::value make_nc_manager_events(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager web::json::value make_nc_device_manager_properties(); web::json::value make_nc_device_manager_methods(); web::json::value make_nc_device_manager_events(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager web::json::value make_nc_class_manager_properties(); web::json::value make_nc_class_manager_methods(); web::json::value make_nc_class_manager_events(); - - // make the core datatypes + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitor + web::json::value make_nc_receiver_monitor_properties(); + web::json::value make_nc_receiver_monitor_methods(); + web::json::value make_nc_receiver_monitor_events(); + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitorprotected + web::json::value make_nc_receiver_monitor_protected_properties(); + web::json::value make_nc_receiver_monitor_protected_methods(); + web::json::value make_nc_receiver_monitor_protected_events(); + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/identification/#ncidentbeacon + web::json::value make_nc_ident_beacon_properties(); + web::json::value make_nc_ident_beacon_methods(); + web::json::value make_nc_ident_beacon_events(); + + // Datatype models + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/#datatype-models-for-branch-v10-dev + // + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcBlockMemberDescriptor.html + web::json::value make_nc_block_member_descriptor_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcClassDescriptor.html + web::json::value make_nc_class_descriptor_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcClassId.html web::json::value make_nc_class_id_datatype(); - web::json::value make_nc_oid_datatype(); - web::json::value make_nc_touchpoint_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptor.html + web::json::value make_nc_datatype_descriptor_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptorEnum.html + web::json::value make_nc_datatype_descriptor_enum_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptorPrimitive.html + web::json::value make_nc_datatype_descriptor_primitive_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptorStruct.html + web::json::value make_nc_datatype_descriptor_struct_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptorTypeDef.html + web::json::value make_nc_datatype_descriptor_type_def_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeType.html + web::json::value make_nc_datatype_type_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDescriptor.html + web::json::value make_nc_descriptor_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDeviceGenericState.html + web::json::value make_nc_device_generic_state_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDeviceOperationalState.html + web::json::value make_nc_device_operational_state_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcElementId.html web::json::value make_nc_element_id_datatype(); - web::json::value make_nc_property_id_datatype(); - web::json::value make_nc_property_contraints_datatype(); - web::json::value make_nc_method_result_property_value_datatype(); - web::json::value make_nc_method_status_datatype(); - web::json::value make_nc_method_result_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcEnumItemDescriptor.html + web::json::value make_nc_enum_item_descriptor_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcEventDescriptor.html + web::json::value make_nc_event_descriptor_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcEventId.html + web::json::value make_nc_event_id_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcFieldDescriptor.html + web::json::value make_nc_field_descriptor_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcId.html web::json::value make_nc_id_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcManufacturer.html + web::json::value make_nc_manufacturer_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodDescriptor.html + web::json::value make_nc_method_descriptor_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodId.html + web::json::value make_nc_method_id_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResult.html + web::json::value make_nc_method_result_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultBlockMemberDescriptors.html + web::json::value make_nc_method_result_block_member_descriptors_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultClassDescriptor.html + web::json::value make_nc_method_result_class_descriptor_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultDatatypeDescriptor.html + web::json::value make_nc_method_result_datatype_descriptor_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultError.html + web::json::value make_nc_method_result_error_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultId.html web::json::value make_nc_method_result_id_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultLength.html web::json::value make_nc_method_result_length_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultPropertyValue.html + web::json::value make_nc_method_result_property_value_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodStatus.html + web::json::value make_nc_method_status_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcName.html + web::json::value make_nc_name_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcOid.html + web::json::value make_nc_oid_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcOrganizationId.html + web::json::value make_nc_organization_id_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcParameterConstraints.html + web::json::value make_nc_parameter_constraints_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcParameterConstraintsNumber.html + web::json::value make_nc_parameter_constraints_number_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcParameterConstraintsString.html + web::json::value make_nc_parameter_constraints_string_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcParameterDescriptor.html + web::json::value make_nc_parameter_descriptor_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcProduct.html + web::json::value make_nc_product_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyChangeType.html web::json::value make_nc_property_change_type_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyChangedEventData.html web::json::value make_nc_property_changed_event_data_datatype(); - web::json::value make_nc_descriptor_datatype(); - web::json::value make_nc_block_member_descriptor_datatype(); - web::json::value make_nc_method_result_block_member_descriptors_datatype(); - web::json::value make_nc_version_code_datatype(); - web::json::value make_nc_organization_id_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyConstraints.html + web::json::value make_nc_property_contraints_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyConstraintsNumber.html + web::json::value make_nc_property_constraints_number_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyConstraintsString.html + web::json::value make_nc_property_constraints_string_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyDescriptor.html + web::json::value make_nc_property_descriptor_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyId.html + web::json::value make_nc_property_id_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcRegex.html + web::json::value make_nc_regex_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcResetCause.html + web::json::value make_nc_reset_cause_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcRolePath.html + web::json::value make_nc_role_path_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTimeInterval.html + web::json::value make_nc_time_interval_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpoint.html + web::json::value make_nc_touchpoint_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointNmos.html + web::json::value make_nc_touchpoint_nmos_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointNmosChannelMapping.html + web::json::value make_nc_touchpoint_nmos_channel_mapping_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointResource.html + web::json::value make_nc_touchpoint_resource_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointResourceNmos.html + web::json::value make_nc_touchpoint_resource_nmos_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointResourceNmosChannelMapping.html + web::json::value make_nc_touchpoint_resource_nmos_channel_mapping_datatype(); + // See // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcUri.html web::json::value make_nc_uri_datatype(); - web::json::value make_nc_manufacturer_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcUuid.html web::json::value make_nc_uuid_datatype(); - web::json::value make_nc_product_datatype(); - web::json::value make_nc_device_generic_state_datatype(); - web::json::value make_nc_device_operational_state_datatype(); - web::json::value make_nc_reset_cause_datatype(); - web::json::value make_nc_name_datatype(); - web::json::value make_nc_property_descriptor_datatype(); - web::json::value make_nc_parameter_descriptor_datatype(); - web::json::value make_nc_method_id_datatype(); - web::json::value make_nc_method_descriptor_datatype(); - web::json::value make_nc_event_id_datatype(); - web::json::value make_nc_event_descriptor_datatype(); - web::json::value make_nc_class_descriptor_datatype(); - web::json::value make_nc_parameter_constraints_datatype(); - web::json::value make_nc_datatype_type_datatype(); - web::json::value make_nc_datatype_descriptor_datatype(); - web::json::value make_nc_method_result_class_descriptor_datatype(); - web::json::value make_nc_method_result_datatype_descriptor_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcVersionCode.html + web::json::value make_nc_version_code_datatype(); + + // Monitoring datatypes + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#datatypes + // + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncconnectionstatus + web::json::value make_nc_connection_status_datatype(); + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncpayloadstatus + web::json::value make_nc_payload_status_datatype(); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject web::json::value make_nc_object(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints); @@ -337,7 +487,7 @@ namespace nmos const web::json::value& user_inventory_code, const web::json::value& device_name, const web::json::value& device_role, const web::json::value& operational_state, nc_reset_cause::cause reset_cause); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager - web::json::value make_nc_class_manager(details::nc_oid oid, nc_oid owner, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints); + web::json::value make_nc_class_manager(details::nc_oid oid, nc_oid owner, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, const nmos::experimental::control_protocol_state& control_protocol_state); } } diff --git a/Development/nmos/control_protocol_resources.cpp b/Development/nmos/control_protocol_resources.cpp index 6c89b6f5a..c0aa6a5f8 100644 --- a/Development/nmos/control_protocol_resources.cpp +++ b/Development/nmos/control_protocol_resources.cpp @@ -33,7 +33,7 @@ namespace nmos } // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager - nmos::resource make_class_manager(details::nc_oid oid, nmos::resource& root_block) + nmos::resource make_class_manager(details::nc_oid oid, nmos::resource& root_block, const nmos::experimental::control_protocol_state& control_protocol_state) { using web::json::value; @@ -42,7 +42,7 @@ namespace nmos const auto user_label = value::string(U("Class manager")); const auto description = value::string(U("The class manager offers access to control class and data type descriptors")); - auto data = details::make_nc_class_manager(oid, owner, user_label, value::null(), value::null()); + auto data = details::make_nc_class_manager(oid, owner, user_label, value::null(), value::null(), control_protocol_state); // add NcClassManager block_member_descriptor to root block members web::json::push_back(root_block_data[nmos::fields::nc::members], diff --git a/Development/nmos/control_protocol_resources.h b/Development/nmos/control_protocol_resources.h index ca16c8d9b..b977043cf 100644 --- a/Development/nmos/control_protocol_resources.h +++ b/Development/nmos/control_protocol_resources.h @@ -7,11 +7,16 @@ namespace nmos { + namespace experimental + { + struct control_protocol_state; + } + struct resource; nmos::resource make_device_manager(details::nc_oid oid, nmos::resource& root_block, const nmos::settings& settings); - nmos::resource make_class_manager(details::nc_oid oid, nmos::resource& root_block); + nmos::resource make_class_manager(details::nc_oid oid, nmos::resource& root_block, const nmos::experimental::control_protocol_state& control_protocol_state); nmos::resource make_root_block(); } diff --git a/Development/nmos/control_protocol_state.cpp b/Development/nmos/control_protocol_state.cpp index 7270591a3..aceb88ef1 100644 --- a/Development/nmos/control_protocol_state.cpp +++ b/Development/nmos/control_protocol_state.cpp @@ -13,17 +13,28 @@ namespace nmos // setup the core control classes control_classes = { + // Control class models + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/#control-class-models-for-branch-v10-dev { details::make_nc_class_id(details::nc_object_class_id), { value::string(U("NcObject class descriptor")), details::nc_object_class_id, U("NcObject"), value::null(), details::make_nc_object_properties(), details::make_nc_object_methods(), details::make_nc_object_events() } }, { details::make_nc_class_id(details::nc_block_class_id), { value::string(U("NcBlock class descriptor")), details::nc_block_class_id, U("NcBlock"), value::null(), details::make_nc_block_properties(), details::make_nc_block_methods(), details::make_nc_block_events() } }, { details::make_nc_class_id(details::nc_worker_class_id), { value::string(U("NcWorker class descriptor")), details::nc_worker_class_id, U("NcWorker"), value::null(), details::make_nc_worker_properties(), details::make_nc_worker_methods(), details::make_nc_worker_events() } }, { details::make_nc_class_id(details::nc_manager_class_id), { value::string(U("NcManager class descriptor")), details::nc_manager_class_id, U("NcManager"), value::null(), details::make_nc_manager_properties(), details::make_nc_manager_methods(), details::make_nc_manager_events() } }, { details::make_nc_class_id(details::nc_device_manager_class_id), { value::string(U("NcDeviceManager class descriptor")), details::nc_device_manager_class_id, U("NcDeviceManager"), value::string(U("DeviceManager")), details::make_nc_device_manager_properties(), details::make_nc_device_manager_methods(), details::make_nc_device_manager_events() } }, - { details::make_nc_class_id(details::nc_class_manager_class_id), { value::string(U("NcClassManager class descriptor")), details::nc_class_manager_class_id, U("NcClassManager"), value::string(U("ClassManager")), details::make_nc_class_manager_properties(), details::make_nc_class_manager_methods(), details::make_nc_class_manager_events() } } + { details::make_nc_class_id(details::nc_class_manager_class_id), { value::string(U("NcClassManager class descriptor")), details::nc_class_manager_class_id, U("NcClassManager"), value::string(U("ClassManager")), details::make_nc_class_manager_properties(), details::make_nc_class_manager_methods(), details::make_nc_class_manager_events() } }, + // identification beacon model + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/identification/#ncidentbeacon + { details::make_nc_class_id(details::nc_ident_beacon_class_id), { value::string(U("NcIdentBeacon class descriptor")), details::nc_ident_beacon_class_id, U("NcIdentBeacon"), value::null(), details::make_nc_ident_beacon_properties(), details::make_nc_ident_beacon_methods(), details::make_nc_ident_beacon_events() } }, + // Monitoring + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitor + { details::make_nc_class_id(details::nc_receiver_monitor_class_id), { value::string(U("NcReceiverMonitor class descriptor")), details::nc_receiver_monitor_class_id, U("NcReceiverMonitor"), value::null(), details::make_nc_receiver_monitor_properties(), details::make_nc_receiver_monitor_methods(), details::make_nc_receiver_monitor_events() } }, + { details::make_nc_class_id(details::nc_receiver_monitor_protected_class_id), { value::string(U("NcReceiverMonitorProtected class descriptor")), details::nc_receiver_monitor_protected_class_id, U("NcReceiverMonitorProtected"), value::null(), details::make_nc_receiver_monitor_protected_properties(), details::make_nc_receiver_monitor_protected_methods(), details::make_nc_receiver_monitor_protected_events() } } }; // setup the core datatypes datatypes = { + // Dataype models + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/#datatype-models-for-branch-v10-dev { U("NcClassId"), {details::make_nc_class_id_datatype()} }, { U("NcOid"), {details::make_nc_oid_datatype()} }, { U("NcTouchpoint"), {details::make_nc_touchpoint_datatype()} }, @@ -62,7 +73,30 @@ namespace nmos { U("NcDatatypeType"), {details::make_nc_datatype_type_datatype()} }, { U("NcDatatypeDescriptor"), {details::make_nc_datatype_descriptor_datatype()} }, { U("NcMethodResultClassDescriptor"), {details::make_nc_method_result_class_descriptor_datatype()} }, - { U("NcMethodResultDatatypeDescriptor"), {details::make_nc_method_result_datatype_descriptor_datatype()} } + { U("NcMethodResultDatatypeDescriptor"), {details::make_nc_method_result_datatype_descriptor_datatype()} }, + { U("NcMethodResultError"), {details::make_nc_method_result_error_datatype()} }, + { U("NcDatatypeDescriptorEnum"), {details::make_nc_datatype_descriptor_enum_datatype()} }, + { U("NcDatatypeDescriptorPrimitive"), {details::make_nc_datatype_descriptor_primitive_datatype()} }, + { U("NcDatatypeDescriptorStruct"), {details::make_nc_datatype_descriptor_struct_datatype()} }, + { U("NcDatatypeDescriptorTypeDef"), {details::make_nc_datatype_descriptor_type_def_datatype()} }, + { U("NcEnumItemDescriptor"), {details::make_nc_enum_item_descriptor_datatype()} }, + { U("NcFieldDescriptor"), {details::make_nc_field_descriptor_datatype()} }, + { U("NcPropertyConstraintsNumber"), {details::make_nc_property_constraints_number_datatype()} }, + { U("NcPropertyConstraintsString"), {details::make_nc_property_constraints_string_datatype()} }, + { U("NcRegex"), {details::make_nc_regex_datatype()} }, + { U("NcRolePath"), {details::make_nc_role_path_datatype()} }, + { U("NcParameterConstraintsNumber"), {details::make_nc_parameter_constraints_number_datatype()} }, + { U("NcParameterConstraintsString"), {details::make_nc_parameter_constraints_string_datatype()} }, + { U("NcTimeInterval"), {details::make_nc_time_interval_datatype()} }, + { U("NcTouchpointNmos"), {details::make_nc_touchpoint_nmos_datatype()} }, + { U("NcTouchpointNmosChannelMapping"), {details::make_nc_touchpoint_nmos_channel_mapping_datatype()} }, + { U("NcTouchpointResource"), {details::make_nc_touchpoint_resource_datatype()} }, + { U("NcTouchpointResourceNmos"), {details::make_nc_touchpoint_resource_nmos_datatype()} }, + { U("NcTouchpointResourceNmosChannelMapping"), {details::make_nc_touchpoint_resource_nmos_channel_mapping_datatype()} }, + // Monitoring + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#datatypes + { U("NcConnectionStatus"), {details::make_nc_connection_status_datatype()} }, + { U("NcPayloadStatus"), {details::make_nc_payload_status_datatype()} } }; } } diff --git a/Development/nmos/control_protocol_state.h b/Development/nmos/control_protocol_state.h index 0dfde5990..c15e2fd65 100644 --- a/Development/nmos/control_protocol_state.h +++ b/Development/nmos/control_protocol_state.h @@ -5,6 +5,7 @@ #include "cpprest/json_utils.h" #include "nmos/control_protocol_class_id.h" // for nmos::details::nc_class_id definitions #include "nmos/mutex.h" +#include "nmos/resources.h" namespace nmos { @@ -20,27 +21,6 @@ namespace nmos web::json::value properties; // array of nc_property_descriptor web::json::value methods; // array of nc_method_descriptor web::json::value events; // array of nc_event_descriptor - - //control_class(details::nc_class_id class_id, utility::string_t name, web::json::value fixed_role, web::json::value properties, web::json::value methods, web::json::value events) - // : description(web::json::value::null()) - // , class_id(std::move(class_id)) - // , name(std::move(name)) - // , fixed_role(std::move(fixed_role)) - // , properties(std::move(properties)) - // , methods(std::move(methods)) - // , events(std::move(events)) - //{} - - //control_class(const utility::string_t& description, details::nc_class_id class_id, utility::string_t name, web::json::value fixed_role, web::json::value properties, web::json::value methods, web::json::value events) - // : description(web::json::value::string(description)) - // , class_id(std::move(class_id)) - // , name(std::move(name)) - // , fixed_role(std::move(fixed_role)) - // , properties(std::move(properties)) - // , methods(std::move(methods)) - // , events(std::move(events)) - //{} - }; struct datatype // NcDatatypeDescriptorEnum/NcDatatypeDescriptorPrimitive/NcDatatypeDescriptorStruct/NcDatatypeDescriptorTypeDef @@ -53,6 +33,10 @@ namespace nmos // nc_name vs datatype typedef std::map datatypes; + // methods defnitions + typedef std::function method; + typedef std::map methods; // method_id vs method handler + struct control_protocol_state { // mutex to be used to protect the members from simultaneous access by multiple threads diff --git a/Development/nmos/control_protocol_ws_api.cpp b/Development/nmos/control_protocol_ws_api.cpp index c51b90655..8e5f31752 100644 --- a/Development/nmos/control_protocol_ws_api.cpp +++ b/Development/nmos/control_protocol_ws_api.cpp @@ -5,6 +5,7 @@ #include "cpprest/regex_utils.h" #include "nmos/api_utils.h" #include "nmos/control_protocol_resources.h" +#include "nmos/control_protocol_state.h" #include "nmos/control_protocol_utils.h" #include "nmos/is12_versions.h" #include "nmos/json_schema.h" @@ -46,6 +47,597 @@ namespace nmos controlprotocol_validator().validate(request_data, experimental::make_controlprotocolapi_subscription_message_schema_uri(version)); } + // hmm, change property to struct + web::json::value find_property(const web::json::value& property_id, const nc_class_id& class_id_, const nmos::experimental::control_classes& control_classes) + { + using web::json::value; + + auto class_id = class_id_; + + while (!class_id.empty()) + { + auto class_found = control_classes.find(make_nc_class_id(class_id)); + if (control_classes.end() != class_found) + { + auto& properties = class_found->second.properties.as_array(); + for (const auto& property : properties) + { + if (property_id == nmos::fields::nc::id(property)) + { + return property; + } + } + } + class_id.pop_back(); + } + + return value::null(); + }; + + // hmm, change method_id to struct, and bring in method handlers via the control_classes + nmos::experimental::method find_method(const web::json::value& method_id, const nc_class_id& class_id_, const nmos::experimental::control_classes& control_classes) + { + using web::json::value; + using web::json::value_of; + + // NcObject methods implementation + // Get property value + const auto get = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + // where arguments is the property id = (level, index) + const auto& property_id = nmos::fields::nc::id(arguments); + + // find the relevant nc_property_descriptor + const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); + if (!property.is_null()) + { + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, resource->data.at(nmos::fields::nc::name(property))); + } + + // unknown property + utility::stringstream_t ss; + ss << U("unknown property: ") << property_id.serialize() << U(" to do Get"); + return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); + }; + // Set property value + const auto set = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + const auto& property_id = nmos::fields::nc::id(arguments); + const auto& val = nmos::fields::nc::value(arguments); + + // find the relevant nc_property_descriptor + const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); + if (!property.is_null()) + { + if (nmos::fields::nc::is_read_only(property)) + { + return details::make_control_protocol_response(handle, { details::nc_method_status::read_only }); + } + + if ((val.is_null() && !nmos::fields::nc::is_nullable(property)) + || (val.is_array() && !nmos::fields::nc::is_sequence(property))) + { + return details::make_control_protocol_response(handle, { details::nc_method_status::parameter_error }); + } + + resources.modify(resource, [&](nmos::resource& resource) + { + resource.data[nmos::fields::nc::name(property)] = val; + + resource.updated = strictly_increasing_update(resources); + }); + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }); + } + + // unknown property + utility::stringstream_t ss; + ss << U("unknown property: ") << property_id.serialize() << " to do Set"; + return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); + }; + // Get sequence item + const auto get_sequence_item = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + const auto& property_id = nmos::fields::nc::id(arguments); + const auto& index = nmos::fields::nc::index(arguments); + + // find the relevant nc_property_descriptor + const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); + if (!property.is_null()) + { + if (!nmos::fields::nc::is_sequence(property)) + { + // property is not a sequence + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do GetSequenceItem"); + return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); + } + + auto& data = resource->data.at(nmos::fields::nc::name(property)); + + if (!data.is_null() && data.as_array().size() > (size_t)index) + { + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, data.at(index)); + } + + // out of bound + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << U(" is outside the available range to do GetSequenceItem"); + return details::make_control_protocol_error_response(handle, { details::nc_method_status::index_out_of_bounds }, ss.str()); + } + + // unknown property + utility::stringstream_t ss; + ss << U("unknown property: ") << property_id.serialize() << U(" to do GetSequenceItem"); + return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); + }; + // Set sequence item + const auto set_sequence_item = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + const auto& property_id = nmos::fields::nc::id(arguments); + const auto& index = nmos::fields::nc::index(arguments); + const auto& val = nmos::fields::nc::value(arguments); + + // find the relevant nc_property_descriptor + const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); + if (!property.is_null()) + { + if (!nmos::fields::nc::is_sequence(property)) + { + // property is not a sequence + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do SetSequenceItem"); + return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); + } + + auto& data = resource->data.at(nmos::fields::nc::name(property)); + + if (!data.is_null() && data.as_array().size() > (size_t)index) + { + resources.modify(resource, [&](nmos::resource& resource) + { + resource.data[nmos::fields::nc::name(property)][index] = val; + + resource.updated = strictly_increasing_update(resources); + }); + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }); + } + + // out of bound + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << U(" is outside the available range to do SetSequenceItem"); + return details::make_control_protocol_error_response(handle, { details::nc_method_status::index_out_of_bounds }, ss.str()); + } + + // unknown property + utility::stringstream_t ss; + ss << U("unknown property: ") << property_id.serialize() << U(" to do SetSequenceItem"); + return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); + }; + // Add item to sequence + const auto add_sequence_item = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + const auto& property_id = nmos::fields::nc::id(arguments); + const auto& val = nmos::fields::nc::value(arguments); + + // find the relevant nc_property_descriptor + const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); + if (!property.is_null()) + { + if (!nmos::fields::nc::is_sequence(property)) + { + // property is not a sequence + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do AddSequenceItem"); + return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); + } + + auto& data = resource->data.at(nmos::fields::nc::name(property)); + + resources.modify(resource, [&](nmos::resource& resource) + { + auto& sequence = resource.data[nmos::fields::nc::name(property)]; + if (data.is_null()) { sequence = value::array(); } + web::json::push_back(sequence, val); + + resource.updated = strictly_increasing_update(resources); + }); + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, uint32_t(data.as_array().size() - 1)); + } + + // unknown property + utility::stringstream_t ss; + ss << U("unknown property: ") << property_id.serialize() << U(" to do AddSequenceItem"); + return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); + }; + // Delete sequence item + const auto remove_sequence_item = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + const auto& property_id = nmos::fields::nc::id(arguments); + const auto& index = nmos::fields::nc::index(arguments); + + // find the relevant nc_property_descriptor + const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); + if (!property.is_null()) + { + if (!nmos::fields::nc::is_sequence(property)) + { + // property is not a sequence + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do RemoveSequenceItem"); + return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); + } + + auto& data = resource->data.at(nmos::fields::nc::name(property)); + + if (!data.is_null() && data.as_array().size() > (size_t)index) + { + resources.modify(resource, [&](nmos::resource& resource) + { + auto& sequence = resource.data[nmos::fields::nc::name(property)].as_array(); + sequence.erase(index); + + resource.updated = strictly_increasing_update(resources); + }); + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }); + } + + // out of bound + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << U(" is outside the available range to do RemoveSequenceItem"); + return details::make_control_protocol_error_response(handle, { details::nc_method_status::index_out_of_bounds }, ss.str()); + } + + // unknown property + utility::stringstream_t ss; + ss << U("unknown property: ") << property_id.serialize() << U(" to do RemoveSequenceItem"); + return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); + }; + // Get sequence length + const auto get_sequence_length = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + const auto& property_id = nmos::fields::nc::id(arguments); + + // find the relevant nc_property_descriptor + const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); + if (!property.is_null()) + { + if (!nmos::fields::nc::is_sequence(property)) + { + // property is not a sequence + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do GetSequenceLength"); + return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); + } + + auto& data = resource->data.at(nmos::fields::nc::name(property)); + + if (nmos::fields::nc::is_nullable(property)) + { + // can be null + if (data.is_null()) + { + // null + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, value::null()); + } + } + else + { + // cannot be null + if (data.is_null()) + { + // null + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << " is a null sequence to do GetSequenceLength"; + return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); + } + } + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, uint32_t(data.as_array().size())); + } + + // unknown property + utility::stringstream_t ss; + ss << U("unknown property: ") << property_id.serialize() << " to do GetSequenceLength"; + return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); + }; + + // NcBlock methods implementation + // Gets descriptors of members of the block + const auto get_member_descriptors = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + const auto& recurse = nmos::fields::nc::recurse(arguments); // If recurse is set to true, nested members is to be retrieved + + auto descriptors = value::array(); + nmos::get_member_descriptors(resources, resource, recurse, descriptors.as_array()); + + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, descriptors); + }; + // Finds member(s) by path + const auto find_members_by_path = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + // Relative path to search for (MUST not include the role of the block targeted by oid) + const auto& path = nmos::fields::nc::path(arguments); + + if (0 == path.size()) + { + // empty path + return details::make_control_protocol_error_response(handle, { details::nc_method_status::parameter_error }, U("empty path to do FindMembersByPath")); + } + + auto nc_block_member_descriptors = value::array(); + + for (const auto& role : path) + { + // look for the role in members + if (resource->data.has_field(nmos::fields::nc::members)) + { + auto& members = nmos::fields::nc::members(resource->data); + auto member_found = std::find_if(members.begin(), members.end(), [&](const web::json::value& nc_block_member_descriptor) + { + return role.as_string() == nmos::fields::nc::role(nc_block_member_descriptor); + }); + + if (members.end() != member_found) + { + web::json::push_back(nc_block_member_descriptors, *member_found); + + // use oid to look for the next resource + resource = nmos::find_resource(resources, utility::s2us(std::to_string(nmos::fields::nc::oid(*member_found)))); + } + else + { + // no role + utility::stringstream_t ss; + ss << U("role: ") << role.as_string() << U(" not found to do FindMembersByPath"); + return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); + } + } + else + { + // no members + return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, U("no members to do FindMembersByPath")); + } + } + + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, nc_block_member_descriptors); + }; + // Finds members with given role name or fragment + const auto find_members_by_role = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + { + const auto& role = nmos::fields::nc::role(arguments); // Role text to search for + const auto& case_sensitive = nmos::fields::nc::case_sensitive(arguments); // Signals if the comparison should be case sensitive + const auto& match_whole_string = nmos::fields::nc::match_whole_string(arguments); // TRUE to only return exact matches + const auto& recurse = nmos::fields::nc::recurse(arguments); // TRUE to search nested blocks + + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + if (role.empty()) + { + // empty role + return details::make_control_protocol_error_response(handle, { details::nc_method_status::parameter_error }, U("empty role to do FindMembersByRole")); + } + + auto descriptors = value::array(); + nmos::find_members_by_role(resources, resource, role, match_whole_string, case_sensitive, recurse, descriptors.as_array()); + + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, descriptors); + }; + // Finds members with given class id + const auto find_members_by_class_id = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + { + const auto& class_id = details::parse_nc_class_id(nmos::fields::nc::class_id(arguments)); // Class id to search for + const auto& include_derived = nmos::fields::nc::include_derived(arguments); // If TRUE it will also include derived class descriptors + const auto& recurse = nmos::fields::nc::recurse(arguments); // TRUE to search nested blocks + + if (class_id.empty()) + { + // empty class_id + return details::make_control_protocol_error_response(handle, { details::nc_method_status::parameter_error }, U("empty classId to do FindMembersByClassId")); + } + + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + auto descriptors = value::array(); + nmos::find_members_by_class_id(resources, resource, class_id, include_derived, recurse, descriptors.as_array()); + + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, descriptors); + }; + + // NcClassManager methods implementation + // Get a single class descriptor + const auto get_control_class = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + { + const auto& class_id = details::parse_nc_class_id(nmos::fields::nc::class_id(arguments)); // Class id to search for + const auto& include_inherited = nmos::fields::nc::include_inherited(arguments); // If set the descriptor would contain all inherited elements + + if (class_id.empty()) + { + // empty class_id + return details::make_control_protocol_error_response(handle, { details::nc_method_status::parameter_error }, U("empty classId to do GetControlClass")); + } + + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + auto class_found = control_classes.find(make_nc_class_id(class_id)); + + if (control_classes.end() != class_found) + { + auto id = class_id; + + auto description = class_found->second.description; + auto name = class_found->second.name; + auto fixed_role = class_found->second.fixed_role; + auto properties = class_found->second.properties; + auto methods = class_found->second.methods; + auto events = class_found->second.events; + + id.pop_back(); + + if (include_inherited) + { + while (!id.empty()) + { + auto found = control_classes.find(make_nc_class_id(id)); + if (control_classes.end() != found) + { + for (const auto& property : found->second.properties.as_array()) { web::json::push_back(properties, property); } + for (const auto& method : found->second.methods.as_array()) { web::json::push_back(methods, method); } + for (const auto& event : found->second.events.as_array()) { web::json::push_back(events, event); } + } + id.pop_back(); + } + } + auto descriptor = details::make_nc_class_descriptor(description, class_id, name, fixed_role, properties, methods, events); + + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, descriptor); + } + + return details::make_control_protocol_error_response(handle, { details::nc_method_status::parameter_error }, U("classId not found")); + }; + // Get a single datatype descriptor + const auto get_datatype = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + { + const auto& name = nmos::fields::nc::name(arguments); // name of datatype + const auto& include_inherited = nmos::fields::nc::include_inherited(arguments); // If set the descriptor would contain all inherited elements + + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + if (name.empty()) + { + // empty name + return details::make_control_protocol_error_response(handle, { details::nc_method_status::parameter_error }, U("empty name to do GetDatatype")); + } + + auto datatype_found = datatypes.find(name); + + if (datatypes.end() != datatype_found) + { + auto descriptor = datatype_found->second.descriptor; + + if (include_inherited) + { + const auto& type = nmos::fields::nc::type(descriptor); + if (details::nc_datatype_type::Struct == type) + { + auto descriptor_ = descriptor; + + for (;;) + { + const auto& parent_type = descriptor_.at(nmos::fields::nc::parent_type); + if (!parent_type.is_null()) + { + auto datatype_found_ = datatypes.find(parent_type.as_string()); + if (datatypes.end() != datatype_found_) + { + descriptor_ = datatype_found_->second.descriptor; + const auto& fields = nmos::fields::nc::fields(descriptor_); + for (const auto& field : fields) + { + web::json::push_back(descriptor.at(nmos::fields::nc::fields), field); + } + } + } + else + { + break; + } + } + } + } + + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, descriptor); + } + + return details::make_control_protocol_error_response(handle, { details::nc_method_status::parameter_error }, U("name not found")); + }; + + // method handlers for the different classes + nmos::experimental::methods nc_object_method_handlers; // method_id vs NcObject method_handler + nmos::experimental::methods nc_block_method_handlers; // method_id vs NcBlock method_handler + nmos::experimental::methods nc_worker_method_handlers; // method_id vs NcWorker method_handler + nmos::experimental::methods nc_manager_method_handlers; // method_id vs NcManager method_handler + nmos::experimental::methods nc_device_manager_method_handlers; // method_id vs NcDeviceManager method_handler + nmos::experimental::methods nc_class_manager_method_handlers; // method_id vs NcClassManager method_handler + + // NcObject methods + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject + nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 1 } })] = get; + nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 2 } })] = set; + nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 3 } })] = get_sequence_item; + nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 4 } })] = set_sequence_item; + nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 5 } })] = add_sequence_item; + nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 6 } })] = remove_sequence_item; + nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 7 } })] = get_sequence_length; + + // NcBlock methods + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock + nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 1 } })] = get_member_descriptors; + nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 2 } })] = find_members_by_path; + nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 3 } })] = find_members_by_role; + nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 4 } })] = find_members_by_class_id; + + // NcWorker has no extended method + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncworker + + // NcManager has no extended method + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanager + + // NcDeviceManger has no extended method + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager + + // NcClassManager methods + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager + nc_class_manager_method_handlers[value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 1 } })] = get_control_class; + nc_class_manager_method_handlers[value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 2 } })] = get_datatype; + + // class id vs method handlers + // hmm, todo, custom class and assoicated methods will need to be inserted within follwoing table! + const std::map methods = + { + { details::make_nc_class_id(details::nc_object_class_id), nc_object_method_handlers }, + { details::make_nc_class_id(details::nc_block_class_id), nc_block_method_handlers }, + { details::make_nc_class_id(details::nc_class_manager_class_id), nc_class_manager_method_handlers } + }; + + auto class_id = class_id_; + + while (!class_id.empty()) + { + auto subset_methods_found = methods.find(make_nc_class_id(class_id)); + + if (methods.end() != subset_methods_found) + { + auto& subset_methods = subset_methods_found->second; + auto method_found = subset_methods.find(method_id); + if (subset_methods.end() != method_found) + { + return method_found->second; + } + } + class_id.pop_back(); + } + + return NULL; + } + + /* std::pair create_properties_methods(nmos::node_model& model, const nc_class_id& class_id_, const nmos::experimental::control_classes& control_classes) { using web::json::value; @@ -55,7 +647,7 @@ namespace nmos // NcObject methods implementation // Get property value - const auto get = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + const auto get = [&model](int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -67,13 +659,10 @@ namespace nmos const auto& property_id = nmos::fields::nc::id(arguments); // find the relevant nc_property_descriptor - auto property_found = std::find_if(properties.begin(), properties.end(), [property_id](const web::json::value& property) - { - return property_id == nmos::fields::nc::id(property); - }); - if (properties.end() != property_found) + const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); + if (!property.is_null()) { - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, resource->data.at(nmos::fields::nc::name(*property_found))); + return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, resource->data.at(nmos::fields::nc::name(property))); } // unknown property @@ -88,7 +677,7 @@ namespace nmos return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; // Set property value - const auto set = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + const auto set = [&model](int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -100,26 +689,23 @@ namespace nmos const auto& val = nmos::fields::nc::value(arguments); // find the relevant nc_property_descriptor - auto property_found = std::find_if(properties.begin(), properties.end(), [property_id](const web::json::value& property) - { - return property_id == nmos::fields::nc::id(property); - }); - if (properties.end() != property_found) + const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); + if (!property.is_null()) { - if (nmos::fields::nc::is_read_only(*property_found)) + if (nmos::fields::nc::is_read_only(property)) { return details::make_control_protocol_response(handle, { details::nc_method_status::read_only }); } - if ((val.is_null() && !nmos::fields::nc::is_nullable(*property_found)) - || (val.is_array() && !nmos::fields::nc::is_sequence(*property_found))) + if ((val.is_null() && !nmos::fields::nc::is_nullable(property)) + || (val.is_array() && !nmos::fields::nc::is_sequence(property))) { return details::make_control_protocol_response(handle, { details::nc_method_status::parameter_error }); } resources.modify(resource, [&](nmos::resource& resource) { - resource.data[nmos::fields::nc::name(*property_found)] = val; + resource.data[nmos::fields::nc::name(property)] = val; resource.updated = strictly_increasing_update(resources); }); @@ -138,7 +724,7 @@ namespace nmos return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; // Get sequence item - const auto get_sequence_item = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + const auto get_sequence_item = [&model](int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -150,13 +736,10 @@ namespace nmos const auto& index = nmos::fields::nc::index(arguments); // find the relevant nc_property_descriptor - auto property_found = std::find_if(properties.begin(), properties.end(), [property_id](const web::json::value& property) + const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); + if (!property.is_null()) { - return property_id == nmos::fields::nc::id(property); - }); - if (properties.end() != property_found) - { - if (!nmos::fields::nc::is_sequence(*property_found)) + if (!nmos::fields::nc::is_sequence(property)) { // property is not a sequence utility::stringstream_t ss; @@ -164,7 +747,7 @@ namespace nmos return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); } - auto& data = resource->data.at(nmos::fields::nc::name(*property_found)); + auto& data = resource->data.at(nmos::fields::nc::name(property)); if (!data.is_null() && data.as_array().size() > (size_t)index) { @@ -189,7 +772,7 @@ namespace nmos return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; // Set sequence item - const auto set_sequence_item = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + const auto set_sequence_item = [&model](int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -202,13 +785,10 @@ namespace nmos const auto& val = nmos::fields::nc::value(arguments); // find the relevant nc_property_descriptor - auto property_found = std::find_if(properties.begin(), properties.end(), [property_id](const web::json::value& property) - { - return property_id == nmos::fields::nc::id(property); - }); - if (properties.end() != property_found) + const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); + if (!property.is_null()) { - if (!nmos::fields::nc::is_sequence(*property_found)) + if (!nmos::fields::nc::is_sequence(property)) { // property is not a sequence utility::stringstream_t ss; @@ -216,13 +796,13 @@ namespace nmos return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); } - auto& data = resource->data.at(nmos::fields::nc::name(*property_found)); + auto& data = resource->data.at(nmos::fields::nc::name(property)); if (!data.is_null() && data.as_array().size() > (size_t)index) { resources.modify(resource, [&](nmos::resource& resource) { - resource.data[nmos::fields::nc::name(*property_found)][index] = val; + resource.data[nmos::fields::nc::name(property)][index] = val; resource.updated = strictly_increasing_update(resources); }); @@ -247,7 +827,7 @@ namespace nmos return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; // Add item to sequence - const auto add_sequence_item = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + const auto add_sequence_item = [&model](int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -259,13 +839,10 @@ namespace nmos const auto& val = nmos::fields::nc::value(arguments); // find the relevant nc_property_descriptor - auto property_found = std::find_if(properties.begin(), properties.end(), [property_id](const web::json::value& property) - { - return property_id == nmos::fields::nc::id(property); - }); - if (properties.end() != property_found) + const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); + if (!property.is_null()) { - if (!nmos::fields::nc::is_sequence(*property_found)) + if (!nmos::fields::nc::is_sequence(property)) { // property is not a sequence utility::stringstream_t ss; @@ -273,11 +850,11 @@ namespace nmos return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); } - auto& data = resource->data.at(nmos::fields::nc::name(*property_found)); + auto& data = resource->data.at(nmos::fields::nc::name(property)); resources.modify(resource, [&](nmos::resource& resource) { - auto& sequence = resource.data[nmos::fields::nc::name(*property_found)]; + auto& sequence = resource.data[nmos::fields::nc::name(property)]; if (data.is_null()) { sequence = value::array(); } web::json::push_back(sequence, val); @@ -298,7 +875,7 @@ namespace nmos return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; // Delete sequence item - const auto remove_sequence_item = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + const auto remove_sequence_item = [&model](int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -310,13 +887,10 @@ namespace nmos const auto& index = nmos::fields::nc::index(arguments); // find the relevant nc_property_descriptor - auto property_found = std::find_if(properties.begin(), properties.end(), [property_id](const web::json::value& property) + const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); + if (!property.is_null()) { - return property_id == nmos::fields::nc::id(property); - }); - if (properties.end() != property_found) - { - if (!nmos::fields::nc::is_sequence(*property_found)) + if (!nmos::fields::nc::is_sequence(property)) { // property is not a sequence utility::stringstream_t ss; @@ -324,13 +898,13 @@ namespace nmos return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); } - auto& data = resource->data.at(nmos::fields::nc::name(*property_found)); + auto& data = resource->data.at(nmos::fields::nc::name(property)); if (!data.is_null() && data.as_array().size() > (size_t)index) { resources.modify(resource, [&](nmos::resource& resource) { - auto& sequence = resource.data[nmos::fields::nc::name(*property_found)].as_array(); + auto& sequence = resource.data[nmos::fields::nc::name(property)].as_array(); sequence.erase(index); resource.updated = strictly_increasing_update(resources); @@ -356,7 +930,7 @@ namespace nmos return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; // Get sequence length - const auto get_sequence_length = [&model](const web::json::array& properties, int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + const auto get_sequence_length = [&model](int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -367,14 +941,10 @@ namespace nmos const auto& property_id = nmos::fields::nc::id(arguments); // find the relevant nc_property_descriptor - auto property_found = std::find_if(properties.begin(), properties.end(), [property_id](const web::json::value& property) - { - return property_id == nmos::fields::nc::id(property); - }); - - if (property_found != properties.end()) + const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); + if (!property.is_null()) { - if (!nmos::fields::nc::is_sequence(*property_found)) + if (!nmos::fields::nc::is_sequence(property)) { // property is not a sequence utility::stringstream_t ss; @@ -382,9 +952,9 @@ namespace nmos return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); } - auto& data = resource->data.at(nmos::fields::nc::name(*property_found)); + auto& data = resource->data.at(nmos::fields::nc::name(property)); - if (nmos::fields::nc::is_nullable(*property_found)) + if (nmos::fields::nc::is_nullable(property)) { // can be null if (data.is_null()) @@ -421,7 +991,7 @@ namespace nmos // NcBlock methods implementation // Gets descriptors of members of the block - const auto get_member_descriptors = [&model](const web::json::array&, int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + const auto get_member_descriptors = [&model](int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -443,7 +1013,7 @@ namespace nmos return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; // Finds member(s) by path - const auto find_members_by_path = [&model](const web::json::array&, int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + const auto find_members_by_path = [&model](int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -504,7 +1074,7 @@ namespace nmos return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; // Finds members with given role name or fragment - const auto find_members_by_role = [&model](const web::json::array&, int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + const auto find_members_by_role = [&model](int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) { const auto& role = nmos::fields::nc::role(arguments); // Role text to search for const auto& case_sensitive = nmos::fields::nc::case_sensitive(arguments); // Signals if the comparison should be case sensitive @@ -536,7 +1106,7 @@ namespace nmos return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; // Finds members with given class id - const auto find_members_by_class_id = [&model](const web::json::array&, int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + const auto find_members_by_class_id = [&model](int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) { const auto& class_id = details::parse_nc_class_id(nmos::fields::nc::class_id(arguments)); // Class id to search for const auto& include_derived = nmos::fields::nc::include_derived(arguments); // If TRUE it will also include derived class descriptors @@ -569,7 +1139,7 @@ namespace nmos // NcClassManager methods implementation // Get a single class descriptor - const auto get_control_class = [&model](const web::json::array&, int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + const auto get_control_class = [&model](int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) { const auto& class_id = details::parse_nc_class_id(nmos::fields::nc::class_id(arguments)); // Class id to search for const auto& include_inherited = nmos::fields::nc::include_inherited(arguments); // If set the descriptor would contain all inherited elements @@ -630,7 +1200,7 @@ namespace nmos return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); }; // Get a single datatype descriptor - const auto get_datatype = [&model](const web::json::array&, int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + const auto get_datatype = [&model](int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) { const auto& name = nmos::fields::nc::name(arguments); // name of datatype const auto& include_inherited = nmos::fields::nc::include_inherited(arguments); // If set the descriptor would contain all inherited elements @@ -793,6 +1363,7 @@ namespace nmos return { properties, methods }; } + */ } // IS-12 Control Protocol WebSocket API @@ -994,18 +1565,14 @@ namespace nmos auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); if (resources.end() != resource) { - // create the combined properties and method handlers based on class_id auto class_id = details::parse_nc_class_id(nmos::fields::nc::class_id(resource->data)); - auto properties_methods = details::create_properties_methods(model, class_id, get_control_protocol_classes()); - auto& properties = properties_methods.first; - auto& methods = properties_methods.second; // find the relevent method handler to execute - auto method_found = methods.find(method_id); - if (method_found != methods.end()) + auto method = details::find_method(method_id, class_id, get_control_protocol_classes()); + if (method) { // execute the relevant method handler, then accumulating up their response to reponses - web::json::push_back(responses, method_found->second(properties.as_array(), handle, oid, arguments, get_control_protocol_classes(), get_control_protocol_datatypes())); + web::json::push_back(responses, method(resources, resource, handle, arguments, get_control_protocol_classes(), get_control_protocol_datatypes())); } else { diff --git a/Development/nmos/json_fields.h b/Development/nmos/json_fields.h index a18242e7c..df831eaec 100644 --- a/Development/nmos/json_fields.h +++ b/Development/nmos/json_fields.h @@ -316,6 +316,20 @@ namespace nmos const web::json::field_as_integer change_type{ U("changeType") }; // NcPropertyChangeType const web::json::field_as_integer sequence_item_index{ U("sequenceItemIndex") }; // NcId, can be null const web::json::field_as_value property_id{ U("propertyId") }; + const web::json::field_as_integer maximum{ U("maximum") }; + const web::json::field_as_integer minimum{ U("minimum") }; + const web::json::field_as_integer step{ U("step") }; + const web::json::field_as_integer max_characters{ U("maxCharacters") }; + const web::json::field_as_string pattern{ U("pattern") }; + const web::json::field_as_value resource{ U("resource") }; + const web::json::field_as_string resource_type{ U("resourceType") }; + const web::json::field_as_string io_id{ U("ioId") }; + const web::json::field_as_integer connection_status{ U("connectionStatus") }; // NcConnectionStatus + const web::json::field_as_string connection_status_message{ U("connectionStatusMessage") }; + const web::json::field_as_integer payload_status{ U("payloadStatus") }; // NcPayloadStatus + const web::json::field_as_string payload_status_message{ U("payloadStatusMessage") }; + const web::json::field_as_bool signal_protection_status{ U("signalProtectionStatus") }; + const web::json::field_as_bool active{ U("active") }; } // NMOS Parameter Registers From f7dacb2a21abd60d9e02bb5ea984685fde5f695f Mon Sep 17 00:00:00 2001 From: lo-simon Date: Fri, 18 Aug 2023 18:50:59 +0100 Subject: [PATCH 025/106] Use control_protocol_ws_port to construct request URLs for the Control Protocol websocket, or negative to disable the control protocol features --- Development/nmos-cpp-node/config.json | 1 + Development/nmos-cpp-node/main.cpp | 7 ++++-- .../nmos-cpp-node/node_implementation.cpp | 23 +++++++++++-------- Development/nmos/node_server.cpp | 23 +++++++++++++------ Development/nmos/settings.h | 1 + 5 files changed, 36 insertions(+), 19 deletions(-) diff --git a/Development/nmos-cpp-node/config.json b/Development/nmos-cpp-node/config.json index 63625c42e..397da858f 100644 --- a/Development/nmos-cpp-node/config.json +++ b/Development/nmos-cpp-node/config.json @@ -137,6 +137,7 @@ //"channelmapping_port": 3215, // system_port [node]: used to construct request URLs for the System API (if not discovered via DNS-SD) //"system_port": 10641, + // control_protocol_ws_port [node]: used to construct request URLs for the Control Protocol websocket, or negative to disable the control protocol features //"control_protocol_ws_port": 3218, // listen_backlog [registry, node]: the maximum length of the queue of pending connections, or zero for the implementation default (the implementation may not honour this value) diff --git a/Development/nmos-cpp-node/main.cpp b/Development/nmos-cpp-node/main.cpp index 5b17eebb5..5dd65c38e 100644 --- a/Development/nmos-cpp-node/main.cpp +++ b/Development/nmos-cpp-node/main.cpp @@ -110,8 +110,11 @@ int main(int argc, char* argv[]) #endif nmos::experimental::control_protocol_state control_protocol_state; - node_implementation.on_get_control_classes(nmos::make_get_control_protocol_classes_handler(control_protocol_state, gate)); - node_implementation.on_get_control_datatypes(nmos::make_get_control_protocol_datatypes_handler(control_protocol_state, gate)); + if (0 <= nmos::fields::control_protocol_ws_port(node_model.settings)) + { + node_implementation.on_get_control_classes(nmos::make_get_control_protocol_classes_handler(control_protocol_state, gate)); + node_implementation.on_get_control_datatypes(nmos::make_get_control_protocol_datatypes_handler(control_protocol_state, gate)); + } // Set up the node server diff --git a/Development/nmos-cpp-node/node_implementation.cpp b/Development/nmos-cpp-node/node_implementation.cpp index d232d3bf3..2d4774f13 100644 --- a/Development/nmos-cpp-node/node_implementation.cpp +++ b/Development/nmos-cpp-node/node_implementation.cpp @@ -897,16 +897,19 @@ void node_implementation_init(nmos::node_model& model, const nmos::experimental: if (!insert_resource_after(delay_millis, model.channelmapping_resources, std::move(channelmapping_output), gate)) throw node_implementation_init_exception(); } - // example root block - auto root_block = nmos::make_root_block(); - // example device manager - auto device_manager = nmos::make_device_manager(2, root_block, model.settings); - if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(device_manager), gate)) throw node_implementation_init_exception(); - // example class manager - auto class_manager = nmos::make_class_manager(3, root_block, control_protocol_state); - if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(class_manager), gate)) throw node_implementation_init_exception(); - // insert root block to model - if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(root_block), gate)) throw node_implementation_init_exception(); + if (0 <= nmos::fields::control_protocol_ws_port(model.settings)) + { + // example root block + auto root_block = nmos::make_root_block(); + // example device manager + auto device_manager = nmos::make_device_manager(2, root_block, model.settings); + if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(device_manager), gate)) throw node_implementation_init_exception(); + // example class manager + auto class_manager = nmos::make_class_manager(3, root_block, control_protocol_state); + if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(class_manager), gate)) throw node_implementation_init_exception(); + // insert root block to model + if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(root_block), gate)) throw node_implementation_init_exception(); + } } void node_implementation_run(nmos::node_model& model, slog::base_gate& gate) diff --git a/Development/nmos/node_server.cpp b/Development/nmos/node_server.cpp index d163fdea8..cf4c15054 100644 --- a/Development/nmos/node_server.cpp +++ b/Development/nmos/node_server.cpp @@ -69,10 +69,14 @@ namespace nmos events_ws_api.first = nmos::make_events_ws_api(node_model, events_ws_api.second, gate); // can't share a port between the events ws and the control protocol ws + const auto& control_protocol_enabled = (0 <= nmos::fields::control_protocol_ws_port(node_model.settings)); const auto& control_protocol_ws_port = nmos::fields::control_protocol_ws_port(node_model.settings); - if (control_protocol_ws_port == events_ws_port) throw std::runtime_error("Same port used for events and control protocol websockets are not supported"); - auto& control_protocol_ws_api = node_server.ws_handlers[{ {}, control_protocol_ws_port }]; - control_protocol_ws_api.first = nmos::make_control_protocol_ws_api(node_model, control_protocol_ws_api.second, node_implementation.get_control_protocol_classes, node_implementation.get_control_protocol_datatypes, gate); + if (control_protocol_enabled) + { + if (control_protocol_ws_port == events_ws_port) throw std::runtime_error("Same port used for events and control protocol websockets are not supported"); + auto& control_protocol_ws_api = node_server.ws_handlers[{ {}, control_protocol_ws_port }]; + control_protocol_ws_api.first = nmos::make_control_protocol_ws_api(node_model, control_protocol_ws_api.second, node_implementation.get_control_protocol_classes, node_implementation.get_control_protocol_datatypes, gate); + } // Set up the listeners for each HTTP API port @@ -110,7 +114,7 @@ namespace nmos else { ++event_ws_pos; } } - if (!found_control_protocol_ws) + if (control_protocol_enabled && !found_control_protocol_ws) { if (ws_handler.first.second == control_protocol_ws_port) { found_control_protocol_ws = true; } else { ++control_protocol_ws_pos; } @@ -118,7 +122,6 @@ namespace nmos } auto& events_ws_listener = node_server.ws_listeners.at(event_ws_pos); - auto& control_protocol_ws_listener = node_server.ws_listeners.at(control_protocol_ws_pos); // Set up node operation (including the DNS-SD advertisements) @@ -133,8 +136,7 @@ namespace nmos [&] { nmos::send_events_ws_messages_thread(events_ws_listener, node_model, events_ws_api.second, gate); }, [&] { nmos::erase_expired_events_resources_thread(node_model, gate); }, [&, resolve_auto, set_transportfile, connection_activated] { nmos::connection_activation_thread(node_model, resolve_auto, set_transportfile, connection_activated, gate); }, - [&, channelmapping_activated] { nmos::channelmapping_activation_thread(node_model, channelmapping_activated, gate); }, - [&] { nmos::send_control_protocol_ws_messages_thread(control_protocol_ws_listener, node_model, control_protocol_ws_api.second, gate); } + [&, channelmapping_activated] { nmos::channelmapping_activation_thread(node_model, channelmapping_activated, gate); } }); auto system_changed = node_implementation.system_changed; @@ -143,6 +145,13 @@ namespace nmos node_server.thread_functions.push_back([&, load_ca_certificates, system_changed] { nmos::node_system_behaviour_thread(node_model, load_ca_certificates, system_changed, gate); }); } + if (control_protocol_enabled) + { + auto& control_protocol_ws_listener = node_server.ws_listeners.at(control_protocol_ws_pos); + auto& control_protocol_ws_api = node_server.ws_handlers.at({ {}, control_protocol_ws_port }); + node_server.thread_functions.push_back([&] { nmos::send_control_protocol_ws_messages_thread(control_protocol_ws_listener, node_model, control_protocol_ws_api.second, gate); }); + } + return node_server; } diff --git a/Development/nmos/settings.h b/Development/nmos/settings.h index e5e46ed0f..467c7c0e2 100644 --- a/Development/nmos/settings.h +++ b/Development/nmos/settings.h @@ -142,6 +142,7 @@ namespace nmos const web::json::field_as_integer_or channelmapping_port{ U("channelmapping_port"), 3215 }; // system_port [node]: used to construct request URLs for the System API (if not discovered via DNS-SD) const web::json::field_as_integer_or system_port{ U("system_port"), 10641 }; + // control_protocol_ws_port [node]: used to construct request URLs for the Control Protocol websocket, or negative to disable the control protocol features const web::json::field_as_integer_or control_protocol_ws_port{ U("control_protocol_ws_port"), 3218 }; // listen_backlog [registry, node]: the maximum length of the queue of pending connections, or zero for the implementation default (the implementation may not honour this value) From 52dc55a420fb09ad5e7c9f6bb61f6c0e843de6b0 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Sun, 20 Aug 2023 00:31:56 +0100 Subject: [PATCH 026/106] Remove unused code --- Development/nmos/control_protocol_ws_api.cpp | 730 +------------------ 1 file changed, 1 insertion(+), 729 deletions(-) diff --git a/Development/nmos/control_protocol_ws_api.cpp b/Development/nmos/control_protocol_ws_api.cpp index 8e5f31752..cb1857d7d 100644 --- a/Development/nmos/control_protocol_ws_api.cpp +++ b/Development/nmos/control_protocol_ws_api.cpp @@ -72,7 +72,7 @@ namespace nmos } return value::null(); - }; + } // hmm, change method_id to struct, and bring in method handlers via the control_classes nmos::experimental::method find_method(const web::json::value& method_id, const nc_class_id& class_id_, const nmos::experimental::control_classes& control_classes) @@ -636,734 +636,6 @@ namespace nmos return NULL; } - - /* - std::pair create_properties_methods(nmos::node_model& model, const nc_class_id& class_id_, const nmos::experimental::control_classes& control_classes) - { - using web::json::value; - using web::json::value_of; - - // hmm, methods should also be passing in via the control_class::methods - - // NcObject methods implementation - // Get property value - const auto get = [&model](int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) - { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - - auto& resources = model.control_protocol_resources; - auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); - if (resources.end() != resource) - { - // where arguments is the property id = (level, index) - const auto& property_id = nmos::fields::nc::id(arguments); - - // find the relevant nc_property_descriptor - const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); - if (!property.is_null()) - { - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, resource->data.at(nmos::fields::nc::name(property))); - } - - // unknown property - utility::stringstream_t ss; - ss << U("unknown property: ") << property_id.serialize() << U(" to do Get"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); - } - - // resource not found for the given oid - utility::stringstream_t ss; - ss << U("unknown oid: ") << oid << U(" to do Get"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); - }; - // Set property value - const auto set = [&model](int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) - { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - - auto& resources = model.control_protocol_resources; - auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); - if (resources.end() != resource) - { - const auto& property_id = nmos::fields::nc::id(arguments); - const auto& val = nmos::fields::nc::value(arguments); - - // find the relevant nc_property_descriptor - const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); - if (!property.is_null()) - { - if (nmos::fields::nc::is_read_only(property)) - { - return details::make_control_protocol_response(handle, { details::nc_method_status::read_only }); - } - - if ((val.is_null() && !nmos::fields::nc::is_nullable(property)) - || (val.is_array() && !nmos::fields::nc::is_sequence(property))) - { - return details::make_control_protocol_response(handle, { details::nc_method_status::parameter_error }); - } - - resources.modify(resource, [&](nmos::resource& resource) - { - resource.data[nmos::fields::nc::name(property)] = val; - - resource.updated = strictly_increasing_update(resources); - }); - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }); - } - - // unknown property - utility::stringstream_t ss; - ss << U("unknown property: ") << property_id.serialize() << " to do Set"; - return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); - } - - // resource not found for the given oid - utility::stringstream_t ss; - ss << U("unknown oid: ") << oid << " to do Set"; - return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); - }; - // Get sequence item - const auto get_sequence_item = [&model](int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) - { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - - auto& resources = model.control_protocol_resources; - auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); - if (resources.end() != resource) - { - const auto& property_id = nmos::fields::nc::id(arguments); - const auto& index = nmos::fields::nc::index(arguments); - - // find the relevant nc_property_descriptor - const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); - if (!property.is_null()) - { - if (!nmos::fields::nc::is_sequence(property)) - { - // property is not a sequence - utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do GetSequenceItem"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); - } - - auto& data = resource->data.at(nmos::fields::nc::name(property)); - - if (!data.is_null() && data.as_array().size() > (size_t)index) - { - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, data.at(index)); - } - - // out of bound - utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << U(" is outside the available range to do GetSequenceItem"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::index_out_of_bounds }, ss.str()); - } - - // unknown property - utility::stringstream_t ss; - ss << U("unknown property: ") << property_id.serialize() << U(" to do GetSequenceItem"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); - } - - // resource not found for the given oid - utility::stringstream_t ss; - ss << U("unknown oid: ") << oid << U(" to do GetSequenceItem"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); - }; - // Set sequence item - const auto set_sequence_item = [&model](int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) - { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - - auto& resources = model.control_protocol_resources; - auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); - if (resources.end() != resource) - { - const auto& property_id = nmos::fields::nc::id(arguments); - const auto& index = nmos::fields::nc::index(arguments); - const auto& val = nmos::fields::nc::value(arguments); - - // find the relevant nc_property_descriptor - const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); - if (!property.is_null()) - { - if (!nmos::fields::nc::is_sequence(property)) - { - // property is not a sequence - utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do SetSequenceItem"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); - } - - auto& data = resource->data.at(nmos::fields::nc::name(property)); - - if (!data.is_null() && data.as_array().size() > (size_t)index) - { - resources.modify(resource, [&](nmos::resource& resource) - { - resource.data[nmos::fields::nc::name(property)][index] = val; - - resource.updated = strictly_increasing_update(resources); - }); - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }); - } - - // out of bound - utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << U(" is outside the available range to do SetSequenceItem"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::index_out_of_bounds }, ss.str()); - } - - // unknown property - utility::stringstream_t ss; - ss << U("unknown property: ") << property_id.serialize() << U(" to do SetSequenceItem"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); - } - - // resource not found for the given oid - utility::stringstream_t ss; - ss << U("unknown oid: ") << oid << U(" to do SetSequenceItem"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); - }; - // Add item to sequence - const auto add_sequence_item = [&model](int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) - { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - - auto& resources = model.control_protocol_resources; - auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); - if (resources.end() != resource) - { - const auto& property_id = nmos::fields::nc::id(arguments); - const auto& val = nmos::fields::nc::value(arguments); - - // find the relevant nc_property_descriptor - const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); - if (!property.is_null()) - { - if (!nmos::fields::nc::is_sequence(property)) - { - // property is not a sequence - utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do AddSequenceItem"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); - } - - auto& data = resource->data.at(nmos::fields::nc::name(property)); - - resources.modify(resource, [&](nmos::resource& resource) - { - auto& sequence = resource.data[nmos::fields::nc::name(property)]; - if (data.is_null()) { sequence = value::array(); } - web::json::push_back(sequence, val); - - resource.updated = strictly_increasing_update(resources); - }); - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, uint32_t(data.as_array().size() - 1)); - } - - // unknown property - utility::stringstream_t ss; - ss << U("unknown property: ") << property_id.serialize() << U(" to do AddSequenceItem"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); - } - - // resource not found for the given oid - utility::stringstream_t ss; - ss << U("unknown oid: ") << oid << U(" to do AddSequenceItem"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); - }; - // Delete sequence item - const auto remove_sequence_item = [&model](int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) - { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - - auto& resources = model.control_protocol_resources; - auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); - if (resources.end() != resource) - { - const auto& property_id = nmos::fields::nc::id(arguments); - const auto& index = nmos::fields::nc::index(arguments); - - // find the relevant nc_property_descriptor - const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); - if (!property.is_null()) - { - if (!nmos::fields::nc::is_sequence(property)) - { - // property is not a sequence - utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do RemoveSequenceItem"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); - } - - auto& data = resource->data.at(nmos::fields::nc::name(property)); - - if (!data.is_null() && data.as_array().size() > (size_t)index) - { - resources.modify(resource, [&](nmos::resource& resource) - { - auto& sequence = resource.data[nmos::fields::nc::name(property)].as_array(); - sequence.erase(index); - - resource.updated = strictly_increasing_update(resources); - }); - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }); - } - - // out of bound - utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << U(" is outside the available range to do RemoveSequenceItem"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::index_out_of_bounds }, ss.str()); - } - - // unknown property - utility::stringstream_t ss; - ss << U("unknown property: ") << property_id.serialize() << U(" to do RemoveSequenceItem"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); - } - - // resource not found for the given oid - utility::stringstream_t ss; - ss << U("unknown oid: ") << oid << U(" to do RemoveSequenceItem"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); - }; - // Get sequence length - const auto get_sequence_length = [&model](int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) - { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - - auto& resources = model.control_protocol_resources; - auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); - if (resources.end() != resource) - { - const auto& property_id = nmos::fields::nc::id(arguments); - - // find the relevant nc_property_descriptor - const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); - if (!property.is_null()) - { - if (!nmos::fields::nc::is_sequence(property)) - { - // property is not a sequence - utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do GetSequenceLength"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); - } - - auto& data = resource->data.at(nmos::fields::nc::name(property)); - - if (nmos::fields::nc::is_nullable(property)) - { - // can be null - if (data.is_null()) - { - // null - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, value::null()); - } - } - else - { - // cannot be null - if (data.is_null()) - { - // null - utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << " is a null sequence to do GetSequenceLength"; - return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); - } - } - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, uint32_t(data.as_array().size())); - } - - // unknown property - utility::stringstream_t ss; - ss << U("unknown property: ") << property_id.serialize() << " to do GetSequenceLength"; - return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); - } - - // resource not found for the given oid - utility::stringstream_t ss; - ss << U("unknown oid: ") << oid << " to do GetSequenceLength"; - return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); - }; - - // NcBlock methods implementation - // Gets descriptors of members of the block - const auto get_member_descriptors = [&model](int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) - { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - - auto& resources = model.control_protocol_resources; - auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); - if (resources.end() != resource) - { - const auto& recurse = nmos::fields::nc::recurse(arguments); // If recurse is set to true, nested members is to be retrieved - - auto descriptors = value::array(); - nmos::get_member_descriptors(resources, nmos::find_resource(resources, utility::s2us(std::to_string(oid))), recurse, descriptors.as_array()); - - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, descriptors); - } - - // resource not found for the given oid - utility::stringstream_t ss; - ss << U("unknown oid: ") << oid << U(" to do GetMemberDescriptors"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); - }; - // Finds member(s) by path - const auto find_members_by_path = [&model](int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) - { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - - auto& resources = model.control_protocol_resources; - auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); - if (resources.end() != resource) - { - // Relative path to search for (MUST not include the role of the block targeted by oid) - const auto& path = nmos::fields::nc::path(arguments); - - if (0 == path.size()) - { - // empty path - return details::make_control_protocol_error_response(handle, { details::nc_method_status::parameter_error }, U("empty path to do FindMembersByPath")); - } - - auto nc_block_member_descriptors = value::array(); - - for (const auto& role : path) - { - // look for the role in members - if (resource->data.has_field(nmos::fields::nc::members)) - { - auto& members = nmos::fields::nc::members(resource->data); - auto member_found = std::find_if(members.begin(), members.end(), [&](const web::json::value& nc_block_member_descriptor) - { - return role.as_string() == nmos::fields::nc::role(nc_block_member_descriptor); - }); - - if (members.end() != member_found) - { - web::json::push_back(nc_block_member_descriptors, *member_found); - - // use oid to look for the next resource - resource = nmos::find_resource(resources, utility::s2us(std::to_string(nmos::fields::nc::oid(*member_found)))); - } - else - { - // no role - utility::stringstream_t ss; - ss << U("role: ") << role.as_string() << U(" not found to do FindMembersByPath"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); - } - } - else - { - // no members - return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, U("no members to do FindMembersByPath")); - } - } - - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, nc_block_member_descriptors); - } - - // resource not found for the given oid - utility::stringstream_t ss; - ss << U("unknown oid: ") << oid << " to do FindMembersByPath"; - return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); - }; - // Finds members with given role name or fragment - const auto find_members_by_role = [&model](int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) - { - const auto& role = nmos::fields::nc::role(arguments); // Role text to search for - const auto& case_sensitive = nmos::fields::nc::case_sensitive(arguments); // Signals if the comparison should be case sensitive - const auto& match_whole_string = nmos::fields::nc::match_whole_string(arguments); // TRUE to only return exact matches - const auto& recurse = nmos::fields::nc::recurse(arguments); // TRUE to search nested blocks - - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - - auto& resources = model.control_protocol_resources; - - auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); - if (resources.end() != resource) - { - if (role.empty()) - { - // empty role - return details::make_control_protocol_error_response(handle, { details::nc_method_status::parameter_error }, U("empty role to do FindMembersByRole")); - } - - auto descriptors = value::array(); - nmos::find_members_by_role(resources, nmos::find_resource(resources, utility::s2us(std::to_string(oid))), role, match_whole_string, case_sensitive, recurse, descriptors.as_array()); - - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, descriptors); - } - - // resource not found for the given oid - utility::stringstream_t ss; - ss << U("unknown oid: ") << oid << U(" to do FindMembersByRole"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); - }; - // Finds members with given class id - const auto find_members_by_class_id = [&model](int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) - { - const auto& class_id = details::parse_nc_class_id(nmos::fields::nc::class_id(arguments)); // Class id to search for - const auto& include_derived = nmos::fields::nc::include_derived(arguments); // If TRUE it will also include derived class descriptors - const auto& recurse = nmos::fields::nc::recurse(arguments); // TRUE to search nested blocks - - if (class_id.empty()) - { - // empty class_id - return details::make_control_protocol_error_response(handle, { details::nc_method_status::parameter_error }, U("empty classId to do FindMembersByClassId")); - } - - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - - auto& resources = model.control_protocol_resources; - - auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); - if (resources.end() != resource) - { - auto descriptors = value::array(); - nmos::find_members_by_class_id(resources, nmos::find_resource(resources, utility::s2us(std::to_string(oid))), class_id, include_derived, recurse, descriptors.as_array()); - - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, descriptors); - } - - // resource not found for the given oid - utility::stringstream_t ss; - ss << U("unknown oid: ") << oid << U(" to do FindMembersByClassId"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); - }; - - // NcClassManager methods implementation - // Get a single class descriptor - const auto get_control_class = [&model](int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) - { - const auto& class_id = details::parse_nc_class_id(nmos::fields::nc::class_id(arguments)); // Class id to search for - const auto& include_inherited = nmos::fields::nc::include_inherited(arguments); // If set the descriptor would contain all inherited elements - - if (class_id.empty()) - { - // empty class_id - return details::make_control_protocol_error_response(handle, { details::nc_method_status::parameter_error }, U("empty classId to do GetControlClass")); - } - - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - - auto& resources = model.control_protocol_resources; - - auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); - if (resources.end() != resource) - { - auto class_found = control_classes.find(make_nc_class_id(class_id)); - - if (control_classes.end() != class_found) - { - auto id = class_id; - - auto description = class_found->second.description; - auto name = class_found->second.name; - auto fixed_role = class_found->second.fixed_role; - auto properties = class_found->second.properties; - auto methods = class_found->second.methods; - auto events = class_found->second.events; - - id.pop_back(); - - if (include_inherited) - { - while (!id.empty()) - { - auto found = control_classes.find(make_nc_class_id(id)); - if (control_classes.end() != found) - { - for (const auto& property : found->second.properties.as_array()) { web::json::push_back(properties, property); } - for (const auto& method : found->second.methods.as_array()) { web::json::push_back(methods, method); } - for (const auto& event : found->second.events.as_array()) { web::json::push_back(events, event); } - } - id.pop_back(); - } - } - auto descriptor = details::make_nc_class_descriptor(description, class_id, name, fixed_role, properties, methods, events); - - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, descriptor); - } - - return details::make_control_protocol_error_response(handle, { details::nc_method_status::parameter_error }, U("classId not found")); - } - - // resource not found for the given oid - utility::stringstream_t ss; - ss << U("unknown oid: ") << oid << U(" to do GetControlClass"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); - }; - // Get a single datatype descriptor - const auto get_datatype = [&model](int32_t handle, int32_t oid, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) - { - const auto& name = nmos::fields::nc::name(arguments); // name of datatype - const auto& include_inherited = nmos::fields::nc::include_inherited(arguments); // If set the descriptor would contain all inherited elements - - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - - auto& resources = model.control_protocol_resources; - - auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); - if (resources.end() != resource) - { - if (name.empty()) - { - // empty name - return details::make_control_protocol_error_response(handle, { details::nc_method_status::parameter_error }, U("empty name to do GetDatatype")); - } - - auto datatype_found = datatypes.find(name); - - if (datatypes.end() != datatype_found) - { - auto descriptor = datatype_found->second.descriptor; - - if (include_inherited) - { - const auto& type = nmos::fields::nc::type(descriptor); - if(details::nc_datatype_type::Struct == type) - { - auto descriptor_ = descriptor; - - for (;;) - { - const auto& parent_type = descriptor_.at(nmos::fields::nc::parent_type); - if (!parent_type.is_null()) - { - auto datatype_found_ = datatypes.find(parent_type.as_string()); - if (datatypes.end() != datatype_found_) - { - descriptor_ = datatype_found_->second.descriptor; - const auto& fields = nmos::fields::nc::fields(descriptor_); - for (const auto& field : fields) - { - web::json::push_back(descriptor.at(nmos::fields::nc::fields), field); - } - } - } - else - { - break; - } - } - } - } - - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, descriptor); - } - - return details::make_control_protocol_error_response(handle, { details::nc_method_status::parameter_error }, U("name not found")); - } - - // resource not found for the given oid - utility::stringstream_t ss; - ss << U("unknown oid: ") << oid << U(" to do GetDatatype"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); - }; - - // method handlers for the different classes - details::methods nc_object_method_handlers; // method_id vs NcObject method_handler - details::methods nc_block_method_handlers; // method_id vs NcBlock method_handler - details::methods nc_worker_method_handlers; // method_id vs NcWorker method_handler - details::methods nc_manager_method_handlers; // method_id vs NcManager method_handler - details::methods nc_device_manager_method_handlers; // method_id vs NcDeviceManager method_handler - details::methods nc_class_manager_method_handlers; // method_id vs NcClassManager method_handler - - // NcObject methods - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject - nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 1 } })] = get; - nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 2 } })] = set; - nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 3 } })] = get_sequence_item; - nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 4 } })] = set_sequence_item; - nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 5 } })] = add_sequence_item; - nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 6 } })] = remove_sequence_item; - nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 7 } })] = get_sequence_length; - - // NcBlock methods - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock - nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 1 } })] = get_member_descriptors; - nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 2 } })] = find_members_by_path; - nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 3 } })] = find_members_by_role; - nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 4 } })] = find_members_by_class_id; - - // NcWorker has no extended method - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncworker - - // NcManager has no extended method - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanager - - // NcDeviceManger has no extended method - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager - - // NcClassManager methods - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager - nc_class_manager_method_handlers[value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 1 } })] = get_control_class; - nc_class_manager_method_handlers[value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 2 } })] = get_datatype; - - value properties = value::array(); // combined base classes nc_property_descriptor(s) for the required class_id - details::methods methods; // list of combined base classes method handlers - - auto class_found = control_classes.find(make_nc_class_id(class_id_)); - if (control_classes.end() != class_found) - { - // hmm, update the array of properties, will be updated the list of method handlers - auto insert_properties = [&properties, &control_classes](const nc_class_id& class_id_) - { - auto class_id = make_nc_class_id(class_id_); - auto class_id_found = control_classes.find(class_id); - if (control_classes.end() != class_id_found) - { - auto& nc_class_properties = class_id_found->second.properties.as_array(); - for (auto& nc_class_property : nc_class_properties) - { - web::json::push_back(properties, nc_class_property); - } - } - }; - - auto class_id = class_id_; - while (class_id.size()) - { - insert_properties(class_id); - - // hmm, to be deleted, once the methods are passed in - if (details::nc_object_class_id == class_id) - { - methods.insert(nc_object_method_handlers.begin(), nc_object_method_handlers.end()); - } - else if (details::nc_block_class_id == class_id) - { - methods.insert(nc_block_method_handlers.begin(), nc_block_method_handlers.end()); - } - else if (details::nc_manager_class_id == class_id) - { - methods.insert(nc_manager_method_handlers.begin(), nc_manager_method_handlers.end()); - } - else if (details::nc_device_manager_class_id == class_id) - { - methods.insert(nc_device_manager_method_handlers.begin(), nc_device_manager_method_handlers.end()); - } - else if (details::nc_class_manager_class_id == class_id) - { - methods.insert(nc_class_manager_method_handlers.begin(), nc_class_manager_method_handlers.end()); - } - class_id.pop_back(); - } - } - else - { - throw std::runtime_error("unknown control class"); - } - - return { properties, methods }; - } - */ } // IS-12 Control Protocol WebSocket API From 3924c6b967342e0b3f8ebe0e122d8bfef117ad79 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 22 Aug 2023 18:16:38 +0100 Subject: [PATCH 027/106] Fix find_members_by_path and write log on method --- Development/nmos/control_protocol_ws_api.cpp | 77 ++++++++++++++------ 1 file changed, 53 insertions(+), 24 deletions(-) diff --git a/Development/nmos/control_protocol_ws_api.cpp b/Development/nmos/control_protocol_ws_api.cpp index cb1857d7d..595c918b9 100644 --- a/Development/nmos/control_protocol_ws_api.cpp +++ b/Development/nmos/control_protocol_ws_api.cpp @@ -82,13 +82,14 @@ namespace nmos // NcObject methods implementation // Get property value - const auto get = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + const auto get = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes&, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - // where arguments is the property id = (level, index) const auto& property_id = nmos::fields::nc::id(arguments); + slog::log(gate, SLOG_FLF) << "Get property: " << property_id.to_string(); + // find the relevant nc_property_descriptor const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); if (!property.is_null()) @@ -102,13 +103,15 @@ namespace nmos return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); }; // Set property value - const auto set = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + const auto set = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes&, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... const auto& property_id = nmos::fields::nc::id(arguments); const auto& val = nmos::fields::nc::value(arguments); + slog::log(gate, SLOG_FLF) << "Set property: " << property_id.to_string() << " value: " << val.to_string(); + // find the relevant nc_property_descriptor const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); if (!property.is_null()) @@ -139,13 +142,15 @@ namespace nmos return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); }; // Get sequence item - const auto get_sequence_item = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + const auto get_sequence_item = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes&, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... const auto& property_id = nmos::fields::nc::id(arguments); const auto& index = nmos::fields::nc::index(arguments); + slog::log(gate, SLOG_FLF) << "Get sequence item: " << property_id.to_string() << " index: " << index; + // find the relevant nc_property_descriptor const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); if (!property.is_null()) @@ -177,7 +182,7 @@ namespace nmos return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); }; // Set sequence item - const auto set_sequence_item = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + const auto set_sequence_item = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes&, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -185,6 +190,8 @@ namespace nmos const auto& index = nmos::fields::nc::index(arguments); const auto& val = nmos::fields::nc::value(arguments); + slog::log(gate, SLOG_FLF) << "Set sequence item: " << property_id.to_string() << " index: " << index << " value: " << val.to_string(); + // find the relevant nc_property_descriptor const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); if (!property.is_null()) @@ -222,13 +229,15 @@ namespace nmos return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); }; // Add item to sequence - const auto add_sequence_item = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + const auto add_sequence_item = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes&, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... const auto& property_id = nmos::fields::nc::id(arguments); const auto& val = nmos::fields::nc::value(arguments); + slog::log(gate, SLOG_FLF) << "Add sequence item: " << property_id.to_string() << " value: " << val.to_string(); + // find the relevant nc_property_descriptor const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); if (!property.is_null()) @@ -260,13 +269,15 @@ namespace nmos return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); }; // Delete sequence item - const auto remove_sequence_item = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + const auto remove_sequence_item = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes&, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... const auto& property_id = nmos::fields::nc::id(arguments); const auto& index = nmos::fields::nc::index(arguments); + slog::log(gate, SLOG_FLF) << "Remove sequence item: " << property_id.to_string() << " index: " << index; + // find the relevant nc_property_descriptor const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); if (!property.is_null()) @@ -305,12 +316,14 @@ namespace nmos return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); }; // Get sequence length - const auto get_sequence_length = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + const auto get_sequence_length = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes&, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... const auto& property_id = nmos::fields::nc::id(arguments); + slog::log(gate, SLOG_FLF) << "Get sequence length: " << property_id.to_string(); + // find the relevant nc_property_descriptor const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); if (!property.is_null()) @@ -355,25 +368,29 @@ namespace nmos }; // NcBlock methods implementation - // Gets descriptors of members of the block - const auto get_member_descriptors = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + // Get descriptors of members of the block + const auto get_member_descriptors = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes&, const nmos::experimental::datatypes&, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... const auto& recurse = nmos::fields::nc::recurse(arguments); // If recurse is set to true, nested members is to be retrieved + slog::log(gate, SLOG_FLF) << "Get descriptors of members of the block: " << "recurse: " << recurse; + auto descriptors = value::array(); nmos::get_member_descriptors(resources, resource, recurse, descriptors.as_array()); return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, descriptors); }; // Finds member(s) by path - const auto find_members_by_path = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + const auto find_members_by_path = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes&, const nmos::experimental::datatypes&, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... // Relative path to search for (MUST not include the role of the block targeted by oid) - const auto& path = nmos::fields::nc::path(arguments); + const auto& path = arguments.at(nmos::fields::nc::path); + + slog::log(gate, SLOG_FLF) << "Find member(s) by path: " << "path: " << path.to_string(); if (0 == path.size()) { @@ -382,21 +399,22 @@ namespace nmos } auto nc_block_member_descriptors = value::array(); + value nc_block_member_descriptor; - for (const auto& role : path) + for (const auto& role : path.as_array()) { // look for the role in members if (resource->data.has_field(nmos::fields::nc::members)) { auto& members = nmos::fields::nc::members(resource->data); auto member_found = std::find_if(members.begin(), members.end(), [&](const web::json::value& nc_block_member_descriptor) - { - return role.as_string() == nmos::fields::nc::role(nc_block_member_descriptor); - }); + { + return role.as_string() == nmos::fields::nc::role(nc_block_member_descriptor); + }); if (members.end() != member_found) { - web::json::push_back(nc_block_member_descriptors, *member_found); + nc_block_member_descriptor = *member_found; // use oid to look for the next resource resource = nmos::find_resource(resources, utility::s2us(std::to_string(nmos::fields::nc::oid(*member_found)))); @@ -416,17 +434,20 @@ namespace nmos } } + web::json::push_back(nc_block_member_descriptors, nc_block_member_descriptor); return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, nc_block_member_descriptors); }; // Finds members with given role name or fragment - const auto find_members_by_role = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + const auto find_members_by_role = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes&, const nmos::experimental::datatypes&, slog::base_gate& gate) { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + const auto& role = nmos::fields::nc::role(arguments); // Role text to search for const auto& case_sensitive = nmos::fields::nc::case_sensitive(arguments); // Signals if the comparison should be case sensitive const auto& match_whole_string = nmos::fields::nc::match_whole_string(arguments); // TRUE to only return exact matches const auto& recurse = nmos::fields::nc::recurse(arguments); // TRUE to search nested blocks - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + slog::log(gate, SLOG_FLF) << "Find members with given role name or fragment: " << "role: " << role; if (role.empty()) { @@ -440,12 +461,16 @@ namespace nmos return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, descriptors); }; // Finds members with given class id - const auto find_members_by_class_id = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + const auto find_members_by_class_id = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes&, const nmos::experimental::datatypes&, slog::base_gate& gate) { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + const auto& class_id = details::parse_nc_class_id(nmos::fields::nc::class_id(arguments)); // Class id to search for const auto& include_derived = nmos::fields::nc::include_derived(arguments); // If TRUE it will also include derived class descriptors const auto& recurse = nmos::fields::nc::recurse(arguments); // TRUE to search nested blocks + slog::log(gate, SLOG_FLF) << "Find members with given class id: " << "class_id: " << details::make_nc_class_id(class_id).to_string(); + if (class_id.empty()) { // empty class_id @@ -462,11 +487,13 @@ namespace nmos // NcClassManager methods implementation // Get a single class descriptor - const auto get_control_class = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + const auto get_control_class = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes&, slog::base_gate& gate) { const auto& class_id = details::parse_nc_class_id(nmos::fields::nc::class_id(arguments)); // Class id to search for const auto& include_inherited = nmos::fields::nc::include_inherited(arguments); // If set the descriptor would contain all inherited elements + slog::log(gate, SLOG_FLF) << "Get a single class descriptor: " << "class_id: " << details::make_nc_class_id(class_id).to_string(); + if (class_id.empty()) { // empty class_id @@ -512,12 +539,14 @@ namespace nmos return details::make_control_protocol_error_response(handle, { details::nc_method_status::parameter_error }, U("classId not found")); }; // Get a single datatype descriptor - const auto get_datatype = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes& datatypes) + const auto get_datatype = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes&, const nmos::experimental::datatypes& datatypes, slog::base_gate& gate) { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + const auto& name = nmos::fields::nc::name(arguments); // name of datatype const auto& include_inherited = nmos::fields::nc::include_inherited(arguments); // If set the descriptor would contain all inherited elements - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + slog::log(gate, SLOG_FLF) << "Get a single datatype descriptor: " << "name: " << name; if (name.empty()) { @@ -844,7 +873,7 @@ namespace nmos if (method) { // execute the relevant method handler, then accumulating up their response to reponses - web::json::push_back(responses, method(resources, resource, handle, arguments, get_control_protocol_classes(), get_control_protocol_datatypes())); + web::json::push_back(responses, method(resources, resource, handle, arguments, get_control_protocol_classes(), get_control_protocol_datatypes(), gate)); } else { From 91457529523082fc20d3887aa31de274f9ddfeba Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 22 Aug 2023 18:17:24 +0100 Subject: [PATCH 028/106] Remove un-used code --- .../nmos/control_protocol_handlers.cpp | 29 ++----------------- Development/nmos/control_protocol_handlers.h | 7 ----- 2 files changed, 3 insertions(+), 33 deletions(-) diff --git a/Development/nmos/control_protocol_handlers.cpp b/Development/nmos/control_protocol_handlers.cpp index 609053ea4..5e52f0700 100644 --- a/Development/nmos/control_protocol_handlers.cpp +++ b/Development/nmos/control_protocol_handlers.cpp @@ -8,7 +8,7 @@ namespace nmos { return [&]() { - slog::log(gate, SLOG_FLF) << "Retrieve all control classes from cache"; + slog::log(gate, SLOG_FLF) << "Retrieve all control classes from cache"; auto lock = control_protocol_state.read_lock(); @@ -16,34 +16,11 @@ namespace nmos }; } - //get_control_protocol_class_handler make_get_control_protocol_class_handler(nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate) - //{ - // return [&](const details::nc_class_id& class_id) - // { - // using web::json::value; - - // slog::log(gate, SLOG_FLF) << "Retrieve control class from cache"; - - // auto lock = control_protocol_state.read_lock(); - - // auto class_id_data = details::make_nc_class_id(class_id); - - // auto& control_classes = control_protocol_state.control_classes; - // auto found = control_classes.find(class_id_data); - // if (control_classes.end() != found) - // { - // return found->second; - // } - - // return experimental::control_class{ value::array(), value::array(), value::array() }; - // }; - //} - add_control_protocol_class_handler make_add_control_protocol_class_handler(nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate) { return [&](const details::nc_class_id& class_id, const experimental::control_class& control_class) { - slog::log(gate, SLOG_FLF) << "Add control class to cache"; + slog::log(gate, SLOG_FLF) << "Add control class to cache"; auto lock = control_protocol_state.write_lock(); @@ -64,7 +41,7 @@ namespace nmos { return [&]() { - slog::log(gate, SLOG_FLF) << "Retrieve all datatypes from cache"; + slog::log(gate, SLOG_FLF) << "Retrieve all datatypes from cache"; auto lock = control_protocol_state.read_lock(); diff --git a/Development/nmos/control_protocol_handlers.h b/Development/nmos/control_protocol_handlers.h index d0af0c30e..565bf6c26 100644 --- a/Development/nmos/control_protocol_handlers.h +++ b/Development/nmos/control_protocol_handlers.h @@ -21,10 +21,6 @@ namespace nmos // this callback should not throw exceptions typedef std::function get_control_protocol_classes_handler; - // callback to retrieve a specific control protocol class - // this callback should not throw exceptions -// typedef std::function get_control_protocol_class_handler; - // callback to add user control protocol class // this callback should not throw exceptions typedef std::function add_control_protocol_class_handler; @@ -36,9 +32,6 @@ namespace nmos // construct callback to retrieve all control protocol classes get_control_protocol_classes_handler make_get_control_protocol_classes_handler(nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate); - // construct callback to retrieve control protocol class -// get_control_protocol_class_handler make_get_control_protocol_class_handler(nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate); - // construct callback to add control protocol class add_control_protocol_class_handler make_add_control_protocol_class_handler(nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate); From 0ef34d0a57c75a8b1105d7a622fbf9cea277e374 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 22 Aug 2023 18:18:40 +0100 Subject: [PATCH 029/106] Add Log gate to method --- Development/nmos/control_protocol_state.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Development/nmos/control_protocol_state.h b/Development/nmos/control_protocol_state.h index c15e2fd65..82f4e755f 100644 --- a/Development/nmos/control_protocol_state.h +++ b/Development/nmos/control_protocol_state.h @@ -7,6 +7,8 @@ #include "nmos/mutex.h" #include "nmos/resources.h" +namespace slog { class base_gate; } + namespace nmos { namespace experimental @@ -34,7 +36,7 @@ namespace nmos typedef std::map datatypes; // methods defnitions - typedef std::function method; + typedef std::function method; typedef std::map methods; // method_id vs method handler struct control_protocol_state From dba104202c3f1c2a7378e1d79d91adc9aa0fd4ed Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 22 Aug 2023 18:20:38 +0100 Subject: [PATCH 030/106] Move nc_class_id definition from control_protocol_resource to control_protocol_utils --- Development/nmos/control_protocol_utils.cpp | 8 ++++++++ Development/nmos/control_protocol_utils.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/Development/nmos/control_protocol_utils.cpp b/Development/nmos/control_protocol_utils.cpp index 106a55a7d..a19f58699 100644 --- a/Development/nmos/control_protocol_utils.cpp +++ b/Development/nmos/control_protocol_utils.cpp @@ -42,6 +42,14 @@ namespace nmos { return is_control_class(nc_class_manager_class_id, class_id); } + + nc_class_id make_nc_class_id(const nc_class_id& prefix, int32_t authority_key, const nc_class_id& suffix) + { + nc_class_id class_id = prefix; + class_id.push_back(authority_key); + class_id.insert(class_id.end(), suffix.begin(), suffix.end()); + return class_id; + } } void get_member_descriptors(const resources& resources, resources::iterator resource, bool recurse, web::json::array& descriptors) diff --git a/Development/nmos/control_protocol_utils.h b/Development/nmos/control_protocol_utils.h index b90f63574..ec59aa747 100644 --- a/Development/nmos/control_protocol_utils.h +++ b/Development/nmos/control_protocol_utils.h @@ -16,6 +16,8 @@ namespace nmos bool is_nc_device_manager(const nc_class_id& class_id); bool is_nc_class_manager(const nc_class_id& class_id); + + nc_class_id make_nc_class_id(const nc_class_id& prefix, int32_t authority_key, const nc_class_id& suffix); } void get_member_descriptors(const resources& resources, resources::iterator resource, bool recurse, web::json::array& descriptors); From 38077d253a9b4dda0342fc69567f3b3bcdfaaeeb Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 22 Aug 2023 18:21:37 +0100 Subject: [PATCH 031/106] Add nested block examples --- .../nmos-cpp-node/node_implementation.cpp | 72 +++++++++++++++++-- .../nmos-cpp-node/node_implementation.h | 2 +- .../nmos/control_protocol_resource.cpp | 13 +++- Development/nmos/control_protocol_resource.h | 43 +++++------ .../nmos/control_protocol_resources.cpp | 36 ++++++++-- Development/nmos/control_protocol_resources.h | 10 +++ 6 files changed, 142 insertions(+), 34 deletions(-) diff --git a/Development/nmos-cpp-node/node_implementation.cpp b/Development/nmos-cpp-node/node_implementation.cpp index 2d4774f13..6d771ae12 100644 --- a/Development/nmos-cpp-node/node_implementation.cpp +++ b/Development/nmos-cpp-node/node_implementation.cpp @@ -23,6 +23,7 @@ #include "nmos/connection_events_activation.h" #include "nmos/control_protocol_resources.h" #include "nmos/control_protocol_state.h" +#include "nmos/control_protocol_utils.h" #include "nmos/events_resources.h" #include "nmos/format.h" #include "nmos/group_hint.h" @@ -46,6 +47,10 @@ #include "nmos/video_jxsv.h" #include "sdp/sdp.h" +// hmm, for IS-12 gain control +#include "nmos/resource.h" +#include "nmos/is12_versions.h" + // example node implementation details namespace impl { @@ -188,7 +193,7 @@ namespace impl } // forward declarations for node_implementation_thread -void node_implementation_init(nmos::node_model& model, const nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate); +void node_implementation_init(nmos::node_model& model, nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate); void node_implementation_run(nmos::node_model& model, slog::base_gate& gate); nmos::connection_resource_auto_resolver make_node_implementation_auto_resolver(const nmos::settings& settings); nmos::connection_sender_transportfile_setter make_node_implementation_transportfile_setter(const nmos::resources& node_resources, const nmos::settings& settings); @@ -198,7 +203,7 @@ struct node_implementation_init_exception {}; // This is an example of how to integrate the nmos-cpp library with a device-specific underlying implementation. // It constructs and inserts a node resource and some sub-resources into the model, based on the model settings, // starts background tasks to emit regular events from the temperature event source, and then waits for shutdown. -void node_implementation_thread(nmos::node_model& model, const nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate_) +void node_implementation_thread(nmos::node_model& model, nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate_) { nmos::details::omanip_gate gate{ gate_, nmos::stash_category(impl::categories::node_implementation) }; @@ -234,7 +239,7 @@ void node_implementation_thread(nmos::node_model& model, const nmos::experimenta } } -void node_implementation_init(nmos::node_model& model, const nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate) +void node_implementation_init(nmos::node_model& model, nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate) { using web::json::value; using web::json::value_from_elements; @@ -897,17 +902,70 @@ void node_implementation_init(nmos::node_model& model, const nmos::experimental: if (!insert_resource_after(delay_millis, model.channelmapping_resources, std::move(channelmapping_output), gate)) throw node_implementation_init_exception(); } + // example of using control protocol if (0 <= nmos::fields::control_protocol_ws_port(model.settings)) { + // example to create a custom Gain control class + const auto gain_control_class_id = nmos::details::make_nc_class_id(nmos::details::nc_worker_class_id, 0, { 1 }); + const web::json::field_as_number gain_value{ U("gainValue") }; + auto make_gain_control_properties = [&gain_value]() + { + auto properties = value::array(); + web::json::push_back(properties, nmos::details::make_nc_property_descriptor(value::string(U("Gain value")), nmos::details::make_nc_property_id(3, 1), gain_value, value::string(U("NcFloat32")), false, false, false, false)); + return properties; + }; + nmos::experimental::control_class gain_control_class = { value::string(U("Gain control class descriptor")), gain_control_class_id, U("GainControl"), value::null(), make_gain_control_properties(), value::array(), value::array()}; + control_protocol_state.control_classes[nmos::details::make_nc_class_id(gain_control_class_id)] = gain_control_class; + // helper function to create Gain control instance + auto make_gain_control = [&gain_value, &gain_control_class_id](nmos::details::nc_oid oid, nmos::details::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, float gain = 0, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null()) + { + auto data = nmos::details::make_nc_worker(gain_control_class_id, oid, true, owner, role, value::string(user_label), touchpoints, runtime_property_constraints, true); + data[gain_value] = value::number(gain); + return nmos::resource{ nmos::is12_versions::v1_0, nmos::types::nc_worker, std::move(data), true }; + }; + // example root block auto root_block = nmos::make_root_block(); + + nmos::details::nc_oid oid{ 2 }; // example device manager - auto device_manager = nmos::make_device_manager(2, root_block, model.settings); - if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(device_manager), gate)) throw node_implementation_init_exception(); + auto device_manager = nmos::make_device_manager(oid++, root_block, model.settings); + // example class manager - auto class_manager = nmos::make_class_manager(3, root_block, control_protocol_state); + auto class_manager = nmos::make_class_manager(oid++, root_block, control_protocol_state); + + // example stereo gain + const auto& root_block_oid = nmos::fields::nc::oid(root_block.data); + const auto stereo_gain_oid = oid++; + // add master-gain and channel-gain + auto stereo_gain = nmos::make_block(stereo_gain_oid, root_block_oid, U("stereo-gain"), U("Stereo gain")); + + // example channel gain + const auto channel_gain_oid = oid++; + // example left/right gains + auto left_gain = make_gain_control(oid++, channel_gain_oid, U("left-gain"), U("Left gain")); + auto right_gain = make_gain_control(oid++, channel_gain_oid, U("right-gain"), U("Right gain")); + // add left-gain and right-gain to channel gain + auto channel_gain = nmos::make_block(channel_gain_oid, stereo_gain_oid, U("channel-gain"), U("Channel gain")); + nmos::add_member_to_block(U("Left channel gain"), left_gain.data, channel_gain.data); + nmos::add_member_to_block(U("Right channel gain"), right_gain.data, channel_gain.data); + + // example master-gain + auto master_gain = make_gain_control(oid++, channel_gain_oid, U("master-gain"), U("Master gain")); + // add master-gain and channel-gain to stereo-gain + nmos::add_member_to_block(U("Master gain block"), master_gain.data, stereo_gain.data); + nmos::add_member_to_block(U("Channel gain block"), channel_gain.data, stereo_gain.data); + // add stereo-gain to root-block + nmos::add_member_to_block(U("Stereo gain block"), stereo_gain.data, root_block.data); + + // insert resources to model + if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(left_gain), gate)) throw node_implementation_init_exception(); + if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(right_gain), gate)) throw node_implementation_init_exception(); + if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(master_gain), gate)) throw node_implementation_init_exception(); + if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(channel_gain), gate)) throw node_implementation_init_exception(); + if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(stereo_gain), gate)) throw node_implementation_init_exception(); + if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(device_manager), gate)) throw node_implementation_init_exception(); if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(class_manager), gate)) throw node_implementation_init_exception(); - // insert root block to model if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(root_block), gate)) throw node_implementation_init_exception(); } } diff --git a/Development/nmos-cpp-node/node_implementation.h b/Development/nmos-cpp-node/node_implementation.h index c5d6504da..3c6b295c3 100644 --- a/Development/nmos-cpp-node/node_implementation.h +++ b/Development/nmos-cpp-node/node_implementation.h @@ -20,7 +20,7 @@ namespace nmos // This is an example of how to integrate the nmos-cpp library with a device-specific underlying implementation. // It constructs and inserts a node resource and some sub-resources into the model, based on the model settings, // starts background tasks to emit regular events from the temperature event source, and then waits for shutdown. -void node_implementation_thread(nmos::node_model& model, const nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate); +void node_implementation_thread(nmos::node_model& model, nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate); // This constructs all the callbacks used to integrate the example device-specific underlying implementation // into the server instance for the NMOS Node. diff --git a/Development/nmos/control_protocol_resource.cpp b/Development/nmos/control_protocol_resource.cpp index b456443f7..731dc00d8 100644 --- a/Development/nmos/control_protocol_resource.cpp +++ b/Development/nmos/control_protocol_resource.cpp @@ -1437,6 +1437,17 @@ namespace nmos return data; } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncworker + web::json::value make_nc_worker(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled) + { + using web::json::value; + + auto data = details::make_nc_object(class_id, oid, constant_oid, owner, role, user_label, touchpoints, runtime_property_constraints); + data[nmos::fields::nc::enabled] = value::boolean(enabled); + + return data; + } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanager web::json::value make_nc_manager(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints) { @@ -1451,7 +1462,7 @@ namespace nmos using web::json::value; auto data = details::make_nc_manager(nc_device_manager_class_id, oid, true, owner, U("DeviceManager"), user_label, touchpoints, runtime_property_constraints); - data[nmos::fields::nc::nc_version] = value::string(U("v1.0")); + data[nmos::fields::nc::nc_version] = value::string(U("v1.0.0")); data[nmos::fields::nc::manufacturer] = manufacturer; data[nmos::fields::nc::product] = product; data[nmos::fields::nc::serial_number] = value::string(serial_number); diff --git a/Development/nmos/control_protocol_resource.h b/Development/nmos/control_protocol_resource.h index 8b1b4a892..387bb6978 100644 --- a/Development/nmos/control_protocol_resource.h +++ b/Development/nmos/control_protocol_resource.h @@ -95,12 +95,12 @@ namespace nmos { enum state { - Unknown = 0, // Unknown - NormalOperation = 1, // Normal operation - Initializing = 2, // Device is initializing - Updating = 3, // Device is performing a software or firmware update - LicensingError = 4, // Device is experiencing a licensing error - InternalError = 5 // Device is experiencing an internal error + unknown = 0, // Unknown + normal_operation = 1, // Normal operation + initializing = 2, // Device is initializing + updating = 3, // Device is performing a software or firmware update + licensing_error = 4, // Device is experiencing a licensing error + internal_error = 5 // Device is experiencing an internal error }; } @@ -109,12 +109,12 @@ namespace nmos { enum cause { - Unknown = 0, // Unknown - Power_on = 1, // Power on - InternalError = 2, // Internal error - Upgrade = 3, // Upgrade - Controller_request = 4, // Controller request - ManualReset = 5 // Manual request from the front panel + unknown = 0, // Unknown + power_on = 1, // Power on + internal_error = 2, // Internal error + upgrade = 3, // Upgrade + controller_request = 4, // Controller request + manual_reset = 5 // Manual request from the front panel }; } @@ -124,10 +124,10 @@ namespace nmos { enum status { - Undefined = 0, // This is the value when there is no receiver - Connected = 1, // Connected to a stream - Disconnected = 2, // Not connected to a stream - ConnectionError = 3 // A connection error was encountered + undefined = 0, // This is the value when there is no receiver + connected = 1, // Connected to a stream + disconnected = 2, // Not connected to a stream + connection_error = 3 // A connection error was encountered }; } @@ -137,10 +137,10 @@ namespace nmos { enum status { - Undefined = 0, // This is the value when there's no connection. - PayloadOK = 1, // Payload is being received without errors and is the correct type - PayloadFormatUnsupported = 2, // Payload is being received but is of an unsupported type - PayloadError = 3 // A payload error was encountered + undefined = 0, // This is the value when there's no connection. + payload_ok = 1, // Payload is being received without errors and is the correct type + payload_format_unsupported = 2, // Payload is being received but is of an unsupported type + payloadError = 3 // A payload error was encountered }; } @@ -478,6 +478,9 @@ namespace nmos // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock web::json::value make_nc_block(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled, const web::json::value& members); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncworker + web::json::value make_nc_worker(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanager web::json::value make_nc_manager(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints); diff --git a/Development/nmos/control_protocol_resources.cpp b/Development/nmos/control_protocol_resources.cpp index c0aa6a5f8..aa126ce1f 100644 --- a/Development/nmos/control_protocol_resources.cpp +++ b/Development/nmos/control_protocol_resources.cpp @@ -1,6 +1,7 @@ #include "nmos/control_protocol_resources.h" #include "nmos/control_protocol_resource.h" +#include "nmos/control_protocol_utils.h" #include "nmos/resource.h" #include "nmos/is12_versions.h" @@ -20,10 +21,10 @@ namespace nmos const auto& serial_number = nmos::experimental::fields::serial_number(settings); const auto device_name = value::null(); const auto device_role = value::null(); - const auto& operational_state = details::make_nc_device_operational_state(details::nc_device_generic_state::NormalOperation, value::null()); + const auto& operational_state = details::make_nc_device_operational_state(details::nc_device_generic_state::normal_operation, value::null()); auto data = details::make_nc_device_manager(oid, owner, user_label, value::null(), value::null(), - manufacturer, product, serial_number, value::null(), device_name, device_role, operational_state, details::nc_reset_cause::Unknown); + manufacturer, product, serial_number, value::null(), device_name, device_role, operational_state, details::nc_reset_cause::unknown); // add NcDeviceManager block_member_descriptor to root block members web::json::push_back(root_block_data[nmos::fields::nc::members], @@ -51,13 +52,38 @@ namespace nmos return{ is12_versions::v1_0, types::nc_class_manager, std::move(data), true }; } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock - nmos::resource make_root_block() + // create block resource + nmos::resource make_block(details::nc_oid oid, const web::json::value& owner, const utility::string_t& role, const utility::string_t& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, const web::json::value& members) { using web::json::value; - auto data = details::make_nc_block(details::nc_block_class_id, 1, true, value::null(), U("root"), value::string(U("Root")), value::null(), value::null(), true, value::array()); + auto data = details::make_nc_block(details::nc_block_class_id, oid, true, owner, role, value::string(user_label), touchpoints, runtime_property_constraints, true, members); return{ is12_versions::v1_0, types::nc_block, std::move(data), true }; } + nmos::resource make_block(details::nc_oid oid, details::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, const web::json::value& members) + { + using web::json::value; + + return make_block(oid, value(owner), role, user_label, touchpoints, runtime_property_constraints, members); + } + + // create Root block resource + nmos::resource make_root_block() + { + using web::json::value; + + return make_block(1, value::null(), U("root"), U("Root")); + } + + // add member to nc_block + bool add_member_to_block(const utility::string_t& description, const web::json::value& nc_block, web::json::value& parent) + { + using web::json::value; + + web::json::push_back(parent[nmos::fields::nc::members], + details::make_nc_block_member_descriptor(value::string(description), nmos::fields::nc::role(nc_block), nmos::fields::nc::oid(nc_block), nmos::fields::nc::constant_oid(nc_block), nc_block.at(nmos::fields::nc::class_id), nc_block.at(nmos::fields::nc::user_label), nmos::fields::nc::oid(parent))); + + return true; + } } diff --git a/Development/nmos/control_protocol_resources.h b/Development/nmos/control_protocol_resources.h index b977043cf..205e16606 100644 --- a/Development/nmos/control_protocol_resources.h +++ b/Development/nmos/control_protocol_resources.h @@ -14,10 +14,20 @@ namespace nmos struct resource; + // create device manager resource nmos::resource make_device_manager(details::nc_oid oid, nmos::resource& root_block, const nmos::settings& settings); + // create class manager resource nmos::resource make_class_manager(details::nc_oid oid, nmos::resource& root_block, const nmos::experimental::control_protocol_state& control_protocol_state); + // create block resource + nmos::resource make_block(details::nc_oid oid, const web::json::value& owner, const utility::string_t& role, const utility::string_t& user_label, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null(), const web::json::value& members = web::json::value::array()); + nmos::resource make_block(details::nc_oid oid, details::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null(), const web::json::value& members = web::json::value::array()); + + // help function to add member to block + bool add_member_to_block(const utility::string_t& description, const web::json::value& nc_block, web::json::value& parent); + + // create Root block resource nmos::resource make_root_block(); } From 90a768b9c7a5ef07525a6cf637e7851002734092 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Wed, 23 Aug 2023 15:34:14 +0100 Subject: [PATCH 032/106] Extract IS-12 version from the rx ws path --- Development/nmos/control_protocol_ws_api.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Development/nmos/control_protocol_ws_api.cpp b/Development/nmos/control_protocol_ws_api.cpp index 595c918b9..1dabbef21 100644 --- a/Development/nmos/control_protocol_ws_api.cpp +++ b/Development/nmos/control_protocol_ws_api.cpp @@ -820,9 +820,8 @@ namespace nmos const auto& ws_ncp_path = connection_uri.path(); slog::log(gate, SLOG_FLF) << "Received websocket message: " << msg << " on connection: " << ws_ncp_path; - // hmm todo: extract the version from the ws_ncp_path - const nmos::api_version version = is12_versions::v1_0; - //const nmos::api_version version = nmos::parse_api_version(ws_ncp_path(nmos::patterns::version.name)); + // extract the control protocol api version from the ws_ncp_path + const auto version = nmos::parse_api_version(web::uri::split_path(ws_ncp_path).back()); auto websocket = websockets.right.find(connection_id); if (websockets.right.end() != websocket) From d47b47a41e25b5da14b8a18f7f820391dfb28c58 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Fri, 25 Aug 2023 00:48:41 +0100 Subject: [PATCH 033/106] Add helper functions to create non-standard control class, and general tidy up --- Development/cmake/NmosCppLibraries.cmake | 3 +- .../nmos-cpp-node/node_implementation.cpp | 56 +- .../nmos/control_protocol_class_id.cpp | 27 - Development/nmos/control_protocol_class_id.h | 19 - .../nmos/control_protocol_handlers.cpp | 3 +- Development/nmos/control_protocol_handlers.h | 2 +- .../nmos/control_protocol_resource.cpp | 2075 +++++++++-------- Development/nmos/control_protocol_resource.h | 589 ++--- .../nmos/control_protocol_resources.cpp | 86 +- Development/nmos/control_protocol_resources.h | 24 +- Development/nmos/control_protocol_state.cpp | 266 ++- Development/nmos/control_protocol_state.h | 37 +- Development/nmos/control_protocol_typedefs.h | 183 ++ Development/nmos/control_protocol_utils.cpp | 59 +- Development/nmos/control_protocol_utils.h | 17 +- Development/nmos/control_protocol_ws_api.cpp | 155 +- 16 files changed, 1929 insertions(+), 1672 deletions(-) delete mode 100644 Development/nmos/control_protocol_class_id.cpp delete mode 100644 Development/nmos/control_protocol_class_id.h create mode 100644 Development/nmos/control_protocol_typedefs.h diff --git a/Development/cmake/NmosCppLibraries.cmake b/Development/cmake/NmosCppLibraries.cmake index a135f74d5..f29a683c7 100644 --- a/Development/cmake/NmosCppLibraries.cmake +++ b/Development/cmake/NmosCppLibraries.cmake @@ -831,7 +831,6 @@ set(NMOS_CPP_NMOS_SOURCES nmos/connection_api.cpp nmos/connection_events_activation.cpp nmos/connection_resources.cpp - nmos/control_protocol_class_id.cpp nmos/control_protocol_handlers.cpp nmos/control_protocol_resource.cpp nmos/control_protocol_resources.cpp @@ -911,11 +910,11 @@ set(NMOS_CPP_NMOS_HEADERS nmos/connection_api.h nmos/connection_events_activation.h nmos/connection_resources.h - nmos/control_protocol_class_id.h nmos/control_protocol_handlers.h nmos/control_protocol_resource.h nmos/control_protocol_resources.h nmos/control_protocol_state.h + nmos/control_protocol_typedefs.h nmos/control_protocol_utils.h nmos/control_protocol_ws_api.h nmos/device_type.h diff --git a/Development/nmos-cpp-node/node_implementation.cpp b/Development/nmos-cpp-node/node_implementation.cpp index 6d771ae12..d7bbbcc36 100644 --- a/Development/nmos-cpp-node/node_implementation.cpp +++ b/Development/nmos-cpp-node/node_implementation.cpp @@ -22,6 +22,7 @@ #include "nmos/connection_resources.h" #include "nmos/connection_events_activation.h" #include "nmos/control_protocol_resources.h" +#include "nmos/control_protocol_resource.h" #include "nmos/control_protocol_state.h" #include "nmos/control_protocol_utils.h" #include "nmos/events_resources.h" @@ -905,19 +906,14 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr // example of using control protocol if (0 <= nmos::fields::control_protocol_ws_port(model.settings)) { - // example to create a custom Gain control class - const auto gain_control_class_id = nmos::details::make_nc_class_id(nmos::details::nc_worker_class_id, 0, { 1 }); + // example to create a non-standard Gain control class + const auto gain_control_class_id = nmos::make_nc_class_id(nmos::nc_worker_class_id, 0, { 1 }); const web::json::field_as_number gain_value{ U("gainValue") }; - auto make_gain_control_properties = [&gain_value]() - { - auto properties = value::array(); - web::json::push_back(properties, nmos::details::make_nc_property_descriptor(value::string(U("Gain value")), nmos::details::make_nc_property_id(3, 1), gain_value, value::string(U("NcFloat32")), false, false, false, false)); - return properties; - }; - nmos::experimental::control_class gain_control_class = { value::string(U("Gain control class descriptor")), gain_control_class_id, U("GainControl"), value::null(), make_gain_control_properties(), value::array(), value::array()}; - control_protocol_state.control_classes[nmos::details::make_nc_class_id(gain_control_class_id)] = gain_control_class; + std::vector gain_control_properties = { nmos::experimental::make_control_class_property(U("Gain value"), { 3, 1 }, gain_value, U("NcFloat32")) }; + auto gain_control_class = nmos::experimental::make_control_class(U("Gain control class descriptor"), gain_control_class_id, U("GainControl"), gain_control_properties, {}, {}); + control_protocol_state.insert(gain_control_class); // helper function to create Gain control instance - auto make_gain_control = [&gain_value, &gain_control_class_id](nmos::details::nc_oid oid, nmos::details::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, float gain = 0, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null()) + auto make_gain_control = [&gain_value, &gain_control_class_id](nmos::nc_oid oid, nmos::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, float gain = 0.0, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null()) { auto data = nmos::details::make_nc_worker(gain_control_class_id, oid, true, owner, role, value::string(user_label), touchpoints, runtime_property_constraints, true); data[gain_value] = value::number(gain); @@ -927,36 +923,40 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr // example root block auto root_block = nmos::make_root_block(); - nmos::details::nc_oid oid{ 2 }; + nmos::nc_oid oid = nmos::root_block_oid; + // example device manager - auto device_manager = nmos::make_device_manager(oid++, root_block, model.settings); + auto device_manager = nmos::make_device_manager(++oid, model.settings); // example class manager - auto class_manager = nmos::make_class_manager(oid++, root_block, control_protocol_state); + auto class_manager = nmos::make_class_manager(++oid, control_protocol_state); // example stereo gain - const auto& root_block_oid = nmos::fields::nc::oid(root_block.data); - const auto stereo_gain_oid = oid++; - // add master-gain and channel-gain - auto stereo_gain = nmos::make_block(stereo_gain_oid, root_block_oid, U("stereo-gain"), U("Stereo gain")); + const auto stereo_gain_oid = ++oid; + auto stereo_gain = nmos::make_block(stereo_gain_oid, nmos::root_block_oid, U("stereo-gain"), U("Stereo gain")); // example channel gain - const auto channel_gain_oid = oid++; + const auto channel_gain_oid = ++oid; + auto channel_gain = nmos::make_block(channel_gain_oid, stereo_gain_oid, U("channel-gain"), U("Channel gain")); // example left/right gains - auto left_gain = make_gain_control(oid++, channel_gain_oid, U("left-gain"), U("Left gain")); - auto right_gain = make_gain_control(oid++, channel_gain_oid, U("right-gain"), U("Right gain")); + auto left_gain = make_gain_control(++oid, channel_gain_oid, U("left-gain"), U("Left gain")); + auto right_gain = make_gain_control(++oid, channel_gain_oid, U("right-gain"), U("Right gain")); // add left-gain and right-gain to channel gain - auto channel_gain = nmos::make_block(channel_gain_oid, stereo_gain_oid, U("channel-gain"), U("Channel gain")); - nmos::add_member_to_block(U("Left channel gain"), left_gain.data, channel_gain.data); - nmos::add_member_to_block(U("Right channel gain"), right_gain.data, channel_gain.data); + nmos::add_member(U("Left channel gain"), left_gain, channel_gain); + nmos::add_member(U("Right channel gain"), right_gain, channel_gain); // example master-gain - auto master_gain = make_gain_control(oid++, channel_gain_oid, U("master-gain"), U("Master gain")); + auto master_gain = make_gain_control(++oid, channel_gain_oid, U("master-gain"), U("Master gain")); // add master-gain and channel-gain to stereo-gain - nmos::add_member_to_block(U("Master gain block"), master_gain.data, stereo_gain.data); - nmos::add_member_to_block(U("Channel gain block"), channel_gain.data, stereo_gain.data); + nmos::add_member(U("Master gain block"), master_gain, stereo_gain); + nmos::add_member(U("Channel gain block"), channel_gain, stereo_gain); + // add stereo-gain to root-block - nmos::add_member_to_block(U("Stereo gain block"), stereo_gain.data, root_block.data); + nmos::add_member(U("Stereo gain block"), stereo_gain, root_block); + // add class-manager to root-block + nmos::add_member(U("The class manager offers access to control class and data type descriptors"), class_manager, root_block); + // add device-manager to root-block + nmos::add_member(U("The device manager offers information about the product this device is representing"), device_manager, root_block); // insert resources to model if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(left_gain), gate)) throw node_implementation_init_exception(); diff --git a/Development/nmos/control_protocol_class_id.cpp b/Development/nmos/control_protocol_class_id.cpp deleted file mode 100644 index 8ca0ec90c..000000000 --- a/Development/nmos/control_protocol_class_id.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "nmos/control_protocol_class_id.h" - -namespace nmos -{ - namespace details - { - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassid - web::json::value make_nc_class_id(const nc_class_id& class_id) - { - using web::json::value; - - auto nc_class_id = value::array(); - for (const auto class_id_item : class_id) { web::json::push_back(nc_class_id, class_id_item); } - return nc_class_id; - } - - nc_class_id parse_nc_class_id(const web::json::array& class_id_) - { - nc_class_id class_id; - for (auto& element : class_id_) - { - class_id.push_back(element.as_integer()); - } - return class_id; - } - } -} diff --git a/Development/nmos/control_protocol_class_id.h b/Development/nmos/control_protocol_class_id.h deleted file mode 100644 index f48bbe731..000000000 --- a/Development/nmos/control_protocol_class_id.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef NMOS_CONTROL_PROTOCOL_CLASS_ID_H -#define NMOS_CONTROL_PROTOCOL_CLASS_ID_H - -#include "cpprest/json_utils.h" - -namespace nmos -{ - namespace details - { - // see https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassid - typedef std::vector nc_class_id; - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassid - web::json::value make_nc_class_id(const nc_class_id& class_id); - nc_class_id parse_nc_class_id(const web::json::array& class_id); - } -} - -#endif diff --git a/Development/nmos/control_protocol_handlers.cpp b/Development/nmos/control_protocol_handlers.cpp index 5e52f0700..1118a35b8 100644 --- a/Development/nmos/control_protocol_handlers.cpp +++ b/Development/nmos/control_protocol_handlers.cpp @@ -1,5 +1,6 @@ #include "nmos/control_protocol_handlers.h" +#include "nmos/control_protocol_resource.h" #include "nmos/slog.h" namespace nmos @@ -18,7 +19,7 @@ namespace nmos add_control_protocol_class_handler make_add_control_protocol_class_handler(nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate) { - return [&](const details::nc_class_id& class_id, const experimental::control_class& control_class) + return [&](const nc_class_id& class_id, const experimental::control_class& control_class) { slog::log(gate, SLOG_FLF) << "Add control class to cache"; diff --git a/Development/nmos/control_protocol_handlers.h b/Development/nmos/control_protocol_handlers.h index 565bf6c26..165b53809 100644 --- a/Development/nmos/control_protocol_handlers.h +++ b/Development/nmos/control_protocol_handlers.h @@ -23,7 +23,7 @@ namespace nmos // callback to add user control protocol class // this callback should not throw exceptions - typedef std::function add_control_protocol_class_handler; + typedef std::function add_control_protocol_class_handler; // callback to retrieve all control protocol datatypes // this callback should not throw exceptions diff --git a/Development/nmos/control_protocol_resource.cpp b/Development/nmos/control_protocol_resource.cpp index 731dc00d8..4ab09f694 100644 --- a/Development/nmos/control_protocol_resource.cpp +++ b/Development/nmos/control_protocol_resource.cpp @@ -31,95 +31,57 @@ namespace nmos return result; } - web::json::value make_control_protocol_error_response(int32_t handle, const nc_method_result& method_result, const utility::string_t& error_message) - { - using web::json::value_of; - - return value_of({ - { nmos::fields::nc::handle, handle }, - { nmos::fields::nc::result, make_nc_method_result_error(method_result, error_message) } - }); - } - - web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result) - { - using web::json::value_of; - - return value_of({ - { nmos::fields::nc::handle, handle }, - { nmos::fields::nc::result, make_nc_method_result(method_result) } - }); - } - - web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result, const web::json::value& value) + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncelementid + web::json::value make_nc_element_id(uint16_t level, uint16_t index) { using web::json::value_of; return value_of({ - { nmos::fields::nc::handle, handle }, - { nmos::fields::nc::result, make_nc_method_result(method_result, value) } + { nmos::fields::nc::level, level }, + { nmos::fields::nc::index, index } }); } - - web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result, uint32_t value_) + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncelementid + web::json::value make_nc_element_id(const nc_element_id& element_id) { - using web::json::value; - - return make_control_protocol_response(handle, method_result, value(value_)); + return make_nc_element_id(element_id.level, element_id.index); } - // message response - // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#command-message-type - web::json::value make_control_protocol_message_response(nc_message_type::type type, const web::json::value& responses) + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#nceventid + web::json::value make_nc_event_id(const nc_event_id& id) { - using web::json::value_of; - - return value_of({ - { nmos::fields::nc::message_type, type }, - { nmos::fields::nc::responses, responses } - }); + return make_nc_element_id(id); } - // error message - // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#error-messages - web::json::value make_control_protocol_error_message(const nc_method_result& method_result, const utility::string_t& error_message) + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmethodid + web::json::value make_nc_method_id(const nc_method_id& id) { - using web::json::value_of; - - return value_of({ - { nmos::fields::nc::message_type, nc_message_type::error }, - { nmos::fields::nc::status, method_result.status}, - { nmos::fields::nc::error_message, error_message } - }); + return make_nc_element_id(id); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncelementid - web::json::value make_nc_element_id(uint16_t level, uint16_t index) + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncpropertyid + web::json::value make_nc_property_id(const nc_property_id& id) { - using web::json::value_of; - - return value_of({ - { nmos::fields::nc::level, level }, - { nmos::fields::nc::index, index } - }); + return make_nc_element_id(id); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#nceventid - web::json::value make_nc_event_id(uint16_t level, uint16_t index) + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassid + web::json::value make_nc_class_id(const nc_class_id& class_id) { - return make_nc_element_id(level, index); - } + using web::json::value; - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmethodid - web::json::value make_nc_method_id(uint16_t level, uint16_t index) - { - return make_nc_element_id(level, index); + auto nc_class_id = value::array(); + for (const auto class_id_item : class_id) { web::json::push_back(nc_class_id, class_id_item); } + return nc_class_id; } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncpropertyid - web::json::value make_nc_property_id(uint16_t level, uint16_t index) + nc_class_id parse_nc_class_id(const web::json::array& class_id_) { - return make_nc_element_id(level, index); + nc_class_id class_id; + for (auto& element : class_id_) + { + class_id.push_back(element.as_integer()); + } + return class_id; } // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanufacturer @@ -177,7 +139,7 @@ namespace nmos // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblockmemberdescriptor // description can be null // user_label can be null - web::json::value make_nc_block_member_descriptor(const web::json::value& description, const utility::string_t& role, nc_oid oid, bool constant_oid, const web::json::value& class_id, const web::json::value& user_label, nc_oid owner) + web::json::value make_nc_block_member_descriptor(const web::json::value& description, const utility::string_t& role, nc_oid oid, bool constant_oid, const nc_class_id& class_id, const web::json::value& user_label, nc_oid owner) { using web::json::value; @@ -185,12 +147,18 @@ namespace nmos data[nmos::fields::nc::role] = value::string(role); data[nmos::fields::nc::oid] = oid; data[nmos::fields::nc::constant_oid] = value::boolean(constant_oid); - data[nmos::fields::nc::class_id] = class_id; + data[nmos::fields::nc::class_id] = make_nc_class_id(class_id); data[nmos::fields::nc::user_label] = user_label; data[nmos::fields::nc::owner] = owner; return data; } + web::json::value make_nc_block_member_descriptor(const utility::string_t& description, const utility::string_t& role, nc_oid oid, bool constant_oid, const nc_class_id& class_id, const utility::string_t& user_label, nc_oid owner) + { + using web::json::value; + + return make_nc_block_member_descriptor(value::string(description), role, oid, constant_oid, class_id, value::string(user_label), owner); + } // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassdescriptor // description can be null @@ -209,6 +177,12 @@ namespace nmos return data; } + web::json::value make_nc_class_descriptor(const utility::string_t& description, const nc_class_id& class_id, const utility::string_t& name, const web::json::value& fixed_role, const web::json::value& properties, const web::json::value& methods, const web::json::value& events) + { + using web::json::value; + + return make_nc_class_descriptor(value::string(description), class_id, name, fixed_role, properties, methods, events); + } // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncenumitemdescriptor // description can be null @@ -222,22 +196,34 @@ namespace nmos return data; } + web::json::value make_nc_enum_item_descriptor(const utility::string_t& description, const utility::string_t& name, uint16_t val) + { + using web::json::value; + + return make_nc_enum_item_descriptor(value::string(description), name, val); + } // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#nceventdescriptor // description can be null // id = make_nc_event_id(level, index) - web::json::value make_nc_event_descriptor(const web::json::value& description, const web::json::value& id, const utility::string_t& name, const utility::string_t& event_datatype, bool is_deprecated) + web::json::value make_nc_event_descriptor(const web::json::value& description, const nc_event_id& id, const utility::string_t& name, const utility::string_t& event_datatype, bool is_deprecated) { using web::json::value; auto data = make_nc_descriptor(description); - data[nmos::fields::nc::id] = id; + data[nmos::fields::nc::id] = make_nc_event_id(id); data[nmos::fields::nc::name] = value::string(name); data[nmos::fields::nc::event_datatype] = value::string(event_datatype); data[nmos::fields::nc::is_deprecated] = value::boolean(is_deprecated); return data; } + web::json::value make_nc_event_descriptor(const utility::string_t& description, const nc_event_id& id, const utility::string_t& name, const utility::string_t& event_datatype, bool is_deprecated) + { + using web::json::value; + + return make_nc_event_descriptor(value::string(description), id, name, event_datatype, is_deprecated); + } // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncfielddescriptor // description can be null @@ -256,17 +242,23 @@ namespace nmos return data; } + web::json::value make_nc_field_descriptor(const utility::string_t& description, const utility::string_t& name, const utility::string_t& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints) + { + using web::json::value; + + return make_nc_field_descriptor(value::string(description), name, value::string(type_name), is_nullable, is_sequence, constraints); + } // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmethoddescriptor // description can be null // id = make_nc_method_id(level, index) // sequence parameters - web::json::value make_nc_method_descriptor(const web::json::value& description, const web::json::value& id, const utility::string_t& name, const utility::string_t& result_datatype, const web::json::value& parameters, bool is_deprecated) + web::json::value make_nc_method_descriptor(const web::json::value& description, const nc_method_id& id, const utility::string_t& name, const utility::string_t& result_datatype, const web::json::value& parameters, bool is_deprecated) { using web::json::value; auto data = make_nc_descriptor(description); - data[nmos::fields::nc::id] = id; + data[nmos::fields::nc::id] = make_nc_method_id(id); data[nmos::fields::nc::name] = value::string(name); data[nmos::fields::nc::result_datatype] = value::string(result_datatype); data[nmos::fields::nc::parameters] = parameters; @@ -274,6 +266,12 @@ namespace nmos return data; } + web::json::value make_nc_method_descriptor(const utility::string_t& description, const nc_method_id& id, const utility::string_t& name, const utility::string_t& result_datatype, const web::json::value& parameters, bool is_deprecated) + { + using web::json::value; + + return make_nc_method_descriptor(value::string(description), id, name, result_datatype, parameters, is_deprecated); + } // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncparameterdescriptor // description can be null @@ -291,19 +289,29 @@ namespace nmos return data; } + web::json::value make_nc_parameter_descriptor(const utility::string_t& description, const utility::string_t& name, bool is_nullable, bool is_sequence, const web::json::value& constraints) + { + using web::json::value; + + return make_nc_parameter_descriptor(value::string(description), name, value::null(), is_nullable, is_sequence, constraints); + } + web::json::value make_nc_parameter_descriptor(const utility::string_t& description, const utility::string_t& name, const utility::string_t& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints) + { + using web::json::value; + + return make_nc_parameter_descriptor(value::string(description), name, value::string(type_name), is_nullable, is_sequence, constraints); + } // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncpropertydescriptor // description can be null - // id = make_nc_property_id(level, index); - // type_name can be null // constraints can be null - web::json::value make_nc_property_descriptor(const web::json::value& description, const web::json::value& id, const utility::string_t& name, const web::json::value& type_name, + web::json::value make_nc_property_descriptor(const web::json::value& description, const nc_property_id& id, const utility::string_t& name, const web::json::value& type_name, bool is_read_only, bool is_nullable, bool is_sequence, bool is_deprecated, const web::json::value& constraints) { using web::json::value; auto data = make_nc_descriptor(description); - data[nmos::fields::nc::id] = id; + data[nmos::fields::nc::id] = make_nc_property_id(id); data[nmos::fields::nc::name] = value::string(name); data[nmos::fields::nc::type_name] = type_name; data[nmos::fields::nc::is_read_only] = value::boolean(is_read_only); @@ -314,6 +322,13 @@ namespace nmos return data; } + web::json::value make_nc_property_descriptor(const utility::string_t& description, const nc_property_id& id, const utility::string_t& name, const utility::string_t& type_name, + bool is_read_only, bool is_nullable, bool is_sequence, bool is_deprecated, const web::json::value& constraints) + { + using web::json::value; + + return nmos::details::make_nc_property_descriptor(value::string(description), id, name, value::string(type_name), is_read_only, is_nullable, is_sequence, is_deprecated, constraints); + } // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptor // description can be null @@ -379,1128 +394,1214 @@ namespace nmos } // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject - web::json::value make_nc_object_properties() - { - using web::json::value; - - auto properties = value::array(); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Static value. All instances of the same class will have the same identity value")), make_nc_property_id(1, 1), nmos::fields::nc::class_id, value::string(U("NcClassId")), true, false, false, false)); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Object identifier")), make_nc_property_id(1, 2), nmos::fields::nc::oid, value::string(U("NcOid")), true, false, false, false)); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("TRUE iff OID is hardwired into device")), make_nc_property_id(1, 3), nmos::fields::nc::constant_oid, value::string(U("NcBoolean")), true, false, false, false)); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("OID of containing block. Can only ever be null for the root block")), make_nc_property_id(1, 4), nmos::fields::nc::owner, value::string(U("NcOid")), true, true, false, false)); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Role of object in the containing block")), make_nc_property_id(1, 5), nmos::fields::nc::role, value::string(U("NcString")), true, false, false, false)); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Scribble strip")), make_nc_property_id(1, 6), nmos::fields::nc::user_label, value::string(U("NcString")), false, true, false, false)); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Touchpoints to other contexts")), make_nc_property_id(1, 7), nmos::fields::nc::touchpoints, value::string(U("NcTouchpoint")), true, true, true, false)); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Runtime property constraints")), make_nc_property_id(1, 8), nmos::fields::nc::runtime_property_constraints, value::string(U("NcPropertyConstraints")), true, true, true, false)); - - return properties; - } - web::json::value make_nc_object_methods() - { - using web::json::value; - - auto methods = value::array(); - { - auto parameters = value::array(); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false)); - web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Get property value")), make_nc_method_id(1, 1), U("Get"), U("NcMethodResultPropertyValue"), parameters, false)); - } - { - auto parameters = value::array(); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false)); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Property value")), nmos::fields::nc::value, value::null(), true, false)); - web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Set property value")), make_nc_method_id(1, 2), U("Set"), U("NcMethodResult"), parameters, false)); - } - { - auto parameters = value::array(); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false)); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Index of item in the sequence")), nmos::fields::nc::index, value::string(U("NcId")), false, false)); - web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Get sequence item")), make_nc_method_id(1, 3), U("GetSequenceItem"), U("NcMethodResultPropertyValue"), parameters, false)); - } - { - auto parameters = value::array(); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false)); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Index of item in the sequence")), nmos::fields::nc::index, value::string(U("NcId")), false, false)); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Value")), nmos::fields::nc::value, value::null(), true, false)); - web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Set sequence item value")), make_nc_method_id(1, 4), U("SetSequenceItem"), U("NcMethodResult"), parameters, false)); - } - { - auto parameters = value::array(); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false)); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Value")), nmos::fields::nc::value, value::null(), true, false)); - web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Add item to sequence")), make_nc_method_id(1, 5), U("AddSequenceItem"), U("NcMethodResultId"), parameters, false)); - } - { - auto parameters = value::array(); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false)); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Index of item in the sequence")), nmos::fields::nc::index, value::string(U("NcId")), false, false)); - web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Delete sequence item")), make_nc_method_id(1, 6), U("RemoveSequenceItem"), U("NcMethodResult"), parameters, false)); - } - { - auto parameters = value::array(); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Property id")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false)); - web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Get sequence length")), make_nc_method_id(1, 7), U("GetSequenceLength"), U("NcMethodResultLength"), parameters, false)); - } - - return methods; - } - web::json::value make_nc_object_events() + web::json::value make_nc_object(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints) { using web::json::value; - auto events = value::array(); - web::json::push_back(events, make_nc_event_descriptor(value::string(U("Property changed event")), make_nc_event_id(1, 1), U("PropertyChanged"), U("NcPropertyChangedEventData"), false)); + const auto id = utility::conversions::details::to_string_t(oid); +// auto data = make_resource_core(id, user_label.is_null() ? U("") : user_label.as_string(), {}); + value data; + data[nmos::fields::id] = value::string(id); // required for nmos::resource + data[nmos::fields::nc::class_id] = make_nc_class_id(class_id); + data[nmos::fields::nc::oid] = oid; + data[nmos::fields::nc::constant_oid] = value::boolean(constant_oid); + data[nmos::fields::nc::owner] = owner; + data[nmos::fields::nc::role] = value::string(role); + data[nmos::fields::nc::user_label] = user_label; + data[nmos::fields::nc::touchpoints] = touchpoints; + data[nmos::fields::nc::runtime_property_constraints] = runtime_property_constraints; - return events; + return data; } // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock - web::json::value make_nc_block_properties() - { - using web::json::value; - - auto properties = value::array(); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("TRUE if block is functional")), make_nc_property_id(2, 1), nmos::fields::nc::enabled, value::string(U("NcBoolean")), true, false, false, false)); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Descriptors of this block's members")), make_nc_property_id(2, 2), nmos::fields::nc::members, value::string(U("NcBlockMemberDescriptor")), true, false, true, false)); - - return properties; - } - web::json::value make_nc_block_methods() + web::json::value make_nc_block(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled, const web::json::value& members) { using web::json::value; - auto methods = value::array(); - { - auto parameters = value::array(); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("If recurse is set to true, nested members can be retrieved")), nmos::fields::nc::recurse, value::string(U("NcBoolean")), false, false)); - web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Gets descriptors of members of the block")), make_nc_method_id(2, 1), U("GetMemberDescriptors"), U("NcMethodResultBlockMemberDescriptors"), parameters, false)); - } - { - auto parameters = value::array(); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Relative path to search for (MUST not include the role of the block targeted by oid)")), nmos::fields::nc::path, value::string(U("NcRolePath")), false, false)); - web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Finds member(s) by path")), make_nc_method_id(2, 2), U("FindMembersByPath"), U("NcMethodResultBlockMemberDescriptors"), parameters, false)); - } - { - auto parameters = value::array(); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Role text to search for")), nmos::fields::nc::role, value::string(U("NcString")), false, false)); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("Signals if the comparison should be case sensitive")), nmos::fields::nc::case_sensitive, value::string(U("NcBoolean")), false, false)); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("TRUE to only return exact matches")), nmos::fields::nc::match_whole_string, value::string(U("NcBoolean")), false, false)); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("TRUE to search nested blocks")), nmos::fields::nc::recurse, value::string(U("NcBoolean")), false, false)); - web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Finds members with given role name or fragment")), make_nc_method_id(2, 3), U("FindMembersByRole"), U("NcMethodResultBlockMemberDescriptors"), parameters, false)); - } - { - auto parameters = value::array(); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("Class id to search for")), nmos::fields::nc::class_id, value::string(U("NcClassId")), false, false)); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("If TRUE it will also include derived class descriptors")), nmos::fields::nc::include_derived, value::string(U("NcBoolean")), false, false)); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(value::string(U("TRUE to search nested blocks")), nmos::fields::nc::recurse, value::string(U("NcBoolean")), false, false)); - web::json::push_back(methods, details::make_nc_method_descriptor(value::string(U("Finds members with given class id")), details::make_nc_method_id(2, 4), U("FindMembersByClassId"), U("NcMethodResultBlockMemberDescriptors"), parameters, false)); - } - - return methods; - } - web::json::value make_nc_block_events() - { - using web::json::value; + auto data = details::make_nc_object(class_id, oid, constant_oid, owner, role, user_label, touchpoints, runtime_property_constraints); + data[nmos::fields::nc::enabled] = value::boolean(enabled); + data[nmos::fields::nc::members] = members; - return value::array(); + return data; } // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncworker - web::json::value make_nc_worker_properties() - { - using web::json::value; - - auto properties = value::array(); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("TRUE iff worker is enabled")), make_nc_property_id(2, 1), nmos::fields::nc::enabled, value::string(U("NcBoolean")), false, false, false, false)); - - return properties; - } - web::json::value make_nc_worker_methods() + web::json::value make_nc_worker(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled) { using web::json::value; - return value::array(); - } - web::json::value make_nc_worker_events() - { - using web::json::value; + auto data = details::make_nc_object(class_id, oid, constant_oid, owner, role, user_label, touchpoints, runtime_property_constraints); + data[nmos::fields::nc::enabled] = value::boolean(enabled); - return value::array(); + return data; } // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanager - web::json::value make_nc_manager_properties() - { - using web::json::value; - - return value::array(); - } - web::json::value make_nc_manager_methods() - { - using web::json::value; - - return value::array(); - } - web::json::value make_nc_manager_events() + web::json::value make_nc_manager(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints) { - using web::json::value; - - return value::array(); + return make_nc_object(class_id, oid, constant_oid, owner, role, user_label, touchpoints, runtime_property_constraints); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager - web::json::value make_nc_device_manager_properties() - { - using web::json::value; - - auto properties = value::array(); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Version of MS-05-02 that this device uses")), make_nc_property_id(3, 1), nmos::fields::nc::nc_version, value::string(U("NcVersionCode")), true, false, false, false)); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Manufacturer descriptor")), make_nc_property_id(3, 2), nmos::fields::nc::manufacturer, value::string(U("NcManufacturer")), true, false, false, false)); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Product descriptor")), make_nc_property_id(3, 3), nmos::fields::nc::product, value::string(U("NcProduct")), true, false, false, false)); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Serial number")), make_nc_property_id(3, 4), nmos::fields::nc::serial_number, value::string(U("NcString")), true, false, false, false)); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Asset tracking identifier (user specified)")), make_nc_property_id(3, 5), nmos::fields::nc::user_inventory_code, value::string(U("NcString")), false, true, false, false)); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Name of this device in the application. Instance name, not product name")), make_nc_property_id(3, 6), nmos::fields::nc::device_name, value::string(U("NcString")), false, true, false, false)); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Role of this device in the application")), make_nc_property_id(3, 7), nmos::fields::nc::device_role, value::string(U("NcString")), false, true, false, false)); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Device operational state")), make_nc_property_id(3, 8), nmos::fields::nc::operational_state, value::string(U("NcDeviceOperationalState")), true, false, false, false)); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Reason for most recent reset")), make_nc_property_id(3, 9), nmos::fields::nc::reset_cause, value::string(U("NcResetCause")), true, false, false, false)); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Arbitrary message from dev to controller")), make_nc_property_id(3, 10), nmos::fields::nc::message, value::string(U("NcString")), true, true, false, false)); - - return properties; - } - web::json::value make_nc_device_manager_methods() + web::json::value make_nc_device_manager(nc_oid oid, nc_oid owner, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, + const web::json::value& manufacturer, const web::json::value& product, const utility::string_t& serial_number, + const web::json::value& user_inventory_code, const web::json::value& device_name, const web::json::value& device_role, const web::json::value& operational_state, nc_reset_cause::cause reset_cause) { using web::json::value; - return value::array(); - } - web::json::value make_nc_device_manager_events() - { - using web::json::value; + auto data = details::make_nc_manager(nc_device_manager_class_id, oid, true, owner, U("DeviceManager"), user_label, touchpoints, runtime_property_constraints); + data[nmos::fields::nc::nc_version] = value::string(U("v1.0.0")); + data[nmos::fields::nc::manufacturer] = manufacturer; + data[nmos::fields::nc::product] = product; + data[nmos::fields::nc::serial_number] = value::string(serial_number); + data[nmos::fields::nc::user_inventory_code] = user_inventory_code; + data[nmos::fields::nc::device_name] = device_name; + data[nmos::fields::nc::device_role] = device_role; + data[nmos::fields::nc::operational_state] = operational_state; + data[nmos::fields::nc::reset_cause] = reset_cause; + data[nmos::fields::nc::message] = value::null(); - return value::array(); + return data; } // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager - web::json::value make_nc_class_manager_properties() + web::json::value make_nc_class_manager(nc_oid oid, nc_oid owner, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, const nmos::experimental::control_protocol_state& control_protocol_state) { using web::json::value; - auto properties = value::array(); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Descriptions of all control classes in the device (descriptors do not contain inherited elements)")), make_nc_property_id(3, 1), nmos::fields::nc::control_classes, value::string(U("NcClassDescriptor")), true, false, true, false)); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Descriptions of all data types in the device (descriptors do not contain inherited elements)")), make_nc_property_id(3, 2), nmos::fields::nc::datatypes, value::string(U("NcDatatypeDescriptor")), true, false, true, false)); - - return properties; - } - web::json::value make_nc_class_manager_methods() - { - using web::json::value; + auto data = make_nc_manager(nc_class_manager_class_id, oid, true, owner, U("ClassManager"), user_label, touchpoints, runtime_property_constraints); - auto methods = value::array(); + // add control classes + data[nmos::fields::nc::control_classes] = value::array(); + auto& control_classes = data[nmos::fields::nc::control_classes]; + for (const auto& control_class : control_protocol_state.control_classes) { - auto parameters = value::array(); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("class ID")), nmos::fields::nc::class_id, value::string(U("NcClassId")), false, false)); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("If set the descriptor would contain all inherited elements")), nmos::fields::nc::include_inherited, value::string(U("NcBoolean")), false, false)); - web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Get a single class descriptor")), make_nc_method_id(3, 1), U("GetControlClass"), U("NcMethodResultClassDescriptor"), parameters, false)); + auto& ctl_class = control_class.second; + web::json::push_back(control_classes, make_nc_class_descriptor(ctl_class.description, ctl_class.class_id, ctl_class.name, ctl_class.fixed_role, ctl_class.properties, ctl_class.methods, ctl_class.events)); } + + // add datatypes + data[nmos::fields::nc::datatypes] = value::array(); + auto& datatypes = data[nmos::fields::nc::datatypes]; + for (const auto& datatype : control_protocol_state.datatypes) { - auto parameters = value::array(); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("name of datatype")), nmos::fields::nc::name, value::string(U("NcName")), false, false)); - web::json::push_back(parameters, make_nc_parameter_descriptor(value::string(U("If set the descriptor would contain all inherited elements")), nmos::fields::nc::include_inherited, value::string(U("NcBoolean")), false, false)); - web::json::push_back(methods, make_nc_method_descriptor(value::string(U("Get a single datatype descriptor")), make_nc_method_id(3, 2), U("GetDatatype"), U("NcMethodResultDatatypeDescriptor"), parameters, false)); + web::json::push_back(datatypes, datatype.second.descriptor); } - return methods; + return data; } - web::json::value make_nc_class_manager_events() - { - using web::json::value; + } - return value::array(); - } + // message response + // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#command-message-type + web::json::value make_control_protocol_message_response(nc_message_type::type type, const web::json::value& responses) + { + using web::json::value_of; - // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitor - web::json::value make_nc_receiver_monitor_properties() - { - using web::json::value; + return value_of({ + { nmos::fields::nc::message_type, type }, + { nmos::fields::nc::responses, responses } + }); + } - auto properties = value::array(); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Connection status property")), make_nc_property_id(3, 1), nmos::fields::nc::connection_status, value::string(U("NcConnectionStatus")), true, false, false, false)); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Connection status message property")), make_nc_property_id(3, 2), nmos::fields::nc::connection_status_message, value::string(U("NcString")), true, true, false, false)); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Payload status property")), make_nc_property_id(3, 3), nmos::fields::nc::payload_status, value::string(U("NcPayloadStatus")), true, false, false, false)); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Payload status message property")), make_nc_property_id(3, 4), nmos::fields::nc::payload_status_message, value::string(U("NcString")), true, true, false, false)); + // error message + // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#error-messages + web::json::value make_control_protocol_error_message(const nc_method_result& method_result, const utility::string_t& error_message) + { + using web::json::value_of; - return properties; - } - web::json::value make_nc_receiver_monitor_methods() - { - using web::json::value; + return value_of({ + { nmos::fields::nc::message_type, nc_message_type::error }, + { nmos::fields::nc::status, method_result.status}, + { nmos::fields::nc::error_message, error_message } + }); + } - return value::array(); - } - web::json::value make_nc_receiver_monitor_events() - { - using web::json::value; + web::json::value make_control_protocol_error_response(int32_t handle, const nc_method_result& method_result, const utility::string_t& error_message) + { + using web::json::value_of; - return value::array(); - } + return value_of({ + { nmos::fields::nc::handle, handle }, + { nmos::fields::nc::result, details::make_nc_method_result_error(method_result, error_message) } + }); + } - // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitorprotected - web::json::value make_nc_receiver_monitor_protected_properties() - { - using web::json::value; + web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result) + { + using web::json::value_of; - auto properties = value::array(); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Indicates if signal protection is active")), make_nc_property_id(4, 1), nmos::fields::nc::signal_protection_status, value::string(U("NcBoolean")), true, false, false, false)); + return value_of({ + { nmos::fields::nc::handle, handle }, + { nmos::fields::nc::result, details::make_nc_method_result(method_result) } + }); + } - return properties; - } - web::json::value make_nc_receiver_monitor_protected_methods() - { - using web::json::value; + web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result, const web::json::value& value) + { + using web::json::value_of; - return value::array(); - } - web::json::value make_nc_receiver_monitor_protected_events() - { - using web::json::value; + return value_of({ + { nmos::fields::nc::handle, handle }, + { nmos::fields::nc::result, details::make_nc_method_result(method_result, value) } + }); + } - return value::array(); - } + web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result, uint32_t value_) + { + using web::json::value; - // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/identification/#ncidentbeacon - web::json::value make_nc_ident_beacon_properties() - { - using web::json::value; + return make_control_protocol_response(handle, method_result, value(value_)); + } - auto properties = value::array(); - web::json::push_back(properties, make_nc_property_descriptor(value::string(U("Indicator active state")), make_nc_property_id(3, 1), nmos::fields::nc::active, value::string(U("NcBoolean")), false, false, false, false)); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject + web::json::value make_nc_object_properties() + { + using web::json::value; + + auto properties = value::array(); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Static value. All instances of the same class will have the same identity value"), { 1, 1 }, nmos::fields::nc::class_id, U("NcClassId"), true, false, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Object identifier"), { 1, 2 }, nmos::fields::nc::oid, U("NcOid"), true, false, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("TRUE iff OID is hardwired into device"), { 1, 3 }, nmos::fields::nc::constant_oid, U("NcBoolean"), true, false, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("OID of containing block. Can only ever be null for the root block"), { 1, 4 }, nmos::fields::nc::owner, U("NcOid"), true, true, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Role of object in the containing block"), { 1, 5 }, nmos::fields::nc::role, U("NcString"), true, false, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Scribble strip"), { 1, 6 }, nmos::fields::nc::user_label, U("NcString"), false, true, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Touchpoints to other contexts"), { 1, 7 }, nmos::fields::nc::touchpoints, U("NcTouchpoint"), true, true, true, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Runtime property constraints"), { 1, 8 }, nmos::fields::nc::runtime_property_constraints, U("NcPropertyConstraints"), true, true, true, false)); + + return properties; + } + web::json::value make_nc_object_methods() + { + using web::json::value; - return properties; + auto methods = value::array(); + { + auto parameters = value::array(); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Property id"), nmos::fields::nc::id, U("NcPropertyId"), false, false, value::null())); + web::json::push_back(methods, details::make_nc_method_descriptor(U("Get property value"), { 1, 1 }, U("Get"), U("NcMethodResultPropertyValue"), parameters, false)); } - web::json::value make_nc_ident_beacon_methods() { - using web::json::value; - - return value::array(); + auto parameters = value::array(); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Property id"), nmos::fields::nc::id, U("NcPropertyId"), false, false, value::null())); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Property value"), nmos::fields::nc::value, true, false)); + web::json::push_back(methods, details::make_nc_method_descriptor(U("Set property value"), { 1, 2 }, U("Set"), U("NcMethodResult"), parameters, false)); } - web::json::value make_nc_ident_beacon_events() { - using web::json::value; - - return value::array(); + auto parameters = value::array(); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Property id"), nmos::fields::nc::id, U("NcPropertyId"), false, false, value::null())); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Index of item in the sequence"), nmos::fields::nc::index, U("NcId"), false, false, value::null())); + web::json::push_back(methods, details::make_nc_method_descriptor(U("Get sequence item"), { 1, 3 }, U("GetSequenceItem"), U("NcMethodResultPropertyValue"), parameters, false)); } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.html - web::json::value make_nc_object_class() { - using web::json::value; - - return make_nc_class_descriptor(value::string(U("NcObject class descriptor")), nc_object_class_id, U("NcObject"), value::null(), make_nc_object_properties(), make_nc_object_methods(), make_nc_object_events()); + auto parameters = value::array(); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Property id"), nmos::fields::nc::id, U("NcPropertyId"), false, false, value::null())); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Index of item in the sequence"), nmos::fields::nc::index, U("NcId"), false, false, value::null())); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Value"), nmos::fields::nc::value, true, false)); + web::json::push_back(methods, details::make_nc_method_descriptor(U("Set sequence item value"), { 1, 4 }, U("SetSequenceItem"), U("NcMethodResult"), parameters, false)); } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.1.html - web::json::value make_nc_block_class() { - using web::json::value; - - return make_nc_class_descriptor(value::string(U("NcBlock class descriptor")), nc_block_class_id, U("NcBlock"), value::null(), make_nc_block_properties(), make_nc_block_methods(), make_nc_block_events()); + auto parameters = value::array(); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Property id"), nmos::fields::nc::id,U("NcPropertyId"), false, false, value::null())); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Value"), nmos::fields::nc::value, true, false)); + web::json::push_back(methods, details::make_nc_method_descriptor(U("Add item to sequence"), { 1, 5 }, U("AddSequenceItem"), U("NcMethodResultId"), parameters, false)); } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.2.html - web::json::value make_nc_worker_class() { - using web::json::value; - - return make_nc_class_descriptor(value::string(U("NcWorker class descriptor")), nc_worker_class_id, U("NcWorker"), value::null(), make_nc_worker_properties(), make_nc_worker_methods(), make_nc_worker_events()); + auto parameters = value::array(); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Property id"), nmos::fields::nc::id, U("NcPropertyId"), false, false, value::null())); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Index of item in the sequence"), nmos::fields::nc::index, U("NcId"), false, false, value::null())); + web::json::push_back(methods, details::make_nc_method_descriptor(U("Delete sequence item"), { 1, 6 }, U("RemoveSequenceItem"), U("NcMethodResult"), parameters, false)); } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.3.html - web::json::value make_nc_manager_class() { - using web::json::value; - - return make_nc_class_descriptor(value::string(U("NcManager class descriptor")), nc_manager_class_id, U("NcManager"), value::null(), make_nc_manager_properties(), make_nc_manager_methods(), make_nc_manager_events()); + auto parameters = value::array(); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Property id"), nmos::fields::nc::id, U("NcPropertyId"), false, false, value::null())); + web::json::push_back(methods, details::make_nc_method_descriptor(U("Get sequence length"), { 1, 7 }, U("GetSequenceLength"), U("NcMethodResultLength"), parameters, false)); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.3.1.html - web::json::value make_nc_device_manager_class() - { - using web::json::value; + return methods; + } + web::json::value make_nc_object_events() + { + using web::json::value; - return make_nc_class_descriptor(value::string(U("NcDeviceManager class descriptor")), nc_device_manager_class_id, U("NcDeviceManager"), value::string(U("DeviceManager")), make_nc_device_manager_properties(), make_nc_device_manager_methods(), make_nc_device_manager_events()); - } + auto events = value::array(); + web::json::push_back(events, details::make_nc_event_descriptor(U("Property changed event"), { 1, 1 }, U("PropertyChanged"), U("NcPropertyChangedEventData"), false)); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.3.2.html - web::json::value make_nc_class_manager_class() - { - using web::json::value; + return events; + } - return make_nc_class_descriptor(value::string(U("NcClassManager class descriptor")), nc_class_manager_class_id, U("NcClassManager"), value::string(U("ClassManager")), make_nc_class_manager_properties(), make_nc_class_manager_methods(), make_nc_class_manager_events()); - } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock + web::json::value make_nc_block_properties() + { + using web::json::value; - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcBlockMemberDescriptor.html - web::json::value make_nc_block_member_descriptor_datatype() - { - using web::json::value; + auto properties = value::array(); + web::json::push_back(properties, details::make_nc_property_descriptor(U("TRUE if block is functional"), { 2, 1 }, nmos::fields::nc::enabled, U("NcBoolean"), true, false, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Descriptors of this block's members"), { 2, 2 }, nmos::fields::nc::members, U("NcBlockMemberDescriptor"), true, false, true, false)); - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Role of member in its containing block")), nmos::fields::nc::role, value::string(U("NcString")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("OID of member")), nmos::fields::nc::oid, value::string(U("NcOid")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff member's OID is hardwired into device")), nmos::fields::nc::constant_oid, value::string(U("NcBoolean")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Class ID")), nmos::fields::nc::class_id, value::string(U("NcClassId")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("User label")), nmos::fields::nc::user_label, value::string(U("NcString")), true, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Containing block's OID")), nmos::fields::nc::owner, value::string(U("NcOid")), false, false)); - return make_nc_datatype_descriptor_struct(value::string(U("Descriptor which is specific to a block member")), U("NcBlockMemberDescriptor"), fields, value::string(U("NcDescriptor"))); - } + return properties; + } + web::json::value make_nc_block_methods() + { + using web::json::value; - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcClassDescriptor.html - web::json::value make_nc_class_descriptor_datatype() + auto methods = value::array(); { - using web::json::value; - - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Identity of the class")), nmos::fields::nc::class_id, value::string(U("NcClassId")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of the class")), nmos::fields::nc::name, value::string(U("NcName")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Role if the class has fixed role (manager classes)")), nmos::fields::nc::fixed_role, value::string(U("NcString")), true, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Property descriptors")), nmos::fields::nc::properties, value::string(U("NcPropertyDescriptor")), false, true)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Method descriptors")), nmos::fields::nc::methods, value::string(U("NcMethodDescriptor")), false, true)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Event descriptors")), nmos::fields::nc::events, value::string(U("NcEventDescriptor")), false, true)); - return make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class")), U("NcClassDescriptor"), fields, value::string(U("NcDescriptor"))); + auto parameters = value::array(); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("If recurse is set to true, nested members can be retrieved"), nmos::fields::nc::recurse, U("NcBoolean"), false, false, value::null())); + web::json::push_back(methods, details::make_nc_method_descriptor(U("Gets descriptors of members of the block"), { 2, 1 }, U("GetMemberDescriptors"), U("NcMethodResultBlockMemberDescriptors"), parameters, false)); } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcClassId.html - web::json::value make_nc_class_id_datatype() { - using web::json::value; - - return make_nc_datatype_typedef(value::string(U("Sequence of class ID fields")), U("NcClassId"), true, U("NcInt32")); + auto parameters = value::array(); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Relative path to search for (MUST not include the role of the block targeted by oid)"), nmos::fields::nc::path, U("NcRolePath"), false, false, value::null())); + web::json::push_back(methods, details::make_nc_method_descriptor(U("Finds member(s) by path"), { 2, 2 }, U("FindMembersByPath"), U("NcMethodResultBlockMemberDescriptors"), parameters, false)); } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptor.html - web::json::value make_nc_datatype_descriptor_datatype() { - using web::json::value; - - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Datatype name")), nmos::fields::nc::name, value::string(U("NcName")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Type: Primitive, Typedef, Struct, Enum")), nmos::fields::nc::type, value::string(U("NcDatatypeType")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Optional constraints on top of the underlying data type")), nmos::fields::nc::constraints, value::string(U("NcParameterConstraints")), true, false)); - return make_nc_datatype_descriptor_struct(value::string(U("Base datatype descriptor")), U("NcDatatypeDescriptor"), fields, value::string(U("NcDescriptor"))); + auto parameters = value::array(); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Role text to search for"), nmos::fields::nc::role, U("NcString"), false, false, value::null())); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Signals if the comparison should be case sensitive"), nmos::fields::nc::case_sensitive, U("NcBoolean"), false, false, value::null())); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("TRUE to only return exact matches"), nmos::fields::nc::match_whole_string, U("NcBoolean"), false, false, value::null())); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("TRUE to search nested blocks"), nmos::fields::nc::recurse, U("NcBoolean"), false, false, value::null())); + web::json::push_back(methods, details::make_nc_method_descriptor(U("Finds members with given role name or fragment"), { 2, 3 }, U("FindMembersByRole"), U("NcMethodResultBlockMemberDescriptors"), parameters, false)); } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptorEnum.html - web::json::value make_nc_datatype_descriptor_enum_datatype() { - using web::json::value; - - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("One item descriptor per enum option")), nmos::fields::nc::items, value::string(U("NcEnumItemDescriptor")), false, true)); - return make_nc_datatype_descriptor_struct(value::string(U("Enum datatype descriptor")), U("NcDatatypeDescriptorEnum"), fields, value::string(U("NcDatatypeDescriptor"))); + auto parameters = value::array(); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Class id to search for"), nmos::fields::nc::class_id, U("NcClassId"), false, false, value::null())); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("If TRUE it will also include derived class descriptors"), nmos::fields::nc::include_derived, U("NcBoolean"), false, false, value::null())); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("TRUE to search nested blocks"), nmos::fields::nc::recurse,U("NcBoolean"), false, false, value::null())); + web::json::push_back(methods, details::make_nc_method_descriptor(U("Finds members with given class id"), { 2, 4 }, U("FindMembersByClassId"), U("NcMethodResultBlockMemberDescriptors"), parameters, false)); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptorPrimitive.html - web::json::value make_nc_datatype_descriptor_primitive_datatype() - { - using web::json::value; + return methods; + } + web::json::value make_nc_block_events() + { + using web::json::value; - auto fields = value::array(); - return make_nc_datatype_descriptor_struct(value::string(U("Primitive datatype descriptor")), U("NcDatatypeDescriptorPrimitive"), fields, value::string(U("NcDatatypeDescriptor"))); - } + return value::array(); + } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptorStruct.html - web::json::value make_nc_datatype_descriptor_struct_datatype() - { - using web::json::value; + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncworker + web::json::value make_nc_worker_properties() + { + using web::json::value; - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("One item descriptor per field of the struct")), nmos::fields::nc::fields, value::string(U("NcFieldDescriptor")), false, true)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of the parent type if any or null if it has no parent")), nmos::fields::nc::parent_type, value::string(U("NcName")), true, false)); - return make_nc_datatype_descriptor_struct(value::string(U("Struct datatype descriptor")), U("NcDatatypeDescriptorStruct"), fields, value::string(U("NcDatatypeDescriptor"))); - } + auto properties = value::array(); + web::json::push_back(properties, details::make_nc_property_descriptor(U("TRUE iff worker is enabled"), { 2, 1 }, nmos::fields::nc::enabled, U("NcBoolean"), false, false, false, false)); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptorTypeDef.html - web::json::value make_nc_datatype_descriptor_type_def_datatype() - { - using web::json::value; + return properties; + } + web::json::value make_nc_worker_methods() + { + using web::json::value; - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Original typedef datatype name")), nmos::fields::nc::parent_type, value::string(U("NcName")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff type is a typedef sequence of another type")), nmos::fields::nc::is_sequence, value::string(U("NcBoolean")), false, false)); - return make_nc_datatype_descriptor_struct(value::string(U("Type def datatype descriptor")), U("NcDatatypeDescriptorTypeDef"), fields, value::string(U("NcDatatypeDescriptor"))); - } + return value::array(); + } + web::json::value make_nc_worker_events() + { + using web::json::value; - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeType.html - web::json::value make_nc_datatype_type_datatype() - { - using web::json::value; + return value::array(); + } - auto items = value::array(); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Primitive datatype")), U("Primitive"), 0)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Simple alias of another datatype")), U("Typedef"), 1)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Data structure")), U("Struct"), 2)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Enum datatype")), U("Enum"), 3)); - return make_nc_datatype_descriptor_enum(value::string(U("Datatype type")), U("NcDatatypeType"), items); - } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanager + web::json::value make_nc_manager_properties() + { + using web::json::value; - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDescriptor.html - web::json::value make_nc_descriptor_datatype() - { - using web::json::value; + return value::array(); + } + web::json::value make_nc_manager_methods() + { + using web::json::value; - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Optional user facing description")), nmos::fields::nc::description, value::string(U("NcString")), true, false)); - return make_nc_datatype_descriptor_struct(value::string(U("Base descriptor")), U("NcDescriptor"), fields, value::null()); - } + return value::array(); + } + web::json::value make_nc_manager_events() + { + using web::json::value; - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDeviceGenericState.html - web::json::value make_nc_device_generic_state_datatype() - { - using web::json::value; + return value::array(); + } - auto items = value::array(); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Unknown")), U("Unknown"), 0)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Normal operation")), U("NormalOperation"), 1)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Device is initializing")), U("Initializing"), 2)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Device is performing a software or firmware update")), U("Updating"), 3)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Device is experiencing a licensing error")), U("LicensingError"), 4)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Device is experiencing an internal error")), U("InternalError"), 5)); - return make_nc_datatype_descriptor_enum(value::string(U("Device generic operational state")), U("NcDeviceGenericState"), items); - } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager + web::json::value make_nc_device_manager_properties() + { + using web::json::value; + + auto properties = value::array(); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Version of MS-05-02 that this device uses"), { 3, 1 }, nmos::fields::nc::nc_version, U("NcVersionCode"), true, false, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Manufacturer descriptor"), { 3, 2 }, nmos::fields::nc::manufacturer, U("NcManufacturer"), true, false, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Product descriptor"), { 3, 3 }, nmos::fields::nc::product, U("NcProduct"), true, false, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Serial number"), { 3, 4 }, nmos::fields::nc::serial_number, U("NcString"), true, false, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Asset tracking identifier (user specified)"), { 3, 5 }, nmos::fields::nc::user_inventory_code, U("NcString"), false, true, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Name of this device in the application. Instance name, not product name"), { 3, 6 }, nmos::fields::nc::device_name, U("NcString"), false, true, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Role of this device in the application"), { 3, 7 }, nmos::fields::nc::device_role, U("NcString"), false, true, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Device operational state"), { 3, 8 }, nmos::fields::nc::operational_state, U("NcDeviceOperationalState"), true, false, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Reason for most recent reset"), { 3, 9 }, nmos::fields::nc::reset_cause, U("NcResetCause"), true, false, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Arbitrary message from dev to controller"), { 3, 10 }, nmos::fields::nc::message, U("NcString"), true, true, false, false)); + + return properties; + } + web::json::value make_nc_device_manager_methods() + { + using web::json::value; - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDeviceOperationalState.html - web::json::value make_nc_device_operational_state_datatype() - { - using web::json::value; + return value::array(); + } + web::json::value make_nc_device_manager_events() + { + using web::json::value; - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Generic operational state")), nmos::fields::nc::generic_state, value::string(U("NcDeviceGenericState")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Specific device details")), nmos::fields::nc::device_specific_details, value::string(U("NcString")), true, false)); - return make_nc_datatype_descriptor_struct(value::string(U("Device operational state")), U("NcDeviceOperationalState"), fields, value::null()); - } + return value::array(); + } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcElementId.html - web::json::value make_nc_element_id_datatype() - { - using web::json::value; + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager + web::json::value make_nc_class_manager_properties() + { + using web::json::value; - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Level of the element")), nmos::fields::nc::level, value::string(U("NcUint16")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Index of the element")), nmos::fields::nc::index, value::string(U("NcUint16")), false, false)); - return make_nc_datatype_descriptor_struct(value::string(U("Class element id which contains the level and index")), U("NcElementId"), fields, value::null()); - } + auto properties = value::array(); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Descriptions of all control classes in the device (descriptors do not contain inherited elements)"), { 3, 1 }, nmos::fields::nc::control_classes, U("NcClassDescriptor"), true, false, true, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Descriptions of all data types in the device (descriptors do not contain inherited elements)"), { 3, 2 }, nmos::fields::nc::datatypes, U("NcDatatypeDescriptor"), true, false, true, false)); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcEnumItemDescriptor.html - web::json::value make_nc_enum_item_descriptor_datatype() - { - using web::json::value; + return properties; + } + web::json::value make_nc_class_manager_methods() + { + using web::json::value; - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of option")), nmos::fields::nc::name, value::string(U("NcName")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Enum item numerical value")), nmos::fields::nc::value, value::string(U("NcUint16")), false, false)); - return make_nc_datatype_descriptor_struct(value::string(U("Descriptor of an enum item")), U("NcEnumItemDescriptor"), fields, value::string(U("NcDescriptor"))); + auto methods = value::array(); + { + auto parameters = value::array(); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("class ID"), nmos::fields::nc::class_id, U("NcClassId"), false, false, value::null())); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("If set the descriptor would contain all inherited elements"), nmos::fields::nc::include_inherited, U("NcBoolean"), false, false, value::null())); + web::json::push_back(methods, details::make_nc_method_descriptor(U("Get a single class descriptor"), { 3, 1 }, U("GetControlClass"), U("NcMethodResultClassDescriptor"), parameters, false)); } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcEventDescriptor.html - web::json::value make_nc_event_descriptor_datatype() { - using web::json::value; - - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Event id with level and index")), nmos::fields::nc::id, value::string(U("NcEventId")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of event")), nmos::fields::nc::name, value::string(U("NcName")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of event data's datatype")), nmos::fields::nc::event_datatype, value::string(U("NcName")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff property is marked as deprecated")), nmos::fields::nc::is_deprecated, value::string(U("NcBoolean")), false, false)); - return make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class event")), U("NcEventDescriptor"), fields, value::string(U("NcDescriptor"))); + auto parameters = value::array(); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("name of datatype"), nmos::fields::nc::name, U("NcName"), false, false, value::null())); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("If set the descriptor would contain all inherited elements"), nmos::fields::nc::include_inherited, U("NcBoolean"), false, false, value::null())); + web::json::push_back(methods, details::make_nc_method_descriptor(U("Get a single datatype descriptor"), { 3, 2 }, U("GetDatatype"), U("NcMethodResultDatatypeDescriptor"), parameters, false)); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcEventId.html - web::json::value make_nc_event_id_datatype() - { - using web::json::value; + return methods; + } + web::json::value make_nc_class_manager_events() + { + using web::json::value; - return make_nc_datatype_descriptor_struct(value::string(U("Event id which contains the level and index")), U("NcEventId"), value::array(), value::string(U("NcElementId"))); - } + return value::array(); + } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcFieldDescriptor.html - web::json::value make_nc_field_descriptor_datatype() - { - using web::json::value; + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitor + web::json::value make_nc_receiver_monitor_properties() + { + using web::json::value; - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of field")), nmos::fields::nc::name, value::string(U("NcName")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of field's datatype. Can only ever be null if the type is any")), nmos::fields::nc::type_name, value::string(U("NcName")), true, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff field is nullable")), nmos::fields::nc::is_nullable, value::string(U("NcBoolean")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff field is a sequence")), nmos::fields::nc::is_sequence, value::string(U("NcBoolean")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Optional constraints on top of the underlying data type")), nmos::fields::nc::constraints, value::string(U("NcParameterConstraints")), true, false)); - return make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a field of a struct")), U("NcFieldDescriptor"), fields, value::string(U("NcDescriptor"))); - } + auto properties = value::array(); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Connection status property"), { 3, 1 }, nmos::fields::nc::connection_status, U("NcConnectionStatus"), true, false, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Connection status message property"), { 3, 2 }, nmos::fields::nc::connection_status_message, U("NcString"), true, true, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Payload status property"), { 3, 3 }, nmos::fields::nc::payload_status, U("NcPayloadStatus"), true, false, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Payload status message property"), { 3, 4 }, nmos::fields::nc::payload_status_message, U("NcString"), true, true, false, false)); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcId.html - web::json::value make_nc_id_datatype() - { - using web::json::value; + return properties; + } + web::json::value make_nc_receiver_monitor_methods() + { + using web::json::value; - return make_nc_datatype_typedef(value::string(U("Identity handler")), U("NcId"), false, U("NcUint32")); - } + return value::array(); + } + web::json::value make_nc_receiver_monitor_events() + { + using web::json::value; - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcManufacturer.html - web::json::value make_nc_manufacturer_datatype() - { - using web::json::value; + return value::array(); + } - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Manufacturer's name")), nmos::fields::nc::name, value::string(U("NcString")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("IEEE OUI or CID of manufacturer")), nmos::fields::nc::organization_id, value::string(U("NcOrganizationId")), true, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("URL of the manufacturer's website")), nmos::fields::nc::website, value::string(U("NcUri")), true, false)); - return make_nc_datatype_descriptor_struct(value::string(U("Manufacturer descriptor")), U("NcManufacturer"), fields, value::null()); - } + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitorprotected + web::json::value make_nc_receiver_monitor_protected_properties() + { + using web::json::value; - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodDescriptor.html - web::json::value make_nc_method_descriptor_datatype() - { - using web::json::value; + auto properties = value::array(); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Indicates if signal protection is active"), { 4, 1 }, nmos::fields::nc::signal_protection_status, U("NcBoolean"), true, false, false, false)); - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Method id with level and index")), nmos::fields::nc::id, value::string(U("NcMethodId")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of method")), nmos::fields::nc::name, value::string(U("NcName")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of method result's datatype")), nmos::fields::nc::result_datatype, value::string(U("NcName")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Parameter descriptors if any")), nmos::fields::nc::parameters, value::string(U("NcParameterDescriptor")), false, true)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff property is marked as deprecated")), nmos::fields::nc::is_deprecated, value::string(U("NcBoolean")), false, false)); - return make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class method")), U("NcMethodDescriptor"), fields, value::string(U("NcDescriptor"))); - } + return properties; + } + web::json::value make_nc_receiver_monitor_protected_methods() + { + using web::json::value; - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodId.html - web::json::value make_nc_method_id_datatype() - { - using web::json::value; + return value::array(); + } + web::json::value make_nc_receiver_monitor_protected_events() + { + using web::json::value; - return make_nc_datatype_descriptor_struct(value::string(U("Method id which contains the level and index")), U("NcMethodId"), value::array(), value::string(U("NcElementId"))); - } + return value::array(); + } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResult.html - web::json::value make_nc_method_result_datatype() - { - using web::json::value; + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/identification/#ncidentbeacon + web::json::value make_nc_ident_beacon_properties() + { + using web::json::value; - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Status for the invoked method")), nmos::fields::nc::status, value::string(U("NcMethodStatus")), false, false)); - return make_nc_datatype_descriptor_struct(value::string(U("Base result of the invoked method")), U("NcMethodResult"), fields, value::null()); - } + auto properties = value::array(); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Indicator active state"), { 3, 1 }, nmos::fields::nc::active, U("NcBoolean"), false, false, false, false)); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultBlockMemberDescriptors.html - web::json::value make_nc_method_result_block_member_descriptors_datatype() - { - using web::json::value; + return properties; + } + web::json::value make_nc_ident_beacon_methods() + { + using web::json::value; - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Block member descriptors method result value")), nmos::fields::nc::value, value::string(U("NcBlockMemberDescriptor")), false, true)); - return make_nc_datatype_descriptor_struct(value::string(U("Method result containing block member descriptors as the value")), U("NcMethodResultBlockMemberDescriptors"), fields, value::string(U("NcMethodResult"))); - } + return value::array(); + } + web::json::value make_nc_ident_beacon_events() + { + using web::json::value; - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultClassDescriptor.html - web::json::value make_nc_method_result_class_descriptor_datatype() - { - using web::json::value; + return value::array(); + } - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Class descriptor method result value")), nmos::fields::nc::value, value::string(U("NcClassDescriptor")), false, false)); - return make_nc_datatype_descriptor_struct(value::string(U("Method result containing a class descriptor as the value")), U("NcMethodResultClassDescriptor"), fields, value::string(U("NcMethodResult"))); - } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.html + web::json::value make_nc_object_class() + { + using web::json::value; - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultDatatypeDescriptor.html - web::json::value make_nc_method_result_datatype_descriptor_datatype() - { - using web::json::value; + return details::make_nc_class_descriptor(value::string(U("NcObject class descriptor")), nc_object_class_id, U("NcObject"), value::null(), make_nc_object_properties(), make_nc_object_methods(), make_nc_object_events()); + } - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Datatype descriptor method result value")), nmos::fields::nc::value, value::string(U("NcDatatypeDescriptor")), false, false)); - return make_nc_datatype_descriptor_struct(value::string(U("Method result containing a datatype descriptor as the value")), U("NcMethodResultDatatypeDescriptor"), fields, value::string(U("NcMethodResult"))); - } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.1.html + web::json::value make_nc_block_class() + { + using web::json::value; - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultError.html - web::json::value make_nc_method_result_error_datatype() - { - using web::json::value; + return details::make_nc_class_descriptor(value::string(U("NcBlock class descriptor")), nc_block_class_id, U("NcBlock"), value::null(), make_nc_block_properties(), make_nc_block_methods(), make_nc_block_events()); + } - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Error message")), nmos::fields::nc::error_message, value::string(U("NcString")), false, false)); - return make_nc_datatype_descriptor_struct(value::string(U("Error result - to be used when the method call encounters an error")), U("NcMethodResultError"), fields, value::string(U("NcMethodResult"))); - } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.2.html + web::json::value make_nc_worker_class() + { + using web::json::value; - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultId.html - web::json::value make_nc_method_result_id_datatype() - { - using web::json::value; + return details::make_nc_class_descriptor(value::string(U("NcWorker class descriptor")), nc_worker_class_id, U("NcWorker"), value::null(), make_nc_worker_properties(), make_nc_worker_methods(), make_nc_worker_events()); + } - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Id result value")), nmos::fields::nc::value, value::string(U("NcId")), false, false)); - return make_nc_datatype_descriptor_struct(value::string(U("Id method result")), U("NcMethodResultId"), fields, value::string(U("NcMethodResult"))); - } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.3.html + web::json::value make_nc_manager_class() + { + using web::json::value; - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultLength.html - web::json::value make_nc_method_result_length_datatype() - { - using web::json::value; + return details::make_nc_class_descriptor(value::string(U("NcManager class descriptor")), nc_manager_class_id, U("NcManager"), value::null(), make_nc_manager_properties(), make_nc_manager_methods(), make_nc_manager_events()); + } - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Length result value")), nmos::fields::nc::value, value::string(U("NcUint32")), true, false)); - return make_nc_datatype_descriptor_struct(value::string(U("Length method result")), U("NcMethodResultLength"), fields, value::string(U("NcMethodResult"))); - } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.3.1.html + web::json::value make_nc_device_manager_class() + { + using web::json::value; - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultPropertyValue.html - web::json::value make_nc_method_result_property_value_datatype() - { - using web::json::value; + return details::make_nc_class_descriptor(value::string(U("NcDeviceManager class descriptor")), nc_device_manager_class_id, U("NcDeviceManager"), value::string(U("DeviceManager")), make_nc_device_manager_properties(), make_nc_device_manager_methods(), make_nc_device_manager_events()); + } - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Getter method value for the associated property")), nmos::fields::nc::value, value::null(), true, false)); - return make_nc_datatype_descriptor_struct(value::string(U("Result when invoking the getter method associated with a property")), U("NcMethodResultPropertyValue"), fields, value::string(U("NcMethodResult"))); - } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.3.2.html + web::json::value make_nc_class_manager_class() + { + using web::json::value; - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodStatus.html - web::json::value make_nc_method_status_datatype() - { - using web::json::value; + return details::make_nc_class_descriptor(value::string(U("NcClassManager class descriptor")), nc_class_manager_class_id, U("NcClassManager"), value::string(U("ClassManager")), make_nc_class_manager_properties(), make_nc_class_manager_methods(), make_nc_class_manager_events()); + } - auto items = value::array(); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Method call was successful")), U("Ok"), 200)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Method call was successful but targeted property is deprecated")), U("PropertyDeprecated"), 298)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Method call was successful but method is deprecated")), U("MethodDeprecated"), 299)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Badly-formed command (e.g. the incoming command has invalid message encoding and cannot be parsed by the underlying protocol)")), U("BadCommandFormat"), 400)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Client is not authorized")), U("Unauthorized"), 401)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Command addresses a nonexistent object")), U("BadOid"), 404)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Attempt to change read-only state")), U("Readonly"), 405)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Method call is invalid in current operating context (e.g. attempting to invoke a method when the object is disabled)")), U("InvalidRequest"), 406)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("There is a conflict with the current state of the device")), U("Conflict"), 409)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Something was too big")), U("BufferOverflow"), 413)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Index is outside the available range")), U("IndexOutOfBounds"), 414)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Method parameter does not meet expectations (e.g. attempting to invoke a method with an invalid type for one of its parameters)")), U("ParameterError"), 417)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Addressed object is locked")), U("Locked"), 423)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Internal device error")), U("DeviceError"), 500)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Addressed method is not implemented by the addressed object")), U("MethodNotImplemented"), 501)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Addressed property is not implemented by the addressed object")), U("PropertyNotImplemented"), 502)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("The device is not ready to handle any commands")), U("NotReady"), 503)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Method call did not finish within the allotted time")), U("Timeout"), 504)); - return make_nc_datatype_descriptor_enum(value::string(U("Method invokation status")), U("NcMethodStatus"), items); - } + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/identification/#ncidentbeacon + web::json::value make_nc_ident_beacon_class() + { + using web::json::value; - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcName.html - web::json::value make_nc_name_datatype() - { - using web::json::value; + return details::make_nc_class_descriptor(value::string(U("NcIdentBeacon class descriptor")), nc_ident_beacon_class_id, U("NcIdentBeacon"), value::null(), make_nc_ident_beacon_properties(), make_nc_ident_beacon_methods(), make_nc_ident_beacon_events()); + } - return make_nc_datatype_typedef(value::string(U("Programmatically significant name, alphanumerics + underscore, no spaces")), U("NcName"), false, U("NcString")); - } + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitor + web::json::value make_nc_receiver_monitor_class() + { + using web::json::value; - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcOid.html - web::json::value make_nc_oid_datatype() - { - using web::json::value; + return details::make_nc_class_descriptor(value::string(U("NcReceiverMonitor class descriptor")), nc_receiver_monitor_class_id, U("NcReceiverMonitor"), value::null(), make_nc_receiver_monitor_properties(), make_nc_receiver_monitor_methods(), make_nc_receiver_monitor_events()); + } - return make_nc_datatype_typedef(value::string(U("Object id")), U("NcOid"), false, U("NcUint32")); - } + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitorprotected + web::json::value make_nc_receiver_monitor_protected_class() + { + using web::json::value; - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcOrganizationId.html - web::json::value make_nc_organization_id_datatype() - { - using web::json::value; + return details::make_nc_class_descriptor(value::string(U("NcReceiverMonitorProtected class descriptor")), nc_receiver_monitor_protected_class_id, U("NcReceiverMonitorProtected"), value::null(), make_nc_receiver_monitor_protected_properties(), make_nc_receiver_monitor_protected_methods(), make_nc_receiver_monitor_protected_events()); + } - return make_nc_datatype_typedef(value::string(U("Unique 24-bit organization id")), U("NcOrganizationId"), false, U("NcInt32")); - } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcBlockMemberDescriptor.html + web::json::value make_nc_block_member_descriptor_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Role of member in its containing block")), nmos::fields::nc::role, value::string(U("NcString")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("OID of member")), nmos::fields::nc::oid, value::string(U("NcOid")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff member's OID is hardwired into device")), nmos::fields::nc::constant_oid, value::string(U("NcBoolean")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Class ID")), nmos::fields::nc::class_id, value::string(U("NcClassId")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("User label")), nmos::fields::nc::user_label, value::string(U("NcString")), true, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Containing block's OID")), nmos::fields::nc::owner, value::string(U("NcOid")), false, false)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor which is specific to a block member")), U("NcBlockMemberDescriptor"), fields, value::string(U("NcDescriptor"))); + } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcParameterConstraints.html - web::json::value make_nc_parameter_constraints_datatype() - { - using web::json::value; + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcClassDescriptor.html + web::json::value make_nc_class_descriptor_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Identity of the class")), nmos::fields::nc::class_id, value::string(U("NcClassId")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of the class")), nmos::fields::nc::name, value::string(U("NcName")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Role if the class has fixed role (manager classes)")), nmos::fields::nc::fixed_role, value::string(U("NcString")), true, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Property descriptors")), nmos::fields::nc::properties, value::string(U("NcPropertyDescriptor")), false, true)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Method descriptors")), nmos::fields::nc::methods, value::string(U("NcMethodDescriptor")), false, true)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Event descriptors")), nmos::fields::nc::events, value::string(U("NcEventDescriptor")), false, true)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class")), U("NcClassDescriptor"), fields, value::string(U("NcDescriptor"))); + } - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Default value")), nmos::fields::nc::default_value, value::null(), true, false)); - return make_nc_datatype_descriptor_struct(value::string(U("Abstract parameter constraints class")), U("NcParameterConstraints"), fields, value::null()); - } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcClassId.html + web::json::value make_nc_class_id_datatype() + { + using web::json::value; - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcParameterConstraintsNumber.html - web::json::value make_nc_parameter_constraints_number_datatype() - { - using web::json::value; + return details::make_nc_datatype_typedef(value::string(U("Sequence of class ID fields")), U("NcClassId"), true, U("NcInt32")); + } - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Optional maximum")), nmos::fields::nc::maximum, value::null(), true, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Optional minimum")), nmos::fields::nc::minimum, value::null(), true, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Optional step")), nmos::fields::nc::step, value::null(), true, false)); - return make_nc_datatype_descriptor_struct(value::string(U("Number parameter constraints class")), U("NcParameterConstraintsNumber"), fields, value::string(U("NcParameterConstraints"))); - } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptor.html + web::json::value make_nc_datatype_descriptor_datatype() + { + using web::json::value; - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcParameterConstraintsString.html - web::json::value make_nc_parameter_constraints_string_datatype() - { - using web::json::value; + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Datatype name")), nmos::fields::nc::name, value::string(U("NcName")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Type: Primitive, Typedef, Struct, Enum")), nmos::fields::nc::type, value::string(U("NcDatatypeType")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional constraints on top of the underlying data type")), nmos::fields::nc::constraints, value::string(U("NcParameterConstraints")), true, false)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Base datatype descriptor")), U("NcDatatypeDescriptor"), fields, value::string(U("NcDescriptor"))); + } - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Maximum characters allowed")), nmos::fields::nc::max_characters, value::string(U("NcUint32")), true, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Regex pattern")), nmos::fields::nc::pattern, value::string(U("NcRegex")), true, false)); - return make_nc_datatype_descriptor_struct(value::string(U("String parameter constraints class")), U("NcParameterConstraintsString"), fields, value::string(U("NcParameterConstraints"))); - } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptorEnum.html + web::json::value make_nc_datatype_descriptor_enum_datatype() + { + using web::json::value; - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcParameterDescriptor.html - web::json::value make_nc_parameter_descriptor_datatype() - { - using web::json::value; + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("One item descriptor per enum option")), nmos::fields::nc::items, value::string(U("NcEnumItemDescriptor")), false, true)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Enum datatype descriptor")), U("NcDatatypeDescriptorEnum"), fields, value::string(U("NcDatatypeDescriptor"))); + } - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of parameter")), nmos::fields::nc::name, value::string(U("NcName")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of parameter's datatype. Can only ever be null if the type is any")), nmos::fields::nc::type_name, value::string(U("NcName")), true, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff property is nullable")), nmos::fields::nc::is_nullable, value::string(U("NcBoolean")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff property is a sequence")), nmos::fields::nc::is_sequence, value::string(U("NcBoolean")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Optional constraints on top of the underlying data type")), nmos::fields::nc::constraints, value::string(U("NcParameterConstraints")), true, false)); - return make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a method parameter")), U("NcParameterDescriptor"), fields, value::string(U("NcDescriptor"))); - } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptorPrimitive.html + web::json::value make_nc_datatype_descriptor_primitive_datatype() + { + using web::json::value; - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcProduct.html - web::json::value make_nc_product_datatype() - { - using web::json::value; + auto fields = value::array(); + return details::make_nc_datatype_descriptor_struct(value::string(U("Primitive datatype descriptor")), U("NcDatatypeDescriptorPrimitive"), fields, value::string(U("NcDatatypeDescriptor"))); + } - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Product name")), nmos::fields::nc::name, value::string(U("NcString")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Manufacturer's unique key to product - model number, SKU, etc")), nmos::fields::nc::key, value::string(U("NcString")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Manufacturer's product revision level code")), nmos::fields::nc::revision_level, value::string(U("NcString")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Brand name under which product is sold")), nmos::fields::nc::brand_name, value::string(U("NcString")), true, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Unique UUID of product (not product instance)")), nmos::fields::nc::uuid, value::string(U("NcUuid")), true, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Text description of product")), nmos::fields::nc::description, value::string(U("NcString")), true, false)); - return make_nc_datatype_descriptor_struct(value::string(U("Product descriptor")), U("NcProduct"), fields, value::null()); - } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptorStruct.html + web::json::value make_nc_datatype_descriptor_struct_datatype() + { + using web::json::value; - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyChangeType.html - web::json::value make_nc_property_change_type_datatype() - { - using web::json::value; + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("One item descriptor per field of the struct")), nmos::fields::nc::fields, value::string(U("NcFieldDescriptor")), false, true)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of the parent type if any or null if it has no parent")), nmos::fields::nc::parent_type, value::string(U("NcName")), true, false)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Struct datatype descriptor")), U("NcDatatypeDescriptorStruct"), fields, value::string(U("NcDatatypeDescriptor"))); + } - auto items = value::array(); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Current value changed")), U("ValueChanged"), 0)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Sequence item added")), U("SequenceItemAdded"), 1)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Sequence item changed")), U("SequenceItemChanged"), 2)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Sequence item removed")), U("SequenceItemRemoved"), 3)); - return make_nc_datatype_descriptor_enum(value::string(U("Type of property change")), U("NcPropertyChangeType"), items); - } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptorTypeDef.html + web::json::value make_nc_datatype_descriptor_type_def_datatype() + { + using web::json::value; - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyChangedEventData.html - web::json::value make_nc_property_changed_event_data_datatype() - { - using web::json::value; + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Original typedef datatype name")), nmos::fields::nc::parent_type, value::string(U("NcName")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff type is a typedef sequence of another type")), nmos::fields::nc::is_sequence, value::string(U("NcBoolean")), false, false)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Type def datatype descriptor")), U("NcDatatypeDescriptorTypeDef"), fields, value::string(U("NcDatatypeDescriptor"))); + } - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("The id of the property that changed")), nmos::fields::nc::property_id, value::string(U("NcPropertyId")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Information regarding the change type")), nmos::fields::nc::change_type, value::string(U("NcPropertyChangeType")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Property-type specific value")), nmos::fields::nc::value, value::null(), true, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Index of sequence item if the property is a sequence")), nmos::fields::nc::sequence_item_index, value::string(U("NcId")), true, false)); - return make_nc_datatype_descriptor_struct(value::string(U("Payload of property-changed event")), U("NcPropertyChangedEventData"), fields, value::null()); - } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeType.html + web::json::value make_nc_datatype_type_datatype() + { + using web::json::value; + + auto items = value::array(); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Primitive datatype")), U("Primitive"), 0)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Simple alias of another datatype")), U("Typedef"), 1)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Data structure")), U("Struct"), 2)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Enum datatype")), U("Enum"), 3)); + return details::make_nc_datatype_descriptor_enum(value::string(U("Datatype type")), U("NcDatatypeType"), items); + } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyConstraints.html - web::json::value make_nc_property_contraints_datatype() - { - using web::json::value; + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDescriptor.html + web::json::value make_nc_descriptor_datatype() + { + using web::json::value; - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("The id of the property being constrained")), nmos::fields::nc::property_id, value::string(U("NcPropertyId")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Optional default value")), nmos::fields::nc::default_value, value::null(), true, false)); - return make_nc_datatype_descriptor_struct(value::string(U("Property constraints class")), U("NcPropertyConstraints"), fields, value::null()); - } + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional user facing description")), nmos::fields::nc::description, value::string(U("NcString")), true, false)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Base descriptor")), U("NcDescriptor"), fields, value::null()); + } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyConstraintsNumber.html - web::json::value make_nc_property_constraints_number_datatype() - { - using web::json::value; + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDeviceGenericState.html + web::json::value make_nc_device_generic_state_datatype() + { + using web::json::value; + + auto items = value::array(); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Unknown")), U("Unknown"), 0)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Normal operation")), U("NormalOperation"), 1)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Device is initializing")), U("Initializing"), 2)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Device is performing a software or firmware update")), U("Updating"), 3)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Device is experiencing a licensing error")), U("LicensingError"), 4)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Device is experiencing an internal error")), U("InternalError"), 5)); + return details::make_nc_datatype_descriptor_enum(value::string(U("Device generic operational state")), U("NcDeviceGenericState"), items); + } - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Optional maximum")), nmos::fields::nc::maximum, value::null(), true, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Optional minimum")), nmos::fields::nc::minimum, value::null(), true, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Optional step")), nmos::fields::nc::step, value::null(), true, false)); - return make_nc_datatype_descriptor_struct(value::string(U("Number property constraints class")), U("NcPropertyConstraintsNumber"), fields, value::string(U("NcPropertyConstraints"))); - } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDeviceOperationalState.html + web::json::value make_nc_device_operational_state_datatype() + { + using web::json::value; - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyConstraintsString.html - web::json::value make_nc_property_constraints_string_datatype() - { - using web::json::value; + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Generic operational state")), nmos::fields::nc::generic_state, value::string(U("NcDeviceGenericState")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Specific device details")), nmos::fields::nc::device_specific_details, value::string(U("NcString")), true, false)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Device operational state")), U("NcDeviceOperationalState"), fields, value::null()); + } - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Maximum characters allowed")), nmos::fields::nc::max_characters, value::string(U("NcUint32")), true, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Regex pattern")), nmos::fields::nc::pattern, value::string(U("NcRegex")), true, false)); - return make_nc_datatype_descriptor_struct(value::string(U("String property constraints class")), U("NcPropertyConstraintsString"), fields, value::string(U("NcPropertyConstraints"))); - } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcElementId.html + web::json::value make_nc_element_id_datatype() + { + using web::json::value; - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyDescriptor.html - web::json::value make_nc_property_descriptor_datatype() - { - using web::json::value; + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Level of the element")), nmos::fields::nc::level, value::string(U("NcUint16")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Index of the element")), nmos::fields::nc::index, value::string(U("NcUint16")), false, false)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Class element id which contains the level and index")), U("NcElementId"), fields, value::null()); + } - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Property id with level and index")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of property")), nmos::fields::nc::name, value::string(U("NcName")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Name of property's datatype. Can only ever be null if the type is any")), nmos::fields::nc::type_name, value::string(U("NcName")), true, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff property is read-only")), nmos::fields::nc::is_read_only, value::string(U("NcBoolean")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff property is nullable")), nmos::fields::nc::is_nullable, value::string(U("NcBoolean")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff property is a sequence")), nmos::fields::nc::is_sequence, value::string(U("NcBoolean")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("TRUE iff property is marked as deprecated")), nmos::fields::nc::is_deprecated, value::string(U("NcBoolean")), false, false)); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Optional constraints on top of the underlying data type")), nmos::fields::nc::constraints, value::string(U("NcParameterConstraints")), true, false)); - return make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class property")), U("NcPropertyDescriptor"), fields, value::string(U("NcDescriptor"))); - } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcEnumItemDescriptor.html + web::json::value make_nc_enum_item_descriptor_datatype() + { + using web::json::value; - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyId.html - web::json::value make_nc_property_id_datatype() - { - using web::json::value; + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of option")), nmos::fields::nc::name, value::string(U("NcName")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Enum item numerical value")), nmos::fields::nc::value, value::string(U("NcUint16")), false, false)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of an enum item")), U("NcEnumItemDescriptor"), fields, value::string(U("NcDescriptor"))); + } - return make_nc_datatype_descriptor_struct(value::string(U("Property id which contains the level and index")), U("NcPropertyId"), value::array(), value::string(U("NcElementId"))); - } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcEventDescriptor.html + web::json::value make_nc_event_descriptor_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Event id with level and index")), nmos::fields::nc::id, value::string(U("NcEventId")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of event")), nmos::fields::nc::name, value::string(U("NcName")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of event data's datatype")), nmos::fields::nc::event_datatype, value::string(U("NcName")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is marked as deprecated")), nmos::fields::nc::is_deprecated, value::string(U("NcBoolean")), false, false)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class event")), U("NcEventDescriptor"), fields, value::string(U("NcDescriptor"))); + } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcRegex.html - web::json::value make_nc_regex_datatype() - { - using web::json::value; + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcEventId.html + web::json::value make_nc_event_id_datatype() + { + using web::json::value; - return make_nc_datatype_typedef(value::string(U("Regex pattern")), U("NcRegex"), false, U("NcString")); - } + return details::make_nc_datatype_descriptor_struct(value::string(U("Event id which contains the level and index")), U("NcEventId"), value::array(), value::string(U("NcElementId"))); + } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcResetCause.html - web::json::value make_nc_reset_cause_datatype() - { - using web::json::value; + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcFieldDescriptor.html + web::json::value make_nc_field_descriptor_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of field")), nmos::fields::nc::name, value::string(U("NcName")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of field's datatype. Can only ever be null if the type is any")), nmos::fields::nc::type_name, value::string(U("NcName")), true, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff field is nullable")), nmos::fields::nc::is_nullable, value::string(U("NcBoolean")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff field is a sequence")), nmos::fields::nc::is_sequence, value::string(U("NcBoolean")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional constraints on top of the underlying data type")), nmos::fields::nc::constraints, value::string(U("NcParameterConstraints")), true, false)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a field of a struct")), U("NcFieldDescriptor"), fields, value::string(U("NcDescriptor"))); + } - auto items = value::array(); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Unknown")), U("Unknown"), 0)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Power on")), U("PowerOn"), 1)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Internal error")), U("InternalError"), 2)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Upgrade")), U("Upgrade"), 3)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Controller request")), U("ControllerRequest"), 4)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Manual request from the front panel")), U("ManualReset"), 5)); - return make_nc_datatype_descriptor_enum(value::string(U("Reset cause enum")), U("NcResetCause"), items); - } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcId.html + web::json::value make_nc_id_datatype() + { + using web::json::value; - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcRolePath.html - web::json::value make_nc_role_path_datatype() - { - using web::json::value; + return details::make_nc_datatype_typedef(value::string(U("Identity handler")), U("NcId"), false, U("NcUint32")); + } - return make_nc_datatype_typedef(value::string(U("Role path")), U("NcRolePath"), true, U("NcString")); - } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcManufacturer.html + web::json::value make_nc_manufacturer_datatype() + { + using web::json::value; - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTimeInterval.html - web::json::value make_nc_time_interval_datatype() - { - using web::json::value; + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Manufacturer's name")), nmos::fields::nc::name, value::string(U("NcString")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("IEEE OUI or CID of manufacturer")), nmos::fields::nc::organization_id, value::string(U("NcOrganizationId")), true, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("URL of the manufacturer's website")), nmos::fields::nc::website, value::string(U("NcUri")), true, false)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Manufacturer descriptor")), U("NcManufacturer"), fields, value::null()); + } - return make_nc_datatype_typedef(value::string(U("Time interval described in nanoseconds")), U("NcTimeInterval"), false, U("NcInt64")); - } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodDescriptor.html + web::json::value make_nc_method_descriptor_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Method id with level and index")), nmos::fields::nc::id, value::string(U("NcMethodId")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of method")), nmos::fields::nc::name, value::string(U("NcName")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of method result's datatype")), nmos::fields::nc::result_datatype, value::string(U("NcName")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Parameter descriptors if any")), nmos::fields::nc::parameters, value::string(U("NcParameterDescriptor")), false, true)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is marked as deprecated")), nmos::fields::nc::is_deprecated, value::string(U("NcBoolean")), false, false)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class method")), U("NcMethodDescriptor"), fields, value::string(U("NcDescriptor"))); + } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpoint.html - web::json::value make_nc_touchpoint_datatype() - { - using web::json::value; + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodId.html + web::json::value make_nc_method_id_datatype() + { + using web::json::value; - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Context namespace")), nmos::fields::nc::context_namespace, value::string(U("NcString")), false, false)); - return make_nc_datatype_descriptor_struct(value::string(U("Base touchpoint class")), U("NcTouchpoint"), fields, value::null()); - } + return details::make_nc_datatype_descriptor_struct(value::string(U("Method id which contains the level and index")), U("NcMethodId"), value::array(), value::string(U("NcElementId"))); + } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointNmos.html - web::json::value make_nc_touchpoint_nmos_datatype() - { - using web::json::value; + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResult.html + web::json::value make_nc_method_result_datatype() + { + using web::json::value; - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Context NMOS resource")), nmos::fields::nc::resource, value::string(U("NcTouchpointResourceNmos")), false, false)); - return make_nc_datatype_descriptor_struct(value::string(U("Touchpoint class for NMOS resources")), U("NcTouchpointNmos"), fields, value::string(U("NcTouchpoint"))); - } + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Status for the invoked method")), nmos::fields::nc::status, value::string(U("NcMethodStatus")), false, false)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Base result of the invoked method")), U("NcMethodResult"), fields, value::null()); + } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointNmosChannelMapping.html - web::json::value make_nc_touchpoint_nmos_channel_mapping_datatype() - { - using web::json::value; + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultBlockMemberDescriptors.html + web::json::value make_nc_method_result_block_member_descriptors_datatype() + { + using web::json::value; - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("Context Channel Mapping resource")), nmos::fields::nc::resource, value::string(U("NcTouchpointResourceNmosChannelMapping")), false, false)); - return make_nc_datatype_descriptor_struct(value::string(U("Touchpoint class for NMOS IS-08 resources")), U("NcTouchpointNmosChannelMapping"), fields, value::string(U("NcTouchpoint"))); - } + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Block member descriptors method result value")), nmos::fields::nc::value, value::string(U("NcBlockMemberDescriptor")), false, true)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Method result containing block member descriptors as the value")), U("NcMethodResultBlockMemberDescriptors"), fields, value::string(U("NcMethodResult"))); + } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointResource.html - web::json::value make_nc_touchpoint_resource_datatype() - { - using web::json::value; + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultClassDescriptor.html + web::json::value make_nc_method_result_class_descriptor_datatype() + { + using web::json::value; - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("The type of the resource")), nmos::fields::nc::resource_type, value::string(U("NcString")), false, false)); - return make_nc_datatype_descriptor_struct(value::string(U("Touchpoint resource class")), U("NcTouchpointResource"), fields, value::null()); - } + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Class descriptor method result value")), nmos::fields::nc::value, value::string(U("NcClassDescriptor")), false, false)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Method result containing a class descriptor as the value")), U("NcMethodResultClassDescriptor"), fields, value::string(U("NcMethodResult"))); + } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointResourceNmos.html - web::json::value make_nc_touchpoint_resource_nmos_datatype() - { - using web::json::value; + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultDatatypeDescriptor.html + web::json::value make_nc_method_result_datatype_descriptor_datatype() + { + using web::json::value; - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("NMOS resource UUID")), nmos::fields::nc::id, value::string(U("NcUuid")), false, false)); - return make_nc_datatype_descriptor_struct(value::string(U("Touchpoint resource class for NMOS resources")), U("NcTouchpointResourceNmos"), fields, value::string(U("NcTouchpointResource"))); - } + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Datatype descriptor method result value")), nmos::fields::nc::value, value::string(U("NcDatatypeDescriptor")), false, false)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Method result containing a datatype descriptor as the value")), U("NcMethodResultDatatypeDescriptor"), fields, value::string(U("NcMethodResult"))); + } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointResourceNmosChannelMapping.html - web::json::value make_nc_touchpoint_resource_nmos_channel_mapping_datatype() - { - using web::json::value; + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultError.html + web::json::value make_nc_method_result_error_datatype() + { + using web::json::value; - auto fields = value::array(); - web::json::push_back(fields, make_nc_field_descriptor(value::string(U("IS-08 Audio Channel Mapping input or output id")), nmos::fields::nc::io_id, value::string(U("NcString")), false, false)); - return make_nc_datatype_descriptor_struct(value::string(U("Touchpoint resource class for NMOS resources")), U("NcTouchpointResourceNmosChannelMapping"), fields, value::string(U("NcTouchpointResourceNmos"))); - } + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Error message")), nmos::fields::nc::error_message, value::string(U("NcString")), false, false)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Error result - to be used when the method call encounters an error")), U("NcMethodResultError"), fields, value::string(U("NcMethodResult"))); + } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcUri.html - web::json::value make_nc_uri_datatype() - { - using web::json::value; + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultId.html + web::json::value make_nc_method_result_id_datatype() + { + using web::json::value; - return make_nc_datatype_typedef(value::string(U("Uniform resource identifier")), U("NcUri"), false, U("NcString")); - } + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Id result value")), nmos::fields::nc::value, value::string(U("NcId")), false, false)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Id method result")), U("NcMethodResultId"), fields, value::string(U("NcMethodResult"))); + } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcUuid.html - web::json::value make_nc_uuid_datatype() - { - using web::json::value; + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultLength.html + web::json::value make_nc_method_result_length_datatype() + { + using web::json::value; - return make_nc_datatype_typedef(value::string(U("UUID")), U("NcUuid"), false, U("NcString")); - } + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Length result value")), nmos::fields::nc::value, value::string(U("NcUint32")), true, false)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Length method result")), U("NcMethodResultLength"), fields, value::string(U("NcMethodResult"))); + } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcVersionCode.html - web::json::value make_nc_version_code_datatype() - { - using web::json::value; + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultPropertyValue.html + web::json::value make_nc_method_result_property_value_datatype() + { + using web::json::value; - return make_nc_datatype_typedef(value::string(U("Version code in semantic versioning format")), U("NcVersionCode"), false, U("NcString")); - } + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Getter method value for the associated property")), nmos::fields::nc::value, value::null(), true, false)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Result when invoking the getter method associated with a property")), U("NcMethodResultPropertyValue"), fields, value::string(U("NcMethodResult"))); + } - // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncconnectionstatus - web::json::value make_nc_connection_status_datatype() - { - using web::json::value; + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodStatus.html + web::json::value make_nc_method_status_datatype() + { + using web::json::value; + + auto items = value::array(); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method call was successful")), U("Ok"), 200)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method call was successful but targeted property is deprecated")), U("PropertyDeprecated"), 298)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method call was successful but method is deprecated")), U("MethodDeprecated"), 299)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Badly-formed command (e.g. the incoming command has invalid message encoding and cannot be parsed by the underlying protocol)")), U("BadCommandFormat"), 400)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Client is not authorized")), U("Unauthorized"), 401)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Command addresses a nonexistent object")), U("BadOid"), 404)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Attempt to change read-only state")), U("Readonly"), 405)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method call is invalid in current operating context (e.g. attempting to invoke a method when the object is disabled)")), U("InvalidRequest"), 406)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("There is a conflict with the current state of the device")), U("Conflict"), 409)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Something was too big")), U("BufferOverflow"), 413)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Index is outside the available range")), U("IndexOutOfBounds"), 414)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method parameter does not meet expectations (e.g. attempting to invoke a method with an invalid type for one of its parameters)")), U("ParameterError"), 417)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Addressed object is locked")), U("Locked"), 423)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Internal device error")), U("DeviceError"), 500)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Addressed method is not implemented by the addressed object")), U("MethodNotImplemented"), 501)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Addressed property is not implemented by the addressed object")), U("PropertyNotImplemented"), 502)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("The device is not ready to handle any commands")), U("NotReady"), 503)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method call did not finish within the allotted time")), U("Timeout"), 504)); + return details::make_nc_datatype_descriptor_enum(value::string(U("Method invokation status")), U("NcMethodStatus"), items); + } - auto items = value::array(); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("This is the value when there is no receiver")), U("Undefined"), 0)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Connected to a stream")), U("Connected"), 1)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Not connected to a stream")), U("Disconnected"), 2)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("A connection error was encountered")), U("ConnectionError"), 3)); - return make_nc_datatype_descriptor_enum(value::string(U("Connection status enum data typee")), U("NcConnectionStatus"), items); - } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcName.html + web::json::value make_nc_name_datatype() + { + using web::json::value; - // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncpayloadstatus - web::json::value make_nc_payload_status_datatype() - { - using web::json::value; + return details::make_nc_datatype_typedef(value::string(U("Programmatically significant name, alphanumerics + underscore, no spaces")), U("NcName"), false, U("NcString")); + } - auto items = value::array(); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("This is the value when there's no connection")), U("Undefined"), 0)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Payload is being received without errors and is the correct type")), U("PayloadOK"), 1)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("Payload is being received but is of an unsupported type")), U("PayloadFormatUnsupported"), 2)); - web::json::push_back(items, make_nc_enum_item_descriptor(value::string(U("A payload error was encountered")), U("PayloadError"), 3)); - return make_nc_datatype_descriptor_enum(value::string(U("Connection status enum data typee")), U("NcPayloadStatus"), items); - } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcOid.html + web::json::value make_nc_oid_datatype() + { + using web::json::value; - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject - web::json::value make_nc_object(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints) - { - using web::json::value; + return details::make_nc_datatype_typedef(value::string(U("Object id")), U("NcOid"), false, U("NcUint32")); + } - const auto id = utility::conversions::details::to_string_t(oid); -// auto data = make_resource_core(id, user_label.is_null() ? U("") : user_label.as_string(), {}); - value data; - data[nmos::fields::id] = value::string(id); // required for nmos::resource - data[nmos::fields::nc::class_id] = make_nc_class_id(class_id); - data[nmos::fields::nc::oid] = oid; - data[nmos::fields::nc::constant_oid] = value::boolean(constant_oid); - data[nmos::fields::nc::owner] = owner; - data[nmos::fields::nc::role] = value::string(role); - data[nmos::fields::nc::user_label] = user_label; - data[nmos::fields::nc::touchpoints] = touchpoints; - data[nmos::fields::nc::runtime_property_constraints] = runtime_property_constraints; + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcOrganizationId.html + web::json::value make_nc_organization_id_datatype() + { + using web::json::value; - return data; - } + return details::make_nc_datatype_typedef(value::string(U("Unique 24-bit organization id")), U("NcOrganizationId"), false, U("NcInt32")); + } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock - web::json::value make_nc_block(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled, const web::json::value& members) - { - using web::json::value; + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcParameterConstraints.html + web::json::value make_nc_parameter_constraints_datatype() + { + using web::json::value; - auto data = details::make_nc_object(class_id, oid, constant_oid, owner, role, user_label, touchpoints, runtime_property_constraints); - data[nmos::fields::nc::enabled] = value::boolean(enabled); - data[nmos::fields::nc::members] = members; + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Default value")), nmos::fields::nc::default_value, value::null(), true, false)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Abstract parameter constraints class")), U("NcParameterConstraints"), fields, value::null()); + } - return data; - } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcParameterConstraintsNumber.html + web::json::value make_nc_parameter_constraints_number_datatype() + { + using web::json::value; - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncworker - web::json::value make_nc_worker(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled) - { - using web::json::value; + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional maximum")), nmos::fields::nc::maximum, value::null(), true, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional minimum")), nmos::fields::nc::minimum, value::null(), true, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional step")), nmos::fields::nc::step, value::null(), true, false)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Number parameter constraints class")), U("NcParameterConstraintsNumber"), fields, value::string(U("NcParameterConstraints"))); + } - auto data = details::make_nc_object(class_id, oid, constant_oid, owner, role, user_label, touchpoints, runtime_property_constraints); - data[nmos::fields::nc::enabled] = value::boolean(enabled); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcParameterConstraintsString.html + web::json::value make_nc_parameter_constraints_string_datatype() + { + using web::json::value; - return data; - } + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Maximum characters allowed")), nmos::fields::nc::max_characters, value::string(U("NcUint32")), true, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Regex pattern")), nmos::fields::nc::pattern, value::string(U("NcRegex")), true, false)); + return details::make_nc_datatype_descriptor_struct(value::string(U("String parameter constraints class")), U("NcParameterConstraintsString"), fields, value::string(U("NcParameterConstraints"))); + } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanager - web::json::value make_nc_manager(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints) - { - return make_nc_object(class_id, oid, constant_oid, owner, role, user_label, touchpoints, runtime_property_constraints); - } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcParameterDescriptor.html + web::json::value make_nc_parameter_descriptor_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of parameter")), nmos::fields::nc::name, value::string(U("NcName")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of parameter's datatype. Can only ever be null if the type is any")), nmos::fields::nc::type_name, value::string(U("NcName")), true, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is nullable")), nmos::fields::nc::is_nullable, value::string(U("NcBoolean")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is a sequence")), nmos::fields::nc::is_sequence, value::string(U("NcBoolean")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional constraints on top of the underlying data type")), nmos::fields::nc::constraints, value::string(U("NcParameterConstraints")), true, false)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a method parameter")), U("NcParameterDescriptor"), fields, value::string(U("NcDescriptor"))); + } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager - web::json::value make_nc_device_manager(nc_oid oid, nc_oid owner, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, - const web::json::value& manufacturer, const web::json::value& product, const utility::string_t& serial_number, - const web::json::value& user_inventory_code, const web::json::value& device_name, const web::json::value& device_role, const web::json::value& operational_state, nc_reset_cause::cause reset_cause) - { - using web::json::value; + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcProduct.html + web::json::value make_nc_product_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Product name")), nmos::fields::nc::name, value::string(U("NcString")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Manufacturer's unique key to product - model number, SKU, etc")), nmos::fields::nc::key, value::string(U("NcString")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Manufacturer's product revision level code")), nmos::fields::nc::revision_level, value::string(U("NcString")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Brand name under which product is sold")), nmos::fields::nc::brand_name, value::string(U("NcString")), true, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Unique UUID of product (not product instance)")), nmos::fields::nc::uuid, value::string(U("NcUuid")), true, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Text description of product")), nmos::fields::nc::description, value::string(U("NcString")), true, false)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Product descriptor")), U("NcProduct"), fields, value::null()); + } - auto data = details::make_nc_manager(nc_device_manager_class_id, oid, true, owner, U("DeviceManager"), user_label, touchpoints, runtime_property_constraints); - data[nmos::fields::nc::nc_version] = value::string(U("v1.0.0")); - data[nmos::fields::nc::manufacturer] = manufacturer; - data[nmos::fields::nc::product] = product; - data[nmos::fields::nc::serial_number] = value::string(serial_number); - data[nmos::fields::nc::user_inventory_code] = user_inventory_code; - data[nmos::fields::nc::device_name] = device_name; - data[nmos::fields::nc::device_role] = device_role; - data[nmos::fields::nc::operational_state] = operational_state; - data[nmos::fields::nc::reset_cause] = reset_cause; - data[nmos::fields::nc::message] = value::null(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyChangeType.html + web::json::value make_nc_property_change_type_datatype() + { + using web::json::value; + + auto items = value::array(); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Current value changed")), U("ValueChanged"), 0)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Sequence item added")), U("SequenceItemAdded"), 1)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Sequence item changed")), U("SequenceItemChanged"), 2)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Sequence item removed")), U("SequenceItemRemoved"), 3)); + return details::make_nc_datatype_descriptor_enum(value::string(U("Type of property change")), U("NcPropertyChangeType"), items); + } - return data; - } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyChangedEventData.html + web::json::value make_nc_property_changed_event_data_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("The id of the property that changed")), nmos::fields::nc::property_id, value::string(U("NcPropertyId")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Information regarding the change type")), nmos::fields::nc::change_type, value::string(U("NcPropertyChangeType")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Property-type specific value")), nmos::fields::nc::value, value::null(), true, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Index of sequence item if the property is a sequence")), nmos::fields::nc::sequence_item_index, value::string(U("NcId")), true, false)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Payload of property-changed event")), U("NcPropertyChangedEventData"), fields, value::null()); + } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager - web::json::value make_nc_class_manager(nc_oid oid, nc_oid owner, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, const nmos::experimental::control_protocol_state& control_protocol_state) - { - using web::json::value; + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyConstraints.html + web::json::value make_nc_property_contraints_datatype() + { + using web::json::value; - auto data = make_nc_manager(nc_class_manager_class_id, oid, true, owner, U("ClassManager"), user_label, touchpoints, runtime_property_constraints); + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("The id of the property being constrained")), nmos::fields::nc::property_id, value::string(U("NcPropertyId")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional default value")), nmos::fields::nc::default_value, value::null(), true, false)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Property constraints class")), U("NcPropertyConstraints"), fields, value::null()); + } - // core control classes - data[nmos::fields::nc::control_classes] = value::array(); - auto& control_classes = data[nmos::fields::nc::control_classes]; - for (const auto& control_class : control_protocol_state.control_classes) - { - auto& ctl_class = control_class.second; - web::json::push_back(control_classes, make_nc_class_descriptor(ctl_class.description, ctl_class.class_id, ctl_class.name, ctl_class.fixed_role, ctl_class.properties, ctl_class.methods, ctl_class.events)); - } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyConstraintsNumber.html + web::json::value make_nc_property_constraints_number_datatype() + { + using web::json::value; - // core datatypes - data[nmos::fields::nc::datatypes] = value::array(); - auto& datatypes = data[nmos::fields::nc::datatypes]; - for (const auto& datatype : control_protocol_state.datatypes) - { - web::json::push_back(datatypes, datatype.second.descriptor); - } + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional maximum")), nmos::fields::nc::maximum, value::null(), true, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional minimum")), nmos::fields::nc::minimum, value::null(), true, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional step")), nmos::fields::nc::step, value::null(), true, false)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Number property constraints class")), U("NcPropertyConstraintsNumber"), fields, value::string(U("NcPropertyConstraints"))); + } - return data; - } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyConstraintsString.html + web::json::value make_nc_property_constraints_string_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Maximum characters allowed")), nmos::fields::nc::max_characters, value::string(U("NcUint32")), true, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Regex pattern")), nmos::fields::nc::pattern, value::string(U("NcRegex")), true, false)); + return details::make_nc_datatype_descriptor_struct(value::string(U("String property constraints class")), U("NcPropertyConstraintsString"), fields, value::string(U("NcPropertyConstraints"))); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyDescriptor.html + web::json::value make_nc_property_descriptor_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Property id with level and index")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of property")), nmos::fields::nc::name, value::string(U("NcName")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of property's datatype. Can only ever be null if the type is any")), nmos::fields::nc::type_name, value::string(U("NcName")), true, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is read-only")), nmos::fields::nc::is_read_only, value::string(U("NcBoolean")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is nullable")), nmos::fields::nc::is_nullable, value::string(U("NcBoolean")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is a sequence")), nmos::fields::nc::is_sequence, value::string(U("NcBoolean")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is marked as deprecated")), nmos::fields::nc::is_deprecated, value::string(U("NcBoolean")), false, false)); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional constraints on top of the underlying data type")), nmos::fields::nc::constraints, value::string(U("NcParameterConstraints")), true, false)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class property")), U("NcPropertyDescriptor"), fields, value::string(U("NcDescriptor"))); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyId.html + web::json::value make_nc_property_id_datatype() + { + using web::json::value; + + return details::make_nc_datatype_descriptor_struct(value::string(U("Property id which contains the level and index")), U("NcPropertyId"), value::array(), value::string(U("NcElementId"))); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcRegex.html + web::json::value make_nc_regex_datatype() + { + using web::json::value; + + return details::make_nc_datatype_typedef(value::string(U("Regex pattern")), U("NcRegex"), false, U("NcString")); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcResetCause.html + web::json::value make_nc_reset_cause_datatype() + { + using web::json::value; + + auto items = value::array(); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Unknown")), U("Unknown"), 0)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Power on")), U("PowerOn"), 1)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Internal error")), U("InternalError"), 2)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Upgrade")), U("Upgrade"), 3)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Controller request")), U("ControllerRequest"), 4)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Manual request from the front panel")), U("ManualReset"), 5)); + return details::make_nc_datatype_descriptor_enum(value::string(U("Reset cause enum")), U("NcResetCause"), items); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcRolePath.html + web::json::value make_nc_role_path_datatype() + { + using web::json::value; + + return details::make_nc_datatype_typedef(value::string(U("Role path")), U("NcRolePath"), true, U("NcString")); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTimeInterval.html + web::json::value make_nc_time_interval_datatype() + { + using web::json::value; + + return details::make_nc_datatype_typedef(value::string(U("Time interval described in nanoseconds")), U("NcTimeInterval"), false, U("NcInt64")); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpoint.html + web::json::value make_nc_touchpoint_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Context namespace")), nmos::fields::nc::context_namespace, value::string(U("NcString")), false, false)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Base touchpoint class")), U("NcTouchpoint"), fields, value::null()); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointNmos.html + web::json::value make_nc_touchpoint_nmos_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Context NMOS resource")), nmos::fields::nc::resource, value::string(U("NcTouchpointResourceNmos")), false, false)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Touchpoint class for NMOS resources")), U("NcTouchpointNmos"), fields, value::string(U("NcTouchpoint"))); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointNmosChannelMapping.html + web::json::value make_nc_touchpoint_nmos_channel_mapping_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Context Channel Mapping resource")), nmos::fields::nc::resource, value::string(U("NcTouchpointResourceNmosChannelMapping")), false, false)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Touchpoint class for NMOS IS-08 resources")), U("NcTouchpointNmosChannelMapping"), fields, value::string(U("NcTouchpoint"))); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointResource.html + web::json::value make_nc_touchpoint_resource_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("The type of the resource")), nmos::fields::nc::resource_type, value::string(U("NcString")), false, false)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Touchpoint resource class")), U("NcTouchpointResource"), fields, value::null()); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointResourceNmos.html + web::json::value make_nc_touchpoint_resource_nmos_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("NMOS resource UUID")), nmos::fields::nc::id, value::string(U("NcUuid")), false, false)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Touchpoint resource class for NMOS resources")), U("NcTouchpointResourceNmos"), fields, value::string(U("NcTouchpointResource"))); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointResourceNmosChannelMapping.html + web::json::value make_nc_touchpoint_resource_nmos_channel_mapping_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("IS-08 Audio Channel Mapping input or output id")), nmos::fields::nc::io_id, value::string(U("NcString")), false, false)); + return details::make_nc_datatype_descriptor_struct(value::string(U("Touchpoint resource class for NMOS resources")), U("NcTouchpointResourceNmosChannelMapping"), fields, value::string(U("NcTouchpointResourceNmos"))); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcUri.html + web::json::value make_nc_uri_datatype() + { + using web::json::value; + + return details::make_nc_datatype_typedef(value::string(U("Uniform resource identifier")), U("NcUri"), false, U("NcString")); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcUuid.html + web::json::value make_nc_uuid_datatype() + { + using web::json::value; + + return details::make_nc_datatype_typedef(value::string(U("UUID")), U("NcUuid"), false, U("NcString")); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcVersionCode.html + web::json::value make_nc_version_code_datatype() + { + using web::json::value; + + return details::make_nc_datatype_typedef(value::string(U("Version code in semantic versioning format")), U("NcVersionCode"), false, U("NcString")); + } + + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncconnectionstatus + web::json::value make_nc_connection_status_datatype() + { + using web::json::value; + + auto items = value::array(); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("This is the value when there is no receiver")), U("Undefined"), 0)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Connected to a stream")), U("Connected"), 1)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Not connected to a stream")), U("Disconnected"), 2)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("A connection error was encountered")), U("ConnectionError"), 3)); + return details::make_nc_datatype_descriptor_enum(value::string(U("Connection status enum data typee")), U("NcConnectionStatus"), items); + } + + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncpayloadstatus + web::json::value make_nc_payload_status_datatype() + { + using web::json::value; + + auto items = value::array(); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("This is the value when there's no connection")), U("Undefined"), 0)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Payload is being received without errors and is the correct type")), U("PayloadOK"), 1)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Payload is being received but is of an unsupported type")), U("PayloadFormatUnsupported"), 2)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("A payload error was encountered")), U("PayloadError"), 3)); + return details::make_nc_datatype_descriptor_enum(value::string(U("Connection status enum data typee")), U("NcPayloadStatus"), items); } } diff --git a/Development/nmos/control_protocol_resource.h b/Development/nmos/control_protocol_resource.h index 387bb6978..8d2c4208b 100644 --- a/Development/nmos/control_protocol_resource.h +++ b/Development/nmos/control_protocol_resource.h @@ -2,7 +2,7 @@ #define NMOS_CONTROL_PROTOCOL_RESOURCE_H #include "cpprest/json_utils.h" -#include "nmos/control_protocol_class_id.h" +#include "nmos/control_protocol_typedefs.h" namespace web { @@ -21,184 +21,25 @@ namespace nmos namespace details { - namespace nc_message_type - { - enum type - { - command = 0, - command_response = 1, - notification = 2, - subscription = 3, - subscription_response = 4, - error = 5 - }; - } - - // Method invokation status - namespace nc_method_status - { - enum status - { - ok = 200, // Method call was successful - property_deprecated = 298, // Method call was successful but targeted property is deprecated - method_deprecated = 299, // Method call was successful but method is deprecated - bad_command_format = 400, // Badly-formed command - unathorized = 401, // Client is not authorized - bad_oid = 404, // Command addresses a nonexistent object - read_only = 405, // Attempt to change read-only state - invalid_request = 406, // Method call is invalid in current operating context - conflict = 409, // There is a conflict with the current state of the device - buffer_overflow = 413, // Something was too big - index_out_of_bounds = 414, // Index is outside the available range - parameter_error = 417, // Method parameter does not meet expectations - locked = 423, // Addressed object is locked - device_error = 500, // Internal device error - method_not_implemented = 501, // Addressed method is not implemented by the addressed object - property_not_implemented = 502, // Addressed property is not implemented by the addressed object - not_ready = 503, // The device is not ready to handle any commands - timeout = 504, // Method call did not finish within the allotted time - property_version_error = 505 // Incompatible protocol version - }; - } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmethodresult - struct nc_method_result - { - nc_method_status::status status; - }; - - // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#command-response-message-type - web::json::value make_control_protocol_error_response(int32_t handle, const nc_method_result& method_result, const utility::string_t& error_message); - web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result); - web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result, const web::json::value& value); - web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result, uint32_t value); - - // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#command-message-type - web::json::value make_control_protocol_message_response(nc_message_type::type type, const web::json::value& responses); - // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#error-messages - web::json::value make_control_protocol_error_message(const nc_method_result& method_result, const utility::string_t& error_message); - - // Datatype type - namespace nc_datatype_type - { - enum type - { - Primitive = 0, - Typedef = 1, - Struct = 2, - Enum = 3 - }; - } - - // Device generic operational state - namespace nc_device_generic_state - { - enum state - { - unknown = 0, // Unknown - normal_operation = 1, // Normal operation - initializing = 2, // Device is initializing - updating = 3, // Device is performing a software or firmware update - licensing_error = 4, // Device is experiencing a licensing error - internal_error = 5 // Device is experiencing an internal error - }; - } - - // Reset cause enum - namespace nc_reset_cause - { - enum cause - { - unknown = 0, // Unknown - power_on = 1, // Power on - internal_error = 2, // Internal error - upgrade = 3, // Upgrade - controller_request = 4, // Controller request - manual_reset = 5 // Manual request from the front panel - }; - } - - // NcConnectionStatus - // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncconnectionstatus - namespace nc_connection_status - { - enum status - { - undefined = 0, // This is the value when there is no receiver - connected = 1, // Connected to a stream - disconnected = 2, // Not connected to a stream - connection_error = 3 // A connection error was encountered - }; - } - - // NcPayloadStatus - // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncpayloadstatus - namespace nc_payload_status - { - enum status - { - undefined = 0, // This is the value when there's no connection. - payload_ok = 1, // Payload is being received without errors and is the correct type - payload_format_unsupported = 2, // Payload is being received but is of an unsupported type - payloadError = 3 // A payload error was encountered - }; - } - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncid - typedef uint32_t nc_id; - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncoid - typedef uint32_t nc_oid; - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncuri - typedef utility::string_t nc_uri; - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncuuid - typedef utility::string_t nc_uuid; - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassid - const nc_class_id nc_object_class_id({ 1 }); - const nc_class_id nc_block_class_id({ 1, 1 }); - const nc_class_id nc_worker_class_id({ 1, 2 }); - const nc_class_id nc_manager_class_id({ 1, 3 }); - const nc_class_id nc_device_manager_class_id({ 1, 3, 1 }); - const nc_class_id nc_class_manager_class_id({ 1, 3, 2 }); - const nc_class_id nc_ident_beacon_class_id({ 1, 2, 2 }); - const nc_class_id nc_receiver_monitor_class_id({ 1, 2, 3 }); - const nc_class_id nc_receiver_monitor_protected_class_id({ 1, 2, 3, 1 }); - - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#nctouchpoint - typedef utility::string_t nc_touch_point; - - web::json::value make_control_protocol_error_response(int32_t handle, const nc_method_result& method_result, const utility::string_t& error_message); - - web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result); - - // value can be - // sequence - // NcClassDescriptor - // NcDatatypeDescriptor - web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result, const web::json::value& value); - - // message response - // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#command-message-type - web::json::value make_control_protocol_message_response(nc_message_type::type type, const web::json::value& responses); - - // error message - // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#error-messages - web::json::value make_control_protocol_error_message(const nc_method_result& method_result, const utility::string_t& error_message); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncelementid - web::json::value make_nc_element_id(uint16_t level, uint16_t index); + //web::json::value make_nc_element_id(uint16_t level, uint16_t index); + web::json::value make_nc_element_id(const nc_element_id& element_id); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#nceventid - web::json::value make_nc_event_id(uint16_t level, uint16_t index); + //web::json::value make_nc_event_id(uint16_t level, uint16_t index); + web::json::value make_nc_event_id(const nc_event_id& event_id); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmethodid - web::json::value make_nc_method_id(uint16_t level, uint16_t index); + //web::json::value make_nc_method_id(uint16_t level, uint16_t index); + web::json::value make_nc_method_id(const nc_method_id& event_id); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncpropertyid - web::json::value make_nc_property_id(uint16_t level, uint16_t index); + //web::json::value make_nc_property_id(uint16_t level, uint16_t index); + web::json::value make_nc_property_id(const nc_property_id& event_id); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassid + web::json::value make_nc_class_id(const nc_class_id& class_id); + nc_class_id parse_nc_class_id(const web::json::array& class_id); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanufacturer web::json::value make_nc_manufacturer(const utility::string_t& name, const web::json::value& organization_id = web::json::value::null(), const web::json::value& website = web::json::value::null()); @@ -221,45 +62,55 @@ namespace nmos // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblockmemberdescriptor // description can be null // user_label can be null - web::json::value make_nc_block_member_descriptor(const web::json::value& description, const utility::string_t& role, nc_oid oid, bool constant_oid, const web::json::value& class_id, const web::json::value& user_label, nc_oid owner); + web::json::value make_nc_block_member_descriptor(const web::json::value& description, const utility::string_t& role, nc_oid oid, bool constant_oid, const nc_class_id& class_id, const web::json::value& user_label, nc_oid owner); + web::json::value make_nc_block_member_descriptor(const utility::string_t& description, const utility::string_t& role, nc_oid oid, bool constant_oid, const nc_class_id& class_id, const utility::string_t& user_label, nc_oid owner); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassdescriptor // description can be null // fixedRole can be null web::json::value make_nc_class_descriptor(const web::json::value& description, const nc_class_id& class_id, const utility::string_t& name, const web::json::value& fixed_role, const web::json::value& properties, const web::json::value& methods, const web::json::value& events); + web::json::value make_nc_class_descriptor(const utility::string_t& description, const nc_class_id& class_id, const utility::string_t& name, const web::json::value& fixed_role, const web::json::value& properties, const web::json::value& methods, const web::json::value& events); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncenumitemdescriptor // description can be null web::json::value make_nc_enum_item_descriptor(const web::json::value& description, const utility::string_t& name, uint16_t val); + web::json::value make_nc_enum_item_descriptor(const utility::string_t& description, const utility::string_t& name, uint16_t val); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#nceventdescriptor // description can be null // id = make_nc_event_id(level, index) - web::json::value make_nc_event_descriptor(const web::json::value& description, const web::json::value& id, const utility::string_t& name, const utility::string_t& event_datatype, bool is_deprecated); + web::json::value make_nc_event_descriptor(const web::json::value& description, const nc_event_id& id, const utility::string_t& name, const utility::string_t& event_datatype, bool is_deprecated); + web::json::value make_nc_event_descriptor(const utility::string_t& description, const nc_event_id& id, const utility::string_t& name, const utility::string_t& event_datatype, bool is_deprecated); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncfielddescriptor // description can be null // type_name can be null // constraints can be null web::json::value make_nc_field_descriptor(const web::json::value& description, const utility::string_t& name, const web::json::value& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints = web::json::value::null()); + web::json::value make_nc_field_descriptor(const utility::string_t& description, const utility::string_t& name, const utility::string_t& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints = web::json::value::null()); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmethoddescriptor // description can be null // id = make_nc_method_id(level, index) // sequence parameters - web::json::value make_nc_method_descriptor(const web::json::value& description, const web::json::value& id, const utility::string_t& name, const utility::string_t& result_datatype, const web::json::value& parameters, bool is_deprecated); + web::json::value make_nc_method_descriptor(const web::json::value& description, const nc_method_id& id, const utility::string_t& name, const utility::string_t& result_datatype, const web::json::value& parameters, bool is_deprecated); + web::json::value make_nc_method_descriptor(const utility::string_t& description, const nc_method_id& id, const utility::string_t& name, const utility::string_t& result_datatype, const web::json::value& parameters, bool is_deprecated); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncparameterdescriptor // description can be null // type_name can be null web::json::value make_nc_parameter_descriptor(const web::json::value& description, const utility::string_t& name, const web::json::value& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints = web::json::value::null()); + web::json::value make_nc_parameter_descriptor(const utility::string_t& description, const utility::string_t& name, bool is_nullable, bool is_sequence, const web::json::value& constraints = web::json::value::null()); + web::json::value make_nc_parameter_descriptor(const utility::string_t& description, const utility::string_t& name, const utility::string_t& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints = web::json::value::null()); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncpropertydescriptor // description can be null // id = make_nc_property_id(level, index); // type_name can be null // constraints can be null - web::json::value make_nc_property_descriptor(const web::json::value& description, const web::json::value& id, const utility::string_t& name, const web::json::value& type_name, + web::json::value make_nc_property_descriptor(const web::json::value& description, const nc_property_id& id, const utility::string_t& name, const web::json::value& type_name, + bool is_read_only, bool is_nullable, bool is_sequence, bool is_deprecated, const web::json::value& constraints = web::json::value::null()); + web::json::value make_nc_property_descriptor(const utility::string_t& description, const nc_property_id& id, const utility::string_t& name, const utility::string_t& type_name, bool is_read_only, bool is_nullable, bool is_sequence, bool is_deprecated, const web::json::value& constraints = web::json::value::null()); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptor @@ -290,188 +141,6 @@ namespace nmos // constraints can be null web::json::value make_nc_datatype_typedef(const web::json::value& description, const utility::string_t& name, bool is_sequence, const utility::string_t& parent_type, const web::json::value& constraints = web::json::value::null()); - // Control class models - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/#control-class-models-for-branch-v10-dev - // - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.html - web::json::value make_nc_object_class(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.1.html - web::json::value make_nc_block_class(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.2.html - web::json::value make_nc_worker_class(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.3.html - web::json::value make_nc_manager_class(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.3.1.html - web::json::value make_nc_device_manager_class(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.3.2.html - web::json::value make_nc_class_manager_class(); - - // control classes proprties/methods/events - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject - web::json::value make_nc_object_properties(); - web::json::value make_nc_object_methods(); - web::json::value make_nc_object_events(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock - web::json::value make_nc_block_properties(); - web::json::value make_nc_block_methods(); - web::json::value make_nc_block_events(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncworker - web::json::value make_nc_worker_properties(); - web::json::value make_nc_worker_methods(); - web::json::value make_nc_worker_events(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanager - web::json::value make_nc_manager_properties(); - web::json::value make_nc_manager_methods(); - web::json::value make_nc_manager_events(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager - web::json::value make_nc_device_manager_properties(); - web::json::value make_nc_device_manager_methods(); - web::json::value make_nc_device_manager_events(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager - web::json::value make_nc_class_manager_properties(); - web::json::value make_nc_class_manager_methods(); - web::json::value make_nc_class_manager_events(); - // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitor - web::json::value make_nc_receiver_monitor_properties(); - web::json::value make_nc_receiver_monitor_methods(); - web::json::value make_nc_receiver_monitor_events(); - // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitorprotected - web::json::value make_nc_receiver_monitor_protected_properties(); - web::json::value make_nc_receiver_monitor_protected_methods(); - web::json::value make_nc_receiver_monitor_protected_events(); - // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/identification/#ncidentbeacon - web::json::value make_nc_ident_beacon_properties(); - web::json::value make_nc_ident_beacon_methods(); - web::json::value make_nc_ident_beacon_events(); - - // Datatype models - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/#datatype-models-for-branch-v10-dev - // - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcBlockMemberDescriptor.html - web::json::value make_nc_block_member_descriptor_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcClassDescriptor.html - web::json::value make_nc_class_descriptor_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcClassId.html - web::json::value make_nc_class_id_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptor.html - web::json::value make_nc_datatype_descriptor_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptorEnum.html - web::json::value make_nc_datatype_descriptor_enum_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptorPrimitive.html - web::json::value make_nc_datatype_descriptor_primitive_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptorStruct.html - web::json::value make_nc_datatype_descriptor_struct_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptorTypeDef.html - web::json::value make_nc_datatype_descriptor_type_def_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeType.html - web::json::value make_nc_datatype_type_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDescriptor.html - web::json::value make_nc_descriptor_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDeviceGenericState.html - web::json::value make_nc_device_generic_state_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDeviceOperationalState.html - web::json::value make_nc_device_operational_state_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcElementId.html - web::json::value make_nc_element_id_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcEnumItemDescriptor.html - web::json::value make_nc_enum_item_descriptor_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcEventDescriptor.html - web::json::value make_nc_event_descriptor_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcEventId.html - web::json::value make_nc_event_id_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcFieldDescriptor.html - web::json::value make_nc_field_descriptor_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcId.html - web::json::value make_nc_id_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcManufacturer.html - web::json::value make_nc_manufacturer_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodDescriptor.html - web::json::value make_nc_method_descriptor_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodId.html - web::json::value make_nc_method_id_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResult.html - web::json::value make_nc_method_result_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultBlockMemberDescriptors.html - web::json::value make_nc_method_result_block_member_descriptors_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultClassDescriptor.html - web::json::value make_nc_method_result_class_descriptor_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultDatatypeDescriptor.html - web::json::value make_nc_method_result_datatype_descriptor_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultError.html - web::json::value make_nc_method_result_error_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultId.html - web::json::value make_nc_method_result_id_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultLength.html - web::json::value make_nc_method_result_length_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultPropertyValue.html - web::json::value make_nc_method_result_property_value_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodStatus.html - web::json::value make_nc_method_status_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcName.html - web::json::value make_nc_name_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcOid.html - web::json::value make_nc_oid_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcOrganizationId.html - web::json::value make_nc_organization_id_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcParameterConstraints.html - web::json::value make_nc_parameter_constraints_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcParameterConstraintsNumber.html - web::json::value make_nc_parameter_constraints_number_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcParameterConstraintsString.html - web::json::value make_nc_parameter_constraints_string_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcParameterDescriptor.html - web::json::value make_nc_parameter_descriptor_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcProduct.html - web::json::value make_nc_product_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyChangeType.html - web::json::value make_nc_property_change_type_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyChangedEventData.html - web::json::value make_nc_property_changed_event_data_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyConstraints.html - web::json::value make_nc_property_contraints_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyConstraintsNumber.html - web::json::value make_nc_property_constraints_number_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyConstraintsString.html - web::json::value make_nc_property_constraints_string_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyDescriptor.html - web::json::value make_nc_property_descriptor_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyId.html - web::json::value make_nc_property_id_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcRegex.html - web::json::value make_nc_regex_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcResetCause.html - web::json::value make_nc_reset_cause_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcRolePath.html - web::json::value make_nc_role_path_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTimeInterval.html - web::json::value make_nc_time_interval_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpoint.html - web::json::value make_nc_touchpoint_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointNmos.html - web::json::value make_nc_touchpoint_nmos_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointNmosChannelMapping.html - web::json::value make_nc_touchpoint_nmos_channel_mapping_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointResource.html - web::json::value make_nc_touchpoint_resource_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointResourceNmos.html - web::json::value make_nc_touchpoint_resource_nmos_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointResourceNmosChannelMapping.html - web::json::value make_nc_touchpoint_resource_nmos_channel_mapping_datatype(); - // See // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcUri.html - web::json::value make_nc_uri_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcUuid.html - web::json::value make_nc_uuid_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcVersionCode.html - web::json::value make_nc_version_code_datatype(); - - // Monitoring datatypes - // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#datatypes - // - // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncconnectionstatus - web::json::value make_nc_connection_status_datatype(); - // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncpayloadstatus - web::json::value make_nc_payload_status_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject web::json::value make_nc_object(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints); @@ -490,8 +159,210 @@ namespace nmos const web::json::value& user_inventory_code, const web::json::value& device_name, const web::json::value& device_role, const web::json::value& operational_state, nc_reset_cause::cause reset_cause); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager - web::json::value make_nc_class_manager(details::nc_oid oid, nc_oid owner, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, const nmos::experimental::control_protocol_state& control_protocol_state); + web::json::value make_nc_class_manager(nc_oid oid, nc_oid owner, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, const nmos::experimental::control_protocol_state& control_protocol_state); } + + // message response + // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#command-message-type + web::json::value make_control_protocol_message_response(nc_message_type::type type, const web::json::value& responses); + + // error message + // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#error-messages + web::json::value make_control_protocol_error_message(const nc_method_result& method_result, const utility::string_t& error_message); + + // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#command-response-message-type + web::json::value make_control_protocol_error_response(int32_t handle, const nc_method_result& method_result, const utility::string_t& error_message); + web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result); + web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result, const web::json::value& value); // value can be sequence, NcClassDescriptor, NcDatatypeDescriptor + web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result, uint32_t value); + + // Control class models + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/#control-class-models-for-branch-v10-dev + // + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.html + web::json::value make_nc_object_class(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.1.html + web::json::value make_nc_block_class(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.2.html + web::json::value make_nc_worker_class(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.3.html + web::json::value make_nc_manager_class(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.3.1.html + web::json::value make_nc_device_manager_class(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.3.2.html + web::json::value make_nc_class_manager_class(); + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/identification/#ncidentbeacon + web::json::value make_nc_ident_beacon_class(); + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitor + web::json::value make_nc_receiver_monitor_class(); + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitorprotected + web::json::value make_nc_receiver_monitor_protected_class(); + + // control classes proprties/methods/events + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject + web::json::value make_nc_object_properties(); + web::json::value make_nc_object_methods(); + web::json::value make_nc_object_events(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock + web::json::value make_nc_block_properties(); + web::json::value make_nc_block_methods(); + web::json::value make_nc_block_events(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncworker + web::json::value make_nc_worker_properties(); + web::json::value make_nc_worker_methods(); + web::json::value make_nc_worker_events(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanager + web::json::value make_nc_manager_properties(); + web::json::value make_nc_manager_methods(); + web::json::value make_nc_manager_events(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager + web::json::value make_nc_device_manager_properties(); + web::json::value make_nc_device_manager_methods(); + web::json::value make_nc_device_manager_events(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager + web::json::value make_nc_class_manager_properties(); + web::json::value make_nc_class_manager_methods(); + web::json::value make_nc_class_manager_events(); + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitor + web::json::value make_nc_receiver_monitor_properties(); + web::json::value make_nc_receiver_monitor_methods(); + web::json::value make_nc_receiver_monitor_events(); + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitorprotected + web::json::value make_nc_receiver_monitor_protected_properties(); + web::json::value make_nc_receiver_monitor_protected_methods(); + web::json::value make_nc_receiver_monitor_protected_events(); + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/identification/#ncidentbeacon + web::json::value make_nc_ident_beacon_properties(); + web::json::value make_nc_ident_beacon_methods(); + web::json::value make_nc_ident_beacon_events(); + + // Datatype models + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/#datatype-models-for-branch-v10-dev + // + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcBlockMemberDescriptor.html + web::json::value make_nc_block_member_descriptor_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcClassDescriptor.html + web::json::value make_nc_class_descriptor_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcClassId.html + web::json::value make_nc_class_id_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptor.html + web::json::value make_nc_datatype_descriptor_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptorEnum.html + web::json::value make_nc_datatype_descriptor_enum_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptorPrimitive.html + web::json::value make_nc_datatype_descriptor_primitive_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptorStruct.html + web::json::value make_nc_datatype_descriptor_struct_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptorTypeDef.html + web::json::value make_nc_datatype_descriptor_type_def_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeType.html + web::json::value make_nc_datatype_type_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDescriptor.html + web::json::value make_nc_descriptor_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDeviceGenericState.html + web::json::value make_nc_device_generic_state_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDeviceOperationalState.html + web::json::value make_nc_device_operational_state_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcElementId.html + web::json::value make_nc_element_id_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcEnumItemDescriptor.html + web::json::value make_nc_enum_item_descriptor_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcEventDescriptor.html + web::json::value make_nc_event_descriptor_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcEventId.html + web::json::value make_nc_event_id_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcFieldDescriptor.html + web::json::value make_nc_field_descriptor_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcId.html + web::json::value make_nc_id_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcManufacturer.html + web::json::value make_nc_manufacturer_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodDescriptor.html + web::json::value make_nc_method_descriptor_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodId.html + web::json::value make_nc_method_id_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResult.html + web::json::value make_nc_method_result_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultBlockMemberDescriptors.html + web::json::value make_nc_method_result_block_member_descriptors_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultClassDescriptor.html + web::json::value make_nc_method_result_class_descriptor_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultDatatypeDescriptor.html + web::json::value make_nc_method_result_datatype_descriptor_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultError.html + web::json::value make_nc_method_result_error_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultId.html + web::json::value make_nc_method_result_id_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultLength.html + web::json::value make_nc_method_result_length_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultPropertyValue.html + web::json::value make_nc_method_result_property_value_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodStatus.html + web::json::value make_nc_method_status_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcName.html + web::json::value make_nc_name_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcOid.html + web::json::value make_nc_oid_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcOrganizationId.html + web::json::value make_nc_organization_id_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcParameterConstraints.html + web::json::value make_nc_parameter_constraints_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcParameterConstraintsNumber.html + web::json::value make_nc_parameter_constraints_number_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcParameterConstraintsString.html + web::json::value make_nc_parameter_constraints_string_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcParameterDescriptor.html + web::json::value make_nc_parameter_descriptor_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcProduct.html + web::json::value make_nc_product_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyChangeType.html + web::json::value make_nc_property_change_type_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyChangedEventData.html + web::json::value make_nc_property_changed_event_data_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyConstraints.html + web::json::value make_nc_property_contraints_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyConstraintsNumber.html + web::json::value make_nc_property_constraints_number_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyConstraintsString.html + web::json::value make_nc_property_constraints_string_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyDescriptor.html + web::json::value make_nc_property_descriptor_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyId.html + web::json::value make_nc_property_id_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcRegex.html + web::json::value make_nc_regex_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcResetCause.html + web::json::value make_nc_reset_cause_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcRolePath.html + web::json::value make_nc_role_path_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTimeInterval.html + web::json::value make_nc_time_interval_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpoint.html + web::json::value make_nc_touchpoint_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointNmos.html + web::json::value make_nc_touchpoint_nmos_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointNmosChannelMapping.html + web::json::value make_nc_touchpoint_nmos_channel_mapping_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointResource.html + web::json::value make_nc_touchpoint_resource_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointResourceNmos.html + web::json::value make_nc_touchpoint_resource_nmos_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointResourceNmosChannelMapping.html + web::json::value make_nc_touchpoint_resource_nmos_channel_mapping_datatype(); + // See // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcUri.html + web::json::value make_nc_uri_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcUuid.html + web::json::value make_nc_uuid_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcVersionCode.html + web::json::value make_nc_version_code_datatype(); + + // Monitoring datatypes + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#datatypes + // + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncconnectionstatus + web::json::value make_nc_connection_status_datatype(); + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncpayloadstatus + web::json::value make_nc_payload_status_datatype(); } #endif diff --git a/Development/nmos/control_protocol_resources.cpp b/Development/nmos/control_protocol_resources.cpp index aa126ce1f..e3a5c5f5a 100644 --- a/Development/nmos/control_protocol_resources.cpp +++ b/Development/nmos/control_protocol_resources.cpp @@ -7,82 +7,76 @@ namespace nmos { + namespace details + { + // create block resource + nmos::resource make_block(nmos::nc_oid oid, const web::json::value& owner, const utility::string_t& role, const utility::string_t& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, const web::json::value& members) + { + using web::json::value; + + auto data = details::make_nc_block(nc_block_class_id, oid, true, owner, role, value::string(user_label), touchpoints, runtime_property_constraints, true, members); + + return{ is12_versions::v1_0, types::nc_block, std::move(data), true }; + } + } + + // create block resource + nmos::resource make_block(nc_oid oid, nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, const web::json::value& members) + { + using web::json::value; + + return details::make_block(oid, value(owner), role, user_label, touchpoints, runtime_property_constraints, members); + } + + // create Root block resource + nmos::resource make_root_block() + { + using web::json::value; + + return details::make_block(1, value::null(), U("root"), U("Root"), value::null(), value::null(), value::array()); + } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager - nmos::resource make_device_manager(details::nc_oid oid, nmos::resource& root_block, const nmos::settings& settings) + nmos::resource make_device_manager(nc_oid oid, const nmos::settings& settings) { using web::json::value; - auto& root_block_data = root_block.data; - const auto& owner = nmos::fields::nc::oid(root_block_data); const auto user_label = value::string(U("Device manager")); - const auto description = value::string(U("The device manager offers information about the product this device is representing")); const auto& manufacturer = details::make_nc_manufacturer(nmos::experimental::fields::manufacturer_name(settings)); const auto& product = details::make_nc_product(nmos::experimental::fields::product_name(settings), nmos::experimental::fields::product_key(settings), nmos::experimental::fields::product_key(settings)); const auto& serial_number = nmos::experimental::fields::serial_number(settings); const auto device_name = value::null(); const auto device_role = value::null(); - const auto& operational_state = details::make_nc_device_operational_state(details::nc_device_generic_state::normal_operation, value::null()); - - auto data = details::make_nc_device_manager(oid, owner, user_label, value::null(), value::null(), - manufacturer, product, serial_number, value::null(), device_name, device_role, operational_state, details::nc_reset_cause::unknown); + const auto& operational_state = details::make_nc_device_operational_state(nc_device_generic_state::normal_operation, value::null()); - // add NcDeviceManager block_member_descriptor to root block members - web::json::push_back(root_block_data[nmos::fields::nc::members], - details::make_nc_block_member_descriptor(description, nmos::fields::nc::role(data), oid, nmos::fields::nc::constant_oid(data), data.at(nmos::fields::nc::class_id), user_label, owner)); + auto data = details::make_nc_device_manager(oid, root_block_oid, user_label, value::null(), value::null(), + manufacturer, product, serial_number, value::null(), device_name, device_role, operational_state, nc_reset_cause::unknown); return{ is12_versions::v1_0, types::nc_device_manager, std::move(data), true }; } // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager - nmos::resource make_class_manager(details::nc_oid oid, nmos::resource& root_block, const nmos::experimental::control_protocol_state& control_protocol_state) + nmos::resource make_class_manager(nc_oid oid, const nmos::experimental::control_protocol_state& control_protocol_state) { using web::json::value; - auto& root_block_data = root_block.data; - const auto& owner = nmos::fields::nc::oid(root_block_data); const auto user_label = value::string(U("Class manager")); - const auto description = value::string(U("The class manager offers access to control class and data type descriptors")); - auto data = details::make_nc_class_manager(oid, owner, user_label, value::null(), value::null(), control_protocol_state); - - // add NcClassManager block_member_descriptor to root block members - web::json::push_back(root_block_data[nmos::fields::nc::members], - details::make_nc_block_member_descriptor(description, nmos::fields::nc::role(data), oid, nmos::fields::nc::constant_oid(data), data.at(nmos::fields::nc::class_id), user_label, owner)); + auto data = details::make_nc_class_manager(oid, root_block_oid, user_label, value::null(), value::null(), control_protocol_state); return{ is12_versions::v1_0, types::nc_class_manager, std::move(data), true }; } - // create block resource - nmos::resource make_block(details::nc_oid oid, const web::json::value& owner, const utility::string_t& role, const utility::string_t& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, const web::json::value& members) - { - using web::json::value; - - auto data = details::make_nc_block(details::nc_block_class_id, oid, true, owner, role, value::string(user_label), touchpoints, runtime_property_constraints, true, members); - - return{ is12_versions::v1_0, types::nc_block, std::move(data), true }; - } - nmos::resource make_block(details::nc_oid oid, details::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, const web::json::value& members) - { - using web::json::value; - - return make_block(oid, value(owner), role, user_label, touchpoints, runtime_property_constraints, members); - } - - // create Root block resource - nmos::resource make_root_block() + // add to owner block member + bool add_member(const utility::string_t& child_description, const nmos::resource& child_block, nmos::resource& parent_block) { using web::json::value; - return make_block(1, value::null(), U("root"), U("Root")); - } - - // add member to nc_block - bool add_member_to_block(const utility::string_t& description, const web::json::value& nc_block, web::json::value& parent) - { - using web::json::value; + auto& parent = parent_block.data; + const auto& child = child_block.data; web::json::push_back(parent[nmos::fields::nc::members], - details::make_nc_block_member_descriptor(value::string(description), nmos::fields::nc::role(nc_block), nmos::fields::nc::oid(nc_block), nmos::fields::nc::constant_oid(nc_block), nc_block.at(nmos::fields::nc::class_id), nc_block.at(nmos::fields::nc::user_label), nmos::fields::nc::oid(parent))); + details::make_nc_block_member_descriptor(child_description, nmos::fields::nc::role(child), nmos::fields::nc::oid(child), nmos::fields::nc::constant_oid(child), details::parse_nc_class_id(nmos::fields::nc::class_id(child)), nmos::fields::nc::user_label(child), nmos::fields::nc::oid(parent))); return true; } diff --git a/Development/nmos/control_protocol_resources.h b/Development/nmos/control_protocol_resources.h index 205e16606..d3fdb44b1 100644 --- a/Development/nmos/control_protocol_resources.h +++ b/Development/nmos/control_protocol_resources.h @@ -1,8 +1,7 @@ #ifndef NMOS_CONTROL_PROTOCOL_RESOURCES_H #define NMOS_CONTROL_PROTOCOL_RESOURCES_H -#include -#include "nmos/control_protocol_resource.h" // for details::nc_oid definition +#include "nmos/control_protocol_typedefs.h" // for details::nc_oid definition #include "nmos/settings.h" namespace nmos @@ -14,21 +13,20 @@ namespace nmos struct resource; - // create device manager resource - nmos::resource make_device_manager(details::nc_oid oid, nmos::resource& root_block, const nmos::settings& settings); - - // create class manager resource - nmos::resource make_class_manager(details::nc_oid oid, nmos::resource& root_block, const nmos::experimental::control_protocol_state& control_protocol_state); - // create block resource - nmos::resource make_block(details::nc_oid oid, const web::json::value& owner, const utility::string_t& role, const utility::string_t& user_label, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null(), const web::json::value& members = web::json::value::array()); - nmos::resource make_block(details::nc_oid oid, details::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null(), const web::json::value& members = web::json::value::array()); - - // help function to add member to block - bool add_member_to_block(const utility::string_t& description, const web::json::value& nc_block, web::json::value& parent); + nmos::resource make_block(nc_oid oid, nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null(), const web::json::value& members = web::json::value::array()); // create Root block resource nmos::resource make_root_block(); + + // create Device manager resource + nmos::resource make_device_manager(nc_oid oid, const nmos::settings& settings); + + // create Class manager resource + nmos::resource make_class_manager(nc_oid oid, const nmos::experimental::control_protocol_state& control_protocol_state); + + // add to owner block member + bool add_member(const utility::string_t& child_description, const nmos::resource& child_block, nmos::resource& parent_block); } #endif diff --git a/Development/nmos/control_protocol_state.cpp b/Development/nmos/control_protocol_state.cpp index aceb88ef1..74c671636 100644 --- a/Development/nmos/control_protocol_state.cpp +++ b/Development/nmos/control_protocol_state.cpp @@ -6,28 +6,98 @@ namespace nmos { namespace experimental { + // create control class property + web::json::value make_control_class_property(const utility::string_t& description, const nc_property_id& id, const utility::string_t& name, const utility::string_t& type_name, bool is_read_only, bool is_nullable, bool is_sequence, bool is_deprecated, const web::json::value& constraints) + { + return nmos::details::make_nc_property_descriptor(description, id, name, type_name, is_read_only, is_nullable, is_sequence, is_deprecated, constraints); + } + + namespace details + { + control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const utility::string_t& name, const web::json::value& fixed_role, const std::vector& properties_, const std::vector& methods_, const std::vector& events_) + { + using web::json::value; + + web::json::value properties = value::array(); + for (const auto& property : properties_) { web::json::push_back(properties, property); } + web::json::value methods = value::array(); + for (const auto& method : methods_) { web::json::push_back(methods, method); } + web::json::value events = value::array(); + for (const auto& event : events_) { web::json::push_back(events, event); } + + return { value::string(description), class_id, name, fixed_role, properties, methods, events }; + } + } + + // create control class with fixed role + control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const utility::string_t& name, const utility::string_t& fixed_role, const std::vector& properties, const std::vector& methods, const std::vector& events) + { + using web::json::value; + + return details::make_control_class(description, class_id, name, value::string(fixed_role), properties, methods, events); + } + // create control class with no fixed role + control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const utility::string_t& name, const std::vector& properties, const std::vector& methods, const std::vector& events) + { + using web::json::value; + + return details::make_control_class(description, class_id, name, value::null(), properties, methods, events); + } + + // create control class method parameter + web::json::value make_control_class_method_parameter(const utility::string_t& description, const utility::string_t& name, const utility::string_t& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints) + { + return nmos::details::make_nc_parameter_descriptor(description, name, type_name, is_nullable, is_sequence, constraints); + } + + // create control class method + web::json::value make_control_class_method(const utility::string_t& description, const nc_method_id& id, const utility::string_t& name, const utility::string_t& result_datatype, const std::vector& parameters_, bool is_deprecated) + { + using web::json::value; + + value parameters = value::array(); + for (const auto& parameter : parameters_) { web::json::push_back(parameters, parameter); } + + return nmos::details::make_nc_method_descriptor(description, id, name, result_datatype, parameters, is_deprecated); + } + + // create control class event + web::json::value make_control_class_event(const utility::string_t& description, const nc_event_id& id, const utility::string_t& name, const utility::string_t& event_datatype, bool is_deprecated) + { + return nmos::details::make_nc_event_descriptor(description, id, name, event_datatype, is_deprecated); + } + control_protocol_state::control_protocol_state() { using web::json::value; + auto to_vector = [](const web::json::value& data) + { + if (!data.is_null()) + { + return std::vector(data.as_array().begin(), data.as_array().end()); + } + return std::vector{}; + }; + // setup the core control classes control_classes = { // Control class models // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/#control-class-models-for-branch-v10-dev - { details::make_nc_class_id(details::nc_object_class_id), { value::string(U("NcObject class descriptor")), details::nc_object_class_id, U("NcObject"), value::null(), details::make_nc_object_properties(), details::make_nc_object_methods(), details::make_nc_object_events() } }, - { details::make_nc_class_id(details::nc_block_class_id), { value::string(U("NcBlock class descriptor")), details::nc_block_class_id, U("NcBlock"), value::null(), details::make_nc_block_properties(), details::make_nc_block_methods(), details::make_nc_block_events() } }, - { details::make_nc_class_id(details::nc_worker_class_id), { value::string(U("NcWorker class descriptor")), details::nc_worker_class_id, U("NcWorker"), value::null(), details::make_nc_worker_properties(), details::make_nc_worker_methods(), details::make_nc_worker_events() } }, - { details::make_nc_class_id(details::nc_manager_class_id), { value::string(U("NcManager class descriptor")), details::nc_manager_class_id, U("NcManager"), value::null(), details::make_nc_manager_properties(), details::make_nc_manager_methods(), details::make_nc_manager_events() } }, - { details::make_nc_class_id(details::nc_device_manager_class_id), { value::string(U("NcDeviceManager class descriptor")), details::nc_device_manager_class_id, U("NcDeviceManager"), value::string(U("DeviceManager")), details::make_nc_device_manager_properties(), details::make_nc_device_manager_methods(), details::make_nc_device_manager_events() } }, - { details::make_nc_class_id(details::nc_class_manager_class_id), { value::string(U("NcClassManager class descriptor")), details::nc_class_manager_class_id, U("NcClassManager"), value::string(U("ClassManager")), details::make_nc_class_manager_properties(), details::make_nc_class_manager_methods(), details::make_nc_class_manager_events() } }, + { nmos::details::make_nc_class_id(nc_object_class_id), make_control_class(U("NcObject class descriptor"), nc_object_class_id, U("NcObject"), to_vector(make_nc_object_properties()), to_vector(make_nc_object_methods()), to_vector(make_nc_object_events())) }, + { nmos::details::make_nc_class_id(nc_block_class_id), make_control_class(U("NcBlock class descriptor"), nc_block_class_id, U("NcBlock"), to_vector(make_nc_block_properties()), to_vector(make_nc_block_methods()), to_vector(make_nc_block_events())) }, + { nmos::details::make_nc_class_id(nc_worker_class_id), make_control_class(U("NcWorker class descriptor"), nc_worker_class_id, U("NcWorker"), to_vector(make_nc_worker_properties()), to_vector(make_nc_worker_methods()), to_vector(make_nc_worker_events())) }, + { nmos::details::make_nc_class_id(nc_manager_class_id), make_control_class(U("NcManager class descriptor"), nc_manager_class_id, U("NcManager"),to_vector(make_nc_manager_properties()), to_vector(make_nc_manager_methods()), to_vector(make_nc_manager_events())) }, + { nmos::details::make_nc_class_id(nc_device_manager_class_id), make_control_class(U("NcDeviceManager class descriptor"), nc_device_manager_class_id, U("NcDeviceManager"), U("DeviceManager"), to_vector(make_nc_device_manager_properties()), to_vector(make_nc_device_manager_methods()), to_vector(make_nc_device_manager_events())) }, + { nmos::details::make_nc_class_id(nc_class_manager_class_id), make_control_class(U("NcClassManager class descriptor"), nc_class_manager_class_id, U("NcClassManager"), U("ClassManager"), to_vector(make_nc_class_manager_properties()), to_vector(make_nc_class_manager_methods()), to_vector(make_nc_class_manager_events())) }, // identification beacon model // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/identification/#ncidentbeacon - { details::make_nc_class_id(details::nc_ident_beacon_class_id), { value::string(U("NcIdentBeacon class descriptor")), details::nc_ident_beacon_class_id, U("NcIdentBeacon"), value::null(), details::make_nc_ident_beacon_properties(), details::make_nc_ident_beacon_methods(), details::make_nc_ident_beacon_events() } }, + { nmos::details::make_nc_class_id(nc_ident_beacon_class_id), make_control_class(U("NcIdentBeacon class descriptor"), nc_ident_beacon_class_id, U("NcIdentBeacon"), to_vector(make_nc_ident_beacon_properties()), to_vector(make_nc_ident_beacon_methods()), to_vector(make_nc_ident_beacon_events())) }, // Monitoring // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitor - { details::make_nc_class_id(details::nc_receiver_monitor_class_id), { value::string(U("NcReceiverMonitor class descriptor")), details::nc_receiver_monitor_class_id, U("NcReceiverMonitor"), value::null(), details::make_nc_receiver_monitor_properties(), details::make_nc_receiver_monitor_methods(), details::make_nc_receiver_monitor_events() } }, - { details::make_nc_class_id(details::nc_receiver_monitor_protected_class_id), { value::string(U("NcReceiverMonitorProtected class descriptor")), details::nc_receiver_monitor_protected_class_id, U("NcReceiverMonitorProtected"), value::null(), details::make_nc_receiver_monitor_protected_properties(), details::make_nc_receiver_monitor_protected_methods(), details::make_nc_receiver_monitor_protected_events() } } + { nmos::details::make_nc_class_id(nc_receiver_monitor_class_id), make_control_class(U("NcReceiverMonitor class descriptor"), nc_receiver_monitor_class_id, U("NcReceiverMonitor"), to_vector(make_nc_receiver_monitor_properties()), to_vector(make_nc_receiver_monitor_methods()), to_vector(make_nc_receiver_monitor_events())) }, + { nmos::details::make_nc_class_id(nc_receiver_monitor_protected_class_id), make_control_class(U("NcReceiverMonitorProtected class descriptor"), nc_receiver_monitor_protected_class_id, U("NcReceiverMonitorProtected"), to_vector(make_nc_receiver_monitor_protected_properties()), to_vector(make_nc_receiver_monitor_protected_methods()), to_vector(make_nc_receiver_monitor_protected_events())) } }; // setup the core datatypes @@ -35,69 +105,127 @@ namespace nmos { // Dataype models // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/#datatype-models-for-branch-v10-dev - { U("NcClassId"), {details::make_nc_class_id_datatype()} }, - { U("NcOid"), {details::make_nc_oid_datatype()} }, - { U("NcTouchpoint"), {details::make_nc_touchpoint_datatype()} }, - { U("NcElementId"), {details::make_nc_element_id_datatype()} }, - { U("NcPropertyId"), {details::make_nc_property_id_datatype()} }, - { U("NcPropertyConstraints"), {details::make_nc_property_contraints_datatype()} }, - { U("NcMethodResultPropertyValue"), {details::make_nc_method_result_property_value_datatype()} }, - { U("NcMethodStatus"), {details::make_nc_method_status_datatype()} }, - { U("NcMethodResult"), {details::make_nc_method_result_datatype()} }, - { U("NcId"), {details::make_nc_id_datatype()} }, - { U("NcMethodResultId"), {details::make_nc_method_result_id_datatype()} }, - { U("NcMethodResultLength"), {details::make_nc_method_result_length_datatype()} }, - { U("NcPropertyChangeType"), {details::make_nc_property_change_type_datatype()} }, - { U("NcPropertyChangedEventData"), {details::make_nc_property_changed_event_data_datatype()} }, - { U("NcDescriptor"), {details::make_nc_descriptor_datatype()} }, - { U("NcBlockMemberDescriptor"), {details::make_nc_block_member_descriptor_datatype()} }, - { U("NcMethodResultBlockMemberDescriptors"), {details::make_nc_method_result_block_member_descriptors_datatype()} }, - { U("NcVersionCode"), {details::make_nc_version_code_datatype()} }, - { U("NcOrganizationId"), {details::make_nc_organization_id_datatype()} }, - { U("NcUri"), {details::make_nc_uri_datatype()} }, - { U("NcManufacturer"), {details::make_nc_manufacturer_datatype()} }, - { U("NcUuid"), {details::make_nc_uuid_datatype()} }, - { U("NcProduct"), {details::make_nc_product_datatype()} }, - { U("NcDeviceGenericState"), {details::make_nc_device_generic_state_datatype()} }, - { U("NcDeviceOperationalState"), {details::make_nc_device_operational_state_datatype()} }, - { U("NcResetCause"), {details::make_nc_reset_cause_datatype()} }, - { U("NcName"), {details::make_nc_name_datatype()} }, - { U("NcPropertyDescriptor"), {details::make_nc_property_descriptor_datatype()} }, - { U("NcParameterDescriptor"), {details::make_nc_parameter_descriptor_datatype()} }, - { U("NcMethodId"), {details::make_nc_method_id_datatype()} }, - { U("NcMethodDescriptor"), {details::make_nc_method_descriptor_datatype()} }, - { U("NcEventId"), {details::make_nc_event_id_datatype()} }, - { U("NcEventDescriptor"), {details::make_nc_event_descriptor_datatype()} }, - { U("NcClassDescriptor"), {details::make_nc_class_descriptor_datatype()} }, - { U("NcParameterConstraints"), {details::make_nc_parameter_constraints_datatype()} }, - { U("NcDatatypeType"), {details::make_nc_datatype_type_datatype()} }, - { U("NcDatatypeDescriptor"), {details::make_nc_datatype_descriptor_datatype()} }, - { U("NcMethodResultClassDescriptor"), {details::make_nc_method_result_class_descriptor_datatype()} }, - { U("NcMethodResultDatatypeDescriptor"), {details::make_nc_method_result_datatype_descriptor_datatype()} }, - { U("NcMethodResultError"), {details::make_nc_method_result_error_datatype()} }, - { U("NcDatatypeDescriptorEnum"), {details::make_nc_datatype_descriptor_enum_datatype()} }, - { U("NcDatatypeDescriptorPrimitive"), {details::make_nc_datatype_descriptor_primitive_datatype()} }, - { U("NcDatatypeDescriptorStruct"), {details::make_nc_datatype_descriptor_struct_datatype()} }, - { U("NcDatatypeDescriptorTypeDef"), {details::make_nc_datatype_descriptor_type_def_datatype()} }, - { U("NcEnumItemDescriptor"), {details::make_nc_enum_item_descriptor_datatype()} }, - { U("NcFieldDescriptor"), {details::make_nc_field_descriptor_datatype()} }, - { U("NcPropertyConstraintsNumber"), {details::make_nc_property_constraints_number_datatype()} }, - { U("NcPropertyConstraintsString"), {details::make_nc_property_constraints_string_datatype()} }, - { U("NcRegex"), {details::make_nc_regex_datatype()} }, - { U("NcRolePath"), {details::make_nc_role_path_datatype()} }, - { U("NcParameterConstraintsNumber"), {details::make_nc_parameter_constraints_number_datatype()} }, - { U("NcParameterConstraintsString"), {details::make_nc_parameter_constraints_string_datatype()} }, - { U("NcTimeInterval"), {details::make_nc_time_interval_datatype()} }, - { U("NcTouchpointNmos"), {details::make_nc_touchpoint_nmos_datatype()} }, - { U("NcTouchpointNmosChannelMapping"), {details::make_nc_touchpoint_nmos_channel_mapping_datatype()} }, - { U("NcTouchpointResource"), {details::make_nc_touchpoint_resource_datatype()} }, - { U("NcTouchpointResourceNmos"), {details::make_nc_touchpoint_resource_nmos_datatype()} }, - { U("NcTouchpointResourceNmosChannelMapping"), {details::make_nc_touchpoint_resource_nmos_channel_mapping_datatype()} }, + { U("NcClassId"), {make_nc_class_id_datatype()} }, + { U("NcOid"), {make_nc_oid_datatype()} }, + { U("NcTouchpoint"), {make_nc_touchpoint_datatype()} }, + { U("NcElementId"), {make_nc_element_id_datatype()} }, + { U("NcPropertyId"), {make_nc_property_id_datatype()} }, + { U("NcPropertyConstraints"), {make_nc_property_contraints_datatype()} }, + { U("NcMethodResultPropertyValue"), {make_nc_method_result_property_value_datatype()} }, + { U("NcMethodStatus"), {make_nc_method_status_datatype()} }, + { U("NcMethodResult"), {make_nc_method_result_datatype()} }, + { U("NcId"), {make_nc_id_datatype()} }, + { U("NcMethodResultId"), {make_nc_method_result_id_datatype()} }, + { U("NcMethodResultLength"), {make_nc_method_result_length_datatype()} }, + { U("NcPropertyChangeType"), {make_nc_property_change_type_datatype()} }, + { U("NcPropertyChangedEventData"), {make_nc_property_changed_event_data_datatype()} }, + { U("NcDescriptor"), {make_nc_descriptor_datatype()} }, + { U("NcBlockMemberDescriptor"), {make_nc_block_member_descriptor_datatype()} }, + { U("NcMethodResultBlockMemberDescriptors"), {make_nc_method_result_block_member_descriptors_datatype()} }, + { U("NcVersionCode"), {make_nc_version_code_datatype()} }, + { U("NcOrganizationId"), {make_nc_organization_id_datatype()} }, + { U("NcUri"), {make_nc_uri_datatype()} }, + { U("NcManufacturer"), {make_nc_manufacturer_datatype()} }, + { U("NcUuid"), {make_nc_uuid_datatype()} }, + { U("NcProduct"), {make_nc_product_datatype()} }, + { U("NcDeviceGenericState"), {make_nc_device_generic_state_datatype()} }, + { U("NcDeviceOperationalState"), {make_nc_device_operational_state_datatype()} }, + { U("NcResetCause"), {make_nc_reset_cause_datatype()} }, + { U("NcName"), {make_nc_name_datatype()} }, + { U("NcPropertyDescriptor"), {make_nc_property_descriptor_datatype()} }, + { U("NcParameterDescriptor"), {make_nc_parameter_descriptor_datatype()} }, + { U("NcMethodId"), {make_nc_method_id_datatype()} }, + { U("NcMethodDescriptor"), {make_nc_method_descriptor_datatype()} }, + { U("NcEventId"), {make_nc_event_id_datatype()} }, + { U("NcEventDescriptor"), {make_nc_event_descriptor_datatype()} }, + { U("NcClassDescriptor"), {make_nc_class_descriptor_datatype()} }, + { U("NcParameterConstraints"), {make_nc_parameter_constraints_datatype()} }, + { U("NcDatatypeType"), {make_nc_datatype_type_datatype()} }, + { U("NcDatatypeDescriptor"), {make_nc_datatype_descriptor_datatype()} }, + { U("NcMethodResultClassDescriptor"), {make_nc_method_result_class_descriptor_datatype()} }, + { U("NcMethodResultDatatypeDescriptor"), {make_nc_method_result_datatype_descriptor_datatype()} }, + { U("NcMethodResultError"), {make_nc_method_result_error_datatype()} }, + { U("NcDatatypeDescriptorEnum"), {make_nc_datatype_descriptor_enum_datatype()} }, + { U("NcDatatypeDescriptorPrimitive"), {make_nc_datatype_descriptor_primitive_datatype()} }, + { U("NcDatatypeDescriptorStruct"), {make_nc_datatype_descriptor_struct_datatype()} }, + { U("NcDatatypeDescriptorTypeDef"), {make_nc_datatype_descriptor_type_def_datatype()} }, + { U("NcEnumItemDescriptor"), {make_nc_enum_item_descriptor_datatype()} }, + { U("NcFieldDescriptor"), {make_nc_field_descriptor_datatype()} }, + { U("NcPropertyConstraintsNumber"), {make_nc_property_constraints_number_datatype()} }, + { U("NcPropertyConstraintsString"), {make_nc_property_constraints_string_datatype()} }, + { U("NcRegex"), {make_nc_regex_datatype()} }, + { U("NcRolePath"), {make_nc_role_path_datatype()} }, + { U("NcParameterConstraintsNumber"), {make_nc_parameter_constraints_number_datatype()} }, + { U("NcParameterConstraintsString"), {make_nc_parameter_constraints_string_datatype()} }, + { U("NcTimeInterval"), {make_nc_time_interval_datatype()} }, + { U("NcTouchpointNmos"), {make_nc_touchpoint_nmos_datatype()} }, + { U("NcTouchpointNmosChannelMapping"), {make_nc_touchpoint_nmos_channel_mapping_datatype()} }, + { U("NcTouchpointResource"), {make_nc_touchpoint_resource_datatype()} }, + { U("NcTouchpointResourceNmos"), {make_nc_touchpoint_resource_nmos_datatype()} }, + { U("NcTouchpointResourceNmosChannelMapping"), {make_nc_touchpoint_resource_nmos_channel_mapping_datatype()} }, // Monitoring // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#datatypes - { U("NcConnectionStatus"), {details::make_nc_connection_status_datatype()} }, - { U("NcPayloadStatus"), {details::make_nc_payload_status_datatype()} } + { U("NcConnectionStatus"), {make_nc_connection_status_datatype()} }, + { U("NcPayloadStatus"), {make_nc_payload_status_datatype()} } }; } + + // insert control class, false if class already presented + bool control_protocol_state::insert(const experimental::control_class& control_class) + { + const auto& class_id = nmos::details::make_nc_class_id(control_class.class_id); + + auto lock = write_lock(); + + if (control_classes.end() == control_classes.find(class_id)) + { + control_classes[nmos::details::make_nc_class_id(control_class.class_id)] = control_class; + return true; + } + return false; + } + + // erase control class of the given class id, false if the required class not found + bool control_protocol_state::erase(nc_class_id class_id_) + { + const auto& class_id = nmos::details::make_nc_class_id(class_id_); + + auto lock = write_lock(); + + if (control_classes.end() != control_classes.find(class_id)) + { + control_classes.erase(class_id); + return true; + } + return false; + } + + // insert datatype, false if datatype already presented + bool control_protocol_state::insert(const experimental::datatype& datatype) + { + const auto& name = nmos::fields::nc::name(datatype.descriptor); + + auto lock = write_lock(); + + if (datatypes.end() == datatypes.find(name)) + { + datatypes[name] = datatype; + return true; + } + return false; + } + + // erase datatype of the given datatype name, false if the required datatype not found + bool control_protocol_state::erase(const utility::string_t& name) + { + auto lock = write_lock(); + + if (datatypes.end() != datatypes.find(name)) + { + datatypes.erase(name); + return true; + } + return false; + } } } \ No newline at end of file diff --git a/Development/nmos/control_protocol_state.h b/Development/nmos/control_protocol_state.h index 82f4e755f..ddf68e906 100644 --- a/Development/nmos/control_protocol_state.h +++ b/Development/nmos/control_protocol_state.h @@ -3,7 +3,7 @@ #include #include "cpprest/json_utils.h" -#include "nmos/control_protocol_class_id.h" // for nmos::details::nc_class_id definitions +#include "nmos/control_protocol_typedefs.h" #include "nmos/mutex.h" #include "nmos/resources.h" @@ -16,11 +16,11 @@ namespace nmos struct control_class // NcClassDescriptor { web::json::value description; - nmos::details::nc_class_id class_id; + nmos::nc_class_id class_id; utility::string_t name; web::json::value fixed_role; - web::json::value properties; // array of nc_property_descriptor + web::json::value properties; // array of nc_property_descriptor web::json::value methods; // array of nc_method_descriptor web::json::value events; // array of nc_event_descriptor }; @@ -51,7 +51,38 @@ namespace nmos nmos::write_lock write_lock() const { return nmos::write_lock{ mutex }; } control_protocol_state(); + + // insert control class, false if class already presented + bool insert(const experimental::control_class& control_class); + // erase control class of the given class id, false if the required class not found + bool erase(nc_class_id class_id); + + // insert datatype, false if datatype already presented + bool insert(const experimental::datatype& datatype); + // erase datatype of the given datatype name, false if the required datatype not found + bool erase(const utility::string_t& name); }; + + // helper functions to create non-standard control class + // + // create control class method parameter + web::json::value make_control_class_method_parameter(const utility::string_t& description, const utility::string_t& name, const utility::string_t& type_name, + bool is_nullable = false, bool is_sequence = false, const web::json::value& constraints = web::json::value::null()); + // create control class method + web::json::value make_control_class_method(const utility::string_t& description, const nc_method_id& id, const utility::string_t& name, const utility::string_t& result_datatype, + const std::vector& parameters = {}, bool is_deprecated = false); + + // create control class event + web::json::value make_control_class_event(const utility::string_t& description, const nc_event_id& id, const utility::string_t& name, const utility::string_t& event_datatype, + bool is_deprecated = false); + + // create control class property + web::json::value make_control_class_property(const utility::string_t& description, const nc_property_id& id, const utility::string_t& name, const utility::string_t& type_name, + bool is_read_only = false, bool is_nullable = false, bool is_sequence = false, bool is_deprecated = false, const web::json::value& constraints = web::json::value::null()); + // create control class with fixed role + control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const utility::string_t& name, const utility::string_t& fixed_role, const std::vector& properties, const std::vector& methods, const std::vector& events); + // create control class with no fixed role + control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const utility::string_t& name, const std::vector& properties, const std::vector& methods, const std::vector& events); } } diff --git a/Development/nmos/control_protocol_typedefs.h b/Development/nmos/control_protocol_typedefs.h new file mode 100644 index 000000000..310a16af4 --- /dev/null +++ b/Development/nmos/control_protocol_typedefs.h @@ -0,0 +1,183 @@ +#ifndef NMOS_CONTROL_PROTOCOL_TYPEDEFS_H +#define NMOS_CONTROL_PROTOCOL_TYPEDEFS_H + +#include "cpprest/basic_utils.h" + +namespace web +{ + namespace json + { + class value; + } +} + +namespace nmos +{ + namespace nc_message_type + { + enum type + { + command = 0, + command_response = 1, + notification = 2, + subscription = 3, + subscription_response = 4, + error = 5 + }; + } + + // Method invokation status + namespace nc_method_status + { + enum status + { + ok = 200, // Method call was successful + property_deprecated = 298, // Method call was successful but targeted property is deprecated + method_deprecated = 299, // Method call was successful but method is deprecated + bad_command_format = 400, // Badly-formed command + unathorized = 401, // Client is not authorized + bad_oid = 404, // Command addresses a nonexistent object + read_only = 405, // Attempt to change read-only state + invalid_request = 406, // Method call is invalid in current operating context + conflict = 409, // There is a conflict with the current state of the device + buffer_overflow = 413, // Something was too big + index_out_of_bounds = 414, // Index is outside the available range + parameter_error = 417, // Method parameter does not meet expectations + locked = 423, // Addressed object is locked + device_error = 500, // Internal device error + method_not_implemented = 501, // Addressed method is not implemented by the addressed object + property_not_implemented = 502, // Addressed property is not implemented by the addressed object + not_ready = 503, // The device is not ready to handle any commands + timeout = 504, // Method call did not finish within the allotted time + property_version_error = 505 // Incompatible protocol version + }; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmethodresult + struct nc_method_result + { + nc_method_status::status status; + }; + + // Datatype type + namespace nc_datatype_type + { + enum type + { + Primitive = 0, + Typedef = 1, + Struct = 2, + Enum = 3 + }; + } + + // Device generic operational state + namespace nc_device_generic_state + { + enum state + { + unknown = 0, // Unknown + normal_operation = 1, // Normal operation + initializing = 2, // Device is initializing + updating = 3, // Device is performing a software or firmware update + licensing_error = 4, // Device is experiencing a licensing error + internal_error = 5 // Device is experiencing an internal error + }; + } + + // Reset cause enum + namespace nc_reset_cause + { + enum cause + { + unknown = 0, // Unknown + power_on = 1, // Power on + internal_error = 2, // Internal error + upgrade = 3, // Upgrade + controller_request = 4, // Controller request + manual_reset = 5 // Manual request from the front panel + }; + } + + // NcConnectionStatus + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncconnectionstatus + namespace nc_connection_status + { + enum status + { + undefined = 0, // This is the value when there is no receiver + connected = 1, // Connected to a stream + disconnected = 2, // Not connected to a stream + connection_error = 3 // A connection error was encountered + }; + } + + // NcPayloadStatus + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncpayloadstatus + namespace nc_payload_status + { + enum status + { + undefined = 0, // This is the value when there's no connection. + payload_ok = 1, // Payload is being received without errors and is the correct type + payload_format_unsupported = 2, // Payload is being received but is of an unsupported type + payloadError = 3 // A payload error was encountered + }; + } + + // NcElementId + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncelementid + struct nc_element_id + { + uint16_t level; + uint16_t index; + }; + + // NcEventId + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#nceventid + typedef nc_element_id nc_event_id; + + // NcMethodId + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmethodid + typedef nc_element_id nc_method_id; + + // NcPropertyId + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncpropertyid + typedef nc_element_id nc_property_id; + + // NcId + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncid + typedef uint32_t nc_id; + + // NcOid + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncoid + typedef uint32_t nc_oid; + const nc_oid root_block_oid{ 1 }; + + // NcUri + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncuri + typedef utility::string_t nc_uri; + + // NcUuid + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncuuid + typedef utility::string_t nc_uuid; + + // NcClassId + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassid + typedef std::vector nc_class_id; + const nc_class_id nc_object_class_id({ 1 }); + const nc_class_id nc_block_class_id({ 1, 1 }); + const nc_class_id nc_worker_class_id({ 1, 2 }); + const nc_class_id nc_manager_class_id({ 1, 3 }); + const nc_class_id nc_device_manager_class_id({ 1, 3, 1 }); + const nc_class_id nc_class_manager_class_id({ 1, 3, 2 }); + const nc_class_id nc_ident_beacon_class_id({ 1, 2, 2 }); + const nc_class_id nc_receiver_monitor_class_id({ 1, 2, 3 }); + const nc_class_id nc_receiver_monitor_protected_class_id({ 1, 2, 3, 1 }); + + // NcTouchpoint + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#nctouchpoint + typedef utility::string_t nc_touch_point; +} + +#endif diff --git a/Development/nmos/control_protocol_utils.cpp b/Development/nmos/control_protocol_utils.cpp index a19f58699..3db423168 100644 --- a/Development/nmos/control_protocol_utils.cpp +++ b/Development/nmos/control_protocol_utils.cpp @@ -4,7 +4,8 @@ #include #include #include "cpprest/json_utils.h" -#include "nmos/control_protocol_resource.h" // for nc_object_class_id, nc_manager_class_id, nc_device_manager_class_id, nc_class_manager_class_id +#include "nmos/control_protocol_resource.h" +#include "nmos/control_protocol_typedefs.h" #include "nmos/json_fields.h" #include "nmos/resources.h" @@ -22,34 +23,34 @@ namespace nmos } return control_class_id == class_id; } + } - bool is_nc_block(const nc_class_id& class_id) - { - return is_control_class(nc_object_class_id, class_id); - } + bool is_nc_block(const nc_class_id& class_id) + { + return details::is_control_class(nc_object_class_id, class_id); + } - bool is_nc_manager(const nc_class_id& class_id) - { - return is_control_class(nc_manager_class_id, class_id); - } + bool is_nc_manager(const nc_class_id& class_id) + { + return details::is_control_class(nc_manager_class_id, class_id); + } - bool is_nc_device_manager(const nc_class_id& class_id) - { - return is_control_class(nc_device_manager_class_id, class_id); - } + bool is_nc_device_manager(const nc_class_id& class_id) + { + return details::is_control_class(nc_device_manager_class_id, class_id); + } - bool is_nc_class_manager(const nc_class_id& class_id) - { - return is_control_class(nc_class_manager_class_id, class_id); - } + bool is_nc_class_manager(const nc_class_id& class_id) + { + return details::is_control_class(nc_class_manager_class_id, class_id); + } - nc_class_id make_nc_class_id(const nc_class_id& prefix, int32_t authority_key, const nc_class_id& suffix) - { - nc_class_id class_id = prefix; - class_id.push_back(authority_key); - class_id.insert(class_id.end(), suffix.begin(), suffix.end()); - return class_id; - } + nc_class_id make_nc_class_id(const nc_class_id& prefix, int32_t authority_key, const nc_class_id& suffix) + { + nc_class_id class_id = prefix; + class_id.push_back(authority_key); + class_id.insert(class_id.end(), suffix.begin(), suffix.end()); + return class_id; } void get_member_descriptors(const resources& resources, resources::iterator resource, bool recurse, web::json::array& descriptors) @@ -69,7 +70,7 @@ namespace nmos // get members on all NcBlock(s) for (const auto& member : members) { - if (details::is_nc_block(details::parse_nc_class_id(nmos::fields::nc::class_id(member)))) + if (is_nc_block(nmos::details::parse_nc_class_id(nmos::fields::nc::class_id(member)))) { // get resource based on the oid const auto& oid = nmos::fields::nc::oid(member); @@ -119,7 +120,7 @@ namespace nmos // do role match on all NcBlock(s) for (const auto& member : members) { - if (details::is_nc_block(details::parse_nc_class_id(nmos::fields::nc::class_id(member)))) + if (is_nc_block(nmos::details::parse_nc_class_id(nmos::fields::nc::class_id(member)))) { // get resource based on the oid const auto& oid = nmos::fields::nc::oid(member); @@ -131,7 +132,7 @@ namespace nmos } } - void find_members_by_class_id(const resources& resources, resources::iterator resource, const details::nc_class_id& class_id_, bool include_derived, bool recurse, web::json::array& descriptors) + void find_members_by_class_id(const resources& resources, resources::iterator resource, const nc_class_id& class_id_, bool include_derived, bool recurse, web::json::array& descriptors) { auto find_members_by_matching_class_id = [&](const web::json::array& members) { @@ -139,7 +140,7 @@ namespace nmos auto match = [&](const web::json::value& descriptor) { - const auto& class_id = details::parse_nc_class_id(nmos::fields::nc::class_id(descriptor)); + const auto& class_id = nmos::details::parse_nc_class_id(nmos::fields::nc::class_id(descriptor)); if (include_derived) { return !boost::find_first(class_id, class_id_).empty(); } else { return class_id == class_id_; } @@ -163,7 +164,7 @@ namespace nmos // do class_id match on all NcBlock(s) for (const auto& member : members) { - if (details::is_nc_block(details::parse_nc_class_id(nmos::fields::nc::class_id(member)))) + if (is_nc_block(nmos::details::parse_nc_class_id(nmos::fields::nc::class_id(member)))) { // get resource based on the oid const auto& oid = nmos::fields::nc::oid(member); diff --git a/Development/nmos/control_protocol_utils.h b/Development/nmos/control_protocol_utils.h index ec59aa747..acb4a7c76 100644 --- a/Development/nmos/control_protocol_utils.h +++ b/Development/nmos/control_protocol_utils.h @@ -2,29 +2,26 @@ #define NMOS_CONTROL_PROTOCOL_UTILS_H #include "cpprest/basic_utils.h" -#include "nmos/control_protocol_class_id.h" // for nc_class_id definition +#include "nmos/control_protocol_typedefs.h" // for nc_class_id definition #include "nmos/resources.h" namespace nmos { - namespace details - { - bool is_nc_block(const nc_class_id& class_id); + bool is_nc_block(const nc_class_id& class_id); - bool is_nc_manager(const nc_class_id& class_id); + bool is_nc_manager(const nc_class_id& class_id); - bool is_nc_device_manager(const nc_class_id& class_id); + bool is_nc_device_manager(const nc_class_id& class_id); - bool is_nc_class_manager(const nc_class_id& class_id); + bool is_nc_class_manager(const nc_class_id& class_id); - nc_class_id make_nc_class_id(const nc_class_id& prefix, int32_t authority_key, const nc_class_id& suffix); - } + nc_class_id make_nc_class_id(const nc_class_id& prefix, int32_t authority_key, const nc_class_id& suffix); void get_member_descriptors(const resources& resources, resources::iterator resource, bool recurse, web::json::array& descriptors); void find_members_by_role(const resources& resources, resources::iterator resource, const utility::string_t& role, bool match_whole_string, bool case_sensitive, bool recurse, web::json::array& nc_block_member_descriptors); - void find_members_by_class_id(const resources& resources, resources::iterator resource, const details::nc_class_id& class_id, bool include_derived, bool recurse, web::json::array& descriptors); + void find_members_by_class_id(const resources& resources, resources::iterator resource, const nc_class_id& class_id, bool include_derived, bool recurse, web::json::array& descriptors); } #endif diff --git a/Development/nmos/control_protocol_ws_api.cpp b/Development/nmos/control_protocol_ws_api.cpp index 1dabbef21..9e9c80784 100644 --- a/Development/nmos/control_protocol_ws_api.cpp +++ b/Development/nmos/control_protocol_ws_api.cpp @@ -5,6 +5,7 @@ #include "cpprest/regex_utils.h" #include "nmos/api_utils.h" #include "nmos/control_protocol_resources.h" +#include "nmos/control_protocol_resource.h" #include "nmos/control_protocol_state.h" #include "nmos/control_protocol_utils.h" #include "nmos/is12_versions.h" @@ -56,7 +57,7 @@ namespace nmos while (!class_id.empty()) { - auto class_found = control_classes.find(make_nc_class_id(class_id)); + auto class_found = control_classes.find(nmos::details::make_nc_class_id(class_id)); if (control_classes.end() != class_found) { auto& properties = class_found->second.properties.as_array(); @@ -88,19 +89,19 @@ namespace nmos const auto& property_id = nmos::fields::nc::id(arguments); - slog::log(gate, SLOG_FLF) << "Get property: " << property_id.to_string(); + slog::log(gate, SLOG_FLF) << "Get property: " << property_id.serialize(); // find the relevant nc_property_descriptor const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); if (!property.is_null()) { - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, resource->data.at(nmos::fields::nc::name(property))); + return make_control_protocol_response(handle, { nc_method_status::ok }, resource->data.at(nmos::fields::nc::name(property))); } // unknown property utility::stringstream_t ss; ss << U("unknown property: ") << property_id.serialize() << U(" to do Get"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); + return make_control_protocol_error_response(handle, { nc_method_status::property_not_implemented }, ss.str()); }; // Set property value const auto set = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes&, slog::base_gate& gate) @@ -110,7 +111,7 @@ namespace nmos const auto& property_id = nmos::fields::nc::id(arguments); const auto& val = nmos::fields::nc::value(arguments); - slog::log(gate, SLOG_FLF) << "Set property: " << property_id.to_string() << " value: " << val.to_string(); + slog::log(gate, SLOG_FLF) << "Set property: " << property_id.serialize() << " value: " << val.serialize(); // find the relevant nc_property_descriptor const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); @@ -118,13 +119,13 @@ namespace nmos { if (nmos::fields::nc::is_read_only(property)) { - return details::make_control_protocol_response(handle, { details::nc_method_status::read_only }); + return make_control_protocol_response(handle, { nc_method_status::read_only }); } if ((val.is_null() && !nmos::fields::nc::is_nullable(property)) || (val.is_array() && !nmos::fields::nc::is_sequence(property))) { - return details::make_control_protocol_response(handle, { details::nc_method_status::parameter_error }); + return make_control_protocol_response(handle, { nc_method_status::parameter_error }); } resources.modify(resource, [&](nmos::resource& resource) @@ -133,13 +134,13 @@ namespace nmos resource.updated = strictly_increasing_update(resources); }); - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }); + return make_control_protocol_response(handle, { nc_method_status::ok }); } // unknown property utility::stringstream_t ss; ss << U("unknown property: ") << property_id.serialize() << " to do Set"; - return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); + return make_control_protocol_error_response(handle, { nc_method_status::property_not_implemented }, ss.str()); }; // Get sequence item const auto get_sequence_item = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes&, slog::base_gate& gate) @@ -149,7 +150,7 @@ namespace nmos const auto& property_id = nmos::fields::nc::id(arguments); const auto& index = nmos::fields::nc::index(arguments); - slog::log(gate, SLOG_FLF) << "Get sequence item: " << property_id.to_string() << " index: " << index; + slog::log(gate, SLOG_FLF) << "Get sequence item: " << property_id.serialize() << " index: " << index; // find the relevant nc_property_descriptor const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); @@ -160,26 +161,26 @@ namespace nmos // property is not a sequence utility::stringstream_t ss; ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do GetSequenceItem"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); + return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); } auto& data = resource->data.at(nmos::fields::nc::name(property)); if (!data.is_null() && data.as_array().size() > (size_t)index) { - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, data.at(index)); + return make_control_protocol_response(handle, { nc_method_status::ok }, data.at(index)); } // out of bound utility::stringstream_t ss; ss << U("property: ") << property_id.serialize() << U(" is outside the available range to do GetSequenceItem"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::index_out_of_bounds }, ss.str()); + return make_control_protocol_error_response(handle, { nc_method_status::index_out_of_bounds }, ss.str()); } // unknown property utility::stringstream_t ss; ss << U("unknown property: ") << property_id.serialize() << U(" to do GetSequenceItem"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); + return make_control_protocol_error_response(handle, { nc_method_status::property_not_implemented }, ss.str()); }; // Set sequence item const auto set_sequence_item = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes&, slog::base_gate& gate) @@ -190,7 +191,7 @@ namespace nmos const auto& index = nmos::fields::nc::index(arguments); const auto& val = nmos::fields::nc::value(arguments); - slog::log(gate, SLOG_FLF) << "Set sequence item: " << property_id.to_string() << " index: " << index << " value: " << val.to_string(); + slog::log(gate, SLOG_FLF) << "Set sequence item: " << property_id.serialize() << " index: " << index << " value: " << val.serialize(); // find the relevant nc_property_descriptor const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); @@ -201,7 +202,7 @@ namespace nmos // property is not a sequence utility::stringstream_t ss; ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do SetSequenceItem"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); + return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); } auto& data = resource->data.at(nmos::fields::nc::name(property)); @@ -214,19 +215,19 @@ namespace nmos resource.updated = strictly_increasing_update(resources); }); - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }); + return make_control_protocol_response(handle, { nc_method_status::ok }); } // out of bound utility::stringstream_t ss; ss << U("property: ") << property_id.serialize() << U(" is outside the available range to do SetSequenceItem"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::index_out_of_bounds }, ss.str()); + return make_control_protocol_error_response(handle, { nc_method_status::index_out_of_bounds }, ss.str()); } // unknown property utility::stringstream_t ss; ss << U("unknown property: ") << property_id.serialize() << U(" to do SetSequenceItem"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); + return make_control_protocol_error_response(handle, { nc_method_status::property_not_implemented }, ss.str()); }; // Add item to sequence const auto add_sequence_item = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes&, slog::base_gate& gate) @@ -236,7 +237,7 @@ namespace nmos const auto& property_id = nmos::fields::nc::id(arguments); const auto& val = nmos::fields::nc::value(arguments); - slog::log(gate, SLOG_FLF) << "Add sequence item: " << property_id.to_string() << " value: " << val.to_string(); + slog::log(gate, SLOG_FLF) << "Add sequence item: " << property_id.serialize() << " value: " << val.serialize(); // find the relevant nc_property_descriptor const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); @@ -247,7 +248,7 @@ namespace nmos // property is not a sequence utility::stringstream_t ss; ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do AddSequenceItem"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); + return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); } auto& data = resource->data.at(nmos::fields::nc::name(property)); @@ -260,13 +261,13 @@ namespace nmos resource.updated = strictly_increasing_update(resources); }); - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, uint32_t(data.as_array().size() - 1)); + return make_control_protocol_response(handle, { nc_method_status::ok }, uint32_t(data.as_array().size() - 1)); } // unknown property utility::stringstream_t ss; ss << U("unknown property: ") << property_id.serialize() << U(" to do AddSequenceItem"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); + return make_control_protocol_error_response(handle, { nc_method_status::property_not_implemented }, ss.str()); }; // Delete sequence item const auto remove_sequence_item = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes&, slog::base_gate& gate) @@ -276,7 +277,7 @@ namespace nmos const auto& property_id = nmos::fields::nc::id(arguments); const auto& index = nmos::fields::nc::index(arguments); - slog::log(gate, SLOG_FLF) << "Remove sequence item: " << property_id.to_string() << " index: " << index; + slog::log(gate, SLOG_FLF) << "Remove sequence item: " << property_id.serialize() << " index: " << index; // find the relevant nc_property_descriptor const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); @@ -287,7 +288,7 @@ namespace nmos // property is not a sequence utility::stringstream_t ss; ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do RemoveSequenceItem"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); + return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); } auto& data = resource->data.at(nmos::fields::nc::name(property)); @@ -295,25 +296,25 @@ namespace nmos if (!data.is_null() && data.as_array().size() > (size_t)index) { resources.modify(resource, [&](nmos::resource& resource) - { - auto& sequence = resource.data[nmos::fields::nc::name(property)].as_array(); - sequence.erase(index); + { + auto& sequence = resource.data[nmos::fields::nc::name(property)].as_array(); + sequence.erase(index); - resource.updated = strictly_increasing_update(resources); - }); - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }); + resource.updated = strictly_increasing_update(resources); + }); + return make_control_protocol_response(handle, { nc_method_status::ok }); } // out of bound utility::stringstream_t ss; ss << U("property: ") << property_id.serialize() << U(" is outside the available range to do RemoveSequenceItem"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::index_out_of_bounds }, ss.str()); + return make_control_protocol_error_response(handle, { nc_method_status::index_out_of_bounds }, ss.str()); } // unknown property utility::stringstream_t ss; ss << U("unknown property: ") << property_id.serialize() << U(" to do RemoveSequenceItem"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); + return make_control_protocol_error_response(handle, { nc_method_status::property_not_implemented }, ss.str()); }; // Get sequence length const auto get_sequence_length = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes&, slog::base_gate& gate) @@ -322,7 +323,7 @@ namespace nmos const auto& property_id = nmos::fields::nc::id(arguments); - slog::log(gate, SLOG_FLF) << "Get sequence length: " << property_id.to_string(); + slog::log(gate, SLOG_FLF) << "Get sequence length: " << property_id.serialize(); // find the relevant nc_property_descriptor const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); @@ -333,7 +334,7 @@ namespace nmos // property is not a sequence utility::stringstream_t ss; ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do GetSequenceLength"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); + return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); } auto& data = resource->data.at(nmos::fields::nc::name(property)); @@ -344,7 +345,7 @@ namespace nmos if (data.is_null()) { // null - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, value::null()); + return make_control_protocol_response(handle, { nc_method_status::ok }, value::null()); } } else @@ -355,16 +356,16 @@ namespace nmos // null utility::stringstream_t ss; ss << U("property: ") << property_id.serialize() << " is a null sequence to do GetSequenceLength"; - return details::make_control_protocol_error_response(handle, { details::nc_method_status::invalid_request }, ss.str()); + return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); } } - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, uint32_t(data.as_array().size())); + return make_control_protocol_response(handle, { nc_method_status::ok }, uint32_t(data.as_array().size())); } // unknown property utility::stringstream_t ss; ss << U("unknown property: ") << property_id.serialize() << " to do GetSequenceLength"; - return details::make_control_protocol_error_response(handle, { details::nc_method_status::property_not_implemented }, ss.str()); + return make_control_protocol_error_response(handle, { nc_method_status::property_not_implemented }, ss.str()); }; // NcBlock methods implementation @@ -380,7 +381,7 @@ namespace nmos auto descriptors = value::array(); nmos::get_member_descriptors(resources, resource, recurse, descriptors.as_array()); - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, descriptors); + return make_control_protocol_response(handle, { nc_method_status::ok }, descriptors); }; // Finds member(s) by path const auto find_members_by_path = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes&, const nmos::experimental::datatypes&, slog::base_gate& gate) @@ -390,12 +391,12 @@ namespace nmos // Relative path to search for (MUST not include the role of the block targeted by oid) const auto& path = arguments.at(nmos::fields::nc::path); - slog::log(gate, SLOG_FLF) << "Find member(s) by path: " << "path: " << path.to_string(); + slog::log(gate, SLOG_FLF) << "Find member(s) by path: " << "path: " << path.serialize(); if (0 == path.size()) { // empty path - return details::make_control_protocol_error_response(handle, { details::nc_method_status::parameter_error }, U("empty path to do FindMembersByPath")); + return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("empty path to do FindMembersByPath")); } auto nc_block_member_descriptors = value::array(); @@ -424,18 +425,18 @@ namespace nmos // no role utility::stringstream_t ss; ss << U("role: ") << role.as_string() << U(" not found to do FindMembersByPath"); - return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str()); + return make_control_protocol_error_response(handle, { nc_method_status::bad_oid }, ss.str()); } } else { // no members - return details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, U("no members to do FindMembersByPath")); + return make_control_protocol_error_response(handle, { nc_method_status::bad_oid }, U("no members to do FindMembersByPath")); } } web::json::push_back(nc_block_member_descriptors, nc_block_member_descriptor); - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, nc_block_member_descriptors); + return make_control_protocol_response(handle, { nc_method_status::ok }, nc_block_member_descriptors); }; // Finds members with given role name or fragment const auto find_members_by_role = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes&, const nmos::experimental::datatypes&, slog::base_gate& gate) @@ -452,29 +453,29 @@ namespace nmos if (role.empty()) { // empty role - return details::make_control_protocol_error_response(handle, { details::nc_method_status::parameter_error }, U("empty role to do FindMembersByRole")); + return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("empty role to do FindMembersByRole")); } auto descriptors = value::array(); nmos::find_members_by_role(resources, resource, role, match_whole_string, case_sensitive, recurse, descriptors.as_array()); - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, descriptors); + return make_control_protocol_response(handle, { nc_method_status::ok }, descriptors); }; // Finds members with given class id const auto find_members_by_class_id = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes&, const nmos::experimental::datatypes&, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - const auto& class_id = details::parse_nc_class_id(nmos::fields::nc::class_id(arguments)); // Class id to search for + const auto& class_id = parse_nc_class_id(nmos::fields::nc::class_id(arguments)); // Class id to search for const auto& include_derived = nmos::fields::nc::include_derived(arguments); // If TRUE it will also include derived class descriptors const auto& recurse = nmos::fields::nc::recurse(arguments); // TRUE to search nested blocks - slog::log(gate, SLOG_FLF) << "Find members with given class id: " << "class_id: " << details::make_nc_class_id(class_id).to_string(); + slog::log(gate, SLOG_FLF) << "Find members with given class id: " << "class_id: " << nmos::details::make_nc_class_id(class_id).serialize(); if (class_id.empty()) { // empty class_id - return details::make_control_protocol_error_response(handle, { details::nc_method_status::parameter_error }, U("empty classId to do FindMembersByClassId")); + return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("empty classId to do FindMembersByClassId")); } // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -482,27 +483,27 @@ namespace nmos auto descriptors = value::array(); nmos::find_members_by_class_id(resources, resource, class_id, include_derived, recurse, descriptors.as_array()); - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, descriptors); + return make_control_protocol_response(handle, { nc_method_status::ok }, descriptors); }; // NcClassManager methods implementation // Get a single class descriptor const auto get_control_class = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes&, slog::base_gate& gate) { - const auto& class_id = details::parse_nc_class_id(nmos::fields::nc::class_id(arguments)); // Class id to search for + const auto& class_id = parse_nc_class_id(nmos::fields::nc::class_id(arguments)); // Class id to search for const auto& include_inherited = nmos::fields::nc::include_inherited(arguments); // If set the descriptor would contain all inherited elements - slog::log(gate, SLOG_FLF) << "Get a single class descriptor: " << "class_id: " << details::make_nc_class_id(class_id).to_string(); + slog::log(gate, SLOG_FLF) << "Get a single class descriptor: " << "class_id: " << nmos::details::make_nc_class_id(class_id).serialize(); if (class_id.empty()) { // empty class_id - return details::make_control_protocol_error_response(handle, { details::nc_method_status::parameter_error }, U("empty classId to do GetControlClass")); + return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("empty classId to do GetControlClass")); } // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - auto class_found = control_classes.find(make_nc_class_id(class_id)); + auto class_found = control_classes.find(nmos::details::make_nc_class_id(class_id)); if (control_classes.end() != class_found) { @@ -521,7 +522,7 @@ namespace nmos { while (!id.empty()) { - auto found = control_classes.find(make_nc_class_id(id)); + auto found = control_classes.find(nmos::details::make_nc_class_id(id)); if (control_classes.end() != found) { for (const auto& property : found->second.properties.as_array()) { web::json::push_back(properties, property); } @@ -533,10 +534,10 @@ namespace nmos } auto descriptor = details::make_nc_class_descriptor(description, class_id, name, fixed_role, properties, methods, events); - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, descriptor); + return make_control_protocol_response(handle, { nc_method_status::ok }, descriptor); } - return details::make_control_protocol_error_response(handle, { details::nc_method_status::parameter_error }, U("classId not found")); + return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("classId not found")); }; // Get a single datatype descriptor const auto get_datatype = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes&, const nmos::experimental::datatypes& datatypes, slog::base_gate& gate) @@ -551,7 +552,7 @@ namespace nmos if (name.empty()) { // empty name - return details::make_control_protocol_error_response(handle, { details::nc_method_status::parameter_error }, U("empty name to do GetDatatype")); + return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("empty name to do GetDatatype")); } auto datatype_found = datatypes.find(name); @@ -563,7 +564,7 @@ namespace nmos if (include_inherited) { const auto& type = nmos::fields::nc::type(descriptor); - if (details::nc_datatype_type::Struct == type) + if (nc_datatype_type::Struct == type) { auto descriptor_ = descriptor; @@ -591,10 +592,10 @@ namespace nmos } } - return details::make_control_protocol_response(handle, { details::nc_method_status::ok }, descriptor); + return make_control_protocol_response(handle, { nc_method_status::ok }, descriptor); } - return details::make_control_protocol_error_response(handle, { details::nc_method_status::parameter_error }, U("name not found")); + return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("name not found")); }; // method handlers for the different classes @@ -640,16 +641,16 @@ namespace nmos // hmm, todo, custom class and assoicated methods will need to be inserted within follwoing table! const std::map methods = { - { details::make_nc_class_id(details::nc_object_class_id), nc_object_method_handlers }, - { details::make_nc_class_id(details::nc_block_class_id), nc_block_method_handlers }, - { details::make_nc_class_id(details::nc_class_manager_class_id), nc_class_manager_method_handlers } + { nmos::details::make_nc_class_id(nc_object_class_id), nc_object_method_handlers }, + { nmos::details::make_nc_class_id(nc_block_class_id), nc_block_method_handlers }, + { nmos::details::make_nc_class_id(nc_class_manager_class_id), nc_class_manager_method_handlers } }; auto class_id = class_id_; while (!class_id.empty()) { - auto subset_methods_found = methods.find(make_nc_class_id(class_id)); + auto subset_methods_found = methods.find(nmos::details::make_nc_class_id(class_id)); if (methods.end() != subset_methods_found) { @@ -711,7 +712,7 @@ namespace nmos const auto ws_href = web::uri_builder() .set_scheme(web::ws_scheme(secure)) .set_host(nmos::get_host(model.settings)) - .set_port(nmos::fields::events_ws_port(model.settings)) + .set_port(nmos::fields::control_protocol_ws_port(model.settings)) .set_path(ws_ncp_path) .to_uri(); @@ -844,7 +845,7 @@ namespace nmos const auto msg_type = nmos::fields::nc::message_type(message); switch (msg_type) { - case details::nc_message_type::command: + case nc_message_type::command: { // validate command-message details::validate_controlprotocolapi_command_message_schema(version, message); @@ -865,7 +866,7 @@ namespace nmos auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); if (resources.end() != resource) { - auto class_id = details::parse_nc_class_id(nmos::fields::nc::class_id(resource->data)); + auto class_id = nmos::details::parse_nc_class_id(nmos::fields::nc::class_id(resource->data)); // find the relevent method handler to execute auto method = details::find_method(method_id, class_id, get_control_protocol_classes()); @@ -879,7 +880,7 @@ namespace nmos utility::stringstream_t ss; ss << U("unsupported method id: ") << method_id.serialize(); web::json::push_back(responses, - details::make_control_protocol_error_response(handle, { details::nc_method_status::method_not_implemented }, ss.str())); + make_control_protocol_error_response(handle, { nc_method_status::method_not_implemented }, ss.str())); } } else @@ -888,7 +889,7 @@ namespace nmos utility::stringstream_t ss; ss << U("unknown oid: ") << oid; web::json::push_back(responses, - details::make_control_protocol_error_response(handle, { details::nc_method_status::bad_oid }, ss.str())); + make_control_protocol_error_response(handle, { nc_method_status::bad_oid }, ss.str())); } } @@ -896,13 +897,13 @@ namespace nmos resources.modify(grain, [&](nmos::resource& grain) { web::json::push_back(nmos::fields::message_grain_data(grain.data), - details::make_control_protocol_message_response(details::nc_message_type::command_response, responses)); + make_control_protocol_message_response(nc_message_type::command_response, responses)); grain.updated = strictly_increasing_update(resources); }); } break; - case details::nc_message_type::subscription: + case nc_message_type::subscription: { // hmm, todo... } @@ -920,7 +921,7 @@ namespace nmos resources.modify(grain, [&](nmos::resource& grain) { web::json::push_back(nmos::fields::message_grain_data(grain.data), - details::make_control_protocol_error_message({ details::nc_method_status::bad_command_format }, utility::s2us(e.what()))); + make_control_protocol_error_message({ nc_method_status::bad_command_format }, utility::s2us(e.what()))); grain.updated = strictly_increasing_update(resources); }); @@ -932,8 +933,7 @@ namespace nmos resources.modify(grain, [&](nmos::resource& grain) { web::json::push_back(nmos::fields::message_grain_data(grain.data), - details::make_control_protocol_error_message({ details::nc_method_status::bad_command_format }, - utility::s2us(std::string("Unexpected exception while handing control protocol command : ") + e.what()))); + make_control_protocol_error_message({ nc_method_status::bad_command_format }, utility::s2us(std::string("Unexpected exception while handing control protocol command : ") + e.what()))); grain.updated = strictly_increasing_update(resources); }); @@ -945,8 +945,7 @@ namespace nmos resources.modify(grain, [&](nmos::resource& grain) { web::json::push_back(nmos::fields::message_grain_data(grain.data), - details::make_control_protocol_error_message({ details::nc_method_status::bad_command_format }, - U("Unexpected unknown exception while handing control protocol command"))); + make_control_protocol_error_message({ nc_method_status::bad_command_format }, U("Unexpected unknown exception while handing control protocol command"))); grain.updated = strictly_increasing_update(resources); }); From 901780a795fe863675718a950b97dabee6889ea3 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 29 Aug 2023 19:13:27 +0100 Subject: [PATCH 034/106] Use of nc_class_id struct and method_id struct for map key --- .../nmos/control_protocol_handlers.cpp | 6 +-- .../nmos/control_protocol_resource.cpp | 20 ++++++- Development/nmos/control_protocol_resource.h | 10 ++-- Development/nmos/control_protocol_state.cpp | 28 +++++----- Development/nmos/control_protocol_state.h | 4 +- Development/nmos/control_protocol_typedefs.h | 10 ++++ Development/nmos/control_protocol_ws_api.cpp | 54 +++++++++++++------ 7 files changed, 89 insertions(+), 43 deletions(-) diff --git a/Development/nmos/control_protocol_handlers.cpp b/Development/nmos/control_protocol_handlers.cpp index 1118a35b8..e60f387cb 100644 --- a/Development/nmos/control_protocol_handlers.cpp +++ b/Development/nmos/control_protocol_handlers.cpp @@ -25,15 +25,13 @@ namespace nmos auto lock = control_protocol_state.write_lock(); - auto class_id_data = details::make_nc_class_id(class_id); - auto& control_classes = control_protocol_state.control_classes; - if (control_classes.end() == control_classes.find(class_id_data)) + if (control_classes.end() == control_classes.find(class_id)) { return false; } - control_classes[class_id_data] = control_class; + control_classes[class_id] = control_class; return true; }; } diff --git a/Development/nmos/control_protocol_resource.cpp b/Development/nmos/control_protocol_resource.cpp index 4ab09f694..12d8da0a8 100644 --- a/Development/nmos/control_protocol_resource.cpp +++ b/Development/nmos/control_protocol_resource.cpp @@ -42,9 +42,13 @@ namespace nmos }); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncelementid - web::json::value make_nc_element_id(const nc_element_id& element_id) + web::json::value make_nc_element_id(const nc_element_id& id) { - return make_nc_element_id(element_id.level, element_id.index); + return make_nc_element_id(id.level, id.index); + } + nc_element_id parse_nc_element_id(const web::json::value& id) + { + return { uint16_t(nmos::fields::nc::level(id)), uint16_t(nmos::fields::nc::index(id)) }; } // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#nceventid @@ -52,18 +56,30 @@ namespace nmos { return make_nc_element_id(id); } + nc_event_id parse_nc_event_id(const web::json::value& id) + { + return parse_nc_element_id(id); + } // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmethodid web::json::value make_nc_method_id(const nc_method_id& id) { return make_nc_element_id(id); } + nc_event_id parse_nc_method_id(const web::json::value& id) + { + return parse_nc_element_id(id); + } // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncpropertyid web::json::value make_nc_property_id(const nc_property_id& id) { return make_nc_element_id(id); } + nc_event_id parse_nc_property_id(const web::json::value& id) + { + return parse_nc_element_id(id); + } // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassid web::json::value make_nc_class_id(const nc_class_id& class_id) diff --git a/Development/nmos/control_protocol_resource.h b/Development/nmos/control_protocol_resource.h index 8d2c4208b..684a0eb44 100644 --- a/Development/nmos/control_protocol_resource.h +++ b/Development/nmos/control_protocol_resource.h @@ -24,18 +24,20 @@ namespace nmos // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncelementid //web::json::value make_nc_element_id(uint16_t level, uint16_t index); web::json::value make_nc_element_id(const nc_element_id& element_id); + nc_element_id parse_nc_element_id(const web::json::value& element_id); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#nceventid //web::json::value make_nc_event_id(uint16_t level, uint16_t index); web::json::value make_nc_event_id(const nc_event_id& event_id); + nc_event_id parse_nc_event_id(const web::json::value& event_id); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmethodid - //web::json::value make_nc_method_id(uint16_t level, uint16_t index); - web::json::value make_nc_method_id(const nc_method_id& event_id); + web::json::value make_nc_method_id(const nc_method_id& method_id); + nc_method_id parse_nc_method_id(const web::json::value& method_id); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncpropertyid - //web::json::value make_nc_property_id(uint16_t level, uint16_t index); - web::json::value make_nc_property_id(const nc_property_id& event_id); + web::json::value make_nc_property_id(const nc_property_id& property_id); + nc_property_id parse_nc_property_id(const web::json::value& property_id); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassid web::json::value make_nc_class_id(const nc_class_id& class_id); diff --git a/Development/nmos/control_protocol_state.cpp b/Development/nmos/control_protocol_state.cpp index 74c671636..d4ff47a85 100644 --- a/Development/nmos/control_protocol_state.cpp +++ b/Development/nmos/control_protocol_state.cpp @@ -85,19 +85,19 @@ namespace nmos { // Control class models // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/#control-class-models-for-branch-v10-dev - { nmos::details::make_nc_class_id(nc_object_class_id), make_control_class(U("NcObject class descriptor"), nc_object_class_id, U("NcObject"), to_vector(make_nc_object_properties()), to_vector(make_nc_object_methods()), to_vector(make_nc_object_events())) }, - { nmos::details::make_nc_class_id(nc_block_class_id), make_control_class(U("NcBlock class descriptor"), nc_block_class_id, U("NcBlock"), to_vector(make_nc_block_properties()), to_vector(make_nc_block_methods()), to_vector(make_nc_block_events())) }, - { nmos::details::make_nc_class_id(nc_worker_class_id), make_control_class(U("NcWorker class descriptor"), nc_worker_class_id, U("NcWorker"), to_vector(make_nc_worker_properties()), to_vector(make_nc_worker_methods()), to_vector(make_nc_worker_events())) }, - { nmos::details::make_nc_class_id(nc_manager_class_id), make_control_class(U("NcManager class descriptor"), nc_manager_class_id, U("NcManager"),to_vector(make_nc_manager_properties()), to_vector(make_nc_manager_methods()), to_vector(make_nc_manager_events())) }, - { nmos::details::make_nc_class_id(nc_device_manager_class_id), make_control_class(U("NcDeviceManager class descriptor"), nc_device_manager_class_id, U("NcDeviceManager"), U("DeviceManager"), to_vector(make_nc_device_manager_properties()), to_vector(make_nc_device_manager_methods()), to_vector(make_nc_device_manager_events())) }, - { nmos::details::make_nc_class_id(nc_class_manager_class_id), make_control_class(U("NcClassManager class descriptor"), nc_class_manager_class_id, U("NcClassManager"), U("ClassManager"), to_vector(make_nc_class_manager_properties()), to_vector(make_nc_class_manager_methods()), to_vector(make_nc_class_manager_events())) }, + { nc_object_class_id, make_control_class(U("NcObject class descriptor"), nc_object_class_id, U("NcObject"), to_vector(make_nc_object_properties()), to_vector(make_nc_object_methods()), to_vector(make_nc_object_events())) }, + { nc_block_class_id, make_control_class(U("NcBlock class descriptor"), nc_block_class_id, U("NcBlock"), to_vector(make_nc_block_properties()), to_vector(make_nc_block_methods()), to_vector(make_nc_block_events())) }, + { nc_worker_class_id, make_control_class(U("NcWorker class descriptor"), nc_worker_class_id, U("NcWorker"), to_vector(make_nc_worker_properties()), to_vector(make_nc_worker_methods()), to_vector(make_nc_worker_events())) }, + { nc_manager_class_id, make_control_class(U("NcManager class descriptor"), nc_manager_class_id, U("NcManager"),to_vector(make_nc_manager_properties()), to_vector(make_nc_manager_methods()), to_vector(make_nc_manager_events())) }, + { nc_device_manager_class_id, make_control_class(U("NcDeviceManager class descriptor"), nc_device_manager_class_id, U("NcDeviceManager"), U("DeviceManager"), to_vector(make_nc_device_manager_properties()), to_vector(make_nc_device_manager_methods()), to_vector(make_nc_device_manager_events())) }, + { nc_class_manager_class_id, make_control_class(U("NcClassManager class descriptor"), nc_class_manager_class_id, U("NcClassManager"), U("ClassManager"), to_vector(make_nc_class_manager_properties()), to_vector(make_nc_class_manager_methods()), to_vector(make_nc_class_manager_events())) }, // identification beacon model // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/identification/#ncidentbeacon - { nmos::details::make_nc_class_id(nc_ident_beacon_class_id), make_control_class(U("NcIdentBeacon class descriptor"), nc_ident_beacon_class_id, U("NcIdentBeacon"), to_vector(make_nc_ident_beacon_properties()), to_vector(make_nc_ident_beacon_methods()), to_vector(make_nc_ident_beacon_events())) }, + { nc_ident_beacon_class_id, make_control_class(U("NcIdentBeacon class descriptor"), nc_ident_beacon_class_id, U("NcIdentBeacon"), to_vector(make_nc_ident_beacon_properties()), to_vector(make_nc_ident_beacon_methods()), to_vector(make_nc_ident_beacon_events())) }, // Monitoring // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitor - { nmos::details::make_nc_class_id(nc_receiver_monitor_class_id), make_control_class(U("NcReceiverMonitor class descriptor"), nc_receiver_monitor_class_id, U("NcReceiverMonitor"), to_vector(make_nc_receiver_monitor_properties()), to_vector(make_nc_receiver_monitor_methods()), to_vector(make_nc_receiver_monitor_events())) }, - { nmos::details::make_nc_class_id(nc_receiver_monitor_protected_class_id), make_control_class(U("NcReceiverMonitorProtected class descriptor"), nc_receiver_monitor_protected_class_id, U("NcReceiverMonitorProtected"), to_vector(make_nc_receiver_monitor_protected_properties()), to_vector(make_nc_receiver_monitor_protected_methods()), to_vector(make_nc_receiver_monitor_protected_events())) } + { nc_receiver_monitor_class_id, make_control_class(U("NcReceiverMonitor class descriptor"), nc_receiver_monitor_class_id, U("NcReceiverMonitor"), to_vector(make_nc_receiver_monitor_properties()), to_vector(make_nc_receiver_monitor_methods()), to_vector(make_nc_receiver_monitor_events())) }, + { nc_receiver_monitor_protected_class_id, make_control_class(U("NcReceiverMonitorProtected class descriptor"), nc_receiver_monitor_protected_class_id, U("NcReceiverMonitorProtected"), to_vector(make_nc_receiver_monitor_protected_properties()), to_vector(make_nc_receiver_monitor_protected_methods()), to_vector(make_nc_receiver_monitor_protected_events())) } }; // setup the core datatypes @@ -173,23 +173,19 @@ namespace nmos // insert control class, false if class already presented bool control_protocol_state::insert(const experimental::control_class& control_class) { - const auto& class_id = nmos::details::make_nc_class_id(control_class.class_id); - auto lock = write_lock(); - if (control_classes.end() == control_classes.find(class_id)) + if (control_classes.end() == control_classes.find(control_class.class_id)) { - control_classes[nmos::details::make_nc_class_id(control_class.class_id)] = control_class; + control_classes[control_class.class_id] = control_class; return true; } return false; } // erase control class of the given class id, false if the required class not found - bool control_protocol_state::erase(nc_class_id class_id_) + bool control_protocol_state::erase(nc_class_id class_id) { - const auto& class_id = nmos::details::make_nc_class_id(class_id_); - auto lock = write_lock(); if (control_classes.end() != control_classes.find(class_id)) diff --git a/Development/nmos/control_protocol_state.h b/Development/nmos/control_protocol_state.h index ddf68e906..41fd6824a 100644 --- a/Development/nmos/control_protocol_state.h +++ b/Development/nmos/control_protocol_state.h @@ -31,13 +31,13 @@ namespace nmos }; // nc_class_id vs control_class - typedef std::map control_classes; + typedef std::map control_classes; // nc_name vs datatype typedef std::map datatypes; // methods defnitions typedef std::function method; - typedef std::map methods; // method_id vs method handler + typedef std::map methods; // method_id vs method handler struct control_protocol_state { diff --git a/Development/nmos/control_protocol_typedefs.h b/Development/nmos/control_protocol_typedefs.h index 310a16af4..a7d6bc1a1 100644 --- a/Development/nmos/control_protocol_typedefs.h +++ b/Development/nmos/control_protocol_typedefs.h @@ -131,6 +131,16 @@ namespace nmos { uint16_t level; uint16_t index; + + nc_element_id(uint16_t level, uint16_t index) + : level(level) + , index(index) + {} + + auto tied() const -> decltype(std::tie(level, index)) { return std::tie(level, index); } + friend bool operator==(const nc_element_id& lhs, const nc_element_id& rhs) { return lhs.tied() == rhs.tied(); } + friend bool operator!=(const nc_element_id& lhs, const nc_element_id& rhs) { return !(lhs == rhs); } + friend bool operator<(const nc_element_id& lhs, const nc_element_id& rhs) { return lhs.tied() < rhs.tied(); } }; // NcEventId diff --git a/Development/nmos/control_protocol_ws_api.cpp b/Development/nmos/control_protocol_ws_api.cpp index 9e9c80784..76926f4d6 100644 --- a/Development/nmos/control_protocol_ws_api.cpp +++ b/Development/nmos/control_protocol_ws_api.cpp @@ -57,7 +57,8 @@ namespace nmos while (!class_id.empty()) { - auto class_found = control_classes.find(nmos::details::make_nc_class_id(class_id)); +// auto class_found = control_classes.find(nmos::details::make_nc_class_id(class_id)); + auto class_found = control_classes.find(class_id); if (control_classes.end() != class_found) { auto& properties = class_found->second.properties.as_array(); @@ -76,7 +77,8 @@ namespace nmos } // hmm, change method_id to struct, and bring in method handlers via the control_classes - nmos::experimental::method find_method(const web::json::value& method_id, const nc_class_id& class_id_, const nmos::experimental::control_classes& control_classes) +// nmos::experimental::method find_method(const web::json::value& method_id, const nc_class_id& class_id_, const nmos::experimental::control_classes& control_classes) + nmos::experimental::method find_method(const nc_method_id& method_id, const nc_class_id& class_id_, const nmos::experimental::control_classes& control_classes) { using web::json::value; using web::json::value_of; @@ -503,7 +505,8 @@ namespace nmos // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - auto class_found = control_classes.find(nmos::details::make_nc_class_id(class_id)); +// auto class_found = control_classes.find(nmos::details::make_nc_class_id(class_id)); + auto class_found = control_classes.find(class_id); if (control_classes.end() != class_found) { @@ -522,7 +525,8 @@ namespace nmos { while (!id.empty()) { - auto found = control_classes.find(nmos::details::make_nc_class_id(id)); +// auto found = control_classes.find(nmos::details::make_nc_class_id(id)); + auto found = control_classes.find(id); if (control_classes.end() != found) { for (const auto& property : found->second.properties.as_array()) { web::json::push_back(properties, property); } @@ -608,6 +612,7 @@ namespace nmos // NcObject methods // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject +/* nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 1 } })] = get; nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 2 } })] = set; nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 3 } })] = get_sequence_item; @@ -615,13 +620,27 @@ namespace nmos nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 5 } })] = add_sequence_item; nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 6 } })] = remove_sequence_item; nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 7 } })] = get_sequence_length; +*/ + nc_object_method_handlers[{1, 1}] = get; + nc_object_method_handlers[{1, 2}] = set; + nc_object_method_handlers[{1, 3}] = get_sequence_item; + nc_object_method_handlers[{1, 4}] = set_sequence_item; + nc_object_method_handlers[{1, 5}] = add_sequence_item; + nc_object_method_handlers[{1, 6}] = remove_sequence_item; + nc_object_method_handlers[{1, 7}] = get_sequence_length; // NcBlock methods // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock +/* nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 1 } })] = get_member_descriptors; nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 2 } })] = find_members_by_path; nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 3 } })] = find_members_by_role; nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 4 } })] = find_members_by_class_id; +*/ + nc_block_method_handlers[{2, 1}] = get_member_descriptors; + nc_block_method_handlers[{2, 2}] = find_members_by_path; + nc_block_method_handlers[{2, 3}] = find_members_by_role; + nc_block_method_handlers[{2, 4}] = find_members_by_class_id; // NcWorker has no extended method // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncworker @@ -634,29 +653,34 @@ namespace nmos // NcClassManager methods // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager +/* nc_class_manager_method_handlers[value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 1 } })] = get_control_class; nc_class_manager_method_handlers[value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 2 } })] = get_datatype; +*/ + nc_class_manager_method_handlers[{3, 1}] = get_control_class; + nc_class_manager_method_handlers[{3, 2}] = get_datatype; // class id vs method handlers // hmm, todo, custom class and assoicated methods will need to be inserted within follwoing table! - const std::map methods = + const std::map methods = { - { nmos::details::make_nc_class_id(nc_object_class_id), nc_object_method_handlers }, - { nmos::details::make_nc_class_id(nc_block_class_id), nc_block_method_handlers }, - { nmos::details::make_nc_class_id(nc_class_manager_class_id), nc_class_manager_method_handlers } + { nc_object_class_id, nc_object_method_handlers }, + { nc_block_class_id, nc_block_method_handlers }, + { nc_class_manager_class_id, nc_class_manager_method_handlers } }; + auto class_id = class_id_; while (!class_id.empty()) { - auto subset_methods_found = methods.find(nmos::details::make_nc_class_id(class_id)); + auto class_id_methods_found = methods.find(class_id); - if (methods.end() != subset_methods_found) + if (methods.end() != class_id_methods_found) { - auto& subset_methods = subset_methods_found->second; - auto method_found = subset_methods.find(method_id); - if (subset_methods.end() != method_found) + auto& class_id_methods = class_id_methods_found->second; + auto method_found = class_id_methods.find(method_id); + if (class_id_methods.end() != method_found) { return method_found->second; } @@ -858,7 +882,7 @@ namespace nmos const auto oid = nmos::fields::nc::oid(cmd); // get methodId - const auto& method_id = nmos::fields::nc::method_id(cmd); + const auto& method_id = nmos::details::parse_nc_method_id(nmos::fields::nc::method_id(cmd)); // get arguments const auto& arguments = nmos::fields::nc::arguments(cmd); @@ -878,7 +902,7 @@ namespace nmos else { utility::stringstream_t ss; - ss << U("unsupported method id: ") << method_id.serialize(); + ss << U("unsupported method id: ") << nmos::fields::nc::method_id(cmd).serialize(); web::json::push_back(responses, make_control_protocol_error_response(handle, { nc_method_status::method_not_implemented }, ss.str())); } From 40c3dc134d7711ed1c212f2783361f767a6bf68b Mon Sep 17 00:00:00 2001 From: lo-simon Date: Wed, 30 Aug 2023 10:45:03 +0100 Subject: [PATCH 035/106] Remove un-used code --- Development/nmos/control_protocol_ws_api.cpp | 46 ++++++-------------- 1 file changed, 13 insertions(+), 33 deletions(-) diff --git a/Development/nmos/control_protocol_ws_api.cpp b/Development/nmos/control_protocol_ws_api.cpp index 76926f4d6..8f22bbc99 100644 --- a/Development/nmos/control_protocol_ws_api.cpp +++ b/Development/nmos/control_protocol_ws_api.cpp @@ -57,7 +57,6 @@ namespace nmos while (!class_id.empty()) { -// auto class_found = control_classes.find(nmos::details::make_nc_class_id(class_id)); auto class_found = control_classes.find(class_id); if (control_classes.end() != class_found) { @@ -76,8 +75,6 @@ namespace nmos return value::null(); } - // hmm, change method_id to struct, and bring in method handlers via the control_classes -// nmos::experimental::method find_method(const web::json::value& method_id, const nc_class_id& class_id_, const nmos::experimental::control_classes& control_classes) nmos::experimental::method find_method(const nc_method_id& method_id, const nc_class_id& class_id_, const nmos::experimental::control_classes& control_classes) { using web::json::value; @@ -490,7 +487,7 @@ namespace nmos // NcClassManager methods implementation // Get a single class descriptor - const auto get_control_class = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes&, slog::base_gate& gate) + const auto get_control_class = [](nmos::resources&, nmos::resources::iterator, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes&, slog::base_gate& gate) { const auto& class_id = parse_nc_class_id(nmos::fields::nc::class_id(arguments)); // Class id to search for const auto& include_inherited = nmos::fields::nc::include_inherited(arguments); // If set the descriptor would contain all inherited elements @@ -505,16 +502,15 @@ namespace nmos // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... -// auto class_found = control_classes.find(nmos::details::make_nc_class_id(class_id)); auto class_found = control_classes.find(class_id); if (control_classes.end() != class_found) { auto id = class_id; - auto description = class_found->second.description; - auto name = class_found->second.name; - auto fixed_role = class_found->second.fixed_role; + auto& description = class_found->second.description; + auto& name = class_found->second.name; + auto& fixed_role = class_found->second.fixed_role; auto properties = class_found->second.properties; auto methods = class_found->second.methods; auto events = class_found->second.events; @@ -525,7 +521,6 @@ namespace nmos { while (!id.empty()) { -// auto found = control_classes.find(nmos::details::make_nc_class_id(id)); auto found = control_classes.find(id); if (control_classes.end() != found) { @@ -544,7 +539,7 @@ namespace nmos return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("classId not found")); }; // Get a single datatype descriptor - const auto get_datatype = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes&, const nmos::experimental::datatypes& datatypes, slog::base_gate& gate) + const auto get_datatype = [](nmos::resources&, nmos::resources::iterator, int32_t handle, const value& arguments, const nmos::experimental::control_classes&, const nmos::experimental::datatypes& datatypes, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -612,15 +607,6 @@ namespace nmos // NcObject methods // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject -/* - nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 1 } })] = get; - nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 2 } })] = set; - nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 3 } })] = get_sequence_item; - nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 4 } })] = set_sequence_item; - nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 5 } })] = add_sequence_item; - nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 6 } })] = remove_sequence_item; - nc_object_method_handlers[value_of({ { nmos::fields::nc::level, 1 }, { nmos::fields::nc::index, 7 } })] = get_sequence_length; -*/ nc_object_method_handlers[{1, 1}] = get; nc_object_method_handlers[{1, 2}] = set; nc_object_method_handlers[{1, 3}] = get_sequence_item; @@ -631,12 +617,6 @@ namespace nmos // NcBlock methods // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock -/* - nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 1 } })] = get_member_descriptors; - nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 2 } })] = find_members_by_path; - nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 3 } })] = find_members_by_role; - nc_block_method_handlers[value_of({ { nmos::fields::nc::level, 2 }, { nmos::fields::nc::index, 4 } })] = find_members_by_class_id; -*/ nc_block_method_handlers[{2, 1}] = get_member_descriptors; nc_block_method_handlers[{2, 2}] = find_members_by_path; nc_block_method_handlers[{2, 3}] = find_members_by_role; @@ -653,10 +633,6 @@ namespace nmos // NcClassManager methods // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager -/* - nc_class_manager_method_handlers[value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 1 } })] = get_control_class; - nc_class_manager_method_handlers[value_of({ { nmos::fields::nc::level, 3 }, { nmos::fields::nc::index, 2 } })] = get_datatype; -*/ nc_class_manager_method_handlers[{3, 1}] = get_control_class; nc_class_manager_method_handlers[{3, 2}] = get_datatype; @@ -678,12 +654,16 @@ namespace nmos if (methods.end() != class_id_methods_found) { - auto& class_id_methods = class_id_methods_found->second; - auto method_found = class_id_methods.find(method_id); - if (class_id_methods.end() != method_found) + auto& method_id_methods = class_id_methods_found->second; + auto method_found = method_id_methods.find(method_id); + if (method_id_methods.end() != method_found) { return method_found->second; } + else + { + //control_classes. + } } class_id.pop_back(); } @@ -890,7 +870,7 @@ namespace nmos auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); if (resources.end() != resource) { - auto class_id = nmos::details::parse_nc_class_id(nmos::fields::nc::class_id(resource->data)); + const auto& class_id = nmos::details::parse_nc_class_id(nmos::fields::nc::class_id(resource->data)); // find the relevent method handler to execute auto method = details::find_method(method_id, class_id, get_control_protocol_classes()); From e4e54d64e7314556e060ef4929d10e3ec6966207 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Thu, 31 Aug 2023 12:16:35 +0100 Subject: [PATCH 036/106] Add support for allowing user to insert non-standard control class method handler --- Development/cmake/NmosCppLibraries.cmake | 2 + Development/nmos-cpp-node/main.cpp | 5 +- .../nmos-cpp-node/node_implementation.cpp | 16 +- .../nmos/control_protocol_handlers.cpp | 46 +- Development/nmos/control_protocol_handlers.h | 38 +- Development/nmos/control_protocol_methods.cpp | 550 ++++++++++++++++ Development/nmos/control_protocol_methods.h | 50 ++ .../nmos/control_protocol_resource.cpp | 40 +- Development/nmos/control_protocol_resource.h | 40 +- Development/nmos/control_protocol_state.cpp | 101 ++- Development/nmos/control_protocol_state.h | 23 +- Development/nmos/control_protocol_typedefs.h | 4 + Development/nmos/control_protocol_utils.cpp | 39 +- Development/nmos/control_protocol_utils.h | 16 +- Development/nmos/control_protocol_ws_api.cpp | 617 +----------------- Development/nmos/control_protocol_ws_api.h | 6 +- Development/nmos/node_server.cpp | 2 +- Development/nmos/node_server.h | 17 +- 18 files changed, 892 insertions(+), 720 deletions(-) create mode 100644 Development/nmos/control_protocol_methods.cpp create mode 100644 Development/nmos/control_protocol_methods.h diff --git a/Development/cmake/NmosCppLibraries.cmake b/Development/cmake/NmosCppLibraries.cmake index f29a683c7..1fe469e1a 100644 --- a/Development/cmake/NmosCppLibraries.cmake +++ b/Development/cmake/NmosCppLibraries.cmake @@ -832,6 +832,7 @@ set(NMOS_CPP_NMOS_SOURCES nmos/connection_events_activation.cpp nmos/connection_resources.cpp nmos/control_protocol_handlers.cpp + nmos/control_protocol_methods.cpp nmos/control_protocol_resource.cpp nmos/control_protocol_resources.cpp nmos/control_protocol_state.cpp @@ -911,6 +912,7 @@ set(NMOS_CPP_NMOS_HEADERS nmos/connection_events_activation.h nmos/connection_resources.h nmos/control_protocol_handlers.h + nmos/control_protocol_methods.h nmos/control_protocol_resource.h nmos/control_protocol_resources.h nmos/control_protocol_state.h diff --git a/Development/nmos-cpp-node/main.cpp b/Development/nmos-cpp-node/main.cpp index 5dd65c38e..ee133835c 100644 --- a/Development/nmos-cpp-node/main.cpp +++ b/Development/nmos-cpp-node/main.cpp @@ -112,8 +112,9 @@ int main(int argc, char* argv[]) nmos::experimental::control_protocol_state control_protocol_state; if (0 <= nmos::fields::control_protocol_ws_port(node_model.settings)) { - node_implementation.on_get_control_classes(nmos::make_get_control_protocol_classes_handler(control_protocol_state, gate)); - node_implementation.on_get_control_datatypes(nmos::make_get_control_protocol_datatypes_handler(control_protocol_state, gate)); + node_implementation.on_get_control_class(nmos::make_get_control_protocol_class_handler(control_protocol_state, gate)); + node_implementation.on_get_control_datatype(nmos::make_get_control_protocol_datatype_handler(control_protocol_state, gate)); + node_implementation.on_get_control_protocol_methods(nmos::make_get_control_protocol_methods_handler(control_protocol_state, gate)); } // Set up the node server diff --git a/Development/nmos-cpp-node/node_implementation.cpp b/Development/nmos-cpp-node/node_implementation.cpp index d7bbbcc36..aa4ab3324 100644 --- a/Development/nmos-cpp-node/node_implementation.cpp +++ b/Development/nmos-cpp-node/node_implementation.cpp @@ -909,8 +909,22 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr // example to create a non-standard Gain control class const auto gain_control_class_id = nmos::make_nc_class_id(nmos::nc_worker_class_id, 0, { 1 }); const web::json::field_as_number gain_value{ U("gainValue") }; + // Gain control class properties std::vector gain_control_properties = { nmos::experimental::make_control_class_property(U("Gain value"), { 3, 1 }, gain_value, U("NcFloat32")) }; - auto gain_control_class = nmos::experimental::make_control_class(U("Gain control class descriptor"), gain_control_class_id, U("GainControl"), gain_control_properties, {}, {}); + // Gain control class method example + auto example_method = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) + { + slog::log(gate, SLOG_FLF) << "Executing the example method"; + return nmos::make_control_protocol_response(handle, { nmos::nc_method_status::ok }); + }; + // Gain control class methods + std::vector> gain_control_methods = + { + { nmos::experimental::make_control_class_method(U("This is an example method"), {3, 1}, U("ExampleMethod"), U("NcMethodResult"), {}, false), example_method } + }; + // create Gain control class + auto gain_control_class = nmos::experimental::make_control_class(U("Gain control class descriptor"), gain_control_class_id, U("GainControl"), gain_control_properties, gain_control_methods, {}); + // insert Gain control class to global state, which will be used by the control_protocol_ws_message_handler to process incoming ws message control_protocol_state.insert(gain_control_class); // helper function to create Gain control instance auto make_gain_control = [&gain_value, &gain_control_class_id](nmos::nc_oid oid, nmos::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, float gain = 0.0, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null()) diff --git a/Development/nmos/control_protocol_handlers.cpp b/Development/nmos/control_protocol_handlers.cpp index e60f387cb..73fa4fa8e 100644 --- a/Development/nmos/control_protocol_handlers.cpp +++ b/Development/nmos/control_protocol_handlers.cpp @@ -1,19 +1,26 @@ #include "nmos/control_protocol_handlers.h" #include "nmos/control_protocol_resource.h" +#include "nmos/control_protocol_state.h" #include "nmos/slog.h" namespace nmos { - get_control_protocol_classes_handler make_get_control_protocol_classes_handler(nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate) + get_control_protocol_class_handler make_get_control_protocol_class_handler(nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate) { - return [&]() + return [&](const nc_class_id& class_id) { - slog::log(gate, SLOG_FLF) << "Retrieve all control classes from cache"; + slog::log(gate, SLOG_FLF) << "Retrieve control class of class_id: " << nmos::details::make_nc_class_id(class_id).serialize() << " from cache"; auto lock = control_protocol_state.read_lock(); - return control_protocol_state.control_classes; + auto& control_classes = control_protocol_state.control_classes; + auto found = control_classes.find(class_id); + if (control_classes.end() != found) + { + return found->second; + } + return nmos::experimental::control_class{}; }; } @@ -36,15 +43,40 @@ namespace nmos }; } - get_control_protocol_datatypes_handler make_get_control_protocol_datatypes_handler(nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate) + get_control_protocol_datatype_handler make_get_control_protocol_datatype_handler(nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate) + { + return [&](const nmos::nc_name& name) + { + slog::log(gate, SLOG_FLF) << "Retrieve datatype of name: " << name << " from cache"; + + auto lock = control_protocol_state.read_lock(); + + auto found = control_protocol_state.datatypes.find(name); + if (control_protocol_state.datatypes.end() != found) + { + return found->second; + } + return nmos::experimental::datatype{}; + }; + } + + get_control_protocol_methods_handler make_get_control_protocol_methods_handler(experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate) { return [&]() { - slog::log(gate, SLOG_FLF) << "Retrieve all datatypes from cache"; + slog::log(gate, SLOG_FLF) << "Retrieve all method handlers from cache"; + + std::map methods; auto lock = control_protocol_state.read_lock(); - return control_protocol_state.datatypes; + auto& control_classes = control_protocol_state.control_classes; + + for (const auto& control_class : control_classes) + { + methods[control_class.first] = control_class.second.method_handlers; + } + return methods; }; } } diff --git a/Development/nmos/control_protocol_handlers.h b/Development/nmos/control_protocol_handlers.h index 165b53809..ce4c03b45 100644 --- a/Development/nmos/control_protocol_handlers.h +++ b/Development/nmos/control_protocol_handlers.h @@ -2,7 +2,9 @@ #define NMOS_CONTROL_PROTOCOL_HANDLERS_H #include -#include "nmos/control_protocol_state.h" +#include +#include "nmos/control_protocol_typedefs.h" +#include "nmos/resources.h" namespace slog { @@ -15,28 +17,44 @@ namespace nmos { struct control_protocol_state; struct control_class; + struct datatype; } - // callback to retrieve all control protocol classes + // callback to retrieve a specific control protocol classe // this callback should not throw exceptions - typedef std::function get_control_protocol_classes_handler; + typedef std::function get_control_protocol_class_handler; // callback to add user control protocol class // this callback should not throw exceptions typedef std::function add_control_protocol_class_handler; - // callback to retrieve all control protocol datatypes + // callback to retrieve a control protocol datatype // this callback should not throw exceptions - typedef std::function get_control_protocol_datatypes_handler; + typedef std::function get_control_protocol_datatype_handler; - // construct callback to retrieve all control protocol classes - get_control_protocol_classes_handler make_get_control_protocol_classes_handler(nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate); + namespace experimental + { + // method handler defnition + typedef std::function method; + // methods defnition + typedef std::map methods; // method_id vs method handler + } + + // callback to retrieve all the method handlers + // this callback should not throw exceptions + typedef std::function()> get_control_protocol_methods_handler; + + // construct callback to retrieve a specific control protocol class + get_control_protocol_class_handler make_get_control_protocol_class_handler(experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate); // construct callback to add control protocol class - add_control_protocol_class_handler make_add_control_protocol_class_handler(nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate); + add_control_protocol_class_handler make_add_control_protocol_class_handler(experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate); + + // construct callback to retrieve a specific datatype + get_control_protocol_datatype_handler make_get_control_protocol_datatype_handler(experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate); - // construct callback to retrieve all datatypes - get_control_protocol_datatypes_handler make_get_control_protocol_datatypes_handler(nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate); + // construct callback to retrieve all method handlers + get_control_protocol_methods_handler make_get_control_protocol_methods_handler(experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate); } #endif diff --git a/Development/nmos/control_protocol_methods.cpp b/Development/nmos/control_protocol_methods.cpp new file mode 100644 index 000000000..8aec5aec1 --- /dev/null +++ b/Development/nmos/control_protocol_methods.cpp @@ -0,0 +1,550 @@ +#include "nmos/control_protocol_methods.h" + +#include "cpprest/json_utils.h" +#include "nmos/control_protocol_resource.h" +#include "nmos/control_protocol_state.h" +#include "nmos/control_protocol_utils.h" +#include "nmos/json_fields.h" +#include "nmos/slog.h" + +namespace nmos +{ + namespace details + { + // NcObject methods implementation + // Get property value + web::json::value get(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + const auto& property_id = nmos::fields::nc::id(arguments); + + slog::log(gate, SLOG_FLF) << "Get property: " << property_id.serialize(); + + // find the relevant nc_property_descriptor + const auto& property = find_property(parse_nc_property_id(property_id), parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), get_control_protocol_class); + if (!property.is_null()) + { + return make_control_protocol_response(handle, { nc_method_status::ok }, resource->data.at(nmos::fields::nc::name(property))); + } + + // unknown property + utility::stringstream_t ss; + ss << U("unknown property: ") << property_id.serialize() << U(" to do Get"); + return make_control_protocol_error_response(handle, { nc_method_status::property_not_implemented }, ss.str()); + } + + // Set property value + web::json::value set(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + const auto& property_id = nmos::fields::nc::id(arguments); + const auto& val = nmos::fields::nc::value(arguments); + + slog::log(gate, SLOG_FLF) << "Set property: " << property_id.serialize() << " value: " << val.serialize(); + + // find the relevant nc_property_descriptor + const auto& property = find_property(parse_nc_property_id(property_id), parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), get_control_protocol_class); + if (!property.is_null()) + { + if (nmos::fields::nc::is_read_only(property)) + { + return make_control_protocol_response(handle, { nc_method_status::read_only }); + } + + if ((val.is_null() && !nmos::fields::nc::is_nullable(property)) + || (val.is_array() && !nmos::fields::nc::is_sequence(property))) + { + return make_control_protocol_response(handle, { nc_method_status::parameter_error }); + } + + resources.modify(resource, [&](nmos::resource& resource) + { + resource.data[nmos::fields::nc::name(property)] = val; + + resource.updated = strictly_increasing_update(resources); + }); + return make_control_protocol_response(handle, { nc_method_status::ok }); + } + + // unknown property + utility::stringstream_t ss; + ss << U("unknown property: ") << property_id.serialize() << " to do Set"; + return make_control_protocol_error_response(handle, { nc_method_status::property_not_implemented }, ss.str()); + } + + // Get sequence item + web::json::value get_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + const auto& property_id = nmos::fields::nc::id(arguments); + const auto& index = nmos::fields::nc::index(arguments); + + slog::log(gate, SLOG_FLF) << "Get sequence item: " << property_id.serialize() << " index: " << index; + + // find the relevant nc_property_descriptor + const auto& property = find_property(parse_nc_property_id(property_id), parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), get_control_protocol_class); + if (!property.is_null()) + { + if (!nmos::fields::nc::is_sequence(property)) + { + // property is not a sequence + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do GetSequenceItem"); + return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); + } + + auto& data = resource->data.at(nmos::fields::nc::name(property)); + + if (!data.is_null() && data.as_array().size() > (size_t)index) + { + return make_control_protocol_response(handle, { nc_method_status::ok }, data.at(index)); + } + + // out of bound + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << U(" is outside the available range to do GetSequenceItem"); + return make_control_protocol_error_response(handle, { nc_method_status::index_out_of_bounds }, ss.str()); + } + + // unknown property + utility::stringstream_t ss; + ss << U("unknown property: ") << property_id.serialize() << U(" to do GetSequenceItem"); + return make_control_protocol_error_response(handle, { nc_method_status::property_not_implemented }, ss.str()); + } + + // Set sequence item + web::json::value set_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + const auto& property_id = nmos::fields::nc::id(arguments); + const auto& index = nmos::fields::nc::index(arguments); + const auto& val = nmos::fields::nc::value(arguments); + + slog::log(gate, SLOG_FLF) << "Set sequence item: " << property_id.serialize() << " index: " << index << " value: " << val.serialize(); + + // find the relevant nc_property_descriptor + const auto& property = find_property(parse_nc_property_id(property_id), parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), get_control_protocol_class); + if (!property.is_null()) + { + if (!nmos::fields::nc::is_sequence(property)) + { + // property is not a sequence + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do SetSequenceItem"); + return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); + } + + auto& data = resource->data.at(nmos::fields::nc::name(property)); + + if (!data.is_null() && data.as_array().size() > (size_t)index) + { + resources.modify(resource, [&](nmos::resource& resource) + { + resource.data[nmos::fields::nc::name(property)][index] = val; + + resource.updated = strictly_increasing_update(resources); + }); + return make_control_protocol_response(handle, { nc_method_status::ok }); + } + + // out of bound + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << U(" is outside the available range to do SetSequenceItem"); + return make_control_protocol_error_response(handle, { nc_method_status::index_out_of_bounds }, ss.str()); + } + + // unknown property + utility::stringstream_t ss; + ss << U("unknown property: ") << property_id.serialize() << U(" to do SetSequenceItem"); + return make_control_protocol_error_response(handle, { nc_method_status::property_not_implemented }, ss.str()); + } + + // Add item to sequence + web::json::value add_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + using web::json::value; + + const auto& property_id = nmos::fields::nc::id(arguments); + const auto& val = nmos::fields::nc::value(arguments); + + slog::log(gate, SLOG_FLF) << "Add sequence item: " << property_id.serialize() << " value: " << val.serialize(); + + // find the relevant nc_property_descriptor + const auto& property = find_property(parse_nc_property_id(property_id), parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), get_control_protocol_class); + if (!property.is_null()) + { + if (!nmos::fields::nc::is_sequence(property)) + { + // property is not a sequence + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do AddSequenceItem"); + return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); + } + + auto& data = resource->data.at(nmos::fields::nc::name(property)); + + resources.modify(resource, [&](nmos::resource& resource) + { + auto& sequence = resource.data[nmos::fields::nc::name(property)]; + if (data.is_null()) { sequence = value::array(); } + web::json::push_back(sequence, val); + + resource.updated = strictly_increasing_update(resources); + }); + return make_control_protocol_response(handle, { nc_method_status::ok }, uint32_t(data.as_array().size() - 1)); + } + + // unknown property + utility::stringstream_t ss; + ss << U("unknown property: ") << property_id.serialize() << U(" to do AddSequenceItem"); + return make_control_protocol_error_response(handle, { nc_method_status::property_not_implemented }, ss.str()); + } + + // Delete sequence item + web::json::value remove_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + const auto& property_id = nmos::fields::nc::id(arguments); + const auto& index = nmos::fields::nc::index(arguments); + + slog::log(gate, SLOG_FLF) << "Remove sequence item: " << property_id.serialize() << " index: " << index; + + // find the relevant nc_property_descriptor + const auto& property = find_property(parse_nc_property_id(property_id), parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), get_control_protocol_class); + if (!property.is_null()) + { + if (!nmos::fields::nc::is_sequence(property)) + { + // property is not a sequence + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do RemoveSequenceItem"); + return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); + } + + auto& data = resource->data.at(nmos::fields::nc::name(property)); + + if (!data.is_null() && data.as_array().size() > (size_t)index) + { + resources.modify(resource, [&](nmos::resource& resource) + { + auto& sequence = resource.data[nmos::fields::nc::name(property)].as_array(); + sequence.erase(index); + + resource.updated = strictly_increasing_update(resources); + }); + return make_control_protocol_response(handle, { nc_method_status::ok }); + } + + // out of bound + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << U(" is outside the available range to do RemoveSequenceItem"); + return make_control_protocol_error_response(handle, { nc_method_status::index_out_of_bounds }, ss.str()); + } + + // unknown property + utility::stringstream_t ss; + ss << U("unknown property: ") << property_id.serialize() << U(" to do RemoveSequenceItem"); + return make_control_protocol_error_response(handle, { nc_method_status::property_not_implemented }, ss.str()); + } + + // Get sequence length + web::json::value get_sequence_length(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + using web::json::value; + + const auto& property_id = nmos::fields::nc::id(arguments); + + slog::log(gate, SLOG_FLF) << "Get sequence length: " << property_id.serialize(); + + // find the relevant nc_property_descriptor + const auto& property = find_property(parse_nc_property_id(property_id), parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), get_control_protocol_class); + if (!property.is_null()) + { + if (!nmos::fields::nc::is_sequence(property)) + { + // property is not a sequence + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do GetSequenceLength"); + return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); + } + + auto& data = resource->data.at(nmos::fields::nc::name(property)); + + if (nmos::fields::nc::is_nullable(property)) + { + // can be null + if (data.is_null()) + { + // null + return make_control_protocol_response(handle, { nc_method_status::ok }, value::null()); + } + } + else + { + // cannot be null + if (data.is_null()) + { + // null + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << " is a null sequence to do GetSequenceLength"; + return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); + } + } + return make_control_protocol_response(handle, { nc_method_status::ok }, uint32_t(data.as_array().size())); + } + + // unknown property + utility::stringstream_t ss; + ss << U("unknown property: ") << property_id.serialize() << " to do GetSequenceLength"; + return make_control_protocol_error_response(handle, { nc_method_status::property_not_implemented }, ss.str()); + } + + // NcBlock methods implementation + // Get descriptors of members of the block + web::json::value get_member_descriptors(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler, get_control_protocol_datatype_handler, slog::base_gate& gate) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + using web::json::value; + + const auto& recurse = nmos::fields::nc::recurse(arguments); // If recurse is set to true, nested members is to be retrieved + + slog::log(gate, SLOG_FLF) << "Get descriptors of members of the block: " << "recurse: " << recurse; + + auto descriptors = value::array(); + nmos::get_member_descriptors(resources, resource, recurse, descriptors.as_array()); + + return make_control_protocol_response(handle, { nc_method_status::ok }, descriptors); + } + + // Finds member(s) by path + web::json::value find_members_by_path(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler, get_control_protocol_datatype_handler, slog::base_gate& gate) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + using web::json::value; + + // Relative path to search for (MUST not include the role of the block targeted by oid) + const auto& path = arguments.at(nmos::fields::nc::path); + + slog::log(gate, SLOG_FLF) << "Find member(s) by path: " << "path: " << path.serialize(); + + if (0 == path.size()) + { + // empty path + return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("empty path to do FindMembersByPath")); + } + + auto nc_block_member_descriptors = value::array(); + value nc_block_member_descriptor; + + for (const auto& role : path.as_array()) + { + // look for the role in members + if (resource->data.has_field(nmos::fields::nc::members)) + { + auto& members = nmos::fields::nc::members(resource->data); + auto member_found = std::find_if(members.begin(), members.end(), [&](const web::json::value& nc_block_member_descriptor) + { + return role.as_string() == nmos::fields::nc::role(nc_block_member_descriptor); + }); + + if (members.end() != member_found) + { + nc_block_member_descriptor = *member_found; + + // use oid to look for the next resource + resource = nmos::find_resource(resources, utility::s2us(std::to_string(nmos::fields::nc::oid(*member_found)))); + } + else + { + // no role + utility::stringstream_t ss; + ss << U("role: ") << role.as_string() << U(" not found to do FindMembersByPath"); + return make_control_protocol_error_response(handle, { nc_method_status::bad_oid }, ss.str()); + } + } + else + { + // no members + return make_control_protocol_error_response(handle, { nc_method_status::bad_oid }, U("no members to do FindMembersByPath")); + } + } + + web::json::push_back(nc_block_member_descriptors, nc_block_member_descriptor); + return make_control_protocol_response(handle, { nc_method_status::ok }, nc_block_member_descriptors); + } + + // Finds members with given role name or fragment + web::json::value find_members_by_role(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler, get_control_protocol_datatype_handler, slog::base_gate& gate) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + using web::json::value; + + const auto& role = nmos::fields::nc::role(arguments); // Role text to search for + const auto& case_sensitive = nmos::fields::nc::case_sensitive(arguments); // Signals if the comparison should be case sensitive + const auto& match_whole_string = nmos::fields::nc::match_whole_string(arguments); // TRUE to only return exact matches + const auto& recurse = nmos::fields::nc::recurse(arguments); // TRUE to search nested blocks + + slog::log(gate, SLOG_FLF) << "Find members with given role name or fragment: " << "role: " << role; + + if (role.empty()) + { + // empty role + return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("empty role to do FindMembersByRole")); + } + + auto descriptors = value::array(); + nmos::find_members_by_role(resources, resource, role, match_whole_string, case_sensitive, recurse, descriptors.as_array()); + + return make_control_protocol_response(handle, { nc_method_status::ok }, descriptors); + } + + // Finds members with given class id + web::json::value find_members_by_class_id(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler, get_control_protocol_datatype_handler, slog::base_gate& gate) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + using web::json::value; + + const auto& class_id = parse_nc_class_id(nmos::fields::nc::class_id(arguments)); // Class id to search for + const auto& include_derived = nmos::fields::nc::include_derived(arguments); // If TRUE it will also include derived class descriptors + const auto& recurse = nmos::fields::nc::recurse(arguments); // TRUE to search nested blocks + + slog::log(gate, SLOG_FLF) << "Find members with given class id: " << "class_id: " << nmos::details::make_nc_class_id(class_id).serialize(); + + if (class_id.empty()) + { + // empty class_id + return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("empty classId to do FindMembersByClassId")); + } + + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + auto descriptors = value::array(); + nmos::find_members_by_class_id(resources, resource, class_id, include_derived, recurse, descriptors.as_array()); + + return make_control_protocol_response(handle, { nc_method_status::ok }, descriptors); + } + + // NcClassManager methods implementation + // Get a single class descriptor + web::json::value get_control_class(nmos::resources&, nmos::resources::iterator, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate) + { + const auto& class_id = parse_nc_class_id(nmos::fields::nc::class_id(arguments)); // Class id to search for + const auto& include_inherited = nmos::fields::nc::include_inherited(arguments); // If set the descriptor would contain all inherited elements + + slog::log(gate, SLOG_FLF) << "Get a single class descriptor: " << "class_id: " << nmos::details::make_nc_class_id(class_id).serialize(); + + if (class_id.empty()) + { + // empty class_id + return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("empty classId to do GetControlClass")); + } + + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + const auto& control_class = get_control_protocol_class(class_id); + if (!control_class.class_id.empty()) + { + auto& description = control_class.description; + auto& name = control_class.name; + auto& fixed_role = control_class.fixed_role; + auto properties = control_class.properties; + auto methods = control_class.methods; + auto events = control_class.events; + + if (include_inherited) + { + auto inherited_class_id = class_id; + inherited_class_id.pop_back(); + + while (!inherited_class_id.empty()) + { + const auto& inherited_control_class = get_control_protocol_class(inherited_class_id); + { + for (const auto& property : inherited_control_class.properties.as_array()) { web::json::push_back(properties, property); } + for (const auto& method : inherited_control_class.methods.as_array()) { web::json::push_back(methods, method); } + for (const auto& event : inherited_control_class.events.as_array()) { web::json::push_back(events, event); } + } + inherited_class_id.pop_back(); + } + } + auto descriptor = details::make_nc_class_descriptor(description, class_id, name, fixed_role, properties, methods, events); + + return make_control_protocol_response(handle, { nc_method_status::ok }, descriptor); + } + + return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("classId not found")); + } + + // Get a single datatype descriptor + web::json::value get_datatype(nmos::resources&, nmos::resources::iterator, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler, get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + const auto& name = nmos::fields::nc::name(arguments); // name of datatype + const auto& include_inherited = nmos::fields::nc::include_inherited(arguments); // If set the descriptor would contain all inherited elements + + slog::log(gate, SLOG_FLF) << "Get a single datatype descriptor: " << "name: " << name; + + if (name.empty()) + { + // empty name + return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("empty name to do GetDatatype")); + } + + const auto& datatype = get_control_protocol_datatype(name); + if (datatype.descriptor.size()) + { + auto descriptor = datatype.descriptor; + + if (include_inherited) + { + const auto& type = nmos::fields::nc::type(descriptor); + if (nc_datatype_type::Struct == type) + { + auto descriptor_ = descriptor; + + for (;;) + { + const auto& parent_type = descriptor_.at(nmos::fields::nc::parent_type); + if (!parent_type.is_null()) + { + const auto& parent_datatype = get_control_protocol_datatype(parent_type.as_string()); + if (parent_datatype.descriptor.size()) + { + descriptor_ = parent_datatype.descriptor; + + const auto& fields = nmos::fields::nc::fields(descriptor_); + for (const auto& field : fields) + { + web::json::push_back(descriptor.at(nmos::fields::nc::fields), field); + } + } + } + else + { + break; + } + } + } + } + + return make_control_protocol_response(handle, { nc_method_status::ok }, descriptor); + } + + return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("name not found")); + } + } +} diff --git a/Development/nmos/control_protocol_methods.h b/Development/nmos/control_protocol_methods.h new file mode 100644 index 000000000..3e7d136e5 --- /dev/null +++ b/Development/nmos/control_protocol_methods.h @@ -0,0 +1,50 @@ +#ifndef NMOS_CONTROL_PROTOCOL_METHODS_H +#define NMOS_CONTROL_PROTOCOL_METHODS_H + +#include "nmos/control_protocol_handlers.h" +#include "nmos/resources.h" + +namespace slog +{ + class base_gate; +} + +namespace nmos +{ + namespace details + { + // NcObject methods implementation + // Get property value + web::json::value get(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate); + // Set property value + web::json::value set(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate); + // Get sequence item + web::json::value get_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate); + // Set sequence item + web::json::value set_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate); + // Add item to sequence + web::json::value add_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate); + // Delete sequence item + web::json::value remove_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate); + // Get sequence length + web::json::value get_sequence_length(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate); + + // NcBlock methods implementation + // Get descriptors of members of the block + web::json::value get_member_descriptors(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler, get_control_protocol_datatype_handler, slog::base_gate& gate); + // Finds member(s) by path + web::json::value find_members_by_path(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler, get_control_protocol_datatype_handler, slog::base_gate& gate); + // Finds members with given role name or fragment + web::json::value find_members_by_role(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler, get_control_protocol_datatype_handler, slog::base_gate& gate); + // Finds members with given class id + web::json::value find_members_by_class_id(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler, get_control_protocol_datatype_handler, slog::base_gate& gate); + + // NcClassManager methods implementation + // Get a single class descriptor + web::json::value get_control_class(nmos::resources&, nmos::resources::iterator, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate); + // Get a single datatype descriptor + web::json::value get_datatype(nmos::resources&, nmos::resources::iterator, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler, get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate); + } +} + +#endif diff --git a/Development/nmos/control_protocol_resource.cpp b/Development/nmos/control_protocol_resource.cpp index 12d8da0a8..5cc1ec3eb 100644 --- a/Development/nmos/control_protocol_resource.cpp +++ b/Development/nmos/control_protocol_resource.cpp @@ -179,7 +179,7 @@ namespace nmos // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassdescriptor // description can be null // fixedRole can be null - web::json::value make_nc_class_descriptor(const web::json::value& description, const nc_class_id& class_id, const utility::string_t& name, const web::json::value& fixed_role, const web::json::value& properties, const web::json::value& methods, const web::json::value& events) + web::json::value make_nc_class_descriptor(const web::json::value& description, const nc_class_id& class_id, const nc_name& name, const web::json::value& fixed_role, const web::json::value& properties, const web::json::value& methods, const web::json::value& events) { using web::json::value; @@ -193,7 +193,7 @@ namespace nmos return data; } - web::json::value make_nc_class_descriptor(const utility::string_t& description, const nc_class_id& class_id, const utility::string_t& name, const web::json::value& fixed_role, const web::json::value& properties, const web::json::value& methods, const web::json::value& events) + web::json::value make_nc_class_descriptor(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const web::json::value& fixed_role, const web::json::value& properties, const web::json::value& methods, const web::json::value& events) { using web::json::value; @@ -202,7 +202,7 @@ namespace nmos // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncenumitemdescriptor // description can be null - web::json::value make_nc_enum_item_descriptor(const web::json::value& description, const utility::string_t& name, uint16_t val) + web::json::value make_nc_enum_item_descriptor(const web::json::value& description, const nc_name& name, uint16_t val) { using web::json::value; @@ -212,7 +212,7 @@ namespace nmos return data; } - web::json::value make_nc_enum_item_descriptor(const utility::string_t& description, const utility::string_t& name, uint16_t val) + web::json::value make_nc_enum_item_descriptor(const utility::string_t& description, const nc_name& name, uint16_t val) { using web::json::value; @@ -222,7 +222,7 @@ namespace nmos // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#nceventdescriptor // description can be null // id = make_nc_event_id(level, index) - web::json::value make_nc_event_descriptor(const web::json::value& description, const nc_event_id& id, const utility::string_t& name, const utility::string_t& event_datatype, bool is_deprecated) + web::json::value make_nc_event_descriptor(const web::json::value& description, const nc_event_id& id, const nc_name& name, const utility::string_t& event_datatype, bool is_deprecated) { using web::json::value; @@ -234,7 +234,7 @@ namespace nmos return data; } - web::json::value make_nc_event_descriptor(const utility::string_t& description, const nc_event_id& id, const utility::string_t& name, const utility::string_t& event_datatype, bool is_deprecated) + web::json::value make_nc_event_descriptor(const utility::string_t& description, const nc_event_id& id, const nc_name& name, const utility::string_t& event_datatype, bool is_deprecated) { using web::json::value; @@ -245,7 +245,7 @@ namespace nmos // description can be null // type_name can be null // constraints can be null - web::json::value make_nc_field_descriptor(const web::json::value& description, const utility::string_t& name, const web::json::value& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints) + web::json::value make_nc_field_descriptor(const web::json::value& description, const nc_name& name, const web::json::value& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints) { using web::json::value; @@ -258,7 +258,7 @@ namespace nmos return data; } - web::json::value make_nc_field_descriptor(const utility::string_t& description, const utility::string_t& name, const utility::string_t& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints) + web::json::value make_nc_field_descriptor(const utility::string_t& description, const nc_name& name, const utility::string_t& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints) { using web::json::value; @@ -269,7 +269,7 @@ namespace nmos // description can be null // id = make_nc_method_id(level, index) // sequence parameters - web::json::value make_nc_method_descriptor(const web::json::value& description, const nc_method_id& id, const utility::string_t& name, const utility::string_t& result_datatype, const web::json::value& parameters, bool is_deprecated) + web::json::value make_nc_method_descriptor(const web::json::value& description, const nc_method_id& id, const nc_name& name, const utility::string_t& result_datatype, const web::json::value& parameters, bool is_deprecated) { using web::json::value; @@ -282,7 +282,7 @@ namespace nmos return data; } - web::json::value make_nc_method_descriptor(const utility::string_t& description, const nc_method_id& id, const utility::string_t& name, const utility::string_t& result_datatype, const web::json::value& parameters, bool is_deprecated) + web::json::value make_nc_method_descriptor(const utility::string_t& description, const nc_method_id& id, const nc_name& name, const utility::string_t& result_datatype, const web::json::value& parameters, bool is_deprecated) { using web::json::value; @@ -292,7 +292,7 @@ namespace nmos // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncparameterdescriptor // description can be null // type_name can be null - web::json::value make_nc_parameter_descriptor(const web::json::value& description, const utility::string_t& name, const web::json::value& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints) + web::json::value make_nc_parameter_descriptor(const web::json::value& description, const nc_name& name, const web::json::value& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints) { using web::json::value; @@ -305,13 +305,13 @@ namespace nmos return data; } - web::json::value make_nc_parameter_descriptor(const utility::string_t& description, const utility::string_t& name, bool is_nullable, bool is_sequence, const web::json::value& constraints) + web::json::value make_nc_parameter_descriptor(const utility::string_t& description, const nc_name& name, bool is_nullable, bool is_sequence, const web::json::value& constraints) { using web::json::value; return make_nc_parameter_descriptor(value::string(description), name, value::null(), is_nullable, is_sequence, constraints); } - web::json::value make_nc_parameter_descriptor(const utility::string_t& description, const utility::string_t& name, const utility::string_t& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints) + web::json::value make_nc_parameter_descriptor(const utility::string_t& description, const nc_name& name, const utility::string_t& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints) { using web::json::value; @@ -321,7 +321,7 @@ namespace nmos // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncpropertydescriptor // description can be null // constraints can be null - web::json::value make_nc_property_descriptor(const web::json::value& description, const nc_property_id& id, const utility::string_t& name, const web::json::value& type_name, + web::json::value make_nc_property_descriptor(const web::json::value& description, const nc_property_id& id, const nc_name& name, const web::json::value& type_name, bool is_read_only, bool is_nullable, bool is_sequence, bool is_deprecated, const web::json::value& constraints) { using web::json::value; @@ -338,7 +338,7 @@ namespace nmos return data; } - web::json::value make_nc_property_descriptor(const utility::string_t& description, const nc_property_id& id, const utility::string_t& name, const utility::string_t& type_name, + web::json::value make_nc_property_descriptor(const utility::string_t& description, const nc_property_id& id, const nc_name& name, const utility::string_t& type_name, bool is_read_only, bool is_nullable, bool is_sequence, bool is_deprecated, const web::json::value& constraints) { using web::json::value; @@ -349,7 +349,7 @@ namespace nmos // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptor // description can be null // constraints can be null - web::json::value make_nc_datatype_descriptor(const web::json::value& description, const utility::string_t& name, nc_datatype_type::type type, const web::json::value& constraints) + web::json::value make_nc_datatype_descriptor(const web::json::value& description, const nc_name& name, nc_datatype_type::type type, const web::json::value& constraints) { using web::json::value; @@ -365,7 +365,7 @@ namespace nmos // description can be null // constraints can be null // items: sequence - web::json::value make_nc_datatype_descriptor_enum(const web::json::value& description, const utility::string_t& name, const web::json::value& items, const web::json::value& constraints) + web::json::value make_nc_datatype_descriptor_enum(const web::json::value& description, const nc_name& name, const web::json::value& items, const web::json::value& constraints) { auto data = make_nc_datatype_descriptor(description, name, nc_datatype_type::Enum, constraints); data[nmos::fields::nc::items] = items; @@ -376,7 +376,7 @@ namespace nmos // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptorprimitive // description can be null // constraints can be null - web::json::value make_nc_datatype_descriptor_primitive(const web::json::value& description, const utility::string_t& name, const web::json::value& constraints) + web::json::value make_nc_datatype_descriptor_primitive(const web::json::value& description, const nc_name& name, const web::json::value& constraints) { return make_nc_datatype_descriptor(description, name, nc_datatype_type::Primitive, constraints); } @@ -386,7 +386,7 @@ namespace nmos // constraints can be null // fields: sequence // parent_type can be null - web::json::value make_nc_datatype_descriptor_struct(const web::json::value& description, const utility::string_t& name, const web::json::value& fields, const web::json::value& parent_type, const web::json::value& constraints) + web::json::value make_nc_datatype_descriptor_struct(const web::json::value& description, const nc_name& name, const web::json::value& fields, const web::json::value& parent_type, const web::json::value& constraints) { auto data = make_nc_datatype_descriptor(description, name, nc_datatype_type::Struct, constraints); data[nmos::fields::nc::fields] = fields; @@ -398,7 +398,7 @@ namespace nmos // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptortypedef // description can be null // constraints can be null - web::json::value make_nc_datatype_typedef(const web::json::value& description, const utility::string_t& name, bool is_sequence, const utility::string_t& parent_type, const web::json::value& constraints) + web::json::value make_nc_datatype_typedef(const web::json::value& description, const nc_name& name, bool is_sequence, const utility::string_t& parent_type, const web::json::value& constraints) { using web::json::value; diff --git a/Development/nmos/control_protocol_resource.h b/Development/nmos/control_protocol_resource.h index 684a0eb44..648b654be 100644 --- a/Development/nmos/control_protocol_resource.h +++ b/Development/nmos/control_protocol_resource.h @@ -70,78 +70,78 @@ namespace nmos // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassdescriptor // description can be null // fixedRole can be null - web::json::value make_nc_class_descriptor(const web::json::value& description, const nc_class_id& class_id, const utility::string_t& name, const web::json::value& fixed_role, const web::json::value& properties, const web::json::value& methods, const web::json::value& events); - web::json::value make_nc_class_descriptor(const utility::string_t& description, const nc_class_id& class_id, const utility::string_t& name, const web::json::value& fixed_role, const web::json::value& properties, const web::json::value& methods, const web::json::value& events); + web::json::value make_nc_class_descriptor(const web::json::value& description, const nc_class_id& class_id, const nc_name& name, const web::json::value& fixed_role, const web::json::value& properties, const web::json::value& methods, const web::json::value& events); + web::json::value make_nc_class_descriptor(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const web::json::value& fixed_role, const web::json::value& properties, const web::json::value& methods, const web::json::value& events); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncenumitemdescriptor // description can be null - web::json::value make_nc_enum_item_descriptor(const web::json::value& description, const utility::string_t& name, uint16_t val); - web::json::value make_nc_enum_item_descriptor(const utility::string_t& description, const utility::string_t& name, uint16_t val); + web::json::value make_nc_enum_item_descriptor(const web::json::value& description, const nc_name& name, uint16_t val); + web::json::value make_nc_enum_item_descriptor(const utility::string_t& description, const nc_name& name, uint16_t val); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#nceventdescriptor // description can be null // id = make_nc_event_id(level, index) - web::json::value make_nc_event_descriptor(const web::json::value& description, const nc_event_id& id, const utility::string_t& name, const utility::string_t& event_datatype, bool is_deprecated); - web::json::value make_nc_event_descriptor(const utility::string_t& description, const nc_event_id& id, const utility::string_t& name, const utility::string_t& event_datatype, bool is_deprecated); + web::json::value make_nc_event_descriptor(const web::json::value& description, const nc_event_id& id, const nc_name& name, const utility::string_t& event_datatype, bool is_deprecated); + web::json::value make_nc_event_descriptor(const utility::string_t& description, const nc_event_id& id, const nc_name& name, const utility::string_t& event_datatype, bool is_deprecated); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncfielddescriptor // description can be null // type_name can be null // constraints can be null - web::json::value make_nc_field_descriptor(const web::json::value& description, const utility::string_t& name, const web::json::value& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints = web::json::value::null()); - web::json::value make_nc_field_descriptor(const utility::string_t& description, const utility::string_t& name, const utility::string_t& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints = web::json::value::null()); + web::json::value make_nc_field_descriptor(const web::json::value& description, const nc_name& name, const web::json::value& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints = web::json::value::null()); + web::json::value make_nc_field_descriptor(const utility::string_t& description, const nc_name& name, const utility::string_t& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints = web::json::value::null()); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmethoddescriptor // description can be null // id = make_nc_method_id(level, index) // sequence parameters - web::json::value make_nc_method_descriptor(const web::json::value& description, const nc_method_id& id, const utility::string_t& name, const utility::string_t& result_datatype, const web::json::value& parameters, bool is_deprecated); - web::json::value make_nc_method_descriptor(const utility::string_t& description, const nc_method_id& id, const utility::string_t& name, const utility::string_t& result_datatype, const web::json::value& parameters, bool is_deprecated); + web::json::value make_nc_method_descriptor(const web::json::value& description, const nc_method_id& id, const nc_name& name, const utility::string_t& result_datatype, const web::json::value& parameters, bool is_deprecated); + web::json::value make_nc_method_descriptor(const utility::string_t& description, const nc_method_id& id, const nc_name& name, const utility::string_t& result_datatype, const web::json::value& parameters, bool is_deprecated); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncparameterdescriptor // description can be null // type_name can be null - web::json::value make_nc_parameter_descriptor(const web::json::value& description, const utility::string_t& name, const web::json::value& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints = web::json::value::null()); - web::json::value make_nc_parameter_descriptor(const utility::string_t& description, const utility::string_t& name, bool is_nullable, bool is_sequence, const web::json::value& constraints = web::json::value::null()); - web::json::value make_nc_parameter_descriptor(const utility::string_t& description, const utility::string_t& name, const utility::string_t& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints = web::json::value::null()); + web::json::value make_nc_parameter_descriptor(const web::json::value& description, const nc_name& name, const web::json::value& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints = web::json::value::null()); + web::json::value make_nc_parameter_descriptor(const utility::string_t& description, const nc_name& name, bool is_nullable, bool is_sequence, const web::json::value& constraints = web::json::value::null()); + web::json::value make_nc_parameter_descriptor(const utility::string_t& description, const nc_name& name, const utility::string_t& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints = web::json::value::null()); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncpropertydescriptor // description can be null // id = make_nc_property_id(level, index); // type_name can be null // constraints can be null - web::json::value make_nc_property_descriptor(const web::json::value& description, const nc_property_id& id, const utility::string_t& name, const web::json::value& type_name, + web::json::value make_nc_property_descriptor(const web::json::value& description, const nc_property_id& id, const nc_name& name, const web::json::value& type_name, bool is_read_only, bool is_nullable, bool is_sequence, bool is_deprecated, const web::json::value& constraints = web::json::value::null()); - web::json::value make_nc_property_descriptor(const utility::string_t& description, const nc_property_id& id, const utility::string_t& name, const utility::string_t& type_name, + web::json::value make_nc_property_descriptor(const utility::string_t& description, const nc_property_id& id, const nc_name& name, const utility::string_t& type_name, bool is_read_only, bool is_nullable, bool is_sequence, bool is_deprecated, const web::json::value& constraints = web::json::value::null()); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptor // description can be null // constraints can be null - web::json::value make_nc_datatype_descriptor(const web::json::value& description, const utility::string_t& name, nc_datatype_type::type type, const web::json::value& constraints = web::json::value::null()); + web::json::value make_nc_datatype_descriptor(const web::json::value& description, const nc_name& name, nc_datatype_type::type type, const web::json::value& constraints = web::json::value::null()); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptorenum // description can be null // constraints can be null // items: sequence - web::json::value make_nc_datatype_descriptor_enum(const web::json::value& description, const utility::string_t& name, const web::json::value& items, const web::json::value& constraints = web::json::value::null()); + web::json::value make_nc_datatype_descriptor_enum(const web::json::value& description, const nc_name& name, const web::json::value& items, const web::json::value& constraints = web::json::value::null()); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptorprimitive // description can be null // constraints can be null - web::json::value make_nc_datatype_descriptor_primitive(const web::json::value& description, const utility::string_t& name, const web::json::value& constraints = web::json::value::null()); + web::json::value make_nc_datatype_descriptor_primitive(const web::json::value& description, const nc_name& name, const web::json::value& constraints = web::json::value::null()); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptorstruct // description can be null // constraints can be null // fields: sequence // parent_type can be null - web::json::value make_nc_datatype_descriptor_struct(const web::json::value& description, const utility::string_t& name, const web::json::value& fields, const web::json::value& parent_type, const web::json::value& constraints = web::json::value::null()); + web::json::value make_nc_datatype_descriptor_struct(const web::json::value& description, const nc_name& name, const web::json::value& fields, const web::json::value& parent_type, const web::json::value& constraints = web::json::value::null()); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptortypedef // description can be null // constraints can be null - web::json::value make_nc_datatype_typedef(const web::json::value& description, const utility::string_t& name, bool is_sequence, const utility::string_t& parent_type, const web::json::value& constraints = web::json::value::null()); + web::json::value make_nc_datatype_typedef(const web::json::value& description, const nc_name& name, bool is_sequence, const utility::string_t& parent_type, const web::json::value& constraints = web::json::value::null()); // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject web::json::value make_nc_object(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints); diff --git a/Development/nmos/control_protocol_state.cpp b/Development/nmos/control_protocol_state.cpp index d4ff47a85..7376a7ed0 100644 --- a/Development/nmos/control_protocol_state.cpp +++ b/Development/nmos/control_protocol_state.cpp @@ -1,49 +1,67 @@ #include "nmos/control_protocol_state.h" -#include "nmos/control_protocol_resource.h" // for nc_object_class_id, nc_block_class_id, nc_worker_class_id, nc_manager_class_id, nc_device_manager_class_id, nc_class_manager_class_id definitions +#include "nmos/control_protocol_methods.h" +#include "nmos/control_protocol_resource.h" namespace nmos { namespace experimental { - // create control class property - web::json::value make_control_class_property(const utility::string_t& description, const nc_property_id& id, const utility::string_t& name, const utility::string_t& type_name, bool is_read_only, bool is_nullable, bool is_sequence, bool is_deprecated, const web::json::value& constraints) - { - return nmos::details::make_nc_property_descriptor(description, id, name, type_name, is_read_only, is_nullable, is_sequence, is_deprecated, constraints); - } - namespace details { - control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const utility::string_t& name, const web::json::value& fixed_role, const std::vector& properties_, const std::vector& methods_, const std::vector& events_) + // create control class + // where + // properties: vector of NcPropertyDescriptor which can be constructed using make_control_class_property + // methods: vector of NcMethodDescriptor which can be constructed using make_nc_method_descriptor and the assoicated method handler + // events: vector of NcEventDescriptor can be constructed using make_nc_event_descriptor + control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const utility::string_t& name, const web::json::value& fixed_role, const std::vector& properties_, const std::vector>& methods_, const std::vector& events_) { using web::json::value; web::json::value properties = value::array(); for (const auto& property : properties_) { web::json::push_back(properties, property); } web::json::value methods = value::array(); - for (const auto& method : methods_) { web::json::push_back(methods, method); } + nmos::experimental::methods method_handlers; + for (const auto& method : methods_) + { + web::json::push_back(methods, method.first); + method_handlers[nmos::details::parse_nc_method_id(nmos::fields::nc::id(method.first))] = method.second; + } web::json::value events = value::array(); for (const auto& event : events_) { web::json::push_back(events, event); } - return { value::string(description), class_id, name, fixed_role, properties, methods, events }; + return { value::string(description), class_id, name, fixed_role, properties, methods, events, method_handlers }; } } - // create control class with fixed role - control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const utility::string_t& name, const utility::string_t& fixed_role, const std::vector& properties, const std::vector& methods, const std::vector& events) + // where + // properties: vector of NcPropertyDescriptor which can be constructed using make_control_class_property + // methods: vector of NcMethodDescriptor which can be constructed using make_nc_method_descriptor and the assoicated method handler + // events: vector of NcEventDescriptor can be constructed using make_nc_event_descriptor + control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const utility::string_t& name, const utility::string_t& fixed_role, const std::vector& properties, const std::vector>& methods, const std::vector& events) { using web::json::value; return details::make_control_class(description, class_id, name, value::string(fixed_role), properties, methods, events); } // create control class with no fixed role - control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const utility::string_t& name, const std::vector& properties, const std::vector& methods, const std::vector& events) + // where + // properties: vector of NcPropertyDescriptor which can be constructed using make_control_class_property + // methods: vector of NcMethodDescriptor which can be constructed using make_nc_method_descriptor and the assoicated method handler + // events: vector of NcEventDescriptor can be constructed using make_nc_event_descriptor + control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const utility::string_t& name, const std::vector& properties, const std::vector>& methods, const std::vector& events) { using web::json::value; return details::make_control_class(description, class_id, name, value::null(), properties, methods, events); } + // create control class property + web::json::value make_control_class_property(const utility::string_t& description, const nc_property_id& id, const utility::string_t& name, const utility::string_t& type_name, bool is_read_only, bool is_nullable, bool is_sequence, bool is_deprecated, const web::json::value& constraints) + { + return nmos::details::make_nc_property_descriptor(description, id, name, type_name, is_read_only, is_nullable, is_sequence, is_deprecated, constraints); + } + // create control class method parameter web::json::value make_control_class_method_parameter(const utility::string_t& description, const utility::string_t& name, const utility::string_t& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints) { @@ -80,24 +98,63 @@ namespace nmos return std::vector{}; }; + auto to_methods_vector = [](const web::json::value& method_data_array, const nmos::experimental::methods& method_handlers) + { + std::vector> methods; + + if (!method_data_array.is_null()) + { + for (auto& method_data : method_data_array.as_array()) + { + methods.push_back({ method_data, method_handlers.at(nmos::details::parse_nc_method_id(nmos::fields::nc::id(method_data))) }); + } + } + return methods; + }; + // setup the core control classes control_classes = { // Control class models // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/#control-class-models-for-branch-v10-dev - { nc_object_class_id, make_control_class(U("NcObject class descriptor"), nc_object_class_id, U("NcObject"), to_vector(make_nc_object_properties()), to_vector(make_nc_object_methods()), to_vector(make_nc_object_events())) }, - { nc_block_class_id, make_control_class(U("NcBlock class descriptor"), nc_block_class_id, U("NcBlock"), to_vector(make_nc_block_properties()), to_vector(make_nc_block_methods()), to_vector(make_nc_block_events())) }, - { nc_worker_class_id, make_control_class(U("NcWorker class descriptor"), nc_worker_class_id, U("NcWorker"), to_vector(make_nc_worker_properties()), to_vector(make_nc_worker_methods()), to_vector(make_nc_worker_events())) }, - { nc_manager_class_id, make_control_class(U("NcManager class descriptor"), nc_manager_class_id, U("NcManager"),to_vector(make_nc_manager_properties()), to_vector(make_nc_manager_methods()), to_vector(make_nc_manager_events())) }, - { nc_device_manager_class_id, make_control_class(U("NcDeviceManager class descriptor"), nc_device_manager_class_id, U("NcDeviceManager"), U("DeviceManager"), to_vector(make_nc_device_manager_properties()), to_vector(make_nc_device_manager_methods()), to_vector(make_nc_device_manager_events())) }, - { nc_class_manager_class_id, make_control_class(U("NcClassManager class descriptor"), nc_class_manager_class_id, U("NcClassManager"), U("ClassManager"), to_vector(make_nc_class_manager_properties()), to_vector(make_nc_class_manager_methods()), to_vector(make_nc_class_manager_events())) }, + { nc_object_class_id, make_control_class(U("NcObject class descriptor"), nc_object_class_id, U("NcObject"), to_vector(make_nc_object_properties()), + to_methods_vector(make_nc_object_methods(), + { + { {1, 1}, nmos::details::get }, + { {1, 2}, nmos::details::set }, + { {1, 3}, nmos::details::get_sequence_item }, + { {1, 4}, nmos::details::set_sequence_item }, + { {1, 5}, nmos::details::add_sequence_item }, + { {1, 6}, nmos::details::remove_sequence_item }, + { {1, 7}, nmos::details::get_sequence_length } + }), + to_vector(make_nc_object_events())) }, + { nc_block_class_id, make_control_class(U("NcBlock class descriptor"), nc_block_class_id, U("NcBlock"), to_vector(make_nc_block_properties()), + to_methods_vector(make_nc_block_methods(), + { + { {2, 1}, nmos::details::get_member_descriptors }, + { {2, 2}, nmos::details::find_members_by_path }, + { {2, 3}, nmos::details::find_members_by_role }, + { {2, 4}, nmos::details::find_members_by_class_id } + }), + to_vector(make_nc_block_events())) }, + { nc_worker_class_id, make_control_class(U("NcWorker class descriptor"), nc_worker_class_id, U("NcWorker"), to_vector(make_nc_worker_properties()), to_methods_vector(make_nc_worker_methods(), {}), to_vector(make_nc_worker_events())) }, + { nc_manager_class_id, make_control_class(U("NcManager class descriptor"), nc_manager_class_id, U("NcManager"),to_vector(make_nc_manager_properties()), to_methods_vector(make_nc_manager_methods(), {}), to_vector(make_nc_manager_events())) }, + { nc_device_manager_class_id, make_control_class(U("NcDeviceManager class descriptor"), nc_device_manager_class_id, U("NcDeviceManager"), U("DeviceManager"), to_vector(make_nc_device_manager_properties()), to_methods_vector(make_nc_device_manager_methods(), {}), to_vector(make_nc_device_manager_events())) }, + { nc_class_manager_class_id, make_control_class(U("NcClassManager class descriptor"), nc_class_manager_class_id, U("NcClassManager"), U("ClassManager"), to_vector(make_nc_class_manager_properties()), + to_methods_vector(make_nc_class_manager_methods(), + { + { {3, 1}, nmos::details::get_control_class }, + { {3, 2}, nmos::details::get_datatype } + }), + to_vector(make_nc_class_manager_events())) }, // identification beacon model // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/identification/#ncidentbeacon - { nc_ident_beacon_class_id, make_control_class(U("NcIdentBeacon class descriptor"), nc_ident_beacon_class_id, U("NcIdentBeacon"), to_vector(make_nc_ident_beacon_properties()), to_vector(make_nc_ident_beacon_methods()), to_vector(make_nc_ident_beacon_events())) }, + { nc_ident_beacon_class_id, make_control_class(U("NcIdentBeacon class descriptor"), nc_ident_beacon_class_id, U("NcIdentBeacon"), to_vector(make_nc_ident_beacon_properties()), to_methods_vector(make_nc_ident_beacon_methods(), {}), to_vector(make_nc_ident_beacon_events())) }, // Monitoring // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitor - { nc_receiver_monitor_class_id, make_control_class(U("NcReceiverMonitor class descriptor"), nc_receiver_monitor_class_id, U("NcReceiverMonitor"), to_vector(make_nc_receiver_monitor_properties()), to_vector(make_nc_receiver_monitor_methods()), to_vector(make_nc_receiver_monitor_events())) }, - { nc_receiver_monitor_protected_class_id, make_control_class(U("NcReceiverMonitorProtected class descriptor"), nc_receiver_monitor_protected_class_id, U("NcReceiverMonitorProtected"), to_vector(make_nc_receiver_monitor_protected_properties()), to_vector(make_nc_receiver_monitor_protected_methods()), to_vector(make_nc_receiver_monitor_protected_events())) } + { nc_receiver_monitor_class_id, make_control_class(U("NcReceiverMonitor class descriptor"), nc_receiver_monitor_class_id, U("NcReceiverMonitor"), to_vector(make_nc_receiver_monitor_properties()), to_methods_vector(make_nc_receiver_monitor_methods(), {}), to_vector(make_nc_receiver_monitor_events())) }, + { nc_receiver_monitor_protected_class_id, make_control_class(U("NcReceiverMonitorProtected class descriptor"), nc_receiver_monitor_protected_class_id, U("NcReceiverMonitorProtected"), to_vector(make_nc_receiver_monitor_protected_properties()), to_methods_vector(make_nc_receiver_monitor_protected_methods(), {}), to_vector(make_nc_receiver_monitor_protected_events())) } }; // setup the core datatypes diff --git a/Development/nmos/control_protocol_state.h b/Development/nmos/control_protocol_state.h index 41fd6824a..77b2571d7 100644 --- a/Development/nmos/control_protocol_state.h +++ b/Development/nmos/control_protocol_state.h @@ -3,9 +3,9 @@ #include #include "cpprest/json_utils.h" +#include "nmos/control_protocol_handlers.h" #include "nmos/control_protocol_typedefs.h" #include "nmos/mutex.h" -#include "nmos/resources.h" namespace slog { class base_gate; } @@ -20,9 +20,11 @@ namespace nmos utility::string_t name; web::json::value fixed_role; - web::json::value properties; // array of nc_property_descriptor - web::json::value methods; // array of nc_method_descriptor - web::json::value events; // array of nc_event_descriptor + web::json::value properties = web::json::value::array(); // array of NcPropertyDescriptor + web::json::value methods = web::json::value::array(); // array of NcMethodDescriptor + web::json::value events = web::json::value::array(); // array of NcEventDescriptor + + nmos::experimental::methods method_handlers; // map of method handlers which are associated to this control_class (class_id), but not including its base class }; struct datatype // NcDatatypeDescriptorEnum/NcDatatypeDescriptorPrimitive/NcDatatypeDescriptorStruct/NcDatatypeDescriptorTypeDef @@ -30,14 +32,8 @@ namespace nmos web::json::value descriptor; }; - // nc_class_id vs control_class typedef std::map control_classes; - // nc_name vs datatype - typedef std::map datatypes; - - // methods defnitions - typedef std::function method; - typedef std::map methods; // method_id vs method handler + typedef std::map datatypes; struct control_protocol_state { @@ -79,10 +75,11 @@ namespace nmos // create control class property web::json::value make_control_class_property(const utility::string_t& description, const nc_property_id& id, const utility::string_t& name, const utility::string_t& type_name, bool is_read_only = false, bool is_nullable = false, bool is_sequence = false, bool is_deprecated = false, const web::json::value& constraints = web::json::value::null()); + // create control class with fixed role - control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const utility::string_t& name, const utility::string_t& fixed_role, const std::vector& properties, const std::vector& methods, const std::vector& events); + control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const utility::string_t& name, const utility::string_t& fixed_role, const std::vector& properties, const std::vector>& methods, const std::vector& events); // create control class with no fixed role - control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const utility::string_t& name, const std::vector& properties, const std::vector& methods, const std::vector& events); + control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const utility::string_t& name, const std::vector& properties, const std::vector>& methods, const std::vector& events); } } diff --git a/Development/nmos/control_protocol_typedefs.h b/Development/nmos/control_protocol_typedefs.h index a7d6bc1a1..bf33a331a 100644 --- a/Development/nmos/control_protocol_typedefs.h +++ b/Development/nmos/control_protocol_typedefs.h @@ -159,6 +159,10 @@ namespace nmos // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncid typedef uint32_t nc_id; + // NcName + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncname + typedef utility::string_t nc_name; + // NcOid // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncoid typedef uint32_t nc_oid; diff --git a/Development/nmos/control_protocol_utils.cpp b/Development/nmos/control_protocol_utils.cpp index 3db423168..0bc6a9f24 100644 --- a/Development/nmos/control_protocol_utils.cpp +++ b/Development/nmos/control_protocol_utils.cpp @@ -5,7 +5,7 @@ #include #include "cpprest/json_utils.h" #include "nmos/control_protocol_resource.h" -#include "nmos/control_protocol_typedefs.h" +#include "nmos/control_protocol_state.h" #include "nmos/json_fields.h" #include "nmos/resources.h" @@ -25,27 +25,59 @@ namespace nmos } } + // is the given class_id a NcBlock bool is_nc_block(const nc_class_id& class_id) { return details::is_control_class(nc_object_class_id, class_id); } + // is the given class_id a NcManager bool is_nc_manager(const nc_class_id& class_id) { return details::is_control_class(nc_manager_class_id, class_id); } + // is the given class_id a NcDeviceManager bool is_nc_device_manager(const nc_class_id& class_id) { return details::is_control_class(nc_device_manager_class_id, class_id); } + // is the given class_id a NcClassManager bool is_nc_class_manager(const nc_class_id& class_id) { return details::is_control_class(nc_class_manager_class_id, class_id); } - nc_class_id make_nc_class_id(const nc_class_id& prefix, int32_t authority_key, const nc_class_id& suffix) + // find control class property (NcPropertyDescriptor) + web::json::value find_property(const nc_property_id& property_id, const nc_class_id& class_id_, get_control_protocol_class_handler get_control_protocol_class) + { + using web::json::value; + + auto class_id = class_id_; + + while (!class_id.empty()) + { + const auto& control_class = get_control_protocol_class(class_id); + auto& properties = control_class.properties.as_array(); + if (properties.size()) + { + for (const auto& property : properties) + { + if (property_id == nmos::details::parse_nc_property_id(nmos::fields::nc::id(property))) + { + return property; + } + } + } + class_id.pop_back(); + } + + return value::null(); + } + + // construct NcClassId + nc_class_id make_nc_class_id(const nc_class_id& prefix, int32_t authority_key, const std::vector& suffix) { nc_class_id class_id = prefix; class_id.push_back(authority_key); @@ -53,6 +85,7 @@ namespace nmos return class_id; } + // get descriptors of members of the block void get_member_descriptors(const resources& resources, resources::iterator resource, bool recurse, web::json::array& descriptors) { if (resource->data.has_field(nmos::fields::nc::members)) @@ -82,6 +115,7 @@ namespace nmos } } + // find members with given role name or fragment void find_members_by_role(const resources& resources, resources::iterator resource, const utility::string_t& role, bool match_whole_string, bool case_sensitive, bool recurse, web::json::array& descriptors) { auto find_members_by_matching_role = [&](const web::json::array& members) @@ -132,6 +166,7 @@ namespace nmos } } + // find members with given class id void find_members_by_class_id(const resources& resources, resources::iterator resource, const nc_class_id& class_id_, bool include_derived, bool recurse, web::json::array& descriptors) { auto find_members_by_matching_class_id = [&](const web::json::array& members) diff --git a/Development/nmos/control_protocol_utils.h b/Development/nmos/control_protocol_utils.h index acb4a7c76..47838ddd6 100644 --- a/Development/nmos/control_protocol_utils.h +++ b/Development/nmos/control_protocol_utils.h @@ -2,25 +2,35 @@ #define NMOS_CONTROL_PROTOCOL_UTILS_H #include "cpprest/basic_utils.h" -#include "nmos/control_protocol_typedefs.h" // for nc_class_id definition -#include "nmos/resources.h" +#include "nmos/control_protocol_handlers.h" namespace nmos { + // is the given class_id a NcBlock bool is_nc_block(const nc_class_id& class_id); + // is the given class_id a NcManager bool is_nc_manager(const nc_class_id& class_id); + // is the given class_id a NcDeviceManager bool is_nc_device_manager(const nc_class_id& class_id); + // is the given class_id a NcClassManager bool is_nc_class_manager(const nc_class_id& class_id); - nc_class_id make_nc_class_id(const nc_class_id& prefix, int32_t authority_key, const nc_class_id& suffix); + // find control class property (NcPropertyDescriptor) + web::json::value find_property(const nc_property_id& property_id, const nc_class_id& class_id, get_control_protocol_class_handler get_control_protocol_class); + // construct NcClassId + nc_class_id make_nc_class_id(const nc_class_id& prefix, int32_t authority_key, const std::vector& suffix); + + // get descriptors of members of the block void get_member_descriptors(const resources& resources, resources::iterator resource, bool recurse, web::json::array& descriptors); + // find members with given role name or fragment void find_members_by_role(const resources& resources, resources::iterator resource, const utility::string_t& role, bool match_whole_string, bool case_sensitive, bool recurse, web::json::array& nc_block_member_descriptors); + // find members with given class id void find_members_by_class_id(const resources& resources, resources::iterator resource, const nc_class_id& class_id, bool include_derived, bool recurse, web::json::array& descriptors); } diff --git a/Development/nmos/control_protocol_ws_api.cpp b/Development/nmos/control_protocol_ws_api.cpp index 8f22bbc99..bca663ee2 100644 --- a/Development/nmos/control_protocol_ws_api.cpp +++ b/Development/nmos/control_protocol_ws_api.cpp @@ -2,12 +2,9 @@ #include #include "cpprest/json_validator.h" -#include "cpprest/regex_utils.h" #include "nmos/api_utils.h" #include "nmos/control_protocol_resources.h" #include "nmos/control_protocol_resource.h" -#include "nmos/control_protocol_state.h" -#include "nmos/control_protocol_utils.h" #include "nmos/is12_versions.h" #include "nmos/json_schema.h" #include "nmos/model.h" @@ -48,604 +45,8 @@ namespace nmos controlprotocol_validator().validate(request_data, experimental::make_controlprotocolapi_subscription_message_schema_uri(version)); } - // hmm, change property to struct - web::json::value find_property(const web::json::value& property_id, const nc_class_id& class_id_, const nmos::experimental::control_classes& control_classes) + nmos::experimental::method find_method(const nc_method_id& method_id, const nc_class_id& class_id_, const std::map& methods) { - using web::json::value; - - auto class_id = class_id_; - - while (!class_id.empty()) - { - auto class_found = control_classes.find(class_id); - if (control_classes.end() != class_found) - { - auto& properties = class_found->second.properties.as_array(); - for (const auto& property : properties) - { - if (property_id == nmos::fields::nc::id(property)) - { - return property; - } - } - } - class_id.pop_back(); - } - - return value::null(); - } - - nmos::experimental::method find_method(const nc_method_id& method_id, const nc_class_id& class_id_, const nmos::experimental::control_classes& control_classes) - { - using web::json::value; - using web::json::value_of; - - // NcObject methods implementation - // Get property value - const auto get = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes&, slog::base_gate& gate) - { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - - const auto& property_id = nmos::fields::nc::id(arguments); - - slog::log(gate, SLOG_FLF) << "Get property: " << property_id.serialize(); - - // find the relevant nc_property_descriptor - const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); - if (!property.is_null()) - { - return make_control_protocol_response(handle, { nc_method_status::ok }, resource->data.at(nmos::fields::nc::name(property))); - } - - // unknown property - utility::stringstream_t ss; - ss << U("unknown property: ") << property_id.serialize() << U(" to do Get"); - return make_control_protocol_error_response(handle, { nc_method_status::property_not_implemented }, ss.str()); - }; - // Set property value - const auto set = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes&, slog::base_gate& gate) - { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - - const auto& property_id = nmos::fields::nc::id(arguments); - const auto& val = nmos::fields::nc::value(arguments); - - slog::log(gate, SLOG_FLF) << "Set property: " << property_id.serialize() << " value: " << val.serialize(); - - // find the relevant nc_property_descriptor - const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); - if (!property.is_null()) - { - if (nmos::fields::nc::is_read_only(property)) - { - return make_control_protocol_response(handle, { nc_method_status::read_only }); - } - - if ((val.is_null() && !nmos::fields::nc::is_nullable(property)) - || (val.is_array() && !nmos::fields::nc::is_sequence(property))) - { - return make_control_protocol_response(handle, { nc_method_status::parameter_error }); - } - - resources.modify(resource, [&](nmos::resource& resource) - { - resource.data[nmos::fields::nc::name(property)] = val; - - resource.updated = strictly_increasing_update(resources); - }); - return make_control_protocol_response(handle, { nc_method_status::ok }); - } - - // unknown property - utility::stringstream_t ss; - ss << U("unknown property: ") << property_id.serialize() << " to do Set"; - return make_control_protocol_error_response(handle, { nc_method_status::property_not_implemented }, ss.str()); - }; - // Get sequence item - const auto get_sequence_item = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes&, slog::base_gate& gate) - { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - - const auto& property_id = nmos::fields::nc::id(arguments); - const auto& index = nmos::fields::nc::index(arguments); - - slog::log(gate, SLOG_FLF) << "Get sequence item: " << property_id.serialize() << " index: " << index; - - // find the relevant nc_property_descriptor - const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); - if (!property.is_null()) - { - if (!nmos::fields::nc::is_sequence(property)) - { - // property is not a sequence - utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do GetSequenceItem"); - return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); - } - - auto& data = resource->data.at(nmos::fields::nc::name(property)); - - if (!data.is_null() && data.as_array().size() > (size_t)index) - { - return make_control_protocol_response(handle, { nc_method_status::ok }, data.at(index)); - } - - // out of bound - utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << U(" is outside the available range to do GetSequenceItem"); - return make_control_protocol_error_response(handle, { nc_method_status::index_out_of_bounds }, ss.str()); - } - - // unknown property - utility::stringstream_t ss; - ss << U("unknown property: ") << property_id.serialize() << U(" to do GetSequenceItem"); - return make_control_protocol_error_response(handle, { nc_method_status::property_not_implemented }, ss.str()); - }; - // Set sequence item - const auto set_sequence_item = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes&, slog::base_gate& gate) - { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - - const auto& property_id = nmos::fields::nc::id(arguments); - const auto& index = nmos::fields::nc::index(arguments); - const auto& val = nmos::fields::nc::value(arguments); - - slog::log(gate, SLOG_FLF) << "Set sequence item: " << property_id.serialize() << " index: " << index << " value: " << val.serialize(); - - // find the relevant nc_property_descriptor - const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); - if (!property.is_null()) - { - if (!nmos::fields::nc::is_sequence(property)) - { - // property is not a sequence - utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do SetSequenceItem"); - return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); - } - - auto& data = resource->data.at(nmos::fields::nc::name(property)); - - if (!data.is_null() && data.as_array().size() > (size_t)index) - { - resources.modify(resource, [&](nmos::resource& resource) - { - resource.data[nmos::fields::nc::name(property)][index] = val; - - resource.updated = strictly_increasing_update(resources); - }); - return make_control_protocol_response(handle, { nc_method_status::ok }); - } - - // out of bound - utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << U(" is outside the available range to do SetSequenceItem"); - return make_control_protocol_error_response(handle, { nc_method_status::index_out_of_bounds }, ss.str()); - } - - // unknown property - utility::stringstream_t ss; - ss << U("unknown property: ") << property_id.serialize() << U(" to do SetSequenceItem"); - return make_control_protocol_error_response(handle, { nc_method_status::property_not_implemented }, ss.str()); - }; - // Add item to sequence - const auto add_sequence_item = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes&, slog::base_gate& gate) - { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - - const auto& property_id = nmos::fields::nc::id(arguments); - const auto& val = nmos::fields::nc::value(arguments); - - slog::log(gate, SLOG_FLF) << "Add sequence item: " << property_id.serialize() << " value: " << val.serialize(); - - // find the relevant nc_property_descriptor - const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); - if (!property.is_null()) - { - if (!nmos::fields::nc::is_sequence(property)) - { - // property is not a sequence - utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do AddSequenceItem"); - return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); - } - - auto& data = resource->data.at(nmos::fields::nc::name(property)); - - resources.modify(resource, [&](nmos::resource& resource) - { - auto& sequence = resource.data[nmos::fields::nc::name(property)]; - if (data.is_null()) { sequence = value::array(); } - web::json::push_back(sequence, val); - - resource.updated = strictly_increasing_update(resources); - }); - return make_control_protocol_response(handle, { nc_method_status::ok }, uint32_t(data.as_array().size() - 1)); - } - - // unknown property - utility::stringstream_t ss; - ss << U("unknown property: ") << property_id.serialize() << U(" to do AddSequenceItem"); - return make_control_protocol_error_response(handle, { nc_method_status::property_not_implemented }, ss.str()); - }; - // Delete sequence item - const auto remove_sequence_item = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes&, slog::base_gate& gate) - { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - - const auto& property_id = nmos::fields::nc::id(arguments); - const auto& index = nmos::fields::nc::index(arguments); - - slog::log(gate, SLOG_FLF) << "Remove sequence item: " << property_id.serialize() << " index: " << index; - - // find the relevant nc_property_descriptor - const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); - if (!property.is_null()) - { - if (!nmos::fields::nc::is_sequence(property)) - { - // property is not a sequence - utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do RemoveSequenceItem"); - return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); - } - - auto& data = resource->data.at(nmos::fields::nc::name(property)); - - if (!data.is_null() && data.as_array().size() > (size_t)index) - { - resources.modify(resource, [&](nmos::resource& resource) - { - auto& sequence = resource.data[nmos::fields::nc::name(property)].as_array(); - sequence.erase(index); - - resource.updated = strictly_increasing_update(resources); - }); - return make_control_protocol_response(handle, { nc_method_status::ok }); - } - - // out of bound - utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << U(" is outside the available range to do RemoveSequenceItem"); - return make_control_protocol_error_response(handle, { nc_method_status::index_out_of_bounds }, ss.str()); - } - - // unknown property - utility::stringstream_t ss; - ss << U("unknown property: ") << property_id.serialize() << U(" to do RemoveSequenceItem"); - return make_control_protocol_error_response(handle, { nc_method_status::property_not_implemented }, ss.str()); - }; - // Get sequence length - const auto get_sequence_length = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes&, slog::base_gate& gate) - { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - - const auto& property_id = nmos::fields::nc::id(arguments); - - slog::log(gate, SLOG_FLF) << "Get sequence length: " << property_id.serialize(); - - // find the relevant nc_property_descriptor - const auto& property = find_property(property_id, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), control_classes); - if (!property.is_null()) - { - if (!nmos::fields::nc::is_sequence(property)) - { - // property is not a sequence - utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do GetSequenceLength"); - return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); - } - - auto& data = resource->data.at(nmos::fields::nc::name(property)); - - if (nmos::fields::nc::is_nullable(property)) - { - // can be null - if (data.is_null()) - { - // null - return make_control_protocol_response(handle, { nc_method_status::ok }, value::null()); - } - } - else - { - // cannot be null - if (data.is_null()) - { - // null - utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << " is a null sequence to do GetSequenceLength"; - return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); - } - } - return make_control_protocol_response(handle, { nc_method_status::ok }, uint32_t(data.as_array().size())); - } - - // unknown property - utility::stringstream_t ss; - ss << U("unknown property: ") << property_id.serialize() << " to do GetSequenceLength"; - return make_control_protocol_error_response(handle, { nc_method_status::property_not_implemented }, ss.str()); - }; - - // NcBlock methods implementation - // Get descriptors of members of the block - const auto get_member_descriptors = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes&, const nmos::experimental::datatypes&, slog::base_gate& gate) - { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - - const auto& recurse = nmos::fields::nc::recurse(arguments); // If recurse is set to true, nested members is to be retrieved - - slog::log(gate, SLOG_FLF) << "Get descriptors of members of the block: " << "recurse: " << recurse; - - auto descriptors = value::array(); - nmos::get_member_descriptors(resources, resource, recurse, descriptors.as_array()); - - return make_control_protocol_response(handle, { nc_method_status::ok }, descriptors); - }; - // Finds member(s) by path - const auto find_members_by_path = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes&, const nmos::experimental::datatypes&, slog::base_gate& gate) - { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - - // Relative path to search for (MUST not include the role of the block targeted by oid) - const auto& path = arguments.at(nmos::fields::nc::path); - - slog::log(gate, SLOG_FLF) << "Find member(s) by path: " << "path: " << path.serialize(); - - if (0 == path.size()) - { - // empty path - return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("empty path to do FindMembersByPath")); - } - - auto nc_block_member_descriptors = value::array(); - value nc_block_member_descriptor; - - for (const auto& role : path.as_array()) - { - // look for the role in members - if (resource->data.has_field(nmos::fields::nc::members)) - { - auto& members = nmos::fields::nc::members(resource->data); - auto member_found = std::find_if(members.begin(), members.end(), [&](const web::json::value& nc_block_member_descriptor) - { - return role.as_string() == nmos::fields::nc::role(nc_block_member_descriptor); - }); - - if (members.end() != member_found) - { - nc_block_member_descriptor = *member_found; - - // use oid to look for the next resource - resource = nmos::find_resource(resources, utility::s2us(std::to_string(nmos::fields::nc::oid(*member_found)))); - } - else - { - // no role - utility::stringstream_t ss; - ss << U("role: ") << role.as_string() << U(" not found to do FindMembersByPath"); - return make_control_protocol_error_response(handle, { nc_method_status::bad_oid }, ss.str()); - } - } - else - { - // no members - return make_control_protocol_error_response(handle, { nc_method_status::bad_oid }, U("no members to do FindMembersByPath")); - } - } - - web::json::push_back(nc_block_member_descriptors, nc_block_member_descriptor); - return make_control_protocol_response(handle, { nc_method_status::ok }, nc_block_member_descriptors); - }; - // Finds members with given role name or fragment - const auto find_members_by_role = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes&, const nmos::experimental::datatypes&, slog::base_gate& gate) - { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - - const auto& role = nmos::fields::nc::role(arguments); // Role text to search for - const auto& case_sensitive = nmos::fields::nc::case_sensitive(arguments); // Signals if the comparison should be case sensitive - const auto& match_whole_string = nmos::fields::nc::match_whole_string(arguments); // TRUE to only return exact matches - const auto& recurse = nmos::fields::nc::recurse(arguments); // TRUE to search nested blocks - - slog::log(gate, SLOG_FLF) << "Find members with given role name or fragment: " << "role: " << role; - - if (role.empty()) - { - // empty role - return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("empty role to do FindMembersByRole")); - } - - auto descriptors = value::array(); - nmos::find_members_by_role(resources, resource, role, match_whole_string, case_sensitive, recurse, descriptors.as_array()); - - return make_control_protocol_response(handle, { nc_method_status::ok }, descriptors); - }; - // Finds members with given class id - const auto find_members_by_class_id = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const value& arguments, const nmos::experimental::control_classes&, const nmos::experimental::datatypes&, slog::base_gate& gate) - { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - - const auto& class_id = parse_nc_class_id(nmos::fields::nc::class_id(arguments)); // Class id to search for - const auto& include_derived = nmos::fields::nc::include_derived(arguments); // If TRUE it will also include derived class descriptors - const auto& recurse = nmos::fields::nc::recurse(arguments); // TRUE to search nested blocks - - slog::log(gate, SLOG_FLF) << "Find members with given class id: " << "class_id: " << nmos::details::make_nc_class_id(class_id).serialize(); - - if (class_id.empty()) - { - // empty class_id - return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("empty classId to do FindMembersByClassId")); - } - - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - - auto descriptors = value::array(); - nmos::find_members_by_class_id(resources, resource, class_id, include_derived, recurse, descriptors.as_array()); - - return make_control_protocol_response(handle, { nc_method_status::ok }, descriptors); - }; - - // NcClassManager methods implementation - // Get a single class descriptor - const auto get_control_class = [](nmos::resources&, nmos::resources::iterator, int32_t handle, const value& arguments, const nmos::experimental::control_classes& control_classes, const nmos::experimental::datatypes&, slog::base_gate& gate) - { - const auto& class_id = parse_nc_class_id(nmos::fields::nc::class_id(arguments)); // Class id to search for - const auto& include_inherited = nmos::fields::nc::include_inherited(arguments); // If set the descriptor would contain all inherited elements - - slog::log(gate, SLOG_FLF) << "Get a single class descriptor: " << "class_id: " << nmos::details::make_nc_class_id(class_id).serialize(); - - if (class_id.empty()) - { - // empty class_id - return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("empty classId to do GetControlClass")); - } - - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - - auto class_found = control_classes.find(class_id); - - if (control_classes.end() != class_found) - { - auto id = class_id; - - auto& description = class_found->second.description; - auto& name = class_found->second.name; - auto& fixed_role = class_found->second.fixed_role; - auto properties = class_found->second.properties; - auto methods = class_found->second.methods; - auto events = class_found->second.events; - - id.pop_back(); - - if (include_inherited) - { - while (!id.empty()) - { - auto found = control_classes.find(id); - if (control_classes.end() != found) - { - for (const auto& property : found->second.properties.as_array()) { web::json::push_back(properties, property); } - for (const auto& method : found->second.methods.as_array()) { web::json::push_back(methods, method); } - for (const auto& event : found->second.events.as_array()) { web::json::push_back(events, event); } - } - id.pop_back(); - } - } - auto descriptor = details::make_nc_class_descriptor(description, class_id, name, fixed_role, properties, methods, events); - - return make_control_protocol_response(handle, { nc_method_status::ok }, descriptor); - } - - return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("classId not found")); - }; - // Get a single datatype descriptor - const auto get_datatype = [](nmos::resources&, nmos::resources::iterator, int32_t handle, const value& arguments, const nmos::experimental::control_classes&, const nmos::experimental::datatypes& datatypes, slog::base_gate& gate) - { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - - const auto& name = nmos::fields::nc::name(arguments); // name of datatype - const auto& include_inherited = nmos::fields::nc::include_inherited(arguments); // If set the descriptor would contain all inherited elements - - slog::log(gate, SLOG_FLF) << "Get a single datatype descriptor: " << "name: " << name; - - if (name.empty()) - { - // empty name - return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("empty name to do GetDatatype")); - } - - auto datatype_found = datatypes.find(name); - - if (datatypes.end() != datatype_found) - { - auto descriptor = datatype_found->second.descriptor; - - if (include_inherited) - { - const auto& type = nmos::fields::nc::type(descriptor); - if (nc_datatype_type::Struct == type) - { - auto descriptor_ = descriptor; - - for (;;) - { - const auto& parent_type = descriptor_.at(nmos::fields::nc::parent_type); - if (!parent_type.is_null()) - { - auto datatype_found_ = datatypes.find(parent_type.as_string()); - if (datatypes.end() != datatype_found_) - { - descriptor_ = datatype_found_->second.descriptor; - const auto& fields = nmos::fields::nc::fields(descriptor_); - for (const auto& field : fields) - { - web::json::push_back(descriptor.at(nmos::fields::nc::fields), field); - } - } - } - else - { - break; - } - } - } - } - - return make_control_protocol_response(handle, { nc_method_status::ok }, descriptor); - } - - return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("name not found")); - }; - - // method handlers for the different classes - nmos::experimental::methods nc_object_method_handlers; // method_id vs NcObject method_handler - nmos::experimental::methods nc_block_method_handlers; // method_id vs NcBlock method_handler - nmos::experimental::methods nc_worker_method_handlers; // method_id vs NcWorker method_handler - nmos::experimental::methods nc_manager_method_handlers; // method_id vs NcManager method_handler - nmos::experimental::methods nc_device_manager_method_handlers; // method_id vs NcDeviceManager method_handler - nmos::experimental::methods nc_class_manager_method_handlers; // method_id vs NcClassManager method_handler - - // NcObject methods - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject - nc_object_method_handlers[{1, 1}] = get; - nc_object_method_handlers[{1, 2}] = set; - nc_object_method_handlers[{1, 3}] = get_sequence_item; - nc_object_method_handlers[{1, 4}] = set_sequence_item; - nc_object_method_handlers[{1, 5}] = add_sequence_item; - nc_object_method_handlers[{1, 6}] = remove_sequence_item; - nc_object_method_handlers[{1, 7}] = get_sequence_length; - - // NcBlock methods - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock - nc_block_method_handlers[{2, 1}] = get_member_descriptors; - nc_block_method_handlers[{2, 2}] = find_members_by_path; - nc_block_method_handlers[{2, 3}] = find_members_by_role; - nc_block_method_handlers[{2, 4}] = find_members_by_class_id; - - // NcWorker has no extended method - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncworker - - // NcManager has no extended method - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanager - - // NcDeviceManger has no extended method - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager - - // NcClassManager methods - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager - nc_class_manager_method_handlers[{3, 1}] = get_control_class; - nc_class_manager_method_handlers[{3, 2}] = get_datatype; - - // class id vs method handlers - // hmm, todo, custom class and assoicated methods will need to be inserted within follwoing table! - const std::map methods = - { - { nc_object_class_id, nc_object_method_handlers }, - { nc_block_class_id, nc_block_method_handlers }, - { nc_class_manager_class_id, nc_class_manager_method_handlers } - }; - - auto class_id = class_id_; while (!class_id.empty()) @@ -660,15 +61,11 @@ namespace nmos { return method_found->second; } - else - { - //control_classes. - } } class_id.pop_back(); } - return NULL; + return nullptr; } } @@ -808,11 +205,13 @@ namespace nmos }; } - web::websockets::experimental::listener::message_handler make_control_protocol_ws_message_handler(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_classes_handler get_control_protocol_classes, nmos::get_control_protocol_datatypes_handler get_control_protocol_datatypes, slog::base_gate& gate_) + web::websockets::experimental::listener::message_handler make_control_protocol_ws_message_handler(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::get_control_protocol_methods_handler get_control_protocol_methods, slog::base_gate& gate_) { using web::json::value; - return [&model, &websockets, get_control_protocol_classes, get_control_protocol_datatypes, &gate_](const web::uri& connection_uri, const web::websockets::experimental::listener::connection_id& connection_id, const web::websockets::websocket_incoming_message& msg_) + auto methods = get_control_protocol_methods(); + + return [&model, &websockets, get_control_protocol_class, get_control_protocol_datatype, methods, &gate_](const web::uri& connection_uri, const web::websockets::experimental::listener::connection_id& connection_id, const web::websockets::websocket_incoming_message& msg_) { nmos::ws_api_gate gate(gate_, connection_uri); @@ -873,11 +272,11 @@ namespace nmos const auto& class_id = nmos::details::parse_nc_class_id(nmos::fields::nc::class_id(resource->data)); // find the relevent method handler to execute - auto method = details::find_method(method_id, class_id, get_control_protocol_classes()); + auto method = details::find_method(method_id, class_id, methods); if (method) { // execute the relevant method handler, then accumulating up their response to reponses - web::json::push_back(responses, method(resources, resource, handle, arguments, get_control_protocol_classes(), get_control_protocol_datatypes(), gate)); + web::json::push_back(responses, method(resources, resource, handle, arguments, get_control_protocol_class, get_control_protocol_datatype, gate)); } else { diff --git a/Development/nmos/control_protocol_ws_api.h b/Development/nmos/control_protocol_ws_api.h index 6f0494ae1..7fb79a520 100644 --- a/Development/nmos/control_protocol_ws_api.h +++ b/Development/nmos/control_protocol_ws_api.h @@ -16,15 +16,15 @@ namespace nmos web::websockets::experimental::listener::validate_handler make_control_protocol_ws_validate_handler(nmos::node_model& model, slog::base_gate& gate); web::websockets::experimental::listener::open_handler make_control_protocol_ws_open_handler(nmos::node_model& model, nmos::websockets& websockets, slog::base_gate& gate); web::websockets::experimental::listener::close_handler make_control_protocol_ws_close_handler(nmos::node_model& model, nmos::websockets& websockets, slog::base_gate& gate); - web::websockets::experimental::listener::message_handler make_control_protocol_ws_message_handler(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_classes_handler get_control_protocol_classes, nmos::get_control_protocol_datatypes_handler get_control_protocol_datatypes, slog::base_gate& gate); + web::websockets::experimental::listener::message_handler make_control_protocol_ws_message_handler(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::get_control_protocol_methods_handler get_control_protocol_methods, slog::base_gate& gate); - inline web::websockets::experimental::listener::websocket_listener_handlers make_control_protocol_ws_api(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_classes_handler get_control_protocol_classes, nmos::get_control_protocol_datatypes_handler get_control_protocol_datatypes, slog::base_gate& gate) + inline web::websockets::experimental::listener::websocket_listener_handlers make_control_protocol_ws_api(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::get_control_protocol_methods_handler get_control_protocol_methods, slog::base_gate& gate) { return{ nmos::make_control_protocol_ws_validate_handler(model, gate), nmos::make_control_protocol_ws_open_handler(model, websockets, gate), nmos::make_control_protocol_ws_close_handler(model, websockets, gate), - nmos::make_control_protocol_ws_message_handler(model, websockets, get_control_protocol_classes, get_control_protocol_datatypes, gate) + nmos::make_control_protocol_ws_message_handler(model, websockets, get_control_protocol_class, get_control_protocol_datatype, get_control_protocol_methods, gate) }; } diff --git a/Development/nmos/node_server.cpp b/Development/nmos/node_server.cpp index cf4c15054..ccc9d1e3f 100644 --- a/Development/nmos/node_server.cpp +++ b/Development/nmos/node_server.cpp @@ -75,7 +75,7 @@ namespace nmos { if (control_protocol_ws_port == events_ws_port) throw std::runtime_error("Same port used for events and control protocol websockets are not supported"); auto& control_protocol_ws_api = node_server.ws_handlers[{ {}, control_protocol_ws_port }]; - control_protocol_ws_api.first = nmos::make_control_protocol_ws_api(node_model, control_protocol_ws_api.second, node_implementation.get_control_protocol_classes, node_implementation.get_control_protocol_datatypes, gate); + control_protocol_ws_api.first = nmos::make_control_protocol_ws_api(node_model, control_protocol_ws_api.second, node_implementation.get_control_protocol_class, node_implementation.get_control_protocol_datatype, node_implementation.get_control_protocol_methods, gate); } // Set up the listeners for each HTTP API port diff --git a/Development/nmos/node_server.h b/Development/nmos/node_server.h index 4f897a8e0..95fdca058 100644 --- a/Development/nmos/node_server.h +++ b/Development/nmos/node_server.h @@ -25,7 +25,7 @@ namespace nmos // underlying implementation into the server instance for the NMOS Node struct node_implementation { - node_implementation(nmos::load_server_certificates_handler load_server_certificates, nmos::load_dh_param_handler load_dh_param, nmos::load_ca_certificates_handler load_ca_certificates, nmos::system_global_handler system_changed, nmos::registration_handler registration_changed, nmos::transport_file_parser parse_transport_file, nmos::details::connection_resource_patch_validator validate_staged, nmos::connection_resource_auto_resolver resolve_auto, nmos::connection_sender_transportfile_setter set_transportfile, nmos::connection_activation_handler connection_activated, nmos::ocsp_response_handler get_ocsp_response, nmos::get_control_protocol_classes_handler get_control_protocol_classes, nmos::get_control_protocol_datatypes_handler get_control_protocol_datatypes) + node_implementation(nmos::load_server_certificates_handler load_server_certificates, nmos::load_dh_param_handler load_dh_param, nmos::load_ca_certificates_handler load_ca_certificates, nmos::system_global_handler system_changed, nmos::registration_handler registration_changed, nmos::transport_file_parser parse_transport_file, nmos::details::connection_resource_patch_validator validate_staged, nmos::connection_resource_auto_resolver resolve_auto, nmos::connection_sender_transportfile_setter set_transportfile, nmos::connection_activation_handler connection_activated, nmos::ocsp_response_handler get_ocsp_response, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::get_control_protocol_methods_handler get_control_protocol_methods) : load_server_certificates(std::move(load_server_certificates)) , load_dh_param(std::move(load_dh_param)) , load_ca_certificates(std::move(load_ca_certificates)) @@ -37,8 +37,9 @@ namespace nmos , set_transportfile(std::move(set_transportfile)) , connection_activated(std::move(connection_activated)) , get_ocsp_response(std::move(get_ocsp_response)) - , get_control_protocol_classes(std::move(get_control_protocol_classes)) - , get_control_protocol_datatypes(std::move(get_control_protocol_datatypes)) + , get_control_protocol_class(std::move(get_control_protocol_class)) + , get_control_protocol_datatype(std::move(get_control_protocol_datatype)) + , get_control_protocol_methods(std::move(get_control_protocol_methods)) {} // use the default constructor and chaining member functions for fluent initialization @@ -60,8 +61,9 @@ namespace nmos node_implementation& on_validate_channelmapping_output_map(nmos::details::channelmapping_output_map_validator validate_map) { this->validate_map = std::move(validate_map); return *this; } node_implementation& on_channelmapping_activated(nmos::channelmapping_activation_handler channelmapping_activated) { this->channelmapping_activated = std::move(channelmapping_activated); return *this; } node_implementation& on_get_ocsp_response(nmos::ocsp_response_handler get_ocsp_response) { this->get_ocsp_response = std::move(get_ocsp_response); return *this; } - node_implementation& on_get_control_classes(nmos::get_control_protocol_classes_handler get_control_protocol_classes) { this->get_control_protocol_classes = std::move(get_control_protocol_classes); return* this; } - node_implementation& on_get_control_datatypes(nmos::get_control_protocol_datatypes_handler get_control_protocol_datatypes) { this->get_control_protocol_datatypes = std::move(get_control_protocol_datatypes); return*this; } + node_implementation& on_get_control_class(nmos::get_control_protocol_class_handler get_control_protocol_class) { this->get_control_protocol_class = std::move(get_control_protocol_class); return *this; } + node_implementation& on_get_control_datatype(nmos::get_control_protocol_datatype_handler get_control_protocol_datatype) { this->get_control_protocol_datatype = std::move(get_control_protocol_datatype); return *this; } + node_implementation& on_get_control_protocol_methods(nmos::get_control_protocol_methods_handler get_control_protocol_methods) { this->get_control_protocol_methods = std::move(get_control_protocol_methods); return *this; } // deprecated, use on_validate_connection_resource_patch node_implementation& on_validate_merged(nmos::details::connection_resource_patch_validator validate_merged) { return on_validate_connection_resource_patch(std::move(validate_merged)); } @@ -92,8 +94,9 @@ namespace nmos nmos::ocsp_response_handler get_ocsp_response; - nmos::get_control_protocol_classes_handler get_control_protocol_classes; - nmos::get_control_protocol_datatypes_handler get_control_protocol_datatypes; + nmos::get_control_protocol_class_handler get_control_protocol_class; + nmos::get_control_protocol_datatype_handler get_control_protocol_datatype; + nmos::get_control_protocol_methods_handler get_control_protocol_methods; }; // Construct a server instance for an NMOS Node, implementing the IS-04 Node API, IS-05 Connection API, IS-07 Events API From c581781dc57e11a388d42d711512e4af5a8d1246 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Thu, 31 Aug 2023 14:15:48 +0100 Subject: [PATCH 037/106] Fix 'nmos::experimental::control_class' constructor initialization --- Development/nmos/control_protocol_state.cpp | 14 +++++----- Development/nmos/control_protocol_state.h | 29 ++++++++++++++++----- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/Development/nmos/control_protocol_state.cpp b/Development/nmos/control_protocol_state.cpp index 7376a7ed0..ed18a4a4b 100644 --- a/Development/nmos/control_protocol_state.cpp +++ b/Development/nmos/control_protocol_state.cpp @@ -14,7 +14,7 @@ namespace nmos // properties: vector of NcPropertyDescriptor which can be constructed using make_control_class_property // methods: vector of NcMethodDescriptor which can be constructed using make_nc_method_descriptor and the assoicated method handler // events: vector of NcEventDescriptor can be constructed using make_nc_event_descriptor - control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const utility::string_t& name, const web::json::value& fixed_role, const std::vector& properties_, const std::vector>& methods_, const std::vector& events_) + control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const web::json::value& fixed_role, const std::vector& properties_, const std::vector>& methods_, const std::vector& events_) { using web::json::value; @@ -38,7 +38,7 @@ namespace nmos // properties: vector of NcPropertyDescriptor which can be constructed using make_control_class_property // methods: vector of NcMethodDescriptor which can be constructed using make_nc_method_descriptor and the assoicated method handler // events: vector of NcEventDescriptor can be constructed using make_nc_event_descriptor - control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const utility::string_t& name, const utility::string_t& fixed_role, const std::vector& properties, const std::vector>& methods, const std::vector& events) + control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const utility::string_t& fixed_role, const std::vector& properties, const std::vector>& methods, const std::vector& events) { using web::json::value; @@ -49,7 +49,7 @@ namespace nmos // properties: vector of NcPropertyDescriptor which can be constructed using make_control_class_property // methods: vector of NcMethodDescriptor which can be constructed using make_nc_method_descriptor and the assoicated method handler // events: vector of NcEventDescriptor can be constructed using make_nc_event_descriptor - control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const utility::string_t& name, const std::vector& properties, const std::vector>& methods, const std::vector& events) + control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const std::vector& properties, const std::vector>& methods, const std::vector& events) { using web::json::value; @@ -57,19 +57,19 @@ namespace nmos } // create control class property - web::json::value make_control_class_property(const utility::string_t& description, const nc_property_id& id, const utility::string_t& name, const utility::string_t& type_name, bool is_read_only, bool is_nullable, bool is_sequence, bool is_deprecated, const web::json::value& constraints) + web::json::value make_control_class_property(const utility::string_t& description, const nc_property_id& id, const nc_name& name, const utility::string_t& type_name, bool is_read_only, bool is_nullable, bool is_sequence, bool is_deprecated, const web::json::value& constraints) { return nmos::details::make_nc_property_descriptor(description, id, name, type_name, is_read_only, is_nullable, is_sequence, is_deprecated, constraints); } // create control class method parameter - web::json::value make_control_class_method_parameter(const utility::string_t& description, const utility::string_t& name, const utility::string_t& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints) + web::json::value make_control_class_method_parameter(const utility::string_t& description, const nc_name& name, const utility::string_t& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints) { return nmos::details::make_nc_parameter_descriptor(description, name, type_name, is_nullable, is_sequence, constraints); } // create control class method - web::json::value make_control_class_method(const utility::string_t& description, const nc_method_id& id, const utility::string_t& name, const utility::string_t& result_datatype, const std::vector& parameters_, bool is_deprecated) + web::json::value make_control_class_method(const utility::string_t& description, const nc_method_id& id, const nc_name& name, const utility::string_t& result_datatype, const std::vector& parameters_, bool is_deprecated) { using web::json::value; @@ -80,7 +80,7 @@ namespace nmos } // create control class event - web::json::value make_control_class_event(const utility::string_t& description, const nc_event_id& id, const utility::string_t& name, const utility::string_t& event_datatype, bool is_deprecated) + web::json::value make_control_class_event(const utility::string_t& description, const nc_event_id& id, const nc_name& name, const utility::string_t& event_datatype, bool is_deprecated) { return nmos::details::make_nc_event_descriptor(description, id, name, event_datatype, is_deprecated); } diff --git a/Development/nmos/control_protocol_state.h b/Development/nmos/control_protocol_state.h index 77b2571d7..319bf1319 100644 --- a/Development/nmos/control_protocol_state.h +++ b/Development/nmos/control_protocol_state.h @@ -17,7 +17,7 @@ namespace nmos { web::json::value description; nmos::nc_class_id class_id; - utility::string_t name; + nmos::nc_name name; web::json::value fixed_role; web::json::value properties = web::json::value::array(); // array of NcPropertyDescriptor @@ -25,6 +25,21 @@ namespace nmos web::json::value events = web::json::value::array(); // array of NcEventDescriptor nmos::experimental::methods method_handlers; // map of method handlers which are associated to this control_class (class_id), but not including its base class + + control_class() + : class_id({ 0 }) + {} + + control_class(web::json::value description, nmos::nc_class_id class_id, nmos::nc_name name, web::json::value fixed_role, web::json::value properties, web::json::value methods, web::json::value events, nmos::experimental::methods method_handlers) + : description(std::move(description)) + , class_id(std::move(class_id)) + , name(std::move(name)) + , fixed_role(std::move(fixed_role)) + , properties(std::move(properties)) + , methods(std::move(methods)) + , events(std::move(events)) + , method_handlers(std::move(method_handlers)) + {} }; struct datatype // NcDatatypeDescriptorEnum/NcDatatypeDescriptorPrimitive/NcDatatypeDescriptorStruct/NcDatatypeDescriptorTypeDef @@ -62,24 +77,24 @@ namespace nmos // helper functions to create non-standard control class // // create control class method parameter - web::json::value make_control_class_method_parameter(const utility::string_t& description, const utility::string_t& name, const utility::string_t& type_name, + web::json::value make_control_class_method_parameter(const utility::string_t& description, const nc_name& name, const utility::string_t& type_name, bool is_nullable = false, bool is_sequence = false, const web::json::value& constraints = web::json::value::null()); // create control class method - web::json::value make_control_class_method(const utility::string_t& description, const nc_method_id& id, const utility::string_t& name, const utility::string_t& result_datatype, + web::json::value make_control_class_method(const utility::string_t& description, const nc_method_id& id, const nc_name& name, const utility::string_t& result_datatype, const std::vector& parameters = {}, bool is_deprecated = false); // create control class event - web::json::value make_control_class_event(const utility::string_t& description, const nc_event_id& id, const utility::string_t& name, const utility::string_t& event_datatype, + web::json::value make_control_class_event(const utility::string_t& description, const nc_event_id& id, const nc_name& name, const utility::string_t& event_datatype, bool is_deprecated = false); // create control class property - web::json::value make_control_class_property(const utility::string_t& description, const nc_property_id& id, const utility::string_t& name, const utility::string_t& type_name, + web::json::value make_control_class_property(const utility::string_t& description, const nc_property_id& id, const nc_name& name, const utility::string_t& type_name, bool is_read_only = false, bool is_nullable = false, bool is_sequence = false, bool is_deprecated = false, const web::json::value& constraints = web::json::value::null()); // create control class with fixed role - control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const utility::string_t& name, const utility::string_t& fixed_role, const std::vector& properties, const std::vector>& methods, const std::vector& events); + control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const utility::string_t& fixed_role, const std::vector& properties, const std::vector>& methods, const std::vector& events); // create control class with no fixed role - control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const utility::string_t& name, const std::vector& properties, const std::vector>& methods, const std::vector& events); + control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const std::vector& properties, const std::vector>& methods, const std::vector& events); } } From 3b585069076fcd1db294ff98413e5b62d489ecae Mon Sep 17 00:00:00 2001 From: lo-simon Date: Thu, 7 Sep 2023 14:52:43 +0100 Subject: [PATCH 038/106] Fix indentation --- Development/nmos/control_protocol_methods.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Development/nmos/control_protocol_methods.cpp b/Development/nmos/control_protocol_methods.cpp index 8aec5aec1..10da83987 100644 --- a/Development/nmos/control_protocol_methods.cpp +++ b/Development/nmos/control_protocol_methods.cpp @@ -354,9 +354,9 @@ namespace nmos { auto& members = nmos::fields::nc::members(resource->data); auto member_found = std::find_if(members.begin(), members.end(), [&](const web::json::value& nc_block_member_descriptor) - { - return role.as_string() == nmos::fields::nc::role(nc_block_member_descriptor); - }); + { + return role.as_string() == nmos::fields::nc::role(nc_block_member_descriptor); + }); if (members.end() != member_found) { From 279358cb5cab208e175ba78fc536df44eda560d8 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Thu, 7 Sep 2023 16:36:48 +0100 Subject: [PATCH 039/106] Use better error instead of `out of bounds` --- Development/nmos/control_protocol_methods.cpp | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Development/nmos/control_protocol_methods.cpp b/Development/nmos/control_protocol_methods.cpp index 10da83987..4359f9fbe 100644 --- a/Development/nmos/control_protocol_methods.cpp +++ b/Development/nmos/control_protocol_methods.cpp @@ -88,7 +88,9 @@ namespace nmos const auto& property = find_property(parse_nc_property_id(property_id), parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), get_control_protocol_class); if (!property.is_null()) { - if (!nmos::fields::nc::is_sequence(property)) + auto& data = resource->data.at(nmos::fields::nc::name(property)); + + if (!nmos::fields::nc::is_sequence(property) || data.is_null() || !data.is_array()) { // property is not a sequence utility::stringstream_t ss; @@ -96,9 +98,7 @@ namespace nmos return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); } - auto& data = resource->data.at(nmos::fields::nc::name(property)); - - if (!data.is_null() && data.as_array().size() > (size_t)index) + if (data.as_array().size() > (size_t)index) { return make_control_protocol_response(handle, { nc_method_status::ok }, data.at(index)); } @@ -130,7 +130,9 @@ namespace nmos const auto& property = find_property(parse_nc_property_id(property_id), parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), get_control_protocol_class); if (!property.is_null()) { - if (!nmos::fields::nc::is_sequence(property)) + auto& data = resource->data.at(nmos::fields::nc::name(property)); + + if (!nmos::fields::nc::is_sequence(property) || data.is_null() || !data.is_array()) { // property is not a sequence utility::stringstream_t ss; @@ -138,9 +140,7 @@ namespace nmos return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); } - auto& data = resource->data.at(nmos::fields::nc::name(property)); - - if (!data.is_null() && data.as_array().size() > (size_t)index) + if (data.as_array().size() > (size_t)index) { resources.modify(resource, [&](nmos::resource& resource) { @@ -220,7 +220,9 @@ namespace nmos const auto& property = find_property(parse_nc_property_id(property_id), parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), get_control_protocol_class); if (!property.is_null()) { - if (!nmos::fields::nc::is_sequence(property)) + auto& data = resource->data.at(nmos::fields::nc::name(property)); + + if (!nmos::fields::nc::is_sequence(property) || data.is_null() || !data.is_array()) { // property is not a sequence utility::stringstream_t ss; @@ -228,9 +230,7 @@ namespace nmos return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); } - auto& data = resource->data.at(nmos::fields::nc::name(property)); - - if (!data.is_null() && data.as_array().size() > (size_t)index) + if (data.as_array().size() > (size_t)index) { resources.modify(resource, [&](nmos::resource& resource) { From 431b4a8459e8d8959dfa48be3d9bd9e3d88e02f3 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 12 Sep 2023 10:23:10 +0100 Subject: [PATCH 040/106] Add non-standard Example class based on nmos-device-control-mock --- .../nmos-cpp-node/node_implementation.cpp | 239 ++++++++++++++++-- 1 file changed, 222 insertions(+), 17 deletions(-) diff --git a/Development/nmos-cpp-node/node_implementation.cpp b/Development/nmos-cpp-node/node_implementation.cpp index aa4ab3324..279387d07 100644 --- a/Development/nmos-cpp-node/node_implementation.cpp +++ b/Development/nmos-cpp-node/node_implementation.cpp @@ -909,31 +909,216 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr // example to create a non-standard Gain control class const auto gain_control_class_id = nmos::make_nc_class_id(nmos::nc_worker_class_id, 0, { 1 }); const web::json::field_as_number gain_value{ U("gainValue") }; - // Gain control class properties - std::vector gain_control_properties = { nmos::experimental::make_control_class_property(U("Gain value"), { 3, 1 }, gain_value, U("NcFloat32")) }; - // Gain control class method example - auto example_method = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) { - slog::log(gate, SLOG_FLF) << "Executing the example method"; - return nmos::make_control_protocol_response(handle, { nmos::nc_method_status::ok }); - }; - // Gain control class methods - std::vector> gain_control_methods = - { - { nmos::experimental::make_control_class_method(U("This is an example method"), {3, 1}, U("ExampleMethod"), U("NcMethodResult"), {}, false), example_method } - }; - // create Gain control class - auto gain_control_class = nmos::experimental::make_control_class(U("Gain control class descriptor"), gain_control_class_id, U("GainControl"), gain_control_properties, gain_control_methods, {}); - // insert Gain control class to global state, which will be used by the control_protocol_ws_message_handler to process incoming ws message - control_protocol_state.insert(gain_control_class); - // helper function to create Gain control instance + // Gain control class properties + std::vector gain_control_properties = { nmos::experimental::make_control_class_property(U("Gain value"), { 3, 1 }, gain_value, U("NcFloat32")) }; + + // create Gain control class + auto gain_control_class = nmos::experimental::make_control_class(U("Gain control class descriptor"), gain_control_class_id, U("GainControl"), gain_control_properties); + + // insert Gain control class to global state, which will be used by the control_protocol_ws_message_handler to process incoming ws message + control_protocol_state.insert(gain_control_class); + } + // helper function to create Gain control auto make_gain_control = [&gain_value, &gain_control_class_id](nmos::nc_oid oid, nmos::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, float gain = 0.0, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null()) { auto data = nmos::details::make_nc_worker(gain_control_class_id, oid, true, owner, role, value::string(user_label), touchpoints, runtime_property_constraints, true); data[gain_value] = value::number(gain); + return nmos::resource{ nmos::is12_versions::v1_0, nmos::types::nc_worker, std::move(data), true }; }; + // example to create a non-standard Example control class + const auto example_control_class_id = nmos::make_nc_class_id(nmos::nc_worker_class_id, 0, { 2 }); + const web::json::field_as_number enum_property{ U("enumProperty") }; + const web::json::field_as_string string_property{ U("stringProperty") }; + const web::json::field_as_number number_property{ U("numberProperty") }; + const web::json::field_as_bool boolean_property{ U("booleanProperty") }; + const web::json::field_as_value object_property{ U("objectProperty") }; + const web::json::field_as_number method_no_args_count{ U("methodNoArgsCount") }; + const web::json::field_as_number method_simple_args_count{ U("methodSimpleArgsCount") }; + const web::json::field_as_number method_object_arg_count{ U("methodObjectArgCount") }; + const web::json::field_as_array string_sequence{ U("stringSequence") }; + const web::json::field_as_array boolean_sequence{ U("booleanSequence") }; + const web::json::field_as_array enum_sequence{ U("enumSequence") }; + const web::json::field_as_array number_sequence{ U("numberSequence") }; + const web::json::field_as_array object_sequence{ U("objectSequence") }; + const web::json::field_as_number enum_arg{ U("enumArg") }; + const web::json::field_as_string string_arg{ U("stringArg") }; + const web::json::field_as_number number_arg{ U("numberArg") }; + const web::json::field_as_bool boolean_arg{ U("booleanArg") }; + const web::json::field_as_bool obj_arg{ U("objArg") }; + enum example_enum + { + Undefined = 0, + Alpha = 1, + Beta = 2, + Gamma = 3 + }; + + { + // Example control class properties + std::vector example_control_properties = { + nmos::experimental::make_control_class_property(U("Example enum property"), { 3, 1 }, enum_property, U("ExampleEnum")), + // todo constraints + nmos::experimental::make_control_class_property(U("Example string property"), { 3, 2 }, string_property, U("NcString"), false, false, false, false, value::null()), + // todo constraints + nmos::experimental::make_control_class_property(U("Example numeric property"), { 3, 3 }, number_property, U("NcUint64"), false, false, false, false, value::null()), + nmos::experimental::make_control_class_property(U("Example boolean property"), { 3, 4 }, boolean_property, U("NcBoolean")), + nmos::experimental::make_control_class_property(U("Example object property"), { 3, 5 }, object_property, U("ExampleDataType")), + nmos::experimental::make_control_class_property(U("Method no args invoke counter"), { 3, 6 }, method_no_args_count, U("NcUint64"), true), + nmos::experimental::make_control_class_property(U("Method simple args invoke counter"), { 3, 7 }, method_simple_args_count, U("NcUint64"), true), + nmos::experimental::make_control_class_property(U("Method obj arg invoke counter"), { 3, 8 }, method_object_arg_count, U("NcUint64"), true), + nmos::experimental::make_control_class_property(U("Example string sequence property"), { 3, 9 }, string_sequence, U("NcString"), false, false, true), + nmos::experimental::make_control_class_property(U("Example boolean sequence property"), { 3, 10 }, boolean_sequence, U("NcBoolean"), false, false, true), + nmos::experimental::make_control_class_property(U("Example enum sequence property"), { 3, 11 }, enum_sequence, U("ExampleEnum"), false, false, true), + nmos::experimental::make_control_class_property(U("Example number sequence property"), { 3, 12 }, number_sequence, U("NcUint64"), false, false, true), + nmos::experimental::make_control_class_property(U("Example object sequence property"), { 3, 13 }, object_sequence, U("ExampleDataType"), false, false, true) + }; + + // Example control class method handlers + auto example_method_with_no_args = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) + { + slog::log(gate, SLOG_FLF) << "Executing the example method with no arguments"; + return nmos::make_control_protocol_response(handle, { nmos::nc_method_status::ok }); + }; + auto example_method_with_simple_args = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) + { + slog::log(gate, SLOG_FLF) << "Executing the example method with simple arguments"; + return nmos::make_control_protocol_response(handle, { nmos::nc_method_status::ok }); + }; + auto example_method_with_object_args = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) + { + slog::log(gate, SLOG_FLF) << "Executing the example method with object arguments"; + return nmos::make_control_protocol_response(handle, { nmos::nc_method_status::ok }); + }; + // Example control class methods + std::vector> example_control_methods = + { + { nmos::experimental::make_control_class_method(U("Example method with no arguments"), { 3, 1 }, U("MethodNoArgs"), U("NcMethodResult"), {}, false), example_method_with_no_args }, + { nmos::experimental::make_control_class_method(U("Example method with simple arguments"), { 3, 2 }, U("MethodSimpleArgs"), U("NcMethodResult"), + { + nmos::details::make_nc_parameter_descriptor(U("Enum example argument"), enum_arg, U("ExampleEnum"), false, false, value::null()), + nmos::details::make_nc_parameter_descriptor(U("String example argument"), string_arg, U("NcString"), false, false, value::null()), // todo constraints + nmos::details::make_nc_parameter_descriptor(U("Number example argument"), number_arg, U("NcUint64"), false, false, value::null()), // todo constraints + nmos::details::make_nc_parameter_descriptor(U("Boolean example argument"), boolean_arg, U("NcBoolean"), false, false, value::null()) + }, + false), example_method_with_simple_args + }, + { nmos::experimental::make_control_class_method(U("Example method with object argument"), { 3, 3 }, U("MethodObjectArg"), U("NcMethodResult"), + { + nmos::details::make_nc_parameter_descriptor(U("Object example argument"), obj_arg, U("ExampleDataType"), false, false, value::null()) + }, + false), example_method_with_object_args + } + }; + + // create Example control class + auto example_control_class = nmos::experimental::make_control_class(U("Example control class descriptor"), example_control_class_id, U("ExampleControl"), example_control_properties, example_control_methods); + + // insert Example control class to global state, which will be used by the control_protocol_ws_message_handler to process incoming ws message + control_protocol_state.insert(example_control_class); + + // create/insert Example datatypes to global state, which will be used by the control_protocol_ws_message_handler to process incoming ws message + auto make_example_enum_datatype = [&]() + { + using web::json::value; + + auto items = value::array(); + web::json::push_back(items, nmos::details::make_nc_enum_item_descriptor(value::string(U("Undefined")), U("Undefined"), example_enum::Undefined)); + web::json::push_back(items, nmos::details::make_nc_enum_item_descriptor(value::string(U("Alphan")), U("Alpha"), example_enum::Alpha)); + web::json::push_back(items, nmos::details::make_nc_enum_item_descriptor(value::string(U("Beta")), U("Beta"), example_enum::Beta)); + web::json::push_back(items, nmos::details::make_nc_enum_item_descriptor(value::string(U("Gamma")), U("Gamma"), example_enum::Gamma)); + return nmos::details::make_nc_datatype_descriptor_enum(value::string(U("Example enum datatype")), U("ExampleEnum"), items); + }; + auto make_example_datatype_datatype = [&]() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, nmos::details::make_nc_field_descriptor(value::string(U("Enum property example")), enum_property, value::string(U("ExampleEnum")), false, false)); + { + value constraints = value::null(); // todo constraints + web::json::push_back(fields, nmos::details::make_nc_field_descriptor(value::string(U("String property example")), string_property, value::string(U("NcString")), false, false, constraints)); + } + { + value constraints = value::null(); // todo constraints + web::json::push_back(fields, nmos::details::make_nc_field_descriptor(value::string(U("Number property example")), number_property, value::string(U("NcUint64")), false, false, constraints)); + } + web::json::push_back(fields, nmos::details::make_nc_field_descriptor(value::string(U("Boolean property example")), boolean_property, value::string(U("NcBoolean")), false, false)); + return nmos::details::make_nc_datatype_descriptor_struct(value::string(U("Example data type")), U("ExampleDataType"), fields, value::null()); + }; + control_protocol_state.insert(nmos::experimental::datatype{ make_example_enum_datatype() }); + control_protocol_state.insert(nmos::experimental::datatype{ make_example_datatype_datatype() }); + } + // helper function to create Example datatype + auto make_example_datatype = [&](example_enum enum_property_, const utility::string_t& string_property_, uint64_t number_property_, bool boolean_property_) + { + using web::json::value_of; + + return web::json::value_of({ + { enum_property, enum_property_ }, + { string_property, string_property_ }, + { number_property, number_property_ }, + { boolean_property, boolean_property_ } + }); + }; + // helper function to create Example control + auto make_example_control = [&](nmos::nc_oid oid, nmos::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, + example_enum enum_property_ = example_enum::Undefined, + const utility::string_t& string_property_ = U(""), + uint64_t number_property_ = 0, + bool boolean_property_ = true, + const value& object_property_ = value::null(), + uint64_t method_no_args_count_ = 0, + uint64_t method_simple_args_count_ = 0, + uint64_t method_object_arg_count_ = 0, + std::vector string_sequence_ = {}, + std::vector boolean_sequence_ = {}, + std::vector enum_sequence_ = {}, + std::vector number_sequence_ = {}, + std::vector object_sequence_ = {}, + const value& touchpoints = value::null(), const value& runtime_property_constraints = value::null()) + { + auto data = nmos::details::make_nc_worker(example_control_class_id, oid, true, owner, role, value::string(user_label), touchpoints, runtime_property_constraints, true); + data[enum_property] = value::number(enum_property_); + data[string_property] = value::string(string_property_); + data[number_property] = value::number(number_property_); + data[boolean_property] = value::boolean(boolean_property_); + data[object_property] = object_property_; + data[method_no_args_count] = value::number(method_no_args_count_); + data[method_simple_args_count] = value::number(method_simple_args_count_); + data[method_object_arg_count] = value::number(method_object_arg_count_); + { + value sequence; + for (const auto& value_ : string_sequence_) { web::json::push_back(sequence, value::string(value_)); } + data[string_sequence] = sequence; + } + { + value sequence; + for (const auto& value_ : boolean_sequence_) { web::json::push_back(sequence, value::boolean(value_)); } + data[boolean_sequence] = sequence; + } + { + value sequence; + for (const auto& value_ : enum_sequence_) { web::json::push_back(sequence, value_); } + data[enum_sequence] = sequence; + } + { + value sequence; + for (const auto& value_ : number_sequence_) { web::json::push_back(sequence, value_); } + data[number_sequence] = sequence; + } + { + value sequence; + for (const auto& value_ : object_sequence_) { web::json::push_back(sequence, value_); } + data[object_sequence] = sequence; + } + + return nmos::resource{ nmos::is12_versions::v1_0, nmos::types::nc_worker, std::move(data), true }; + }; + + // example root block auto root_block = nmos::make_root_block(); @@ -965,6 +1150,25 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr nmos::add_member(U("Master gain block"), master_gain, stereo_gain); nmos::add_member(U("Channel gain block"), channel_gain, stereo_gain); + // example example-control + auto example_control = make_example_control(++oid, nmos::root_block_oid, U("ExampleControl"), U("Example control worker"), + example_enum::Undefined, + U("test"), + 3, + false, + make_example_datatype(example_enum::Undefined, U("default"), 5, false), + 0, + 0, + 0, + { U("red"), U("blue"), U("green") }, + { true, false }, + { example_enum::Alpha, example_enum::Gamma }, + { 0, 50, 80 }, + { make_example_datatype(example_enum::Alpha, U("example"), 50, false), make_example_datatype(example_enum::Gamma, U("different"), 75, true) } + ); + + // add example-control to root-block + nmos::add_member(U("Example control worker"), example_control, root_block); // add stereo-gain to root-block nmos::add_member(U("Stereo gain block"), stereo_gain, root_block); // add class-manager to root-block @@ -973,6 +1177,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr nmos::add_member(U("The device manager offers information about the product this device is representing"), device_manager, root_block); // insert resources to model + if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(example_control), gate)) throw node_implementation_init_exception(); if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(left_gain), gate)) throw node_implementation_init_exception(); if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(right_gain), gate)) throw node_implementation_init_exception(); if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(master_gain), gate)) throw node_implementation_init_exception(); From 0b87a783fef9ffc8b1bd1df8f03bea2cd0be02ee Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 12 Sep 2023 10:24:38 +0100 Subject: [PATCH 041/106] Update log messages --- Development/nmos/control_protocol_handlers.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Development/nmos/control_protocol_handlers.cpp b/Development/nmos/control_protocol_handlers.cpp index 73fa4fa8e..2c3fdac56 100644 --- a/Development/nmos/control_protocol_handlers.cpp +++ b/Development/nmos/control_protocol_handlers.cpp @@ -10,7 +10,7 @@ namespace nmos { return [&](const nc_class_id& class_id) { - slog::log(gate, SLOG_FLF) << "Retrieve control class of class_id: " << nmos::details::make_nc_class_id(class_id).serialize() << " from cache"; + slog::log(gate, SLOG_FLF) << "Retrieve control protocol control class of class_id: " << nmos::details::make_nc_class_id(class_id).serialize() << " from cache"; auto lock = control_protocol_state.read_lock(); @@ -28,7 +28,7 @@ namespace nmos { return [&](const nc_class_id& class_id, const experimental::control_class& control_class) { - slog::log(gate, SLOG_FLF) << "Add control class to cache"; + slog::log(gate, SLOG_FLF) << "Add control protocol control class to cache"; auto lock = control_protocol_state.write_lock(); @@ -47,7 +47,7 @@ namespace nmos { return [&](const nmos::nc_name& name) { - slog::log(gate, SLOG_FLF) << "Retrieve datatype of name: " << name << " from cache"; + slog::log(gate, SLOG_FLF) << "Retrieve control protocol datatype of name: " << name << " from cache"; auto lock = control_protocol_state.read_lock(); @@ -64,7 +64,7 @@ namespace nmos { return [&]() { - slog::log(gate, SLOG_FLF) << "Retrieve all method handlers from cache"; + slog::log(gate, SLOG_FLF) << "Retrieve all control protocol method handlers from cache"; std::map methods; From d8a803ff3ab579796d4a23979503b6037ecf09ae Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 12 Sep 2023 10:25:58 +0100 Subject: [PATCH 042/106] Fix is_nc_block() --- Development/nmos/control_protocol_utils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Development/nmos/control_protocol_utils.cpp b/Development/nmos/control_protocol_utils.cpp index 0bc6a9f24..de9e00713 100644 --- a/Development/nmos/control_protocol_utils.cpp +++ b/Development/nmos/control_protocol_utils.cpp @@ -28,7 +28,7 @@ namespace nmos // is the given class_id a NcBlock bool is_nc_block(const nc_class_id& class_id) { - return details::is_control_class(nc_object_class_id, class_id); + return details::is_control_class(nc_block_class_id, class_id); } // is the given class_id a NcManager From 9e1fdc832347598d7f41686c83af976b5a804e33 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 12 Sep 2023 10:27:33 +0100 Subject: [PATCH 043/106] Tidy-up function signatures --- Development/nmos/control_protocol_state.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Development/nmos/control_protocol_state.h b/Development/nmos/control_protocol_state.h index 319bf1319..3be439b23 100644 --- a/Development/nmos/control_protocol_state.h +++ b/Development/nmos/control_protocol_state.h @@ -92,9 +92,9 @@ namespace nmos bool is_read_only = false, bool is_nullable = false, bool is_sequence = false, bool is_deprecated = false, const web::json::value& constraints = web::json::value::null()); // create control class with fixed role - control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const utility::string_t& fixed_role, const std::vector& properties, const std::vector>& methods, const std::vector& events); + control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const utility::string_t& fixed_role, const std::vector& properties = {}, const std::vector>& methods = {}, const std::vector& events = {}); // create control class with no fixed role - control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const std::vector& properties, const std::vector>& methods, const std::vector& events); + control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const std::vector& properties = {}, const std::vector>& methods = {}, const std::vector& events = {}); } } From 8b4d0d1dff71c6de865062d05d0aef90e8c07210 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Fri, 15 Sep 2023 15:19:49 +0100 Subject: [PATCH 044/106] Add subscription support --- .../nmos-cpp-node/node_implementation.cpp | 14 +- Development/nmos/api_utils.cpp | 6 +- Development/nmos/control_protocol_methods.cpp | 78 ++++---- .../nmos/control_protocol_resource.cpp | 173 +++++++++++------- Development/nmos/control_protocol_resource.h | 23 ++- .../nmos/control_protocol_resources.cpp | 62 ++++++- Development/nmos/control_protocol_resources.h | 14 +- Development/nmos/control_protocol_state.cpp | 26 +-- Development/nmos/control_protocol_typedefs.h | 128 ++++++++++++- Development/nmos/control_protocol_ws_api.cpp | 56 ++++-- Development/nmos/json_fields.h | 34 ++-- Development/nmos/query_utils.cpp | 44 +++++ Development/nmos/query_utils.h | 3 + Development/nmos/type.h | 12 +- 14 files changed, 493 insertions(+), 180 deletions(-) diff --git a/Development/nmos-cpp-node/node_implementation.cpp b/Development/nmos-cpp-node/node_implementation.cpp index 279387d07..8039782f9 100644 --- a/Development/nmos-cpp-node/node_implementation.cpp +++ b/Development/nmos-cpp-node/node_implementation.cpp @@ -925,7 +925,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr auto data = nmos::details::make_nc_worker(gain_control_class_id, oid, true, owner, role, value::string(user_label), touchpoints, runtime_property_constraints, true); data[gain_value] = value::number(gain); - return nmos::resource{ nmos::is12_versions::v1_0, nmos::types::nc_worker, std::move(data), true }; + return nmos::resource{ nmos::is12_versions::v1_0, nmos::types::nc_object, std::move(data), true }; }; // example to create a non-standard Example control class @@ -980,17 +980,17 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr auto example_method_with_no_args = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) { slog::log(gate, SLOG_FLF) << "Executing the example method with no arguments"; - return nmos::make_control_protocol_response(handle, { nmos::nc_method_status::ok }); + return nmos::make_control_protocol_message_response(handle, { nmos::nc_method_status::ok }); }; auto example_method_with_simple_args = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) { slog::log(gate, SLOG_FLF) << "Executing the example method with simple arguments"; - return nmos::make_control_protocol_response(handle, { nmos::nc_method_status::ok }); + return nmos::make_control_protocol_message_response(handle, { nmos::nc_method_status::ok }); }; auto example_method_with_object_args = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) { slog::log(gate, SLOG_FLF) << "Executing the example method with object arguments"; - return nmos::make_control_protocol_response(handle, { nmos::nc_method_status::ok }); + return nmos::make_control_protocol_message_response(handle, { nmos::nc_method_status::ok }); }; // Example control class methods std::vector> example_control_methods = @@ -1026,7 +1026,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr auto items = value::array(); web::json::push_back(items, nmos::details::make_nc_enum_item_descriptor(value::string(U("Undefined")), U("Undefined"), example_enum::Undefined)); - web::json::push_back(items, nmos::details::make_nc_enum_item_descriptor(value::string(U("Alphan")), U("Alpha"), example_enum::Alpha)); + web::json::push_back(items, nmos::details::make_nc_enum_item_descriptor(value::string(U("Alpha")), U("Alpha"), example_enum::Alpha)); web::json::push_back(items, nmos::details::make_nc_enum_item_descriptor(value::string(U("Beta")), U("Beta"), example_enum::Beta)); web::json::push_back(items, nmos::details::make_nc_enum_item_descriptor(value::string(U("Gamma")), U("Gamma"), example_enum::Gamma)); return nmos::details::make_nc_datatype_descriptor_enum(value::string(U("Example enum datatype")), U("ExampleEnum"), items); @@ -1115,7 +1115,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr data[object_sequence] = sequence; } - return nmos::resource{ nmos::is12_versions::v1_0, nmos::types::nc_worker, std::move(data), true }; + return nmos::resource{ nmos::is12_versions::v1_0, nmos::types::nc_object, std::move(data), true }; }; @@ -1204,6 +1204,7 @@ void node_implementation_run(nmos::node_model& model, slog::base_gate& gate) std::shared_ptr events_engine(new std::default_random_engine(events_seeder)); auto cancellation_source = pplx::cancellation_token_source(); + auto token = cancellation_source.get_token(); auto events = pplx::do_while([&model, seed_id, how_many, ws_sender_ports, events_engine, &gate, token] { @@ -1263,6 +1264,7 @@ void node_implementation_run(nmos::node_model& model, slog::base_gate& gate) cancellation_source.cancel(); // wait without the lock since it is also used by the background tasks nmos::details::reverse_lock_guard unlock{ lock }; + events.wait(); } diff --git a/Development/nmos/api_utils.cpp b/Development/nmos/api_utils.cpp index bf352c77c..69d38c5ae 100644 --- a/Development/nmos/api_utils.cpp +++ b/Development/nmos/api_utils.cpp @@ -156,7 +156,8 @@ namespace nmos { U("receivers"), nmos::types::receiver }, { U("subscriptions"), nmos::types::subscription }, { U("inputs"), nmos::types::input }, - { U("outputs"), nmos::types::output } + { U("outputs"), nmos::types::output }, + { U("nc_object"), nmos::types::nc_object } }; return types_from_resourceType.at(resourceType); } @@ -175,7 +176,8 @@ namespace nmos { nmos::types::subscription, U("subscriptions") }, { nmos::types::grain, {} }, // subscription websocket grains aren't exposed via the Query API { nmos::types::input, U("inputs") }, - { nmos::types::output, U("outputs") } + { nmos::types::output, U("outputs") }, + { nmos::types::nc_object, U("nc_object") } }; return resourceTypes_from_type.at(type); } diff --git a/Development/nmos/control_protocol_methods.cpp b/Development/nmos/control_protocol_methods.cpp index 4359f9fbe..200f8768a 100644 --- a/Development/nmos/control_protocol_methods.cpp +++ b/Development/nmos/control_protocol_methods.cpp @@ -2,6 +2,7 @@ #include "cpprest/json_utils.h" #include "nmos/control_protocol_resource.h" +#include "nmos/control_protocol_resources.h" #include "nmos/control_protocol_state.h" #include "nmos/control_protocol_utils.h" #include "nmos/json_fields.h" @@ -25,7 +26,7 @@ namespace nmos const auto& property = find_property(parse_nc_property_id(property_id), parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), get_control_protocol_class); if (!property.is_null()) { - return make_control_protocol_response(handle, { nc_method_status::ok }, resource->data.at(nmos::fields::nc::name(property))); + return make_control_protocol_message_response(handle, { nc_method_status::ok }, resource->data.at(nmos::fields::nc::name(property))); } // unknown property @@ -50,22 +51,25 @@ namespace nmos { if (nmos::fields::nc::is_read_only(property)) { - return make_control_protocol_response(handle, { nc_method_status::read_only }); + return make_control_protocol_message_response(handle, { nc_method_status::read_only }); } if ((val.is_null() && !nmos::fields::nc::is_nullable(property)) || (val.is_array() && !nmos::fields::nc::is_sequence(property))) { - return make_control_protocol_response(handle, { nc_method_status::parameter_error }); + return make_control_protocol_message_response(handle, { nc_method_status::parameter_error }); } - resources.modify(resource, [&](nmos::resource& resource) + const auto notification = make_control_protocol_notification(nmos::fields::nc::oid(resource->data), nc_object_property_changed_event_id, { parse_nc_property_id(property_id), nc_property_change_type::type::value_changed, val }); + const auto notification_event = make_control_protocol_notification(web::json::value_of({ notification })); + + modify_control_protocol_resource(resources, resource->id, [&](nmos::resource& resource) { resource.data[nmos::fields::nc::name(property)] = val; - resource.updated = strictly_increasing_update(resources); - }); - return make_control_protocol_response(handle, { nc_method_status::ok }); + }, notification_event); + + return make_control_protocol_message_response(handle, { nc_method_status::ok }); } // unknown property @@ -100,7 +104,7 @@ namespace nmos if (data.as_array().size() > (size_t)index) { - return make_control_protocol_response(handle, { nc_method_status::ok }, data.at(index)); + return make_control_protocol_message_response(handle, { nc_method_status::ok }, data.at(index)); } // out of bound @@ -142,13 +146,16 @@ namespace nmos if (data.as_array().size() > (size_t)index) { - resources.modify(resource, [&](nmos::resource& resource) + const auto notification = make_control_protocol_notification(nmos::fields::nc::oid(resource->data), nc_object_property_changed_event_id, { parse_nc_property_id(property_id), nc_property_change_type::type::sequence_item_changed, val, nc_id(index) }); + const auto notification_event = make_control_protocol_notification(web::json::value_of({ notification })); + + modify_control_protocol_resource(resources, resource->id, [&](nmos::resource& resource) { resource.data[nmos::fields::nc::name(property)][index] = val; - resource.updated = strictly_increasing_update(resources); - }); - return make_control_protocol_response(handle, { nc_method_status::ok }); + }, notification_event); + + return make_control_protocol_message_response(handle, { nc_method_status::ok }); } // out of bound @@ -189,15 +196,19 @@ namespace nmos auto& data = resource->data.at(nmos::fields::nc::name(property)); - resources.modify(resource, [&](nmos::resource& resource) + const nc_id sequence_item_index = data.is_null() ? 0 : nc_id(data.as_array().size()); + const auto notification = make_control_protocol_notification(nmos::fields::nc::oid(resource->data), nc_object_property_changed_event_id, { parse_nc_property_id(property_id), nc_property_change_type::type::sequence_item_added, val, sequence_item_index }); + const auto notification_event = make_control_protocol_notification(web::json::value_of({ notification })); + + modify_control_protocol_resource(resources, resource->id, [&](nmos::resource& resource) { auto& sequence = resource.data[nmos::fields::nc::name(property)]; if (data.is_null()) { sequence = value::array(); } web::json::push_back(sequence, val); - resource.updated = strictly_increasing_update(resources); - }); - return make_control_protocol_response(handle, { nc_method_status::ok }, uint32_t(data.as_array().size() - 1)); + }, notification_event); + + return make_control_protocol_message_response(handle, { nc_method_status::ok }, sequence_item_index); } // unknown property @@ -232,14 +243,17 @@ namespace nmos if (data.as_array().size() > (size_t)index) { - resources.modify(resource, [&](nmos::resource& resource) + const auto notification = make_control_protocol_notification(nmos::fields::nc::oid(resource->data), nc_object_property_changed_event_id, { parse_nc_property_id(property_id), nc_property_change_type::type::sequence_item_removed, data.as_array().at(index), nc_id(index)}); + const auto notification_event = make_control_protocol_notification(web::json::value_of({ notification })); + + modify_control_protocol_resource(resources, resource->id, [&](nmos::resource& resource) { auto& sequence = resource.data[nmos::fields::nc::name(property)].as_array(); sequence.erase(index); - resource.updated = strictly_increasing_update(resources); - }); - return make_control_protocol_response(handle, { nc_method_status::ok }); + }, notification_event); + + return make_control_protocol_message_response(handle, { nc_method_status::ok }); } // out of bound @@ -285,7 +299,7 @@ namespace nmos if (data.is_null()) { // null - return make_control_protocol_response(handle, { nc_method_status::ok }, value::null()); + return make_control_protocol_message_response(handle, { nc_method_status::ok }, value::null()); } } else @@ -299,7 +313,7 @@ namespace nmos return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); } } - return make_control_protocol_response(handle, { nc_method_status::ok }, uint32_t(data.as_array().size())); + return make_control_protocol_message_response(handle, { nc_method_status::ok }, uint32_t(data.as_array().size())); } // unknown property @@ -323,7 +337,7 @@ namespace nmos auto descriptors = value::array(); nmos::get_member_descriptors(resources, resource, recurse, descriptors.as_array()); - return make_control_protocol_response(handle, { nc_method_status::ok }, descriptors); + return make_control_protocol_message_response(handle, { nc_method_status::ok }, descriptors); } // Finds member(s) by path @@ -344,8 +358,8 @@ namespace nmos return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("empty path to do FindMembersByPath")); } - auto nc_block_member_descriptors = value::array(); - value nc_block_member_descriptor; + auto descriptors = value::array(); + value descriptor; for (const auto& role : path.as_array()) { @@ -360,7 +374,7 @@ namespace nmos if (members.end() != member_found) { - nc_block_member_descriptor = *member_found; + descriptor = *member_found; // use oid to look for the next resource resource = nmos::find_resource(resources, utility::s2us(std::to_string(nmos::fields::nc::oid(*member_found)))); @@ -380,8 +394,8 @@ namespace nmos } } - web::json::push_back(nc_block_member_descriptors, nc_block_member_descriptor); - return make_control_protocol_response(handle, { nc_method_status::ok }, nc_block_member_descriptors); + web::json::push_back(descriptors, descriptor); + return make_control_protocol_message_response(handle, { nc_method_status::ok }, descriptors); } // Finds members with given role name or fragment @@ -407,7 +421,7 @@ namespace nmos auto descriptors = value::array(); nmos::find_members_by_role(resources, resource, role, match_whole_string, case_sensitive, recurse, descriptors.as_array()); - return make_control_protocol_response(handle, { nc_method_status::ok }, descriptors); + return make_control_protocol_message_response(handle, { nc_method_status::ok }, descriptors); } // Finds members with given class id @@ -434,7 +448,7 @@ namespace nmos auto descriptors = value::array(); nmos::find_members_by_class_id(resources, resource, class_id, include_derived, recurse, descriptors.as_array()); - return make_control_protocol_response(handle, { nc_method_status::ok }, descriptors); + return make_control_protocol_message_response(handle, { nc_method_status::ok }, descriptors); } // NcClassManager methods implementation @@ -482,7 +496,7 @@ namespace nmos } auto descriptor = details::make_nc_class_descriptor(description, class_id, name, fixed_role, properties, methods, events); - return make_control_protocol_response(handle, { nc_method_status::ok }, descriptor); + return make_control_protocol_message_response(handle, { nc_method_status::ok }, descriptor); } return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("classId not found")); @@ -541,7 +555,7 @@ namespace nmos } } - return make_control_protocol_response(handle, { nc_method_status::ok }, descriptor); + return make_control_protocol_message_response(handle, { nc_method_status::ok }, descriptor); } return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("name not found")); diff --git a/Development/nmos/control_protocol_resource.cpp b/Development/nmos/control_protocol_resource.cpp index 5cc1ec3eb..1a9f89507 100644 --- a/Development/nmos/control_protocol_resource.cpp +++ b/Development/nmos/control_protocol_resource.cpp @@ -507,68 +507,111 @@ namespace nmos return data; } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncpropertychangedeventdata + web::json::value make_nc_property_changed_event_data(const nc_property_changed_event_data& property_changed_event_data) + { + using web::json::value_of; + + return value_of({ + { nmos::fields::nc::property_id, details::make_nc_property_id(property_changed_event_data.property_id) }, + { nmos::fields::nc::change_type, property_changed_event_data.change_type }, + { nmos::fields::nc::value, property_changed_event_data.value }, + { nmos::fields::nc::sequence_item_index, property_changed_event_data.sequence_item_index } + }); + } } // message response - // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#command-message-type - web::json::value make_control_protocol_message_response(nc_message_type::type type, const web::json::value& responses) + // See https://specs.amwa.tv/is-12/branches/v1.0.x/docs/Protocol_messaging.html#command-response-message-type + web::json::value make_control_protocol_error_response(int32_t handle, const nc_method_result& method_result, const utility::string_t& error_message) { using web::json::value_of; return value_of({ - { nmos::fields::nc::message_type, type }, - { nmos::fields::nc::responses, responses } + { nmos::fields::nc::handle, handle }, + { nmos::fields::nc::result, details::make_nc_method_result_error(method_result, error_message) } }); } + web::json::value make_control_protocol_message_response(int32_t handle, const nc_method_result& method_result) + { + using web::json::value_of; - // error message - // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#error-messages - web::json::value make_control_protocol_error_message(const nc_method_result& method_result, const utility::string_t& error_message) + return value_of({ + { nmos::fields::nc::handle, handle }, + { nmos::fields::nc::result, details::make_nc_method_result(method_result) } + }); + } + web::json::value make_control_protocol_message_response(int32_t handle, const nc_method_result& method_result, const web::json::value& value) { using web::json::value_of; return value_of({ - { nmos::fields::nc::message_type, nc_message_type::error }, - { nmos::fields::nc::status, method_result.status}, - { nmos::fields::nc::error_message, error_message } + { nmos::fields::nc::handle, handle }, + { nmos::fields::nc::result, details::make_nc_method_result(method_result, value) } }); } + web::json::value make_control_protocol_message_response(int32_t handle, const nc_method_result& method_result, uint32_t value_) + { + using web::json::value; - web::json::value make_control_protocol_error_response(int32_t handle, const nc_method_result& method_result, const utility::string_t& error_message) + return make_control_protocol_message_response(handle, method_result, value(value_)); + } + web::json::value make_control_protocol_message_response(const web::json::value& responses) { using web::json::value_of; return value_of({ - { nmos::fields::nc::handle, handle }, - { nmos::fields::nc::result, details::make_nc_method_result_error(method_result, error_message) } + { nmos::fields::nc::message_type, nc_message_type::command_response }, + { nmos::fields::nc::responses, responses } }); } - web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result) + // subscription response + // See https://specs.amwa.tv/is-12/branches/v1.0.x/docs/Protocol_messaging.html#subscription-response-message-type + web::json::value make_control_protocol_subscription_response(const web::json::value& subscriptions) { using web::json::value_of; return value_of({ - { nmos::fields::nc::handle, handle }, - { nmos::fields::nc::result, details::make_nc_method_result(method_result) } + { nmos::fields::nc::message_type, nc_message_type::subscription_response }, + { nmos::fields::nc::subscriptions, subscriptions } }); } - web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result, const web::json::value& value) + // notification + // See https://specs.amwa.tv/is-12/branches/v1.0.x/docs/Protocol_messaging.html#notification-message-type + web::json::value make_control_protocol_notification(nc_oid oid, const nc_event_id& event_id, const nc_property_changed_event_data& property_changed_event_data) { using web::json::value_of; return value_of({ - { nmos::fields::nc::handle, handle }, - { nmos::fields::nc::result, details::make_nc_method_result(method_result, value) } + { nmos::fields::nc::oid, oid }, + { nmos::fields::nc::event_id, details::make_nc_event_id(event_id)}, + { nmos::fields::nc::event_data, details::make_nc_property_changed_event_data(property_changed_event_data) } }); } + web::json::value make_control_protocol_notification(const web::json::value& notifications) + { + using web::json::value_of; - web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result, uint32_t value_) + return value_of({ + { nmos::fields::nc::message_type, nc_message_type::notification }, + { nmos::fields::nc::notifications, notifications } + }); + } + + // error message + // See https://specs.amwa.tv/is-12/branches/v1.0.x/docs/Protocol_messaging.html#error-messages + web::json::value make_control_protocol_error_message(const nc_method_result& method_result, const utility::string_t& error_message) { - using web::json::value; + using web::json::value_of; - return make_control_protocol_response(handle, method_result, value(value_)); + return value_of({ + { nmos::fields::nc::message_type, nc_message_type::error }, + { nmos::fields::nc::status, method_result.status}, + { nmos::fields::nc::error_message, error_message } + }); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject @@ -577,14 +620,14 @@ namespace nmos using web::json::value; auto properties = value::array(); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Static value. All instances of the same class will have the same identity value"), { 1, 1 }, nmos::fields::nc::class_id, U("NcClassId"), true, false, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Object identifier"), { 1, 2 }, nmos::fields::nc::oid, U("NcOid"), true, false, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("TRUE iff OID is hardwired into device"), { 1, 3 }, nmos::fields::nc::constant_oid, U("NcBoolean"), true, false, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("OID of containing block. Can only ever be null for the root block"), { 1, 4 }, nmos::fields::nc::owner, U("NcOid"), true, true, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Role of object in the containing block"), { 1, 5 }, nmos::fields::nc::role, U("NcString"), true, false, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Scribble strip"), { 1, 6 }, nmos::fields::nc::user_label, U("NcString"), false, true, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Touchpoints to other contexts"), { 1, 7 }, nmos::fields::nc::touchpoints, U("NcTouchpoint"), true, true, true, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Runtime property constraints"), { 1, 8 }, nmos::fields::nc::runtime_property_constraints, U("NcPropertyConstraints"), true, true, true, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Static value. All instances of the same class will have the same identity value"), nc_object_class_id_property_id, nmos::fields::nc::class_id, U("NcClassId"), true, false, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Object identifier"), nc_object_oid_property_id, nmos::fields::nc::oid, U("NcOid"), true, false, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("TRUE iff OID is hardwired into device"), nc_object_constant_oid_property_id, nmos::fields::nc::constant_oid, U("NcBoolean"), true, false, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("OID of containing block. Can only ever be null for the root block"), nc_object_owner_property_id, nmos::fields::nc::owner, U("NcOid"), true, true, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Role of object in the containing block"), nc_object_role_property_id, nmos::fields::nc::role, U("NcString"), true, false, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Scribble strip"), nc_object_user_label_property_id, nmos::fields::nc::user_label, U("NcString"), false, true, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Touchpoints to other contexts"), nc_object_touchpoints_property_id, nmos::fields::nc::touchpoints, U("NcTouchpoint"), true, true, true, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Runtime property constraints"), nc_object_runtime_property_constraints_property_id, nmos::fields::nc::runtime_property_constraints, U("NcPropertyConstraints"), true, true, true, false)); return properties; } @@ -596,43 +639,43 @@ namespace nmos { auto parameters = value::array(); web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Property id"), nmos::fields::nc::id, U("NcPropertyId"), false, false, value::null())); - web::json::push_back(methods, details::make_nc_method_descriptor(U("Get property value"), { 1, 1 }, U("Get"), U("NcMethodResultPropertyValue"), parameters, false)); + web::json::push_back(methods, details::make_nc_method_descriptor(U("Get property value"), nc_object_get_method_id, U("Get"), U("NcMethodResultPropertyValue"), parameters, false)); } { auto parameters = value::array(); web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Property id"), nmos::fields::nc::id, U("NcPropertyId"), false, false, value::null())); web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Property value"), nmos::fields::nc::value, true, false)); - web::json::push_back(methods, details::make_nc_method_descriptor(U("Set property value"), { 1, 2 }, U("Set"), U("NcMethodResult"), parameters, false)); + web::json::push_back(methods, details::make_nc_method_descriptor(U("Set property value"), nc_object_set_method_id, U("Set"), U("NcMethodResult"), parameters, false)); } { auto parameters = value::array(); web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Property id"), nmos::fields::nc::id, U("NcPropertyId"), false, false, value::null())); web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Index of item in the sequence"), nmos::fields::nc::index, U("NcId"), false, false, value::null())); - web::json::push_back(methods, details::make_nc_method_descriptor(U("Get sequence item"), { 1, 3 }, U("GetSequenceItem"), U("NcMethodResultPropertyValue"), parameters, false)); + web::json::push_back(methods, details::make_nc_method_descriptor(U("Get sequence item"), nc_object_get_sequence_item_method_id, U("GetSequenceItem"), U("NcMethodResultPropertyValue"), parameters, false)); } { auto parameters = value::array(); web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Property id"), nmos::fields::nc::id, U("NcPropertyId"), false, false, value::null())); web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Index of item in the sequence"), nmos::fields::nc::index, U("NcId"), false, false, value::null())); web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Value"), nmos::fields::nc::value, true, false)); - web::json::push_back(methods, details::make_nc_method_descriptor(U("Set sequence item value"), { 1, 4 }, U("SetSequenceItem"), U("NcMethodResult"), parameters, false)); + web::json::push_back(methods, details::make_nc_method_descriptor(U("Set sequence item value"), nc_object_set_sequence_item_method_id, U("SetSequenceItem"), U("NcMethodResult"), parameters, false)); } { auto parameters = value::array(); web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Property id"), nmos::fields::nc::id,U("NcPropertyId"), false, false, value::null())); web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Value"), nmos::fields::nc::value, true, false)); - web::json::push_back(methods, details::make_nc_method_descriptor(U("Add item to sequence"), { 1, 5 }, U("AddSequenceItem"), U("NcMethodResultId"), parameters, false)); + web::json::push_back(methods, details::make_nc_method_descriptor(U("Add item to sequence"), nc_object_add_sequence_item_method_id, U("AddSequenceItem"), U("NcMethodResultId"), parameters, false)); } { auto parameters = value::array(); web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Property id"), nmos::fields::nc::id, U("NcPropertyId"), false, false, value::null())); web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Index of item in the sequence"), nmos::fields::nc::index, U("NcId"), false, false, value::null())); - web::json::push_back(methods, details::make_nc_method_descriptor(U("Delete sequence item"), { 1, 6 }, U("RemoveSequenceItem"), U("NcMethodResult"), parameters, false)); + web::json::push_back(methods, details::make_nc_method_descriptor(U("Delete sequence item"), nc_object_remove_sequence_item_method_id, U("RemoveSequenceItem"), U("NcMethodResult"), parameters, false)); } { auto parameters = value::array(); web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Property id"), nmos::fields::nc::id, U("NcPropertyId"), false, false, value::null())); - web::json::push_back(methods, details::make_nc_method_descriptor(U("Get sequence length"), { 1, 7 }, U("GetSequenceLength"), U("NcMethodResultLength"), parameters, false)); + web::json::push_back(methods, details::make_nc_method_descriptor(U("Get sequence length"), nc_object_get_sequence_length_method_id, U("GetSequenceLength"), U("NcMethodResultLength"), parameters, false)); } return methods; @@ -642,7 +685,7 @@ namespace nmos using web::json::value; auto events = value::array(); - web::json::push_back(events, details::make_nc_event_descriptor(U("Property changed event"), { 1, 1 }, U("PropertyChanged"), U("NcPropertyChangedEventData"), false)); + web::json::push_back(events, details::make_nc_event_descriptor(U("Property changed event"), nc_object_property_changed_event_id, U("PropertyChanged"), U("NcPropertyChangedEventData"), false)); return events; } @@ -653,8 +696,8 @@ namespace nmos using web::json::value; auto properties = value::array(); - web::json::push_back(properties, details::make_nc_property_descriptor(U("TRUE if block is functional"), { 2, 1 }, nmos::fields::nc::enabled, U("NcBoolean"), true, false, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Descriptors of this block's members"), { 2, 2 }, nmos::fields::nc::members, U("NcBlockMemberDescriptor"), true, false, true, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("TRUE if block is functional"), nc_block_enabled_property_id, nmos::fields::nc::enabled, U("NcBoolean"), true, false, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Descriptors of this block's members"), nc_block_members_property_id, nmos::fields::nc::members, U("NcBlockMemberDescriptor"), true, false, true, false)); return properties; } @@ -666,12 +709,12 @@ namespace nmos { auto parameters = value::array(); web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("If recurse is set to true, nested members can be retrieved"), nmos::fields::nc::recurse, U("NcBoolean"), false, false, value::null())); - web::json::push_back(methods, details::make_nc_method_descriptor(U("Gets descriptors of members of the block"), { 2, 1 }, U("GetMemberDescriptors"), U("NcMethodResultBlockMemberDescriptors"), parameters, false)); + web::json::push_back(methods, details::make_nc_method_descriptor(U("Gets descriptors of members of the block"), nc_block_get_member_descriptors_method_id, U("GetMemberDescriptors"), U("NcMethodResultBlockMemberDescriptors"), parameters, false)); } { auto parameters = value::array(); web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Relative path to search for (MUST not include the role of the block targeted by oid)"), nmos::fields::nc::path, U("NcRolePath"), false, false, value::null())); - web::json::push_back(methods, details::make_nc_method_descriptor(U("Finds member(s) by path"), { 2, 2 }, U("FindMembersByPath"), U("NcMethodResultBlockMemberDescriptors"), parameters, false)); + web::json::push_back(methods, details::make_nc_method_descriptor(U("Finds member(s) by path"), nc_block_find_members_by_path_method_id, U("FindMembersByPath"), U("NcMethodResultBlockMemberDescriptors"), parameters, false)); } { auto parameters = value::array(); @@ -679,14 +722,14 @@ namespace nmos web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Signals if the comparison should be case sensitive"), nmos::fields::nc::case_sensitive, U("NcBoolean"), false, false, value::null())); web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("TRUE to only return exact matches"), nmos::fields::nc::match_whole_string, U("NcBoolean"), false, false, value::null())); web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("TRUE to search nested blocks"), nmos::fields::nc::recurse, U("NcBoolean"), false, false, value::null())); - web::json::push_back(methods, details::make_nc_method_descriptor(U("Finds members with given role name or fragment"), { 2, 3 }, U("FindMembersByRole"), U("NcMethodResultBlockMemberDescriptors"), parameters, false)); + web::json::push_back(methods, details::make_nc_method_descriptor(U("Finds members with given role name or fragment"), nc_block_find_members_by_role_method_id, U("FindMembersByRole"), U("NcMethodResultBlockMemberDescriptors"), parameters, false)); } { auto parameters = value::array(); web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Class id to search for"), nmos::fields::nc::class_id, U("NcClassId"), false, false, value::null())); web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("If TRUE it will also include derived class descriptors"), nmos::fields::nc::include_derived, U("NcBoolean"), false, false, value::null())); web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("TRUE to search nested blocks"), nmos::fields::nc::recurse,U("NcBoolean"), false, false, value::null())); - web::json::push_back(methods, details::make_nc_method_descriptor(U("Finds members with given class id"), { 2, 4 }, U("FindMembersByClassId"), U("NcMethodResultBlockMemberDescriptors"), parameters, false)); + web::json::push_back(methods, details::make_nc_method_descriptor(U("Finds members with given class id"), nc_block_find_members_by_class_id_method_id, U("FindMembersByClassId"), U("NcMethodResultBlockMemberDescriptors"), parameters, false)); } return methods; @@ -704,7 +747,7 @@ namespace nmos using web::json::value; auto properties = value::array(); - web::json::push_back(properties, details::make_nc_property_descriptor(U("TRUE iff worker is enabled"), { 2, 1 }, nmos::fields::nc::enabled, U("NcBoolean"), false, false, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("TRUE iff worker is enabled"), nc_worker_enabled_property_id, nmos::fields::nc::enabled, U("NcBoolean"), false, false, false, false)); return properties; } @@ -747,16 +790,16 @@ namespace nmos using web::json::value; auto properties = value::array(); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Version of MS-05-02 that this device uses"), { 3, 1 }, nmos::fields::nc::nc_version, U("NcVersionCode"), true, false, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Manufacturer descriptor"), { 3, 2 }, nmos::fields::nc::manufacturer, U("NcManufacturer"), true, false, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Product descriptor"), { 3, 3 }, nmos::fields::nc::product, U("NcProduct"), true, false, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Serial number"), { 3, 4 }, nmos::fields::nc::serial_number, U("NcString"), true, false, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Asset tracking identifier (user specified)"), { 3, 5 }, nmos::fields::nc::user_inventory_code, U("NcString"), false, true, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Name of this device in the application. Instance name, not product name"), { 3, 6 }, nmos::fields::nc::device_name, U("NcString"), false, true, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Role of this device in the application"), { 3, 7 }, nmos::fields::nc::device_role, U("NcString"), false, true, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Device operational state"), { 3, 8 }, nmos::fields::nc::operational_state, U("NcDeviceOperationalState"), true, false, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Reason for most recent reset"), { 3, 9 }, nmos::fields::nc::reset_cause, U("NcResetCause"), true, false, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Arbitrary message from dev to controller"), { 3, 10 }, nmos::fields::nc::message, U("NcString"), true, true, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Version of MS-05-02 that this device uses"), nc_device_manager_nc_version_property_id, nmos::fields::nc::nc_version, U("NcVersionCode"), true, false, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Manufacturer descriptor"), nc_device_manager_manufacturer_property_id, nmos::fields::nc::manufacturer, U("NcManufacturer"), true, false, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Product descriptor"), nc_device_manager_product_property_id, nmos::fields::nc::product, U("NcProduct"), true, false, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Serial number"), nc_device_manager_serial_number_property_id, nmos::fields::nc::serial_number, U("NcString"), true, false, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Asset tracking identifier (user specified)"), nc_device_manager_user_inventory_code_property_id, nmos::fields::nc::user_inventory_code, U("NcString"), false, true, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Name of this device in the application. Instance name, not product name"), nc_device_manager_device_name_property_id, nmos::fields::nc::device_name, U("NcString"), false, true, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Role of this device in the application"), nc_device_manager_device_role_property_id, nmos::fields::nc::device_role, U("NcString"), false, true, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Device operational state"), nc_device_manager_operational_state_property_id, nmos::fields::nc::operational_state, U("NcDeviceOperationalState"), true, false, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Reason for most recent reset"), nc_device_manager_reset_cause_property_id, nmos::fields::nc::reset_cause, U("NcResetCause"), true, false, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Arbitrary message from dev to controller"), nc_device_manager_message_property_id, nmos::fields::nc::message, U("NcString"), true, true, false, false)); return properties; } @@ -779,8 +822,8 @@ namespace nmos using web::json::value; auto properties = value::array(); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Descriptions of all control classes in the device (descriptors do not contain inherited elements)"), { 3, 1 }, nmos::fields::nc::control_classes, U("NcClassDescriptor"), true, false, true, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Descriptions of all data types in the device (descriptors do not contain inherited elements)"), { 3, 2 }, nmos::fields::nc::datatypes, U("NcDatatypeDescriptor"), true, false, true, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Descriptions of all control classes in the device (descriptors do not contain inherited elements)"), nc_class_manager_control_classes_property_id, nmos::fields::nc::control_classes, U("NcClassDescriptor"), true, false, true, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Descriptions of all data types in the device (descriptors do not contain inherited elements)"), nc_class_manager_datatypes_property_id, nmos::fields::nc::datatypes, U("NcDatatypeDescriptor"), true, false, true, false)); return properties; } @@ -793,13 +836,13 @@ namespace nmos auto parameters = value::array(); web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("class ID"), nmos::fields::nc::class_id, U("NcClassId"), false, false, value::null())); web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("If set the descriptor would contain all inherited elements"), nmos::fields::nc::include_inherited, U("NcBoolean"), false, false, value::null())); - web::json::push_back(methods, details::make_nc_method_descriptor(U("Get a single class descriptor"), { 3, 1 }, U("GetControlClass"), U("NcMethodResultClassDescriptor"), parameters, false)); + web::json::push_back(methods, details::make_nc_method_descriptor(U("Get a single class descriptor"), nc_class_manager_get_control_class_method_id, U("GetControlClass"), U("NcMethodResultClassDescriptor"), parameters, false)); } { auto parameters = value::array(); web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("name of datatype"), nmos::fields::nc::name, U("NcName"), false, false, value::null())); web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("If set the descriptor would contain all inherited elements"), nmos::fields::nc::include_inherited, U("NcBoolean"), false, false, value::null())); - web::json::push_back(methods, details::make_nc_method_descriptor(U("Get a single datatype descriptor"), { 3, 2 }, U("GetDatatype"), U("NcMethodResultDatatypeDescriptor"), parameters, false)); + web::json::push_back(methods, details::make_nc_method_descriptor(U("Get a single datatype descriptor"), nc_class_manager_get_datatype_method_id, U("GetDatatype"), U("NcMethodResultDatatypeDescriptor"), parameters, false)); } return methods; @@ -817,10 +860,10 @@ namespace nmos using web::json::value; auto properties = value::array(); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Connection status property"), { 3, 1 }, nmos::fields::nc::connection_status, U("NcConnectionStatus"), true, false, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Connection status message property"), { 3, 2 }, nmos::fields::nc::connection_status_message, U("NcString"), true, true, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Payload status property"), { 3, 3 }, nmos::fields::nc::payload_status, U("NcPayloadStatus"), true, false, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Payload status message property"), { 3, 4 }, nmos::fields::nc::payload_status_message, U("NcString"), true, true, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Connection status property"), nc_receiver_monitor_connection_status_property_id, nmos::fields::nc::connection_status, U("NcConnectionStatus"), true, false, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Connection status message property"), nc_receiver_monitor_connection_status_message_property_id, nmos::fields::nc::connection_status_message, U("NcString"), true, true, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Payload status property"), nc_receiver_monitor_payload_status_property_id, nmos::fields::nc::payload_status, U("NcPayloadStatus"), true, false, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Payload status message property"), nc_receiver_monitor_payload_status_message_property_id, nmos::fields::nc::payload_status_message, U("NcString"), true, true, false, false)); return properties; } @@ -843,7 +886,7 @@ namespace nmos using web::json::value; auto properties = value::array(); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Indicates if signal protection is active"), { 4, 1 }, nmos::fields::nc::signal_protection_status, U("NcBoolean"), true, false, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Indicates if signal protection is active"), nc_receiver_monitor_protected_signal_protection_status_property_id, nmos::fields::nc::signal_protection_status, U("NcBoolean"), true, false, false, false)); return properties; } @@ -866,7 +909,7 @@ namespace nmos using web::json::value; auto properties = value::array(); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Indicator active state"), { 3, 1 }, nmos::fields::nc::active, U("NcBoolean"), false, false, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Indicator active state"), nc_ident_beacon_active_property_id, nmos::fields::nc::active, U("NcBoolean"), false, false, false, false)); return properties; } diff --git a/Development/nmos/control_protocol_resource.h b/Development/nmos/control_protocol_resource.h index 648b654be..f40234977 100644 --- a/Development/nmos/control_protocol_resource.h +++ b/Development/nmos/control_protocol_resource.h @@ -165,19 +165,26 @@ namespace nmos } // message response - // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#command-message-type - web::json::value make_control_protocol_message_response(nc_message_type::type type, const web::json::value& responses); + // See https://specs.amwa.tv/is-12/branches/v1.0.x/docs/Protocol_messaging.html#command-response-message-type + web::json::value make_control_protocol_error_response(int32_t handle, const nc_method_result& method_result, const utility::string_t& error_message); + web::json::value make_control_protocol_message_response(int32_t handle, const nc_method_result& method_result); + web::json::value make_control_protocol_message_response(int32_t handle, const nc_method_result& method_result, const web::json::value& value); // value can be sequence, NcClassDescriptor, NcDatatypeDescriptor + web::json::value make_control_protocol_message_response(int32_t handle, const nc_method_result& method_result, uint32_t value); + web::json::value make_control_protocol_message_response(const web::json::value& responses); + + // subscription response + // See https://specs.amwa.tv/is-12/branches/v1.0.x/docs/Protocol_messaging.html#subscription-response-message-type + web::json::value make_control_protocol_subscription_response(const web::json::value& subscriptions); + + // notification + // See https://specs.amwa.tv/is-12/branches/v1.0.x/docs/Protocol_messaging.html#notification-message-type + web::json::value make_control_protocol_notification(nc_oid oid, const nc_event_id& event_id, const nc_property_changed_event_data& property_changed_event_data); + web::json::value make_control_protocol_notification(const web::json::value& notifications); // error message // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#error-messages web::json::value make_control_protocol_error_message(const nc_method_result& method_result, const utility::string_t& error_message); - // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#command-response-message-type - web::json::value make_control_protocol_error_response(int32_t handle, const nc_method_result& method_result, const utility::string_t& error_message); - web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result); - web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result, const web::json::value& value); // value can be sequence, NcClassDescriptor, NcDatatypeDescriptor - web::json::value make_control_protocol_response(int32_t handle, const nc_method_result& method_result, uint32_t value); - // Control class models // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/#control-class-models-for-branch-v10-dev // diff --git a/Development/nmos/control_protocol_resources.cpp b/Development/nmos/control_protocol_resources.cpp index e3a5c5f5a..48b6e7d1f 100644 --- a/Development/nmos/control_protocol_resources.cpp +++ b/Development/nmos/control_protocol_resources.cpp @@ -2,6 +2,7 @@ #include "nmos/control_protocol_resource.h" #include "nmos/control_protocol_utils.h" +#include "nmos/query_utils.h" #include "nmos/resource.h" #include "nmos/is12_versions.h" @@ -10,18 +11,18 @@ namespace nmos namespace details { // create block resource - nmos::resource make_block(nmos::nc_oid oid, const web::json::value& owner, const utility::string_t& role, const utility::string_t& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, const web::json::value& members) + resource make_block(nmos::nc_oid oid, const web::json::value& owner, const utility::string_t& role, const utility::string_t& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, const web::json::value& members) { using web::json::value; auto data = details::make_nc_block(nc_block_class_id, oid, true, owner, role, value::string(user_label), touchpoints, runtime_property_constraints, true, members); - return{ is12_versions::v1_0, types::nc_block, std::move(data), true }; + return{ is12_versions::v1_0, types::nc_object, std::move(data), true }; } } // create block resource - nmos::resource make_block(nc_oid oid, nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, const web::json::value& members) + resource make_block(nc_oid oid, nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, const web::json::value& members) { using web::json::value; @@ -29,7 +30,7 @@ namespace nmos } // create Root block resource - nmos::resource make_root_block() + resource make_root_block() { using web::json::value; @@ -37,7 +38,7 @@ namespace nmos } // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager - nmos::resource make_device_manager(nc_oid oid, const nmos::settings& settings) + resource make_device_manager(nc_oid oid, const nmos::settings& settings) { using web::json::value; @@ -52,11 +53,11 @@ namespace nmos auto data = details::make_nc_device_manager(oid, root_block_oid, user_label, value::null(), value::null(), manufacturer, product, serial_number, value::null(), device_name, device_role, operational_state, nc_reset_cause::unknown); - return{ is12_versions::v1_0, types::nc_device_manager, std::move(data), true }; + return{ is12_versions::v1_0, types::nc_object, std::move(data), true }; } // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager - nmos::resource make_class_manager(nc_oid oid, const nmos::experimental::control_protocol_state& control_protocol_state) + resource make_class_manager(nc_oid oid, const nmos::experimental::control_protocol_state& control_protocol_state) { using web::json::value; @@ -64,7 +65,7 @@ namespace nmos auto data = details::make_nc_class_manager(oid, root_block_oid, user_label, value::null(), value::null(), control_protocol_state); - return{ is12_versions::v1_0, types::nc_class_manager, std::move(data), true }; + return{ is12_versions::v1_0, types::nc_object, std::move(data), true }; } // add to owner block member @@ -80,4 +81,49 @@ namespace nmos return true; } + + // modify a resource, and insert notification event to all subscriptions + bool modify_control_protocol_resource(resources& resources, const id& id, std::function modifier, const web::json::value& notification_event) + { + auto found = resources.find(id); + if (resources.end() == found || !found->has_data()) return false; + + auto pre = found->data; + + // "If an exception is thrown by some user-provided operation, then the element pointed to by position is erased." + // This seems too surprising, despite the fact that it means that a modification may have been partially completed, + // so capture and rethrow. + // See https://www.boost.org/doc/libs/1_68_0/libs/multi_index/doc/reference/ord_indices.html#modify + std::exception_ptr modifier_exception; + + auto resource_updated = nmos::strictly_increasing_update(resources); + auto result = resources.modify(found, [&resource_updated, &modifier, &modifier_exception](resource& resource) + { + try + { + modifier(resource); + } + catch (...) + { + modifier_exception = std::current_exception(); + } + + // set the update timestamp + resource.updated = resource_updated; + }); + + if (result) + { + auto& modified = *found; + + insert_notification_events(resources, modified.version, modified.downgrade_version, modified.type, pre, modified.data, notification_event); + } + + if (modifier_exception) + { + std::rethrow_exception(modifier_exception); + } + + return result; + } } diff --git a/Development/nmos/control_protocol_resources.h b/Development/nmos/control_protocol_resources.h index d3fdb44b1..56f80103f 100644 --- a/Development/nmos/control_protocol_resources.h +++ b/Development/nmos/control_protocol_resources.h @@ -2,6 +2,7 @@ #define NMOS_CONTROL_PROTOCOL_RESOURCES_H #include "nmos/control_protocol_typedefs.h" // for details::nc_oid definition +#include "nmos/resources.h" #include "nmos/settings.h" namespace nmos @@ -14,19 +15,22 @@ namespace nmos struct resource; // create block resource - nmos::resource make_block(nc_oid oid, nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null(), const web::json::value& members = web::json::value::array()); + resource make_block(nc_oid oid, nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null(), const web::json::value& members = web::json::value::array()); // create Root block resource - nmos::resource make_root_block(); + resource make_root_block(); // create Device manager resource - nmos::resource make_device_manager(nc_oid oid, const nmos::settings& settings); + resource make_device_manager(nc_oid oid, const nmos::settings& settings); // create Class manager resource - nmos::resource make_class_manager(nc_oid oid, const nmos::experimental::control_protocol_state& control_protocol_state); + resource make_class_manager(nc_oid oid, const nmos::experimental::control_protocol_state& control_protocol_state); // add to owner block member - bool add_member(const utility::string_t& child_description, const nmos::resource& child_block, nmos::resource& parent_block); + bool add_member(const utility::string_t& child_description, const resource& child_block, resource& parent_block); + + // modify a resource, and insert notification event to all subscriptions + bool modify_control_protocol_resource(resources& resources, const id& id, std::function modifier, const web::json::value& notification_event); } #endif diff --git a/Development/nmos/control_protocol_state.cpp b/Development/nmos/control_protocol_state.cpp index ed18a4a4b..c308ad26d 100644 --- a/Development/nmos/control_protocol_state.cpp +++ b/Development/nmos/control_protocol_state.cpp @@ -120,22 +120,22 @@ namespace nmos { nc_object_class_id, make_control_class(U("NcObject class descriptor"), nc_object_class_id, U("NcObject"), to_vector(make_nc_object_properties()), to_methods_vector(make_nc_object_methods(), { - { {1, 1}, nmos::details::get }, - { {1, 2}, nmos::details::set }, - { {1, 3}, nmos::details::get_sequence_item }, - { {1, 4}, nmos::details::set_sequence_item }, - { {1, 5}, nmos::details::add_sequence_item }, - { {1, 6}, nmos::details::remove_sequence_item }, - { {1, 7}, nmos::details::get_sequence_length } + { nc_object_get_method_id, nmos::details::get }, + { nc_object_set_method_id, nmos::details::set }, + { nc_object_get_sequence_item_method_id, nmos::details::get_sequence_item }, + { nc_object_set_sequence_item_method_id, nmos::details::set_sequence_item }, + { nc_object_add_sequence_item_method_id, nmos::details::add_sequence_item }, + { nc_object_remove_sequence_item_method_id, nmos::details::remove_sequence_item }, + { nc_object_get_sequence_length_method_id, nmos::details::get_sequence_length } }), to_vector(make_nc_object_events())) }, { nc_block_class_id, make_control_class(U("NcBlock class descriptor"), nc_block_class_id, U("NcBlock"), to_vector(make_nc_block_properties()), to_methods_vector(make_nc_block_methods(), { - { {2, 1}, nmos::details::get_member_descriptors }, - { {2, 2}, nmos::details::find_members_by_path }, - { {2, 3}, nmos::details::find_members_by_role }, - { {2, 4}, nmos::details::find_members_by_class_id } + { nc_block_get_member_descriptors_method_id, nmos::details::get_member_descriptors }, + { nc_block_find_members_by_path_method_id, nmos::details::find_members_by_path }, + { nc_block_find_members_by_role_method_id, nmos::details::find_members_by_role }, + { nc_block_find_members_by_class_id_method_id, nmos::details::find_members_by_class_id } }), to_vector(make_nc_block_events())) }, { nc_worker_class_id, make_control_class(U("NcWorker class descriptor"), nc_worker_class_id, U("NcWorker"), to_vector(make_nc_worker_properties()), to_methods_vector(make_nc_worker_methods(), {}), to_vector(make_nc_worker_events())) }, @@ -144,8 +144,8 @@ namespace nmos { nc_class_manager_class_id, make_control_class(U("NcClassManager class descriptor"), nc_class_manager_class_id, U("NcClassManager"), U("ClassManager"), to_vector(make_nc_class_manager_properties()), to_methods_vector(make_nc_class_manager_methods(), { - { {3, 1}, nmos::details::get_control_class }, - { {3, 2}, nmos::details::get_datatype } + { nc_class_manager_get_control_class_method_id, nmos::details::get_control_class }, + { nc_class_manager_get_datatype_method_id, nmos::details::get_datatype } }), to_vector(make_nc_class_manager_events())) }, // identification beacon model diff --git a/Development/nmos/control_protocol_typedefs.h b/Development/nmos/control_protocol_typedefs.h index bf33a331a..9c0962742 100644 --- a/Development/nmos/control_protocol_typedefs.h +++ b/Development/nmos/control_protocol_typedefs.h @@ -2,14 +2,7 @@ #define NMOS_CONTROL_PROTOCOL_TYPEDEFS_H #include "cpprest/basic_utils.h" - -namespace web -{ - namespace json - { - class value; - } -} +#include "cpprest/json_utils.h" namespace nmos { @@ -146,14 +139,81 @@ namespace nmos // NcEventId // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#nceventid typedef nc_element_id nc_event_id; + // NcEventIds for NcObject + // SEe https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncobject + const nc_event_id nc_object_property_changed_event_id(1, 1); // NcMethodId // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmethodid typedef nc_element_id nc_method_id; + // NcMethodIds for NcObject + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncobject + const nc_method_id nc_object_get_method_id(1, 1); + const nc_method_id nc_object_set_method_id(1, 2); + const nc_method_id nc_object_get_sequence_item_method_id(1, 3); + const nc_method_id nc_object_set_sequence_item_method_id(1, 4); + const nc_method_id nc_object_add_sequence_item_method_id(1, 5); + const nc_method_id nc_object_remove_sequence_item_method_id(1, 6); + const nc_method_id nc_object_get_sequence_length_method_id(1, 7); + // NcMethodIds for NcBlock + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncblock + const nc_method_id nc_block_get_member_descriptors_method_id(2, 1); + const nc_method_id nc_block_find_members_by_path_method_id(2, 2); + const nc_method_id nc_block_find_members_by_role_method_id(2, 3); + const nc_method_id nc_block_find_members_by_class_id_method_id(2, 4); + // NcMethodIds for NcClassManager + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncclassmanager + const nc_method_id nc_class_manager_get_control_class_method_id(3, 1); + const nc_method_id nc_class_manager_get_datatype_method_id(3, 2); // NcPropertyId // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncpropertyid typedef nc_element_id nc_property_id; + // NcPropertyIds for NcObject + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncobject + const nc_property_id nc_object_class_id_property_id(1, 1); + const nc_property_id nc_object_oid_property_id(1, 2); + const nc_property_id nc_object_constant_oid_property_id(1, 3); + const nc_property_id nc_object_owner_property_id(1, 4); + const nc_property_id nc_object_role_property_id(1, 5); + const nc_property_id nc_object_user_label_property_id(1, 6); + const nc_property_id nc_object_touchpoints_property_id(1, 7); + const nc_property_id nc_object_runtime_property_constraints_property_id(1, 8); + // NcPropertyIds for NcBlock + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncblock + const nc_property_id nc_block_enabled_property_id(2, 1); + const nc_property_id nc_block_members_property_id(2, 2); + // NcPropertyIds for NcWorker + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncworker + const nc_property_id nc_worker_enabled_property_id(2, 1); + // NcPropertyIds for NcDeviceManager + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdevicemanager + const nc_property_id nc_device_manager_nc_version_property_id(3, 1); + const nc_property_id nc_device_manager_manufacturer_property_id(3, 2); + const nc_property_id nc_device_manager_product_property_id(3, 3); + const nc_property_id nc_device_manager_serial_number_property_id(3, 4); + const nc_property_id nc_device_manager_user_inventory_code_property_id(3, 5); + const nc_property_id nc_device_manager_device_name_property_id(3, 6); + const nc_property_id nc_device_manager_device_role_property_id(3, 7); + const nc_property_id nc_device_manager_operational_state_property_id(3, 8); + const nc_property_id nc_device_manager_reset_cause_property_id(3, 9); + const nc_property_id nc_device_manager_message_property_id(3, 10); + // NcPropertyIds for NcClassManager + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncclassmanager + const nc_property_id nc_class_manager_control_classes_property_id(3, 1); + const nc_property_id nc_class_manager_datatypes_property_id(3, 2); + // NcPropertyids for NcReceiverMonitor + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitor + const nc_property_id nc_receiver_monitor_connection_status_property_id(3, 1); + const nc_property_id nc_receiver_monitor_connection_status_message_property_id(3, 2); + const nc_property_id nc_receiver_monitor_payload_status_property_id(3, 3); + const nc_property_id nc_receiver_monitor_payload_status_message_property_id(3, 4); + // NcPropertyids for NcReceiverMonitorProtected + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitorprotected + const nc_property_id nc_receiver_monitor_protected_signal_protection_status_property_id(4, 1); + // NcPropertyids for NcIdentBeacon + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/identification/#ncidentbeacon + const nc_property_id nc_ident_beacon_active_property_id(3, 1); // NcId // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncid @@ -166,6 +226,7 @@ namespace nmos // NcOid // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncoid typedef uint32_t nc_oid; + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Blocks.html const nc_oid root_block_oid{ 1 }; // NcUri @@ -179,19 +240,70 @@ namespace nmos // NcClassId // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassid typedef std::vector nc_class_id; + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncobject const nc_class_id nc_object_class_id({ 1 }); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncblock const nc_class_id nc_block_class_id({ 1, 1 }); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncworker const nc_class_id nc_worker_class_id({ 1, 2 }); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncmanager const nc_class_id nc_manager_class_id({ 1, 3 }); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdevicemanager const nc_class_id nc_device_manager_class_id({ 1, 3, 1 }); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncclassmanager const nc_class_id nc_class_manager_class_id({ 1, 3, 2 }); + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/identification/#ncidentbeacon const nc_class_id nc_ident_beacon_class_id({ 1, 2, 2 }); + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitor const nc_class_id nc_receiver_monitor_class_id({ 1, 2, 3 }); + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitorprotected const nc_class_id nc_receiver_monitor_protected_class_id({ 1, 2, 3, 1 }); // NcTouchpoint // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#nctouchpoint typedef utility::string_t nc_touch_point; + + // NcPropertyChangeType + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncpropertychangetype + namespace nc_property_change_type + { + enum type + { + value_changed = 0, // Current value changed + sequence_item_added = 1, // Sequence item added + sequence_item_changed = 2, // Sequence item changed + sequence_item_removed = 3 // Sequence item removed + }; + } + + // NcPropertyChangedEventData + // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncpropertychangedeventdata + struct nc_property_changed_event_data + { + nc_property_id property_id; + nc_property_change_type::type change_type; + web::json::value value; + web::json::value sequence_item_index; // nc_id, can be null + + nc_property_changed_event_data(nc_property_id property_id, nc_property_change_type::type change_type, web::json::value value, nc_id sequence_item_index) + : property_id(std::move(property_id)) + , change_type(change_type) + , value(std::move(value)) + , sequence_item_index(sequence_item_index) + {} + + nc_property_changed_event_data(nc_property_id property_id, nc_property_change_type::type change_type, web::json::value value) + : property_id(std::move(property_id)) + , change_type(change_type) + , value(std::move(value)) + , sequence_item_index(web::json::value::null()) + {} + + auto tied() const -> decltype(std::tie(property_id, change_type, value, sequence_item_index)) { return std::tie(property_id, change_type, value, sequence_item_index); } + friend bool operator==(const nc_property_changed_event_data& lhs, const nc_property_changed_event_data& rhs) { return lhs.tied() == rhs.tied(); } + friend bool operator!=(const nc_property_changed_event_data& lhs, const nc_property_changed_event_data& rhs) { return !(lhs == rhs); } + friend bool operator<(const nc_property_changed_event_data& lhs, const nc_property_changed_event_data& rhs) { return lhs.tied() < rhs.tied(); } + }; } #endif diff --git a/Development/nmos/control_protocol_ws_api.cpp b/Development/nmos/control_protocol_ws_api.cpp index bca663ee2..2fd5e1c67 100644 --- a/Development/nmos/control_protocol_ws_api.cpp +++ b/Development/nmos/control_protocol_ws_api.cpp @@ -1,5 +1,6 @@ #include "nmos/control_protocol_ws_api.h" +#include #include #include "cpprest/json_validator.h" #include "nmos/api_utils.h" @@ -21,7 +22,7 @@ namespace nmos static const web::json::experimental::json_validator validator { nmos::experimental::load_json_schema, - boost::copy_range>(boost::join(boost::join( + boost::copy_range>(boost::range::join(boost::range::join( is12_versions::all | boost::adaptors::transformed(experimental::make_controlprotocolapi_base_message_schema_uri), is12_versions::all | boost::adaptors::transformed(experimental::make_controlprotocolapi_command_message_schema_uri)), is12_versions::all | boost::adaptors::transformed(experimental::make_controlprotocolapi_subscription_message_schema_uri) @@ -121,7 +122,7 @@ namespace nmos value data = value_of({ { nmos::fields::id, nmos::make_id() }, { nmos::fields::max_update_rate_ms, 0 }, - { nmos::fields::resource_path, U('/') + nmos::resourceType_from_type(nmos::types::source) }, + { nmos::fields::resource_path, U('/') + nmos::resourceType_from_type(nmos::types::nc_object) }, { nmos::fields::params, value_of({ { U("query.rql"), U("in(id,())") } }) }, { nmos::fields::persist, non_persistent }, { nmos::fields::secure, secure }, @@ -154,7 +155,7 @@ namespace nmos websockets.insert({ id, connection_id }); - slog::log(gate, SLOG_FLF) << "Creating websocket connection: " << id; + slog::log(gate, SLOG_FLF) << "Creating websocket connection: " << id << " to subscription: " << subscription->id; slog::log(gate, SLOG_FLF) << "Notifying control protocol websockets thread"; // and anyone else who cares... model.notify(); @@ -180,7 +181,7 @@ namespace nmos if (resources.end() != grain) { - slog::log(gate, SLOG_FLF) << "Deleting websocket connection"; + slog::log(gate, SLOG_FLF) << "Deleting websocket connection: " << grain->id; // subscriptions have a 1-1 relationship with the websocket connection and both should now be erased immediately auto subscription = find_resource(resources, { nmos::fields::subscription_id(grain->data), nmos::types::subscription }); @@ -195,7 +196,6 @@ namespace nmos // a grain without a subscription shouldn't be possible, but let's be tidy erase_resource(resources, grain->id); } - //erase_resource(resources, grain->id); } websockets.right.erase(websocket); @@ -208,6 +208,7 @@ namespace nmos web::websockets::experimental::listener::message_handler make_control_protocol_ws_message_handler(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::get_control_protocol_methods_handler get_control_protocol_methods, slog::base_gate& gate_) { using web::json::value; + using web::json::value_of; auto methods = get_control_protocol_methods(); @@ -296,11 +297,10 @@ namespace nmos } } - // add command_response for the control protocol response thread to return to the client + // add command_response to the grain ready to transfer to the client in nmos::send_control_protocol_ws_messages_thread resources.modify(grain, [&](nmos::resource& grain) { - web::json::push_back(nmos::fields::message_grain_data(grain.data), - make_control_protocol_message_response(nc_message_type::command_response, responses)); + web::json::push_back(nmos::fields::message_grain_data(grain.data), make_control_protocol_message_response(responses)); grain.updated = strictly_increasing_update(resources); }); @@ -308,11 +308,45 @@ namespace nmos break; case nc_message_type::subscription: { - // hmm, todo... + // validate subscription-message + details::validate_controlprotocolapi_subscription_message_schema(version, message); + + // subscribing to multiple OIDs, and filtering out invalid OIDs which cannot be subscribed to + auto& subscriptions = nmos::fields::nc::subscriptions(message); + value valid_subscriptions = value::array(); + for (const auto& subscription : subscriptions) + { + const auto oid = subscription.as_integer(); + auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); + if (resources.end() != resource) + { + // only add the valid OIDs which can be subscribed to + web::json::push_back(valid_subscriptions, subscription); + } + } + + // update the subscription + modify_resource(resources, subscription->id, [&valid_subscriptions](nmos::resource& resource) + { + auto rql_query = U("in(id,(") + boost::algorithm::join(valid_subscriptions.as_array() | boost::adaptors::transformed([](const value& v) { return U("string:") + utility::s2us(std::to_string(v.as_integer())); }), U(",")) + U("))"); + + resource.data[nmos::fields::params] = value_of({ { U("query.rql"), rql_query } }); + }); + + // add subscription_response to the grain ready to transfer to the client in nmos::send_control_protocol_ws_messages_thread + resources.modify(grain, [&](nmos::resource& grain) + { + web::json::push_back(nmos::fields::message_grain_data(grain.data), make_control_protocol_subscription_response(valid_subscriptions)); + + grain.updated = strictly_increasing_update(resources); + }); + + slog::log(gate, SLOG_FLF) << "Received subscription command for " << valid_subscriptions.serialize(); + model.notify(); } - break; + break; default: - // unexpected message type + // ignore unexpected message type break; } diff --git a/Development/nmos/json_fields.h b/Development/nmos/json_fields.h index df831eaec..0c293ac97 100644 --- a/Development/nmos/json_fields.h +++ b/Development/nmos/json_fields.h @@ -238,6 +238,7 @@ namespace nmos // for control_protocol_ws_api commands const web::json::field_as_array commands{ U("commands") }; + const web::json::field_as_array subscriptions{ U("subscriptions")}; const web::json::field_as_integer oid{ U("oid") }; const web::json::field_as_value method_id{ U("methodId") }; const web::json::field_as_value arguments{ U("arguments") }; @@ -255,6 +256,11 @@ namespace nmos // for control_protocol_ws_api commands & responses const web::json::field_as_integer handle{ U("handle") }; + // for cntrol_protocol_ws_api notifications + const web::json::field_as_array notifications{ U("notifications") }; + const web::json::field_as_value event_data{ U("eventData") }; + const web::json::field_as_value event_id{ U("eventId") }; + const web::json::field_as_array class_id{ U("classId") }; const web::json::field_as_bool constant_oid{ U("constantOid") }; const web::json::field_as_integer owner{ U("owner") }; @@ -265,39 +271,39 @@ namespace nmos const web::json::field_as_bool recurse{ U("recurse") }; const web::json::field_as_bool enabled{ U("enabled") }; const web::json::field_as_array members{ U("members") }; - const web::json::field_as_string description{ U("description") }; // can be null - const web::json::field_as_string nc_version{ U("ncVersion") }; // NcVersionCode, string + const web::json::field_as_string description{ U("description") }; + const web::json::field_as_string nc_version{ U("ncVersion") }; // NcVersionCode const web::json::field_as_value manufacturer{ U("manufacturer") }; // NcManufacturer const web::json::field_as_value product{ U("product") }; // NcProduct const web::json::field_as_string serial_number{ U("serialNumber") }; - const web::json::field_as_string user_inventory_code{ U("userInventoryCode") }; // string, can be null - const web::json::field_as_string device_name{ U("deviceName") }; // string, can be null - const web::json::field_as_string device_role{ U("deviceRole") }; // string, can be null + const web::json::field_as_string user_inventory_code{ U("userInventoryCode") }; + const web::json::field_as_string device_name{ U("deviceName") }; + const web::json::field_as_string device_role{ U("deviceRole") }; const web::json::field_as_value operational_state{ U("operationalState") }; // NcDeviceOperationalState const web::json::field_as_integer reset_cause{ U("resetCause") }; // NcResetCause - const web::json::field_as_string message{ U("message") }; // string, can be null + const web::json::field_as_string message{ U("message") }; const web::json::field_as_array control_classes{ U("controlClasses") }; // sequence const web::json::field_as_array datatypes{ U("datatypes") }; // sequence const web::json::field_as_string name{ U("name")}; - const web::json::field_as_string fixed_role{ U("fixedRole") }; // string, can be null + const web::json::field_as_string fixed_role{ U("fixedRole") }; const web::json::field_as_array properties{ U("properties") }; // sequence const web::json::field_as_array methods{ U("methods") }; // sequence const web::json::field_as_array events{ U("events") }; // sequence const web::json::field_as_integer type{ U("type") }; // NcDatatypeType - const web::json::field_as_value constraints{ U("constraints") }; // NcParameterConstraints, can be null + const web::json::field_as_value constraints{ U("constraints") }; // NcParameterConstraints const web::json::field_as_integer organization_id{ U("organizationId") }; const web::json::field_as_string website{ U("website") }; const web::json::field_as_string key{ U("key") }; const web::json::field_as_string revision_level{ U("revisionLevel") }; - const web::json::field_as_string brand_name{ U("brandName") }; // string, can be null - const web::json::field_as_string uuid{ U("uuid") }; // string, can be null - const web::json::field_as_string type_name{ U("typeName") }; // string, can be null + const web::json::field_as_string brand_name{ U("brandName") }; + const web::json::field_as_string uuid{ U("uuid") }; + const web::json::field_as_string type_name{ U("typeName") }; const web::json::field_as_bool is_read_only{ U("isReadOnly") }; const web::json::field_as_bool is_persistent{ U("isPersistent") }; const web::json::field_as_bool is_nullable{ U("isNullable") }; const web::json::field_as_bool is_sequence{ U("isSequence") }; const web::json::field_as_bool is_deprecated{ U("isDeprecated") }; - const web::json::field_as_bool is_constant{ U("isConstant") }; // bool, can be null + const web::json::field_as_bool is_constant{ U("isConstant") }; const web::json::field_as_string parent_type{ U("parentType") }; const web::json::field_as_string event_datatype{ U("eventDatatype") }; const web::json::field_as_string result_datatype{ U("resultDatatype") }; @@ -305,7 +311,7 @@ namespace nmos const web::json::field_as_array items{ U("items") }; // sequence const web::json::field_as_array fields{ U("fields") }; // sequence const web::json::field_as_integer generic_state{ U("generic") }; // NcDeviceGenericState - const web::json::field_as_string device_specific_details{ U("deviceSpecificDetails") }; // string, can be null + const web::json::field_as_string device_specific_details{ U("deviceSpecificDetails") }; const web::json::field_as_array path{ U("path") }; // NcRolePath const web::json::field_as_bool case_sensitive{ U("caseSensitive") }; const web::json::field_as_bool match_whole_string{ U("matchWholeString") }; @@ -314,7 +320,7 @@ namespace nmos const web::json::field_as_string context_namespace{ U("contextNamespace") }; const web::json::field_as_value default_value{ U("defaultValue") }; const web::json::field_as_integer change_type{ U("changeType") }; // NcPropertyChangeType - const web::json::field_as_integer sequence_item_index{ U("sequenceItemIndex") }; // NcId, can be null + const web::json::field_as_integer sequence_item_index{ U("sequenceItemIndex") }; // NcId const web::json::field_as_value property_id{ U("propertyId") }; const web::json::field_as_integer maximum{ U("maximum") }; const web::json::field_as_integer minimum{ U("minimum") }; diff --git a/Development/nmos/query_utils.cpp b/Development/nmos/query_utils.cpp index 14e381200..672e610e6 100644 --- a/Development/nmos/query_utils.cpp +++ b/Development/nmos/query_utils.cpp @@ -577,4 +577,48 @@ namespace nmos } } } + + // insert 'value changed', 'sequence item added', 'sequence item changed' or 'sequence item removed' notification events into all grains whose subscriptions match the specified version, type and "pre" or "post" values + void insert_notification_events(nmos::resources& resources, const nmos::api_version& version, const nmos::api_version& downgrade_version, const nmos::type& type, const web::json::value& pre, const web::json::value& post, const web::json::value& event) + { + using web::json::value; + + if (pre == post) return; + + if (!details::is_queryable_resource(type)) return; + + auto& by_type = resources.get(); + const auto subscriptions = by_type.equal_range(details::has_data(nmos::types::subscription)); + + for (auto it = subscriptions.first; subscriptions.second != it; ++it) + { + // for each subscription + const auto& subscription = *it; + + // check whether the resource_path matches the resource type and the query parameters match either the "pre" or "post" resource + + const auto resource_path = nmos::fields::resource_path(subscription.data); + const resource_query match(subscription.version, resource_path, nmos::fields::params(subscription.data)); + + const bool pre_match = match(version, downgrade_version, type, pre, resources); + const bool post_match = match(version, downgrade_version, type, post, resources); + + if (!pre_match && !post_match) continue; + + // add the event to the grain for each websocket connection to this subscription + + for (const auto& id : subscription.sub_resources) + { + auto grain = find_resource(resources, { id, nmos::types::grain }); + if (resources.end() == grain) continue; // check websocket connection is still open + + resources.modify(grain, [&resources, &event](nmos::resource& grain) + { + auto& events = nmos::fields::message_grain_data(grain.data); + web::json::push_back(events, event); + grain.updated = strictly_increasing_update(resources); + }); + } + } + } } diff --git a/Development/nmos/query_utils.h b/Development/nmos/query_utils.h index 91addbe46..fcfbe9c0b 100644 --- a/Development/nmos/query_utils.h +++ b/Development/nmos/query_utils.h @@ -114,6 +114,9 @@ namespace nmos // insert 'added', 'removed' or 'modified' resource events into all grains whose subscriptions match the specified version, type and "pre" or "post" values void insert_resource_events(nmos::resources& resources, const nmos::api_version& version, const nmos::api_version& downgrade_version, const nmos::type& type, const web::json::value& pre, const web::json::value& post); + // insert 'value changed', 'sequence item added', 'sequence item changed' or 'sequence item removed' notification events into all grains whose subscriptions match the specified version, type and "pre" or "post" values + void insert_notification_events(nmos::resources& resources, const nmos::api_version& version, const nmos::api_version& downgrade_version, const nmos::type& type, const web::json::value& pre, const web::json::value& post, const web::json::value& event); + namespace fields { const web::json::field_as_string_or query_rql{ U("query.rql"), {} }; diff --git a/Development/nmos/type.h b/Development/nmos/type.h index 4fcf54f97..4e6831aa1 100644 --- a/Development/nmos/type.h +++ b/Development/nmos/type.h @@ -28,10 +28,13 @@ namespace nmos // to a subscription is managed as a sub-resource of the subscription const type grain{ U("grain") }; + // the Control Protocol API resource type, see nmos/control_protcol_resources.h + const type nc_object{ U("nc_object") }; + // all types ordered so that sub-resource types appear after super-resource types // according to the guidelines on referential integrity // see https://specs.amwa.tv/is-04/releases/v1.2.1/docs/4.1._Behaviour_-_Registration.html#referential-integrity - const std::vector all{ nmos::types::node, nmos::types::device, nmos::types::source, nmos::types::flow, nmos::types::sender, nmos::types::receiver, nmos::types::subscription, nmos::types::grain }; + const std::vector all{ nmos::types::node, nmos::types::device, nmos::types::source, nmos::types::flow, nmos::types::sender, nmos::types::receiver, nmos::types::subscription, nmos::types::grain, nmos::types::nc_object }; // the Channel Mapping API resource types, see nmos/channelmapping_resources.h const type input{ U("input") }; @@ -39,13 +42,6 @@ namespace nmos // the System API global configuration resource type, see nmos/system_resources.h const type global{ U("global") }; - - // the Control Protocol API resource types, see nmos/control_protcol_resources.h - const type nc_block{ U("nc_block") }; - const type nc_worker{ U("nc_worker") }; - const type nc_manager{ U("nc_manager") }; - const type nc_device_manager{ U("nc_device_manager") }; - const type nc_class_manager{ U("nc_class_manager") }; } } From b7a24e52dc448e8e0af00fcd198c6281f90cd03e Mon Sep 17 00:00:00 2001 From: lo-simon Date: Fri, 15 Sep 2023 15:35:15 +0100 Subject: [PATCH 045/106] Update outdated IS-12 links --- Development/nmos-cpp-node/config.json | 6 +- .../nmos/control_protocol_resource.cpp | 199 +++++++++-------- Development/nmos/control_protocol_resource.h | 202 +++++++++--------- .../nmos/control_protocol_resources.cpp | 4 +- Development/nmos/control_protocol_state.cpp | 4 +- Development/nmos/control_protocol_typedefs.h | 28 +-- Development/nmos/settings.h | 6 +- 7 files changed, 224 insertions(+), 225 deletions(-) diff --git a/Development/nmos-cpp-node/config.json b/Development/nmos-cpp-node/config.json index 397da858f..93ea3e669 100644 --- a/Development/nmos-cpp-node/config.json +++ b/Development/nmos-cpp-node/config.json @@ -288,17 +288,17 @@ //"ocsp_request_max": 30, // manufacturer_name [node]: the manufacturer name of the NcDeviceManager used for NMOS Control Protocol - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdevicemanager //"manufacturer_name": "", // product_name/product_key/product_revision_level [node]: the product description of the NcDeviceManager used for NMOS Control Protocol - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncproduct + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncproduct //"product_name": "", //"product_key": "", //"product_revision_level": "", // serial_number [node]: the serial number of the NcDeviceManager used for NMOS Control Protocol - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdevicemanager //"serial_number": "", "don't worry": "about trailing commas" diff --git a/Development/nmos/control_protocol_resource.cpp b/Development/nmos/control_protocol_resource.cpp index 1a9f89507..74d934c68 100644 --- a/Development/nmos/control_protocol_resource.cpp +++ b/Development/nmos/control_protocol_resource.cpp @@ -31,7 +31,7 @@ namespace nmos return result; } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncelementid + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncelementid web::json::value make_nc_element_id(uint16_t level, uint16_t index) { using web::json::value_of; @@ -41,7 +41,6 @@ namespace nmos { nmos::fields::nc::index, index } }); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncelementid web::json::value make_nc_element_id(const nc_element_id& id) { return make_nc_element_id(id.level, id.index); @@ -51,7 +50,7 @@ namespace nmos return { uint16_t(nmos::fields::nc::level(id)), uint16_t(nmos::fields::nc::index(id)) }; } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#nceventid + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#nceventid web::json::value make_nc_event_id(const nc_event_id& id) { return make_nc_element_id(id); @@ -61,7 +60,7 @@ namespace nmos return parse_nc_element_id(id); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmethodid + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncmethodid web::json::value make_nc_method_id(const nc_method_id& id) { return make_nc_element_id(id); @@ -71,7 +70,7 @@ namespace nmos return parse_nc_element_id(id); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncpropertyid + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncpropertyid web::json::value make_nc_property_id(const nc_property_id& id) { return make_nc_element_id(id); @@ -81,7 +80,7 @@ namespace nmos return parse_nc_element_id(id); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassid + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncclassid web::json::value make_nc_class_id(const nc_class_id& class_id) { using web::json::value; @@ -100,7 +99,7 @@ namespace nmos return class_id; } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanufacturer + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncmanufacturer web::json::value make_nc_manufacturer(const utility::string_t& name, const web::json::value& organization_id, const web::json::value& website) { using web::json::value_of; @@ -112,7 +111,7 @@ namespace nmos }); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncproduct + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncproduct // brand_name can be null // uuid can be null // description can be null @@ -131,7 +130,7 @@ namespace nmos }); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdeviceoperationalstate + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdeviceoperationalstate // device_specific_details can be null web::json::value make_nc_device_operational_state(nc_device_generic_state::state generic_state, const web::json::value& device_specific_details) { @@ -143,7 +142,7 @@ namespace nmos }); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdescriptor + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdescriptor // description can be null web::json::value make_nc_descriptor(const web::json::value& description) { @@ -152,7 +151,7 @@ namespace nmos return value_of({ { nmos::fields::nc::description, description } }); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblockmemberdescriptor + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncblockmemberdescriptor // description can be null // user_label can be null web::json::value make_nc_block_member_descriptor(const web::json::value& description, const utility::string_t& role, nc_oid oid, bool constant_oid, const nc_class_id& class_id, const web::json::value& user_label, nc_oid owner) @@ -176,7 +175,7 @@ namespace nmos return make_nc_block_member_descriptor(value::string(description), role, oid, constant_oid, class_id, value::string(user_label), owner); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassdescriptor + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncclassdescriptor // description can be null // fixedRole can be null web::json::value make_nc_class_descriptor(const web::json::value& description, const nc_class_id& class_id, const nc_name& name, const web::json::value& fixed_role, const web::json::value& properties, const web::json::value& methods, const web::json::value& events) @@ -200,7 +199,7 @@ namespace nmos return make_nc_class_descriptor(value::string(description), class_id, name, fixed_role, properties, methods, events); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncenumitemdescriptor + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncenumitemdescriptor // description can be null web::json::value make_nc_enum_item_descriptor(const web::json::value& description, const nc_name& name, uint16_t val) { @@ -219,7 +218,7 @@ namespace nmos return make_nc_enum_item_descriptor(value::string(description), name, val); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#nceventdescriptor + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#nceventdescriptor // description can be null // id = make_nc_event_id(level, index) web::json::value make_nc_event_descriptor(const web::json::value& description, const nc_event_id& id, const nc_name& name, const utility::string_t& event_datatype, bool is_deprecated) @@ -241,7 +240,7 @@ namespace nmos return make_nc_event_descriptor(value::string(description), id, name, event_datatype, is_deprecated); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncfielddescriptor + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncfielddescriptor // description can be null // type_name can be null // constraints can be null @@ -265,7 +264,7 @@ namespace nmos return make_nc_field_descriptor(value::string(description), name, value::string(type_name), is_nullable, is_sequence, constraints); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmethoddescriptor + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncmethoddescriptor // description can be null // id = make_nc_method_id(level, index) // sequence parameters @@ -289,7 +288,7 @@ namespace nmos return make_nc_method_descriptor(value::string(description), id, name, result_datatype, parameters, is_deprecated); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncparameterdescriptor + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterdescriptor // description can be null // type_name can be null web::json::value make_nc_parameter_descriptor(const web::json::value& description, const nc_name& name, const web::json::value& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints) @@ -318,7 +317,7 @@ namespace nmos return make_nc_parameter_descriptor(value::string(description), name, value::string(type_name), is_nullable, is_sequence, constraints); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncpropertydescriptor + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncpropertydescriptor // description can be null // constraints can be null web::json::value make_nc_property_descriptor(const web::json::value& description, const nc_property_id& id, const nc_name& name, const web::json::value& type_name, @@ -346,7 +345,7 @@ namespace nmos return nmos::details::make_nc_property_descriptor(value::string(description), id, name, value::string(type_name), is_read_only, is_nullable, is_sequence, is_deprecated, constraints); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptor + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdatatypedescriptor // description can be null // constraints can be null web::json::value make_nc_datatype_descriptor(const web::json::value& description, const nc_name& name, nc_datatype_type::type type, const web::json::value& constraints) @@ -361,7 +360,7 @@ namespace nmos return data; } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptorenum + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdatatypedescriptorenum // description can be null // constraints can be null // items: sequence @@ -373,7 +372,7 @@ namespace nmos return data; } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptorprimitive + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdatatypedescriptorprimitive // description can be null // constraints can be null web::json::value make_nc_datatype_descriptor_primitive(const web::json::value& description, const nc_name& name, const web::json::value& constraints) @@ -381,7 +380,7 @@ namespace nmos return make_nc_datatype_descriptor(description, name, nc_datatype_type::Primitive, constraints); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptorstruct + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdatatypedescriptorstruct // description can be null // constraints can be null // fields: sequence @@ -395,7 +394,7 @@ namespace nmos return data; } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptortypedef + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdatatypedescriptortypedef // description can be null // constraints can be null web::json::value make_nc_datatype_typedef(const web::json::value& description, const nc_name& name, bool is_sequence, const utility::string_t& parent_type, const web::json::value& constraints) @@ -409,7 +408,7 @@ namespace nmos return data; } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncobject web::json::value make_nc_object(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints) { using web::json::value; @@ -430,7 +429,7 @@ namespace nmos return data; } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncblock web::json::value make_nc_block(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled, const web::json::value& members) { using web::json::value; @@ -442,7 +441,7 @@ namespace nmos return data; } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncworker + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncworker web::json::value make_nc_worker(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled) { using web::json::value; @@ -453,13 +452,13 @@ namespace nmos return data; } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanager + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncmanager web::json::value make_nc_manager(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints) { return make_nc_object(class_id, oid, constant_oid, owner, role, user_label, touchpoints, runtime_property_constraints); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdevicemanager web::json::value make_nc_device_manager(nc_oid oid, nc_oid owner, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, const web::json::value& manufacturer, const web::json::value& product, const utility::string_t& serial_number, const web::json::value& user_inventory_code, const web::json::value& device_name, const web::json::value& device_role, const web::json::value& operational_state, nc_reset_cause::cause reset_cause) @@ -481,7 +480,7 @@ namespace nmos return data; } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncclassmanager web::json::value make_nc_class_manager(nc_oid oid, nc_oid owner, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, const nmos::experimental::control_protocol_state& control_protocol_state) { using web::json::value; @@ -508,7 +507,7 @@ namespace nmos return data; } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncpropertychangedeventdata + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncpropertychangedeventdata web::json::value make_nc_property_changed_event_data(const nc_property_changed_event_data& property_changed_event_data) { using web::json::value_of; @@ -614,7 +613,7 @@ namespace nmos }); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncobject web::json::value make_nc_object_properties() { using web::json::value; @@ -690,7 +689,7 @@ namespace nmos return events; } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncblock web::json::value make_nc_block_properties() { using web::json::value; @@ -741,7 +740,7 @@ namespace nmos return value::array(); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncworker + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncworker web::json::value make_nc_worker_properties() { using web::json::value; @@ -764,7 +763,7 @@ namespace nmos return value::array(); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanager + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncmanager web::json::value make_nc_manager_properties() { using web::json::value; @@ -784,7 +783,7 @@ namespace nmos return value::array(); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdevicemanager web::json::value make_nc_device_manager_properties() { using web::json::value; @@ -816,7 +815,7 @@ namespace nmos return value::array(); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncclassmanager web::json::value make_nc_class_manager_properties() { using web::json::value; @@ -926,7 +925,7 @@ namespace nmos return value::array(); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/classes/1.html web::json::value make_nc_object_class() { using web::json::value; @@ -934,7 +933,7 @@ namespace nmos return details::make_nc_class_descriptor(value::string(U("NcObject class descriptor")), nc_object_class_id, U("NcObject"), value::null(), make_nc_object_properties(), make_nc_object_methods(), make_nc_object_events()); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.1.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/classes/1.1.html web::json::value make_nc_block_class() { using web::json::value; @@ -942,7 +941,7 @@ namespace nmos return details::make_nc_class_descriptor(value::string(U("NcBlock class descriptor")), nc_block_class_id, U("NcBlock"), value::null(), make_nc_block_properties(), make_nc_block_methods(), make_nc_block_events()); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.2.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/classes/1.2.html web::json::value make_nc_worker_class() { using web::json::value; @@ -950,7 +949,7 @@ namespace nmos return details::make_nc_class_descriptor(value::string(U("NcWorker class descriptor")), nc_worker_class_id, U("NcWorker"), value::null(), make_nc_worker_properties(), make_nc_worker_methods(), make_nc_worker_events()); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.3.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/classes/1.3.html web::json::value make_nc_manager_class() { using web::json::value; @@ -958,7 +957,7 @@ namespace nmos return details::make_nc_class_descriptor(value::string(U("NcManager class descriptor")), nc_manager_class_id, U("NcManager"), value::null(), make_nc_manager_properties(), make_nc_manager_methods(), make_nc_manager_events()); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.3.1.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/classes/1.3.1.html web::json::value make_nc_device_manager_class() { using web::json::value; @@ -966,7 +965,7 @@ namespace nmos return details::make_nc_class_descriptor(value::string(U("NcDeviceManager class descriptor")), nc_device_manager_class_id, U("NcDeviceManager"), value::string(U("DeviceManager")), make_nc_device_manager_properties(), make_nc_device_manager_methods(), make_nc_device_manager_events()); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.3.2.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/classes/1.3.2.html web::json::value make_nc_class_manager_class() { using web::json::value; @@ -998,7 +997,7 @@ namespace nmos return details::make_nc_class_descriptor(value::string(U("NcReceiverMonitorProtected class descriptor")), nc_receiver_monitor_protected_class_id, U("NcReceiverMonitorProtected"), value::null(), make_nc_receiver_monitor_protected_properties(), make_nc_receiver_monitor_protected_methods(), make_nc_receiver_monitor_protected_events()); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcBlockMemberDescriptor.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcBlockMemberDescriptor.html web::json::value make_nc_block_member_descriptor_datatype() { using web::json::value; @@ -1013,7 +1012,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor which is specific to a block member")), U("NcBlockMemberDescriptor"), fields, value::string(U("NcDescriptor"))); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcClassDescriptor.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcClassDescriptor.html web::json::value make_nc_class_descriptor_datatype() { using web::json::value; @@ -1028,7 +1027,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class")), U("NcClassDescriptor"), fields, value::string(U("NcDescriptor"))); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcClassId.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcClassId.html web::json::value make_nc_class_id_datatype() { using web::json::value; @@ -1036,7 +1035,7 @@ namespace nmos return details::make_nc_datatype_typedef(value::string(U("Sequence of class ID fields")), U("NcClassId"), true, U("NcInt32")); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptor.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcDatatypeDescriptor.html web::json::value make_nc_datatype_descriptor_datatype() { using web::json::value; @@ -1048,7 +1047,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Base datatype descriptor")), U("NcDatatypeDescriptor"), fields, value::string(U("NcDescriptor"))); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptorEnum.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcDatatypeDescriptorEnum.html web::json::value make_nc_datatype_descriptor_enum_datatype() { using web::json::value; @@ -1058,7 +1057,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Enum datatype descriptor")), U("NcDatatypeDescriptorEnum"), fields, value::string(U("NcDatatypeDescriptor"))); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptorPrimitive.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcDatatypeDescriptorPrimitive.html web::json::value make_nc_datatype_descriptor_primitive_datatype() { using web::json::value; @@ -1067,7 +1066,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Primitive datatype descriptor")), U("NcDatatypeDescriptorPrimitive"), fields, value::string(U("NcDatatypeDescriptor"))); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptorStruct.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcDatatypeDescriptorStruct.html web::json::value make_nc_datatype_descriptor_struct_datatype() { using web::json::value; @@ -1078,7 +1077,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Struct datatype descriptor")), U("NcDatatypeDescriptorStruct"), fields, value::string(U("NcDatatypeDescriptor"))); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptorTypeDef.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcDatatypeDescriptorTypeDef.html web::json::value make_nc_datatype_descriptor_type_def_datatype() { using web::json::value; @@ -1089,7 +1088,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Type def datatype descriptor")), U("NcDatatypeDescriptorTypeDef"), fields, value::string(U("NcDatatypeDescriptor"))); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeType.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcDatatypeType.html web::json::value make_nc_datatype_type_datatype() { using web::json::value; @@ -1102,7 +1101,7 @@ namespace nmos return details::make_nc_datatype_descriptor_enum(value::string(U("Datatype type")), U("NcDatatypeType"), items); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDescriptor.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcDescriptor.html web::json::value make_nc_descriptor_datatype() { using web::json::value; @@ -1112,7 +1111,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Base descriptor")), U("NcDescriptor"), fields, value::null()); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDeviceGenericState.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcDeviceGenericState.html web::json::value make_nc_device_generic_state_datatype() { using web::json::value; @@ -1127,7 +1126,7 @@ namespace nmos return details::make_nc_datatype_descriptor_enum(value::string(U("Device generic operational state")), U("NcDeviceGenericState"), items); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDeviceOperationalState.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcDeviceOperationalState.html web::json::value make_nc_device_operational_state_datatype() { using web::json::value; @@ -1138,7 +1137,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Device operational state")), U("NcDeviceOperationalState"), fields, value::null()); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcElementId.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcElementId.html web::json::value make_nc_element_id_datatype() { using web::json::value; @@ -1149,7 +1148,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Class element id which contains the level and index")), U("NcElementId"), fields, value::null()); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcEnumItemDescriptor.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcEnumItemDescriptor.html web::json::value make_nc_enum_item_descriptor_datatype() { using web::json::value; @@ -1160,7 +1159,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of an enum item")), U("NcEnumItemDescriptor"), fields, value::string(U("NcDescriptor"))); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcEventDescriptor.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcEventDescriptor.html web::json::value make_nc_event_descriptor_datatype() { using web::json::value; @@ -1173,7 +1172,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class event")), U("NcEventDescriptor"), fields, value::string(U("NcDescriptor"))); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcEventId.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcEventId.html web::json::value make_nc_event_id_datatype() { using web::json::value; @@ -1181,7 +1180,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Event id which contains the level and index")), U("NcEventId"), value::array(), value::string(U("NcElementId"))); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcFieldDescriptor.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcFieldDescriptor.html web::json::value make_nc_field_descriptor_datatype() { using web::json::value; @@ -1195,7 +1194,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a field of a struct")), U("NcFieldDescriptor"), fields, value::string(U("NcDescriptor"))); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcId.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcId.html web::json::value make_nc_id_datatype() { using web::json::value; @@ -1203,7 +1202,7 @@ namespace nmos return details::make_nc_datatype_typedef(value::string(U("Identity handler")), U("NcId"), false, U("NcUint32")); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcManufacturer.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcManufacturer.html web::json::value make_nc_manufacturer_datatype() { using web::json::value; @@ -1215,7 +1214,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Manufacturer descriptor")), U("NcManufacturer"), fields, value::null()); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodDescriptor.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcMethodDescriptor.html web::json::value make_nc_method_descriptor_datatype() { using web::json::value; @@ -1229,7 +1228,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class method")), U("NcMethodDescriptor"), fields, value::string(U("NcDescriptor"))); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodId.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcMethodId.html web::json::value make_nc_method_id_datatype() { using web::json::value; @@ -1237,7 +1236,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Method id which contains the level and index")), U("NcMethodId"), value::array(), value::string(U("NcElementId"))); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResult.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcMethodResult.html web::json::value make_nc_method_result_datatype() { using web::json::value; @@ -1247,7 +1246,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Base result of the invoked method")), U("NcMethodResult"), fields, value::null()); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultBlockMemberDescriptors.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcMethodResultBlockMemberDescriptors.html web::json::value make_nc_method_result_block_member_descriptors_datatype() { using web::json::value; @@ -1257,7 +1256,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Method result containing block member descriptors as the value")), U("NcMethodResultBlockMemberDescriptors"), fields, value::string(U("NcMethodResult"))); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultClassDescriptor.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcMethodResultClassDescriptor.html web::json::value make_nc_method_result_class_descriptor_datatype() { using web::json::value; @@ -1267,7 +1266,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Method result containing a class descriptor as the value")), U("NcMethodResultClassDescriptor"), fields, value::string(U("NcMethodResult"))); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultDatatypeDescriptor.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcMethodResultDatatypeDescriptor.html web::json::value make_nc_method_result_datatype_descriptor_datatype() { using web::json::value; @@ -1277,7 +1276,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Method result containing a datatype descriptor as the value")), U("NcMethodResultDatatypeDescriptor"), fields, value::string(U("NcMethodResult"))); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultError.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcMethodResultError.html web::json::value make_nc_method_result_error_datatype() { using web::json::value; @@ -1287,7 +1286,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Error result - to be used when the method call encounters an error")), U("NcMethodResultError"), fields, value::string(U("NcMethodResult"))); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultId.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcMethodResultId.html web::json::value make_nc_method_result_id_datatype() { using web::json::value; @@ -1297,7 +1296,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Id method result")), U("NcMethodResultId"), fields, value::string(U("NcMethodResult"))); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultLength.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcMethodResultLength.html web::json::value make_nc_method_result_length_datatype() { using web::json::value; @@ -1307,7 +1306,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Length method result")), U("NcMethodResultLength"), fields, value::string(U("NcMethodResult"))); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultPropertyValue.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcMethodResultPropertyValue.html web::json::value make_nc_method_result_property_value_datatype() { using web::json::value; @@ -1317,7 +1316,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Result when invoking the getter method associated with a property")), U("NcMethodResultPropertyValue"), fields, value::string(U("NcMethodResult"))); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodStatus.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcMethodStatus.html web::json::value make_nc_method_status_datatype() { using web::json::value; @@ -1344,7 +1343,7 @@ namespace nmos return details::make_nc_datatype_descriptor_enum(value::string(U("Method invokation status")), U("NcMethodStatus"), items); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcName.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcName.html web::json::value make_nc_name_datatype() { using web::json::value; @@ -1352,7 +1351,7 @@ namespace nmos return details::make_nc_datatype_typedef(value::string(U("Programmatically significant name, alphanumerics + underscore, no spaces")), U("NcName"), false, U("NcString")); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcOid.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcOid.html web::json::value make_nc_oid_datatype() { using web::json::value; @@ -1360,7 +1359,7 @@ namespace nmos return details::make_nc_datatype_typedef(value::string(U("Object id")), U("NcOid"), false, U("NcUint32")); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcOrganizationId.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcOrganizationId.html web::json::value make_nc_organization_id_datatype() { using web::json::value; @@ -1368,7 +1367,7 @@ namespace nmos return details::make_nc_datatype_typedef(value::string(U("Unique 24-bit organization id")), U("NcOrganizationId"), false, U("NcInt32")); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcParameterConstraints.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcParameterConstraints.html web::json::value make_nc_parameter_constraints_datatype() { using web::json::value; @@ -1378,7 +1377,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Abstract parameter constraints class")), U("NcParameterConstraints"), fields, value::null()); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcParameterConstraintsNumber.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcParameterConstraintsNumber.html web::json::value make_nc_parameter_constraints_number_datatype() { using web::json::value; @@ -1390,7 +1389,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Number parameter constraints class")), U("NcParameterConstraintsNumber"), fields, value::string(U("NcParameterConstraints"))); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcParameterConstraintsString.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcParameterConstraintsString.html web::json::value make_nc_parameter_constraints_string_datatype() { using web::json::value; @@ -1401,7 +1400,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("String parameter constraints class")), U("NcParameterConstraintsString"), fields, value::string(U("NcParameterConstraints"))); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcParameterDescriptor.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcParameterDescriptor.html web::json::value make_nc_parameter_descriptor_datatype() { using web::json::value; @@ -1415,7 +1414,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a method parameter")), U("NcParameterDescriptor"), fields, value::string(U("NcDescriptor"))); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcProduct.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcProduct.html web::json::value make_nc_product_datatype() { using web::json::value; @@ -1430,7 +1429,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Product descriptor")), U("NcProduct"), fields, value::null()); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyChangeType.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcPropertyChangeType.html web::json::value make_nc_property_change_type_datatype() { using web::json::value; @@ -1443,7 +1442,7 @@ namespace nmos return details::make_nc_datatype_descriptor_enum(value::string(U("Type of property change")), U("NcPropertyChangeType"), items); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyChangedEventData.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcPropertyChangedEventData.html web::json::value make_nc_property_changed_event_data_datatype() { using web::json::value; @@ -1456,7 +1455,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Payload of property-changed event")), U("NcPropertyChangedEventData"), fields, value::null()); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyConstraints.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcPropertyConstraints.html web::json::value make_nc_property_contraints_datatype() { using web::json::value; @@ -1467,7 +1466,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Property constraints class")), U("NcPropertyConstraints"), fields, value::null()); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyConstraintsNumber.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcPropertyConstraintsNumber.html web::json::value make_nc_property_constraints_number_datatype() { using web::json::value; @@ -1479,7 +1478,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Number property constraints class")), U("NcPropertyConstraintsNumber"), fields, value::string(U("NcPropertyConstraints"))); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyConstraintsString.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcPropertyConstraintsString.html web::json::value make_nc_property_constraints_string_datatype() { using web::json::value; @@ -1490,7 +1489,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("String property constraints class")), U("NcPropertyConstraintsString"), fields, value::string(U("NcPropertyConstraints"))); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyDescriptor.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcPropertyDescriptor.html web::json::value make_nc_property_descriptor_datatype() { using web::json::value; @@ -1507,7 +1506,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class property")), U("NcPropertyDescriptor"), fields, value::string(U("NcDescriptor"))); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyId.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcPropertyId.html web::json::value make_nc_property_id_datatype() { using web::json::value; @@ -1515,7 +1514,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Property id which contains the level and index")), U("NcPropertyId"), value::array(), value::string(U("NcElementId"))); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcRegex.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcRegex.html web::json::value make_nc_regex_datatype() { using web::json::value; @@ -1523,7 +1522,7 @@ namespace nmos return details::make_nc_datatype_typedef(value::string(U("Regex pattern")), U("NcRegex"), false, U("NcString")); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcResetCause.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcResetCause.html web::json::value make_nc_reset_cause_datatype() { using web::json::value; @@ -1538,7 +1537,7 @@ namespace nmos return details::make_nc_datatype_descriptor_enum(value::string(U("Reset cause enum")), U("NcResetCause"), items); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcRolePath.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcRolePath.html web::json::value make_nc_role_path_datatype() { using web::json::value; @@ -1546,7 +1545,7 @@ namespace nmos return details::make_nc_datatype_typedef(value::string(U("Role path")), U("NcRolePath"), true, U("NcString")); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTimeInterval.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcTimeInterval.html web::json::value make_nc_time_interval_datatype() { using web::json::value; @@ -1554,7 +1553,7 @@ namespace nmos return details::make_nc_datatype_typedef(value::string(U("Time interval described in nanoseconds")), U("NcTimeInterval"), false, U("NcInt64")); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpoint.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcTouchpoint.html web::json::value make_nc_touchpoint_datatype() { using web::json::value; @@ -1564,7 +1563,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Base touchpoint class")), U("NcTouchpoint"), fields, value::null()); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointNmos.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcTouchpointNmos.html web::json::value make_nc_touchpoint_nmos_datatype() { using web::json::value; @@ -1574,7 +1573,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Touchpoint class for NMOS resources")), U("NcTouchpointNmos"), fields, value::string(U("NcTouchpoint"))); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointNmosChannelMapping.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcTouchpointNmosChannelMapping.html web::json::value make_nc_touchpoint_nmos_channel_mapping_datatype() { using web::json::value; @@ -1584,7 +1583,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Touchpoint class for NMOS IS-08 resources")), U("NcTouchpointNmosChannelMapping"), fields, value::string(U("NcTouchpoint"))); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointResource.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcTouchpointResource.html web::json::value make_nc_touchpoint_resource_datatype() { using web::json::value; @@ -1594,7 +1593,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Touchpoint resource class")), U("NcTouchpointResource"), fields, value::null()); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointResourceNmos.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcTouchpointResourceNmos.html web::json::value make_nc_touchpoint_resource_nmos_datatype() { using web::json::value; @@ -1604,7 +1603,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Touchpoint resource class for NMOS resources")), U("NcTouchpointResourceNmos"), fields, value::string(U("NcTouchpointResource"))); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointResourceNmosChannelMapping.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcTouchpointResourceNmosChannelMapping.html web::json::value make_nc_touchpoint_resource_nmos_channel_mapping_datatype() { using web::json::value; @@ -1614,7 +1613,7 @@ namespace nmos return details::make_nc_datatype_descriptor_struct(value::string(U("Touchpoint resource class for NMOS resources")), U("NcTouchpointResourceNmosChannelMapping"), fields, value::string(U("NcTouchpointResourceNmos"))); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcUri.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcUri.html web::json::value make_nc_uri_datatype() { using web::json::value; @@ -1622,7 +1621,7 @@ namespace nmos return details::make_nc_datatype_typedef(value::string(U("Uniform resource identifier")), U("NcUri"), false, U("NcString")); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcUuid.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcUuid.html web::json::value make_nc_uuid_datatype() { using web::json::value; @@ -1630,7 +1629,7 @@ namespace nmos return details::make_nc_datatype_typedef(value::string(U("UUID")), U("NcUuid"), false, U("NcString")); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcVersionCode.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcVersionCode.html web::json::value make_nc_version_code_datatype() { using web::json::value; diff --git a/Development/nmos/control_protocol_resource.h b/Development/nmos/control_protocol_resource.h index f40234977..bff521676 100644 --- a/Development/nmos/control_protocol_resource.h +++ b/Development/nmos/control_protocol_resource.h @@ -21,91 +21,91 @@ namespace nmos namespace details { - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncelementid + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncelementid //web::json::value make_nc_element_id(uint16_t level, uint16_t index); web::json::value make_nc_element_id(const nc_element_id& element_id); nc_element_id parse_nc_element_id(const web::json::value& element_id); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#nceventid + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#nceventid //web::json::value make_nc_event_id(uint16_t level, uint16_t index); web::json::value make_nc_event_id(const nc_event_id& event_id); nc_event_id parse_nc_event_id(const web::json::value& event_id); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmethodid + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncmethodid web::json::value make_nc_method_id(const nc_method_id& method_id); nc_method_id parse_nc_method_id(const web::json::value& method_id); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncpropertyid + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncpropertyid web::json::value make_nc_property_id(const nc_property_id& property_id); nc_property_id parse_nc_property_id(const web::json::value& property_id); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassid + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncclassid web::json::value make_nc_class_id(const nc_class_id& class_id); nc_class_id parse_nc_class_id(const web::json::array& class_id); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanufacturer + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncmanufacturer web::json::value make_nc_manufacturer(const utility::string_t& name, const web::json::value& organization_id = web::json::value::null(), const web::json::value& website = web::json::value::null()); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncproduct + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncproduct // brand_name can be null // uuid can be null // description can be null web::json::value make_nc_product(const utility::string_t& name, const utility::string_t& key, const utility::string_t& revision_level, const web::json::value& brand_name = web::json::value::null(), const web::json::value& uuid = web::json::value::null(), const web::json::value& description = web::json::value::null()); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdeviceoperationalstate + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdeviceoperationalstate // device_specific_details can be null web::json::value make_nc_device_operational_state(nc_device_generic_state::state generic_state, const web::json::value& device_specific_details); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdescriptor + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdescriptor // description can be null web::json::value make_nc_descriptor(const web::json::value& description); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblockmemberdescriptor + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncblockmemberdescriptor // description can be null // user_label can be null web::json::value make_nc_block_member_descriptor(const web::json::value& description, const utility::string_t& role, nc_oid oid, bool constant_oid, const nc_class_id& class_id, const web::json::value& user_label, nc_oid owner); web::json::value make_nc_block_member_descriptor(const utility::string_t& description, const utility::string_t& role, nc_oid oid, bool constant_oid, const nc_class_id& class_id, const utility::string_t& user_label, nc_oid owner); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassdescriptor + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncclassdescriptor // description can be null // fixedRole can be null web::json::value make_nc_class_descriptor(const web::json::value& description, const nc_class_id& class_id, const nc_name& name, const web::json::value& fixed_role, const web::json::value& properties, const web::json::value& methods, const web::json::value& events); web::json::value make_nc_class_descriptor(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const web::json::value& fixed_role, const web::json::value& properties, const web::json::value& methods, const web::json::value& events); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncenumitemdescriptor + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncenumitemdescriptor // description can be null web::json::value make_nc_enum_item_descriptor(const web::json::value& description, const nc_name& name, uint16_t val); web::json::value make_nc_enum_item_descriptor(const utility::string_t& description, const nc_name& name, uint16_t val); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#nceventdescriptor + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#nceventdescriptor // description can be null // id = make_nc_event_id(level, index) web::json::value make_nc_event_descriptor(const web::json::value& description, const nc_event_id& id, const nc_name& name, const utility::string_t& event_datatype, bool is_deprecated); web::json::value make_nc_event_descriptor(const utility::string_t& description, const nc_event_id& id, const nc_name& name, const utility::string_t& event_datatype, bool is_deprecated); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncfielddescriptor + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncfielddescriptor // description can be null // type_name can be null // constraints can be null web::json::value make_nc_field_descriptor(const web::json::value& description, const nc_name& name, const web::json::value& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints = web::json::value::null()); web::json::value make_nc_field_descriptor(const utility::string_t& description, const nc_name& name, const utility::string_t& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints = web::json::value::null()); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmethoddescriptor + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncmethoddescriptor // description can be null // id = make_nc_method_id(level, index) // sequence parameters web::json::value make_nc_method_descriptor(const web::json::value& description, const nc_method_id& id, const nc_name& name, const utility::string_t& result_datatype, const web::json::value& parameters, bool is_deprecated); web::json::value make_nc_method_descriptor(const utility::string_t& description, const nc_method_id& id, const nc_name& name, const utility::string_t& result_datatype, const web::json::value& parameters, bool is_deprecated); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncparameterdescriptor + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterdescriptor // description can be null // type_name can be null web::json::value make_nc_parameter_descriptor(const web::json::value& description, const nc_name& name, const web::json::value& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints = web::json::value::null()); web::json::value make_nc_parameter_descriptor(const utility::string_t& description, const nc_name& name, bool is_nullable, bool is_sequence, const web::json::value& constraints = web::json::value::null()); web::json::value make_nc_parameter_descriptor(const utility::string_t& description, const nc_name& name, const utility::string_t& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints = web::json::value::null()); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncpropertydescriptor + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncpropertydescriptor // description can be null // id = make_nc_property_id(level, index); // type_name can be null @@ -115,52 +115,52 @@ namespace nmos web::json::value make_nc_property_descriptor(const utility::string_t& description, const nc_property_id& id, const nc_name& name, const utility::string_t& type_name, bool is_read_only, bool is_nullable, bool is_sequence, bool is_deprecated, const web::json::value& constraints = web::json::value::null()); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptor + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdatatypedescriptor // description can be null // constraints can be null web::json::value make_nc_datatype_descriptor(const web::json::value& description, const nc_name& name, nc_datatype_type::type type, const web::json::value& constraints = web::json::value::null()); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptorenum + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdatatypedescriptorenum // description can be null // constraints can be null // items: sequence web::json::value make_nc_datatype_descriptor_enum(const web::json::value& description, const nc_name& name, const web::json::value& items, const web::json::value& constraints = web::json::value::null()); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptorprimitive + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdatatypedescriptorprimitive // description can be null // constraints can be null web::json::value make_nc_datatype_descriptor_primitive(const web::json::value& description, const nc_name& name, const web::json::value& constraints = web::json::value::null()); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptorstruct + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdatatypedescriptorstruct // description can be null // constraints can be null // fields: sequence // parent_type can be null web::json::value make_nc_datatype_descriptor_struct(const web::json::value& description, const nc_name& name, const web::json::value& fields, const web::json::value& parent_type, const web::json::value& constraints = web::json::value::null()); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdatatypedescriptortypedef + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdatatypedescriptortypedef // description can be null // constraints can be null web::json::value make_nc_datatype_typedef(const web::json::value& description, const nc_name& name, bool is_sequence, const utility::string_t& parent_type, const web::json::value& constraints = web::json::value::null()); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncobject web::json::value make_nc_object(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncblock web::json::value make_nc_block(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled, const web::json::value& members); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncworker + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncworker web::json::value make_nc_worker(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanager + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncmanager web::json::value make_nc_manager(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdevicemanager web::json::value make_nc_device_manager(nc_oid oid, nc_oid owner, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, const web::json::value& manufacturer, const web::json::value& product, const utility::string_t& serial_number, const web::json::value& user_inventory_code, const web::json::value& device_name, const web::json::value& device_role, const web::json::value& operational_state, nc_reset_cause::cause reset_cause); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncclassmanager web::json::value make_nc_class_manager(nc_oid oid, nc_oid owner, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, const nmos::experimental::control_protocol_state& control_protocol_state); } @@ -182,23 +182,23 @@ namespace nmos web::json::value make_control_protocol_notification(const web::json::value& notifications); // error message - // See https://specs.amwa.tv/is-12/branches/v1.0-dev/docs/Protocol_messaging.html#error-messages + // See https://specs.amwa.tv/is-12/branches/v1.0.x/docs/Protocol_messaging.html#error-messages web::json::value make_control_protocol_error_message(const nc_method_result& method_result, const utility::string_t& error_message); // Control class models - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/#control-class-models-for-branch-v10-dev + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/classes/#control-class-models-for-branch-v10-dev // - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/classes/1.html web::json::value make_nc_object_class(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.1.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/classes/1.1.html web::json::value make_nc_block_class(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.2.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/classes/1.2.html web::json::value make_nc_worker_class(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.3.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/classes/1.3.html web::json::value make_nc_manager_class(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.3.1.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/classes/1.3.1.html web::json::value make_nc_device_manager_class(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/1.3.2.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/classes/1.3.2.html web::json::value make_nc_class_manager_class(); // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/identification/#ncidentbeacon web::json::value make_nc_ident_beacon_class(); @@ -208,27 +208,27 @@ namespace nmos web::json::value make_nc_receiver_monitor_protected_class(); // control classes proprties/methods/events - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncobject + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncobject web::json::value make_nc_object_properties(); web::json::value make_nc_object_methods(); web::json::value make_nc_object_events(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncblock + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncblock web::json::value make_nc_block_properties(); web::json::value make_nc_block_methods(); web::json::value make_nc_block_events(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncworker + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncworker web::json::value make_nc_worker_properties(); web::json::value make_nc_worker_methods(); web::json::value make_nc_worker_events(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmanager + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncmanager web::json::value make_nc_manager_properties(); web::json::value make_nc_manager_methods(); web::json::value make_nc_manager_events(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdevicemanager web::json::value make_nc_device_manager_properties(); web::json::value make_nc_device_manager_methods(); web::json::value make_nc_device_manager_events(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncclassmanager web::json::value make_nc_class_manager_properties(); web::json::value make_nc_class_manager_methods(); web::json::value make_nc_class_manager_events(); @@ -246,123 +246,123 @@ namespace nmos web::json::value make_nc_ident_beacon_events(); // Datatype models - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/#datatype-models-for-branch-v10-dev + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/#datatype-models-for-branch-v10-dev // - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcBlockMemberDescriptor.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcBlockMemberDescriptor.html web::json::value make_nc_block_member_descriptor_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcClassDescriptor.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcClassDescriptor.html web::json::value make_nc_class_descriptor_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcClassId.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcClassId.html web::json::value make_nc_class_id_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptor.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcDatatypeDescriptor.html web::json::value make_nc_datatype_descriptor_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptorEnum.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcDatatypeDescriptorEnum.html web::json::value make_nc_datatype_descriptor_enum_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptorPrimitive.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcDatatypeDescriptorPrimitive.html web::json::value make_nc_datatype_descriptor_primitive_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptorStruct.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcDatatypeDescriptorStruct.html web::json::value make_nc_datatype_descriptor_struct_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeDescriptorTypeDef.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcDatatypeDescriptorTypeDef.html web::json::value make_nc_datatype_descriptor_type_def_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDatatypeType.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcDatatypeType.html web::json::value make_nc_datatype_type_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDescriptor.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcDescriptor.html web::json::value make_nc_descriptor_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDeviceGenericState.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcDeviceGenericState.html web::json::value make_nc_device_generic_state_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcDeviceOperationalState.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcDeviceOperationalState.html web::json::value make_nc_device_operational_state_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcElementId.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcElementId.html web::json::value make_nc_element_id_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcEnumItemDescriptor.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcEnumItemDescriptor.html web::json::value make_nc_enum_item_descriptor_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcEventDescriptor.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcEventDescriptor.html web::json::value make_nc_event_descriptor_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcEventId.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcEventId.html web::json::value make_nc_event_id_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcFieldDescriptor.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcFieldDescriptor.html web::json::value make_nc_field_descriptor_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcId.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcId.html web::json::value make_nc_id_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcManufacturer.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcManufacturer.html web::json::value make_nc_manufacturer_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodDescriptor.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcMethodDescriptor.html web::json::value make_nc_method_descriptor_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodId.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcMethodId.html web::json::value make_nc_method_id_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResult.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcMethodResult.html web::json::value make_nc_method_result_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultBlockMemberDescriptors.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcMethodResultBlockMemberDescriptors.html web::json::value make_nc_method_result_block_member_descriptors_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultClassDescriptor.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcMethodResultClassDescriptor.html web::json::value make_nc_method_result_class_descriptor_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultDatatypeDescriptor.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcMethodResultDatatypeDescriptor.html web::json::value make_nc_method_result_datatype_descriptor_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultError.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcMethodResultError.html web::json::value make_nc_method_result_error_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultId.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcMethodResultId.html web::json::value make_nc_method_result_id_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultLength.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcMethodResultLength.html web::json::value make_nc_method_result_length_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodResultPropertyValue.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcMethodResultPropertyValue.html web::json::value make_nc_method_result_property_value_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcMethodStatus.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcMethodStatus.html web::json::value make_nc_method_status_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcName.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcName.html web::json::value make_nc_name_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcOid.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcOid.html web::json::value make_nc_oid_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcOrganizationId.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcOrganizationId.html web::json::value make_nc_organization_id_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcParameterConstraints.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcParameterConstraints.html web::json::value make_nc_parameter_constraints_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcParameterConstraintsNumber.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcParameterConstraintsNumber.html web::json::value make_nc_parameter_constraints_number_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcParameterConstraintsString.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcParameterConstraintsString.html web::json::value make_nc_parameter_constraints_string_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcParameterDescriptor.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcParameterDescriptor.html web::json::value make_nc_parameter_descriptor_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcProduct.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcProduct.html web::json::value make_nc_product_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyChangeType.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcPropertyChangeType.html web::json::value make_nc_property_change_type_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyChangedEventData.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcPropertyChangedEventData.html web::json::value make_nc_property_changed_event_data_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyConstraints.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcPropertyConstraints.html web::json::value make_nc_property_contraints_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyConstraintsNumber.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcPropertyConstraintsNumber.html web::json::value make_nc_property_constraints_number_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyConstraintsString.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcPropertyConstraintsString.html web::json::value make_nc_property_constraints_string_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyDescriptor.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcPropertyDescriptor.html web::json::value make_nc_property_descriptor_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcPropertyId.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcPropertyId.html web::json::value make_nc_property_id_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcRegex.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcRegex.html web::json::value make_nc_regex_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcResetCause.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcResetCause.html web::json::value make_nc_reset_cause_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcRolePath.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcRolePath.html web::json::value make_nc_role_path_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTimeInterval.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcTimeInterval.html web::json::value make_nc_time_interval_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpoint.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcTouchpoint.html web::json::value make_nc_touchpoint_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointNmos.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcTouchpointNmos.html web::json::value make_nc_touchpoint_nmos_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointNmosChannelMapping.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcTouchpointNmosChannelMapping.html web::json::value make_nc_touchpoint_nmos_channel_mapping_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointResource.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcTouchpointResource.html web::json::value make_nc_touchpoint_resource_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointResourceNmos.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcTouchpointResourceNmos.html web::json::value make_nc_touchpoint_resource_nmos_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcTouchpointResourceNmosChannelMapping.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcTouchpointResourceNmosChannelMapping.html web::json::value make_nc_touchpoint_resource_nmos_channel_mapping_datatype(); - // See // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcUri.html + // See // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcUri.html web::json::value make_nc_uri_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcUuid.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcUuid.html web::json::value make_nc_uuid_datatype(); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/NcVersionCode.html + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcVersionCode.html web::json::value make_nc_version_code_datatype(); // Monitoring datatypes diff --git a/Development/nmos/control_protocol_resources.cpp b/Development/nmos/control_protocol_resources.cpp index 48b6e7d1f..b7e28fd29 100644 --- a/Development/nmos/control_protocol_resources.cpp +++ b/Development/nmos/control_protocol_resources.cpp @@ -37,7 +37,7 @@ namespace nmos return details::make_block(1, value::null(), U("root"), U("Root"), value::null(), value::null(), value::array()); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdevicemanager resource make_device_manager(nc_oid oid, const nmos::settings& settings) { using web::json::value; @@ -56,7 +56,7 @@ namespace nmos return{ is12_versions::v1_0, types::nc_object, std::move(data), true }; } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassmanager + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncclassmanager resource make_class_manager(nc_oid oid, const nmos::experimental::control_protocol_state& control_protocol_state) { using web::json::value; diff --git a/Development/nmos/control_protocol_state.cpp b/Development/nmos/control_protocol_state.cpp index c308ad26d..f9a24eb65 100644 --- a/Development/nmos/control_protocol_state.cpp +++ b/Development/nmos/control_protocol_state.cpp @@ -116,7 +116,7 @@ namespace nmos control_classes = { // Control class models - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/classes/#control-class-models-for-branch-v10-dev + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/classes/#control-class-models-for-branch-v10-dev { nc_object_class_id, make_control_class(U("NcObject class descriptor"), nc_object_class_id, U("NcObject"), to_vector(make_nc_object_properties()), to_methods_vector(make_nc_object_methods(), { @@ -161,7 +161,7 @@ namespace nmos datatypes = { // Dataype models - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/models/datatypes/#datatype-models-for-branch-v10-dev + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/#datatype-models-for-branch-v10-dev { U("NcClassId"), {make_nc_class_id_datatype()} }, { U("NcOid"), {make_nc_oid_datatype()} }, { U("NcTouchpoint"), {make_nc_touchpoint_datatype()} }, diff --git a/Development/nmos/control_protocol_typedefs.h b/Development/nmos/control_protocol_typedefs.h index 9c0962742..92e655df2 100644 --- a/Development/nmos/control_protocol_typedefs.h +++ b/Development/nmos/control_protocol_typedefs.h @@ -46,7 +46,7 @@ namespace nmos }; } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmethodresult + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncmethodresult struct nc_method_result { nc_method_status::status status; @@ -119,7 +119,7 @@ namespace nmos } // NcElementId - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncelementid + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncelementid struct nc_element_id { uint16_t level; @@ -137,14 +137,14 @@ namespace nmos }; // NcEventId - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#nceventid + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#nceventid typedef nc_element_id nc_event_id; // NcEventIds for NcObject // SEe https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncobject const nc_event_id nc_object_property_changed_event_id(1, 1); // NcMethodId - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncmethodid + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncmethodid typedef nc_element_id nc_method_id; // NcMethodIds for NcObject // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncobject @@ -167,7 +167,7 @@ namespace nmos const nc_method_id nc_class_manager_get_datatype_method_id(3, 2); // NcPropertyId - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncpropertyid + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncpropertyid typedef nc_element_id nc_property_id; // NcPropertyIds for NcObject // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncobject @@ -216,29 +216,29 @@ namespace nmos const nc_property_id nc_ident_beacon_active_property_id(3, 1); // NcId - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncid + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncid typedef uint32_t nc_id; // NcName - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncname + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncname typedef utility::string_t nc_name; // NcOid - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncoid + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncoid typedef uint32_t nc_oid; // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Blocks.html const nc_oid root_block_oid{ 1 }; // NcUri - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncuri + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncuri typedef utility::string_t nc_uri; // NcUuid - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncuuid + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncuuid typedef utility::string_t nc_uuid; // NcClassId - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncclassid + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncclassid typedef std::vector nc_class_id; // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncobject const nc_class_id nc_object_class_id({ 1 }); @@ -260,11 +260,11 @@ namespace nmos const nc_class_id nc_receiver_monitor_protected_class_id({ 1, 2, 3, 1 }); // NcTouchpoint - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#nctouchpoint + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#nctouchpoint typedef utility::string_t nc_touch_point; // NcPropertyChangeType - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncpropertychangetype + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncpropertychangetype namespace nc_property_change_type { enum type @@ -277,7 +277,7 @@ namespace nmos } // NcPropertyChangedEventData - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncpropertychangedeventdata + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncpropertychangedeventdata struct nc_property_changed_event_data { nc_property_id property_id; diff --git a/Development/nmos/settings.h b/Development/nmos/settings.h index 467c7c0e2..94c9d6f7a 100644 --- a/Development/nmos/settings.h +++ b/Development/nmos/settings.h @@ -366,17 +366,17 @@ namespace nmos const web::json::field_as_integer_or ocsp_request_max{ U("ocsp_request_max"), 30 }; // manufacturer_name [node]: the manufacturer name of the NcDeviceManager used for NMOS Control Protocol - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdevicemanager const web::json::field_as_string_or manufacturer_name{ U("manufacturer_name"), U("") }; // product_name/product_key/product_revision_level [node]: the product description of the NcDeviceManager used for NMOS Control Protocol - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncproduct + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncproduct const web::json::field_as_string_or product_name{ U("product_name"), U("") }; const web::json::field_as_string_or product_key{ U("product_key"), U("") }; const web::json::field_as_string_or product_revision_level{ U("product_revision_level"), U("") }; // serial_number [node]: the serial number of the NcDeviceManager used for NMOS Control Protocol - // See https://specs.amwa.tv/ms-05-02/branches/v1.0-dev/docs/Framework.html#ncdevicemanager + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdevicemanager const web::json::field_as_string_or serial_number{ U("serial_number"), U("") }; } } From ec516384c9d818b642650c1aa238f531a0f496db Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 19 Sep 2023 00:12:12 +0100 Subject: [PATCH 046/106] Tidy up, less casting --- .../nmos-cpp-node/node_implementation.cpp | 20 +- .../nmos/control_protocol_resource.cpp | 518 ++++++++++-------- Development/nmos/control_protocol_resource.h | 30 +- 3 files changed, 305 insertions(+), 263 deletions(-) diff --git a/Development/nmos-cpp-node/node_implementation.cpp b/Development/nmos-cpp-node/node_implementation.cpp index 8039782f9..8d3588c6e 100644 --- a/Development/nmos-cpp-node/node_implementation.cpp +++ b/Development/nmos-cpp-node/node_implementation.cpp @@ -1025,28 +1025,28 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr using web::json::value; auto items = value::array(); - web::json::push_back(items, nmos::details::make_nc_enum_item_descriptor(value::string(U("Undefined")), U("Undefined"), example_enum::Undefined)); - web::json::push_back(items, nmos::details::make_nc_enum_item_descriptor(value::string(U("Alpha")), U("Alpha"), example_enum::Alpha)); - web::json::push_back(items, nmos::details::make_nc_enum_item_descriptor(value::string(U("Beta")), U("Beta"), example_enum::Beta)); - web::json::push_back(items, nmos::details::make_nc_enum_item_descriptor(value::string(U("Gamma")), U("Gamma"), example_enum::Gamma)); - return nmos::details::make_nc_datatype_descriptor_enum(value::string(U("Example enum datatype")), U("ExampleEnum"), items); + web::json::push_back(items, nmos::details::make_nc_enum_item_descriptor(U("Undefined"), U("Undefined"), example_enum::Undefined)); + web::json::push_back(items, nmos::details::make_nc_enum_item_descriptor(U("Alpha"), U("Alpha"), example_enum::Alpha)); + web::json::push_back(items, nmos::details::make_nc_enum_item_descriptor(U("Beta"), U("Beta"), example_enum::Beta)); + web::json::push_back(items, nmos::details::make_nc_enum_item_descriptor(U("Gamma"), U("Gamma"), example_enum::Gamma)); + return nmos::details::make_nc_datatype_descriptor_enum(U("Example enum datatype"), U("ExampleEnum"), items, value::null()); }; auto make_example_datatype_datatype = [&]() { using web::json::value; auto fields = value::array(); - web::json::push_back(fields, nmos::details::make_nc_field_descriptor(value::string(U("Enum property example")), enum_property, value::string(U("ExampleEnum")), false, false)); + web::json::push_back(fields, nmos::details::make_nc_field_descriptor(U("Enum property example"), enum_property, U("ExampleEnum"), false, false, value::null())); { value constraints = value::null(); // todo constraints - web::json::push_back(fields, nmos::details::make_nc_field_descriptor(value::string(U("String property example")), string_property, value::string(U("NcString")), false, false, constraints)); + web::json::push_back(fields, nmos::details::make_nc_field_descriptor(U("String property example"), string_property, U("NcString"), false, false, constraints)); } { value constraints = value::null(); // todo constraints - web::json::push_back(fields, nmos::details::make_nc_field_descriptor(value::string(U("Number property example")), number_property, value::string(U("NcUint64")), false, false, constraints)); + web::json::push_back(fields, nmos::details::make_nc_field_descriptor(U("Number property example"), number_property, U("NcUint64"), false, false, constraints)); } - web::json::push_back(fields, nmos::details::make_nc_field_descriptor(value::string(U("Boolean property example")), boolean_property, value::string(U("NcBoolean")), false, false)); - return nmos::details::make_nc_datatype_descriptor_struct(value::string(U("Example data type")), U("ExampleDataType"), fields, value::null()); + web::json::push_back(fields, nmos::details::make_nc_field_descriptor(U("Boolean property example"), boolean_property, U("NcBoolean"), false, false, value::null())); + return nmos::details::make_nc_datatype_descriptor_struct(U("Example data type"), U("ExampleDataType"), fields, value::null()); }; control_protocol_state.insert(nmos::experimental::datatype{ make_example_enum_datatype() }); control_protocol_state.insert(nmos::experimental::datatype{ make_example_datatype_datatype() }); diff --git a/Development/nmos/control_protocol_resource.cpp b/Development/nmos/control_protocol_resource.cpp index 74d934c68..8d89358b2 100644 --- a/Development/nmos/control_protocol_resource.cpp +++ b/Development/nmos/control_protocol_resource.cpp @@ -263,6 +263,12 @@ namespace nmos return make_nc_field_descriptor(value::string(description), name, value::string(type_name), is_nullable, is_sequence, constraints); } + web::json::value make_nc_field_descriptor(const utility::string_t& description, const nc_name& name, bool is_nullable, bool is_sequence, const web::json::value& constraints) + { + using web::json::value; + + return make_nc_field_descriptor(value::string(description), name, value::null(), is_nullable, is_sequence, constraints); + } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncmethoddescriptor // description can be null @@ -371,6 +377,12 @@ namespace nmos return data; } + web::json::value make_nc_datatype_descriptor_enum(const utility::string_t& description, const nc_name& name, const web::json::value& items, const web::json::value& constraints) + { + using web::json::value; + + return make_nc_datatype_descriptor_enum(value::string(description), name, items, constraints); + } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdatatypedescriptorprimitive // description can be null @@ -379,6 +391,12 @@ namespace nmos { return make_nc_datatype_descriptor(description, name, nc_datatype_type::Primitive, constraints); } + web::json::value make_nc_datatype_descriptor_primitive(const utility::string_t& description, const nc_name& name, const web::json::value& constraints) + { + using web::json::value; + + return make_nc_datatype_descriptor_primitive(value::string(description), name, constraints); + } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdatatypedescriptorstruct // description can be null @@ -393,6 +411,18 @@ namespace nmos return data; } + web::json::value make_nc_datatype_descriptor_struct(const utility::string_t& description, const nc_name& name, const web::json::value& fields, const utility::string_t& parent_type, const web::json::value& constraints) + { + using web::json::value; + + return make_nc_datatype_descriptor_struct(value::string(description), name, fields, value::string(parent_type), constraints); + } + web::json::value make_nc_datatype_descriptor_struct(const utility::string_t& description, const nc_name& name, const web::json::value& fields, const web::json::value& constraints) + { + using web::json::value; + + return make_nc_datatype_descriptor_struct(value::string(description), name, fields, value::null(), constraints); + } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdatatypedescriptortypedef // description can be null @@ -407,6 +437,12 @@ namespace nmos return data; } + web::json::value make_nc_datatype_typedef(const utility::string_t& description, const nc_name& name, bool is_sequence, const utility::string_t& parent_type, const web::json::value& constraints) + { + using web::json::value; + + return make_nc_datatype_typedef(value::string(description), name, is_sequence, parent_type, constraints); + } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncobject web::json::value make_nc_object(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints) @@ -619,14 +655,14 @@ namespace nmos using web::json::value; auto properties = value::array(); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Static value. All instances of the same class will have the same identity value"), nc_object_class_id_property_id, nmos::fields::nc::class_id, U("NcClassId"), true, false, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Object identifier"), nc_object_oid_property_id, nmos::fields::nc::oid, U("NcOid"), true, false, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("TRUE iff OID is hardwired into device"), nc_object_constant_oid_property_id, nmos::fields::nc::constant_oid, U("NcBoolean"), true, false, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("OID of containing block. Can only ever be null for the root block"), nc_object_owner_property_id, nmos::fields::nc::owner, U("NcOid"), true, true, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Role of object in the containing block"), nc_object_role_property_id, nmos::fields::nc::role, U("NcString"), true, false, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Scribble strip"), nc_object_user_label_property_id, nmos::fields::nc::user_label, U("NcString"), false, true, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Touchpoints to other contexts"), nc_object_touchpoints_property_id, nmos::fields::nc::touchpoints, U("NcTouchpoint"), true, true, true, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Runtime property constraints"), nc_object_runtime_property_constraints_property_id, nmos::fields::nc::runtime_property_constraints, U("NcPropertyConstraints"), true, true, true, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Static value. All instances of the same class will have the same identity value"), nc_object_class_id_property_id, nmos::fields::nc::class_id, U("NcClassId"), true, false, false, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Object identifier"), nc_object_oid_property_id, nmos::fields::nc::oid, U("NcOid"), true, false, false, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(U("TRUE iff OID is hardwired into device"), nc_object_constant_oid_property_id, nmos::fields::nc::constant_oid, U("NcBoolean"), true, false, false, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(U("OID of containing block. Can only ever be null for the root block"), nc_object_owner_property_id, nmos::fields::nc::owner, U("NcOid"), true, true, false, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Role of object in the containing block"), nc_object_role_property_id, nmos::fields::nc::role, U("NcString"), true, false, false, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Scribble strip"), nc_object_user_label_property_id, nmos::fields::nc::user_label, U("NcString"), false, true, false, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Touchpoints to other contexts"), nc_object_touchpoints_property_id, nmos::fields::nc::touchpoints, U("NcTouchpoint"), true, true, true, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Runtime property constraints"), nc_object_runtime_property_constraints_property_id, nmos::fields::nc::runtime_property_constraints, U("NcPropertyConstraints"), true, true, true, false, value::null())); return properties; } @@ -643,7 +679,7 @@ namespace nmos { auto parameters = value::array(); web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Property id"), nmos::fields::nc::id, U("NcPropertyId"), false, false, value::null())); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Property value"), nmos::fields::nc::value, true, false)); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Property value"), nmos::fields::nc::value, true, false, value::null())); web::json::push_back(methods, details::make_nc_method_descriptor(U("Set property value"), nc_object_set_method_id, U("Set"), U("NcMethodResult"), parameters, false)); } { @@ -656,13 +692,13 @@ namespace nmos auto parameters = value::array(); web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Property id"), nmos::fields::nc::id, U("NcPropertyId"), false, false, value::null())); web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Index of item in the sequence"), nmos::fields::nc::index, U("NcId"), false, false, value::null())); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Value"), nmos::fields::nc::value, true, false)); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Value"), nmos::fields::nc::value, true, false, value::null())); web::json::push_back(methods, details::make_nc_method_descriptor(U("Set sequence item value"), nc_object_set_sequence_item_method_id, U("SetSequenceItem"), U("NcMethodResult"), parameters, false)); } { auto parameters = value::array(); web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Property id"), nmos::fields::nc::id,U("NcPropertyId"), false, false, value::null())); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Value"), nmos::fields::nc::value, true, false)); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("Value"), nmos::fields::nc::value, true, false, value::null())); web::json::push_back(methods, details::make_nc_method_descriptor(U("Add item to sequence"), nc_object_add_sequence_item_method_id, U("AddSequenceItem"), U("NcMethodResultId"), parameters, false)); } { @@ -695,8 +731,8 @@ namespace nmos using web::json::value; auto properties = value::array(); - web::json::push_back(properties, details::make_nc_property_descriptor(U("TRUE if block is functional"), nc_block_enabled_property_id, nmos::fields::nc::enabled, U("NcBoolean"), true, false, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Descriptors of this block's members"), nc_block_members_property_id, nmos::fields::nc::members, U("NcBlockMemberDescriptor"), true, false, true, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("TRUE if block is functional"), nc_block_enabled_property_id, nmos::fields::nc::enabled, U("NcBoolean"), true, false, false, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Descriptors of this block's members"), nc_block_members_property_id, nmos::fields::nc::members, U("NcBlockMemberDescriptor"), true, false, true, false, value::null())); return properties; } @@ -746,7 +782,7 @@ namespace nmos using web::json::value; auto properties = value::array(); - web::json::push_back(properties, details::make_nc_property_descriptor(U("TRUE iff worker is enabled"), nc_worker_enabled_property_id, nmos::fields::nc::enabled, U("NcBoolean"), false, false, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("TRUE iff worker is enabled"), nc_worker_enabled_property_id, nmos::fields::nc::enabled, U("NcBoolean"), false, false, false, false, value::null())); return properties; } @@ -789,16 +825,16 @@ namespace nmos using web::json::value; auto properties = value::array(); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Version of MS-05-02 that this device uses"), nc_device_manager_nc_version_property_id, nmos::fields::nc::nc_version, U("NcVersionCode"), true, false, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Manufacturer descriptor"), nc_device_manager_manufacturer_property_id, nmos::fields::nc::manufacturer, U("NcManufacturer"), true, false, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Product descriptor"), nc_device_manager_product_property_id, nmos::fields::nc::product, U("NcProduct"), true, false, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Serial number"), nc_device_manager_serial_number_property_id, nmos::fields::nc::serial_number, U("NcString"), true, false, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Asset tracking identifier (user specified)"), nc_device_manager_user_inventory_code_property_id, nmos::fields::nc::user_inventory_code, U("NcString"), false, true, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Name of this device in the application. Instance name, not product name"), nc_device_manager_device_name_property_id, nmos::fields::nc::device_name, U("NcString"), false, true, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Role of this device in the application"), nc_device_manager_device_role_property_id, nmos::fields::nc::device_role, U("NcString"), false, true, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Device operational state"), nc_device_manager_operational_state_property_id, nmos::fields::nc::operational_state, U("NcDeviceOperationalState"), true, false, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Reason for most recent reset"), nc_device_manager_reset_cause_property_id, nmos::fields::nc::reset_cause, U("NcResetCause"), true, false, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Arbitrary message from dev to controller"), nc_device_manager_message_property_id, nmos::fields::nc::message, U("NcString"), true, true, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Version of MS-05-02 that this device uses"), nc_device_manager_nc_version_property_id, nmos::fields::nc::nc_version, U("NcVersionCode"), true, false, false, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Manufacturer descriptor"), nc_device_manager_manufacturer_property_id, nmos::fields::nc::manufacturer, U("NcManufacturer"), true, false, false, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Product descriptor"), nc_device_manager_product_property_id, nmos::fields::nc::product, U("NcProduct"), true, false, false, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Serial number"), nc_device_manager_serial_number_property_id, nmos::fields::nc::serial_number, U("NcString"), true, false, false, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Asset tracking identifier (user specified)"), nc_device_manager_user_inventory_code_property_id, nmos::fields::nc::user_inventory_code, U("NcString"), false, true, false, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Name of this device in the application. Instance name, not product name"), nc_device_manager_device_name_property_id, nmos::fields::nc::device_name, U("NcString"), false, true, false, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Role of this device in the application"), nc_device_manager_device_role_property_id, nmos::fields::nc::device_role, U("NcString"), false, true, false, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Device operational state"), nc_device_manager_operational_state_property_id, nmos::fields::nc::operational_state, U("NcDeviceOperationalState"), true, false, false, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Reason for most recent reset"), nc_device_manager_reset_cause_property_id, nmos::fields::nc::reset_cause, U("NcResetCause"), true, false, false, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Arbitrary message from dev to controller"), nc_device_manager_message_property_id, nmos::fields::nc::message, U("NcString"), true, true, false, false, value::null())); return properties; } @@ -821,8 +857,8 @@ namespace nmos using web::json::value; auto properties = value::array(); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Descriptions of all control classes in the device (descriptors do not contain inherited elements)"), nc_class_manager_control_classes_property_id, nmos::fields::nc::control_classes, U("NcClassDescriptor"), true, false, true, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Descriptions of all data types in the device (descriptors do not contain inherited elements)"), nc_class_manager_datatypes_property_id, nmos::fields::nc::datatypes, U("NcDatatypeDescriptor"), true, false, true, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Descriptions of all control classes in the device (descriptors do not contain inherited elements)"), nc_class_manager_control_classes_property_id, nmos::fields::nc::control_classes, U("NcClassDescriptor"), true, false, true, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Descriptions of all data types in the device (descriptors do not contain inherited elements)"), nc_class_manager_datatypes_property_id, nmos::fields::nc::datatypes, U("NcDatatypeDescriptor"), true, false, true, false, value::null())); return properties; } @@ -859,10 +895,10 @@ namespace nmos using web::json::value; auto properties = value::array(); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Connection status property"), nc_receiver_monitor_connection_status_property_id, nmos::fields::nc::connection_status, U("NcConnectionStatus"), true, false, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Connection status message property"), nc_receiver_monitor_connection_status_message_property_id, nmos::fields::nc::connection_status_message, U("NcString"), true, true, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Payload status property"), nc_receiver_monitor_payload_status_property_id, nmos::fields::nc::payload_status, U("NcPayloadStatus"), true, false, false, false)); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Payload status message property"), nc_receiver_monitor_payload_status_message_property_id, nmos::fields::nc::payload_status_message, U("NcString"), true, true, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Connection status property"), nc_receiver_monitor_connection_status_property_id, nmos::fields::nc::connection_status, U("NcConnectionStatus"), true, false, false, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Connection status message property"), nc_receiver_monitor_connection_status_message_property_id, nmos::fields::nc::connection_status_message, U("NcString"), true, true, false, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Payload status property"), nc_receiver_monitor_payload_status_property_id, nmos::fields::nc::payload_status, U("NcPayloadStatus"), true, false, false, false, value::null())); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Payload status message property"), nc_receiver_monitor_payload_status_message_property_id, nmos::fields::nc::payload_status_message, U("NcString"), true, true, false, false, value::null())); return properties; } @@ -885,7 +921,7 @@ namespace nmos using web::json::value; auto properties = value::array(); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Indicates if signal protection is active"), nc_receiver_monitor_protected_signal_protection_status_property_id, nmos::fields::nc::signal_protection_status, U("NcBoolean"), true, false, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Indicates if signal protection is active"), nc_receiver_monitor_protected_signal_protection_status_property_id, nmos::fields::nc::signal_protection_status, U("NcBoolean"), true, false, false, false, value::null())); return properties; } @@ -908,7 +944,7 @@ namespace nmos using web::json::value; auto properties = value::array(); - web::json::push_back(properties, details::make_nc_property_descriptor(U("Indicator active state"), nc_ident_beacon_active_property_id, nmos::fields::nc::active, U("NcBoolean"), false, false, false, false)); + web::json::push_back(properties, details::make_nc_property_descriptor(U("Indicator active state"), nc_ident_beacon_active_property_id, nmos::fields::nc::active, U("NcBoolean"), false, false, false, false, value::null())); return properties; } @@ -930,7 +966,7 @@ namespace nmos { using web::json::value; - return details::make_nc_class_descriptor(value::string(U("NcObject class descriptor")), nc_object_class_id, U("NcObject"), value::null(), make_nc_object_properties(), make_nc_object_methods(), make_nc_object_events()); + return details::make_nc_class_descriptor(U("NcObject class descriptor"), nc_object_class_id, U("NcObject"), value::null(), make_nc_object_properties(), make_nc_object_methods(), make_nc_object_events()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/classes/1.1.html @@ -938,7 +974,7 @@ namespace nmos { using web::json::value; - return details::make_nc_class_descriptor(value::string(U("NcBlock class descriptor")), nc_block_class_id, U("NcBlock"), value::null(), make_nc_block_properties(), make_nc_block_methods(), make_nc_block_events()); + return details::make_nc_class_descriptor(U("NcBlock class descriptor"), nc_block_class_id, U("NcBlock"), value::null(), make_nc_block_properties(), make_nc_block_methods(), make_nc_block_events()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/classes/1.2.html @@ -946,7 +982,7 @@ namespace nmos { using web::json::value; - return details::make_nc_class_descriptor(value::string(U("NcWorker class descriptor")), nc_worker_class_id, U("NcWorker"), value::null(), make_nc_worker_properties(), make_nc_worker_methods(), make_nc_worker_events()); + return details::make_nc_class_descriptor(U("NcWorker class descriptor"), nc_worker_class_id, U("NcWorker"), value::null(), make_nc_worker_properties(), make_nc_worker_methods(), make_nc_worker_events()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/classes/1.3.html @@ -954,7 +990,7 @@ namespace nmos { using web::json::value; - return details::make_nc_class_descriptor(value::string(U("NcManager class descriptor")), nc_manager_class_id, U("NcManager"), value::null(), make_nc_manager_properties(), make_nc_manager_methods(), make_nc_manager_events()); + return details::make_nc_class_descriptor(U("NcManager class descriptor"), nc_manager_class_id, U("NcManager"), value::null(), make_nc_manager_properties(), make_nc_manager_methods(), make_nc_manager_events()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/classes/1.3.1.html @@ -962,7 +998,7 @@ namespace nmos { using web::json::value; - return details::make_nc_class_descriptor(value::string(U("NcDeviceManager class descriptor")), nc_device_manager_class_id, U("NcDeviceManager"), value::string(U("DeviceManager")), make_nc_device_manager_properties(), make_nc_device_manager_methods(), make_nc_device_manager_events()); + return details::make_nc_class_descriptor(U("NcDeviceManager class descriptor"), nc_device_manager_class_id, U("NcDeviceManager"), value::string(U("DeviceManager")), make_nc_device_manager_properties(), make_nc_device_manager_methods(), make_nc_device_manager_events()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/classes/1.3.2.html @@ -970,7 +1006,7 @@ namespace nmos { using web::json::value; - return details::make_nc_class_descriptor(value::string(U("NcClassManager class descriptor")), nc_class_manager_class_id, U("NcClassManager"), value::string(U("ClassManager")), make_nc_class_manager_properties(), make_nc_class_manager_methods(), make_nc_class_manager_events()); + return details::make_nc_class_descriptor(U("NcClassManager class descriptor"), nc_class_manager_class_id, U("NcClassManager"), value::string(U("ClassManager")), make_nc_class_manager_properties(), make_nc_class_manager_methods(), make_nc_class_manager_events()); } // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/identification/#ncidentbeacon @@ -978,7 +1014,7 @@ namespace nmos { using web::json::value; - return details::make_nc_class_descriptor(value::string(U("NcIdentBeacon class descriptor")), nc_ident_beacon_class_id, U("NcIdentBeacon"), value::null(), make_nc_ident_beacon_properties(), make_nc_ident_beacon_methods(), make_nc_ident_beacon_events()); + return details::make_nc_class_descriptor(U("NcIdentBeacon class descriptor"), nc_ident_beacon_class_id, U("NcIdentBeacon"), value::null(), make_nc_ident_beacon_properties(), make_nc_ident_beacon_methods(), make_nc_ident_beacon_events()); } // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitor @@ -986,7 +1022,7 @@ namespace nmos { using web::json::value; - return details::make_nc_class_descriptor(value::string(U("NcReceiverMonitor class descriptor")), nc_receiver_monitor_class_id, U("NcReceiverMonitor"), value::null(), make_nc_receiver_monitor_properties(), make_nc_receiver_monitor_methods(), make_nc_receiver_monitor_events()); + return details::make_nc_class_descriptor(U("NcReceiverMonitor class descriptor"), nc_receiver_monitor_class_id, U("NcReceiverMonitor"), value::null(), make_nc_receiver_monitor_properties(), make_nc_receiver_monitor_methods(), make_nc_receiver_monitor_events()); } // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitorprotected @@ -994,7 +1030,7 @@ namespace nmos { using web::json::value; - return details::make_nc_class_descriptor(value::string(U("NcReceiverMonitorProtected class descriptor")), nc_receiver_monitor_protected_class_id, U("NcReceiverMonitorProtected"), value::null(), make_nc_receiver_monitor_protected_properties(), make_nc_receiver_monitor_protected_methods(), make_nc_receiver_monitor_protected_events()); + return details::make_nc_class_descriptor(U("NcReceiverMonitorProtected class descriptor"), nc_receiver_monitor_protected_class_id, U("NcReceiverMonitorProtected"), value::null(), make_nc_receiver_monitor_protected_properties(), make_nc_receiver_monitor_protected_methods(), make_nc_receiver_monitor_protected_events()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcBlockMemberDescriptor.html @@ -1003,13 +1039,13 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Role of member in its containing block")), nmos::fields::nc::role, value::string(U("NcString")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("OID of member")), nmos::fields::nc::oid, value::string(U("NcOid")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff member's OID is hardwired into device")), nmos::fields::nc::constant_oid, value::string(U("NcBoolean")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Class ID")), nmos::fields::nc::class_id, value::string(U("NcClassId")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("User label")), nmos::fields::nc::user_label, value::string(U("NcString")), true, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Containing block's OID")), nmos::fields::nc::owner, value::string(U("NcOid")), false, false)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor which is specific to a block member")), U("NcBlockMemberDescriptor"), fields, value::string(U("NcDescriptor"))); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Role of member in its containing block"), nmos::fields::nc::role, U("NcString"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("OID of member"), nmos::fields::nc::oid, U("NcOid"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("TRUE iff member's OID is hardwired into device"), nmos::fields::nc::constant_oid, U("NcBoolean"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Class ID"), nmos::fields::nc::class_id, U("NcClassId"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("User label"), nmos::fields::nc::user_label, U("NcString"), true, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Containing block's OID"), nmos::fields::nc::owner, U("NcOid"), false, false, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Descriptor which is specific to a block member"), U("NcBlockMemberDescriptor"), fields, U("NcDescriptor"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcClassDescriptor.html @@ -1018,13 +1054,13 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Identity of the class")), nmos::fields::nc::class_id, value::string(U("NcClassId")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of the class")), nmos::fields::nc::name, value::string(U("NcName")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Role if the class has fixed role (manager classes)")), nmos::fields::nc::fixed_role, value::string(U("NcString")), true, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Property descriptors")), nmos::fields::nc::properties, value::string(U("NcPropertyDescriptor")), false, true)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Method descriptors")), nmos::fields::nc::methods, value::string(U("NcMethodDescriptor")), false, true)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Event descriptors")), nmos::fields::nc::events, value::string(U("NcEventDescriptor")), false, true)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class")), U("NcClassDescriptor"), fields, value::string(U("NcDescriptor"))); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Identity of the class"), nmos::fields::nc::class_id, U("NcClassId"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Name of the class"), nmos::fields::nc::name, U("NcName"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Role if the class has fixed role (manager classes)"), nmos::fields::nc::fixed_role, U("NcString"), true, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Property descriptors"), nmos::fields::nc::properties, U("NcPropertyDescriptor"), false, true, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Method descriptors"), nmos::fields::nc::methods, U("NcMethodDescriptor"), false, true, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Event descriptors"), nmos::fields::nc::events, U("NcEventDescriptor"), false, true, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Descriptor of a class"), U("NcClassDescriptor"), fields, U("NcDescriptor"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcClassId.html @@ -1032,7 +1068,7 @@ namespace nmos { using web::json::value; - return details::make_nc_datatype_typedef(value::string(U("Sequence of class ID fields")), U("NcClassId"), true, U("NcInt32")); + return details::make_nc_datatype_typedef(U("Sequence of class ID fields"), U("NcClassId"), true, U("NcInt32"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcDatatypeDescriptor.html @@ -1041,10 +1077,10 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Datatype name")), nmos::fields::nc::name, value::string(U("NcName")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Type: Primitive, Typedef, Struct, Enum")), nmos::fields::nc::type, value::string(U("NcDatatypeType")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional constraints on top of the underlying data type")), nmos::fields::nc::constraints, value::string(U("NcParameterConstraints")), true, false)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Base datatype descriptor")), U("NcDatatypeDescriptor"), fields, value::string(U("NcDescriptor"))); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Datatype name"), nmos::fields::nc::name, U("NcName"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Type: Primitive, Typedef, Struct, Enum"), nmos::fields::nc::type, U("NcDatatypeType"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Optional constraints on top of the underlying data type"), nmos::fields::nc::constraints, U("NcParameterConstraints"), true, false, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Base datatype descriptor"), U("NcDatatypeDescriptor"), fields, U("NcDescriptor"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcDatatypeDescriptorEnum.html @@ -1053,8 +1089,8 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("One item descriptor per enum option")), nmos::fields::nc::items, value::string(U("NcEnumItemDescriptor")), false, true)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Enum datatype descriptor")), U("NcDatatypeDescriptorEnum"), fields, value::string(U("NcDatatypeDescriptor"))); + web::json::push_back(fields, details::make_nc_field_descriptor(U("One item descriptor per enum option"), nmos::fields::nc::items, U("NcEnumItemDescriptor"), false, true, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Enum datatype descriptor"), U("NcDatatypeDescriptorEnum"), fields, U("NcDatatypeDescriptor"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcDatatypeDescriptorPrimitive.html @@ -1063,7 +1099,7 @@ namespace nmos using web::json::value; auto fields = value::array(); - return details::make_nc_datatype_descriptor_struct(value::string(U("Primitive datatype descriptor")), U("NcDatatypeDescriptorPrimitive"), fields, value::string(U("NcDatatypeDescriptor"))); + return details::make_nc_datatype_descriptor_struct(U("Primitive datatype descriptor"), U("NcDatatypeDescriptorPrimitive"), fields, U("NcDatatypeDescriptor"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcDatatypeDescriptorStruct.html @@ -1072,9 +1108,9 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("One item descriptor per field of the struct")), nmos::fields::nc::fields, value::string(U("NcFieldDescriptor")), false, true)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of the parent type if any or null if it has no parent")), nmos::fields::nc::parent_type, value::string(U("NcName")), true, false)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Struct datatype descriptor")), U("NcDatatypeDescriptorStruct"), fields, value::string(U("NcDatatypeDescriptor"))); + web::json::push_back(fields, details::make_nc_field_descriptor(U("One item descriptor per field of the struct"), nmos::fields::nc::fields, U("NcFieldDescriptor"), false, true, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Name of the parent type if any or null if it has no parent"), nmos::fields::nc::parent_type, U("NcName"), true, false, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Struct datatype descriptor"), U("NcDatatypeDescriptorStruct"), fields, U("NcDatatypeDescriptor"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcDatatypeDescriptorTypeDef.html @@ -1083,9 +1119,9 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Original typedef datatype name")), nmos::fields::nc::parent_type, value::string(U("NcName")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff type is a typedef sequence of another type")), nmos::fields::nc::is_sequence, value::string(U("NcBoolean")), false, false)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Type def datatype descriptor")), U("NcDatatypeDescriptorTypeDef"), fields, value::string(U("NcDatatypeDescriptor"))); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Original typedef datatype name"), nmos::fields::nc::parent_type, U("NcName"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("TRUE iff type is a typedef sequence of another type"), nmos::fields::nc::is_sequence, U("NcBoolean"), false, false, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Type def datatype descriptor"), U("NcDatatypeDescriptorTypeDef"), fields, U("NcDatatypeDescriptor"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcDatatypeType.html @@ -1094,11 +1130,11 @@ namespace nmos using web::json::value; auto items = value::array(); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Primitive datatype")), U("Primitive"), 0)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Simple alias of another datatype")), U("Typedef"), 1)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Data structure")), U("Struct"), 2)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Enum datatype")), U("Enum"), 3)); - return details::make_nc_datatype_descriptor_enum(value::string(U("Datatype type")), U("NcDatatypeType"), items); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Primitive datatype"), U("Primitive"), 0)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Simple alias of another datatype"), U("Typedef"), 1)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Data structure"), U("Struct"), 2)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Enum datatype"), U("Enum"), 3)); + return details::make_nc_datatype_descriptor_enum(U("Datatype type"), U("NcDatatypeType"), items, value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcDescriptor.html @@ -1107,8 +1143,8 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional user facing description")), nmos::fields::nc::description, value::string(U("NcString")), true, false)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Base descriptor")), U("NcDescriptor"), fields, value::null()); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Optional user facing description"), nmos::fields::nc::description, U("NcString"), true, false, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Base descriptor"), U("NcDescriptor"), fields, value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcDeviceGenericState.html @@ -1117,13 +1153,13 @@ namespace nmos using web::json::value; auto items = value::array(); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Unknown")), U("Unknown"), 0)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Normal operation")), U("NormalOperation"), 1)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Device is initializing")), U("Initializing"), 2)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Device is performing a software or firmware update")), U("Updating"), 3)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Device is experiencing a licensing error")), U("LicensingError"), 4)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Device is experiencing an internal error")), U("InternalError"), 5)); - return details::make_nc_datatype_descriptor_enum(value::string(U("Device generic operational state")), U("NcDeviceGenericState"), items); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Unknown"), U("Unknown"), 0)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Normal operation"), U("NormalOperation"), 1)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Device is initializing"), U("Initializing"), 2)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Device is performing a software or firmware update"), U("Updating"), 3)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Device is experiencing a licensing error"), U("LicensingError"), 4)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Device is experiencing an internal error"), U("InternalError"), 5)); + return details::make_nc_datatype_descriptor_enum(U("Device generic operational state"), U("NcDeviceGenericState"), items, value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcDeviceOperationalState.html @@ -1132,9 +1168,9 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Generic operational state")), nmos::fields::nc::generic_state, value::string(U("NcDeviceGenericState")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Specific device details")), nmos::fields::nc::device_specific_details, value::string(U("NcString")), true, false)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Device operational state")), U("NcDeviceOperationalState"), fields, value::null()); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Generic operational state"), nmos::fields::nc::generic_state, U("NcDeviceGenericState"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Specific device details"), nmos::fields::nc::device_specific_details, U("NcString"), true, false, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Device operational state"), U("NcDeviceOperationalState"), fields, value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcElementId.html @@ -1143,9 +1179,9 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Level of the element")), nmos::fields::nc::level, value::string(U("NcUint16")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Index of the element")), nmos::fields::nc::index, value::string(U("NcUint16")), false, false)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Class element id which contains the level and index")), U("NcElementId"), fields, value::null()); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Level of the element"), nmos::fields::nc::level, U("NcUint16"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Index of the element"), nmos::fields::nc::index, U("NcUint16"), false, false, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Class element id which contains the level and index"), U("NcElementId"), fields, value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcEnumItemDescriptor.html @@ -1154,9 +1190,9 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of option")), nmos::fields::nc::name, value::string(U("NcName")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Enum item numerical value")), nmos::fields::nc::value, value::string(U("NcUint16")), false, false)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of an enum item")), U("NcEnumItemDescriptor"), fields, value::string(U("NcDescriptor"))); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Name of option"), nmos::fields::nc::name, U("NcName"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Enum item numerical value"), nmos::fields::nc::value, U("NcUint16"), false, false, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Descriptor of an enum item"), U("NcEnumItemDescriptor"), fields, U("NcDescriptor"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcEventDescriptor.html @@ -1165,11 +1201,11 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Event id with level and index")), nmos::fields::nc::id, value::string(U("NcEventId")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of event")), nmos::fields::nc::name, value::string(U("NcName")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of event data's datatype")), nmos::fields::nc::event_datatype, value::string(U("NcName")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is marked as deprecated")), nmos::fields::nc::is_deprecated, value::string(U("NcBoolean")), false, false)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class event")), U("NcEventDescriptor"), fields, value::string(U("NcDescriptor"))); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Event id with level and index"), nmos::fields::nc::id, U("NcEventId"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Name of event"), nmos::fields::nc::name, U("NcName"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Name of event data's datatype"), nmos::fields::nc::event_datatype, U("NcName"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("TRUE iff property is marked as deprecated"), nmos::fields::nc::is_deprecated, U("NcBoolean"), false, false, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Descriptor of a class event"), U("NcEventDescriptor"), fields, U("NcDescriptor"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcEventId.html @@ -1177,7 +1213,7 @@ namespace nmos { using web::json::value; - return details::make_nc_datatype_descriptor_struct(value::string(U("Event id which contains the level and index")), U("NcEventId"), value::array(), value::string(U("NcElementId"))); + return details::make_nc_datatype_descriptor_struct(U("Event id which contains the level and index"), U("NcEventId"), value::array(), U("NcElementId"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcFieldDescriptor.html @@ -1186,12 +1222,12 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of field")), nmos::fields::nc::name, value::string(U("NcName")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of field's datatype. Can only ever be null if the type is any")), nmos::fields::nc::type_name, value::string(U("NcName")), true, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff field is nullable")), nmos::fields::nc::is_nullable, value::string(U("NcBoolean")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff field is a sequence")), nmos::fields::nc::is_sequence, value::string(U("NcBoolean")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional constraints on top of the underlying data type")), nmos::fields::nc::constraints, value::string(U("NcParameterConstraints")), true, false)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a field of a struct")), U("NcFieldDescriptor"), fields, value::string(U("NcDescriptor"))); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Name of field"), nmos::fields::nc::name, U("NcName"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Name of field's datatype. Can only ever be null if the type is any"), nmos::fields::nc::type_name, U("NcName"), true, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("TRUE iff field is nullable"), nmos::fields::nc::is_nullable, U("NcBoolean"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("TRUE iff field is a sequence"), nmos::fields::nc::is_sequence, U("NcBoolean"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Optional constraints on top of the underlying data type"), nmos::fields::nc::constraints, U("NcParameterConstraints"), true, false, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Descriptor of a field of a struct"), U("NcFieldDescriptor"), fields, U("NcDescriptor"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcId.html @@ -1199,7 +1235,7 @@ namespace nmos { using web::json::value; - return details::make_nc_datatype_typedef(value::string(U("Identity handler")), U("NcId"), false, U("NcUint32")); + return details::make_nc_datatype_typedef(U("Identity handler"), U("NcId"), false, U("NcUint32"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcManufacturer.html @@ -1208,10 +1244,10 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Manufacturer's name")), nmos::fields::nc::name, value::string(U("NcString")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("IEEE OUI or CID of manufacturer")), nmos::fields::nc::organization_id, value::string(U("NcOrganizationId")), true, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("URL of the manufacturer's website")), nmos::fields::nc::website, value::string(U("NcUri")), true, false)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Manufacturer descriptor")), U("NcManufacturer"), fields, value::null()); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Manufacturer's name"), nmos::fields::nc::name, U("NcString"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("IEEE OUI or CID of manufacturer"), nmos::fields::nc::organization_id, U("NcOrganizationId"), true, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("URL of the manufacturer's website"), nmos::fields::nc::website, U("NcUri"), true, false, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Manufacturer descriptor"), U("NcManufacturer"), fields, value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcMethodDescriptor.html @@ -1220,12 +1256,12 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Method id with level and index")), nmos::fields::nc::id, value::string(U("NcMethodId")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of method")), nmos::fields::nc::name, value::string(U("NcName")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of method result's datatype")), nmos::fields::nc::result_datatype, value::string(U("NcName")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Parameter descriptors if any")), nmos::fields::nc::parameters, value::string(U("NcParameterDescriptor")), false, true)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is marked as deprecated")), nmos::fields::nc::is_deprecated, value::string(U("NcBoolean")), false, false)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class method")), U("NcMethodDescriptor"), fields, value::string(U("NcDescriptor"))); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Method id with level and index"), nmos::fields::nc::id, U("NcMethodId"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Name of method"), nmos::fields::nc::name, U("NcName"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Name of method result's datatype"), nmos::fields::nc::result_datatype, U("NcName"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Parameter descriptors if any"), nmos::fields::nc::parameters, U("NcParameterDescriptor"), false, true, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("TRUE iff property is marked as deprecated"), nmos::fields::nc::is_deprecated, U("NcBoolean"), false, false, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Descriptor of a class method"), U("NcMethodDescriptor"), fields, U("NcDescriptor"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcMethodId.html @@ -1233,7 +1269,7 @@ namespace nmos { using web::json::value; - return details::make_nc_datatype_descriptor_struct(value::string(U("Method id which contains the level and index")), U("NcMethodId"), value::array(), value::string(U("NcElementId"))); + return details::make_nc_datatype_descriptor_struct(U("Method id which contains the level and index"), U("NcMethodId"), value::array(), U("NcElementId"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcMethodResult.html @@ -1242,8 +1278,8 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Status for the invoked method")), nmos::fields::nc::status, value::string(U("NcMethodStatus")), false, false)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Base result of the invoked method")), U("NcMethodResult"), fields, value::null()); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Status for the invoked method"), nmos::fields::nc::status, U("NcMethodStatus"), false, false, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Base result of the invoked method"), U("NcMethodResult"), fields, value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcMethodResultBlockMemberDescriptors.html @@ -1252,8 +1288,8 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Block member descriptors method result value")), nmos::fields::nc::value, value::string(U("NcBlockMemberDescriptor")), false, true)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Method result containing block member descriptors as the value")), U("NcMethodResultBlockMemberDescriptors"), fields, value::string(U("NcMethodResult"))); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Block member descriptors method result value"), nmos::fields::nc::value, U("NcBlockMemberDescriptor"), false, true, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Method result containing block member descriptors as the value"), U("NcMethodResultBlockMemberDescriptors"), fields, U("NcMethodResult"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcMethodResultClassDescriptor.html @@ -1262,8 +1298,8 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Class descriptor method result value")), nmos::fields::nc::value, value::string(U("NcClassDescriptor")), false, false)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Method result containing a class descriptor as the value")), U("NcMethodResultClassDescriptor"), fields, value::string(U("NcMethodResult"))); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Class descriptor method result value"), nmos::fields::nc::value, U("NcClassDescriptor"), false, false, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Method result containing a class descriptor as the value"), U("NcMethodResultClassDescriptor"), fields, U("NcMethodResult"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcMethodResultDatatypeDescriptor.html @@ -1272,8 +1308,8 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Datatype descriptor method result value")), nmos::fields::nc::value, value::string(U("NcDatatypeDescriptor")), false, false)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Method result containing a datatype descriptor as the value")), U("NcMethodResultDatatypeDescriptor"), fields, value::string(U("NcMethodResult"))); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Datatype descriptor method result value"), nmos::fields::nc::value, U("NcDatatypeDescriptor"), false, false, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Method result containing a datatype descriptor as the value"), U("NcMethodResultDatatypeDescriptor"), fields, U("NcMethodResult"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcMethodResultError.html @@ -1282,8 +1318,8 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Error message")), nmos::fields::nc::error_message, value::string(U("NcString")), false, false)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Error result - to be used when the method call encounters an error")), U("NcMethodResultError"), fields, value::string(U("NcMethodResult"))); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Error message"), nmos::fields::nc::error_message, U("NcString"), false, false, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Error result - to be used when the method call encounters an error"), U("NcMethodResultError"), fields, U("NcMethodResult"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcMethodResultId.html @@ -1292,8 +1328,8 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Id result value")), nmos::fields::nc::value, value::string(U("NcId")), false, false)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Id method result")), U("NcMethodResultId"), fields, value::string(U("NcMethodResult"))); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Id result value"), nmos::fields::nc::value, U("NcId"), false, false, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Id method result"), U("NcMethodResultId"), fields, U("NcMethodResult"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcMethodResultLength.html @@ -1302,8 +1338,8 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Length result value")), nmos::fields::nc::value, value::string(U("NcUint32")), true, false)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Length method result")), U("NcMethodResultLength"), fields, value::string(U("NcMethodResult"))); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Length result value"), nmos::fields::nc::value, U("NcUint32"), true, false, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Length method result"), U("NcMethodResultLength"), fields, U("NcMethodResult"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcMethodResultPropertyValue.html @@ -1312,8 +1348,8 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Getter method value for the associated property")), nmos::fields::nc::value, value::null(), true, false)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Result when invoking the getter method associated with a property")), U("NcMethodResultPropertyValue"), fields, value::string(U("NcMethodResult"))); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Getter method value for the associated property"), nmos::fields::nc::value, true, false, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Result when invoking the getter method associated with a property"), U("NcMethodResultPropertyValue"), fields, U("NcMethodResult"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcMethodStatus.html @@ -1322,25 +1358,25 @@ namespace nmos using web::json::value; auto items = value::array(); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method call was successful")), U("Ok"), 200)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method call was successful but targeted property is deprecated")), U("PropertyDeprecated"), 298)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method call was successful but method is deprecated")), U("MethodDeprecated"), 299)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Badly-formed command (e.g. the incoming command has invalid message encoding and cannot be parsed by the underlying protocol)")), U("BadCommandFormat"), 400)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Client is not authorized")), U("Unauthorized"), 401)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Command addresses a nonexistent object")), U("BadOid"), 404)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Attempt to change read-only state")), U("Readonly"), 405)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method call is invalid in current operating context (e.g. attempting to invoke a method when the object is disabled)")), U("InvalidRequest"), 406)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("There is a conflict with the current state of the device")), U("Conflict"), 409)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Something was too big")), U("BufferOverflow"), 413)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Index is outside the available range")), U("IndexOutOfBounds"), 414)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method parameter does not meet expectations (e.g. attempting to invoke a method with an invalid type for one of its parameters)")), U("ParameterError"), 417)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Addressed object is locked")), U("Locked"), 423)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Internal device error")), U("DeviceError"), 500)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Addressed method is not implemented by the addressed object")), U("MethodNotImplemented"), 501)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Addressed property is not implemented by the addressed object")), U("PropertyNotImplemented"), 502)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("The device is not ready to handle any commands")), U("NotReady"), 503)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Method call did not finish within the allotted time")), U("Timeout"), 504)); - return details::make_nc_datatype_descriptor_enum(value::string(U("Method invokation status")), U("NcMethodStatus"), items); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Method call was successful"), U("Ok"), 200)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Method call was successful but targeted property is deprecated"), U("PropertyDeprecated"), 298)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Method call was successful but method is deprecated"), U("MethodDeprecated"), 299)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Badly-formed command (e.g. the incoming command has invalid message encoding and cannot be parsed by the underlying protocol)"), U("BadCommandFormat"), 400)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Client is not authorized"), U("Unauthorized"), 401)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Command addresses a nonexistent object"), U("BadOid"), 404)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Attempt to change read-only state"), U("Readonly"), 405)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Method call is invalid in current operating context (e.g. attempting to invoke a method when the object is disabled)"), U("InvalidRequest"), 406)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("There is a conflict with the current state of the device"), U("Conflict"), 409)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Something was too big"), U("BufferOverflow"), 413)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Index is outside the available range"), U("IndexOutOfBounds"), 414)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Method parameter does not meet expectations (e.g. attempting to invoke a method with an invalid type for one of its parameters)"), U("ParameterError"), 417)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Addressed object is locked"), U("Locked"), 423)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Internal device error"), U("DeviceError"), 500)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Addressed method is not implemented by the addressed object"), U("MethodNotImplemented"), 501)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Addressed property is not implemented by the addressed object"), U("PropertyNotImplemented"), 502)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("The device is not ready to handle any commands"), U("NotReady"), 503)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Method call did not finish within the allotted time"), U("Timeout"), 504)); + return details::make_nc_datatype_descriptor_enum(U("Method invokation status"), U("NcMethodStatus"), items, value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcName.html @@ -1348,7 +1384,7 @@ namespace nmos { using web::json::value; - return details::make_nc_datatype_typedef(value::string(U("Programmatically significant name, alphanumerics + underscore, no spaces")), U("NcName"), false, U("NcString")); + return details::make_nc_datatype_typedef(U("Programmatically significant name, alphanumerics + underscore, no spaces"), U("NcName"), false, U("NcString"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcOid.html @@ -1356,7 +1392,7 @@ namespace nmos { using web::json::value; - return details::make_nc_datatype_typedef(value::string(U("Object id")), U("NcOid"), false, U("NcUint32")); + return details::make_nc_datatype_typedef(U("Object id"), U("NcOid"), false, U("NcUint32"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcOrganizationId.html @@ -1364,7 +1400,7 @@ namespace nmos { using web::json::value; - return details::make_nc_datatype_typedef(value::string(U("Unique 24-bit organization id")), U("NcOrganizationId"), false, U("NcInt32")); + return details::make_nc_datatype_typedef(U("Unique 24-bit organization id"), U("NcOrganizationId"), false, U("NcInt32"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcParameterConstraints.html @@ -1373,8 +1409,8 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Default value")), nmos::fields::nc::default_value, value::null(), true, false)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Abstract parameter constraints class")), U("NcParameterConstraints"), fields, value::null()); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Default value"), nmos::fields::nc::default_value, true, false, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Abstract parameter constraints class"), U("NcParameterConstraints"), fields, value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcParameterConstraintsNumber.html @@ -1383,10 +1419,10 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional maximum")), nmos::fields::nc::maximum, value::null(), true, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional minimum")), nmos::fields::nc::minimum, value::null(), true, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional step")), nmos::fields::nc::step, value::null(), true, false)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Number parameter constraints class")), U("NcParameterConstraintsNumber"), fields, value::string(U("NcParameterConstraints"))); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Optional maximum"), nmos::fields::nc::maximum, true, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Optional minimum"), nmos::fields::nc::minimum, true, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Optional step"), nmos::fields::nc::step, true, false, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Number parameter constraints class"), U("NcParameterConstraintsNumber"), fields, U("NcParameterConstraints"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcParameterConstraintsString.html @@ -1395,9 +1431,9 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Maximum characters allowed")), nmos::fields::nc::max_characters, value::string(U("NcUint32")), true, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Regex pattern")), nmos::fields::nc::pattern, value::string(U("NcRegex")), true, false)); - return details::make_nc_datatype_descriptor_struct(value::string(U("String parameter constraints class")), U("NcParameterConstraintsString"), fields, value::string(U("NcParameterConstraints"))); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Maximum characters allowed"), nmos::fields::nc::max_characters, U("NcUint32"), true, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Regex pattern"), nmos::fields::nc::pattern, U("NcRegex"), true, false, value::null())); + return details::make_nc_datatype_descriptor_struct(U("String parameter constraints class"), U("NcParameterConstraintsString"), fields, U("NcParameterConstraints"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcParameterDescriptor.html @@ -1406,12 +1442,12 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of parameter")), nmos::fields::nc::name, value::string(U("NcName")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of parameter's datatype. Can only ever be null if the type is any")), nmos::fields::nc::type_name, value::string(U("NcName")), true, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is nullable")), nmos::fields::nc::is_nullable, value::string(U("NcBoolean")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is a sequence")), nmos::fields::nc::is_sequence, value::string(U("NcBoolean")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional constraints on top of the underlying data type")), nmos::fields::nc::constraints, value::string(U("NcParameterConstraints")), true, false)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a method parameter")), U("NcParameterDescriptor"), fields, value::string(U("NcDescriptor"))); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Name of parameter"), nmos::fields::nc::name, U("NcName"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Name of parameter's datatype. Can only ever be null if the type is any"), nmos::fields::nc::type_name, U("NcName"), true, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("TRUE iff property is nullable"), nmos::fields::nc::is_nullable, U("NcBoolean"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("TRUE iff property is a sequence"), nmos::fields::nc::is_sequence, U("NcBoolean"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Optional constraints on top of the underlying data type"), nmos::fields::nc::constraints, U("NcParameterConstraints"), true, false, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Descriptor of a method parameter"), U("NcParameterDescriptor"), fields, U("NcDescriptor"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcProduct.html @@ -1420,13 +1456,13 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Product name")), nmos::fields::nc::name, value::string(U("NcString")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Manufacturer's unique key to product - model number, SKU, etc")), nmos::fields::nc::key, value::string(U("NcString")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Manufacturer's product revision level code")), nmos::fields::nc::revision_level, value::string(U("NcString")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Brand name under which product is sold")), nmos::fields::nc::brand_name, value::string(U("NcString")), true, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Unique UUID of product (not product instance)")), nmos::fields::nc::uuid, value::string(U("NcUuid")), true, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Text description of product")), nmos::fields::nc::description, value::string(U("NcString")), true, false)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Product descriptor")), U("NcProduct"), fields, value::null()); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Product name"), nmos::fields::nc::name, U("NcString"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Manufacturer's unique key to product - model number, SKU, etc"), nmos::fields::nc::key, U("NcString"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Manufacturer's product revision level code"), nmos::fields::nc::revision_level, U("NcString"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Brand name under which product is sold"), nmos::fields::nc::brand_name, U("NcString"), true, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Unique UUID of product (not product instance)"), nmos::fields::nc::uuid, U("NcUuid"), true, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Text description of product"), nmos::fields::nc::description, U("NcString"), true, false, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Product descriptor"), U("NcProduct"), fields, value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcPropertyChangeType.html @@ -1435,11 +1471,11 @@ namespace nmos using web::json::value; auto items = value::array(); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Current value changed")), U("ValueChanged"), 0)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Sequence item added")), U("SequenceItemAdded"), 1)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Sequence item changed")), U("SequenceItemChanged"), 2)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Sequence item removed")), U("SequenceItemRemoved"), 3)); - return details::make_nc_datatype_descriptor_enum(value::string(U("Type of property change")), U("NcPropertyChangeType"), items); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Current value changed"), U("ValueChanged"), 0)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Sequence item added"), U("SequenceItemAdded"), 1)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Sequence item changed"), U("SequenceItemChanged"), 2)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Sequence item removed"), U("SequenceItemRemoved"), 3)); + return details::make_nc_datatype_descriptor_enum(U("Type of property change"), U("NcPropertyChangeType"), items, value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcPropertyChangedEventData.html @@ -1448,11 +1484,11 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("The id of the property that changed")), nmos::fields::nc::property_id, value::string(U("NcPropertyId")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Information regarding the change type")), nmos::fields::nc::change_type, value::string(U("NcPropertyChangeType")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Property-type specific value")), nmos::fields::nc::value, value::null(), true, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Index of sequence item if the property is a sequence")), nmos::fields::nc::sequence_item_index, value::string(U("NcId")), true, false)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Payload of property-changed event")), U("NcPropertyChangedEventData"), fields, value::null()); + web::json::push_back(fields, details::make_nc_field_descriptor(U("The id of the property that changed"), nmos::fields::nc::property_id, U("NcPropertyId"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Information regarding the change type"), nmos::fields::nc::change_type, U("NcPropertyChangeType"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Property-type specific value"), nmos::fields::nc::value, true, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Index of sequence item if the property is a sequence"), nmos::fields::nc::sequence_item_index,U("NcId"), true, false, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Payload of property-changed event"), U("NcPropertyChangedEventData"), fields, value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcPropertyConstraints.html @@ -1461,9 +1497,9 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("The id of the property being constrained")), nmos::fields::nc::property_id, value::string(U("NcPropertyId")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional default value")), nmos::fields::nc::default_value, value::null(), true, false)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Property constraints class")), U("NcPropertyConstraints"), fields, value::null()); + web::json::push_back(fields, details::make_nc_field_descriptor(U("The id of the property being constrained"), nmos::fields::nc::property_id, U("NcPropertyId"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Optional default value"), nmos::fields::nc::default_value, true, false, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Property constraints class"), U("NcPropertyConstraints"), fields, value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcPropertyConstraintsNumber.html @@ -1472,10 +1508,10 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional maximum")), nmos::fields::nc::maximum, value::null(), true, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional minimum")), nmos::fields::nc::minimum, value::null(), true, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional step")), nmos::fields::nc::step, value::null(), true, false)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Number property constraints class")), U("NcPropertyConstraintsNumber"), fields, value::string(U("NcPropertyConstraints"))); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Optional maximum"), nmos::fields::nc::maximum, true, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Optional minimum"), nmos::fields::nc::minimum, true, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Optional step"), nmos::fields::nc::step, true, false, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Number property constraints class"), U("NcPropertyConstraintsNumber"), fields, U("NcPropertyConstraints"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcPropertyConstraintsString.html @@ -1484,9 +1520,9 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Maximum characters allowed")), nmos::fields::nc::max_characters, value::string(U("NcUint32")), true, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Regex pattern")), nmos::fields::nc::pattern, value::string(U("NcRegex")), true, false)); - return details::make_nc_datatype_descriptor_struct(value::string(U("String property constraints class")), U("NcPropertyConstraintsString"), fields, value::string(U("NcPropertyConstraints"))); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Maximum characters allowed"), nmos::fields::nc::max_characters, U("NcUint32"), true, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Regex pattern"), nmos::fields::nc::pattern, U("NcRegex"), true, false, value::null())); + return details::make_nc_datatype_descriptor_struct(U("String property constraints class"), U("NcPropertyConstraintsString"), fields, U("NcPropertyConstraints"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcPropertyDescriptor.html @@ -1495,15 +1531,15 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Property id with level and index")), nmos::fields::nc::id, value::string(U("NcPropertyId")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of property")), nmos::fields::nc::name, value::string(U("NcName")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Name of property's datatype. Can only ever be null if the type is any")), nmos::fields::nc::type_name, value::string(U("NcName")), true, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is read-only")), nmos::fields::nc::is_read_only, value::string(U("NcBoolean")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is nullable")), nmos::fields::nc::is_nullable, value::string(U("NcBoolean")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is a sequence")), nmos::fields::nc::is_sequence, value::string(U("NcBoolean")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("TRUE iff property is marked as deprecated")), nmos::fields::nc::is_deprecated, value::string(U("NcBoolean")), false, false)); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Optional constraints on top of the underlying data type")), nmos::fields::nc::constraints, value::string(U("NcParameterConstraints")), true, false)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Descriptor of a class property")), U("NcPropertyDescriptor"), fields, value::string(U("NcDescriptor"))); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Property id with level and index"), nmos::fields::nc::id, U("NcPropertyId"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Name of property"), nmos::fields::nc::name, U("NcName"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Name of property's datatype. Can only ever be null if the type is any"), nmos::fields::nc::type_name, U("NcName"), true, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("TRUE iff property is read-only"), nmos::fields::nc::is_read_only, U("NcBoolean"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("TRUE iff property is nullable"), nmos::fields::nc::is_nullable, U("NcBoolean"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("TRUE iff property is a sequence"), nmos::fields::nc::is_sequence, U("NcBoolean"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("TRUE iff property is marked as deprecated"), nmos::fields::nc::is_deprecated, U("NcBoolean"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Optional constraints on top of the underlying data type"), nmos::fields::nc::constraints, U("NcParameterConstraints"), true, false, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Descriptor of a class property"), U("NcPropertyDescriptor"), fields, U("NcDescriptor"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcPropertyId.html @@ -1511,7 +1547,7 @@ namespace nmos { using web::json::value; - return details::make_nc_datatype_descriptor_struct(value::string(U("Property id which contains the level and index")), U("NcPropertyId"), value::array(), value::string(U("NcElementId"))); + return details::make_nc_datatype_descriptor_struct(U("Property id which contains the level and index"), U("NcPropertyId"), value::array(), U("NcElementId"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcRegex.html @@ -1519,7 +1555,7 @@ namespace nmos { using web::json::value; - return details::make_nc_datatype_typedef(value::string(U("Regex pattern")), U("NcRegex"), false, U("NcString")); + return details::make_nc_datatype_typedef(U("Regex pattern"), U("NcRegex"), false, U("NcString"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcResetCause.html @@ -1528,13 +1564,13 @@ namespace nmos using web::json::value; auto items = value::array(); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Unknown")), U("Unknown"), 0)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Power on")), U("PowerOn"), 1)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Internal error")), U("InternalError"), 2)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Upgrade")), U("Upgrade"), 3)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Controller request")), U("ControllerRequest"), 4)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Manual request from the front panel")), U("ManualReset"), 5)); - return details::make_nc_datatype_descriptor_enum(value::string(U("Reset cause enum")), U("NcResetCause"), items); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Unknown"), U("Unknown"), 0)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Power on"), U("PowerOn"), 1)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Internal error"), U("InternalError"), 2)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Upgrade"), U("Upgrade"), 3)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Controller request"), U("ControllerRequest"), 4)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Manual request from the front panel"), U("ManualReset"), 5)); + return details::make_nc_datatype_descriptor_enum(U("Reset cause enum"), U("NcResetCause"), items, value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcRolePath.html @@ -1542,7 +1578,7 @@ namespace nmos { using web::json::value; - return details::make_nc_datatype_typedef(value::string(U("Role path")), U("NcRolePath"), true, U("NcString")); + return details::make_nc_datatype_typedef(U("Role path"), U("NcRolePath"), true, U("NcString"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcTimeInterval.html @@ -1550,7 +1586,7 @@ namespace nmos { using web::json::value; - return details::make_nc_datatype_typedef(value::string(U("Time interval described in nanoseconds")), U("NcTimeInterval"), false, U("NcInt64")); + return details::make_nc_datatype_typedef(U("Time interval described in nanoseconds"), U("NcTimeInterval"), false, U("NcInt64"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcTouchpoint.html @@ -1559,8 +1595,8 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Context namespace")), nmos::fields::nc::context_namespace, value::string(U("NcString")), false, false)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Base touchpoint class")), U("NcTouchpoint"), fields, value::null()); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Context namespace"), nmos::fields::nc::context_namespace, U("NcString"), false, false, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Base touchpoint class"), U("NcTouchpoint"), fields, value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcTouchpointNmos.html @@ -1569,8 +1605,8 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Context NMOS resource")), nmos::fields::nc::resource, value::string(U("NcTouchpointResourceNmos")), false, false)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Touchpoint class for NMOS resources")), U("NcTouchpointNmos"), fields, value::string(U("NcTouchpoint"))); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Context NMOS resource"), nmos::fields::nc::resource, U("NcTouchpointResourceNmos"), false, false, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Touchpoint class for NMOS resources"), U("NcTouchpointNmos"), fields, U("NcTouchpoint"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcTouchpointNmosChannelMapping.html @@ -1579,8 +1615,8 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("Context Channel Mapping resource")), nmos::fields::nc::resource, value::string(U("NcTouchpointResourceNmosChannelMapping")), false, false)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Touchpoint class for NMOS IS-08 resources")), U("NcTouchpointNmosChannelMapping"), fields, value::string(U("NcTouchpoint"))); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Context Channel Mapping resource"), nmos::fields::nc::resource,U("NcTouchpointResourceNmosChannelMapping"), false, false, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Touchpoint class for NMOS IS-08 resources"), U("NcTouchpointNmosChannelMapping"), fields, U("NcTouchpoint"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcTouchpointResource.html @@ -1589,8 +1625,8 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("The type of the resource")), nmos::fields::nc::resource_type, value::string(U("NcString")), false, false)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Touchpoint resource class")), U("NcTouchpointResource"), fields, value::null()); + web::json::push_back(fields, details::make_nc_field_descriptor(U("The type of the resource"), nmos::fields::nc::resource_type, U("NcString"), false, false, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Touchpoint resource class"), U("NcTouchpointResource"), fields, value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcTouchpointResourceNmos.html @@ -1599,8 +1635,8 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("NMOS resource UUID")), nmos::fields::nc::id, value::string(U("NcUuid")), false, false)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Touchpoint resource class for NMOS resources")), U("NcTouchpointResourceNmos"), fields, value::string(U("NcTouchpointResource"))); + web::json::push_back(fields, details::make_nc_field_descriptor(U("NMOS resource UUID"), nmos::fields::nc::id, U("NcUuid"), false, false, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Touchpoint resource class for NMOS resources"), U("NcTouchpointResourceNmos"), fields, U("NcTouchpointResource"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcTouchpointResourceNmosChannelMapping.html @@ -1609,8 +1645,8 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(value::string(U("IS-08 Audio Channel Mapping input or output id")), nmos::fields::nc::io_id, value::string(U("NcString")), false, false)); - return details::make_nc_datatype_descriptor_struct(value::string(U("Touchpoint resource class for NMOS resources")), U("NcTouchpointResourceNmosChannelMapping"), fields, value::string(U("NcTouchpointResourceNmos"))); + web::json::push_back(fields, details::make_nc_field_descriptor(U("IS-08 Audio Channel Mapping input or output id"), nmos::fields::nc::io_id, U("NcString"), false, false, value::null())); + return details::make_nc_datatype_descriptor_struct(U("Touchpoint resource class for NMOS resources"), U("NcTouchpointResourceNmosChannelMapping"), fields, U("NcTouchpointResourceNmos"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcUri.html @@ -1618,7 +1654,7 @@ namespace nmos { using web::json::value; - return details::make_nc_datatype_typedef(value::string(U("Uniform resource identifier")), U("NcUri"), false, U("NcString")); + return details::make_nc_datatype_typedef(U("Uniform resource identifier"), U("NcUri"), false, U("NcString"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcUuid.html @@ -1626,7 +1662,7 @@ namespace nmos { using web::json::value; - return details::make_nc_datatype_typedef(value::string(U("UUID")), U("NcUuid"), false, U("NcString")); + return details::make_nc_datatype_typedef(U("UUID"), U("NcUuid"), false, U("NcString"), value::null()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcVersionCode.html @@ -1634,7 +1670,7 @@ namespace nmos { using web::json::value; - return details::make_nc_datatype_typedef(value::string(U("Version code in semantic versioning format")), U("NcVersionCode"), false, U("NcString")); + return details::make_nc_datatype_typedef(U("Version code in semantic versioning format"), U("NcVersionCode"), false, U("NcString"), value::null()); } // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncconnectionstatus @@ -1643,11 +1679,11 @@ namespace nmos using web::json::value; auto items = value::array(); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("This is the value when there is no receiver")), U("Undefined"), 0)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Connected to a stream")), U("Connected"), 1)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Not connected to a stream")), U("Disconnected"), 2)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("A connection error was encountered")), U("ConnectionError"), 3)); - return details::make_nc_datatype_descriptor_enum(value::string(U("Connection status enum data typee")), U("NcConnectionStatus"), items); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("This is the value when there is no receiver"), U("Undefined"), 0)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Connected to a stream"), U("Connected"), 1)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Not connected to a stream"), U("Disconnected"), 2)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("A connection error was encountered"), U("ConnectionError"), 3)); + return details::make_nc_datatype_descriptor_enum(U("Connection status enum data typee"), U("NcConnectionStatus"), items, value::null()); } // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncpayloadstatus @@ -1656,10 +1692,10 @@ namespace nmos using web::json::value; auto items = value::array(); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("This is the value when there's no connection")), U("Undefined"), 0)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Payload is being received without errors and is the correct type")), U("PayloadOK"), 1)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("Payload is being received but is of an unsupported type")), U("PayloadFormatUnsupported"), 2)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(value::string(U("A payload error was encountered")), U("PayloadError"), 3)); - return details::make_nc_datatype_descriptor_enum(value::string(U("Connection status enum data typee")), U("NcPayloadStatus"), items); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("This is the value when there's no connection"), U("Undefined"), 0)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Payload is being received without errors and is the correct type"), U("PayloadOK"), 1)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Payload is being received but is of an unsupported type"), U("PayloadFormatUnsupported"), 2)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("A payload error was encountered"), U("PayloadError"), 3)); + return details::make_nc_datatype_descriptor_enum(U("Connection status enum data typee"), U("NcPayloadStatus"), items, value::null()); } } diff --git a/Development/nmos/control_protocol_resource.h b/Development/nmos/control_protocol_resource.h index bff521676..99f82c497 100644 --- a/Development/nmos/control_protocol_resource.h +++ b/Development/nmos/control_protocol_resource.h @@ -88,8 +88,9 @@ namespace nmos // description can be null // type_name can be null // constraints can be null - web::json::value make_nc_field_descriptor(const web::json::value& description, const nc_name& name, const web::json::value& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints = web::json::value::null()); - web::json::value make_nc_field_descriptor(const utility::string_t& description, const nc_name& name, const utility::string_t& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints = web::json::value::null()); + web::json::value make_nc_field_descriptor(const web::json::value& description, const nc_name& name, const web::json::value& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints); + web::json::value make_nc_field_descriptor(const utility::string_t& description, const nc_name& name, const utility::string_t& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints); + web::json::value make_nc_field_descriptor(const utility::string_t& description, const nc_name& name, bool is_nullable, bool is_sequence, const web::json::value& constraints); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncmethoddescriptor // description can be null @@ -101,9 +102,9 @@ namespace nmos // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterdescriptor // description can be null // type_name can be null - web::json::value make_nc_parameter_descriptor(const web::json::value& description, const nc_name& name, const web::json::value& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints = web::json::value::null()); - web::json::value make_nc_parameter_descriptor(const utility::string_t& description, const nc_name& name, bool is_nullable, bool is_sequence, const web::json::value& constraints = web::json::value::null()); - web::json::value make_nc_parameter_descriptor(const utility::string_t& description, const nc_name& name, const utility::string_t& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints = web::json::value::null()); + web::json::value make_nc_parameter_descriptor(const web::json::value& description, const nc_name& name, const web::json::value& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints); + web::json::value make_nc_parameter_descriptor(const utility::string_t& description, const nc_name& name, bool is_nullable, bool is_sequence, const web::json::value& constraints); + web::json::value make_nc_parameter_descriptor(const utility::string_t& description, const nc_name& name, const utility::string_t& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncpropertydescriptor // description can be null @@ -111,37 +112,42 @@ namespace nmos // type_name can be null // constraints can be null web::json::value make_nc_property_descriptor(const web::json::value& description, const nc_property_id& id, const nc_name& name, const web::json::value& type_name, - bool is_read_only, bool is_nullable, bool is_sequence, bool is_deprecated, const web::json::value& constraints = web::json::value::null()); + bool is_read_only, bool is_nullable, bool is_sequence, bool is_deprecated, const web::json::value& constraints); web::json::value make_nc_property_descriptor(const utility::string_t& description, const nc_property_id& id, const nc_name& name, const utility::string_t& type_name, - bool is_read_only, bool is_nullable, bool is_sequence, bool is_deprecated, const web::json::value& constraints = web::json::value::null()); + bool is_read_only, bool is_nullable, bool is_sequence, bool is_deprecated, const web::json::value& constraints); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdatatypedescriptor // description can be null // constraints can be null - web::json::value make_nc_datatype_descriptor(const web::json::value& description, const nc_name& name, nc_datatype_type::type type, const web::json::value& constraints = web::json::value::null()); + web::json::value make_nc_datatype_descriptor(const web::json::value& description, const nc_name& name, nc_datatype_type::type type, const web::json::value& constraints); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdatatypedescriptorenum // description can be null // constraints can be null // items: sequence - web::json::value make_nc_datatype_descriptor_enum(const web::json::value& description, const nc_name& name, const web::json::value& items, const web::json::value& constraints = web::json::value::null()); + web::json::value make_nc_datatype_descriptor_enum(const web::json::value& description, const nc_name& name, const web::json::value& items, const web::json::value& constraints); + web::json::value make_nc_datatype_descriptor_enum(const utility::string_t& description, const nc_name& name, const web::json::value& items, const web::json::value& constraints); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdatatypedescriptorprimitive // description can be null // constraints can be null - web::json::value make_nc_datatype_descriptor_primitive(const web::json::value& description, const nc_name& name, const web::json::value& constraints = web::json::value::null()); + web::json::value make_nc_datatype_descriptor_primitive(const web::json::value& description, const nc_name& name, const web::json::value& constraints); + web::json::value make_nc_datatype_descriptor_primitive(const utility::string_t& description, const nc_name& name, const web::json::value& constraints); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdatatypedescriptorstruct // description can be null // constraints can be null // fields: sequence // parent_type can be null - web::json::value make_nc_datatype_descriptor_struct(const web::json::value& description, const nc_name& name, const web::json::value& fields, const web::json::value& parent_type, const web::json::value& constraints = web::json::value::null()); + web::json::value make_nc_datatype_descriptor_struct(const web::json::value& description, const nc_name& name, const web::json::value& fields, const web::json::value& parent_type, const web::json::value& constraints); + web::json::value make_nc_datatype_descriptor_struct(const utility::string_t& description, const nc_name& name, const web::json::value& fields, const utility::string_t& parent_type, const web::json::value& constraints); + web::json::value make_nc_datatype_descriptor_struct(const utility::string_t& description, const nc_name& name, const web::json::value& fields, const web::json::value& constraints); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdatatypedescriptortypedef // description can be null // constraints can be null - web::json::value make_nc_datatype_typedef(const web::json::value& description, const nc_name& name, bool is_sequence, const utility::string_t& parent_type, const web::json::value& constraints = web::json::value::null()); + web::json::value make_nc_datatype_typedef(const web::json::value& description, const nc_name& name, bool is_sequence, const utility::string_t& parent_type, const web::json::value& constraints); + web::json::value make_nc_datatype_typedef(const utility::string_t& description, const nc_name& name, bool is_sequence, const utility::string_t& parent_type, const web::json::value& constraints); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncobject web::json::value make_nc_object(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints); From de5beed75397b2adad42a59533a736e76bb474fe Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 19 Sep 2023 13:28:41 +0100 Subject: [PATCH 047/106] Add description to nc_object to simplify create nc_xxx class --- .../nmos-cpp-node/node_implementation.cpp | 38 ++++----- .../nmos/control_protocol_resource.cpp | 27 +++---- Development/nmos/control_protocol_resource.h | 12 +-- .../nmos/control_protocol_resources.cpp | 77 ++----------------- Development/nmos/control_protocol_resources.h | 9 +-- 5 files changed, 45 insertions(+), 118 deletions(-) diff --git a/Development/nmos-cpp-node/node_implementation.cpp b/Development/nmos-cpp-node/node_implementation.cpp index 8d3588c6e..ee8565b55 100644 --- a/Development/nmos-cpp-node/node_implementation.cpp +++ b/Development/nmos-cpp-node/node_implementation.cpp @@ -920,9 +920,9 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr control_protocol_state.insert(gain_control_class); } // helper function to create Gain control - auto make_gain_control = [&gain_value, &gain_control_class_id](nmos::nc_oid oid, nmos::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, float gain = 0.0, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null()) + auto make_gain_control = [&gain_value, &gain_control_class_id](nmos::nc_oid oid, nmos::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, float gain = 0.0, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null()) { - auto data = nmos::details::make_nc_worker(gain_control_class_id, oid, true, owner, role, value::string(user_label), touchpoints, runtime_property_constraints, true); + auto data = nmos::details::make_nc_worker(gain_control_class_id, oid, true, owner, role, value::string(user_label), description, touchpoints, runtime_property_constraints, true); data[gain_value] = value::number(gain); return nmos::resource{ nmos::is12_versions::v1_0, nmos::types::nc_object, std::move(data), true }; @@ -1064,7 +1064,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr }); }; // helper function to create Example control - auto make_example_control = [&](nmos::nc_oid oid, nmos::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, + auto make_example_control = [&](nmos::nc_oid oid, nmos::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, example_enum enum_property_ = example_enum::Undefined, const utility::string_t& string_property_ = U(""), uint64_t number_property_ = 0, @@ -1080,7 +1080,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr std::vector object_sequence_ = {}, const value& touchpoints = value::null(), const value& runtime_property_constraints = value::null()) { - auto data = nmos::details::make_nc_worker(example_control_class_id, oid, true, owner, role, value::string(user_label), touchpoints, runtime_property_constraints, true); + auto data = nmos::details::make_nc_worker(example_control_class_id, oid, true, owner, role, value::string(user_label), description, touchpoints, runtime_property_constraints, true); data[enum_property] = value::number(enum_property_); data[string_property] = value::string(string_property_); data[number_property] = value::number(number_property_); @@ -1132,26 +1132,26 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr // example stereo gain const auto stereo_gain_oid = ++oid; - auto stereo_gain = nmos::make_block(stereo_gain_oid, nmos::root_block_oid, U("stereo-gain"), U("Stereo gain")); + auto stereo_gain = nmos::make_block(stereo_gain_oid, nmos::root_block_oid, U("stereo-gain"), U("Stereo gain"), U("Stereo gain block")); // example channel gain const auto channel_gain_oid = ++oid; - auto channel_gain = nmos::make_block(channel_gain_oid, stereo_gain_oid, U("channel-gain"), U("Channel gain")); + auto channel_gain = nmos::make_block(channel_gain_oid, stereo_gain_oid, U("channel-gain"), U("Channel gain"), U("Channel gain block")); // example left/right gains - auto left_gain = make_gain_control(++oid, channel_gain_oid, U("left-gain"), U("Left gain")); - auto right_gain = make_gain_control(++oid, channel_gain_oid, U("right-gain"), U("Right gain")); + auto left_gain = make_gain_control(++oid, channel_gain_oid, U("left-gain"), U("Left gain"), U("Left channel gain")); + auto right_gain = make_gain_control(++oid, channel_gain_oid, U("right-gain"), U("Right gain"), U("Right channel gain")); // add left-gain and right-gain to channel gain - nmos::add_member(U("Left channel gain"), left_gain, channel_gain); - nmos::add_member(U("Right channel gain"), right_gain, channel_gain); + nmos::push_back(channel_gain, left_gain); + nmos::push_back(channel_gain, right_gain); // example master-gain - auto master_gain = make_gain_control(++oid, channel_gain_oid, U("master-gain"), U("Master gain")); - // add master-gain and channel-gain to stereo-gain - nmos::add_member(U("Master gain block"), master_gain, stereo_gain); - nmos::add_member(U("Channel gain block"), channel_gain, stereo_gain); + auto master_gain = make_gain_control(++oid, channel_gain_oid, U("master-gain"), U("Master gain"), U("Master gain block")); + // add channel-gain and master-gain to stereo-gain + nmos::push_back(stereo_gain, channel_gain); + nmos::push_back(stereo_gain, master_gain); // example example-control - auto example_control = make_example_control(++oid, nmos::root_block_oid, U("ExampleControl"), U("Example control worker"), + auto example_control = make_example_control(++oid, nmos::root_block_oid, U("ExampleControl"), U("Example control worker"), U("Example control worker"), example_enum::Undefined, U("test"), 3, @@ -1168,13 +1168,13 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr ); // add example-control to root-block - nmos::add_member(U("Example control worker"), example_control, root_block); + nmos::push_back(root_block, example_control); // add stereo-gain to root-block - nmos::add_member(U("Stereo gain block"), stereo_gain, root_block); + nmos::push_back(root_block, stereo_gain); // add class-manager to root-block - nmos::add_member(U("The class manager offers access to control class and data type descriptors"), class_manager, root_block); + nmos::push_back(root_block, class_manager); // add device-manager to root-block - nmos::add_member(U("The device manager offers information about the product this device is representing"), device_manager, root_block); + nmos::push_back(root_block, device_manager); // insert resources to model if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(example_control), gate)) throw node_implementation_init_exception(); diff --git a/Development/nmos/control_protocol_resource.cpp b/Development/nmos/control_protocol_resource.cpp index 8d89358b2..afc578156 100644 --- a/Development/nmos/control_protocol_resource.cpp +++ b/Development/nmos/control_protocol_resource.cpp @@ -1,6 +1,5 @@ #include "nmos/control_protocol_resource.h" -//#include "nmos/resource.h" #include "nmos/control_protocol_state.h" // for nmos::experimental::control_classes definitions #include "nmos/json_fields.h" @@ -445,14 +444,12 @@ namespace nmos } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncobject - web::json::value make_nc_object(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints) + web::json::value make_nc_object(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints) { using web::json::value; const auto id = utility::conversions::details::to_string_t(oid); -// auto data = make_resource_core(id, user_label.is_null() ? U("") : user_label.as_string(), {}); - value data; - data[nmos::fields::id] = value::string(id); // required for nmos::resource + auto data = make_resource_core(id, user_label.is_null() ? U("") : user_label.as_string(), description); // required for nmos::resource data[nmos::fields::nc::class_id] = make_nc_class_id(class_id); data[nmos::fields::nc::oid] = oid; data[nmos::fields::nc::constant_oid] = value::boolean(constant_oid); @@ -466,11 +463,11 @@ namespace nmos } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncblock - web::json::value make_nc_block(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled, const web::json::value& members) + web::json::value make_nc_block(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled, const web::json::value& members) { using web::json::value; - auto data = details::make_nc_object(class_id, oid, constant_oid, owner, role, user_label, touchpoints, runtime_property_constraints); + auto data = details::make_nc_object(class_id, oid, constant_oid, owner, role, user_label, description, touchpoints, runtime_property_constraints); data[nmos::fields::nc::enabled] = value::boolean(enabled); data[nmos::fields::nc::members] = members; @@ -478,30 +475,30 @@ namespace nmos } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncworker - web::json::value make_nc_worker(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled) + web::json::value make_nc_worker(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled) { using web::json::value; - auto data = details::make_nc_object(class_id, oid, constant_oid, owner, role, user_label, touchpoints, runtime_property_constraints); + auto data = details::make_nc_object(class_id, oid, constant_oid, owner, role, user_label, description, touchpoints, runtime_property_constraints); data[nmos::fields::nc::enabled] = value::boolean(enabled); return data; } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncmanager - web::json::value make_nc_manager(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints) + web::json::value make_nc_manager(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints) { - return make_nc_object(class_id, oid, constant_oid, owner, role, user_label, touchpoints, runtime_property_constraints); + return make_nc_object(class_id, oid, constant_oid, owner, role, user_label, description, touchpoints, runtime_property_constraints); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdevicemanager - web::json::value make_nc_device_manager(nc_oid oid, nc_oid owner, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, + web::json::value make_nc_device_manager(nc_oid oid, nc_oid owner, const web::json::value& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, const web::json::value& manufacturer, const web::json::value& product, const utility::string_t& serial_number, const web::json::value& user_inventory_code, const web::json::value& device_name, const web::json::value& device_role, const web::json::value& operational_state, nc_reset_cause::cause reset_cause) { using web::json::value; - auto data = details::make_nc_manager(nc_device_manager_class_id, oid, true, owner, U("DeviceManager"), user_label, touchpoints, runtime_property_constraints); + auto data = details::make_nc_manager(nc_device_manager_class_id, oid, true, owner, U("DeviceManager"), user_label, description, touchpoints, runtime_property_constraints); data[nmos::fields::nc::nc_version] = value::string(U("v1.0.0")); data[nmos::fields::nc::manufacturer] = manufacturer; data[nmos::fields::nc::product] = product; @@ -517,11 +514,11 @@ namespace nmos } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncclassmanager - web::json::value make_nc_class_manager(nc_oid oid, nc_oid owner, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, const nmos::experimental::control_protocol_state& control_protocol_state) + web::json::value make_nc_class_manager(nc_oid oid, nc_oid owner, const web::json::value& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, const nmos::experimental::control_protocol_state& control_protocol_state) { using web::json::value; - auto data = make_nc_manager(nc_class_manager_class_id, oid, true, owner, U("ClassManager"), user_label, touchpoints, runtime_property_constraints); + auto data = make_nc_manager(nc_class_manager_class_id, oid, true, owner, U("ClassManager"), user_label, description, touchpoints, runtime_property_constraints); // add control classes data[nmos::fields::nc::control_classes] = value::array(); diff --git a/Development/nmos/control_protocol_resource.h b/Development/nmos/control_protocol_resource.h index 99f82c497..2479a7f9f 100644 --- a/Development/nmos/control_protocol_resource.h +++ b/Development/nmos/control_protocol_resource.h @@ -150,24 +150,24 @@ namespace nmos web::json::value make_nc_datatype_typedef(const utility::string_t& description, const nc_name& name, bool is_sequence, const utility::string_t& parent_type, const web::json::value& constraints); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncobject - web::json::value make_nc_object(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints); + web::json::value make_nc_object(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncblock - web::json::value make_nc_block(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled, const web::json::value& members); + web::json::value make_nc_block(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled, const web::json::value& members); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncworker - web::json::value make_nc_worker(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled); + web::json::value make_nc_worker(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncmanager - web::json::value make_nc_manager(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints); + web::json::value make_nc_manager(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdevicemanager - web::json::value make_nc_device_manager(nc_oid oid, nc_oid owner, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, + web::json::value make_nc_device_manager(nc_oid oid, nc_oid owner, const web::json::value& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, const web::json::value& manufacturer, const web::json::value& product, const utility::string_t& serial_number, const web::json::value& user_inventory_code, const web::json::value& device_name, const web::json::value& device_role, const web::json::value& operational_state, nc_reset_cause::cause reset_cause); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncclassmanager - web::json::value make_nc_class_manager(nc_oid oid, nc_oid owner, const web::json::value& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, const nmos::experimental::control_protocol_state& control_protocol_state); + web::json::value make_nc_class_manager(nc_oid oid, nc_oid owner, const web::json::value& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, const nmos::experimental::control_protocol_state& control_protocol_state); } // message response diff --git a/Development/nmos/control_protocol_resources.cpp b/Development/nmos/control_protocol_resources.cpp index b7e28fd29..f576fd44d 100644 --- a/Development/nmos/control_protocol_resources.cpp +++ b/Development/nmos/control_protocol_resources.cpp @@ -2,7 +2,6 @@ #include "nmos/control_protocol_resource.h" #include "nmos/control_protocol_utils.h" -#include "nmos/query_utils.h" #include "nmos/resource.h" #include "nmos/is12_versions.h" @@ -11,22 +10,22 @@ namespace nmos namespace details { // create block resource - resource make_block(nmos::nc_oid oid, const web::json::value& owner, const utility::string_t& role, const utility::string_t& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, const web::json::value& members) + resource make_block(nmos::nc_oid oid, const web::json::value& owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, const web::json::value& members) { using web::json::value; - auto data = details::make_nc_block(nc_block_class_id, oid, true, owner, role, value::string(user_label), touchpoints, runtime_property_constraints, true, members); + auto data = details::make_nc_block(nc_block_class_id, oid, true, owner, role, value::string(user_label), description, touchpoints, runtime_property_constraints, true, members); return{ is12_versions::v1_0, types::nc_object, std::move(data), true }; } } // create block resource - resource make_block(nc_oid oid, nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, const web::json::value& members) + resource make_block(nc_oid oid, nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, const web::json::value& members) { using web::json::value; - return details::make_block(oid, value(owner), role, user_label, touchpoints, runtime_property_constraints, members); + return details::make_block(oid, value(owner), role, user_label, description, touchpoints, runtime_property_constraints, members); } // create Root block resource @@ -34,7 +33,7 @@ namespace nmos { using web::json::value; - return details::make_block(1, value::null(), U("root"), U("Root"), value::null(), value::null(), value::array()); + return details::make_block(1, value::null(), U("root"), U("Root"), U("Root block"), value::null(), value::null(), value::array()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdevicemanager @@ -42,7 +41,6 @@ namespace nmos { using web::json::value; - const auto user_label = value::string(U("Device manager")); const auto& manufacturer = details::make_nc_manufacturer(nmos::experimental::fields::manufacturer_name(settings)); const auto& product = details::make_nc_product(nmos::experimental::fields::product_name(settings), nmos::experimental::fields::product_key(settings), nmos::experimental::fields::product_key(settings)); const auto& serial_number = nmos::experimental::fields::serial_number(settings); @@ -50,7 +48,7 @@ namespace nmos const auto device_role = value::null(); const auto& operational_state = details::make_nc_device_operational_state(nc_device_generic_state::normal_operation, value::null()); - auto data = details::make_nc_device_manager(oid, root_block_oid, user_label, value::null(), value::null(), + auto data = details::make_nc_device_manager(oid, root_block_oid, value::string(U("Device manager")), U("The device manager offers information about the product this device is representing"), value::null(), value::null(), manufacturer, product, serial_number, value::null(), device_name, device_role, operational_state, nc_reset_cause::unknown); return{ is12_versions::v1_0, types::nc_object, std::move(data), true }; @@ -61,69 +59,8 @@ namespace nmos { using web::json::value; - const auto user_label = value::string(U("Class manager")); - - auto data = details::make_nc_class_manager(oid, root_block_oid, user_label, value::null(), value::null(), control_protocol_state); + auto data = details::make_nc_class_manager(oid, root_block_oid, value::string(U("Class manager")), U("The class manager offers access to control class and data type descriptors"), value::null(), value::null(), control_protocol_state); return{ is12_versions::v1_0, types::nc_object, std::move(data), true }; } - - // add to owner block member - bool add_member(const utility::string_t& child_description, const nmos::resource& child_block, nmos::resource& parent_block) - { - using web::json::value; - - auto& parent = parent_block.data; - const auto& child = child_block.data; - - web::json::push_back(parent[nmos::fields::nc::members], - details::make_nc_block_member_descriptor(child_description, nmos::fields::nc::role(child), nmos::fields::nc::oid(child), nmos::fields::nc::constant_oid(child), details::parse_nc_class_id(nmos::fields::nc::class_id(child)), nmos::fields::nc::user_label(child), nmos::fields::nc::oid(parent))); - - return true; - } - - // modify a resource, and insert notification event to all subscriptions - bool modify_control_protocol_resource(resources& resources, const id& id, std::function modifier, const web::json::value& notification_event) - { - auto found = resources.find(id); - if (resources.end() == found || !found->has_data()) return false; - - auto pre = found->data; - - // "If an exception is thrown by some user-provided operation, then the element pointed to by position is erased." - // This seems too surprising, despite the fact that it means that a modification may have been partially completed, - // so capture and rethrow. - // See https://www.boost.org/doc/libs/1_68_0/libs/multi_index/doc/reference/ord_indices.html#modify - std::exception_ptr modifier_exception; - - auto resource_updated = nmos::strictly_increasing_update(resources); - auto result = resources.modify(found, [&resource_updated, &modifier, &modifier_exception](resource& resource) - { - try - { - modifier(resource); - } - catch (...) - { - modifier_exception = std::current_exception(); - } - - // set the update timestamp - resource.updated = resource_updated; - }); - - if (result) - { - auto& modified = *found; - - insert_notification_events(resources, modified.version, modified.downgrade_version, modified.type, pre, modified.data, notification_event); - } - - if (modifier_exception) - { - std::rethrow_exception(modifier_exception); - } - - return result; - } } diff --git a/Development/nmos/control_protocol_resources.h b/Development/nmos/control_protocol_resources.h index 56f80103f..c1718c0a0 100644 --- a/Development/nmos/control_protocol_resources.h +++ b/Development/nmos/control_protocol_resources.h @@ -2,7 +2,6 @@ #define NMOS_CONTROL_PROTOCOL_RESOURCES_H #include "nmos/control_protocol_typedefs.h" // for details::nc_oid definition -#include "nmos/resources.h" #include "nmos/settings.h" namespace nmos @@ -15,7 +14,7 @@ namespace nmos struct resource; // create block resource - resource make_block(nc_oid oid, nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null(), const web::json::value& members = web::json::value::array()); + resource make_block(nc_oid oid, nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null(), const web::json::value& members = web::json::value::array()); // create Root block resource resource make_root_block(); @@ -25,12 +24,6 @@ namespace nmos // create Class manager resource resource make_class_manager(nc_oid oid, const nmos::experimental::control_protocol_state& control_protocol_state); - - // add to owner block member - bool add_member(const utility::string_t& child_description, const resource& child_block, resource& parent_block); - - // modify a resource, and insert notification event to all subscriptions - bool modify_control_protocol_resource(resources& resources, const id& id, std::function modifier, const web::json::value& notification_event); } #endif From fa2a4ba0fd8aea25124e939afb9ae437d9948930 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 19 Sep 2023 13:35:12 +0100 Subject: [PATCH 048/106] Move nc helper functions to nc utils --- Development/nmos/control_protocol_methods.cpp | 8 +-- Development/nmos/control_protocol_utils.cpp | 58 +++++++++++++++++++ Development/nmos/control_protocol_utils.h | 6 ++ 3 files changed, 68 insertions(+), 4 deletions(-) diff --git a/Development/nmos/control_protocol_methods.cpp b/Development/nmos/control_protocol_methods.cpp index 200f8768a..6d8a93dea 100644 --- a/Development/nmos/control_protocol_methods.cpp +++ b/Development/nmos/control_protocol_methods.cpp @@ -63,7 +63,7 @@ namespace nmos const auto notification = make_control_protocol_notification(nmos::fields::nc::oid(resource->data), nc_object_property_changed_event_id, { parse_nc_property_id(property_id), nc_property_change_type::type::value_changed, val }); const auto notification_event = make_control_protocol_notification(web::json::value_of({ notification })); - modify_control_protocol_resource(resources, resource->id, [&](nmos::resource& resource) + modify_resource(resources, resource->id, [&](nmos::resource& resource) { resource.data[nmos::fields::nc::name(property)] = val; @@ -149,7 +149,7 @@ namespace nmos const auto notification = make_control_protocol_notification(nmos::fields::nc::oid(resource->data), nc_object_property_changed_event_id, { parse_nc_property_id(property_id), nc_property_change_type::type::sequence_item_changed, val, nc_id(index) }); const auto notification_event = make_control_protocol_notification(web::json::value_of({ notification })); - modify_control_protocol_resource(resources, resource->id, [&](nmos::resource& resource) + modify_resource(resources, resource->id, [&](nmos::resource& resource) { resource.data[nmos::fields::nc::name(property)][index] = val; @@ -200,7 +200,7 @@ namespace nmos const auto notification = make_control_protocol_notification(nmos::fields::nc::oid(resource->data), nc_object_property_changed_event_id, { parse_nc_property_id(property_id), nc_property_change_type::type::sequence_item_added, val, sequence_item_index }); const auto notification_event = make_control_protocol_notification(web::json::value_of({ notification })); - modify_control_protocol_resource(resources, resource->id, [&](nmos::resource& resource) + modify_resource(resources, resource->id, [&](nmos::resource& resource) { auto& sequence = resource.data[nmos::fields::nc::name(property)]; if (data.is_null()) { sequence = value::array(); } @@ -246,7 +246,7 @@ namespace nmos const auto notification = make_control_protocol_notification(nmos::fields::nc::oid(resource->data), nc_object_property_changed_event_id, { parse_nc_property_id(property_id), nc_property_change_type::type::sequence_item_removed, data.as_array().at(index), nc_id(index)}); const auto notification_event = make_control_protocol_notification(web::json::value_of({ notification })); - modify_control_protocol_resource(resources, resource->id, [&](nmos::resource& resource) + modify_resource(resources, resource->id, [&](nmos::resource& resource) { auto& sequence = resource.data[nmos::fields::nc::name(property)].as_array(); sequence.erase(index); diff --git a/Development/nmos/control_protocol_utils.cpp b/Development/nmos/control_protocol_utils.cpp index de9e00713..641d95f49 100644 --- a/Development/nmos/control_protocol_utils.cpp +++ b/Development/nmos/control_protocol_utils.cpp @@ -7,6 +7,7 @@ #include "nmos/control_protocol_resource.h" #include "nmos/control_protocol_state.h" #include "nmos/json_fields.h" +#include "nmos/query_utils.h" #include "nmos/resources.h" namespace nmos @@ -210,4 +211,61 @@ namespace nmos } } } + + // add block (NcBlock) to other block (NcBlock) + void push_back(nmos::resource& parent_block, const nmos::resource& child_block) + { + using web::json::value; + + auto& parent = parent_block.data; + const auto& child = child_block.data; + + web::json::push_back(parent[nmos::fields::nc::members], + details::make_nc_block_member_descriptor(nmos::fields::description(child), nmos::fields::nc::role(child), nmos::fields::nc::oid(child), nmos::fields::nc::constant_oid(child), details::parse_nc_class_id(nmos::fields::nc::class_id(child)), nmos::fields::nc::user_label(child), nmos::fields::nc::oid(parent))); + } + + // modify a resource, and insert notification event to all subscriptions + bool modify_resource(resources& resources, const id& id, std::function modifier, const web::json::value& notification_event) + { + auto found = resources.find(id); + if (resources.end() == found || !found->has_data()) return false; + + auto pre = found->data; + + // "If an exception is thrown by some user-provided operation, then the element pointed to by position is erased." + // This seems too surprising, despite the fact that it means that a modification may have been partially completed, + // so capture and rethrow. + // See https://www.boost.org/doc/libs/1_68_0/libs/multi_index/doc/reference/ord_indices.html#modify + std::exception_ptr modifier_exception; + + auto resource_updated = nmos::strictly_increasing_update(resources); + auto result = resources.modify(found, [&resource_updated, &modifier, &modifier_exception](resource& resource) + { + try + { + modifier(resource); + } + catch (...) + { + modifier_exception = std::current_exception(); + } + + // set the update timestamp + resource.updated = resource_updated; + }); + + if (result) + { + auto& modified = *found; + + insert_notification_events(resources, modified.version, modified.downgrade_version, modified.type, pre, modified.data, notification_event); + } + + if (modifier_exception) + { + std::rethrow_exception(modifier_exception); + } + + return result; + } } diff --git a/Development/nmos/control_protocol_utils.h b/Development/nmos/control_protocol_utils.h index 47838ddd6..2a47ae831 100644 --- a/Development/nmos/control_protocol_utils.h +++ b/Development/nmos/control_protocol_utils.h @@ -32,6 +32,12 @@ namespace nmos // find members with given class id void find_members_by_class_id(const resources& resources, resources::iterator resource, const nc_class_id& class_id, bool include_derived, bool recurse, web::json::array& descriptors); + + // add block (NcBlock) to other block (NcBlock) + void push_back(resource& parent_block, const resource& child_block); + + // modify a resource, and insert notification event to all subscriptions + bool modify_resource(resources& resources, const id& id, std::function modifier, const web::json::value& notification_event); } #endif From ac8f21ba73fbab4cdbd8cdc462c757c664219f52 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 19 Sep 2023 22:32:35 +0100 Subject: [PATCH 049/106] look before accessing control_protocol_state --- Development/nmos/control_protocol_resource.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Development/nmos/control_protocol_resource.cpp b/Development/nmos/control_protocol_resource.cpp index afc578156..acf369cac 100644 --- a/Development/nmos/control_protocol_resource.cpp +++ b/Development/nmos/control_protocol_resource.cpp @@ -520,6 +520,8 @@ namespace nmos auto data = make_nc_manager(nc_class_manager_class_id, oid, true, owner, U("ClassManager"), user_label, description, touchpoints, runtime_property_constraints); + auto lock = control_protocol_state.read_lock(); + // add control classes data[nmos::fields::nc::control_classes] = value::array(); auto& control_classes = data[nmos::fields::nc::control_classes]; From a805d8a988f30645b127b2ce1e3c51fc96b1c6db Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 19 Sep 2023 22:34:53 +0100 Subject: [PATCH 050/106] pusback allows on NcBlock only --- Development/nmos/control_protocol_utils.cpp | 11 ++++++++--- Development/nmos/control_protocol_utils.h | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Development/nmos/control_protocol_utils.cpp b/Development/nmos/control_protocol_utils.cpp index 641d95f49..5fa97bd8c 100644 --- a/Development/nmos/control_protocol_utils.cpp +++ b/Development/nmos/control_protocol_utils.cpp @@ -213,15 +213,20 @@ namespace nmos } // add block (NcBlock) to other block (NcBlock) - void push_back(nmos::resource& parent_block, const nmos::resource& child_block) + bool push_back(resource& parent_block, const resource& child_block) { using web::json::value; auto& parent = parent_block.data; const auto& child = child_block.data; - web::json::push_back(parent[nmos::fields::nc::members], - details::make_nc_block_member_descriptor(nmos::fields::description(child), nmos::fields::nc::role(child), nmos::fields::nc::oid(child), nmos::fields::nc::constant_oid(child), details::parse_nc_class_id(nmos::fields::nc::class_id(child)), nmos::fields::nc::user_label(child), nmos::fields::nc::oid(parent))); + if (is_nc_block(details::parse_nc_class_id(nmos::fields::nc::class_id(parent))) ) + { + web::json::push_back(parent[nmos::fields::nc::members], + details::make_nc_block_member_descriptor(nmos::fields::description(child), nmos::fields::nc::role(child), nmos::fields::nc::oid(child), nmos::fields::nc::constant_oid(child), details::parse_nc_class_id(nmos::fields::nc::class_id(child)), nmos::fields::nc::user_label(child), nmos::fields::nc::oid(parent))); + return true; + } + return false; } // modify a resource, and insert notification event to all subscriptions diff --git a/Development/nmos/control_protocol_utils.h b/Development/nmos/control_protocol_utils.h index 2a47ae831..2ab06e9e7 100644 --- a/Development/nmos/control_protocol_utils.h +++ b/Development/nmos/control_protocol_utils.h @@ -34,7 +34,7 @@ namespace nmos void find_members_by_class_id(const resources& resources, resources::iterator resource, const nc_class_id& class_id, bool include_derived, bool recurse, web::json::array& descriptors); // add block (NcBlock) to other block (NcBlock) - void push_back(resource& parent_block, const resource& child_block); + bool push_back(resource& parent_block, const resource& child_block); // modify a resource, and insert notification event to all subscriptions bool modify_resource(resources& resources, const id& id, std::function modifier, const web::json::value& notification_event); From 4873c40bd6b882a6757e486d98e0bcbc08ef304c Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 19 Sep 2023 22:35:42 +0100 Subject: [PATCH 051/106] Add control protocol unit tests --- Development/cmake/NmosCppTest.cmake | 1 + .../nmos/test/control_protocol_test.cpp | 628 ++++++++++++++++++ 2 files changed, 629 insertions(+) create mode 100644 Development/nmos/test/control_protocol_test.cpp diff --git a/Development/cmake/NmosCppTest.cmake b/Development/cmake/NmosCppTest.cmake index 02db14903..c0819bcf4 100644 --- a/Development/cmake/NmosCppTest.cmake +++ b/Development/cmake/NmosCppTest.cmake @@ -42,6 +42,7 @@ set(NMOS_CPP_TEST_NMOS_TEST_SOURCES nmos/test/api_utils_test.cpp nmos/test/capabilities_test.cpp nmos/test/channels_test.cpp + nmos/test/control_protocol_test.cpp nmos/test/did_sdid_test.cpp nmos/test/event_type_test.cpp nmos/test/json_validator_test.cpp diff --git a/Development/nmos/test/control_protocol_test.cpp b/Development/nmos/test/control_protocol_test.cpp new file mode 100644 index 000000000..8b44e335b --- /dev/null +++ b/Development/nmos/test/control_protocol_test.cpp @@ -0,0 +1,628 @@ +// The first "test" is of course whether the header compiles standalone +#include "nmos/control_protocol_resource.h" +#include "nmos/control_protocol_typedefs.h" +#include "nmos/json_fields.h" + +#include "bst/test/test.h" + +//////////////////////////////////////////////////////////////////////////////////////////// +BST_TEST_CASE(testNcObject) +{ + using web::json::value_of; + using web::json::value; + + // NcObject + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/classes/1.html + + const auto property_class_id = value_of({ + { U("description"), U("Static value. All instances of the same class will have the same identity value") }, + { U("id"), value_of({ + { U("level"), 1 }, + { U("index"), 1 } + }) }, + { U("name"), U("classId") }, + { U("typeName"), U("NcClassId") }, + { U("isReadOnly"), true }, + { U("isNullable"), false }, + { U("isSequence"), false }, + { U("isDeprecated"), false }, + { U("constraints"), value::null() } + }); + const auto property_class_id_ = nmos::details::make_nc_property_descriptor(U("Static value. All instances of the same class will have the same identity value"), nmos::nc_object_class_id_property_id, nmos::fields::nc::class_id, U("NcClassId"), true, false, false, false, value::null()); + BST_REQUIRE_EQUAL(property_class_id, property_class_id_); + + const auto property_oid = value_of({ + { U("description"), U("Object identifier") }, + { U("id"), value_of({ + { U("level"), 1 }, + { U("index"), 2 } + }) }, + { U("name"), U("oid") }, + { U("typeName"), U("NcOid") }, + { U("isReadOnly"), true }, + { U("isNullable"), false }, + { U("isSequence"), false }, + { U("isDeprecated"), false }, + { U("constraints"), value::null() } + }); + const auto property_oid_ = nmos::details::make_nc_property_descriptor(U("Object identifier"), nmos::nc_object_oid_property_id, nmos::fields::nc::oid, U("NcOid"), true, false, false, false, value::null()); + BST_REQUIRE_EQUAL(property_oid, property_oid_); + + const auto property_constant_oid = value_of({ + { U("description"), U("TRUE iff OID is hardwired into device") }, + { U("id"), value_of({ + { U("level"), 1 }, + { U("index"), 3 } + }) }, + { U("name"), U("constantOid") }, + { U("typeName"), U("NcBoolean") }, + { U("isReadOnly"), true }, + { U("isNullable"), false }, + { U("isSequence"), false }, + { U("isDeprecated"), false }, + { U("constraints"), value::null() } + }); + const auto property_constant_oid_ = nmos::details::make_nc_property_descriptor(U("TRUE iff OID is hardwired into device"), nmos::nc_object_constant_oid_property_id, nmos::fields::nc::constant_oid, U("NcBoolean"), true, false, false, false, value::null()); + BST_REQUIRE_EQUAL(property_constant_oid, property_constant_oid_); + + const auto property_owner = value_of({ + { U("description"), U("OID of containing block. Can only ever be null for the root block") }, + { U("id"), value_of({ + { U("level"), 1 }, + { U("index"), 4 } + }) }, + { U("name"), U("owner") }, + { U("typeName"), U("NcOid") }, + { U("isReadOnly"), true }, + { U("isNullable"), true }, + { U("isSequence"), false }, + { U("isDeprecated"), false }, + { U("constraints"), value::null() } + }); + const auto property_owner_ = nmos::details::make_nc_property_descriptor(U("OID of containing block. Can only ever be null for the root block"), nmos::nc_object_owner_property_id, nmos::fields::nc::owner, U("NcOid"), true, true, false, false, value::null()); + BST_REQUIRE_EQUAL(property_owner, property_owner_); + + const auto property_role = value_of({ + { U("description"), U("Role of object in the containing block") }, + { U("id"), value_of({ + { U("level"), 1 }, + { U("index"), 5 } + }) }, + { U("name"), U("role") }, + { U("typeName"), U("NcString") }, + { U("isReadOnly"), true }, + { U("isNullable"), false }, + { U("isSequence"), false }, + { U("isDeprecated"), false }, + { U("constraints"), value::null() } + }); + const auto property_role_ = nmos::details::make_nc_property_descriptor(U("Role of object in the containing block"), nmos::nc_object_role_property_id, nmos::fields::nc::role, U("NcString"), true, false, false, false, value::null()); + BST_REQUIRE_EQUAL(property_role, property_role_); + + const auto property_user_label = value_of({ + { U("description"), U("Scribble strip") }, + { U("id"), value_of({ + { U("level"), 1 }, + { U("index"), 6 } + }) }, + { U("name"), U("userLabel") }, + { U("typeName"), U("NcString") }, + { U("isReadOnly"), false }, + { U("isNullable"), true }, + { U("isSequence"), false }, + { U("isDeprecated"), false }, + { U("constraints"), value::null() } + }); + const auto property_user_label_ = nmos::details::make_nc_property_descriptor(U("Scribble strip"), nmos::nc_object_user_label_property_id, nmos::fields::nc::user_label, U("NcString"), false, true, false, false, value::null()); + BST_REQUIRE_EQUAL(property_user_label, property_user_label_); + + const auto property_touchpoints = value_of({ + { U("description"), U("Touchpoints to other contexts") }, + { U("id"), value_of({ + { U("level"), 1 }, + { U("index"), 7 } + }) }, + { U("name"), U("touchpoints") }, + { U("typeName"), U("NcTouchpoint") }, + { U("isReadOnly"), true }, + { U("isNullable"), true }, + { U("isSequence"), true }, + { U("isDeprecated"), false }, + { U("constraints"), value::null() } + }); + const auto property_touchpoints_ = nmos::details::make_nc_property_descriptor(U("Touchpoints to other contexts"), nmos::nc_object_touchpoints_property_id, nmos::fields::nc::touchpoints, U("NcTouchpoint"), true, true, true, false, value::null()); + BST_REQUIRE_EQUAL(property_touchpoints, property_touchpoints_); + + const auto property_runtime_property_constraints = value_of({ + { U("description"), U("Runtime property constraints") }, + { U("id"), value_of({ + { U("level"), 1 }, + { U("index"), 8 } + }) }, + { U("name"), U("runtimePropertyConstraints") }, + { U("typeName"), U("NcPropertyConstraints") }, + { U("isReadOnly"), true }, + { U("isNullable"), true }, + { U("isSequence"), true }, + { U("isDeprecated"), false }, + { U("constraints"), value::null() } + }); + const auto property_runtime_property_constraints_ = nmos::details::make_nc_property_descriptor(U("Runtime property constraints"), nmos::nc_object_runtime_property_constraints_property_id, nmos::fields::nc::runtime_property_constraints, U("NcPropertyConstraints"), true, true, true, false, value::null()); + BST_REQUIRE_EQUAL(property_runtime_property_constraints, property_runtime_property_constraints_); + + const auto method_get = value_of({ + { U("description"), U("Get property value") }, + { U("id"), value_of({ + { U("level"), 1 }, + { U("index"), 1 } + }) }, + { U("name"), U("Get") }, + { U("resultDatatype"), U("NcMethodResultPropertyValue") }, + { U("parameters"), value_of({ + value_of({ + { U("description"), U("Property id") }, + { U("name"), U("id") }, + { U("typeName"), U("NcPropertyId") }, + { U("isNullable"), false }, + { U("isSequence"), false }, + { U("constraints"), value::null() } + }) + }) }, + { U("isDeprecated"), false } + }); + + { + auto parameters = value::array(); + web::json::push_back(parameters, nmos::details::make_nc_parameter_descriptor(U("Property id"), nmos::fields::nc::id, U("NcPropertyId"), false, false, value::null())); + const auto method_get_ = nmos::details::make_nc_method_descriptor(U("Get property value"), nmos::nc_object_get_method_id, U("Get"), U("NcMethodResultPropertyValue"), parameters, false); + + BST_REQUIRE_EQUAL(method_get, method_get_); + } + + const auto method_set = value_of({ + { U("description"), U("Set property value") }, + { U("id"), value_of({ + { U("level"), 1 }, + { U("index"), 2 } + }) }, + { U("name"), U("Set") }, + { U("resultDatatype"), U("NcMethodResult") }, + { U("parameters"), value_of({ + value_of({ + { U("description"), U("Property id") }, + { U("name"), U("id") }, + { U("typeName"), U("NcPropertyId") }, + { U("isNullable"), false }, + { U("isSequence"), false }, + { U("constraints"), value::null() } + }), + value_of({ + { U("description"), U("Property value") }, + { U("name"), U("value") }, + { U("typeName"), value::null() }, + { U("isNullable"), true }, + { U("isSequence"), false }, + { U("constraints"), value::null() } + }) + }) }, + { U("isDeprecated"), false } + }); + + { + auto parameters = value::array(); + web::json::push_back(parameters, nmos::details::make_nc_parameter_descriptor(U("Property id"), nmos::fields::nc::id, U("NcPropertyId"), false, false, value::null())); + web::json::push_back(parameters, nmos::details::make_nc_parameter_descriptor(U("Property value"), nmos::fields::nc::value, true, false, value::null())); + const auto method_set_ = nmos::details::make_nc_method_descriptor(U("Set property value"), nmos::nc_object_set_method_id, U("Set"), U("NcMethodResult"), parameters, false); + + BST_REQUIRE_EQUAL(method_set, method_set_); + } + + const auto method_get_sequence_item = value_of({ + { U("description"), U("Get sequence item") }, + { U("id"), value_of({ + { U("level"), 1 }, + { U("index"), 3 } + }) }, + { U("name"), U("GetSequenceItem") }, + { U("resultDatatype"), U("NcMethodResultPropertyValue") }, + { U("parameters"), value_of({ + value_of({ + { U("description"), U("Property id") }, + { U("name"), U("id") }, + { U("typeName"), U("NcPropertyId") }, + { U("isNullable"), false }, + { U("isSequence"), false }, + { U("constraints"), value::null() } + }), + value_of({ + { U("description"), U("Index of item in the sequence") }, + { U("name"), U("index") }, + { U("typeName"), U("NcId")}, + { U("isNullable"), false }, + { U("isSequence"), false }, + { U("constraints"), value::null() } + }) + }) }, + { U("isDeprecated"), false } + }); + + { + auto parameters = value::array(); + web::json::push_back(parameters, nmos::details::make_nc_parameter_descriptor(U("Property id"), nmos::fields::nc::id, U("NcPropertyId"), false, false, value::null())); + web::json::push_back(parameters, nmos::details::make_nc_parameter_descriptor(U("Index of item in the sequence"), nmos::fields::nc::index, U("NcId"), false, false, value::null())); + const auto method_get_sequence_item_ = nmos::details::make_nc_method_descriptor(U("Get sequence item"), nmos::nc_object_get_sequence_item_method_id, U("GetSequenceItem"), U("NcMethodResultPropertyValue"), parameters, false); + + BST_REQUIRE_EQUAL(method_get_sequence_item, method_get_sequence_item_); + } + + const auto method_set_sequence_item = value_of({ + { U("description"), U("Set sequence item value") }, + { U("id"), value_of({ + { U("level"), 1 }, + { U("index"), 4 } + }) }, + { U("name"), U("SetSequenceItem") }, + { U("resultDatatype"), U("NcMethodResult") }, + { U("parameters"), value_of({ + value_of({ + { U("description"), U("Property id") }, + { U("name"), U("id") }, + { U("typeName"), U("NcPropertyId") }, + { U("isNullable"), false }, + { U("isSequence"), false }, + { U("constraints"), value::null() } + }), + value_of({ + { U("description"), U("Index of item in the sequence") }, + { U("name"), U("index") }, + { U("typeName"), U("NcId") }, + { U("isNullable"), false }, + { U("isSequence"), false }, + { U("constraints"), value::null() } + }), + value_of({ + { U("description"), U("Value") }, + { U("name"), U("value") }, + { U("typeName"), value::null() }, + { U("isNullable"), true }, + { U("isSequence"), false }, + { U("constraints"), value::null() } + }) + }) }, + { U("isDeprecated"), false } + }); + + { + auto parameters = value::array(); + web::json::push_back(parameters, nmos::details::make_nc_parameter_descriptor(U("Property id"), nmos::fields::nc::id, U("NcPropertyId"), false, false, value::null())); + web::json::push_back(parameters, nmos::details::make_nc_parameter_descriptor(U("Index of item in the sequence"), nmos::fields::nc::index, U("NcId"), false, false, value::null())); + web::json::push_back(parameters, nmos::details::make_nc_parameter_descriptor(U("Value"), nmos::fields::nc::value, true, false, value::null())); + const auto method_set_sequence_item_ = nmos::details::make_nc_method_descriptor(U("Set sequence item value"), nmos::nc_object_set_sequence_item_method_id, U("SetSequenceItem"), U("NcMethodResult"), parameters, false); + + BST_REQUIRE_EQUAL(method_set_sequence_item, method_set_sequence_item_); + } + + const auto method_add_sequence_item = value_of({ + { U("description"), U("Add item to sequence") }, + { U("id"), value_of({ + { U("level"), 1 }, + { U("index"), 5 } + }) }, + { U("name"), U("AddSequenceItem") }, + { U("resultDatatype"), U("NcMethodResultId") }, + { U("parameters"), value_of({ + value_of({ + { U("description"), U("Property id") }, + { U("name"), U("id") }, + { U("typeName"), U("NcPropertyId") }, + { U("isNullable"), false }, + { U("isSequence"), false }, + { U("constraints"), value::null() } + }), + value_of({ + { U("description"), U("Value") }, + { U("name"), U("value") }, + { U("typeName"), value::null() }, + { U("isNullable"), true }, + { U("isSequence"), false }, + { U("constraints"), value::null() } + }) + }) }, + { U("isDeprecated"), false } + }); + + { + auto parameters = value::array(); + web::json::push_back(parameters, nmos::details::make_nc_parameter_descriptor(U("Property id"), nmos::fields::nc::id, U("NcPropertyId"), false, false, value::null())); + web::json::push_back(parameters, nmos::details::make_nc_parameter_descriptor(U("Value"), nmos::fields::nc::value, true, false, value::null())); + const auto method_add_sequence_item_ = nmos::details::make_nc_method_descriptor(U("Add item to sequence"), nmos::nc_object_add_sequence_item_method_id, U("AddSequenceItem"), U("NcMethodResultId"), parameters, false); + + BST_REQUIRE_EQUAL(method_add_sequence_item, method_add_sequence_item_); + } + + const auto method_remove_sequence_item = value_of({ + { U("description"), U("Delete sequence item") }, + { U("id"), value_of({ + { U("level"), 1 }, + { U("index"), 6 } + }) }, + { U("name"), U("RemoveSequenceItem") }, + { U("resultDatatype"), U("NcMethodResult") }, + { U("parameters"), value_of({ + value_of({ + { U("description"), U("Property id") }, + { U("name"), U("id") }, + { U("typeName"), U("NcPropertyId") }, + { U("isNullable"), false }, + { U("isSequence"), false }, + { U("constraints"), value::null() } + }), + value_of({ + { U("description"), U("Index of item in the sequence") }, + { U("name"), U("index") }, + { U("typeName"), U("NcId") }, + { U("isNullable"), false }, + { U("isSequence"), false }, + { U("constraints"), value::null() } + }) + }) }, + { U("isDeprecated"), false } + }); + + { + auto parameters = value::array(); + web::json::push_back(parameters, nmos::details::make_nc_parameter_descriptor(U("Property id"), nmos::fields::nc::id, U("NcPropertyId"), false, false, value::null())); + web::json::push_back(parameters, nmos::details::make_nc_parameter_descriptor(U("Index of item in the sequence"), nmos::fields::nc::index, U("NcId"), false, false, value::null())); + const auto method_remove_sequence_item_ = nmos::details::make_nc_method_descriptor(U("Delete sequence item"), nmos::nc_object_remove_sequence_item_method_id, U("RemoveSequenceItem"), U("NcMethodResult"), parameters, false); + + BST_REQUIRE_EQUAL(method_remove_sequence_item, method_remove_sequence_item_); + } + + const auto method_get_sequence_length = value_of({ + { U("description"), U("Get sequence length") }, + { U("id"), value_of({ + { U("level"), 1 }, + { U("index"), 7 } + }) }, + { U("name"), U("GetSequenceLength") }, + { U("resultDatatype"), U("NcMethodResultLength") }, + { U("parameters"), value_of({ + value_of({ + { U("description"), U("Property id") }, + { U("name"), U("id") }, + { U("typeName"), U("NcPropertyId") }, + { U("isNullable"), false }, + { U("isSequence"), false }, + { U("constraints"), value::null() } + }) + }) }, + { U("isDeprecated"), false } + }); + + { + auto parameters = value::array(); + web::json::push_back(parameters, nmos::details::make_nc_parameter_descriptor(U("Property id"), nmos::fields::nc::id, U("NcPropertyId"), false, false, value::null())); + const auto method_get_sequence_length_ = nmos::details::make_nc_method_descriptor(U("Get sequence length"), nmos::nc_object_get_sequence_length_method_id, U("GetSequenceLength"), U("NcMethodResultLength"), parameters, false); + + BST_REQUIRE_EQUAL(method_get_sequence_length, method_get_sequence_length_); + } + + const auto event_property_changed = value_of({ + { U("description"), U("Property changed event") }, + { U("id"), value_of({ + { U("level"), 1 }, + { U("index"), 1 } + }) }, + { U("name"), U("PropertyChanged") }, + { U("eventDatatype"), U("NcPropertyChangedEventData") }, + { U("isDeprecated"), false } + }); + + const auto event_property_changed_ = nmos::details::make_nc_event_descriptor(U("Property changed event"), nmos::nc_object_property_changed_event_id, U("PropertyChanged"), U("NcPropertyChangedEventData"), false); + BST_REQUIRE_EQUAL(event_property_changed, event_property_changed_); + + const auto nc_object_class = value_of({ + { U("description"), U("NcObject class descriptor") }, + { U("classId"), value_of({ + { 1 } + }) }, + { U("name"), U("NcObject") }, + { U("fixedRole"), value::null() }, + { U("properties"), value_of({ + property_class_id, + property_oid, + property_constant_oid, + property_owner, + property_role, + property_user_label, + property_touchpoints, + property_runtime_property_constraints + }) }, + { U("methods"), value_of({ + method_get, + method_set, + method_get_sequence_item, + method_set_sequence_item, + method_add_sequence_item, + method_remove_sequence_item, + method_get_sequence_length + }) }, + { U("events"), value_of({ + event_property_changed + }) } + }); + const auto nc_object_class_ = nmos::details::make_nc_class_descriptor(U("NcObject class descriptor"), nmos::nc_object_class_id, U("NcObject"), value::null(), nmos::make_nc_object_properties(), nmos::make_nc_object_methods(), nmos::make_nc_object_events()); + BST_REQUIRE_EQUAL(nc_object_class, nc_object_class_); +} + +BST_TEST_CASE(testNcBlockMemberDescriptor) +{ + using web::json::value_of; + using web::json::value; + + // NcBlockMemberDescriptor + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcBlockMemberDescriptor.html + const auto nc_datatype_descriptor = value_of({ + { U("description"), U("Descriptor which is specific to a block member") }, + { U("name"), U("NcBlockMemberDescriptor") }, + { U("type"), 2 }, + { U("fields"), value_of({ + value_of({ + { U("description"), U("Role of member in its containing block") }, + { U("name"), U("role") }, + { U("typeName"), U("NcString") }, + { U("isNullable"), false }, + { U("isSequence"), false }, + { U("constraints"), value::null() } + }), + value_of({ + { U("description"), U("OID of member") }, + { U("name"), U("oid") }, + { U("typeName"), U("NcOid") }, + { U("isNullable"), false }, + { U("isSequence"), false }, + { U("constraints"), value::null() } + }), + value_of({ + { U("description"), U("TRUE iff member's OID is hardwired into device") }, + { U("name"), U("constantOid") }, + { U("typeName"), U("NcBoolean") }, + { U("isNullable"), false }, + { U("isSequence"), false }, + { U("constraints"), value::null() } + }), + value_of({ + { U("description"), U("Class ID") }, + { U("name"), U("classId") }, + { U("typeName"), U("NcClassId") }, + { U("isNullable"), false }, + { U("isSequence"), false }, + { U("constraints"), value::null() } + }), + value_of({ + { U("description"), U("User label") }, + { U("name"), U("userLabel") }, + { U("typeName"), U("NcString") }, + { U("isNullable"), true }, + { U("isSequence"), false }, + { U("constraints"), value::null() } + }), + value_of({ + { U("description"), U("Containing block's OID") }, + { U("name"), U("owner") }, + { U("typeName"), U("NcOid") }, + { U("isNullable"), false }, + { U("isSequence"), false }, + { U("constraints"), value::null() } + }) + }) }, + { U("parentType"), U("NcDescriptor") }, + { U("constraints"), value::null() } + }); + + auto fields = value::array(); + web::json::push_back(fields, nmos::details::make_nc_field_descriptor(U("Role of member in its containing block"), nmos::fields::nc::role, U("NcString"), false, false, value::null())); + web::json::push_back(fields, nmos::details::make_nc_field_descriptor(U("OID of member"), nmos::fields::nc::oid, U("NcOid"), false, false, value::null())); + web::json::push_back(fields, nmos::details::make_nc_field_descriptor(U("TRUE iff member's OID is hardwired into device"), nmos::fields::nc::constant_oid, U("NcBoolean"), false, false, value::null())); + web::json::push_back(fields, nmos::details::make_nc_field_descriptor(U("Class ID"), nmos::fields::nc::class_id, U("NcClassId"), false, false, value::null())); + web::json::push_back(fields, nmos::details::make_nc_field_descriptor(U("User label"), nmos::fields::nc::user_label, U("NcString"), true, false, value::null())); + web::json::push_back(fields, nmos::details::make_nc_field_descriptor(U("Containing block's OID"), nmos::fields::nc::owner, U("NcOid"), false, false, value::null())); + const auto nc_datatype_descriptor_ = nmos::details::make_nc_datatype_descriptor_struct(U("Descriptor which is specific to a block member"), U("NcBlockMemberDescriptor"), fields, U("NcDescriptor"), value::null()); + + BST_REQUIRE_EQUAL(nc_datatype_descriptor, nc_datatype_descriptor_); +} + +BST_TEST_CASE(testNcClassId) +{ + using web::json::value_of; + using web::json::value; + + // NcClassId + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcClassId.html + const auto nc_class_id = value_of({ + { U("description"), U("Sequence of class ID fields") }, + { U("name"), U("NcClassId") }, + { U("type"), 1 }, + { U("parentType"), U("NcInt32") }, + { U("isSequence"), true }, + { U("constraints"), value::null() } + }); + const auto nc_class_id_ = nmos::details::make_nc_datatype_typedef(U("Sequence of class ID fields"), U("NcClassId"), true, U("NcInt32"), value::null()); + + BST_REQUIRE_EQUAL(nc_class_id, nc_class_id_); +} + +BST_TEST_CASE(testNcDeviceGenericState) +{ + using web::json::value_of; + using web::json::value; + + // NcDeviceGenericState + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcDeviceGenericState.html + const auto nc_device_generic_state = value_of({ + { U("description"), U("Device generic operational state") }, + { U("name"), U("NcDeviceGenericState") }, + { U("type"), 3 }, + { U("items"), value_of({ + value_of({ + { U("description"), U("Unknown") }, + { U("name"), U("Unknown") }, + { U("value"), 0 } + }), + value_of({ + { U("description"), U("Normal operation") }, + { U("name"), U("NormalOperation") }, + { U("value"), 1 } + }), + value_of({ + { U("description"), U("Device is initializing") }, + { U("name"), U("Initializing") }, + { U("value"), 2 } + }), + value_of({ + { U("description"), U("Device is performing a software or firmware update") }, + { U("name"), U("Updating") }, + { U("value"), 3 } + }), + value_of({ + { U("description"), U("Device is experiencing a licensing error") }, + { U("name"), U("LicensingError") }, + { U("value"), 4 } + }), + value_of({ + { U("description"), U("Device is experiencing an internal error") }, + { U("name"), U("InternalError") }, + { U("value"), 5 } + }) + }) }, + { U("constraints"), value::null() } + }); + + auto items = value::array(); + web::json::push_back(items, nmos::details::make_nc_enum_item_descriptor(U("Unknown"), U("Unknown"), 0)); + web::json::push_back(items, nmos::details::make_nc_enum_item_descriptor(U("Normal operation"), U("NormalOperation"), 1)); + web::json::push_back(items, nmos::details::make_nc_enum_item_descriptor(U("Device is initializing"), U("Initializing"), 2)); + web::json::push_back(items, nmos::details::make_nc_enum_item_descriptor(U("Device is performing a software or firmware update"), U("Updating"), 3)); + web::json::push_back(items, nmos::details::make_nc_enum_item_descriptor(U("Device is experiencing a licensing error"), U("LicensingError"), 4)); + web::json::push_back(items, nmos::details::make_nc_enum_item_descriptor(U("Device is experiencing an internal error"), U("InternalError"), 5)); + const auto nc_device_generic_state_ = nmos::details::make_nc_datatype_descriptor_enum(U("Device generic operational state"), U("NcDeviceGenericState"), items, value::null()); + + BST_REQUIRE_EQUAL(nc_device_generic_state, nc_device_generic_state_); +} + +BST_TEST_CASE(testNcDatatypeDescriptorPrimitive) +{ + using web::json::value_of; + using web::json::value; + + const auto test_primitive = value_of({ + { U("description"), U("Primitive datatype descriptor") }, + { U("name"), U("test_primitive") }, + { U("type"), 0 }, + { U("constraints"), value::null() } + }); + + const auto test_primitive_ = nmos::details::make_nc_datatype_descriptor_primitive(U("Primitive datatype descriptor"), U("test_primitive"), value::null()); + + BST_REQUIRE_EQUAL(test_primitive, test_primitive_); +} From 68defebea6655f6d417d4300a055052745728978 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Wed, 20 Sep 2023 17:37:12 +0100 Subject: [PATCH 052/106] Add more unit tests --- Development/nmos-cpp-node/main.cpp | 6 +- .../nmos-cpp-node/node_implementation.cpp | 8 +- .../nmos/control_protocol_handlers.cpp | 31 +------ Development/nmos/control_protocol_handlers.h | 9 +- Development/nmos/control_protocol_methods.cpp | 2 +- Development/nmos/control_protocol_utils.cpp | 31 ++++--- Development/nmos/control_protocol_utils.h | 12 ++- .../nmos/test/control_protocol_test.cpp | 84 +++++++++++++++++-- 8 files changed, 120 insertions(+), 63 deletions(-) diff --git a/Development/nmos-cpp-node/main.cpp b/Development/nmos-cpp-node/main.cpp index ee133835c..ae9d4380f 100644 --- a/Development/nmos-cpp-node/main.cpp +++ b/Development/nmos-cpp-node/main.cpp @@ -112,9 +112,9 @@ int main(int argc, char* argv[]) nmos::experimental::control_protocol_state control_protocol_state; if (0 <= nmos::fields::control_protocol_ws_port(node_model.settings)) { - node_implementation.on_get_control_class(nmos::make_get_control_protocol_class_handler(control_protocol_state, gate)); - node_implementation.on_get_control_datatype(nmos::make_get_control_protocol_datatype_handler(control_protocol_state, gate)); - node_implementation.on_get_control_protocol_methods(nmos::make_get_control_protocol_methods_handler(control_protocol_state, gate)); + node_implementation.on_get_control_class(nmos::make_get_control_protocol_class_handler(control_protocol_state)); + node_implementation.on_get_control_datatype(nmos::make_get_control_protocol_datatype_handler(control_protocol_state)); + node_implementation.on_get_control_protocol_methods(nmos::make_get_control_protocol_methods_handler(control_protocol_state)); } // Set up the node server diff --git a/Development/nmos-cpp-node/node_implementation.cpp b/Development/nmos-cpp-node/node_implementation.cpp index ee8565b55..b0f6a0e45 100644 --- a/Development/nmos-cpp-node/node_implementation.cpp +++ b/Development/nmos-cpp-node/node_implementation.cpp @@ -29,6 +29,7 @@ #include "nmos/format.h" #include "nmos/group_hint.h" #include "nmos/interlace_mode.h" +#include "nmos/is12_versions.h" // for IS-12 gain control #ifdef HAVE_LLDP #include "nmos/lldp_manager.h" #endif @@ -39,6 +40,7 @@ #include "nmos/node_resources.h" #include "nmos/node_server.h" #include "nmos/random.h" +#include "nmos/resource.h" // for IS-12 gain control #include "nmos/sdp_utils.h" #include "nmos/slog.h" #include "nmos/st2110_21_sender_type.h" @@ -48,10 +50,6 @@ #include "nmos/video_jxsv.h" #include "sdp/sdp.h" -// hmm, for IS-12 gain control -#include "nmos/resource.h" -#include "nmos/is12_versions.h" - // example node implementation details namespace impl { @@ -903,7 +901,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr if (!insert_resource_after(delay_millis, model.channelmapping_resources, std::move(channelmapping_output), gate)) throw node_implementation_init_exception(); } - // example of using control protocol + // example of using IS-12 control protocol if (0 <= nmos::fields::control_protocol_ws_port(model.settings)) { // example to create a non-standard Gain control class diff --git a/Development/nmos/control_protocol_handlers.cpp b/Development/nmos/control_protocol_handlers.cpp index 2c3fdac56..e9d70f85c 100644 --- a/Development/nmos/control_protocol_handlers.cpp +++ b/Development/nmos/control_protocol_handlers.cpp @@ -6,12 +6,10 @@ namespace nmos { - get_control_protocol_class_handler make_get_control_protocol_class_handler(nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate) + get_control_protocol_class_handler make_get_control_protocol_class_handler(nmos::experimental::control_protocol_state& control_protocol_state) { return [&](const nc_class_id& class_id) { - slog::log(gate, SLOG_FLF) << "Retrieve control protocol control class of class_id: " << nmos::details::make_nc_class_id(class_id).serialize() << " from cache"; - auto lock = control_protocol_state.read_lock(); auto& control_classes = control_protocol_state.control_classes; @@ -24,31 +22,10 @@ namespace nmos }; } - add_control_protocol_class_handler make_add_control_protocol_class_handler(nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate) - { - return [&](const nc_class_id& class_id, const experimental::control_class& control_class) - { - slog::log(gate, SLOG_FLF) << "Add control protocol control class to cache"; - - auto lock = control_protocol_state.write_lock(); - - auto& control_classes = control_protocol_state.control_classes; - if (control_classes.end() == control_classes.find(class_id)) - { - return false; - } - - control_classes[class_id] = control_class; - return true; - }; - } - - get_control_protocol_datatype_handler make_get_control_protocol_datatype_handler(nmos::experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate) + get_control_protocol_datatype_handler make_get_control_protocol_datatype_handler(nmos::experimental::control_protocol_state& control_protocol_state) { return [&](const nmos::nc_name& name) { - slog::log(gate, SLOG_FLF) << "Retrieve control protocol datatype of name: " << name << " from cache"; - auto lock = control_protocol_state.read_lock(); auto found = control_protocol_state.datatypes.find(name); @@ -60,12 +37,10 @@ namespace nmos }; } - get_control_protocol_methods_handler make_get_control_protocol_methods_handler(experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate) + get_control_protocol_methods_handler make_get_control_protocol_methods_handler(experimental::control_protocol_state& control_protocol_state) { return [&]() { - slog::log(gate, SLOG_FLF) << "Retrieve all control protocol method handlers from cache"; - std::map methods; auto lock = control_protocol_state.read_lock(); diff --git a/Development/nmos/control_protocol_handlers.h b/Development/nmos/control_protocol_handlers.h index ce4c03b45..4f328ac3b 100644 --- a/Development/nmos/control_protocol_handlers.h +++ b/Development/nmos/control_protocol_handlers.h @@ -45,16 +45,13 @@ namespace nmos typedef std::function()> get_control_protocol_methods_handler; // construct callback to retrieve a specific control protocol class - get_control_protocol_class_handler make_get_control_protocol_class_handler(experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate); - - // construct callback to add control protocol class - add_control_protocol_class_handler make_add_control_protocol_class_handler(experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate); + get_control_protocol_class_handler make_get_control_protocol_class_handler(experimental::control_protocol_state& control_protocol_state); // construct callback to retrieve a specific datatype - get_control_protocol_datatype_handler make_get_control_protocol_datatype_handler(experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate); + get_control_protocol_datatype_handler make_get_control_protocol_datatype_handler(experimental::control_protocol_state& control_protocol_state); // construct callback to retrieve all method handlers - get_control_protocol_methods_handler make_get_control_protocol_methods_handler(experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate); + get_control_protocol_methods_handler make_get_control_protocol_methods_handler(experimental::control_protocol_state& control_protocol_state); } #endif diff --git a/Development/nmos/control_protocol_methods.cpp b/Development/nmos/control_protocol_methods.cpp index 6d8a93dea..87c43054c 100644 --- a/Development/nmos/control_protocol_methods.cpp +++ b/Development/nmos/control_protocol_methods.cpp @@ -323,7 +323,7 @@ namespace nmos } // NcBlock methods implementation - // Get descriptors of members of the block + // Gets descriptors of members of the block web::json::value get_member_descriptors(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler, get_control_protocol_datatype_handler, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... diff --git a/Development/nmos/control_protocol_utils.cpp b/Development/nmos/control_protocol_utils.cpp index 5fa97bd8c..a6a43e07f 100644 --- a/Development/nmos/control_protocol_utils.cpp +++ b/Development/nmos/control_protocol_utils.cpp @@ -32,6 +32,12 @@ namespace nmos return details::is_control_class(nc_block_class_id, class_id); } + // is the given class_id a NcWorker + bool is_nc_worker(const nc_class_id& class_id) + { + return details::is_control_class(nc_worker_class_id, class_id); + } + // is the given class_id a NcManager bool is_nc_manager(const nc_class_id& class_id) { @@ -50,6 +56,19 @@ namespace nmos return details::is_control_class(nc_class_manager_class_id, class_id); } + // construct NcClassId + nc_class_id make_nc_class_id(const nc_class_id& prefix, int32_t authority_key, const std::vector& suffix) + { + nc_class_id class_id = prefix; + class_id.push_back(authority_key); + class_id.insert(class_id.end(), suffix.begin(), suffix.end()); + return class_id; + } + nc_class_id make_nc_class_id(const nc_class_id& prefix, const std::vector& suffix) + { + return make_nc_class_id(prefix, 0, suffix); + } + // find control class property (NcPropertyDescriptor) web::json::value find_property(const nc_property_id& property_id, const nc_class_id& class_id_, get_control_protocol_class_handler get_control_protocol_class) { @@ -77,23 +96,13 @@ namespace nmos return value::null(); } - // construct NcClassId - nc_class_id make_nc_class_id(const nc_class_id& prefix, int32_t authority_key, const std::vector& suffix) - { - nc_class_id class_id = prefix; - class_id.push_back(authority_key); - class_id.insert(class_id.end(), suffix.begin(), suffix.end()); - return class_id; - } - - // get descriptors of members of the block + // get block member descriptors void get_member_descriptors(const resources& resources, resources::iterator resource, bool recurse, web::json::array& descriptors) { if (resource->data.has_field(nmos::fields::nc::members)) { const auto& members = nmos::fields::nc::members(resource->data); - // hmm, maybe an easier way to apeend array to array for (const auto& member : members) { web::json::push_back(descriptors, member); diff --git a/Development/nmos/control_protocol_utils.h b/Development/nmos/control_protocol_utils.h index 2ab06e9e7..da506c8fc 100644 --- a/Development/nmos/control_protocol_utils.h +++ b/Development/nmos/control_protocol_utils.h @@ -9,6 +9,9 @@ namespace nmos // is the given class_id a NcBlock bool is_nc_block(const nc_class_id& class_id); + // is the given class_id a NcWorker + bool is_nc_worker(const nc_class_id& class_id); + // is the given class_id a NcManager bool is_nc_manager(const nc_class_id& class_id); @@ -18,13 +21,14 @@ namespace nmos // is the given class_id a NcClassManager bool is_nc_class_manager(const nc_class_id& class_id); - // find control class property (NcPropertyDescriptor) - web::json::value find_property(const nc_property_id& property_id, const nc_class_id& class_id, get_control_protocol_class_handler get_control_protocol_class); - // construct NcClassId nc_class_id make_nc_class_id(const nc_class_id& prefix, int32_t authority_key, const std::vector& suffix); + nc_class_id make_nc_class_id(const nc_class_id& prefix, const std::vector& suffix); // using default authority_key 0 + + // find control class property (NcPropertyDescriptor) + web::json::value find_property(const nc_property_id& property_id, const nc_class_id& class_id, get_control_protocol_class_handler get_control_protocol_class); - // get descriptors of members of the block + // get block memeber descriptors void get_member_descriptors(const resources& resources, resources::iterator resource, bool recurse, web::json::array& descriptors); // find members with given role name or fragment diff --git a/Development/nmos/test/control_protocol_test.cpp b/Development/nmos/test/control_protocol_test.cpp index 8b44e335b..cff0a181c 100644 --- a/Development/nmos/test/control_protocol_test.cpp +++ b/Development/nmos/test/control_protocol_test.cpp @@ -1,12 +1,13 @@ // The first "test" is of course whether the header compiles standalone #include "nmos/control_protocol_resource.h" +#include "nmos/control_protocol_state.h" #include "nmos/control_protocol_typedefs.h" -#include "nmos/json_fields.h" +#include "nmos/control_protocol_utils.h" #include "bst/test/test.h" //////////////////////////////////////////////////////////////////////////////////////////// -BST_TEST_CASE(testNcObject) +BST_TEST_CASE(testNcClassDescriptor) { using web::json::value_of; using web::json::value; @@ -455,7 +456,7 @@ BST_TEST_CASE(testNcObject) BST_REQUIRE_EQUAL(nc_object_class, nc_object_class_); } -BST_TEST_CASE(testNcBlockMemberDescriptor) +BST_TEST_CASE(testNcDatatypeDescriptorStruct) { using web::json::value_of; using web::json::value; @@ -532,7 +533,7 @@ BST_TEST_CASE(testNcBlockMemberDescriptor) BST_REQUIRE_EQUAL(nc_datatype_descriptor, nc_datatype_descriptor_); } -BST_TEST_CASE(testNcClassId) +BST_TEST_CASE(testNcDatatypeTypedef) { using web::json::value_of; using web::json::value; @@ -552,7 +553,7 @@ BST_TEST_CASE(testNcClassId) BST_REQUIRE_EQUAL(nc_class_id, nc_class_id_); } -BST_TEST_CASE(testNcDeviceGenericState) +BST_TEST_CASE(testNcDatatypeDescriptorEnum) { using web::json::value_of; using web::json::value; @@ -626,3 +627,76 @@ BST_TEST_CASE(testNcDatatypeDescriptorPrimitive) BST_REQUIRE_EQUAL(test_primitive, test_primitive_); } + +BST_TEST_CASE(testNcClassId) +{ + BST_REQUIRE_EQUAL(false, nmos::is_nc_block({ })); + BST_REQUIRE_EQUAL(false, nmos::is_nc_block({ 1 })); + BST_REQUIRE_EQUAL(false, nmos::is_nc_block({ 1, 2 })); + BST_REQUIRE_EQUAL(false, nmos::is_nc_block({ 1, 2, 0 })); + BST_REQUIRE(nmos::is_nc_block(nmos::nc_block_class_id)); + BST_REQUIRE(nmos::is_nc_block(nmos::make_nc_class_id(nmos::nc_block_class_id, { 1 }))); + + BST_REQUIRE_EQUAL(false, nmos::is_nc_worker({ })); + BST_REQUIRE_EQUAL(false, nmos::is_nc_worker({ 1 })); + BST_REQUIRE_EQUAL(false, nmos::is_nc_worker({ 1, 1 })); + BST_REQUIRE_EQUAL(false, nmos::is_nc_worker({ 1, 1, 1 })); + BST_REQUIRE(nmos::is_nc_worker(nmos::nc_worker_class_id)); + BST_REQUIRE(nmos::is_nc_worker(nmos::make_nc_class_id(nmos::nc_worker_class_id, { 1 }))); + + BST_REQUIRE_EQUAL(false, nmos::is_nc_manager({ })); + BST_REQUIRE_EQUAL(false, nmos::is_nc_manager({ 1 })); + BST_REQUIRE_EQUAL(false, nmos::is_nc_manager({ 1, 1 })); + BST_REQUIRE_EQUAL(false, nmos::is_nc_manager({ 1, 1, 1 })); + BST_REQUIRE(nmos::is_nc_manager(nmos::nc_manager_class_id)); + BST_REQUIRE(nmos::is_nc_manager(nmos::make_nc_class_id(nmos::nc_manager_class_id, { 1 }))); + + BST_REQUIRE_EQUAL(false, nmos::is_nc_device_manager({ })); + BST_REQUIRE_EQUAL(false, nmos::is_nc_device_manager({ 1 })); + BST_REQUIRE_EQUAL(false, nmos::is_nc_device_manager({ 1, 1 })); + BST_REQUIRE_EQUAL(false, nmos::is_nc_device_manager({ 1, 1, 1 })); + BST_REQUIRE_EQUAL(false, nmos::is_nc_device_manager({ 1, 3, 2 })); + BST_REQUIRE(nmos::is_nc_device_manager(nmos::nc_device_manager_class_id)); + BST_REQUIRE(nmos::is_nc_device_manager(nmos::make_nc_class_id(nmos::nc_device_manager_class_id, { 1 }))); + + BST_REQUIRE_EQUAL(false, nmos::is_nc_class_manager({ })); + BST_REQUIRE_EQUAL(false, nmos::is_nc_class_manager({ 1 })); + BST_REQUIRE_EQUAL(false, nmos::is_nc_class_manager({ 1, 1 })); + BST_REQUIRE_EQUAL(false, nmos::is_nc_class_manager({ 1, 1, 1 })); + BST_REQUIRE_EQUAL(false, nmos::is_nc_class_manager({ 1, 3, 1 })); + BST_REQUIRE(nmos::is_nc_class_manager(nmos::nc_class_manager_class_id)); + BST_REQUIRE(nmos::is_nc_class_manager(nmos::make_nc_class_id(nmos::nc_class_manager_class_id, { 1 }))); +} + +BST_TEST_CASE(testFindProperty) +{ + auto& nc_block_members_property_id = nmos::nc_block_members_property_id; + auto& nc_block_class_id = nmos::nc_block_class_id; + auto& nc_worker_class_id = nmos::nc_worker_class_id; + const auto invalid_property_id = nmos::nc_property_id(1000, 1000); + const auto invalid_class_id = nmos::nc_class_id({ 1000, 1000 }); + + nmos::experimental::control_protocol_state control_protocol_state; + auto get_control_protocol_class = nmos::make_get_control_protocol_class_handler(control_protocol_state); + + { + // valid - find members property in NcBlock + auto property = nmos::find_property(nc_block_members_property_id, nc_block_class_id, get_control_protocol_class); + BST_REQUIRE(!property.is_null()); + } + { + // invalid - find members property in NcWorker + auto property = nmos::find_property(nc_block_members_property_id, nc_worker_class_id, get_control_protocol_class); + BST_REQUIRE(property.is_null()); + } + { + // invalid - find unknown propertry in NcBlock + auto property = nmos::find_property(invalid_property_id, nc_block_class_id, get_control_protocol_class); + BST_REQUIRE(property.is_null()); + } + { + // invalid - find unknown property in unknown class + auto property = nmos::find_property(invalid_property_id, invalid_class_id, get_control_protocol_class); + BST_REQUIRE(property.is_null()); + } +} From f773372b085bddcc55d22901203803cdec5673cb Mon Sep 17 00:00:00 2001 From: lo-simon Date: Thu, 21 Sep 2023 13:53:31 +0100 Subject: [PATCH 053/106] Add NcPropertyConstraintsNumber, NcPropertyConstraintsString, NcParameterConstraintsNumber, NcParameterConstraintsString datatypes --- .../nmos-cpp-node/node_implementation.cpp | 6 +- .../nmos/control_protocol_resource.cpp | 201 ++++++++++++++++++ Development/nmos/control_protocol_resource.h | 81 +++---- Development/nmos/control_protocol_state.cpp | 2 +- Development/nmos/control_protocol_state.h | 4 +- Development/nmos/control_protocol_typedefs.h | 8 + 6 files changed, 247 insertions(+), 55 deletions(-) diff --git a/Development/nmos-cpp-node/node_implementation.cpp b/Development/nmos-cpp-node/node_implementation.cpp index b0f6a0e45..cc264c2fe 100644 --- a/Development/nmos-cpp-node/node_implementation.cpp +++ b/Development/nmos-cpp-node/node_implementation.cpp @@ -958,10 +958,8 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr // Example control class properties std::vector example_control_properties = { nmos::experimental::make_control_class_property(U("Example enum property"), { 3, 1 }, enum_property, U("ExampleEnum")), - // todo constraints - nmos::experimental::make_control_class_property(U("Example string property"), { 3, 2 }, string_property, U("NcString"), false, false, false, false, value::null()), - // todo constraints - nmos::experimental::make_control_class_property(U("Example numeric property"), { 3, 3 }, number_property, U("NcUint64"), false, false, false, false, value::null()), + nmos::experimental::make_control_class_property(U("Example string property"), { 3, 2 }, string_property, U("NcString"), false, false, false, false, nmos::details::make_nc_parameter_constraints_string(10)), + nmos::experimental::make_control_class_property(U("Example numeric property"), { 3, 3 }, number_property, U("NcUint64"), false, false, false, false, nmos::details::make_nc_parameter_constraints_number(1000, 0, 1)), nmos::experimental::make_control_class_property(U("Example boolean property"), { 3, 4 }, boolean_property, U("NcBoolean")), nmos::experimental::make_control_class_property(U("Example object property"), { 3, 5 }, object_property, U("ExampleDataType")), nmos::experimental::make_control_class_property(U("Method no args invoke counter"), { 3, 6 }, method_no_args_count, U("NcUint64"), true), diff --git a/Development/nmos/control_protocol_resource.cpp b/Development/nmos/control_protocol_resource.cpp index acf369cac..53a035c56 100644 --- a/Development/nmos/control_protocol_resource.cpp +++ b/Development/nmos/control_protocol_resource.cpp @@ -1,5 +1,6 @@ #include "nmos/control_protocol_resource.h" +#include "cpprest/base_uri.h" #include "nmos/control_protocol_state.h" // for nmos::experimental::control_classes definitions #include "nmos/json_fields.h" @@ -109,6 +110,24 @@ namespace nmos { nmos::fields::nc::website, website } }); } + web::json::value make_nc_manufacturer(const utility::string_t& name, nc_organization_id organization_id, const web::uri& website) + { + using web::json::value; + + return make_nc_manufacturer(name, organization_id, value::string(website.to_string())); + } + web::json::value make_nc_manufacturer(const utility::string_t& name, nc_organization_id organization_id) + { + using web::json::value; + + return make_nc_manufacturer(name, organization_id, value::null()); + } + web::json::value make_nc_manufacturer(const utility::string_t& name) + { + using web::json::value; + + return make_nc_manufacturer(name, value::null(), value::null()); + } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncproduct // brand_name can be null @@ -128,6 +147,33 @@ namespace nmos { nmos::fields::nc::description, description } }); } + web::json::value make_nc_product(const utility::string_t& name, const utility::string_t& key, const utility::string_t& revision_level, + const utility::string_t& brand_name, const nc_uuid& uuid, const utility::string_t& description) + { + using web::json::value; + + return make_nc_product(name, key, revision_level, value::string(brand_name), value::string(uuid), value::string(description)); + } + web::json::value make_nc_product(const utility::string_t& name, const utility::string_t& key, const utility::string_t& revision_level, + const utility::string_t& brand_name, const nc_uuid& uuid) + { + using web::json::value; + + return make_nc_product(name, key, revision_level, value::string(brand_name), value::string(uuid), value::null()); + } + web::json::value make_nc_product(const utility::string_t& name, const utility::string_t& key, const utility::string_t& revision_level, + const utility::string_t& brand_name) + { + using web::json::value; + + return make_nc_product(name, key, revision_level, value::string(brand_name), value::null(), value::null()); + } + web::json::value make_nc_product(const utility::string_t& name, const utility::string_t& key, const utility::string_t& revision_level) + { + using web::json::value; + + return make_nc_product(name, key, revision_level, value::null(), value::null(), value::null()); + } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdeviceoperationalstate // device_specific_details can be null @@ -197,6 +243,18 @@ namespace nmos return make_nc_class_descriptor(value::string(description), class_id, name, fixed_role, properties, methods, events); } + web::json::value make_nc_class_descriptor(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const utility::string_t& fixed_role, const web::json::value& properties, const web::json::value& methods, const web::json::value& events) + { + using web::json::value; + + return make_nc_class_descriptor(value::string(description), class_id, name, value::string(fixed_role), properties, methods, events); + } + web::json::value make_nc_class_descriptor(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const web::json::value& properties, const web::json::value& methods, const web::json::value& events) + { + using web::json::value; + + return make_nc_class_descriptor(value::string(description), class_id, name, value::null(), properties, methods, events); + } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncenumitemdescriptor // description can be null @@ -443,6 +501,149 @@ namespace nmos return make_nc_datatype_typedef(value::string(description), name, is_sequence, parent_type, constraints); } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncpropertyconstraints + web::json::value make_nc_property_constraints(const nc_property_id& property_id, const web::json::value& default_value) + { + using web::json::value_of; + + return value_of({ + { nmos::fields::nc::property_id, make_nc_property_id(property_id) }, + { nmos::fields::nc::default_value, default_value } + }); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncpropertyconstraintsnumber + web::json::value make_nc_property_constraints_number(const nc_property_id& property_id, const web::json::value& default_value, const web::json::value& maximum, const web::json::value& minimum, const web::json::value& step) + { + using web::json::value; + + auto data = make_nc_property_constraints(property_id, default_value); + data[nmos::fields::nc::maximum] = maximum; + data[nmos::fields::nc::minimum] = minimum; + data[nmos::fields::nc::step] = step; + + return data; + } + web::json::value make_nc_property_constraints_number(const nc_property_id& property_id, uint64_t default_value, uint64_t maximum, uint64_t minimum, uint64_t step) + { + using web::json::value; + + return make_nc_property_constraints_number(property_id, value(default_value), value(maximum), value(minimum), value(step)); + } + web::json::value make_nc_property_constraints_number(const nc_property_id& property_id, uint64_t maximum, uint64_t minimum, uint64_t step) + { + using web::json::value; + + return make_nc_property_constraints_number(property_id, value::null(), maximum, minimum, step); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncpropertyconstraintsstring + web::json::value make_nc_property_constraints_string(const nc_property_id& property_id, const web::json::value& default_value, const web::json::value& max_characters, const web::json::value& pattern) + { + using web::json::value; + + auto data = make_nc_property_constraints(property_id, default_value); + data[nmos::fields::nc::max_characters] = max_characters; + data[nmos::fields::nc::pattern] = pattern; + + return data; + } + web::json::value make_nc_property_constraints_string(const nc_property_id& property_id, const utility::string_t& default_value, uint32_t max_characters, const nc_regex& pattern) + { + using web::json::value; + + return make_nc_property_constraints_string(property_id, value::string(default_value), max_characters, value::string(pattern)); + } + web::json::value make_nc_property_constraints_string(const nc_property_id& property_id, uint32_t max_characters, const nc_regex& pattern) + { + using web::json::value; + + return make_nc_property_constraints_string(property_id, value::null(), max_characters, value::string(pattern)); + } + web::json::value make_nc_property_constraints_string(const nc_property_id& property_id, uint32_t max_characters) + { + using web::json::value; + + return make_nc_property_constraints_string(property_id, value::null(), max_characters, value::null()); + } + web::json::value make_nc_property_constraints_string(const nc_property_id& property_id, const nc_regex& pattern) + { + using web::json::value; + + return make_nc_property_constraints_string(property_id, value::null(), value::null(), value::string(pattern)); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraints + web::json::value make_nc_parameter_constraints(const web::json::value& default_value) + { + using web::json::value_of; + + return value_of({ + { nmos::fields::nc::default_value, default_value } + }); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsnumber + web::json::value make_nc_parameter_constraints_number(const web::json::value& default_value, const web::json::value& maximum, const web::json::value& minimum, const web::json::value& step) + { + using web::json::value; + + auto data = make_nc_parameter_constraints(default_value); + data[nmos::fields::nc::maximum] = maximum; + data[nmos::fields::nc::minimum] = minimum; + data[nmos::fields::nc::step] = step; + + return data; + } + web::json::value make_nc_parameter_constraints_number(uint64_t default_value, uint64_t maximum, uint64_t minimum, uint64_t step) + { + using web::json::value; + + return make_nc_parameter_constraints_number(value(default_value), value(maximum), value(minimum), value(step)); + } + web::json::value make_nc_parameter_constraints_number(uint64_t maximum, uint64_t minimum, uint64_t step) + { + using web::json::value; + + return make_nc_parameter_constraints_number(value::null(), maximum, minimum, step); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsstring + web::json::value make_nc_parameter_constraints_string(const web::json::value& default_value, const web::json::value& max_characters, const web::json::value& pattern) + { + using web::json::value; + + auto data = make_nc_parameter_constraints(default_value); + data[nmos::fields::nc::max_characters] = max_characters; + data[nmos::fields::nc::pattern] = pattern; + + return data; + } + web::json::value make_nc_parameter_constraints_string(const utility::string_t& default_value, uint32_t max_characters, const nc_regex& pattern) + { + using web::json::value; + + return make_nc_parameter_constraints_string(value::string(default_value), max_characters, value::string(pattern)); + } + web::json::value make_nc_parameter_constraints_string(uint32_t max_characters, const nc_regex& pattern) + { + using web::json::value; + + return make_nc_parameter_constraints_string(value::null(), max_characters, value::string(pattern)); + } + web::json::value make_nc_parameter_constraints_string(uint32_t max_characters) + { + using web::json::value; + + return make_nc_parameter_constraints_string(value::null(), max_characters, value::null()); + } + web::json::value make_nc_parameter_constraints_string(const nc_regex& pattern) + { + using web::json::value; + + return make_nc_parameter_constraints_string(value::null(), value::null(), value::string(pattern)); + } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncobject web::json::value make_nc_object(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints) { diff --git a/Development/nmos/control_protocol_resource.h b/Development/nmos/control_protocol_resource.h index 2479a7f9f..af832ab16 100644 --- a/Development/nmos/control_protocol_resource.h +++ b/Development/nmos/control_protocol_resource.h @@ -10,6 +10,7 @@ namespace web { class value; } + class uri; } namespace nmos @@ -44,111 +45,95 @@ namespace nmos nc_class_id parse_nc_class_id(const web::json::array& class_id); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncmanufacturer - web::json::value make_nc_manufacturer(const utility::string_t& name, const web::json::value& organization_id = web::json::value::null(), const web::json::value& website = web::json::value::null()); + web::json::value make_nc_manufacturer(const utility::string_t& name, nc_organization_id organization_id, const web::uri& website); + web::json::value make_nc_manufacturer(const utility::string_t& name, nc_organization_id organization_id); + web::json::value make_nc_manufacturer(const utility::string_t& name); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncproduct - // brand_name can be null - // uuid can be null - // description can be null web::json::value make_nc_product(const utility::string_t& name, const utility::string_t& key, const utility::string_t& revision_level, - const web::json::value& brand_name = web::json::value::null(), const web::json::value& uuid = web::json::value::null(), const web::json::value& description = web::json::value::null()); + const utility::string_t& brand_name, const nc_uuid& uuid, const utility::string_t& description); + web::json::value make_nc_product(const utility::string_t& name, const utility::string_t& key, const utility::string_t& revision_level, + const utility::string_t& brand_name, const nc_uuid& uuid); + web::json::value make_nc_product(const utility::string_t& name, const utility::string_t& key, const utility::string_t& revision_level, + const utility::string_t& brand_name); + web::json::value make_nc_product(const utility::string_t& name, const utility::string_t& key, const utility::string_t& revision_level); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdeviceoperationalstate // device_specific_details can be null web::json::value make_nc_device_operational_state(nc_device_generic_state::state generic_state, const web::json::value& device_specific_details); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdescriptor - // description can be null - web::json::value make_nc_descriptor(const web::json::value& description); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncblockmemberdescriptor - // description can be null - // user_label can be null - web::json::value make_nc_block_member_descriptor(const web::json::value& description, const utility::string_t& role, nc_oid oid, bool constant_oid, const nc_class_id& class_id, const web::json::value& user_label, nc_oid owner); web::json::value make_nc_block_member_descriptor(const utility::string_t& description, const utility::string_t& role, nc_oid oid, bool constant_oid, const nc_class_id& class_id, const utility::string_t& user_label, nc_oid owner); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncclassdescriptor - // description can be null // fixedRole can be null - web::json::value make_nc_class_descriptor(const web::json::value& description, const nc_class_id& class_id, const nc_name& name, const web::json::value& fixed_role, const web::json::value& properties, const web::json::value& methods, const web::json::value& events); web::json::value make_nc_class_descriptor(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const web::json::value& fixed_role, const web::json::value& properties, const web::json::value& methods, const web::json::value& events); + web::json::value make_nc_class_descriptor(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const utility::string_t& fixed_role, const web::json::value& properties, const web::json::value& methods, const web::json::value& events); + web::json::value make_nc_class_descriptor(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const web::json::value& properties, const web::json::value& methods, const web::json::value& events); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncenumitemdescriptor - // description can be null - web::json::value make_nc_enum_item_descriptor(const web::json::value& description, const nc_name& name, uint16_t val); web::json::value make_nc_enum_item_descriptor(const utility::string_t& description, const nc_name& name, uint16_t val); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#nceventdescriptor - // description can be null - // id = make_nc_event_id(level, index) - web::json::value make_nc_event_descriptor(const web::json::value& description, const nc_event_id& id, const nc_name& name, const utility::string_t& event_datatype, bool is_deprecated); web::json::value make_nc_event_descriptor(const utility::string_t& description, const nc_event_id& id, const nc_name& name, const utility::string_t& event_datatype, bool is_deprecated); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncfielddescriptor - // description can be null - // type_name can be null // constraints can be null - web::json::value make_nc_field_descriptor(const web::json::value& description, const nc_name& name, const web::json::value& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints); web::json::value make_nc_field_descriptor(const utility::string_t& description, const nc_name& name, const utility::string_t& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints); web::json::value make_nc_field_descriptor(const utility::string_t& description, const nc_name& name, bool is_nullable, bool is_sequence, const web::json::value& constraints); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncmethoddescriptor - // description can be null - // id = make_nc_method_id(level, index) // sequence parameters - web::json::value make_nc_method_descriptor(const web::json::value& description, const nc_method_id& id, const nc_name& name, const utility::string_t& result_datatype, const web::json::value& parameters, bool is_deprecated); web::json::value make_nc_method_descriptor(const utility::string_t& description, const nc_method_id& id, const nc_name& name, const utility::string_t& result_datatype, const web::json::value& parameters, bool is_deprecated); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterdescriptor - // description can be null - // type_name can be null - web::json::value make_nc_parameter_descriptor(const web::json::value& description, const nc_name& name, const web::json::value& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints); + // constraints can be null web::json::value make_nc_parameter_descriptor(const utility::string_t& description, const nc_name& name, bool is_nullable, bool is_sequence, const web::json::value& constraints); web::json::value make_nc_parameter_descriptor(const utility::string_t& description, const nc_name& name, const utility::string_t& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncpropertydescriptor - // description can be null - // id = make_nc_property_id(level, index); - // type_name can be null // constraints can be null - web::json::value make_nc_property_descriptor(const web::json::value& description, const nc_property_id& id, const nc_name& name, const web::json::value& type_name, - bool is_read_only, bool is_nullable, bool is_sequence, bool is_deprecated, const web::json::value& constraints); web::json::value make_nc_property_descriptor(const utility::string_t& description, const nc_property_id& id, const nc_name& name, const utility::string_t& type_name, bool is_read_only, bool is_nullable, bool is_sequence, bool is_deprecated, const web::json::value& constraints); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdatatypedescriptor - // description can be null - // constraints can be null - web::json::value make_nc_datatype_descriptor(const web::json::value& description, const nc_name& name, nc_datatype_type::type type, const web::json::value& constraints); - // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdatatypedescriptorenum - // description can be null // constraints can be null // items: sequence - web::json::value make_nc_datatype_descriptor_enum(const web::json::value& description, const nc_name& name, const web::json::value& items, const web::json::value& constraints); web::json::value make_nc_datatype_descriptor_enum(const utility::string_t& description, const nc_name& name, const web::json::value& items, const web::json::value& constraints); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdatatypedescriptorprimitive - // description can be null // constraints can be null - web::json::value make_nc_datatype_descriptor_primitive(const web::json::value& description, const nc_name& name, const web::json::value& constraints); web::json::value make_nc_datatype_descriptor_primitive(const utility::string_t& description, const nc_name& name, const web::json::value& constraints); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdatatypedescriptorstruct - // description can be null // constraints can be null // fields: sequence - // parent_type can be null - web::json::value make_nc_datatype_descriptor_struct(const web::json::value& description, const nc_name& name, const web::json::value& fields, const web::json::value& parent_type, const web::json::value& constraints); web::json::value make_nc_datatype_descriptor_struct(const utility::string_t& description, const nc_name& name, const web::json::value& fields, const utility::string_t& parent_type, const web::json::value& constraints); web::json::value make_nc_datatype_descriptor_struct(const utility::string_t& description, const nc_name& name, const web::json::value& fields, const web::json::value& constraints); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdatatypedescriptortypedef - // description can be null - // constraints can be null - web::json::value make_nc_datatype_typedef(const web::json::value& description, const nc_name& name, bool is_sequence, const utility::string_t& parent_type, const web::json::value& constraints); web::json::value make_nc_datatype_typedef(const utility::string_t& description, const nc_name& name, bool is_sequence, const utility::string_t& parent_type, const web::json::value& constraints); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncpropertyconstraintsnumber + web::json::value make_nc_property_constraints_number(const nc_property_id& property_id, uint64_t default_value, uint64_t maximum, uint64_t minimum, uint64_t step); + web::json::value make_nc_property_constraints_number(const nc_property_id& property_id, uint64_t maximum, uint64_t minimum, uint64_t step); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncpropertyconstraintsstring + web::json::value make_nc_property_constraints_string(const nc_property_id& property_id, const utility::string_t& default_value, uint32_t max_characters, const nc_regex& pattern); + web::json::value make_nc_property_constraints_string(const nc_property_id& property_id, uint32_t max_characters, const nc_regex& pattern); + web::json::value make_nc_property_constraints_string(const nc_property_id& property_id, uint32_t max_characters); + web::json::value make_nc_property_constraints_string(const nc_property_id& property_id, const nc_regex& pattern); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsnumber + web::json::value make_nc_parameter_constraints_number(uint64_t default_value, uint64_t maximum, uint64_t minimum, uint64_t step); + web::json::value make_nc_parameter_constraints_number(uint64_t maximum, uint64_t minimum, uint64_t step); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsstring + web::json::value make_nc_parameter_constraints_string(const utility::string_t& default_value, uint32_t max_characters, const nc_regex& pattern); + web::json::value make_nc_parameter_constraints_string(uint32_t max_characters, const nc_regex& pattern); + web::json::value make_nc_parameter_constraints_string(uint32_t max_characters); + web::json::value make_nc_parameter_constraints_string(const nc_regex& pattern); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncobject web::json::value make_nc_object(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints); diff --git a/Development/nmos/control_protocol_state.cpp b/Development/nmos/control_protocol_state.cpp index f9a24eb65..80ff4254c 100644 --- a/Development/nmos/control_protocol_state.cpp +++ b/Development/nmos/control_protocol_state.cpp @@ -30,7 +30,7 @@ namespace nmos web::json::value events = value::array(); for (const auto& event : events_) { web::json::push_back(events, event); } - return { value::string(description), class_id, name, fixed_role, properties, methods, events, method_handlers }; + return { description, class_id, name, fixed_role, properties, methods, events, method_handlers }; } } // create control class with fixed role diff --git a/Development/nmos/control_protocol_state.h b/Development/nmos/control_protocol_state.h index 3be439b23..b95c26e48 100644 --- a/Development/nmos/control_protocol_state.h +++ b/Development/nmos/control_protocol_state.h @@ -15,7 +15,7 @@ namespace nmos { struct control_class // NcClassDescriptor { - web::json::value description; + utility::string_t description; nmos::nc_class_id class_id; nmos::nc_name name; web::json::value fixed_role; @@ -30,7 +30,7 @@ namespace nmos : class_id({ 0 }) {} - control_class(web::json::value description, nmos::nc_class_id class_id, nmos::nc_name name, web::json::value fixed_role, web::json::value properties, web::json::value methods, web::json::value events, nmos::experimental::methods method_handlers) + control_class(utility::string_t description, nmos::nc_class_id class_id, nmos::nc_name name, web::json::value fixed_role, web::json::value properties, web::json::value methods, web::json::value events, nmos::experimental::methods method_handlers) : description(std::move(description)) , class_id(std::move(class_id)) , name(std::move(name)) diff --git a/Development/nmos/control_protocol_typedefs.h b/Development/nmos/control_protocol_typedefs.h index 92e655df2..6ba68ac25 100644 --- a/Development/nmos/control_protocol_typedefs.h +++ b/Development/nmos/control_protocol_typedefs.h @@ -237,6 +237,14 @@ namespace nmos // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncuuid typedef utility::string_t nc_uuid; + // NcRegex + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncregex + typedef utility::string_t nc_regex; + + // NcOrganizationId + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncorganizationid + typedef int32_t nc_organization_id; + // NcClassId // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncclassid typedef std::vector nc_class_id; From 1bd72830ff6f24aac089341b3fe5997fd4092ced Mon Sep 17 00:00:00 2001 From: lo-simon Date: Thu, 21 Sep 2023 14:48:27 +0100 Subject: [PATCH 054/106] Tidy up make_nc_class_descriptor --- Development/nmos/control_protocol_methods.cpp | 6 +++- .../nmos/control_protocol_resource.cpp | 29 +++++++++---------- Development/nmos/control_protocol_resource.h | 2 -- .../nmos/test/control_protocol_test.cpp | 2 +- 4 files changed, 19 insertions(+), 20 deletions(-) diff --git a/Development/nmos/control_protocol_methods.cpp b/Development/nmos/control_protocol_methods.cpp index 87c43054c..d67842cad 100644 --- a/Development/nmos/control_protocol_methods.cpp +++ b/Development/nmos/control_protocol_methods.cpp @@ -455,6 +455,8 @@ namespace nmos // Get a single class descriptor web::json::value get_control_class(nmos::resources&, nmos::resources::iterator, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate) { + using web::json::value; + const auto& class_id = parse_nc_class_id(nmos::fields::nc::class_id(arguments)); // Class id to search for const auto& include_inherited = nmos::fields::nc::include_inherited(arguments); // If set the descriptor would contain all inherited elements @@ -494,7 +496,9 @@ namespace nmos inherited_class_id.pop_back(); } } - auto descriptor = details::make_nc_class_descriptor(description, class_id, name, fixed_role, properties, methods, events); + const auto descriptor = fixed_role.is_null() + ? details::make_nc_class_descriptor(description, class_id, name, properties, methods, events) + : details::make_nc_class_descriptor(description, class_id, name, fixed_role.as_string(), properties, methods, events); return make_control_protocol_message_response(handle, { nc_method_status::ok }, descriptor); } diff --git a/Development/nmos/control_protocol_resource.cpp b/Development/nmos/control_protocol_resource.cpp index 53a035c56..590d36cc9 100644 --- a/Development/nmos/control_protocol_resource.cpp +++ b/Development/nmos/control_protocol_resource.cpp @@ -237,12 +237,6 @@ namespace nmos return data; } - web::json::value make_nc_class_descriptor(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const web::json::value& fixed_role, const web::json::value& properties, const web::json::value& methods, const web::json::value& events) - { - using web::json::value; - - return make_nc_class_descriptor(value::string(description), class_id, name, fixed_role, properties, methods, events); - } web::json::value make_nc_class_descriptor(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const utility::string_t& fixed_role, const web::json::value& properties, const web::json::value& methods, const web::json::value& events) { using web::json::value; @@ -729,7 +723,10 @@ namespace nmos for (const auto& control_class : control_protocol_state.control_classes) { auto& ctl_class = control_class.second; - web::json::push_back(control_classes, make_nc_class_descriptor(ctl_class.description, ctl_class.class_id, ctl_class.name, ctl_class.fixed_role, ctl_class.properties, ctl_class.methods, ctl_class.events)); + const auto class_description = ctl_class.fixed_role.is_null() + ? make_nc_class_descriptor(ctl_class.description, ctl_class.class_id, ctl_class.name, ctl_class.properties, ctl_class.methods, ctl_class.events) + : make_nc_class_descriptor(ctl_class.description, ctl_class.class_id, ctl_class.name, ctl_class.fixed_role.as_string(), ctl_class.properties, ctl_class.methods, ctl_class.events); + web::json::push_back(control_classes, class_description); } // add datatypes @@ -1166,7 +1163,7 @@ namespace nmos { using web::json::value; - return details::make_nc_class_descriptor(U("NcObject class descriptor"), nc_object_class_id, U("NcObject"), value::null(), make_nc_object_properties(), make_nc_object_methods(), make_nc_object_events()); + return details::make_nc_class_descriptor(U("NcObject class descriptor"), nc_object_class_id, U("NcObject"), make_nc_object_properties(), make_nc_object_methods(), make_nc_object_events()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/classes/1.1.html @@ -1174,7 +1171,7 @@ namespace nmos { using web::json::value; - return details::make_nc_class_descriptor(U("NcBlock class descriptor"), nc_block_class_id, U("NcBlock"), value::null(), make_nc_block_properties(), make_nc_block_methods(), make_nc_block_events()); + return details::make_nc_class_descriptor(U("NcBlock class descriptor"), nc_block_class_id, U("NcBlock"), make_nc_block_properties(), make_nc_block_methods(), make_nc_block_events()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/classes/1.2.html @@ -1182,7 +1179,7 @@ namespace nmos { using web::json::value; - return details::make_nc_class_descriptor(U("NcWorker class descriptor"), nc_worker_class_id, U("NcWorker"), value::null(), make_nc_worker_properties(), make_nc_worker_methods(), make_nc_worker_events()); + return details::make_nc_class_descriptor(U("NcWorker class descriptor"), nc_worker_class_id, U("NcWorker"), make_nc_worker_properties(), make_nc_worker_methods(), make_nc_worker_events()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/classes/1.3.html @@ -1190,7 +1187,7 @@ namespace nmos { using web::json::value; - return details::make_nc_class_descriptor(U("NcManager class descriptor"), nc_manager_class_id, U("NcManager"), value::null(), make_nc_manager_properties(), make_nc_manager_methods(), make_nc_manager_events()); + return details::make_nc_class_descriptor(U("NcManager class descriptor"), nc_manager_class_id, U("NcManager"), make_nc_manager_properties(), make_nc_manager_methods(), make_nc_manager_events()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/classes/1.3.1.html @@ -1198,7 +1195,7 @@ namespace nmos { using web::json::value; - return details::make_nc_class_descriptor(U("NcDeviceManager class descriptor"), nc_device_manager_class_id, U("NcDeviceManager"), value::string(U("DeviceManager")), make_nc_device_manager_properties(), make_nc_device_manager_methods(), make_nc_device_manager_events()); + return details::make_nc_class_descriptor(U("NcDeviceManager class descriptor"), nc_device_manager_class_id, U("NcDeviceManager"), U("DeviceManager"), make_nc_device_manager_properties(), make_nc_device_manager_methods(), make_nc_device_manager_events()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/classes/1.3.2.html @@ -1206,7 +1203,7 @@ namespace nmos { using web::json::value; - return details::make_nc_class_descriptor(U("NcClassManager class descriptor"), nc_class_manager_class_id, U("NcClassManager"), value::string(U("ClassManager")), make_nc_class_manager_properties(), make_nc_class_manager_methods(), make_nc_class_manager_events()); + return details::make_nc_class_descriptor(U("NcClassManager class descriptor"), nc_class_manager_class_id, U("NcClassManager"), U("ClassManager"), make_nc_class_manager_properties(), make_nc_class_manager_methods(), make_nc_class_manager_events()); } // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/identification/#ncidentbeacon @@ -1214,7 +1211,7 @@ namespace nmos { using web::json::value; - return details::make_nc_class_descriptor(U("NcIdentBeacon class descriptor"), nc_ident_beacon_class_id, U("NcIdentBeacon"), value::null(), make_nc_ident_beacon_properties(), make_nc_ident_beacon_methods(), make_nc_ident_beacon_events()); + return details::make_nc_class_descriptor(U("NcIdentBeacon class descriptor"), nc_ident_beacon_class_id, U("NcIdentBeacon"), make_nc_ident_beacon_properties(), make_nc_ident_beacon_methods(), make_nc_ident_beacon_events()); } // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitor @@ -1222,7 +1219,7 @@ namespace nmos { using web::json::value; - return details::make_nc_class_descriptor(U("NcReceiverMonitor class descriptor"), nc_receiver_monitor_class_id, U("NcReceiverMonitor"), value::null(), make_nc_receiver_monitor_properties(), make_nc_receiver_monitor_methods(), make_nc_receiver_monitor_events()); + return details::make_nc_class_descriptor(U("NcReceiverMonitor class descriptor"), nc_receiver_monitor_class_id, U("NcReceiverMonitor"), make_nc_receiver_monitor_properties(), make_nc_receiver_monitor_methods(), make_nc_receiver_monitor_events()); } // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitorprotected @@ -1230,7 +1227,7 @@ namespace nmos { using web::json::value; - return details::make_nc_class_descriptor(U("NcReceiverMonitorProtected class descriptor"), nc_receiver_monitor_protected_class_id, U("NcReceiverMonitorProtected"), value::null(), make_nc_receiver_monitor_protected_properties(), make_nc_receiver_monitor_protected_methods(), make_nc_receiver_monitor_protected_events()); + return details::make_nc_class_descriptor(U("NcReceiverMonitorProtected class descriptor"), nc_receiver_monitor_protected_class_id, U("NcReceiverMonitorProtected"), make_nc_receiver_monitor_protected_properties(), make_nc_receiver_monitor_protected_methods(), make_nc_receiver_monitor_protected_events()); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcBlockMemberDescriptor.html diff --git a/Development/nmos/control_protocol_resource.h b/Development/nmos/control_protocol_resource.h index af832ab16..1237f4787 100644 --- a/Development/nmos/control_protocol_resource.h +++ b/Development/nmos/control_protocol_resource.h @@ -66,8 +66,6 @@ namespace nmos web::json::value make_nc_block_member_descriptor(const utility::string_t& description, const utility::string_t& role, nc_oid oid, bool constant_oid, const nc_class_id& class_id, const utility::string_t& user_label, nc_oid owner); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncclassdescriptor - // fixedRole can be null - web::json::value make_nc_class_descriptor(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const web::json::value& fixed_role, const web::json::value& properties, const web::json::value& methods, const web::json::value& events); web::json::value make_nc_class_descriptor(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const utility::string_t& fixed_role, const web::json::value& properties, const web::json::value& methods, const web::json::value& events); web::json::value make_nc_class_descriptor(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const web::json::value& properties, const web::json::value& methods, const web::json::value& events); diff --git a/Development/nmos/test/control_protocol_test.cpp b/Development/nmos/test/control_protocol_test.cpp index cff0a181c..91a115a42 100644 --- a/Development/nmos/test/control_protocol_test.cpp +++ b/Development/nmos/test/control_protocol_test.cpp @@ -452,7 +452,7 @@ BST_TEST_CASE(testNcClassDescriptor) event_property_changed }) } }); - const auto nc_object_class_ = nmos::details::make_nc_class_descriptor(U("NcObject class descriptor"), nmos::nc_object_class_id, U("NcObject"), value::null(), nmos::make_nc_object_properties(), nmos::make_nc_object_methods(), nmos::make_nc_object_events()); + const auto nc_object_class_ = nmos::details::make_nc_class_descriptor(U("NcObject class descriptor"), nmos::nc_object_class_id, U("NcObject"), nmos::make_nc_object_properties(), nmos::make_nc_object_methods(), nmos::make_nc_object_events()); BST_REQUIRE_EQUAL(nc_object_class, nc_object_class_); } From 84f13d45907ac344c068bfd85f23003a5069ec21 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Fri, 6 Oct 2023 15:11:07 +0100 Subject: [PATCH 055/106] Fix to handle empty NCP URL path --- Development/nmos/control_protocol_ws_api.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Development/nmos/control_protocol_ws_api.cpp b/Development/nmos/control_protocol_ws_api.cpp index 2fd5e1c67..c6f7d39a8 100644 --- a/Development/nmos/control_protocol_ws_api.cpp +++ b/Development/nmos/control_protocol_ws_api.cpp @@ -225,9 +225,6 @@ namespace nmos const auto& ws_ncp_path = connection_uri.path(); slog::log(gate, SLOG_FLF) << "Received websocket message: " << msg << " on connection: " << ws_ncp_path; - // extract the control protocol api version from the ws_ncp_path - const auto version = nmos::parse_api_version(web::uri::split_path(ws_ncp_path).back()); - auto websocket = websockets.right.find(connection_id); if (websockets.right.end() != websocket) { @@ -241,6 +238,11 @@ namespace nmos { try { + // extract the control protocol api version from the ws_ncp_path + if (web::uri::split_path(ws_ncp_path).empty()) { throw std::invalid_argument("empty URL"); } + const auto version = nmos::parse_api_version(web::uri::split_path(ws_ncp_path).back()); + + // convert message to JSON const auto message = value::parse(utility::conversions::to_string_t(msg)); // validate the base-message From 645ff22992b1eeeea47c4596cb1b827ac74878ac Mon Sep 17 00:00:00 2001 From: lo-simon Date: Fri, 6 Oct 2023 15:37:42 +0100 Subject: [PATCH 056/106] Code fix to construct nc_property_changed_event_data, thanks for @maweit reviewing --- Development/nmos/control_protocol_methods.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/Development/nmos/control_protocol_methods.cpp b/Development/nmos/control_protocol_methods.cpp index d67842cad..598d73016 100644 --- a/Development/nmos/control_protocol_methods.cpp +++ b/Development/nmos/control_protocol_methods.cpp @@ -60,12 +60,13 @@ namespace nmos return make_control_protocol_message_response(handle, { nc_method_status::parameter_error }); } - const auto notification = make_control_protocol_notification(nmos::fields::nc::oid(resource->data), nc_object_property_changed_event_id, { parse_nc_property_id(property_id), nc_property_change_type::type::value_changed, val }); + const nc_property_changed_event_data property_changed_event_data{ parse_nc_property_id(property_id), nc_property_change_type::type::value_changed, val }; + const auto notification = make_control_protocol_notification(nmos::fields::nc::oid(resource->data), nc_object_property_changed_event_id, property_changed_event_data); const auto notification_event = make_control_protocol_notification(web::json::value_of({ notification })); modify_resource(resources, resource->id, [&](nmos::resource& resource) { - resource.data[nmos::fields::nc::name(property)] = val; + resource.data[nmos::fields::nc::name(property)] = property_changed_event_data.value; }, notification_event); @@ -146,12 +147,13 @@ namespace nmos if (data.as_array().size() > (size_t)index) { - const auto notification = make_control_protocol_notification(nmos::fields::nc::oid(resource->data), nc_object_property_changed_event_id, { parse_nc_property_id(property_id), nc_property_change_type::type::sequence_item_changed, val, nc_id(index) }); + const nc_property_changed_event_data property_changed_event_data{ parse_nc_property_id(property_id), nc_property_change_type::type::sequence_item_changed, val, nc_id(index) }; + const auto notification = make_control_protocol_notification(nmos::fields::nc::oid(resource->data), nc_object_property_changed_event_id, property_changed_event_data); const auto notification_event = make_control_protocol_notification(web::json::value_of({ notification })); modify_resource(resources, resource->id, [&](nmos::resource& resource) { - resource.data[nmos::fields::nc::name(property)][index] = val; + resource.data[nmos::fields::nc::name(property)][index] = property_changed_event_data.value; }, notification_event); @@ -197,14 +199,15 @@ namespace nmos auto& data = resource->data.at(nmos::fields::nc::name(property)); const nc_id sequence_item_index = data.is_null() ? 0 : nc_id(data.as_array().size()); - const auto notification = make_control_protocol_notification(nmos::fields::nc::oid(resource->data), nc_object_property_changed_event_id, { parse_nc_property_id(property_id), nc_property_change_type::type::sequence_item_added, val, sequence_item_index }); + const nc_property_changed_event_data property_changed_event_data{ parse_nc_property_id(property_id), nc_property_change_type::type::sequence_item_added, val, sequence_item_index }; + const auto notification = make_control_protocol_notification(nmos::fields::nc::oid(resource->data), nc_object_property_changed_event_id, property_changed_event_data); const auto notification_event = make_control_protocol_notification(web::json::value_of({ notification })); modify_resource(resources, resource->id, [&](nmos::resource& resource) { auto& sequence = resource.data[nmos::fields::nc::name(property)]; if (data.is_null()) { sequence = value::array(); } - web::json::push_back(sequence, val); + web::json::push_back(sequence, property_changed_event_data.value); }, notification_event); @@ -243,7 +246,8 @@ namespace nmos if (data.as_array().size() > (size_t)index) { - const auto notification = make_control_protocol_notification(nmos::fields::nc::oid(resource->data), nc_object_property_changed_event_id, { parse_nc_property_id(property_id), nc_property_change_type::type::sequence_item_removed, data.as_array().at(index), nc_id(index)}); + const nc_property_changed_event_data property_changed_event_data{ parse_nc_property_id(property_id), nc_property_change_type::type::sequence_item_removed, data.as_array().at(index), nc_id(index) }; + const auto notification = make_control_protocol_notification(nmos::fields::nc::oid(resource->data), nc_object_property_changed_event_id, property_changed_event_data); const auto notification_event = make_control_protocol_notification(web::json::value_of({ notification })); modify_resource(resources, resource->id, [&](nmos::resource& resource) From 472883ecdc8a9be8dc4c0d898521e73edc7b5f05 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Fri, 13 Oct 2023 23:11:19 +0100 Subject: [PATCH 057/106] Insert root block resource to the model will also inserting all its nested control protocol resources to the model as suggested by @maweit --- .../nmos-cpp-node/node_implementation.cpp | 37 +++++++++++++------ Development/nmos/control_protocol_resource.h | 18 +++++++++ .../nmos/control_protocol_resources.cpp | 10 ++--- Development/nmos/control_protocol_resources.h | 10 ++--- Development/nmos/control_protocol_utils.cpp | 21 +++++------ Development/nmos/control_protocol_utils.h | 6 ++- 6 files changed, 67 insertions(+), 35 deletions(-) diff --git a/Development/nmos-cpp-node/node_implementation.cpp b/Development/nmos-cpp-node/node_implementation.cpp index cc264c2fe..9edcc0f2c 100644 --- a/Development/nmos-cpp-node/node_implementation.cpp +++ b/Development/nmos-cpp-node/node_implementation.cpp @@ -300,6 +300,27 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr return success; }; + // it is important that the model be locked before inserting, updating or deleting a resource + // and that the the node behaviour thread be notified after doing so + const auto insert_root_after = [&model, insert_resource_after](unsigned int milliseconds, nmos::control_protocol_resource& root, slog::base_gate& gate) + { + std::function insert_resources; + + insert_resources = [&milliseconds, insert_resource_after, &insert_resources, &gate](nmos::resources& resources, nmos::control_protocol_resource& resource) + { + for (auto& resource_ : resource.resources) + { + insert_resources(resources, resource_); + if (!insert_resource_after(milliseconds, resources, std::move(resource_), gate)) throw node_implementation_init_exception(); + } + }; + + auto& resources = model.control_protocol_resources; + + insert_resources(resources, root); + if (!insert_resource_after(milliseconds, resources, std::move(root), gate)) throw node_implementation_init_exception(); + }; + const auto resolve_auto = make_node_implementation_auto_resolver(model.settings); const auto set_transportfile = make_node_implementation_transportfile_setter(model.node_resources, model.settings); @@ -923,7 +944,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr auto data = nmos::details::make_nc_worker(gain_control_class_id, oid, true, owner, role, value::string(user_label), description, touchpoints, runtime_property_constraints, true); data[gain_value] = value::number(gain); - return nmos::resource{ nmos::is12_versions::v1_0, nmos::types::nc_object, std::move(data), true }; + return nmos::control_protocol_resource{ nmos::is12_versions::v1_0, nmos::types::nc_object, std::move(data), true }; }; // example to create a non-standard Example control class @@ -1111,7 +1132,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr data[object_sequence] = sequence; } - return nmos::resource{ nmos::is12_versions::v1_0, nmos::types::nc_object, std::move(data), true }; + return nmos::control_protocol_resource{ nmos::is12_versions::v1_0, nmos::types::nc_object, std::move(data), true }; }; @@ -1172,16 +1193,8 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr // add device-manager to root-block nmos::push_back(root_block, device_manager); - // insert resources to model - if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(example_control), gate)) throw node_implementation_init_exception(); - if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(left_gain), gate)) throw node_implementation_init_exception(); - if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(right_gain), gate)) throw node_implementation_init_exception(); - if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(master_gain), gate)) throw node_implementation_init_exception(); - if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(channel_gain), gate)) throw node_implementation_init_exception(); - if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(stereo_gain), gate)) throw node_implementation_init_exception(); - if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(device_manager), gate)) throw node_implementation_init_exception(); - if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(class_manager), gate)) throw node_implementation_init_exception(); - if (!insert_resource_after(delay_millis, model.control_protocol_resources, std::move(root_block), gate)) throw node_implementation_init_exception(); + // insert control protocol resources to model + insert_root_after(delay_millis, root_block, gate); } } diff --git a/Development/nmos/control_protocol_resource.h b/Development/nmos/control_protocol_resource.h index 1237f4787..7647bfd29 100644 --- a/Development/nmos/control_protocol_resource.h +++ b/Development/nmos/control_protocol_resource.h @@ -3,6 +3,7 @@ #include "cpprest/json_utils.h" #include "nmos/control_protocol_typedefs.h" +#include "nmos/resource.h" namespace web { @@ -13,6 +14,23 @@ namespace web class uri; } +namespace nmos +{ + struct control_protocol_resource : resource + { + control_protocol_resource(api_version version, nmos::type type, web::json::value&& data, nmos::id id, bool never_expire) + : resource(version, type, std::move(data), id, never_expire) + {} + + control_protocol_resource(api_version version, nmos::type type, web::json::value data, bool never_expire) + : resource(version, type, data, never_expire) + {} + + // temporary storage to hold the resources until they are moved to the model resources + std::vector resources; + }; +} + namespace nmos { namespace experimental diff --git a/Development/nmos/control_protocol_resources.cpp b/Development/nmos/control_protocol_resources.cpp index f576fd44d..df0b6b9d9 100644 --- a/Development/nmos/control_protocol_resources.cpp +++ b/Development/nmos/control_protocol_resources.cpp @@ -10,7 +10,7 @@ namespace nmos namespace details { // create block resource - resource make_block(nmos::nc_oid oid, const web::json::value& owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, const web::json::value& members) + control_protocol_resource make_block(nmos::nc_oid oid, const web::json::value& owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, const web::json::value& members) { using web::json::value; @@ -21,7 +21,7 @@ namespace nmos } // create block resource - resource make_block(nc_oid oid, nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, const web::json::value& members) + control_protocol_resource make_block(nc_oid oid, nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, const web::json::value& members) { using web::json::value; @@ -29,7 +29,7 @@ namespace nmos } // create Root block resource - resource make_root_block() + control_protocol_resource make_root_block() { using web::json::value; @@ -37,7 +37,7 @@ namespace nmos } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdevicemanager - resource make_device_manager(nc_oid oid, const nmos::settings& settings) + control_protocol_resource make_device_manager(nc_oid oid, const nmos::settings& settings) { using web::json::value; @@ -55,7 +55,7 @@ namespace nmos } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncclassmanager - resource make_class_manager(nc_oid oid, const nmos::experimental::control_protocol_state& control_protocol_state) + control_protocol_resource make_class_manager(nc_oid oid, const nmos::experimental::control_protocol_state& control_protocol_state) { using web::json::value; diff --git a/Development/nmos/control_protocol_resources.h b/Development/nmos/control_protocol_resources.h index c1718c0a0..99f3c588a 100644 --- a/Development/nmos/control_protocol_resources.h +++ b/Development/nmos/control_protocol_resources.h @@ -11,19 +11,19 @@ namespace nmos struct control_protocol_state; } - struct resource; + struct control_protocol_resource; // create block resource - resource make_block(nc_oid oid, nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null(), const web::json::value& members = web::json::value::array()); + control_protocol_resource make_block(nc_oid oid, nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null(), const web::json::value& members = web::json::value::array()); // create Root block resource - resource make_root_block(); + control_protocol_resource make_root_block(); // create Device manager resource - resource make_device_manager(nc_oid oid, const nmos::settings& settings); + control_protocol_resource make_device_manager(nc_oid oid, const nmos::settings& settings); // create Class manager resource - resource make_class_manager(nc_oid oid, const nmos::experimental::control_protocol_state& control_protocol_state); + control_protocol_resource make_class_manager(nc_oid oid, const nmos::experimental::control_protocol_state& control_protocol_state); } #endif diff --git a/Development/nmos/control_protocol_utils.cpp b/Development/nmos/control_protocol_utils.cpp index a6a43e07f..0ab690021 100644 --- a/Development/nmos/control_protocol_utils.cpp +++ b/Development/nmos/control_protocol_utils.cpp @@ -221,21 +221,20 @@ namespace nmos } } - // add block (NcBlock) to other block (NcBlock) - bool push_back(resource& parent_block, const resource& child_block) + // push control protocol resource into other control protocol NcBlock resource + void push_back(control_protocol_resource& nc_block_resource, const control_protocol_resource& resource) { using web::json::value; - auto& parent = parent_block.data; - const auto& child = child_block.data; + auto& parent = nc_block_resource.data; + const auto& child = resource.data; - if (is_nc_block(details::parse_nc_class_id(nmos::fields::nc::class_id(parent))) ) - { - web::json::push_back(parent[nmos::fields::nc::members], - details::make_nc_block_member_descriptor(nmos::fields::description(child), nmos::fields::nc::role(child), nmos::fields::nc::oid(child), nmos::fields::nc::constant_oid(child), details::parse_nc_class_id(nmos::fields::nc::class_id(child)), nmos::fields::nc::user_label(child), nmos::fields::nc::oid(parent))); - return true; - } - return false; + if (!is_nc_block(details::parse_nc_class_id(nmos::fields::nc::class_id(parent)))) throw std::logic_error("non-NcBlock cannot be nested"); + + web::json::push_back(parent[nmos::fields::nc::members], + details::make_nc_block_member_descriptor(nmos::fields::description(child), nmos::fields::nc::role(child), nmos::fields::nc::oid(child), nmos::fields::nc::constant_oid(child), details::parse_nc_class_id(nmos::fields::nc::class_id(child)), nmos::fields::nc::user_label(child), nmos::fields::nc::oid(parent))); + + nc_block_resource.resources.push_back(resource); } // modify a resource, and insert notification event to all subscriptions diff --git a/Development/nmos/control_protocol_utils.h b/Development/nmos/control_protocol_utils.h index da506c8fc..ef69f1673 100644 --- a/Development/nmos/control_protocol_utils.h +++ b/Development/nmos/control_protocol_utils.h @@ -6,6 +6,8 @@ namespace nmos { + struct control_protocol_resource; + // is the given class_id a NcBlock bool is_nc_block(const nc_class_id& class_id); @@ -37,8 +39,8 @@ namespace nmos // find members with given class id void find_members_by_class_id(const resources& resources, resources::iterator resource, const nc_class_id& class_id, bool include_derived, bool recurse, web::json::array& descriptors); - // add block (NcBlock) to other block (NcBlock) - bool push_back(resource& parent_block, const resource& child_block); + // push control protocol resource into other control protocol NcBlock resource + void push_back(control_protocol_resource& nc_block_resource, const control_protocol_resource& resource); // modify a resource, and insert notification event to all subscriptions bool modify_resource(resources& resources, const id& id, std::function modifier, const web::json::value& notification_event); From 094f5684b86d4424bbb1547c9ac0a0ed487d5d71 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Sat, 14 Oct 2023 00:02:18 +0100 Subject: [PATCH 058/106] Add IS-12 to Readme --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 050394924..b8a917cba 100644 --- a/README.md +++ b/README.md @@ -10,11 +10,14 @@ This repository contains an implementation of the [AMWA Networked Media Open Spe - [AMWA IS-07 NMOS Event & Tally Specification](https://specs.amwa.tv/is-07/) - [AMWA IS-08 NMOS Audio Channel Mapping Specification](https://specs.amwa.tv/is-08/) - [AMWA IS-09 NMOS System Parameters Specification](https://specs.amwa.tv/is-09/) (originally defined in JT-NM TR-1001-1:2018 Annex A) +- [AMWA IS-12 AMWA IS-12 NMOS Control Protocol](https://specs.amwa.tv/is-12/) - [AMWA BCP-002-01 NMOS Grouping Recommendations - Natural Grouping](https://specs.amwa.tv/bcp-002-01/) - [AMWA BCP-002-02 NMOS Asset Distinguishing Information](https://specs.amwa.tv/bcp-002-02/) - [AMWA BCP-003-01 Secure Communication in NMOS Systems](https://specs.amwa.tv/bcp-003-01/) - [AMWA BCP-004-01 NMOS Receiver Capabilities](https://specs.amwa.tv/bcp-004-01/) - [AMWA BCP-006-01 NMOS With JPEG XS](https://specs.amwa.tv/bcp-006-01/) +- [AMWA MS-05-01 NMOS Control Architecture](https://specs.amwa.tv/ms-05-01/) +- [AMWA MS-05-02 NMOS Control Framework](https://specs.amwa.tv/ms-05-02/) For more information about AMWA, NMOS and the Networked Media Incubator, please refer to . @@ -112,6 +115,7 @@ The implementation is designed to be extended. Development is ongoing, following Recent activity on the project (newest first): +- Added support for the IS-12 NMOS Control Protocol - Added support for HSTS and OCSP stapling - Added support for BCP-006-01 v1.0-dev, which can be demonstrated with **nmos-cpp-node** by using `"video_type": "video/jxsv"` - Updates to the GitHub Actions build-test workflow for better coverage of platforms and to include unicast DNS-SD tests From 3ff45a406fb32678cc6db6e97744c7f35727dc3a Mon Sep 17 00:00:00 2001 From: lo-simon Date: Wed, 18 Oct 2023 22:33:40 +0100 Subject: [PATCH 059/106] Add tounchpoint support and link Receiver-Monitor with IS-04/IS-05 Receiver --- .../nmos-cpp-node/node_implementation.cpp | 29 +++++++- .../nmos/control_protocol_handlers.cpp | 28 ++++++++ Development/nmos/control_protocol_handlers.h | 9 ++- Development/nmos/control_protocol_methods.cpp | 8 +-- ...tocol_nmos_channel_mapping_resource_type.h | 19 +++++ .../control_protocol_nmos_resource_type.h | 23 ++++++ .../nmos/control_protocol_resource.cpp | 70 +++++++++++++++++-- Development/nmos/control_protocol_resource.h | 9 +++ .../nmos/control_protocol_resources.cpp | 15 ++++ Development/nmos/control_protocol_resources.h | 8 +++ Development/nmos/control_protocol_typedefs.h | 66 ++++++++++++++++- Development/nmos/control_protocol_utils.cpp | 27 ++++++- Development/nmos/control_protocol_utils.h | 7 +- Development/nmos/control_protocol_ws_api.cpp | 4 +- 14 files changed, 299 insertions(+), 23 deletions(-) create mode 100644 Development/nmos/control_protocol_nmos_channel_mapping_resource_type.h create mode 100644 Development/nmos/control_protocol_nmos_resource_type.h diff --git a/Development/nmos-cpp-node/node_implementation.cpp b/Development/nmos-cpp-node/node_implementation.cpp index 9edcc0f2c..e89a9eaa0 100644 --- a/Development/nmos-cpp-node/node_implementation.cpp +++ b/Development/nmos-cpp-node/node_implementation.cpp @@ -40,7 +40,6 @@ #include "nmos/node_resources.h" #include "nmos/node_server.h" #include "nmos/random.h" -#include "nmos/resource.h" // for IS-12 gain control #include "nmos/sdp_utils.h" #include "nmos/slog.h" #include "nmos/st2110_21_sender_type.h" @@ -939,7 +938,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr control_protocol_state.insert(gain_control_class); } // helper function to create Gain control - auto make_gain_control = [&gain_value, &gain_control_class_id](nmos::nc_oid oid, nmos::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, float gain = 0.0, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null()) + auto make_gain_control = [&gain_value, &gain_control_class_id](nmos::nc_oid oid, nmos::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null(), float gain = 0.0) { auto data = nmos::details::make_nc_worker(gain_control_class_id, oid, true, owner, role, value::string(user_label), description, touchpoints, runtime_property_constraints, true); data[gain_value] = value::number(gain); @@ -1184,6 +1183,26 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr { make_example_datatype(example_enum::Alpha, U("example"), 50, false), make_example_datatype(example_enum::Gamma, U("different"), 75, true) } ); + // example receiver-monitor(s) + { + int count = 0; + for (int index = 0; index < how_many; ++index) + { + for (const auto& port : rtp_receiver_ports) + { + const auto receiver_id = impl::make_id(seed_id, nmos::types::receiver, port, index); + + utility::stringstream_t role; + role << U("monitor-") << ++count; + const auto& receiver = nmos::find_resource(model.node_resources, receiver_id); + const auto receiver_monitor = nmos::make_receiver_monitor(++oid, nmos::root_block_oid, role.str(), nmos::fields::label(receiver->data), nmos::fields::description(receiver->data), value_of({ { nmos::details::make_nc_touchpoint_nmos({nmos::ncp_nmos_resource_types::receiver, receiver_id}) } })); + + // add receiver-monitor to root-block + nmos::push_back(root_block, receiver_monitor); + } + } + } + // add example-control to root-block nmos::push_back(root_block, example_control); // add stereo-gain to root-block @@ -1545,13 +1564,17 @@ nmos::connection_activation_handler make_node_implementation_connection_activati auto handle_events_ws_message = make_node_implementation_events_ws_message_handler(model, gate); auto handle_close = nmos::experimental::make_events_ws_close_handler(model, gate); auto connection_events_activation_handler = nmos::make_connection_events_websocket_activation_handler(handle_load_ca_certificates, handle_events_ws_message, handle_close, model.settings, gate); + // this example uses this callback to update IS-12 Receiver-Monitor connection status + auto receiver_monitor_connection_activation_handler = nmos::make_receiver_monitor_connection_activation_handler(model.control_protocol_resources); - return [connection_events_activation_handler, &gate](const nmos::resource& resource, const nmos::resource& connection_resource) + return [connection_events_activation_handler, receiver_monitor_connection_activation_handler, &gate](const nmos::resource& resource, const nmos::resource& connection_resource) { const std::pair id_type{ resource.id, resource.type }; slog::log(gate, SLOG_FLF) << nmos::stash_category(impl::categories::node_implementation) << "Activating " << id_type; connection_events_activation_handler(resource, connection_resource); + + receiver_monitor_connection_activation_handler(connection_resource); }; } diff --git a/Development/nmos/control_protocol_handlers.cpp b/Development/nmos/control_protocol_handlers.cpp index e9d70f85c..1e38c6a20 100644 --- a/Development/nmos/control_protocol_handlers.cpp +++ b/Development/nmos/control_protocol_handlers.cpp @@ -2,6 +2,7 @@ #include "nmos/control_protocol_resource.h" #include "nmos/control_protocol_state.h" +#include "nmos/control_protocol_utils.h" #include "nmos/slog.h" namespace nmos @@ -54,4 +55,31 @@ namespace nmos return methods; }; } + + control_protocol_connection_activation_handler make_receiver_monitor_connection_activation_handler(resources& resources) + { + return [&resources](const resource& connection_resource) + { + auto found = find_control_protocol_resource(resources, connection_resource.id); + if (resources.end() != found && nc_receiver_monitor_class_id == details::parse_nc_class_id(nmos::fields::nc::class_id(found->data))) + { + // update receiver-monitor's connectionStatus propertry + + auto active = nmos::fields::master_enable(nmos::fields::endpoint_active(connection_resource.data)); + + nc_property_id property_id = nc_receiver_monitor_connection_status_property_id; + web::json::value val = active ? nc_connection_status::connected : nc_connection_status::disconnected; + const nc_property_changed_event_data property_changed_event_data{ property_id, nc_property_change_type::type::value_changed, val }; + const auto notification = make_control_protocol_notification(nmos::fields::nc::oid(found->data), nc_object_property_changed_event_id, property_changed_event_data); + const auto notification_event = make_control_protocol_notification(web::json::value_of({ notification })); + + modify_control_protocol_resource(resources, found->id, [&](nmos::resource& resource) + { + resource.data[nmos::fields::nc::connection_status] = property_changed_event_data.value; + // hmm, maybe updating connectionStatusMessage, payloadStatus, and payloadStatusMessage too + + }, notification_event); + } + }; + } } diff --git a/Development/nmos/control_protocol_handlers.h b/Development/nmos/control_protocol_handlers.h index 4f328ac3b..bab1904f4 100644 --- a/Development/nmos/control_protocol_handlers.h +++ b/Development/nmos/control_protocol_handlers.h @@ -30,7 +30,7 @@ namespace nmos // callback to retrieve a control protocol datatype // this callback should not throw exceptions - typedef std::function get_control_protocol_datatype_handler; + typedef std::function get_control_protocol_datatype_handler; namespace experimental { @@ -52,6 +52,13 @@ namespace nmos // construct callback to retrieve all method handlers get_control_protocol_methods_handler make_get_control_protocol_methods_handler(experimental::control_protocol_state& control_protocol_state); + + // a control_protocol_connection_activation_handler is a notification that the active parameters for the specified (IS-05) sender/connection_sender or receiver/connection_receiver have changed + // this callback should not throw exceptions + typedef std::function control_protocol_connection_activation_handler; + + // construct callback for receiver monitor to process connection (de)activation + control_protocol_connection_activation_handler make_receiver_monitor_connection_activation_handler(nmos::resources& resources); } #endif diff --git a/Development/nmos/control_protocol_methods.cpp b/Development/nmos/control_protocol_methods.cpp index 598d73016..7c9153083 100644 --- a/Development/nmos/control_protocol_methods.cpp +++ b/Development/nmos/control_protocol_methods.cpp @@ -64,7 +64,7 @@ namespace nmos const auto notification = make_control_protocol_notification(nmos::fields::nc::oid(resource->data), nc_object_property_changed_event_id, property_changed_event_data); const auto notification_event = make_control_protocol_notification(web::json::value_of({ notification })); - modify_resource(resources, resource->id, [&](nmos::resource& resource) + modify_control_protocol_resource(resources, resource->id, [&](nmos::resource& resource) { resource.data[nmos::fields::nc::name(property)] = property_changed_event_data.value; @@ -151,7 +151,7 @@ namespace nmos const auto notification = make_control_protocol_notification(nmos::fields::nc::oid(resource->data), nc_object_property_changed_event_id, property_changed_event_data); const auto notification_event = make_control_protocol_notification(web::json::value_of({ notification })); - modify_resource(resources, resource->id, [&](nmos::resource& resource) + modify_control_protocol_resource(resources, resource->id, [&](nmos::resource& resource) { resource.data[nmos::fields::nc::name(property)][index] = property_changed_event_data.value; @@ -203,7 +203,7 @@ namespace nmos const auto notification = make_control_protocol_notification(nmos::fields::nc::oid(resource->data), nc_object_property_changed_event_id, property_changed_event_data); const auto notification_event = make_control_protocol_notification(web::json::value_of({ notification })); - modify_resource(resources, resource->id, [&](nmos::resource& resource) + modify_control_protocol_resource(resources, resource->id, [&](nmos::resource& resource) { auto& sequence = resource.data[nmos::fields::nc::name(property)]; if (data.is_null()) { sequence = value::array(); } @@ -250,7 +250,7 @@ namespace nmos const auto notification = make_control_protocol_notification(nmos::fields::nc::oid(resource->data), nc_object_property_changed_event_id, property_changed_event_data); const auto notification_event = make_control_protocol_notification(web::json::value_of({ notification })); - modify_resource(resources, resource->id, [&](nmos::resource& resource) + modify_control_protocol_resource(resources, resource->id, [&](nmos::resource& resource) { auto& sequence = resource.data[nmos::fields::nc::name(property)].as_array(); sequence.erase(index); diff --git a/Development/nmos/control_protocol_nmos_channel_mapping_resource_type.h b/Development/nmos/control_protocol_nmos_channel_mapping_resource_type.h new file mode 100644 index 000000000..8e31c96cf --- /dev/null +++ b/Development/nmos/control_protocol_nmos_channel_mapping_resource_type.h @@ -0,0 +1,19 @@ +#ifndef NMOS_CONTROL_PROTOCOL_NMOS_CHANNEL_MAPPING_RESOURCE_TYPE_H +#define NMOS_CONTROL_PROTOCOL_NMOS_CHANNEL_MAPPING_RESOURCE_TYPE_H + +#include "cpprest/basic_utils.h" +#include "nmos/string_enum.h" + +namespace nmos +{ + // resourceType + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#nctouchpointresourcenmoschannelmapping + DEFINE_STRING_ENUM(ncp_nmos_channel_mapping_resource_type) + namespace ncp_nmos_channel_mapping_resource_types + { + const ncp_nmos_channel_mapping_resource_type input{ U("input") }; + const ncp_nmos_channel_mapping_resource_type output{ U("output") }; + } +} + +#endif diff --git a/Development/nmos/control_protocol_nmos_resource_type.h b/Development/nmos/control_protocol_nmos_resource_type.h new file mode 100644 index 000000000..436b72257 --- /dev/null +++ b/Development/nmos/control_protocol_nmos_resource_type.h @@ -0,0 +1,23 @@ +#ifndef NMOS_CONTROL_PROTOCOL_NMOS_RESOURCE_TYPE_H +#define NMOS_CONTROL_PROTOCOL_NMOS_RESOURCE_TYPE_H + +#include "cpprest/basic_utils.h" +#include "nmos/string_enum.h" + +namespace nmos +{ + // resourceType + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#nctouchpointresourcenmos + DEFINE_STRING_ENUM(ncp_nmos_resource_type) + namespace ncp_nmos_resource_types + { + const ncp_nmos_resource_type node{ U("node") }; + const ncp_nmos_resource_type device{ U("device") }; + const ncp_nmos_resource_type source{ U("source") }; + const ncp_nmos_resource_type flow{ U("flow") }; + const ncp_nmos_resource_type sender{ U("sender") }; + const ncp_nmos_resource_type receiver{ U("receiver") }; + } +} + +#endif diff --git a/Development/nmos/control_protocol_resource.cpp b/Development/nmos/control_protocol_resource.cpp index 590d36cc9..71a048923 100644 --- a/Development/nmos/control_protocol_resource.cpp +++ b/Development/nmos/control_protocol_resource.cpp @@ -605,8 +605,6 @@ namespace nmos // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsstring web::json::value make_nc_parameter_constraints_string(const web::json::value& default_value, const web::json::value& max_characters, const web::json::value& pattern) { - using web::json::value; - auto data = make_nc_parameter_constraints(default_value); data[nmos::fields::nc::max_characters] = max_characters; data[nmos::fields::nc::pattern] = pattern; @@ -638,6 +636,66 @@ namespace nmos return make_nc_parameter_constraints_string(value::null(), value::null(), value::string(pattern)); } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#nctouchpointresource + web::json::value make_nc_touchpoint_resource(const nc_touchpoint_resource& resource) + { + using web::json::value_of; + + return value_of({ + { nmos::fields::nc::resource_type, resource.resource_type } + }); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#nctouchpointresourcenmos + web::json::value make_nc_touchpoint_resource_nmos(const nc_touchpoint_resource_nmos& resource) + { + using web::json::value; + + auto data = make_nc_touchpoint_resource(resource); + data[nmos::fields::nc::id] = value::string(resource.id); + + return data; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#nctouchpointresourcenmoschannelmapping + web::json::value make_nc_touchpoint_resource_nmos_channel_mapping(const nc_touchpoint_resource_nmos_channel_mapping& resource) + { + using web::json::value; + + auto data = make_nc_touchpoint_resource_nmos(resource); + data[nmos::fields::nc::io_id] = value::string(resource.io_id); + + return data; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#nctouchpoint + web::json::value make_nc_touchpoint(const utility::string_t& context_namespace) + { + using web::json::value_of; + + return value_of({ + { nmos::fields::nc::context_namespace, context_namespace } + }); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#nctouchpointnmos + web::json::value make_nc_touchpoint_nmos(const nc_touchpoint_resource_nmos& resource) + { + auto data = make_nc_touchpoint(U("x-nmos")); + data[nmos::fields::nc::resource] = make_nc_touchpoint_resource_nmos(resource); + + return data; + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#nctouchpointnmoschannelmapping + web::json::value make_nc_touchpoint_nmos_channel_mapping(const nc_touchpoint_resource_nmos_channel_mapping& resource) + { + auto data = make_nc_touchpoint(U("x-nmos/channelmapping")); + data[nmos::fields::nc::resource] = make_nc_touchpoint_resource_nmos_channel_mapping(resource); + + return data; + } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncobject web::json::value make_nc_object(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints) { @@ -794,7 +852,7 @@ namespace nmos using web::json::value_of; return value_of({ - { nmos::fields::nc::message_type, nc_message_type::command_response }, + { nmos::fields::nc::message_type, ncp_message_type::command_response }, { nmos::fields::nc::responses, responses } }); } @@ -806,7 +864,7 @@ namespace nmos using web::json::value_of; return value_of({ - { nmos::fields::nc::message_type, nc_message_type::subscription_response }, + { nmos::fields::nc::message_type, ncp_message_type::subscription_response }, { nmos::fields::nc::subscriptions, subscriptions } }); } @@ -828,7 +886,7 @@ namespace nmos using web::json::value_of; return value_of({ - { nmos::fields::nc::message_type, nc_message_type::notification }, + { nmos::fields::nc::message_type, ncp_message_type::notification }, { nmos::fields::nc::notifications, notifications } }); } @@ -840,7 +898,7 @@ namespace nmos using web::json::value_of; return value_of({ - { nmos::fields::nc::message_type, nc_message_type::error }, + { nmos::fields::nc::message_type, ncp_message_type::error }, { nmos::fields::nc::status, method_result.status}, { nmos::fields::nc::error_message, error_message } }); diff --git a/Development/nmos/control_protocol_resource.h b/Development/nmos/control_protocol_resource.h index 7647bfd29..808cfe7fc 100644 --- a/Development/nmos/control_protocol_resource.h +++ b/Development/nmos/control_protocol_resource.h @@ -150,6 +150,15 @@ namespace nmos web::json::value make_nc_parameter_constraints_string(uint32_t max_characters); web::json::value make_nc_parameter_constraints_string(const nc_regex& pattern); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#nctouchpoint + web::json::value make_nc_touchpoint(const utility::string_t& context_namespace); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#nctouchpointnmos + web::json::value make_nc_touchpoint_nmos(const nc_touchpoint_resource_nmos& resource); + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#nctouchpointnmoschannelmapping + web::json::value make_nc_touchpoint_nmos_channel_mapping(const nc_touchpoint_resource_nmos_channel_mapping& resource); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncobject web::json::value make_nc_object(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints); diff --git a/Development/nmos/control_protocol_resources.cpp b/Development/nmos/control_protocol_resources.cpp index df0b6b9d9..40a7c1c97 100644 --- a/Development/nmos/control_protocol_resources.cpp +++ b/Development/nmos/control_protocol_resources.cpp @@ -63,4 +63,19 @@ namespace nmos return{ is12_versions::v1_0, types::nc_object, std::move(data), true }; } + + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitor + control_protocol_resource make_receiver_monitor(nc_oid oid, nmos::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, + nc_connection_status::status connection_status, const utility::string_t& connection_status_message, nc_payload_status::status payload_status, const utility::string_t& payload_status_message) + { + using web::json::value; + + auto data = nmos::details::make_nc_worker(nc_receiver_monitor_class_id, oid, true, owner, role, value::string(user_label), description, touchpoints, runtime_property_constraints, true); + data[nmos::fields::nc::connection_status] = value::number(connection_status); + data[nmos::fields::nc::connection_status_message] = value::string(connection_status_message); + data[nmos::fields::nc::payload_status] = value::number(payload_status); + data[nmos::fields::nc::payload_status_message] = value::string(payload_status_message); + + return{ is12_versions::v1_0, types::nc_object, std::move(data), true }; + } } diff --git a/Development/nmos/control_protocol_resources.h b/Development/nmos/control_protocol_resources.h index 99f3c588a..c17edcc8d 100644 --- a/Development/nmos/control_protocol_resources.h +++ b/Development/nmos/control_protocol_resources.h @@ -24,6 +24,14 @@ namespace nmos // create Class manager resource control_protocol_resource make_class_manager(nc_oid oid, const nmos::experimental::control_protocol_state& control_protocol_state); + + // create Receiver Monitor resource + control_protocol_resource make_receiver_monitor(nc_oid oid, nmos::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null(), + nc_connection_status::status connection_status = nc_connection_status::status::undefined, + const utility::string_t& connection_status_message = U(""), + nc_payload_status::status payload_status = nc_payload_status::status::undefined, + const utility::string_t& payload_status_message = U("") + ); } #endif diff --git a/Development/nmos/control_protocol_typedefs.h b/Development/nmos/control_protocol_typedefs.h index 6ba68ac25..dc491cd45 100644 --- a/Development/nmos/control_protocol_typedefs.h +++ b/Development/nmos/control_protocol_typedefs.h @@ -3,10 +3,13 @@ #include "cpprest/basic_utils.h" #include "cpprest/json_utils.h" +#include "nmos/control_protocol_nmos_channel_mapping_resource_type.h" +#include "nmos/control_protocol_nmos_resource_type.h" namespace nmos { - namespace nc_message_type + // See https://specs.amwa.tv/is-12/branches/v1.0.x/docs/Protocol_messaging.html + namespace ncp_message_type { enum type { @@ -20,6 +23,7 @@ namespace nmos } // Method invokation status + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncmethodstatus namespace nc_method_status { enum status @@ -42,7 +46,6 @@ namespace nmos property_not_implemented = 502, // Addressed property is not implemented by the addressed object not_ready = 503, // The device is not ready to handle any commands timeout = 504, // Method call did not finish within the allotted time - property_version_error = 505 // Incompatible protocol version }; } @@ -53,6 +56,7 @@ namespace nmos }; // Datatype type + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdatatypetype namespace nc_datatype_type { enum type @@ -65,6 +69,7 @@ namespace nmos } // Device generic operational state + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdevicegenericstate namespace nc_device_generic_state { enum state @@ -79,6 +84,7 @@ namespace nmos } // Reset cause enum + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncresetcause namespace nc_reset_cause { enum cause @@ -312,6 +318,62 @@ namespace nmos friend bool operator!=(const nc_property_changed_event_data& lhs, const nc_property_changed_event_data& rhs) { return !(lhs == rhs); } friend bool operator<(const nc_property_changed_event_data& lhs, const nc_property_changed_event_data& rhs) { return lhs.tied() < rhs.tied(); } }; + + // NcTouchpointResource + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#nctouchpointresource + struct nc_touchpoint_resource + { + utility::string_t resource_type; + + nc_touchpoint_resource(const utility::string_t& resource_type) + : resource_type(resource_type) + {} + + auto tied() const -> decltype(std::tie(resource_type)) { return std::tie(resource_type); } + friend bool operator==(const nc_touchpoint_resource& lhs, const nc_touchpoint_resource& rhs) { return lhs.tied() == rhs.tied(); } + friend bool operator!=(const nc_touchpoint_resource& lhs, const nc_touchpoint_resource& rhs) { return !(lhs == rhs); } + friend bool operator<(const nc_touchpoint_resource& lhs, const nc_touchpoint_resource& rhs) { return lhs.tied() < rhs.tied(); } + }; + + // NcTouchpointResourceNmos + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#nctouchpointresourcenmos + struct nc_touchpoint_resource_nmos : nc_touchpoint_resource + { + nc_uuid id; + + nc_touchpoint_resource_nmos(const utility::string_t& resource_type, nc_uuid id) + : nc_touchpoint_resource(resource_type) + , id(id) + {} + + nc_touchpoint_resource_nmos(const ncp_nmos_resource_type& resource_type, nc_uuid id) + : nc_touchpoint_resource(resource_type.name) + , id(id) + {} + + auto tied() const -> decltype(std::tie(resource_type, id)) { return std::tie(resource_type, id); } + friend bool operator==(const nc_touchpoint_resource_nmos& lhs, const nc_touchpoint_resource_nmos& rhs) { return lhs.tied() == rhs.tied(); } + friend bool operator!=(const nc_touchpoint_resource_nmos& lhs, const nc_touchpoint_resource_nmos& rhs) { return !(lhs == rhs); } + friend bool operator<(const nc_touchpoint_resource_nmos& lhs, const nc_touchpoint_resource_nmos& rhs) { return lhs.tied() < rhs.tied(); } + }; + + // NcTouchpointResourceNmosChannelMapping + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#nctouchpointresourcenmoschannelmapping + struct nc_touchpoint_resource_nmos_channel_mapping : nc_touchpoint_resource_nmos + { + //ncp_nmos_channel_mapping_resource_type resource_type; + nc_uuid io_id; + + nc_touchpoint_resource_nmos_channel_mapping(const ncp_nmos_channel_mapping_resource_type& resource_type, nc_uuid id, const utility::string_t& io_id) + : nc_touchpoint_resource_nmos(resource_type.name, id) + , io_id(io_id) + {} + + auto tied() const -> decltype(std::tie(resource_type, id, io_id)) { return std::tie(resource_type, id, io_id); } + friend bool operator==(const nc_touchpoint_resource_nmos_channel_mapping& lhs, const nc_touchpoint_resource_nmos_channel_mapping& rhs) { return lhs.tied() == rhs.tied(); } + friend bool operator!=(const nc_touchpoint_resource_nmos_channel_mapping& lhs, const nc_touchpoint_resource_nmos_channel_mapping& rhs) { return !(lhs == rhs); } + friend bool operator<(const nc_touchpoint_resource_nmos_channel_mapping& lhs, const nc_touchpoint_resource_nmos_channel_mapping& rhs) { return lhs.tied() < rhs.tied(); } + }; } #endif diff --git a/Development/nmos/control_protocol_utils.cpp b/Development/nmos/control_protocol_utils.cpp index 0ab690021..aefb541bb 100644 --- a/Development/nmos/control_protocol_utils.cpp +++ b/Development/nmos/control_protocol_utils.cpp @@ -221,7 +221,7 @@ namespace nmos } } - // push control protocol resource into other control protocol NcBlock resource + // push a control protocol resource into other control protocol NcBlock resource void push_back(control_protocol_resource& nc_block_resource, const control_protocol_resource& resource) { using web::json::value; @@ -237,8 +237,8 @@ namespace nmos nc_block_resource.resources.push_back(resource); } - // modify a resource, and insert notification event to all subscriptions - bool modify_resource(resources& resources, const id& id, std::function modifier, const web::json::value& notification_event) + // modify a control protocol resource, and insert notification event to all subscriptions + bool modify_control_protocol_resource(resources& resources, const id& id, std::function modifier, const web::json::value& notification_event) { auto found = resources.find(id); if (resources.end() == found || !found->has_data()) return false; @@ -281,4 +281,25 @@ namespace nmos return result; } + + // find the control protocol resource which is assoicated with the given IS-04/IS-05/IS-08 resource id + resources::const_iterator find_control_protocol_resource(resources& resources, const id& resource_id) + { + return find_resource_if(resources, nmos::types::nc_object, [resource_id](const nmos::resource& resource) + { + auto& touchpoints = resource.data.at(nmos::fields::nc::touchpoints); + if (!touchpoints.is_null() && touchpoints.is_array()) + { + auto& tps = touchpoints.as_array(); + auto found_tp = std::find_if(tps.begin(), tps.end(), [resource_id](const web::json::value& touchpoint) + { + auto& resource = nmos::fields::nc::resource(touchpoint); + return (resource_id == nmos::fields::nc::id(resource).as_string() + && nmos::ncp_nmos_resource_types::receiver.name == nmos::fields::nc::resource_type(resource)); + }); + return (tps.end() != found_tp); + } + return false; + }); + } } diff --git a/Development/nmos/control_protocol_utils.h b/Development/nmos/control_protocol_utils.h index ef69f1673..a62fb011c 100644 --- a/Development/nmos/control_protocol_utils.h +++ b/Development/nmos/control_protocol_utils.h @@ -42,8 +42,11 @@ namespace nmos // push control protocol resource into other control protocol NcBlock resource void push_back(control_protocol_resource& nc_block_resource, const control_protocol_resource& resource); - // modify a resource, and insert notification event to all subscriptions - bool modify_resource(resources& resources, const id& id, std::function modifier, const web::json::value& notification_event); + // modify a control protocol resource, and insert notification event to all subscriptions + bool modify_control_protocol_resource(resources& resources, const id& id, std::function modifier, const web::json::value& notification_event); + + // find the control protocol resource which is assoicated with the given IS-04/IS-05/IS-08 resource id + resources::const_iterator find_control_protocol_resource(resources& resources, const id& id); } #endif diff --git a/Development/nmos/control_protocol_ws_api.cpp b/Development/nmos/control_protocol_ws_api.cpp index c6f7d39a8..3df60f751 100644 --- a/Development/nmos/control_protocol_ws_api.cpp +++ b/Development/nmos/control_protocol_ws_api.cpp @@ -251,7 +251,7 @@ namespace nmos const auto msg_type = nmos::fields::nc::message_type(message); switch (msg_type) { - case nc_message_type::command: + case ncp_message_type::command: { // validate command-message details::validate_controlprotocolapi_command_message_schema(version, message); @@ -308,7 +308,7 @@ namespace nmos }); } break; - case nc_message_type::subscription: + case ncp_message_type::subscription: { // validate subscription-message details::validate_controlprotocolapi_subscription_message_schema(version, message); From f8f5270758add47e8b966dd8eb1bc4ed04faff44 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Wed, 18 Oct 2023 22:35:39 +0100 Subject: [PATCH 060/106] Add new headers to makefile --- Development/cmake/NmosCppLibraries.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Development/cmake/NmosCppLibraries.cmake b/Development/cmake/NmosCppLibraries.cmake index 1fe469e1a..dd92bc22a 100644 --- a/Development/cmake/NmosCppLibraries.cmake +++ b/Development/cmake/NmosCppLibraries.cmake @@ -913,6 +913,8 @@ set(NMOS_CPP_NMOS_HEADERS nmos/connection_resources.h nmos/control_protocol_handlers.h nmos/control_protocol_methods.h + nmos/control_protocol_nmos_channel_mapping_resource_type.h + nmos/control_protocol_nmos_resource_type.h nmos/control_protocol_resource.h nmos/control_protocol_resources.h nmos/control_protocol_state.h From 264cfba55bb13acbcfc3fe9a4bc4f27e3fdabe1e Mon Sep 17 00:00:00 2001 From: lo-simon Date: Thu, 19 Oct 2023 14:49:50 +0100 Subject: [PATCH 061/106] Set IS-12 nmos resource with relevant nmos::type --- .../nmos-cpp-node/node_implementation.cpp | 4 ++-- Development/nmos/api_utils.cpp | 16 ++++++++++++++-- Development/nmos/control_protocol_handlers.cpp | 2 +- Development/nmos/control_protocol_resources.cpp | 8 ++++---- Development/nmos/control_protocol_utils.cpp | 4 ++-- Development/nmos/control_protocol_utils.h | 2 +- Development/nmos/control_protocol_ws_api.cpp | 5 +++-- Development/nmos/query_utils.cpp | 1 + Development/nmos/type.h | 14 ++++++++++---- 9 files changed, 38 insertions(+), 18 deletions(-) diff --git a/Development/nmos-cpp-node/node_implementation.cpp b/Development/nmos-cpp-node/node_implementation.cpp index e89a9eaa0..b73eff13b 100644 --- a/Development/nmos-cpp-node/node_implementation.cpp +++ b/Development/nmos-cpp-node/node_implementation.cpp @@ -943,7 +943,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr auto data = nmos::details::make_nc_worker(gain_control_class_id, oid, true, owner, role, value::string(user_label), description, touchpoints, runtime_property_constraints, true); data[gain_value] = value::number(gain); - return nmos::control_protocol_resource{ nmos::is12_versions::v1_0, nmos::types::nc_object, std::move(data), true }; + return nmos::control_protocol_resource{ nmos::is12_versions::v1_0, nmos::types::nc_worker, std::move(data), true }; }; // example to create a non-standard Example control class @@ -1131,7 +1131,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr data[object_sequence] = sequence; } - return nmos::control_protocol_resource{ nmos::is12_versions::v1_0, nmos::types::nc_object, std::move(data), true }; + return nmos::control_protocol_resource{ nmos::is12_versions::v1_0, nmos::types::nc_worker, std::move(data), true }; }; diff --git a/Development/nmos/api_utils.cpp b/Development/nmos/api_utils.cpp index 69d38c5ae..3413ee509 100644 --- a/Development/nmos/api_utils.cpp +++ b/Development/nmos/api_utils.cpp @@ -157,7 +157,13 @@ namespace nmos { U("subscriptions"), nmos::types::subscription }, { U("inputs"), nmos::types::input }, { U("outputs"), nmos::types::output }, - { U("nc_object"), nmos::types::nc_object } + { U("nc_block"), nmos::types::nc_block }, + { U("nc_worker"), nmos::types::nc_worker }, + { U("nc_manager"), nmos::types::nc_manager }, + { U("nc_device_manager"), nmos::types::nc_device_manager }, + { U("nc_class_manager"), nmos::types::nc_class_manager }, + { U("nc_receiver_monitor"), nmos::types::nc_receiver_monitor }, + { U("nc_receiver_monitor_protected"), nmos::types::nc_receiver_monitor_protected } }; return types_from_resourceType.at(resourceType); } @@ -177,7 +183,13 @@ namespace nmos { nmos::types::grain, {} }, // subscription websocket grains aren't exposed via the Query API { nmos::types::input, U("inputs") }, { nmos::types::output, U("outputs") }, - { nmos::types::nc_object, U("nc_object") } + { nmos::types::nc_block, U("nc_block") }, + { nmos::types::nc_worker, U("nc_worker") }, + { nmos::types::nc_manager, U("nc_manager") }, + { nmos::types::nc_device_manager, U("nc_device_manager") }, + { nmos::types::nc_class_manager, U("nc_class_manager") }, + { nmos::types::nc_receiver_monitor, U("nc_receiver_monitor") }, + { nmos::types::nc_receiver_monitor_protected, U("nc_receiver_monitor_protected") } }; return resourceTypes_from_type.at(type); } diff --git a/Development/nmos/control_protocol_handlers.cpp b/Development/nmos/control_protocol_handlers.cpp index 1e38c6a20..8d7aa619c 100644 --- a/Development/nmos/control_protocol_handlers.cpp +++ b/Development/nmos/control_protocol_handlers.cpp @@ -60,7 +60,7 @@ namespace nmos { return [&resources](const resource& connection_resource) { - auto found = find_control_protocol_resource(resources, connection_resource.id); + auto found = find_control_protocol_resource(resources, nmos::types::nc_receiver_monitor, connection_resource.id); if (resources.end() != found && nc_receiver_monitor_class_id == details::parse_nc_class_id(nmos::fields::nc::class_id(found->data))) { // update receiver-monitor's connectionStatus propertry diff --git a/Development/nmos/control_protocol_resources.cpp b/Development/nmos/control_protocol_resources.cpp index 40a7c1c97..b1a267f7e 100644 --- a/Development/nmos/control_protocol_resources.cpp +++ b/Development/nmos/control_protocol_resources.cpp @@ -16,7 +16,7 @@ namespace nmos auto data = details::make_nc_block(nc_block_class_id, oid, true, owner, role, value::string(user_label), description, touchpoints, runtime_property_constraints, true, members); - return{ is12_versions::v1_0, types::nc_object, std::move(data), true }; + return{ is12_versions::v1_0, types::nc_block, std::move(data), true }; } } @@ -51,7 +51,7 @@ namespace nmos auto data = details::make_nc_device_manager(oid, root_block_oid, value::string(U("Device manager")), U("The device manager offers information about the product this device is representing"), value::null(), value::null(), manufacturer, product, serial_number, value::null(), device_name, device_role, operational_state, nc_reset_cause::unknown); - return{ is12_versions::v1_0, types::nc_object, std::move(data), true }; + return{ is12_versions::v1_0, types::nc_device_manager, std::move(data), true }; } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncclassmanager @@ -61,7 +61,7 @@ namespace nmos auto data = details::make_nc_class_manager(oid, root_block_oid, value::string(U("Class manager")), U("The class manager offers access to control class and data type descriptors"), value::null(), value::null(), control_protocol_state); - return{ is12_versions::v1_0, types::nc_object, std::move(data), true }; + return{ is12_versions::v1_0, types::nc_class_manager, std::move(data), true }; } // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitor @@ -76,6 +76,6 @@ namespace nmos data[nmos::fields::nc::payload_status] = value::number(payload_status); data[nmos::fields::nc::payload_status_message] = value::string(payload_status_message); - return{ is12_versions::v1_0, types::nc_object, std::move(data), true }; + return{ is12_versions::v1_0, types::nc_receiver_monitor, std::move(data), true }; } } diff --git a/Development/nmos/control_protocol_utils.cpp b/Development/nmos/control_protocol_utils.cpp index aefb541bb..38e215f7c 100644 --- a/Development/nmos/control_protocol_utils.cpp +++ b/Development/nmos/control_protocol_utils.cpp @@ -283,9 +283,9 @@ namespace nmos } // find the control protocol resource which is assoicated with the given IS-04/IS-05/IS-08 resource id - resources::const_iterator find_control_protocol_resource(resources& resources, const id& resource_id) + resources::const_iterator find_control_protocol_resource(resources& resources, type type, const id& resource_id) { - return find_resource_if(resources, nmos::types::nc_object, [resource_id](const nmos::resource& resource) + return find_resource_if(resources, type, [resource_id](const nmos::resource& resource) { auto& touchpoints = resource.data.at(nmos::fields::nc::touchpoints); if (!touchpoints.is_null() && touchpoints.is_array()) diff --git a/Development/nmos/control_protocol_utils.h b/Development/nmos/control_protocol_utils.h index a62fb011c..72580351f 100644 --- a/Development/nmos/control_protocol_utils.h +++ b/Development/nmos/control_protocol_utils.h @@ -46,7 +46,7 @@ namespace nmos bool modify_control_protocol_resource(resources& resources, const id& id, std::function modifier, const web::json::value& notification_event); // find the control protocol resource which is assoicated with the given IS-04/IS-05/IS-08 resource id - resources::const_iterator find_control_protocol_resource(resources& resources, const id& id); + resources::const_iterator find_control_protocol_resource(resources& resources, type type, const id& id); } #endif diff --git a/Development/nmos/control_protocol_ws_api.cpp b/Development/nmos/control_protocol_ws_api.cpp index 3df60f751..26948a8c9 100644 --- a/Development/nmos/control_protocol_ws_api.cpp +++ b/Development/nmos/control_protocol_ws_api.cpp @@ -118,11 +118,13 @@ namespace nmos .set_path(ws_ncp_path) .to_uri(); + const utility::string_t control_protocol_resource_path; + const bool non_persistent = false; value data = value_of({ { nmos::fields::id, nmos::make_id() }, { nmos::fields::max_update_rate_ms, 0 }, - { nmos::fields::resource_path, U('/') + nmos::resourceType_from_type(nmos::types::nc_object) }, + { nmos::fields::resource_path, control_protocol_resource_path }, { nmos::fields::params, value_of({ { U("query.rql"), U("in(id,())") } }) }, { nmos::fields::persist, non_persistent }, { nmos::fields::secure, secure }, @@ -147,7 +149,6 @@ namespace nmos const auto resource_path = nmos::fields::resource_path(subscription->data); const auto topic = resource_path + U('/'); - // source_id and flow_id are set per-message depending on the source, unlike Query WebSocket API data[nmos::fields::message] = details::make_grain({}, {}, topic); resource grain{ is12_versions::v1_0, nmos::types::grain, std::move(data), false }; diff --git a/Development/nmos/query_utils.cpp b/Development/nmos/query_utils.cpp index 672e610e6..62977ff09 100644 --- a/Development/nmos/query_utils.cpp +++ b/Development/nmos/query_utils.cpp @@ -579,6 +579,7 @@ namespace nmos } // insert 'value changed', 'sequence item added', 'sequence item changed' or 'sequence item removed' notification events into all grains whose subscriptions match the specified version, type and "pre" or "post" values + // this is used for the IS-12 propertry changed event void insert_notification_events(nmos::resources& resources, const nmos::api_version& version, const nmos::api_version& downgrade_version, const nmos::type& type, const web::json::value& pre, const web::json::value& post, const web::json::value& event) { using web::json::value; diff --git a/Development/nmos/type.h b/Development/nmos/type.h index 4e6831aa1..3c2853ebe 100644 --- a/Development/nmos/type.h +++ b/Development/nmos/type.h @@ -28,13 +28,10 @@ namespace nmos // to a subscription is managed as a sub-resource of the subscription const type grain{ U("grain") }; - // the Control Protocol API resource type, see nmos/control_protcol_resources.h - const type nc_object{ U("nc_object") }; - // all types ordered so that sub-resource types appear after super-resource types // according to the guidelines on referential integrity // see https://specs.amwa.tv/is-04/releases/v1.2.1/docs/4.1._Behaviour_-_Registration.html#referential-integrity - const std::vector all{ nmos::types::node, nmos::types::device, nmos::types::source, nmos::types::flow, nmos::types::sender, nmos::types::receiver, nmos::types::subscription, nmos::types::grain, nmos::types::nc_object }; + const std::vector all{ nmos::types::node, nmos::types::device, nmos::types::source, nmos::types::flow, nmos::types::sender, nmos::types::receiver, nmos::types::subscription, nmos::types::grain }; // the Channel Mapping API resource types, see nmos/channelmapping_resources.h const type input{ U("input") }; @@ -42,6 +39,15 @@ namespace nmos // the System API global configuration resource type, see nmos/system_resources.h const type global{ U("global") }; + + // the Control Protocol API resource type, see nmos/control_protcol_resources.h + const type nc_block{ U("nc_block") }; + const type nc_worker{ U("nc_worker") }; + const type nc_manager{ U("nc_manager") }; + const type nc_device_manager{ U("nc_device_manager") }; + const type nc_class_manager{ U("nc_class_manager") }; + const type nc_receiver_monitor{ U("nc_receiver_monitor") }; + const type nc_receiver_monitor_protected{ U("nc_receiver_monitor_protected") }; } } From ce6286507e5fadc65dfe854d31f11c631e43ce57 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Thu, 19 Oct 2023 20:07:36 +0100 Subject: [PATCH 062/106] Clean up on how to construct propertry changed event --- .../nmos/control_protocol_handlers.cpp | 19 ++++++------ Development/nmos/control_protocol_methods.cpp | 29 +++++-------------- .../nmos/control_protocol_resource.cpp | 18 +++++++++++- Development/nmos/control_protocol_resource.h | 8 ++++- Development/nmos/control_protocol_typedefs.h | 7 +++++ 5 files changed, 48 insertions(+), 33 deletions(-) diff --git a/Development/nmos/control_protocol_handlers.cpp b/Development/nmos/control_protocol_handlers.cpp index 8d7aa619c..f51b85cf6 100644 --- a/Development/nmos/control_protocol_handlers.cpp +++ b/Development/nmos/control_protocol_handlers.cpp @@ -65,20 +65,21 @@ namespace nmos { // update receiver-monitor's connectionStatus propertry - auto active = nmos::fields::master_enable(nmos::fields::endpoint_active(connection_resource.data)); + const auto active = nmos::fields::master_enable(nmos::fields::endpoint_active(connection_resource.data)); + const web::json::value val = active ? nc_connection_status::connected : nc_connection_status::disconnected; - nc_property_id property_id = nc_receiver_monitor_connection_status_property_id; - web::json::value val = active ? nc_connection_status::connected : nc_connection_status::disconnected; - const nc_property_changed_event_data property_changed_event_data{ property_id, nc_property_change_type::type::value_changed, val }; - const auto notification = make_control_protocol_notification(nmos::fields::nc::oid(found->data), nc_object_property_changed_event_id, property_changed_event_data); - const auto notification_event = make_control_protocol_notification(web::json::value_of({ notification })); + // hmm, maybe updating connectionStatusMessage, payloadStatus, and payloadStatusMessage too + + const auto propertry_changed_event = make_propertry_changed_event(nmos::fields::nc::oid(found->data), + { + { nc_receiver_monitor_connection_status_property_id, nc_property_change_type::type::value_changed, val } + }); modify_control_protocol_resource(resources, found->id, [&](nmos::resource& resource) { - resource.data[nmos::fields::nc::connection_status] = property_changed_event_data.value; - // hmm, maybe updating connectionStatusMessage, payloadStatus, and payloadStatusMessage too + resource.data[nmos::fields::nc::connection_status] = val; - }, notification_event); + }, propertry_changed_event); } }; } diff --git a/Development/nmos/control_protocol_methods.cpp b/Development/nmos/control_protocol_methods.cpp index 7c9153083..b6aad64dc 100644 --- a/Development/nmos/control_protocol_methods.cpp +++ b/Development/nmos/control_protocol_methods.cpp @@ -60,15 +60,11 @@ namespace nmos return make_control_protocol_message_response(handle, { nc_method_status::parameter_error }); } - const nc_property_changed_event_data property_changed_event_data{ parse_nc_property_id(property_id), nc_property_change_type::type::value_changed, val }; - const auto notification = make_control_protocol_notification(nmos::fields::nc::oid(resource->data), nc_object_property_changed_event_id, property_changed_event_data); - const auto notification_event = make_control_protocol_notification(web::json::value_of({ notification })); - modify_control_protocol_resource(resources, resource->id, [&](nmos::resource& resource) { - resource.data[nmos::fields::nc::name(property)] = property_changed_event_data.value; + resource.data[nmos::fields::nc::name(property)] = val; - }, notification_event); + }, make_propertry_changed_event(nmos::fields::nc::oid(resource->data), { { parse_nc_property_id(property_id), nc_property_change_type::type::value_changed, val } })); return make_control_protocol_message_response(handle, { nc_method_status::ok }); } @@ -147,15 +143,11 @@ namespace nmos if (data.as_array().size() > (size_t)index) { - const nc_property_changed_event_data property_changed_event_data{ parse_nc_property_id(property_id), nc_property_change_type::type::sequence_item_changed, val, nc_id(index) }; - const auto notification = make_control_protocol_notification(nmos::fields::nc::oid(resource->data), nc_object_property_changed_event_id, property_changed_event_data); - const auto notification_event = make_control_protocol_notification(web::json::value_of({ notification })); - modify_control_protocol_resource(resources, resource->id, [&](nmos::resource& resource) { - resource.data[nmos::fields::nc::name(property)][index] = property_changed_event_data.value; + resource.data[nmos::fields::nc::name(property)][index] = val; - }, notification_event); + }, make_propertry_changed_event(nmos::fields::nc::oid(resource->data), { { parse_nc_property_id(property_id), nc_property_change_type::type::sequence_item_changed, val, nc_id(index) } })); return make_control_protocol_message_response(handle, { nc_method_status::ok }); } @@ -199,17 +191,14 @@ namespace nmos auto& data = resource->data.at(nmos::fields::nc::name(property)); const nc_id sequence_item_index = data.is_null() ? 0 : nc_id(data.as_array().size()); - const nc_property_changed_event_data property_changed_event_data{ parse_nc_property_id(property_id), nc_property_change_type::type::sequence_item_added, val, sequence_item_index }; - const auto notification = make_control_protocol_notification(nmos::fields::nc::oid(resource->data), nc_object_property_changed_event_id, property_changed_event_data); - const auto notification_event = make_control_protocol_notification(web::json::value_of({ notification })); modify_control_protocol_resource(resources, resource->id, [&](nmos::resource& resource) { auto& sequence = resource.data[nmos::fields::nc::name(property)]; if (data.is_null()) { sequence = value::array(); } - web::json::push_back(sequence, property_changed_event_data.value); + web::json::push_back(sequence, val); - }, notification_event); + }, make_propertry_changed_event(nmos::fields::nc::oid(resource->data), { { parse_nc_property_id(property_id), nc_property_change_type::type::sequence_item_added, val, sequence_item_index } })); return make_control_protocol_message_response(handle, { nc_method_status::ok }, sequence_item_index); } @@ -246,16 +235,12 @@ namespace nmos if (data.as_array().size() > (size_t)index) { - const nc_property_changed_event_data property_changed_event_data{ parse_nc_property_id(property_id), nc_property_change_type::type::sequence_item_removed, data.as_array().at(index), nc_id(index) }; - const auto notification = make_control_protocol_notification(nmos::fields::nc::oid(resource->data), nc_object_property_changed_event_id, property_changed_event_data); - const auto notification_event = make_control_protocol_notification(web::json::value_of({ notification })); - modify_control_protocol_resource(resources, resource->id, [&](nmos::resource& resource) { auto& sequence = resource.data[nmos::fields::nc::name(property)].as_array(); sequence.erase(index); - }, notification_event); + }, make_propertry_changed_event(nmos::fields::nc::oid(resource->data), { { parse_nc_property_id(property_id), nc_property_change_type::type::sequence_item_removed, nc_id(index) } })); return make_control_protocol_message_response(handle, { nc_method_status::ok }); } diff --git a/Development/nmos/control_protocol_resource.cpp b/Development/nmos/control_protocol_resource.cpp index 71a048923..b374de30d 100644 --- a/Development/nmos/control_protocol_resource.cpp +++ b/Development/nmos/control_protocol_resource.cpp @@ -870,6 +870,7 @@ namespace nmos } // notification + // See https://specs.amwa.tv/ms-05-01/branches/v1.0.x/docs/Core_Mechanisms.html#notification-messages // See https://specs.amwa.tv/is-12/branches/v1.0.x/docs/Protocol_messaging.html#notification-message-type web::json::value make_control_protocol_notification(nc_oid oid, const nc_event_id& event_id, const nc_property_changed_event_data& property_changed_event_data) { @@ -881,7 +882,7 @@ namespace nmos { nmos::fields::nc::event_data, details::make_nc_property_changed_event_data(property_changed_event_data) } }); } - web::json::value make_control_protocol_notification(const web::json::value& notifications) + web::json::value make_control_protocol_notification_message(const web::json::value& notifications) { using web::json::value_of; @@ -891,6 +892,21 @@ namespace nmos }); } + // property changed notification event + // See https://specs.amwa.tv/ms-05-01/branches/v1.0.x/docs/Core_Mechanisms.html#the-propertychanged-event + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/NcObject.html#propertychanged-event + web::json::value make_propertry_changed_event(nc_oid oid, const std::vector& property_changed_event_data_list) + { + using web::json::value; + + auto notifications = value::array(); + for (auto& property_changed_event_data : property_changed_event_data_list) + { + web::json::push_back(notifications, make_control_protocol_notification(oid, nc_object_property_changed_event_id, property_changed_event_data)); + } + return make_control_protocol_notification_message(notifications); + } + // error message // See https://specs.amwa.tv/is-12/branches/v1.0.x/docs/Protocol_messaging.html#error-messages web::json::value make_control_protocol_error_message(const nc_method_result& method_result, const utility::string_t& error_message) diff --git a/Development/nmos/control_protocol_resource.h b/Development/nmos/control_protocol_resource.h index 808cfe7fc..fc4910dd5 100644 --- a/Development/nmos/control_protocol_resource.h +++ b/Development/nmos/control_protocol_resource.h @@ -193,9 +193,15 @@ namespace nmos web::json::value make_control_protocol_subscription_response(const web::json::value& subscriptions); // notification + // See https://specs.amwa.tv/ms-05-01/branches/v1.0.x/docs/Core_Mechanisms.html#notification-messages // See https://specs.amwa.tv/is-12/branches/v1.0.x/docs/Protocol_messaging.html#notification-message-type web::json::value make_control_protocol_notification(nc_oid oid, const nc_event_id& event_id, const nc_property_changed_event_data& property_changed_event_data); - web::json::value make_control_protocol_notification(const web::json::value& notifications); + web::json::value make_control_protocol_notification_message(const web::json::value& notifications); + + // property changed notification event + // See https://specs.amwa.tv/ms-05-01/branches/v1.0.x/docs/Core_Mechanisms.html#the-propertychanged-event + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/NcObject.html#propertychanged-event + web::json::value make_propertry_changed_event(nc_oid oid, const std::vector& property_changed_event_data_list); // error message // See https://specs.amwa.tv/is-12/branches/v1.0.x/docs/Protocol_messaging.html#error-messages diff --git a/Development/nmos/control_protocol_typedefs.h b/Development/nmos/control_protocol_typedefs.h index dc491cd45..f31ca98df 100644 --- a/Development/nmos/control_protocol_typedefs.h +++ b/Development/nmos/control_protocol_typedefs.h @@ -313,6 +313,13 @@ namespace nmos , sequence_item_index(web::json::value::null()) {} + nc_property_changed_event_data(nc_property_id property_id, nc_property_change_type::type change_type, nc_id sequence_item_index) + : property_id(std::move(property_id)) + , change_type(change_type) + , value(web::json::value::null()) + , sequence_item_index(sequence_item_index) + {} + auto tied() const -> decltype(std::tie(property_id, change_type, value, sequence_item_index)) { return std::tie(property_id, change_type, value, sequence_item_index); } friend bool operator==(const nc_property_changed_event_data& lhs, const nc_property_changed_event_data& rhs) { return lhs.tied() == rhs.tied(); } friend bool operator!=(const nc_property_changed_event_data& lhs, const nc_property_changed_event_data& rhs) { return !(lhs == rhs); } From 28187d80e351732fea11bdebe396208c6e43226b Mon Sep 17 00:00:00 2001 From: lo-simon Date: Thu, 26 Oct 2023 17:32:42 +0100 Subject: [PATCH 063/106] Add constraints support, see https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html --- .../nmos-cpp-node/node_implementation.cpp | 68 +++++++--- Development/nmos/control_protocol_methods.cpp | 45 +++++-- .../nmos/control_protocol_resource.cpp | 30 ++--- Development/nmos/control_protocol_resource.h | 8 +- Development/nmos/control_protocol_utils.cpp | 127 ++++++++++++++++-- Development/nmos/control_protocol_utils.h | 18 +++ Development/nmos/json_fields.h | 6 +- .../nmos/test/control_protocol_test.cpp | 66 +++++++++ 8 files changed, 313 insertions(+), 55 deletions(-) diff --git a/Development/nmos-cpp-node/node_implementation.cpp b/Development/nmos-cpp-node/node_implementation.cpp index b73eff13b..e1c60fc3b 100644 --- a/Development/nmos-cpp-node/node_implementation.cpp +++ b/Development/nmos-cpp-node/node_implementation.cpp @@ -965,7 +965,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr const web::json::field_as_string string_arg{ U("stringArg") }; const web::json::field_as_number number_arg{ U("numberArg") }; const web::json::field_as_bool boolean_arg{ U("booleanArg") }; - const web::json::field_as_bool obj_arg{ U("objArg") }; + const web::json::field_as_value obj_arg{ U("objArg") }; enum example_enum { Undefined = 0, @@ -978,8 +978,10 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr // Example control class properties std::vector example_control_properties = { nmos::experimental::make_control_class_property(U("Example enum property"), { 3, 1 }, enum_property, U("ExampleEnum")), + // create "Example string property" with level 1: property constraints, See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html nmos::experimental::make_control_class_property(U("Example string property"), { 3, 2 }, string_property, U("NcString"), false, false, false, false, nmos::details::make_nc_parameter_constraints_string(10)), - nmos::experimental::make_control_class_property(U("Example numeric property"), { 3, 3 }, number_property, U("NcUint64"), false, false, false, false, nmos::details::make_nc_parameter_constraints_number(1000, 0, 1)), + // create "Example numeric property" with level 1: property constraints, See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html + nmos::experimental::make_control_class_property(U("Example numeric property"), { 3, 3 }, number_property, U("NcUint64"), false, false, false, false, nmos::details::make_nc_parameter_constraints_number(0, 1000, 1)), nmos::experimental::make_control_class_property(U("Example boolean property"), { 3, 4 }, boolean_property, U("NcBoolean")), nmos::experimental::make_control_class_property(U("Example object property"), { 3, 5 }, object_property, U("ExampleDataType")), nmos::experimental::make_control_class_property(U("Method no args invoke counter"), { 3, 6 }, method_no_args_count, U("NcUint64"), true), @@ -993,19 +995,43 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr }; // Example control class method handlers + auto make_string_example_argument_constraints = []() {return nmos::details::make_nc_parameter_constraints_string(80); }; + auto make_number_example_argument_constraints = []() {return nmos::details::make_nc_parameter_constraints_number(100, 1000, 1); }; + auto example_method_with_no_args = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) { slog::log(gate, SLOG_FLF) << "Executing the example method with no arguments"; + return nmos::make_control_protocol_message_response(handle, { nmos::nc_method_status::ok }); }; - auto example_method_with_simple_args = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) + auto example_method_with_simple_args = [&](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) { - slog::log(gate, SLOG_FLF) << "Executing the example method with simple arguments"; + slog::log(gate, SLOG_FLF) << "Executing the example method with simple arguments:" + << " enum_arg: " + << enum_arg(arguments).to_int32() + << " string_arg: " + << string_arg(arguments) + << " number_arg: " + << number_arg(arguments).to_uint64() + << " boolean_arg: " + << boolean_arg(arguments); + + // example to do method arguments constraints validation + const auto string_example_argument_constraints = make_string_example_argument_constraints(); + if (!nmos::constraints_validation(arguments.at(string_arg), make_string_example_argument_constraints()) + || !nmos::constraints_validation(arguments.at(number_arg), make_number_example_argument_constraints())) + { + return nmos::make_control_protocol_message_response(handle, { nmos::nc_method_status::parameter_error }); + } + return nmos::make_control_protocol_message_response(handle, { nmos::nc_method_status::ok }); }; - auto example_method_with_object_args = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) + auto example_method_with_object_args = [&](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) { - slog::log(gate, SLOG_FLF) << "Executing the example method with object arguments"; + slog::log(gate, SLOG_FLF) << "Executing the example method with object argument:" + << " obj_arg: " + << obj_arg(arguments).serialize(); + return nmos::make_control_protocol_message_response(handle, { nmos::nc_method_status::ok }); }; // Example control class methods @@ -1015,8 +1041,8 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr { nmos::experimental::make_control_class_method(U("Example method with simple arguments"), { 3, 2 }, U("MethodSimpleArgs"), U("NcMethodResult"), { nmos::details::make_nc_parameter_descriptor(U("Enum example argument"), enum_arg, U("ExampleEnum"), false, false, value::null()), - nmos::details::make_nc_parameter_descriptor(U("String example argument"), string_arg, U("NcString"), false, false, value::null()), // todo constraints - nmos::details::make_nc_parameter_descriptor(U("Number example argument"), number_arg, U("NcUint64"), false, false, value::null()), // todo constraints + nmos::details::make_nc_parameter_descriptor(U("String example argument"), string_arg, U("NcString"), false, false, make_string_example_argument_constraints()), // e.g. include method property constraints + nmos::details::make_nc_parameter_descriptor(U("Number example argument"), number_arg, U("NcUint64"), false, false, make_number_example_argument_constraints()), // e.g. include method property constraints nmos::details::make_nc_parameter_descriptor(U("Boolean example argument"), boolean_arg, U("NcBoolean"), false, false, value::null()) }, false), example_method_with_simple_args @@ -1054,12 +1080,16 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr auto fields = value::array(); web::json::push_back(fields, nmos::details::make_nc_field_descriptor(U("Enum property example"), enum_property, U("ExampleEnum"), false, false, value::null())); { - value constraints = value::null(); // todo constraints - web::json::push_back(fields, nmos::details::make_nc_field_descriptor(U("String property example"), string_property, U("NcString"), false, false, constraints)); + // level 0: datatype constraints, See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html + // use nmos::details::make_nc_parameter_constraints_string to create datatype constraints + value datatype_constraints = value::null(); + web::json::push_back(fields, nmos::details::make_nc_field_descriptor(U("String property example"), string_property, U("NcString"), false, false, datatype_constraints)); } { - value constraints = value::null(); // todo constraints - web::json::push_back(fields, nmos::details::make_nc_field_descriptor(U("Number property example"), number_property, U("NcUint64"), false, false, constraints)); + // level 0: datatype constraints, See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html + // use nmos::details::make_nc_parameter_constraints_number to create datatype constraints + value datatype_constraints = value::null(); + web::json::push_back(fields, nmos::details::make_nc_field_descriptor(U("Number property example"), number_property, U("NcUint64"), false, false, datatype_constraints)); } web::json::push_back(fields, nmos::details::make_nc_field_descriptor(U("Boolean property example"), boolean_property, U("NcBoolean"), false, false, value::null())); return nmos::details::make_nc_datatype_descriptor_struct(U("Example data type"), U("ExampleDataType"), fields, value::null()); @@ -1080,7 +1110,9 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr }); }; // helper function to create Example control - auto make_example_control = [&](nmos::nc_oid oid, nmos::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, + auto make_example_control = [&](nmos::nc_oid oid, nmos::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const value& touchpoints = value::null(), + const value& runtime_property_constraints = value::null(), // level 2: runtime constraints. See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html + // use of make_nc_property_constraints_stringand make_nc_property_constraints_number to create runtime constraints example_enum enum_property_ = example_enum::Undefined, const utility::string_t& string_property_ = U(""), uint64_t number_property_ = 0, @@ -1093,8 +1125,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr std::vector boolean_sequence_ = {}, std::vector enum_sequence_ = {}, std::vector number_sequence_ = {}, - std::vector object_sequence_ = {}, - const value& touchpoints = value::null(), const value& runtime_property_constraints = value::null()) + std::vector object_sequence_ = {}) { auto data = nmos::details::make_nc_worker(example_control_class_id, oid, true, owner, role, value::string(user_label), description, touchpoints, runtime_property_constraints, true); data[enum_property] = value::number(enum_property_); @@ -1168,6 +1199,13 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr // example example-control auto example_control = make_example_control(++oid, nmos::root_block_oid, U("ExampleControl"), U("Example control worker"), U("Example control worker"), + value::null(), + value::null(), // specify the level 2: runtime constraints, see https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html + // use of make_nc_property_constraints_string and make_nc_property_constraints_number to create runtime constraints + // e.g. value_of({ + // { nmos::details::make_nc_property_constraints_string({3, 2}, 10) }, + // { nmos::details::make_nc_property_constraints_number({3, 3}, 10, 100, 2) } + // }), example_enum::Undefined, U("test"), 3, diff --git a/Development/nmos/control_protocol_methods.cpp b/Development/nmos/control_protocol_methods.cpp index b6aad64dc..de2dcba4b 100644 --- a/Development/nmos/control_protocol_methods.cpp +++ b/Development/nmos/control_protocol_methods.cpp @@ -36,7 +36,7 @@ namespace nmos } // Set property value - web::json::value set(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate) + web::json::value set(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -46,7 +46,8 @@ namespace nmos slog::log(gate, SLOG_FLF) << "Set property: " << property_id.serialize() << " value: " << val.serialize(); // find the relevant nc_property_descriptor - const auto& property = find_property(parse_nc_property_id(property_id), parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), get_control_protocol_class); + const auto property_id_ = parse_nc_property_id(property_id); + const auto& property = find_property(property_id_, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), get_control_protocol_class); if (!property.is_null()) { if (nmos::fields::nc::is_read_only(property)) @@ -60,11 +61,21 @@ namespace nmos return make_control_protocol_message_response(handle, { nc_method_status::parameter_error }); } + // do constraints validation + if (!val.is_null()) + { + if (!constraints_validation(val, get_runtime_property_constraints(property_id_, resource->data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), get_datatype_constraints(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype))) + { + return make_control_protocol_message_response(handle, { nc_method_status::parameter_error }); + } + } + + // update property modify_control_protocol_resource(resources, resource->id, [&](nmos::resource& resource) { resource.data[nmos::fields::nc::name(property)] = val; - }, make_propertry_changed_event(nmos::fields::nc::oid(resource->data), { { parse_nc_property_id(property_id), nc_property_change_type::type::value_changed, val } })); + }, make_propertry_changed_event(nmos::fields::nc::oid(resource->data), { { property_id_, nc_property_change_type::type::value_changed, val } })); return make_control_protocol_message_response(handle, { nc_method_status::ok }); } @@ -117,7 +128,7 @@ namespace nmos } // Set sequence item - web::json::value set_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate) + web::json::value set_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -128,7 +139,8 @@ namespace nmos slog::log(gate, SLOG_FLF) << "Set sequence item: " << property_id.serialize() << " index: " << index << " value: " << val.serialize(); // find the relevant nc_property_descriptor - const auto& property = find_property(parse_nc_property_id(property_id), parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), get_control_protocol_class); + const auto property_id_ = parse_nc_property_id(property_id); + const auto& property = find_property(property_id_, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), get_control_protocol_class); if (!property.is_null()) { auto& data = resource->data.at(nmos::fields::nc::name(property)); @@ -143,11 +155,18 @@ namespace nmos if (data.as_array().size() > (size_t)index) { + // do constraints validation + if (!constraints_validation(val, get_runtime_property_constraints(property_id_, resource->data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), get_datatype_constraints(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype))) + { + return make_control_protocol_message_response(handle, { nc_method_status::parameter_error }); + } + + // update property modify_control_protocol_resource(resources, resource->id, [&](nmos::resource& resource) { resource.data[nmos::fields::nc::name(property)][index] = val; - }, make_propertry_changed_event(nmos::fields::nc::oid(resource->data), { { parse_nc_property_id(property_id), nc_property_change_type::type::sequence_item_changed, val, nc_id(index) } })); + }, make_propertry_changed_event(nmos::fields::nc::oid(resource->data), { { property_id_, nc_property_change_type::type::sequence_item_changed, val, nc_id(index) } })); return make_control_protocol_message_response(handle, { nc_method_status::ok }); } @@ -165,7 +184,7 @@ namespace nmos } // Add item to sequence - web::json::value add_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate) + web::json::value add_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -177,7 +196,8 @@ namespace nmos slog::log(gate, SLOG_FLF) << "Add sequence item: " << property_id.serialize() << " value: " << val.serialize(); // find the relevant nc_property_descriptor - const auto& property = find_property(parse_nc_property_id(property_id), parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), get_control_protocol_class); + const auto property_id_ = parse_nc_property_id(property_id); + const auto& property = find_property(property_id_, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), get_control_protocol_class); if (!property.is_null()) { if (!nmos::fields::nc::is_sequence(property)) @@ -192,13 +212,20 @@ namespace nmos const nc_id sequence_item_index = data.is_null() ? 0 : nc_id(data.as_array().size()); + // do constraints validation + if (!constraints_validation(val, get_runtime_property_constraints(property_id_, resource->data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), get_datatype_constraints(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype))) + { + return make_control_protocol_message_response(handle, { nc_method_status::parameter_error }); + } + + // update property modify_control_protocol_resource(resources, resource->id, [&](nmos::resource& resource) { auto& sequence = resource.data[nmos::fields::nc::name(property)]; if (data.is_null()) { sequence = value::array(); } web::json::push_back(sequence, val); - }, make_propertry_changed_event(nmos::fields::nc::oid(resource->data), { { parse_nc_property_id(property_id), nc_property_change_type::type::sequence_item_added, val, sequence_item_index } })); + }, make_propertry_changed_event(nmos::fields::nc::oid(resource->data), { { property_id_, nc_property_change_type::type::sequence_item_added, val, sequence_item_index } })); return make_control_protocol_message_response(handle, { nc_method_status::ok }, sequence_item_index); } diff --git a/Development/nmos/control_protocol_resource.cpp b/Development/nmos/control_protocol_resource.cpp index b374de30d..7a80aae17 100644 --- a/Development/nmos/control_protocol_resource.cpp +++ b/Development/nmos/control_protocol_resource.cpp @@ -507,28 +507,28 @@ namespace nmos } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncpropertyconstraintsnumber - web::json::value make_nc_property_constraints_number(const nc_property_id& property_id, const web::json::value& default_value, const web::json::value& maximum, const web::json::value& minimum, const web::json::value& step) + web::json::value make_nc_property_constraints_number(const nc_property_id& property_id, const web::json::value& default_value, const web::json::value& minimum, const web::json::value& maximum, const web::json::value& step) { using web::json::value; auto data = make_nc_property_constraints(property_id, default_value); - data[nmos::fields::nc::maximum] = maximum; data[nmos::fields::nc::minimum] = minimum; + data[nmos::fields::nc::maximum] = maximum; data[nmos::fields::nc::step] = step; return data; } - web::json::value make_nc_property_constraints_number(const nc_property_id& property_id, uint64_t default_value, uint64_t maximum, uint64_t minimum, uint64_t step) + web::json::value make_nc_property_constraints_number(const nc_property_id& property_id, uint64_t default_value, uint64_t minimum, uint64_t maximum, uint64_t step) { using web::json::value; - return make_nc_property_constraints_number(property_id, value(default_value), value(maximum), value(minimum), value(step)); + return make_nc_property_constraints_number(property_id, value(default_value), value(minimum), value(maximum), value(step)); } - web::json::value make_nc_property_constraints_number(const nc_property_id& property_id, uint64_t maximum, uint64_t minimum, uint64_t step) + web::json::value make_nc_property_constraints_number(const nc_property_id& property_id, uint64_t minimum, uint64_t maximum, uint64_t step) { using web::json::value; - return make_nc_property_constraints_number(property_id, value::null(), maximum, minimum, step); + return make_nc_property_constraints_number(property_id, value::null(), minimum, maximum, step); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncpropertyconstraintsstring @@ -578,28 +578,28 @@ namespace nmos } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsnumber - web::json::value make_nc_parameter_constraints_number(const web::json::value& default_value, const web::json::value& maximum, const web::json::value& minimum, const web::json::value& step) + web::json::value make_nc_parameter_constraints_number(const web::json::value& default_value, const web::json::value& minimum, const web::json::value& maximum, const web::json::value& step) { using web::json::value; auto data = make_nc_parameter_constraints(default_value); - data[nmos::fields::nc::maximum] = maximum; data[nmos::fields::nc::minimum] = minimum; + data[nmos::fields::nc::maximum] = maximum; data[nmos::fields::nc::step] = step; return data; } - web::json::value make_nc_parameter_constraints_number(uint64_t default_value, uint64_t maximum, uint64_t minimum, uint64_t step) + web::json::value make_nc_parameter_constraints_number(uint64_t default_value, uint64_t minimum, uint64_t maximum, uint64_t step) { using web::json::value; - return make_nc_parameter_constraints_number(value(default_value), value(maximum), value(minimum), value(step)); + return make_nc_parameter_constraints_number(value(default_value), value(minimum), value(maximum), value(step)); } - web::json::value make_nc_parameter_constraints_number(uint64_t maximum, uint64_t minimum, uint64_t step) + web::json::value make_nc_parameter_constraints_number(uint64_t minimum, uint64_t maximum, uint64_t step) { using web::json::value; - return make_nc_parameter_constraints_number(value::null(), maximum, minimum, step); + return make_nc_parameter_constraints_number(value::null(), minimum, maximum, step); } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsstring @@ -710,7 +710,7 @@ namespace nmos data[nmos::fields::nc::role] = value::string(role); data[nmos::fields::nc::user_label] = user_label; data[nmos::fields::nc::touchpoints] = touchpoints; - data[nmos::fields::nc::runtime_property_constraints] = runtime_property_constraints; + data[nmos::fields::nc::runtime_property_constraints] = runtime_property_constraints; // level 2 runtime constraints. See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html return data; } @@ -1690,8 +1690,8 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(U("Optional maximum"), nmos::fields::nc::maximum, true, false, value::null())); web::json::push_back(fields, details::make_nc_field_descriptor(U("Optional minimum"), nmos::fields::nc::minimum, true, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Optional maximum"), nmos::fields::nc::maximum, true, false, value::null())); web::json::push_back(fields, details::make_nc_field_descriptor(U("Optional step"), nmos::fields::nc::step, true, false, value::null())); return details::make_nc_datatype_descriptor_struct(U("Number parameter constraints class"), U("NcParameterConstraintsNumber"), fields, U("NcParameterConstraints"), value::null()); } @@ -1779,8 +1779,8 @@ namespace nmos using web::json::value; auto fields = value::array(); - web::json::push_back(fields, details::make_nc_field_descriptor(U("Optional maximum"), nmos::fields::nc::maximum, true, false, value::null())); web::json::push_back(fields, details::make_nc_field_descriptor(U("Optional minimum"), nmos::fields::nc::minimum, true, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Optional maximum"), nmos::fields::nc::maximum, true, false, value::null())); web::json::push_back(fields, details::make_nc_field_descriptor(U("Optional step"), nmos::fields::nc::step, true, false, value::null())); return details::make_nc_datatype_descriptor_struct(U("Number property constraints class"), U("NcPropertyConstraintsNumber"), fields, U("NcPropertyConstraints"), value::null()); } diff --git a/Development/nmos/control_protocol_resource.h b/Development/nmos/control_protocol_resource.h index fc4910dd5..1ff7e8e85 100644 --- a/Development/nmos/control_protocol_resource.h +++ b/Development/nmos/control_protocol_resource.h @@ -131,8 +131,8 @@ namespace nmos web::json::value make_nc_datatype_typedef(const utility::string_t& description, const nc_name& name, bool is_sequence, const utility::string_t& parent_type, const web::json::value& constraints); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncpropertyconstraintsnumber - web::json::value make_nc_property_constraints_number(const nc_property_id& property_id, uint64_t default_value, uint64_t maximum, uint64_t minimum, uint64_t step); - web::json::value make_nc_property_constraints_number(const nc_property_id& property_id, uint64_t maximum, uint64_t minimum, uint64_t step); + web::json::value make_nc_property_constraints_number(const nc_property_id& property_id, uint64_t default_value, uint64_t minimum, uint64_t maximum, uint64_t step); + web::json::value make_nc_property_constraints_number(const nc_property_id& property_id, uint64_t minimum, uint64_t maximum, uint64_t step); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncpropertyconstraintsstring web::json::value make_nc_property_constraints_string(const nc_property_id& property_id, const utility::string_t& default_value, uint32_t max_characters, const nc_regex& pattern); @@ -141,8 +141,8 @@ namespace nmos web::json::value make_nc_property_constraints_string(const nc_property_id& property_id, const nc_regex& pattern); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsnumber - web::json::value make_nc_parameter_constraints_number(uint64_t default_value, uint64_t maximum, uint64_t minimum, uint64_t step); - web::json::value make_nc_parameter_constraints_number(uint64_t maximum, uint64_t minimum, uint64_t step); + web::json::value make_nc_parameter_constraints_number(uint64_t default_value, uint64_t minimum, uint64_t maximum, uint64_t step); + web::json::value make_nc_parameter_constraints_number(uint64_t minimum, uint64_t maximum, uint64_t step); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsstring web::json::value make_nc_parameter_constraints_string(const utility::string_t& default_value, uint32_t max_characters, const nc_regex& pattern); diff --git a/Development/nmos/control_protocol_utils.cpp b/Development/nmos/control_protocol_utils.cpp index 38e215f7c..e03c6697f 100644 --- a/Development/nmos/control_protocol_utils.cpp +++ b/Development/nmos/control_protocol_utils.cpp @@ -3,6 +3,7 @@ #include #include #include +#include "bst/regex.h" #include "cpprest/json_utils.h" #include "nmos/control_protocol_resource.h" #include "nmos/control_protocol_state.h" @@ -24,6 +25,44 @@ namespace nmos } return control_class_id == class_id; } + + // get the runtime property constraints of a given property_id + web::json::value get_runtime_property_constraints(const nc_property_id& property_id, const web::json::value& runtime_property_constraints) + { + using web::json::value; + + if (!runtime_property_constraints.is_null()) + { + auto& runtime_prop_constraints = runtime_property_constraints.as_array(); + auto found_constraints = std::find_if(runtime_prop_constraints.begin(), runtime_prop_constraints.end(), [&property_id](const web::json::value& constraints) + { + //return nmos::fields::nc::id(property) == nmos::fields::nc::property_id(constraints); + return property_id == parse_nc_property_id(nmos::fields::nc::property_id(constraints)); + }); + + if (runtime_prop_constraints.end() != found_constraints) + { + return *found_constraints; + } + } + return value::null(); + } + + // get the datatype property constraints of a given type_name + web::json::value get_datatype_constraints(const web::json::value& type_name, get_control_protocol_datatype_handler get_control_protocol_datatype) + { + using web::json::value; + + if (!type_name.is_null()) + { + const auto& datatype = get_control_protocol_datatype(type_name.as_string()); + if (!datatype.descriptor.is_null()) // NcDatatypeDescriptor + { + return nmos::fields::nc::constraints(datatype.descriptor); + } + } + return value::null(); + } } // is the given class_id a NcBlock @@ -80,16 +119,12 @@ namespace nmos { const auto& control_class = get_control_protocol_class(class_id); auto& properties = control_class.properties.as_array(); - if (properties.size()) + auto found = std::find_if(properties.begin(), properties.end(), [&property_id](const web::json::value& property) { - for (const auto& property : properties) - { - if (property_id == nmos::details::parse_nc_property_id(nmos::fields::nc::id(property))) - { - return property; - } - } - } + return (property_id == nmos::details::parse_nc_property_id(nmos::fields::nc::id(property))); + }); + if (properties.end() != found) { return *found; } + class_id.pop_back(); } @@ -302,4 +337,78 @@ namespace nmos return false; }); } + + // constraints validation + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsnumber + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsstring + bool constraints_validation(const web::json::value& value, const web::json::value& constraints) + { + // is numeric constraints + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsnumber + if (constraints.has_field(nmos::fields::nc::step) && !nmos::fields::nc::step(constraints).is_null()) + { + if (!value.is_integer()) { return false; } + + const auto step = nmos::fields::nc::step(constraints).as_double(); + if (step <= 0) { return false; } + + const auto value_double = value.as_double(); + if (constraints.has_field(nmos::fields::nc::minimum) && !nmos::fields::nc::minimum(constraints).is_null()) + { + auto min = nmos::fields::nc::minimum(constraints).as_double(); + if (0 != std::fmod(value_double - min, step)) { return false; } + } + else if (constraints.has_field(nmos::fields::nc::maximum) && !nmos::fields::nc::maximum(constraints).is_null()) + { + auto max = nmos::fields::nc::maximum(constraints).as_double(); + if (0 != std::fmod(max - value_double, step)) { return false; } + } + else + { + if (0 != std::fmod(value_double, step)) { return false; } + } + } + if (constraints.has_field(nmos::fields::nc::minimum) && !nmos::fields::nc::minimum(constraints).is_null()) + { + if (!value.is_integer() || value.as_double() < nmos::fields::nc::minimum(constraints).as_double()) { return false; } + } + if (constraints.has_field(nmos::fields::nc::maximum) && !nmos::fields::nc::maximum(constraints).is_null()) + { + if (!value.is_integer() || value.as_double() > nmos::fields::nc::maximum(constraints).as_double()) { return false; } + } + + // is string constraints + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsstring + if (constraints.has_field(nmos::fields::nc::max_characters) && !constraints.at(nmos::fields::nc::max_characters).is_null()) + { + const auto max_characters = nmos::fields::nc::max_characters(constraints); + if (!value.is_string() || value.as_string().length() > max_characters) { return false; } + } + if (constraints.has_field(nmos::fields::nc::pattern) && !constraints.at(nmos::fields::nc::pattern).is_null()) + { + if (!value.is_string()) { return false; } + const auto value_string = utility::us2s(value.as_string()); + bst::regex pattern(utility::us2s(nmos::fields::nc::pattern(constraints))); + if (!bst::regex_match(value_string, pattern)) { return false; } + } + + return true; + } + + // multiple levels of constraints validation + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html + bool constraints_validation(const web::json::value& value, const web::json::value& runtime_property_constraints, const web::json::value& property_constraints, const web::json::value& datatype_constraints) + { + // do level 2 runtime property constraints validation + if (!runtime_property_constraints.is_null()) { return constraints_validation(value, runtime_property_constraints); } + + // do level 1 property constraints validation + if (!property_constraints.is_null()) { return constraints_validation(value, property_constraints); } + + // do level 0 datatype constraints validation + if (!datatype_constraints.is_null()) { return constraints_validation(value, datatype_constraints); } + + // reaching here, no validation is required + return true; + } } diff --git a/Development/nmos/control_protocol_utils.h b/Development/nmos/control_protocol_utils.h index 72580351f..ec16841da 100644 --- a/Development/nmos/control_protocol_utils.h +++ b/Development/nmos/control_protocol_utils.h @@ -8,6 +8,15 @@ namespace nmos { struct control_protocol_resource; + namespace details + { + // get the runtime property constraints of a given property_id + web::json::value get_runtime_property_constraints(const nc_property_id& property_id, const web::json::value& runtime_property_constraints_list); + + // get the datatype property constraints of a given type_name + web::json::value get_datatype_constraints(const web::json::value& type_name, get_control_protocol_datatype_handler get_control_protocol_datatype); + } + // is the given class_id a NcBlock bool is_nc_block(const nc_class_id& class_id); @@ -47,6 +56,15 @@ namespace nmos // find the control protocol resource which is assoicated with the given IS-04/IS-05/IS-08 resource id resources::const_iterator find_control_protocol_resource(resources& resources, type type, const id& id); + + // constraints validation + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsnumber + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsstring + bool constraints_validation(const web::json::value& value, const web::json::value& constraints); + + // multiple levels of constraints validation + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html + bool constraints_validation(const web::json::value& value, const web::json::value& runtime_property_constraints, const web::json::value& property_constraints, const web::json::value& data_constraints); } #endif diff --git a/Development/nmos/json_fields.h b/Development/nmos/json_fields.h index 0c293ac97..12bfa9bbf 100644 --- a/Development/nmos/json_fields.h +++ b/Development/nmos/json_fields.h @@ -322,9 +322,9 @@ namespace nmos const web::json::field_as_integer change_type{ U("changeType") }; // NcPropertyChangeType const web::json::field_as_integer sequence_item_index{ U("sequenceItemIndex") }; // NcId const web::json::field_as_value property_id{ U("propertyId") }; - const web::json::field_as_integer maximum{ U("maximum") }; - const web::json::field_as_integer minimum{ U("minimum") }; - const web::json::field_as_integer step{ U("step") }; + const web::json::field_as_value maximum{ U("maximum") }; + const web::json::field_as_value minimum{ U("minimum") }; + const web::json::field_as_value step{ U("step") }; const web::json::field_as_integer max_characters{ U("maxCharacters") }; const web::json::field_as_string pattern{ U("pattern") }; const web::json::field_as_value resource{ U("resource") }; diff --git a/Development/nmos/test/control_protocol_test.cpp b/Development/nmos/test/control_protocol_test.cpp index 91a115a42..1b8a4e5fe 100644 --- a/Development/nmos/test/control_protocol_test.cpp +++ b/Development/nmos/test/control_protocol_test.cpp @@ -700,3 +700,69 @@ BST_TEST_CASE(testFindProperty) BST_REQUIRE(property.is_null()); } } + +BST_TEST_CASE(testConstraints) +{ + using web::json::value_of; + using web::json::value; + + const nmos::nc_property_id property_string_id{ 100, 1 }; + const nmos::nc_property_id property_number_id{ 100, 2 }; + const nmos::nc_property_id unknown_property_id{ 100, 3 }; + + const auto runtime_property_string_constraints = nmos::details::make_nc_property_constraints_string(property_string_id, 10, U("^[0-9]+$")); + const auto runtime_property_number_constraints = nmos::details::make_nc_property_constraints_number(property_number_id, 10, 1000, 1); + + const auto runtime_property_constraints = value_of({ + { runtime_property_string_constraints }, + { runtime_property_number_constraints } + }); + + const auto property_string_constraints = nmos::details::make_nc_parameter_constraints_string(5, U("^[a-z]+$")); + const auto property_number_constraints = nmos::details::make_nc_parameter_constraints_number(50, 500, 5); + + const auto datatype_string_constraints = nmos::details::make_nc_parameter_constraints_string(2, U("^[0-9a-z]+$")); + const auto datatype_number_constraints = nmos::details::make_nc_parameter_constraints_number(100, 250, 10); + + // test get_runtime_property_constraints + BST_REQUIRE_EQUAL(nmos::details::get_runtime_property_constraints(property_string_id, runtime_property_constraints), runtime_property_string_constraints); + BST_REQUIRE_EQUAL(nmos::details::get_runtime_property_constraints(property_number_id, runtime_property_constraints), runtime_property_number_constraints); + BST_REQUIRE_EQUAL(nmos::details::get_runtime_property_constraints(unknown_property_id, runtime_property_constraints), value::null()); + + // string property constraints validation + BST_REQUIRE(nmos::constraints_validation(value::string(U("1234567890")), runtime_property_string_constraints, property_string_constraints, datatype_string_constraints)); + BST_REQUIRE_EQUAL(nmos::constraints_validation(value::string(U("12345678901")), runtime_property_string_constraints, property_string_constraints, datatype_string_constraints), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(value::string(U("123456789A")), runtime_property_string_constraints, property_string_constraints, datatype_string_constraints), false); + BST_REQUIRE(nmos::constraints_validation(value::string(U("12345678901")), value::null(), value::null(), value::null())); + BST_REQUIRE(nmos::constraints_validation(value::string(U("123456789A")), value::null(), value::null(), value::null())); + + BST_REQUIRE(nmos::constraints_validation(value::string(U("abcde")), value::null(), property_string_constraints, datatype_string_constraints)); + BST_REQUIRE_EQUAL(nmos::constraints_validation(value::string(U("abcdef")), value::null(), property_string_constraints, datatype_string_constraints), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(value::string(U("abcd1")), value::null(), property_string_constraints, datatype_string_constraints), false); + + BST_REQUIRE(nmos::constraints_validation(value::string(U("1a")), value::null(), value::null(), datatype_string_constraints)); + BST_REQUIRE_EQUAL(nmos::constraints_validation(value::string(U("1a2")), value::null(), value::null(), datatype_string_constraints), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(value::string(U("1*")), value::null(), value::null(), datatype_string_constraints), false); + + // number property constraints validation + BST_REQUIRE(nmos::constraints_validation(10, runtime_property_number_constraints, property_number_constraints, datatype_number_constraints)); + BST_REQUIRE(nmos::constraints_validation(1000, runtime_property_number_constraints, property_number_constraints, datatype_number_constraints)); + BST_REQUIRE_EQUAL(nmos::constraints_validation(9, runtime_property_number_constraints, property_number_constraints, datatype_number_constraints), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(1001, runtime_property_number_constraints, property_number_constraints, datatype_number_constraints), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(0.5, runtime_property_number_constraints, property_number_constraints, datatype_number_constraints), false); + BST_REQUIRE(nmos::constraints_validation(9, value::null(), value::null(), value::null())); + BST_REQUIRE(nmos::constraints_validation(1001, value::null(), value::null(), value::null())); + BST_REQUIRE(nmos::constraints_validation(0.5, value::null(), value::null(), value::null())); + + BST_REQUIRE(nmos::constraints_validation(50, value::null(), property_number_constraints, datatype_number_constraints)); + BST_REQUIRE(nmos::constraints_validation(500, value::null(), property_number_constraints, datatype_number_constraints)); + BST_REQUIRE_EQUAL(nmos::constraints_validation(45, value::null(), property_number_constraints, datatype_number_constraints), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(505, value::null(), property_number_constraints, datatype_number_constraints), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(499, value::null(), property_number_constraints, datatype_number_constraints), false); + + BST_REQUIRE(nmos::constraints_validation(100, value::null(), value::null(), datatype_number_constraints)); + BST_REQUIRE(nmos::constraints_validation(250, value::null(), value::null(), datatype_number_constraints)); + BST_REQUIRE_EQUAL(nmos::constraints_validation(90, value::null(), value::null(), datatype_number_constraints), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(260, value::null(), value::null(), datatype_number_constraints), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(99, value::null(), value::null(), datatype_number_constraints), false); +} From 677f66e7ce0b75b51886e1cc3feb5c04fc0769d4 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Mon, 30 Oct 2023 19:00:49 +0000 Subject: [PATCH 064/106] Update comments --- Development/nmos-cpp-node/node_implementation.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Development/nmos-cpp-node/node_implementation.cpp b/Development/nmos-cpp-node/node_implementation.cpp index e1c60fc3b..ed4a4f70c 100644 --- a/Development/nmos-cpp-node/node_implementation.cpp +++ b/Development/nmos-cpp-node/node_implementation.cpp @@ -921,7 +921,10 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr if (!insert_resource_after(delay_millis, model.channelmapping_resources, std::move(channelmapping_output), gate)) throw node_implementation_init_exception(); } - // example of using IS-12 control protocol + // examples of using IS-12 control protocol + // they are based on the NC-DEVICE-MOCK + // See https://specs.amwa.tv/nmos-device-control-mock/#about-nc-device-mock + // See https://github.com/AMWA-TV/nmos-device-control-mock/blob/main/code/src/NCModel/Features.ts if (0 <= nmos::fields::control_protocol_ws_port(model.settings)) { // example to create a non-standard Gain control class @@ -1102,7 +1105,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr { using web::json::value_of; - return web::json::value_of({ + return value_of({ { enum_property, enum_property_ }, { string_property, string_property_ }, { number_property, number_property_ }, From ad85dd0c13417d865736ce99ddd5bc0792108be0 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Mon, 30 Oct 2023 19:01:12 +0000 Subject: [PATCH 065/106] typo --- Development/nmos/control_protocol_state.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Development/nmos/control_protocol_state.cpp b/Development/nmos/control_protocol_state.cpp index 80ff4254c..10e8eac49 100644 --- a/Development/nmos/control_protocol_state.cpp +++ b/Development/nmos/control_protocol_state.cpp @@ -160,7 +160,7 @@ namespace nmos // setup the core datatypes datatypes = { - // Dataype models + // Datatype models // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/#datatype-models-for-branch-v10-dev { U("NcClassId"), {make_nc_class_id_datatype()} }, { U("NcOid"), {make_nc_oid_datatype()} }, From 613beaf9a257fc83b6675cc6a7fd15726bbfcf41 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 31 Oct 2023 10:32:21 +0000 Subject: [PATCH 066/106] Add primitive types --- .../nmos/control_protocol_resource.cpp | 80 +++++++++++++++++ Development/nmos/control_protocol_resource.h | 20 +++++ Development/nmos/control_protocol_state.cpp | 89 +++++++++++++++++-- 3 files changed, 180 insertions(+), 9 deletions(-) diff --git a/Development/nmos/control_protocol_resource.cpp b/Development/nmos/control_protocol_resource.cpp index 7a80aae17..61ab4b3ec 100644 --- a/Development/nmos/control_protocol_resource.cpp +++ b/Development/nmos/control_protocol_resource.cpp @@ -1304,6 +1304,86 @@ namespace nmos return details::make_nc_class_descriptor(U("NcReceiverMonitorProtected class descriptor"), nc_receiver_monitor_protected_class_id, U("NcReceiverMonitorProtected"), make_nc_receiver_monitor_protected_properties(), make_nc_receiver_monitor_protected_methods(), make_nc_receiver_monitor_protected_events()); } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#primitives + web::json::value make_nc_boolean_datatype() + { + using web::json::value; + + return details::make_nc_datatype_descriptor_primitive(U("Boolean primitive type"), U("NcBoolean"), value::null()); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#primitives + web::json::value make_nc_int16_datatype() + { + using web::json::value; + + return details::make_nc_datatype_descriptor_primitive(U("short"), U("NcInt16"), value::null()); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#primitives + web::json::value make_nc_int32_datatype() + { + using web::json::value; + + return details::make_nc_datatype_descriptor_primitive(U("long"), U("NcInt32"), value::null()); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#primitives + web::json::value make_nc_int64_datatype() + { + using web::json::value; + + return details::make_nc_datatype_descriptor_primitive(U("longlong"), U("NcInt64"), value::null()); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#primitives + web::json::value make_nc_uint16_datatype() + { + using web::json::value; + + return details::make_nc_datatype_descriptor_primitive(U("unsignedshort"), U("NcUint16"), value::null()); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#primitives + web::json::value make_nc_uint32_datatype() + { + using web::json::value; + + return details::make_nc_datatype_descriptor_primitive(U("unsignedlong"), U("NcUint32"), value::null()); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#primitives + web::json::value make_nc_uint64_datatype() + { + using web::json::value; + + return details::make_nc_datatype_descriptor_primitive(U("unsignedlonglong"), U("NcUint64"), value::null()); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#primitives + web::json::value make_nc_float32_datatype() + { + using web::json::value; + + return details::make_nc_datatype_descriptor_primitive(U("unrestrictedfloat"), U("NcFloat32"), value::null()); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#primitives + web::json::value make_nc_float64_datatype() + { + using web::json::value; + + return details::make_nc_datatype_descriptor_primitive(U("unrestricteddouble"), U("NcFloat64"), value::null()); + } + + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#primitives + web::json::value make_nc_string_datatype() + { + using web::json::value; + + return details::make_nc_datatype_descriptor_primitive(U("UTF-8 string"), U("NcString"), value::null()); + } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcBlockMemberDescriptor.html web::json::value make_nc_block_member_descriptor_datatype() { diff --git a/Development/nmos/control_protocol_resource.h b/Development/nmos/control_protocol_resource.h index 1ff7e8e85..700f8e194 100644 --- a/Development/nmos/control_protocol_resource.h +++ b/Development/nmos/control_protocol_resource.h @@ -270,6 +270,26 @@ namespace nmos // Datatype models // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/#datatype-models-for-branch-v10-dev // + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#primitives + web::json::value make_nc_boolean_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#primitives + web::json::value make_nc_int16_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#primitives + web::json::value make_nc_int32_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#primitives + web::json::value make_nc_int64_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#primitives + web::json::value make_nc_uint16_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#primitives + web::json::value make_nc_uint32_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#primitives + web::json::value make_nc_uint64_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#primitives + web::json::value make_nc_float32_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#primitives + web::json::value make_nc_float64_datatype(); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#primitives + web::json::value make_nc_string_datatype(); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcBlockMemberDescriptor.html web::json::value make_nc_block_member_descriptor_datatype(); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcClassDescriptor.html diff --git a/Development/nmos/control_protocol_state.cpp b/Development/nmos/control_protocol_state.cpp index 10e8eac49..5ab2ccc32 100644 --- a/Development/nmos/control_protocol_state.cpp +++ b/Development/nmos/control_protocol_state.cpp @@ -117,9 +117,15 @@ namespace nmos { // Control class models // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/classes/#control-class-models-for-branch-v10-dev - { nc_object_class_id, make_control_class(U("NcObject class descriptor"), nc_object_class_id, U("NcObject"), to_vector(make_nc_object_properties()), + + // NcObject + { nc_object_class_id, make_control_class(U("NcObject class descriptor"), nc_object_class_id, U("NcObject"), + // NcObject properties + to_vector(make_nc_object_properties()), + // NcObject methods to_methods_vector(make_nc_object_methods(), { + // link NcObject method_ids with method functions { nc_object_get_method_id, nmos::details::get }, { nc_object_set_method_id, nmos::details::set }, { nc_object_get_sequence_item_method_id, nmos::details::get_sequence_item }, @@ -128,33 +134,88 @@ namespace nmos { nc_object_remove_sequence_item_method_id, nmos::details::remove_sequence_item }, { nc_object_get_sequence_length_method_id, nmos::details::get_sequence_length } }), + // NcObject events to_vector(make_nc_object_events())) }, - { nc_block_class_id, make_control_class(U("NcBlock class descriptor"), nc_block_class_id, U("NcBlock"), to_vector(make_nc_block_properties()), + // NcBlock + { nc_block_class_id, make_control_class(U("NcBlock class descriptor"), nc_block_class_id, U("NcBlock"), + // NcBlock properties + to_vector(make_nc_block_properties()), + // NcBlock methods to_methods_vector(make_nc_block_methods(), { + // link NcBlock method_ids with method functions { nc_block_get_member_descriptors_method_id, nmos::details::get_member_descriptors }, { nc_block_find_members_by_path_method_id, nmos::details::find_members_by_path }, { nc_block_find_members_by_role_method_id, nmos::details::find_members_by_role }, { nc_block_find_members_by_class_id_method_id, nmos::details::find_members_by_class_id } }), + // NcBlock events to_vector(make_nc_block_events())) }, - { nc_worker_class_id, make_control_class(U("NcWorker class descriptor"), nc_worker_class_id, U("NcWorker"), to_vector(make_nc_worker_properties()), to_methods_vector(make_nc_worker_methods(), {}), to_vector(make_nc_worker_events())) }, - { nc_manager_class_id, make_control_class(U("NcManager class descriptor"), nc_manager_class_id, U("NcManager"),to_vector(make_nc_manager_properties()), to_methods_vector(make_nc_manager_methods(), {}), to_vector(make_nc_manager_events())) }, - { nc_device_manager_class_id, make_control_class(U("NcDeviceManager class descriptor"), nc_device_manager_class_id, U("NcDeviceManager"), U("DeviceManager"), to_vector(make_nc_device_manager_properties()), to_methods_vector(make_nc_device_manager_methods(), {}), to_vector(make_nc_device_manager_events())) }, - { nc_class_manager_class_id, make_control_class(U("NcClassManager class descriptor"), nc_class_manager_class_id, U("NcClassManager"), U("ClassManager"), to_vector(make_nc_class_manager_properties()), + // NcWorker + { nc_worker_class_id, make_control_class(U("NcWorker class descriptor"), nc_worker_class_id, U("NcWorker"), + // NcWorker properties + to_vector(make_nc_worker_properties()), + // NcWorker methods + to_methods_vector(make_nc_worker_methods(), {}), + // NcWorker events + to_vector(make_nc_worker_events())) }, + // NcManager + { nc_manager_class_id, make_control_class(U("NcManager class descriptor"), nc_manager_class_id, U("NcManager"), + // NcManager properties + to_vector(make_nc_manager_properties()), + // NcManager methods + to_methods_vector(make_nc_manager_methods(), {}), + // NcManager events + to_vector(make_nc_manager_events())) }, + // NcDeviceManager + { nc_device_manager_class_id, make_control_class(U("NcDeviceManager class descriptor"), nc_device_manager_class_id, U("NcDeviceManager"), U("DeviceManager"), + // NcDeviceManager properties + to_vector(make_nc_device_manager_properties()), + // NcDeviceManager methods + to_methods_vector(make_nc_device_manager_methods(), {}), + // NcDeviceManager events + to_vector(make_nc_device_manager_events())) }, + // NcClassManager + { nc_class_manager_class_id, make_control_class(U("NcClassManager class descriptor"), nc_class_manager_class_id, U("NcClassManager"), U("ClassManager"), + // NcClassManager properties + to_vector(make_nc_class_manager_properties()), + // NcClassManager methods to_methods_vector(make_nc_class_manager_methods(), { + // link NcClassManager method_ids with method functions { nc_class_manager_get_control_class_method_id, nmos::details::get_control_class }, { nc_class_manager_get_datatype_method_id, nmos::details::get_datatype } }), + // NcClassManager events to_vector(make_nc_class_manager_events())) }, // identification beacon model // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/identification/#ncidentbeacon - { nc_ident_beacon_class_id, make_control_class(U("NcIdentBeacon class descriptor"), nc_ident_beacon_class_id, U("NcIdentBeacon"), to_vector(make_nc_ident_beacon_properties()), to_methods_vector(make_nc_ident_beacon_methods(), {}), to_vector(make_nc_ident_beacon_events())) }, + // NcIdentBeacon + { nc_ident_beacon_class_id, make_control_class(U("NcIdentBeacon class descriptor"), nc_ident_beacon_class_id, U("NcIdentBeacon"), + // NcIdentBeacon properties + to_vector(make_nc_ident_beacon_properties()), + // NcIdentBeacon methods + to_methods_vector(make_nc_ident_beacon_methods(), {}), + // NcIdentBeacon events + to_vector(make_nc_ident_beacon_events())) }, // Monitoring // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitor - { nc_receiver_monitor_class_id, make_control_class(U("NcReceiverMonitor class descriptor"), nc_receiver_monitor_class_id, U("NcReceiverMonitor"), to_vector(make_nc_receiver_monitor_properties()), to_methods_vector(make_nc_receiver_monitor_methods(), {}), to_vector(make_nc_receiver_monitor_events())) }, - { nc_receiver_monitor_protected_class_id, make_control_class(U("NcReceiverMonitorProtected class descriptor"), nc_receiver_monitor_protected_class_id, U("NcReceiverMonitorProtected"), to_vector(make_nc_receiver_monitor_protected_properties()), to_methods_vector(make_nc_receiver_monitor_protected_methods(), {}), to_vector(make_nc_receiver_monitor_protected_events())) } + // NcReceiverMonitor + { nc_receiver_monitor_class_id, make_control_class(U("NcReceiverMonitor class descriptor"), nc_receiver_monitor_class_id, U("NcReceiverMonitor"), + // NcReceiverMonitor properties + to_vector(make_nc_receiver_monitor_properties()), + // NcReceiverMonitor methods + to_methods_vector(make_nc_receiver_monitor_methods(), {}), + // NcReceiverMonitor events + to_vector(make_nc_receiver_monitor_events())) }, + // NcReceiverMonitorProtected + { nc_receiver_monitor_protected_class_id, make_control_class(U("NcReceiverMonitorProtected class descriptor"), nc_receiver_monitor_protected_class_id, U("NcReceiverMonitorProtected"), + // NcReceiverMonitorProtected properties + to_vector(make_nc_receiver_monitor_protected_properties()), + // NcReceiverMonitorProtected methods + to_methods_vector(make_nc_receiver_monitor_protected_methods(), {}), + // NcReceiverMonitorProtected events + to_vector(make_nc_receiver_monitor_protected_events())) } }; // setup the core datatypes @@ -162,6 +223,16 @@ namespace nmos { // Datatype models // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/#datatype-models-for-branch-v10-dev + { U("NcBoolean"), {make_nc_boolean_datatype()} }, + { U("NcInt16"), {make_nc_int16_datatype()} }, + { U("NcInt32"), {make_nc_int32_datatype()} }, + { U("NcInt64"), {make_nc_int64_datatype()} }, + { U("NcUint16"), {make_nc_uint16_datatype()} }, + { U("NcUint32"), {make_nc_uint32_datatype()} }, + { U("NcUint64"), {make_nc_uint64_datatype()} }, + { U("NcFloat32"), {make_nc_float32_datatype()} }, + { U("NcFloat64"), {make_nc_float64_datatype()} }, + { U("NcString"), {make_nc_string_datatype()} }, { U("NcClassId"), {make_nc_class_id_datatype()} }, { U("NcOid"), {make_nc_oid_datatype()} }, { U("NcTouchpoint"), {make_nc_touchpoint_datatype()} }, From cbedf53da8c6df1ca5d492c951cb2bc8811280ca Mon Sep 17 00:00:00 2001 From: lo-simon Date: Fri, 3 Nov 2023 11:28:41 +0000 Subject: [PATCH 067/106] Add a simple temperature sensor example, which pumps out new temperature value in a time interval --- .../nmos-cpp-node/node_implementation.cpp | 59 ++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/Development/nmos-cpp-node/node_implementation.cpp b/Development/nmos-cpp-node/node_implementation.cpp index ed4a4f70c..fa4293c02 100644 --- a/Development/nmos-cpp-node/node_implementation.cpp +++ b/Development/nmos-cpp-node/node_implementation.cpp @@ -976,7 +976,6 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr Beta = 2, Gamma = 3 }; - { // Example control class properties std::vector example_control_properties = { @@ -1168,6 +1167,32 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr return nmos::control_protocol_resource{ nmos::is12_versions::v1_0, nmos::types::nc_worker, std::move(data), true }; }; + // example to create a non-standard Temperature Sensor control class + const auto temperature_sensor_control_class_id = nmos::make_nc_class_id(nmos::nc_worker_class_id, 0, { 3 }); + const web::json::field_as_number temperature{ U("temperature") }; + const web::json::field_as_string unit{ U("uint") }; + { + // Temperature Sensor control class properties + std::vector temperature_sensor_properties = { + nmos::experimental::make_control_class_property(U("Temperature"), { 3, 1 }, temperature, U("NcFloat32"), true), + nmos::experimental::make_control_class_property(U("Unit"), { 3, 2 }, unit, U("NcString"), true) + }; + + // create Temperature Sensor control class + auto temperature_sensor_control_class = nmos::experimental::make_control_class(U("Temperature Sensor control class descriptor"), temperature_sensor_control_class_id, U("TemperatureSensor"), temperature_sensor_properties); + + // insert Temperature Sensor control class to global state, which will be used by the control_protocol_ws_message_handler to process incoming ws message + control_protocol_state.insert(temperature_sensor_control_class); + } + // helper function to create Temperature Sensor control + auto make_temperature_sensor = [&temperature, &unit, temperature_sensor_control_class_id](nmos::nc_oid oid, nmos::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null(), float temperature_ = 0.0, const utility::string_t& unit_ = U("Celsius")) + { + auto data = nmos::details::make_nc_worker(temperature_sensor_control_class_id, oid, true, owner, role, value::string(user_label), description, touchpoints, runtime_property_constraints, true); + data[temperature] = value::number(temperature_); + data[unit] = value::string(unit_); + + return nmos::control_protocol_resource{ nmos::is12_versions::v1_0, nmos::types::nc_worker, std::move(data), true }; + }; // example root block auto root_block = nmos::make_root_block(); @@ -1244,6 +1269,11 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr } } + // example temperature-sensor + const auto temperature_sensor = make_temperature_sensor(++oid, nmos::root_block_oid, U("temperature-sensor"), U("Temperature Sensor"), U("Temperature Sensor block")); + + // add temperature-sensor to root-block + nmos::push_back(root_block, temperature_sensor); // add example-control to root-block nmos::push_back(root_block, example_control); // add stereo-gain to root-block @@ -1319,6 +1349,33 @@ void node_implementation_run(nmos::node_model& model, slog::base_gate& gate) } } + // update temperature sensor + { + const auto temperature_sensor_control_class_id = nmos::make_nc_class_id(nmos::nc_worker_class_id, 0, { 3 }); + const web::json::field_as_number temperature{ U("temperature") }; + + auto& resources = model.control_protocol_resources; + + auto found = nmos::find_resource_if(resources, nmos::types::nc_worker, [&temperature_sensor_control_class_id](const nmos::resource& resource) + { + return temperature_sensor_control_class_id == nmos::details::parse_nc_class_id(nmos::fields::nc::class_id(resource.data)); + }); + + if (resources.end() != found) + { + const auto propertry_changed_event = nmos::make_propertry_changed_event(nmos::fields::nc::oid(found->data), + { + { {3, 1}, nmos::nc_property_change_type::type::value_changed, web::json::value(temp.scaled_value()) } + }); + + nmos::modify_control_protocol_resource(model.control_protocol_resources, found->id, [&](nmos::resource& resource) + { + resource.data[temperature] = temp.scaled_value(); + + }, propertry_changed_event); + } + } + slog::log(gate, SLOG_FLF) << "Temperature updated: " << temp.scaled_value() << " (" << impl::temperature_Celsius.name << ")"; model.notify(); From d21ca754cbe1df9774e6d13685b541b8ccf20698 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 7 Nov 2023 18:36:23 +0000 Subject: [PATCH 068/106] Fix non-standard class's method handing --- Development/nmos-cpp-node/main.cpp | 2 +- .../nmos-cpp-node/node_implementation.cpp | 12 +++++-- .../nmos/control_protocol_handlers.cpp | 26 +++++++++++----- Development/nmos/control_protocol_handlers.h | 12 ++++--- Development/nmos/control_protocol_state.cpp | 12 +++---- Development/nmos/control_protocol_state.h | 4 +-- Development/nmos/control_protocol_ws_api.cpp | 31 ++----------------- Development/nmos/control_protocol_ws_api.h | 6 ++-- Development/nmos/node_server.cpp | 2 +- Development/nmos/node_server.h | 8 ++--- 10 files changed, 55 insertions(+), 60 deletions(-) diff --git a/Development/nmos-cpp-node/main.cpp b/Development/nmos-cpp-node/main.cpp index ae9d4380f..dbd2a8f0c 100644 --- a/Development/nmos-cpp-node/main.cpp +++ b/Development/nmos-cpp-node/main.cpp @@ -114,7 +114,7 @@ int main(int argc, char* argv[]) { node_implementation.on_get_control_class(nmos::make_get_control_protocol_class_handler(control_protocol_state)); node_implementation.on_get_control_datatype(nmos::make_get_control_protocol_datatype_handler(control_protocol_state)); - node_implementation.on_get_control_protocol_methods(nmos::make_get_control_protocol_methods_handler(control_protocol_state)); + node_implementation.on_get_control_protocol_method(nmos::make_get_control_protocol_method_handler(control_protocol_state)); } // Set up the node server diff --git a/Development/nmos-cpp-node/node_implementation.cpp b/Development/nmos-cpp-node/node_implementation.cpp index fa4293c02..67360c8c8 100644 --- a/Development/nmos-cpp-node/node_implementation.cpp +++ b/Development/nmos-cpp-node/node_implementation.cpp @@ -1002,12 +1002,16 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr auto example_method_with_no_args = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + slog::log(gate, SLOG_FLF) << "Executing the example method with no arguments"; return nmos::make_control_protocol_message_response(handle, { nmos::nc_method_status::ok }); }; - auto example_method_with_simple_args = [&](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) + auto example_method_with_simple_args = [enum_arg, string_arg, number_arg, boolean_arg, make_string_example_argument_constraints, make_number_example_argument_constraints](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + slog::log(gate, SLOG_FLF) << "Executing the example method with simple arguments:" << " enum_arg: " << enum_arg(arguments).to_int32() @@ -1028,8 +1032,10 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr return nmos::make_control_protocol_message_response(handle, { nmos::nc_method_status::ok }); }; - auto example_method_with_object_args = [&](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) + auto example_method_with_object_args = [obj_arg](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + slog::log(gate, SLOG_FLF) << "Executing the example method with object argument:" << " obj_arg: " << obj_arg(arguments).serialize(); @@ -1037,7 +1043,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr return nmos::make_control_protocol_message_response(handle, { nmos::nc_method_status::ok }); }; // Example control class methods - std::vector> example_control_methods = + std::vector> example_control_methods = { { nmos::experimental::make_control_class_method(U("Example method with no arguments"), { 3, 1 }, U("MethodNoArgs"), U("NcMethodResult"), {}, false), example_method_with_no_args }, { nmos::experimental::make_control_class_method(U("Example method with simple arguments"), { 3, 2 }, U("MethodSimpleArgs"), U("NcMethodResult"), diff --git a/Development/nmos/control_protocol_handlers.cpp b/Development/nmos/control_protocol_handlers.cpp index f51b85cf6..e650496aa 100644 --- a/Development/nmos/control_protocol_handlers.cpp +++ b/Development/nmos/control_protocol_handlers.cpp @@ -38,21 +38,31 @@ namespace nmos }; } - get_control_protocol_methods_handler make_get_control_protocol_methods_handler(experimental::control_protocol_state& control_protocol_state) + get_control_protocol_method_handler make_get_control_protocol_method_handler(experimental::control_protocol_state& control_protocol_state) { - return [&]() + return [&](const nc_class_id& class_id_, const nc_method_id& method_id) { - std::map methods; + auto class_id = class_id_; - auto lock = control_protocol_state.read_lock(); + auto get_control_protocol_class = make_get_control_protocol_class_handler(control_protocol_state); - auto& control_classes = control_protocol_state.control_classes; + auto lock = control_protocol_state.read_lock(); - for (const auto& control_class : control_classes) + while (!class_id.empty()) { - methods[control_class.first] = control_class.second.method_handlers; + const auto& control_class = get_control_protocol_class(class_id); + auto& methods = control_class.method_handlers; + + auto method_found = methods.find(method_id); + if (methods.end() != method_found) + { + return method_found->second; + } + + class_id.pop_back(); } - return methods; + + return experimental::method_handler(nullptr); }; } diff --git a/Development/nmos/control_protocol_handlers.h b/Development/nmos/control_protocol_handlers.h index bab1904f4..a21277612 100644 --- a/Development/nmos/control_protocol_handlers.h +++ b/Development/nmos/control_protocol_handlers.h @@ -35,23 +35,27 @@ namespace nmos namespace experimental { // method handler defnition - typedef std::function method; + typedef std::function method_handler; // methods defnition - typedef std::map methods; // method_id vs method handler + typedef std::map methods; // method_id vs method handler } // callback to retrieve all the method handlers // this callback should not throw exceptions typedef std::function()> get_control_protocol_methods_handler; + // callback to retrieve a specific method handler + // this callback should not throw exceptions + typedef std::function get_control_protocol_method_handler; + // construct callback to retrieve a specific control protocol class get_control_protocol_class_handler make_get_control_protocol_class_handler(experimental::control_protocol_state& control_protocol_state); // construct callback to retrieve a specific datatype get_control_protocol_datatype_handler make_get_control_protocol_datatype_handler(experimental::control_protocol_state& control_protocol_state); - // construct callback to retrieve all method handlers - get_control_protocol_methods_handler make_get_control_protocol_methods_handler(experimental::control_protocol_state& control_protocol_state); + // construct callback to retrieve a specific method handler + get_control_protocol_method_handler make_get_control_protocol_method_handler(experimental::control_protocol_state& control_protocol_state); // a control_protocol_connection_activation_handler is a notification that the active parameters for the specified (IS-05) sender/connection_sender or receiver/connection_receiver have changed // this callback should not throw exceptions diff --git a/Development/nmos/control_protocol_state.cpp b/Development/nmos/control_protocol_state.cpp index 5ab2ccc32..60661b966 100644 --- a/Development/nmos/control_protocol_state.cpp +++ b/Development/nmos/control_protocol_state.cpp @@ -11,10 +11,10 @@ namespace nmos { // create control class // where - // properties: vector of NcPropertyDescriptor which can be constructed using make_control_class_property - // methods: vector of NcMethodDescriptor which can be constructed using make_nc_method_descriptor and the assoicated method handler + // properties: vector of NcPropertyDescriptor can be constructed using make_control_class_property + // methods: vector of NcMethodDescriptor can be constructed using make_nc_method_descriptor and the assoicated method handler // events: vector of NcEventDescriptor can be constructed using make_nc_event_descriptor - control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const web::json::value& fixed_role, const std::vector& properties_, const std::vector>& methods_, const std::vector& events_) + control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const web::json::value& fixed_role, const std::vector& properties_, const std::vector>& methods_, const std::vector& events_) { using web::json::value; @@ -38,7 +38,7 @@ namespace nmos // properties: vector of NcPropertyDescriptor which can be constructed using make_control_class_property // methods: vector of NcMethodDescriptor which can be constructed using make_nc_method_descriptor and the assoicated method handler // events: vector of NcEventDescriptor can be constructed using make_nc_event_descriptor - control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const utility::string_t& fixed_role, const std::vector& properties, const std::vector>& methods, const std::vector& events) + control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const utility::string_t& fixed_role, const std::vector& properties, const std::vector>& methods, const std::vector& events) { using web::json::value; @@ -49,7 +49,7 @@ namespace nmos // properties: vector of NcPropertyDescriptor which can be constructed using make_control_class_property // methods: vector of NcMethodDescriptor which can be constructed using make_nc_method_descriptor and the assoicated method handler // events: vector of NcEventDescriptor can be constructed using make_nc_event_descriptor - control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const std::vector& properties, const std::vector>& methods, const std::vector& events) + control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const std::vector& properties, const std::vector>& methods, const std::vector& events) { using web::json::value; @@ -100,7 +100,7 @@ namespace nmos auto to_methods_vector = [](const web::json::value& method_data_array, const nmos::experimental::methods& method_handlers) { - std::vector> methods; + std::vector> methods; if (!method_data_array.is_null()) { diff --git a/Development/nmos/control_protocol_state.h b/Development/nmos/control_protocol_state.h index b95c26e48..54431fca8 100644 --- a/Development/nmos/control_protocol_state.h +++ b/Development/nmos/control_protocol_state.h @@ -92,9 +92,9 @@ namespace nmos bool is_read_only = false, bool is_nullable = false, bool is_sequence = false, bool is_deprecated = false, const web::json::value& constraints = web::json::value::null()); // create control class with fixed role - control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const utility::string_t& fixed_role, const std::vector& properties = {}, const std::vector>& methods = {}, const std::vector& events = {}); + control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const utility::string_t& fixed_role, const std::vector& properties = {}, const std::vector>& methods = {}, const std::vector& events = {}); // create control class with no fixed role - control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const std::vector& properties = {}, const std::vector>& methods = {}, const std::vector& events = {}); + control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const std::vector& properties = {}, const std::vector>& methods = {}, const std::vector& events = {}); } } diff --git a/Development/nmos/control_protocol_ws_api.cpp b/Development/nmos/control_protocol_ws_api.cpp index 26948a8c9..beb54823d 100644 --- a/Development/nmos/control_protocol_ws_api.cpp +++ b/Development/nmos/control_protocol_ws_api.cpp @@ -45,29 +45,6 @@ namespace nmos { controlprotocol_validator().validate(request_data, experimental::make_controlprotocolapi_subscription_message_schema_uri(version)); } - - nmos::experimental::method find_method(const nc_method_id& method_id, const nc_class_id& class_id_, const std::map& methods) - { - auto class_id = class_id_; - - while (!class_id.empty()) - { - auto class_id_methods_found = methods.find(class_id); - - if (methods.end() != class_id_methods_found) - { - auto& method_id_methods = class_id_methods_found->second; - auto method_found = method_id_methods.find(method_id); - if (method_id_methods.end() != method_found) - { - return method_found->second; - } - } - class_id.pop_back(); - } - - return nullptr; - } } // IS-12 Control Protocol WebSocket API @@ -206,14 +183,12 @@ namespace nmos }; } - web::websockets::experimental::listener::message_handler make_control_protocol_ws_message_handler(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::get_control_protocol_methods_handler get_control_protocol_methods, slog::base_gate& gate_) + web::websockets::experimental::listener::message_handler make_control_protocol_ws_message_handler(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::get_control_protocol_method_handler get_control_protocol_method, slog::base_gate& gate_) { using web::json::value; using web::json::value_of; - auto methods = get_control_protocol_methods(); - - return [&model, &websockets, get_control_protocol_class, get_control_protocol_datatype, methods, &gate_](const web::uri& connection_uri, const web::websockets::experimental::listener::connection_id& connection_id, const web::websockets::websocket_incoming_message& msg_) + return [&model, &websockets, get_control_protocol_class, get_control_protocol_datatype, get_control_protocol_method, &gate_](const web::uri& connection_uri, const web::websockets::experimental::listener::connection_id& connection_id, const web::websockets::websocket_incoming_message& msg_) { nmos::ws_api_gate gate(gate_, connection_uri); @@ -276,7 +251,7 @@ namespace nmos const auto& class_id = nmos::details::parse_nc_class_id(nmos::fields::nc::class_id(resource->data)); // find the relevent method handler to execute - auto method = details::find_method(method_id, class_id, methods); + auto method = get_control_protocol_method(class_id, method_id); if (method) { // execute the relevant method handler, then accumulating up their response to reponses diff --git a/Development/nmos/control_protocol_ws_api.h b/Development/nmos/control_protocol_ws_api.h index 7fb79a520..bbb686272 100644 --- a/Development/nmos/control_protocol_ws_api.h +++ b/Development/nmos/control_protocol_ws_api.h @@ -16,15 +16,15 @@ namespace nmos web::websockets::experimental::listener::validate_handler make_control_protocol_ws_validate_handler(nmos::node_model& model, slog::base_gate& gate); web::websockets::experimental::listener::open_handler make_control_protocol_ws_open_handler(nmos::node_model& model, nmos::websockets& websockets, slog::base_gate& gate); web::websockets::experimental::listener::close_handler make_control_protocol_ws_close_handler(nmos::node_model& model, nmos::websockets& websockets, slog::base_gate& gate); - web::websockets::experimental::listener::message_handler make_control_protocol_ws_message_handler(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::get_control_protocol_methods_handler get_control_protocol_methods, slog::base_gate& gate); + web::websockets::experimental::listener::message_handler make_control_protocol_ws_message_handler(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::get_control_protocol_method_handler get_control_protocol_method, slog::base_gate& gate); - inline web::websockets::experimental::listener::websocket_listener_handlers make_control_protocol_ws_api(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::get_control_protocol_methods_handler get_control_protocol_methods, slog::base_gate& gate) + inline web::websockets::experimental::listener::websocket_listener_handlers make_control_protocol_ws_api(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::get_control_protocol_method_handler get_control_protocol_method, slog::base_gate& gate) { return{ nmos::make_control_protocol_ws_validate_handler(model, gate), nmos::make_control_protocol_ws_open_handler(model, websockets, gate), nmos::make_control_protocol_ws_close_handler(model, websockets, gate), - nmos::make_control_protocol_ws_message_handler(model, websockets, get_control_protocol_class, get_control_protocol_datatype, get_control_protocol_methods, gate) + nmos::make_control_protocol_ws_message_handler(model, websockets, get_control_protocol_class, get_control_protocol_datatype, get_control_protocol_method, gate) }; } diff --git a/Development/nmos/node_server.cpp b/Development/nmos/node_server.cpp index ccc9d1e3f..babb2c045 100644 --- a/Development/nmos/node_server.cpp +++ b/Development/nmos/node_server.cpp @@ -75,7 +75,7 @@ namespace nmos { if (control_protocol_ws_port == events_ws_port) throw std::runtime_error("Same port used for events and control protocol websockets are not supported"); auto& control_protocol_ws_api = node_server.ws_handlers[{ {}, control_protocol_ws_port }]; - control_protocol_ws_api.first = nmos::make_control_protocol_ws_api(node_model, control_protocol_ws_api.second, node_implementation.get_control_protocol_class, node_implementation.get_control_protocol_datatype, node_implementation.get_control_protocol_methods, gate); + control_protocol_ws_api.first = nmos::make_control_protocol_ws_api(node_model, control_protocol_ws_api.second, node_implementation.get_control_protocol_class, node_implementation.get_control_protocol_datatype, node_implementation.get_control_protocol_method, gate); } // Set up the listeners for each HTTP API port diff --git a/Development/nmos/node_server.h b/Development/nmos/node_server.h index 95fdca058..a58b17e05 100644 --- a/Development/nmos/node_server.h +++ b/Development/nmos/node_server.h @@ -25,7 +25,7 @@ namespace nmos // underlying implementation into the server instance for the NMOS Node struct node_implementation { - node_implementation(nmos::load_server_certificates_handler load_server_certificates, nmos::load_dh_param_handler load_dh_param, nmos::load_ca_certificates_handler load_ca_certificates, nmos::system_global_handler system_changed, nmos::registration_handler registration_changed, nmos::transport_file_parser parse_transport_file, nmos::details::connection_resource_patch_validator validate_staged, nmos::connection_resource_auto_resolver resolve_auto, nmos::connection_sender_transportfile_setter set_transportfile, nmos::connection_activation_handler connection_activated, nmos::ocsp_response_handler get_ocsp_response, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::get_control_protocol_methods_handler get_control_protocol_methods) + node_implementation(nmos::load_server_certificates_handler load_server_certificates, nmos::load_dh_param_handler load_dh_param, nmos::load_ca_certificates_handler load_ca_certificates, nmos::system_global_handler system_changed, nmos::registration_handler registration_changed, nmos::transport_file_parser parse_transport_file, nmos::details::connection_resource_patch_validator validate_staged, nmos::connection_resource_auto_resolver resolve_auto, nmos::connection_sender_transportfile_setter set_transportfile, nmos::connection_activation_handler connection_activated, nmos::ocsp_response_handler get_ocsp_response, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::get_control_protocol_method_handler get_control_protocol_method) : load_server_certificates(std::move(load_server_certificates)) , load_dh_param(std::move(load_dh_param)) , load_ca_certificates(std::move(load_ca_certificates)) @@ -39,7 +39,7 @@ namespace nmos , get_ocsp_response(std::move(get_ocsp_response)) , get_control_protocol_class(std::move(get_control_protocol_class)) , get_control_protocol_datatype(std::move(get_control_protocol_datatype)) - , get_control_protocol_methods(std::move(get_control_protocol_methods)) + , get_control_protocol_method(std::move(get_control_protocol_method)) {} // use the default constructor and chaining member functions for fluent initialization @@ -63,7 +63,7 @@ namespace nmos node_implementation& on_get_ocsp_response(nmos::ocsp_response_handler get_ocsp_response) { this->get_ocsp_response = std::move(get_ocsp_response); return *this; } node_implementation& on_get_control_class(nmos::get_control_protocol_class_handler get_control_protocol_class) { this->get_control_protocol_class = std::move(get_control_protocol_class); return *this; } node_implementation& on_get_control_datatype(nmos::get_control_protocol_datatype_handler get_control_protocol_datatype) { this->get_control_protocol_datatype = std::move(get_control_protocol_datatype); return *this; } - node_implementation& on_get_control_protocol_methods(nmos::get_control_protocol_methods_handler get_control_protocol_methods) { this->get_control_protocol_methods = std::move(get_control_protocol_methods); return *this; } + node_implementation& on_get_control_protocol_method(nmos::get_control_protocol_method_handler get_control_protocol_method) { this->get_control_protocol_method = std::move(get_control_protocol_method); return *this; } // deprecated, use on_validate_connection_resource_patch node_implementation& on_validate_merged(nmos::details::connection_resource_patch_validator validate_merged) { return on_validate_connection_resource_patch(std::move(validate_merged)); } @@ -96,7 +96,7 @@ namespace nmos nmos::get_control_protocol_class_handler get_control_protocol_class; nmos::get_control_protocol_datatype_handler get_control_protocol_datatype; - nmos::get_control_protocol_methods_handler get_control_protocol_methods; + nmos::get_control_protocol_method_handler get_control_protocol_method; }; // Construct a server instance for an NMOS Node, implementing the IS-04 Node API, IS-05 Connection API, IS-07 Events API From f039f8f41a09a4377cafd91e40a86a1417ed56b2 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Wed, 8 Nov 2023 16:04:43 +0000 Subject: [PATCH 069/106] Remove un-used code and fix typo --- Development/nmos-cpp-node/node_implementation.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Development/nmos-cpp-node/node_implementation.cpp b/Development/nmos-cpp-node/node_implementation.cpp index 67360c8c8..31ad30004 100644 --- a/Development/nmos-cpp-node/node_implementation.cpp +++ b/Development/nmos-cpp-node/node_implementation.cpp @@ -980,9 +980,9 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr // Example control class properties std::vector example_control_properties = { nmos::experimental::make_control_class_property(U("Example enum property"), { 3, 1 }, enum_property, U("ExampleEnum")), - // create "Example string property" with level 1: property constraints, See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html + // create "Example string property" with level 1: property constraints, See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html nmos::experimental::make_control_class_property(U("Example string property"), { 3, 2 }, string_property, U("NcString"), false, false, false, false, nmos::details::make_nc_parameter_constraints_string(10)), - // create "Example numeric property" with level 1: property constraints, See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html + // create "Example numeric property" with level 1: property constraints, See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html nmos::experimental::make_control_class_property(U("Example numeric property"), { 3, 3 }, number_property, U("NcUint64"), false, false, false, false, nmos::details::make_nc_parameter_constraints_number(0, 1000, 1)), nmos::experimental::make_control_class_property(U("Example boolean property"), { 3, 4 }, boolean_property, U("NcBoolean")), nmos::experimental::make_control_class_property(U("Example object property"), { 3, 5 }, object_property, U("ExampleDataType")), @@ -1023,7 +1023,6 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr << boolean_arg(arguments); // example to do method arguments constraints validation - const auto string_example_argument_constraints = make_string_example_argument_constraints(); if (!nmos::constraints_validation(arguments.at(string_arg), make_string_example_argument_constraints()) || !nmos::constraints_validation(arguments.at(number_arg), make_number_example_argument_constraints())) { @@ -1120,7 +1119,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr // helper function to create Example control auto make_example_control = [&](nmos::nc_oid oid, nmos::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const value& touchpoints = value::null(), const value& runtime_property_constraints = value::null(), // level 2: runtime constraints. See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html - // use of make_nc_property_constraints_stringand make_nc_property_constraints_number to create runtime constraints + // use of make_nc_property_constraints_string and make_nc_property_constraints_number to create runtime constraints example_enum enum_property_ = example_enum::Undefined, const utility::string_t& string_property_ = U(""), uint64_t number_property_ = 0, From 98b4b5654056492fa9c47eb565c681d66cc625b1 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Wed, 8 Nov 2023 16:10:48 +0000 Subject: [PATCH 070/106] Test readonly on set_sequence_item and add_sequence_item --- Development/nmos/control_protocol_methods.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Development/nmos/control_protocol_methods.cpp b/Development/nmos/control_protocol_methods.cpp index de2dcba4b..04b891b69 100644 --- a/Development/nmos/control_protocol_methods.cpp +++ b/Development/nmos/control_protocol_methods.cpp @@ -143,6 +143,11 @@ namespace nmos const auto& property = find_property(property_id_, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), get_control_protocol_class); if (!property.is_null()) { + if (nmos::fields::nc::is_read_only(property)) + { + return make_control_protocol_message_response(handle, { nc_method_status::read_only }); + } + auto& data = resource->data.at(nmos::fields::nc::name(property)); if (!nmos::fields::nc::is_sequence(property) || data.is_null() || !data.is_array()) @@ -200,6 +205,11 @@ namespace nmos const auto& property = find_property(property_id_, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), get_control_protocol_class); if (!property.is_null()) { + if (nmos::fields::nc::is_read_only(property)) + { + return make_control_protocol_message_response(handle, { nc_method_status::read_only }); + } + if (!nmos::fields::nc::is_sequence(property)) { // property is not a sequence From b14afefb4c67b95908cf8cc3d4b9ffa78356ce28 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 14 Nov 2023 15:27:38 +0000 Subject: [PATCH 071/106] Enhance level 0 datatype constraints validation --- Development/nmos/control_protocol_methods.cpp | 6 +- Development/nmos/control_protocol_resource.h | 6 + Development/nmos/control_protocol_utils.cpp | 284 +++++-- Development/nmos/control_protocol_utils.h | 15 +- .../nmos/test/control_protocol_test.cpp | 741 +++++++++++++++++- 5 files changed, 934 insertions(+), 118 deletions(-) diff --git a/Development/nmos/control_protocol_methods.cpp b/Development/nmos/control_protocol_methods.cpp index 04b891b69..feba52442 100644 --- a/Development/nmos/control_protocol_methods.cpp +++ b/Development/nmos/control_protocol_methods.cpp @@ -64,7 +64,7 @@ namespace nmos // do constraints validation if (!val.is_null()) { - if (!constraints_validation(val, get_runtime_property_constraints(property_id_, resource->data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), get_datatype_constraints(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype))) + if (!constraints_validation(val, get_runtime_property_constraints(property_id_, resource->data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), { get_datatype_descriptor(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype), get_control_protocol_datatype })) { return make_control_protocol_message_response(handle, { nc_method_status::parameter_error }); } @@ -161,7 +161,7 @@ namespace nmos if (data.as_array().size() > (size_t)index) { // do constraints validation - if (!constraints_validation(val, get_runtime_property_constraints(property_id_, resource->data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), get_datatype_constraints(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype))) + if (!constraints_validation(val, get_runtime_property_constraints(property_id_, resource->data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), { get_datatype_descriptor(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype), get_control_protocol_datatype })) { return make_control_protocol_message_response(handle, { nc_method_status::parameter_error }); } @@ -223,7 +223,7 @@ namespace nmos const nc_id sequence_item_index = data.is_null() ? 0 : nc_id(data.as_array().size()); // do constraints validation - if (!constraints_validation(val, get_runtime_property_constraints(property_id_, resource->data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), get_datatype_constraints(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype))) + if (!constraints_validation(val, get_runtime_property_constraints(property_id_, resource->data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), { get_datatype_descriptor(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype), get_control_protocol_datatype })) { return make_control_protocol_message_response(handle, { nc_method_status::parameter_error }); } diff --git a/Development/nmos/control_protocol_resource.h b/Development/nmos/control_protocol_resource.h index 700f8e194..193e9a800 100644 --- a/Development/nmos/control_protocol_resource.h +++ b/Development/nmos/control_protocol_resource.h @@ -130,6 +130,9 @@ namespace nmos // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdatatypedescriptortypedef web::json::value make_nc_datatype_typedef(const utility::string_t& description, const nc_name& name, bool is_sequence, const utility::string_t& parent_type, const web::json::value& constraints); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncpropertyconstraints + web::json::value make_nc_property_constraints(const nc_property_id& property_id, const web::json::value& default_value); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncpropertyconstraintsnumber web::json::value make_nc_property_constraints_number(const nc_property_id& property_id, uint64_t default_value, uint64_t minimum, uint64_t maximum, uint64_t step); web::json::value make_nc_property_constraints_number(const nc_property_id& property_id, uint64_t minimum, uint64_t maximum, uint64_t step); @@ -140,6 +143,9 @@ namespace nmos web::json::value make_nc_property_constraints_string(const nc_property_id& property_id, uint32_t max_characters); web::json::value make_nc_property_constraints_string(const nc_property_id& property_id, const nc_regex& pattern); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraints + web::json::value make_nc_parameter_constraints(const web::json::value& default_value); + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsnumber web::json::value make_nc_parameter_constraints_number(uint64_t default_value, uint64_t minimum, uint64_t maximum, uint64_t step); web::json::value make_nc_parameter_constraints_number(uint64_t minimum, uint64_t maximum, uint64_t step); diff --git a/Development/nmos/control_protocol_utils.cpp b/Development/nmos/control_protocol_utils.cpp index e03c6697f..d1f2f933f 100644 --- a/Development/nmos/control_protocol_utils.cpp +++ b/Development/nmos/control_protocol_utils.cpp @@ -26,7 +26,7 @@ namespace nmos return control_class_id == class_id; } - // get the runtime property constraints of a given property_id + // get the runtime property constraints of a specific property_id web::json::value get_runtime_property_constraints(const nc_property_id& property_id, const web::json::value& runtime_property_constraints) { using web::json::value; @@ -48,20 +48,222 @@ namespace nmos return value::null(); } - // get the datatype property constraints of a given type_name - web::json::value get_datatype_constraints(const web::json::value& type_name, get_control_protocol_datatype_handler get_control_protocol_datatype) + // get the datatype descriptor of a specific type_name + web::json::value get_datatype_descriptor(const web::json::value& type_name, get_control_protocol_datatype_handler get_control_protocol_datatype) { using web::json::value; if (!type_name.is_null()) { - const auto& datatype = get_control_protocol_datatype(type_name.as_string()); - if (!datatype.descriptor.is_null()) // NcDatatypeDescriptor + return get_control_protocol_datatype(type_name.as_string()).descriptor; + } + return value::null(); + } + + // get the datatype property constraints of a specific type_name + web::json::value get_datatype_constraints(const web::json::value& type_name, get_control_protocol_datatype_handler get_control_protocol_datatype) + { + using web::json::value; + + // NcDatatypeDescriptor + const auto& datatype_descriptor = get_datatype_descriptor(type_name, get_control_protocol_datatype); + if (!datatype_descriptor.is_null()) + { + return nmos::fields::nc::constraints(datatype_descriptor); + } + return value::null(); + } + + // constraints validation + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsnumber + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsstring + bool constraints_validation(const web::json::value& value, const web::json::value& constraints) + { + // is numeric constraints + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsnumber + if (constraints.has_field(nmos::fields::nc::step) && !nmos::fields::nc::step(constraints).is_null()) + { + if (!value.is_integer()) { return false; } + + const auto step = nmos::fields::nc::step(constraints).as_double(); + if (step <= 0) { return false; } + + const auto value_double = value.as_double(); + if (constraints.has_field(nmos::fields::nc::minimum) && !nmos::fields::nc::minimum(constraints).is_null()) + { + auto min = nmos::fields::nc::minimum(constraints).as_double(); + if (0 != std::fmod(value_double - min, step)) { return false; } + } + else if (constraints.has_field(nmos::fields::nc::maximum) && !nmos::fields::nc::maximum(constraints).is_null()) + { + auto max = nmos::fields::nc::maximum(constraints).as_double(); + if (0 != std::fmod(max - value_double, step)) { return false; } + } + else { - return nmos::fields::nc::constraints(datatype.descriptor); + if (0 != std::fmod(value_double, step)) { return false; } } } - return value::null(); + if (constraints.has_field(nmos::fields::nc::minimum) && !nmos::fields::nc::minimum(constraints).is_null()) + { + if (!value.is_integer() || value.as_double() < nmos::fields::nc::minimum(constraints).as_double()) { return false; } + } + if (constraints.has_field(nmos::fields::nc::maximum) && !nmos::fields::nc::maximum(constraints).is_null()) + { + if (!value.is_integer() || value.as_double() > nmos::fields::nc::maximum(constraints).as_double()) { return false; } + } + + // is string constraints + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsstring + if (constraints.has_field(nmos::fields::nc::max_characters) && !constraints.at(nmos::fields::nc::max_characters).is_null()) + { + const auto max_characters = nmos::fields::nc::max_characters(constraints); + if (!value.is_string() || value.as_string().length() > max_characters) { return false; } + } + if (constraints.has_field(nmos::fields::nc::pattern) && !constraints.at(nmos::fields::nc::pattern).is_null()) + { + if (!value.is_string()) { return false; } + const auto value_string = utility::us2s(value.as_string()); + bst::regex pattern(utility::us2s(nmos::fields::nc::pattern(constraints))); + if (!bst::regex_match(value_string, pattern)) { return false; } + } + + // reaching here, no validation is required + return true; + } + + // level 0 datatype constraints validation + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html + bool datatype_constraints_validation(const web::json::value& data, const datatype_constraints_validation_parameters& params) + { + const auto& datatype_type = nmos::fields::nc::type(params.datatype_descriptor); + + auto is_int16 = [](int32_t value) + { + return value >= (std::numeric_limits::min)() + && value <= (std::numeric_limits::max)(); + }; + auto is_uint16 = [](uint32_t value) + { + return value >= (std::numeric_limits::min)() + && value <= (std::numeric_limits::max)(); + }; + auto is_float32 = [](double value) + { + return value >= (std::numeric_limits::min)() + && value <= (std::numeric_limits::max)(); + }; + + // do NcDatatypeDescriptorPrimitive constraints validation + if (nc_datatype_type::Primitive == datatype_type) + { + // hmm, for the primitive type, it should not have datatype constraints specified via the datatype_descriptor but just in case + const auto& datatype_constraints = nmos::fields::nc::constraints(params.datatype_descriptor); + if (!datatype_constraints.is_null()) { return constraints_validation(data, datatype_constraints); } + + // do primitive type constraints + const auto& name = nmos::fields::nc::name(params.datatype_descriptor); + if (U("NcBoolean") == name) { return data.is_boolean(); } + if (U("NcInt16") == name && data.is_number()) { return is_int16(data.as_number().to_int32()); } + if (U("NcInt32") == name && data.is_number()) { return data.as_number().is_int32(); } + if (U("NcInt64") == name && data.is_number()) { return data.as_number().is_int64(); } + if (U("NcUint16") == name && data.is_number()) { return is_uint16(data.as_number().to_uint32()); } + if (U("NcUint32") == name && data.is_number()) { return data.as_number().is_uint32(); } + if (U("NcUint64") == name && data.is_number()) { return data.as_number().is_uint64(); } + if (U("NcFloat32") == name && data.is_number()) { return is_float32(data.as_number().to_double()); } + if (U("NcFloat64") == name && data.is_number()) { return !data.as_number().is_integral(); } + if (U("NcString") == name) { return data.is_string(); } + + // invalid primitive type + return false; + } + + // do NcDatatypeDescriptorTypeDef constraints validation + if (nc_datatype_type::Typedef == datatype_type) + { + // do the datatype constraints specified via the datatype_descriptor if presented + const auto& datatype_constraints = nmos::fields::nc::constraints(params.datatype_descriptor); + if (!datatype_constraints.is_null()) { return constraints_validation(data, datatype_constraints); } + + // do parent typename constraints validation + const auto& type_name = params.datatype_descriptor.at(nmos::fields::nc::parent_type); // parent type_name + if (!datatype_constraints_validation(data, { details::get_datatype_descriptor(type_name, params.get_control_protocol_datatype), params.get_control_protocol_datatype })) { return false; } + } + + // do NcDatatypeDescriptorEnum constraints validation + if (nc_datatype_type::Enum == datatype_type) + { + const auto& items = nmos::fields::nc::items(params.datatype_descriptor); + return (items.end() != std::find_if(items.begin(), items.end(), [&](const web::json::value& nc_enum_item_descriptor) { return nmos::fields::nc::value(nc_enum_item_descriptor) == data; })); + } + + // do NcDatatypeDescriptorStruct constraints validation + if (nc_datatype_type::Struct == datatype_type) + { + const auto& fields = nmos::fields::nc::fields(params.datatype_descriptor); + // NcFieldDescriptor + for (const web::json::value& nc_field_descriptor : fields) + { + const auto& name = nmos::fields::nc::name(nc_field_descriptor); + // check is the specific element in value strurcture + if (!data.has_field(name)) { return false; } + + // check is the element is a nullable field + if (nmos::fields::nc::is_nullable(nc_field_descriptor) != data.is_null()) { return false; } + + // check is the element is a sequence field + if (nmos::fields::nc::is_sequence(nc_field_descriptor) != data.is_array()) { return false; } + + // check against field constraints if presented + const auto& constraints = nmos::fields::nc::constraints(nc_field_descriptor); + if (!constraints.is_null()) + { + auto value = data.at(name); + + if (value.is_array()) + { + for (const auto& val : value.as_array()) + { + // do field constraints validation + if (!constraints_validation(val, constraints)) { return false; } + } + } + else + { + // do field constraints validation + if (!constraints_validation(value, constraints)) { return false; } + } + } + else + { + // no field constraints, move to check the constraints of its typeName + const auto& type_name = nc_field_descriptor.at(nmos::fields::nc::type_name); + + if (!type_name.is_null()) + { + auto value = data.at(name); + + if (value.is_array()) + { + for (const auto& val : value.as_array()) + { + // do typename constraints validation + if (!datatype_constraints_validation(val, { details::get_datatype_descriptor(type_name, params.get_control_protocol_datatype), params.get_control_protocol_datatype })) { return false; } + } + } + else + { + // do typename constraints validation + if (!datatype_constraints_validation(value, { details::get_datatype_descriptor(type_name, params.get_control_protocol_datatype), params.get_control_protocol_datatype })) { return false; } + } + } + } + } + return true; + } + + // unsupport datatype_type, no validation is required + return true; } } @@ -338,77 +540,17 @@ namespace nmos }); } - // constraints validation - // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsnumber - // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsstring - bool constraints_validation(const web::json::value& value, const web::json::value& constraints) - { - // is numeric constraints - // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsnumber - if (constraints.has_field(nmos::fields::nc::step) && !nmos::fields::nc::step(constraints).is_null()) - { - if (!value.is_integer()) { return false; } - - const auto step = nmos::fields::nc::step(constraints).as_double(); - if (step <= 0) { return false; } - - const auto value_double = value.as_double(); - if (constraints.has_field(nmos::fields::nc::minimum) && !nmos::fields::nc::minimum(constraints).is_null()) - { - auto min = nmos::fields::nc::minimum(constraints).as_double(); - if (0 != std::fmod(value_double - min, step)) { return false; } - } - else if (constraints.has_field(nmos::fields::nc::maximum) && !nmos::fields::nc::maximum(constraints).is_null()) - { - auto max = nmos::fields::nc::maximum(constraints).as_double(); - if (0 != std::fmod(max - value_double, step)) { return false; } - } - else - { - if (0 != std::fmod(value_double, step)) { return false; } - } - } - if (constraints.has_field(nmos::fields::nc::minimum) && !nmos::fields::nc::minimum(constraints).is_null()) - { - if (!value.is_integer() || value.as_double() < nmos::fields::nc::minimum(constraints).as_double()) { return false; } - } - if (constraints.has_field(nmos::fields::nc::maximum) && !nmos::fields::nc::maximum(constraints).is_null()) - { - if (!value.is_integer() || value.as_double() > nmos::fields::nc::maximum(constraints).as_double()) { return false; } - } - - // is string constraints - // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsstring - if (constraints.has_field(nmos::fields::nc::max_characters) && !constraints.at(nmos::fields::nc::max_characters).is_null()) - { - const auto max_characters = nmos::fields::nc::max_characters(constraints); - if (!value.is_string() || value.as_string().length() > max_characters) { return false; } - } - if (constraints.has_field(nmos::fields::nc::pattern) && !constraints.at(nmos::fields::nc::pattern).is_null()) - { - if (!value.is_string()) { return false; } - const auto value_string = utility::us2s(value.as_string()); - bst::regex pattern(utility::us2s(nmos::fields::nc::pattern(constraints))); - if (!bst::regex_match(value_string, pattern)) { return false; } - } - - return true; - } - // multiple levels of constraints validation // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html - bool constraints_validation(const web::json::value& value, const web::json::value& runtime_property_constraints, const web::json::value& property_constraints, const web::json::value& datatype_constraints) + bool constraints_validation(const web::json::value& value, const web::json::value& runtime_property_constraints, const web::json::value& property_constraints, const datatype_constraints_validation_parameters& params) { // do level 2 runtime property constraints validation - if (!runtime_property_constraints.is_null()) { return constraints_validation(value, runtime_property_constraints); } + if (!runtime_property_constraints.is_null()) { return details::constraints_validation(value, runtime_property_constraints); } // do level 1 property constraints validation - if (!property_constraints.is_null()) { return constraints_validation(value, property_constraints); } + if (!property_constraints.is_null()) { return details::constraints_validation(value, property_constraints); } // do level 0 datatype constraints validation - if (!datatype_constraints.is_null()) { return constraints_validation(value, datatype_constraints); } - - // reaching here, no validation is required - return true; + return details::datatype_constraints_validation(value, params); } } diff --git a/Development/nmos/control_protocol_utils.h b/Development/nmos/control_protocol_utils.h index ec16841da..1718e01cc 100644 --- a/Development/nmos/control_protocol_utils.h +++ b/Development/nmos/control_protocol_utils.h @@ -13,6 +13,9 @@ namespace nmos // get the runtime property constraints of a given property_id web::json::value get_runtime_property_constraints(const nc_property_id& property_id, const web::json::value& runtime_property_constraints_list); + // get the datatype descriptor of a specific type_name + web::json::value get_datatype_descriptor(const web::json::value& type_name, get_control_protocol_datatype_handler get_control_protocol_datatype); + // get the datatype property constraints of a given type_name web::json::value get_datatype_constraints(const web::json::value& type_name, get_control_protocol_datatype_handler get_control_protocol_datatype); } @@ -57,14 +60,14 @@ namespace nmos // find the control protocol resource which is assoicated with the given IS-04/IS-05/IS-08 resource id resources::const_iterator find_control_protocol_resource(resources& resources, type type, const id& id); - // constraints validation - // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsnumber - // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsstring - bool constraints_validation(const web::json::value& value, const web::json::value& constraints); - + struct datatype_constraints_validation_parameters + { + web::json::value datatype_descriptor; + get_control_protocol_datatype_handler get_control_protocol_datatype; + }; // multiple levels of constraints validation // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html - bool constraints_validation(const web::json::value& value, const web::json::value& runtime_property_constraints, const web::json::value& property_constraints, const web::json::value& data_constraints); + bool constraints_validation(const web::json::value& value, const web::json::value& runtime_property_constraints, const web::json::value& property_constraints, const datatype_constraints_validation_parameters& params); } #endif diff --git a/Development/nmos/test/control_protocol_test.cpp b/Development/nmos/test/control_protocol_test.cpp index 1b8a4e5fe..7ffd6d59f 100644 --- a/Development/nmos/test/control_protocol_test.cpp +++ b/Development/nmos/test/control_protocol_test.cpp @@ -707,62 +707,727 @@ BST_TEST_CASE(testConstraints) using web::json::value; const nmos::nc_property_id property_string_id{ 100, 1 }; - const nmos::nc_property_id property_number_id{ 100, 2 }; + const nmos::nc_property_id property_int32_id{ 100, 2 }; const nmos::nc_property_id unknown_property_id{ 100, 3 }; + // constraints + + // runtime constraints const auto runtime_property_string_constraints = nmos::details::make_nc_property_constraints_string(property_string_id, 10, U("^[0-9]+$")); - const auto runtime_property_number_constraints = nmos::details::make_nc_property_constraints_number(property_number_id, 10, 1000, 1); + const auto runtime_property_int32_constraints = nmos::details::make_nc_property_constraints_number(property_int32_id, 10, 1000, 1); const auto runtime_property_constraints = value_of({ { runtime_property_string_constraints }, - { runtime_property_number_constraints } + { runtime_property_int32_constraints } }); + // propertry constraints const auto property_string_constraints = nmos::details::make_nc_parameter_constraints_string(5, U("^[a-z]+$")); - const auto property_number_constraints = nmos::details::make_nc_parameter_constraints_number(50, 500, 5); + const auto property_int32_constraints = nmos::details::make_nc_parameter_constraints_number(50, 500, 5); + // datatype constraints const auto datatype_string_constraints = nmos::details::make_nc_parameter_constraints_string(2, U("^[0-9a-z]+$")); - const auto datatype_number_constraints = nmos::details::make_nc_parameter_constraints_number(100, 250, 10); + const auto datatype_int32_constraints = nmos::details::make_nc_parameter_constraints_number(100, 250, 10); + + // datatypes + const auto no_constraints_bool_datatype = nmos::details::make_nc_datatype_typedef(U("No constraints boolean datatype"), U("NoConstraintsBoolean"), false, U("NcBoolean"), value::null()); + const auto no_constraints_int16_datatype = nmos::details::make_nc_datatype_typedef(U("No constraints int16 datatype"), U("NoConstraintsInt16"), false, U("NcInt16"), value::null()); + const auto no_constraints_int32_datatype = nmos::details::make_nc_datatype_typedef(U("No constraints int32 datatype"), U("NoConstraintsInt32"), false, U("NcInt32"), value::null()); + const auto no_constraints_int64_datatype = nmos::details::make_nc_datatype_typedef(U("No constraints int64 datatype"), U("NoConstraintsInt64"), false, U("NcInt64"), value::null()); + const auto no_constraints_uint16_datatype = nmos::details::make_nc_datatype_typedef(U("No constraints uint16 datatype"), U("NoConstraintsUint16"), false, U("NcUint16"), value::null()); + const auto no_constraints_uint32_datatype = nmos::details::make_nc_datatype_typedef(U("No constraints uint32 datatype"), U("NoConstraintsUint32"), false, U("NcUint32"), value::null()); + const auto no_constraints_uint64_datatype = nmos::details::make_nc_datatype_typedef(U("No constraints uint64 datatype"), U("NoConstraintsUint64"), false, U("NcUint64"), value::null()); + const auto no_constraints_float32_datatype = nmos::details::make_nc_datatype_typedef(U("No constraints float32 datatype"), U("NoConstraintsFloat32"), false, U("NcFloat32"), value::null()); + const auto no_constraints_float64_datatype = nmos::details::make_nc_datatype_typedef(U("No constraints float64 datatype"), U("NoConstraintsFloat64"), false, U("NcFloat64"), value::null()); + const auto no_constraints_string_datatype = nmos::details::make_nc_datatype_typedef(U("No constraints string datatype"), U("NoConstraintsString"), false, U("NcString"), value::null()); + const auto with_constraints_string_datatype = nmos::details::make_nc_datatype_typedef(U("With constraints string datatype"), U("WithConstraintsString"), false, U("NcString"), datatype_string_constraints); + const auto with_constraints_int32_datatype = nmos::details::make_nc_datatype_typedef(U("With constraints int32 datatype"), U("WithConstraintsInt32"), false, U("NcInt32"), datatype_int32_constraints); + + enum enum_value { foo, bar, baz }; + auto items = value::array(); + web::json::push_back(items, nmos::details::make_nc_enum_item_descriptor(U("foo"), U("foo"), enum_value::foo)); + web::json::push_back(items, nmos::details::make_nc_enum_item_descriptor(U("bar"), U("bar"), enum_value::bar)); + web::json::push_back(items, nmos::details::make_nc_enum_item_descriptor(U("baz"), U("baz"), enum_value::baz)); + const auto enum_datatype = nmos::details::make_nc_datatype_descriptor_enum(U("enum datatype"), U("enumDatatype"), items, value::null()); // no datatype constraints for enum datatype + + auto simple_struct_fields = value::array(); + web::json::push_back(simple_struct_fields, nmos::details::make_nc_field_descriptor(U("simple enum property example"), U("simpleEnumProperty"), U("enumDatatype"), false, false, value::null())); // no field constraints for enum field, as it is already described by its type + web::json::push_back(simple_struct_fields, nmos::details::make_nc_field_descriptor(U("simple string property example"), U("simpleStringProperty"), U("NcString"), false, false, datatype_string_constraints)); + web::json::push_back(simple_struct_fields, nmos::details::make_nc_field_descriptor(U("simple number property example"), U("simpleNumberProperty"), U("NcInt32"), false, false, datatype_int32_constraints)); + web::json::push_back(simple_struct_fields, nmos::details::make_nc_field_descriptor(U("simle boolean property example"), U("simpleBooleanProperty"), U("NcBoolean"), false, false, value::null())); // no field constraints for boolean field, as it is already described by its type + const auto simple_struct_datatype = nmos::details::make_nc_datatype_descriptor_struct(U("simple struct datatype"), U("simpleStructDatatype"), simple_struct_fields, value::null()); // no datatype constraints for struct datatype + + auto fields = value::array(); + web::json::push_back(fields, nmos::details::make_nc_field_descriptor(U("Enum property example"), U("enumProperty"), U("enumDatatype"), false, false, value::null())); // no field constraints for enum field, as it is already described by its type + web::json::push_back(fields, nmos::details::make_nc_field_descriptor(U("String property example"), U("stringProperty"), U("NcString"), false, false, datatype_string_constraints)); + web::json::push_back(fields, nmos::details::make_nc_field_descriptor(U("Number property example"), U("numberProperty"), U("NcInt32"), false, false, datatype_int32_constraints)); + web::json::push_back(fields, nmos::details::make_nc_field_descriptor(U("Boolean property example"), U("booleanProperty"), U("NcBoolean"), false, false, value::null())); // no field constraints for boolean field, as it is already described by its type + web::json::push_back(fields, nmos::details::make_nc_field_descriptor(U("Struct property example"), U("structProperty"), U("simpleStructDatatype"), false, false, value::null())); // no datatype constraints for struct datatype + web::json::push_back(fields, nmos::details::make_nc_field_descriptor(U("Sequence enum property example"), U("sequenceEnumProperty"), U("enumDatatype"), false, false, value::null())); // no field constraints for enum field, as it is already described by its type + web::json::push_back(fields, nmos::details::make_nc_field_descriptor(U("Sequence string property example"), U("sequenceStringProperty"), U("NcString"), false, false, datatype_string_constraints)); + web::json::push_back(fields, nmos::details::make_nc_field_descriptor(U("Sequence number property example"), U("sequenceNumberProperty"), U("NcInt32"), false, false, datatype_int32_constraints)); + web::json::push_back(fields, nmos::details::make_nc_field_descriptor(U("Sequence boolean property example"), U("sequenceBooleanProperty"), U("NcBoolean"), false, false, value::null())); // no field constraints for boolean field, as it is already described by its type + web::json::push_back(fields, nmos::details::make_nc_field_descriptor(U("Sequence struct property example"), U("sequenceStructProperty"), U("simpleStructDatatype"), false, false, value::null())); // no field constraints for struct field + const auto struct_datatype = nmos::details::make_nc_datatype_descriptor_struct(U("struct datatype"), U("structDatatype"), fields, value::null()); // no datatype constraints for struct datatype + + // setup datatypes in control_protocol_state + nmos::experimental::control_protocol_state control_protocol_state; + control_protocol_state.insert(nmos::experimental::datatype{ no_constraints_int16_datatype }); + control_protocol_state.insert(nmos::experimental::datatype{ no_constraints_int32_datatype }); + control_protocol_state.insert(nmos::experimental::datatype{ no_constraints_int64_datatype }); + control_protocol_state.insert(nmos::experimental::datatype{ no_constraints_uint16_datatype }); + control_protocol_state.insert(nmos::experimental::datatype{ no_constraints_uint32_datatype }); + control_protocol_state.insert(nmos::experimental::datatype{ no_constraints_uint64_datatype }); + control_protocol_state.insert(nmos::experimental::datatype{ no_constraints_string_datatype }); + control_protocol_state.insert(nmos::experimental::datatype{ with_constraints_int32_datatype }); + control_protocol_state.insert(nmos::experimental::datatype{ with_constraints_string_datatype }); + control_protocol_state.insert(nmos::experimental::datatype{ enum_datatype }); + control_protocol_state.insert(nmos::experimental::datatype{ simple_struct_datatype }); + control_protocol_state.insert(nmos::experimental::datatype{ struct_datatype }); // test get_runtime_property_constraints BST_REQUIRE_EQUAL(nmos::details::get_runtime_property_constraints(property_string_id, runtime_property_constraints), runtime_property_string_constraints); - BST_REQUIRE_EQUAL(nmos::details::get_runtime_property_constraints(property_number_id, runtime_property_constraints), runtime_property_number_constraints); + BST_REQUIRE_EQUAL(nmos::details::get_runtime_property_constraints(property_int32_id, runtime_property_constraints), runtime_property_int32_constraints); BST_REQUIRE_EQUAL(nmos::details::get_runtime_property_constraints(unknown_property_id, runtime_property_constraints), value::null()); // string property constraints validation - BST_REQUIRE(nmos::constraints_validation(value::string(U("1234567890")), runtime_property_string_constraints, property_string_constraints, datatype_string_constraints)); - BST_REQUIRE_EQUAL(nmos::constraints_validation(value::string(U("12345678901")), runtime_property_string_constraints, property_string_constraints, datatype_string_constraints), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(value::string(U("123456789A")), runtime_property_string_constraints, property_string_constraints, datatype_string_constraints), false); - BST_REQUIRE(nmos::constraints_validation(value::string(U("12345678901")), value::null(), value::null(), value::null())); - BST_REQUIRE(nmos::constraints_validation(value::string(U("123456789A")), value::null(), value::null(), value::null())); - - BST_REQUIRE(nmos::constraints_validation(value::string(U("abcde")), value::null(), property_string_constraints, datatype_string_constraints)); - BST_REQUIRE_EQUAL(nmos::constraints_validation(value::string(U("abcdef")), value::null(), property_string_constraints, datatype_string_constraints), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(value::string(U("abcd1")), value::null(), property_string_constraints, datatype_string_constraints), false); - BST_REQUIRE(nmos::constraints_validation(value::string(U("1a")), value::null(), value::null(), datatype_string_constraints)); - BST_REQUIRE_EQUAL(nmos::constraints_validation(value::string(U("1a2")), value::null(), value::null(), datatype_string_constraints), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(value::string(U("1*")), value::null(), value::null(), datatype_string_constraints), false); + // runtime property constraints validation + const nmos::datatype_constraints_validation_parameters with_constraints_string_constraints_validation_params{ with_constraints_string_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + BST_REQUIRE(nmos::constraints_validation(value::string(U("1234567890")), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params)); + BST_REQUIRE_EQUAL(nmos::constraints_validation(value::string(U("12345678901")), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(value::string(U("123456789A")), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params), false); + // property constraints validation + BST_REQUIRE(nmos::constraints_validation(value::string(U("abcde")), value::null(), property_string_constraints, with_constraints_string_constraints_validation_params)); + BST_REQUIRE_EQUAL(nmos::constraints_validation(value::string(U("abcdef")), value::null(), property_string_constraints, with_constraints_string_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(value::string(U("abcd1")), value::null(), property_string_constraints, with_constraints_string_constraints_validation_params), false); + // datatype constraints validation + BST_REQUIRE(nmos::constraints_validation(value::string(U("1a")), value::null(), value::null(), with_constraints_string_constraints_validation_params)); + BST_REQUIRE_EQUAL(nmos::constraints_validation(value::string(U("1a2")), value::null(), value::null(), with_constraints_string_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(value::string(U("1*")), value::null(), value::null(), with_constraints_string_constraints_validation_params), false); + const nmos::datatype_constraints_validation_parameters no_constraints_string_constraints_validation_params{ no_constraints_string_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + BST_REQUIRE(nmos::constraints_validation(value::string(U("1234567890-abcde-!\"£$%^&*()_+=")), value::null(), value::null(), no_constraints_string_constraints_validation_params)); // number property constraints validation - BST_REQUIRE(nmos::constraints_validation(10, runtime_property_number_constraints, property_number_constraints, datatype_number_constraints)); - BST_REQUIRE(nmos::constraints_validation(1000, runtime_property_number_constraints, property_number_constraints, datatype_number_constraints)); - BST_REQUIRE_EQUAL(nmos::constraints_validation(9, runtime_property_number_constraints, property_number_constraints, datatype_number_constraints), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(1001, runtime_property_number_constraints, property_number_constraints, datatype_number_constraints), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(0.5, runtime_property_number_constraints, property_number_constraints, datatype_number_constraints), false); - BST_REQUIRE(nmos::constraints_validation(9, value::null(), value::null(), value::null())); - BST_REQUIRE(nmos::constraints_validation(1001, value::null(), value::null(), value::null())); - BST_REQUIRE(nmos::constraints_validation(0.5, value::null(), value::null(), value::null())); - - BST_REQUIRE(nmos::constraints_validation(50, value::null(), property_number_constraints, datatype_number_constraints)); - BST_REQUIRE(nmos::constraints_validation(500, value::null(), property_number_constraints, datatype_number_constraints)); - BST_REQUIRE_EQUAL(nmos::constraints_validation(45, value::null(), property_number_constraints, datatype_number_constraints), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(505, value::null(), property_number_constraints, datatype_number_constraints), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(499, value::null(), property_number_constraints, datatype_number_constraints), false); - - BST_REQUIRE(nmos::constraints_validation(100, value::null(), value::null(), datatype_number_constraints)); - BST_REQUIRE(nmos::constraints_validation(250, value::null(), value::null(), datatype_number_constraints)); - BST_REQUIRE_EQUAL(nmos::constraints_validation(90, value::null(), value::null(), datatype_number_constraints), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(260, value::null(), value::null(), datatype_number_constraints), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(99, value::null(), value::null(), datatype_number_constraints), false); + + // runtime property constraints validation + const nmos::datatype_constraints_validation_parameters with_constraints_int32_constraints_validation_params{ with_constraints_int32_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + BST_REQUIRE(nmos::constraints_validation(10, runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params)); + BST_REQUIRE(nmos::constraints_validation(1000, runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params)); + BST_REQUIRE_EQUAL(nmos::constraints_validation(9, runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(1001, runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params), false); + // property constraints validation + BST_REQUIRE(nmos::constraints_validation(50, value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params)); + BST_REQUIRE(nmos::constraints_validation(500, value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params)); + BST_REQUIRE_EQUAL(nmos::constraints_validation(45, value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(505, value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(499, value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), false); + // datatype constraints validation + BST_REQUIRE(nmos::constraints_validation(100, value::null(), value::null(), with_constraints_int32_constraints_validation_params)); + BST_REQUIRE(nmos::constraints_validation(250, value::null(), value::null(), with_constraints_int32_constraints_validation_params)); + BST_REQUIRE_EQUAL(nmos::constraints_validation(90, value::null(), value::null(), with_constraints_int32_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(260, value::null(), value::null(), with_constraints_int32_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(99, value::null(), value::null(), with_constraints_int32_constraints_validation_params), false); + // int16 datatype constraints validation + const nmos::datatype_constraints_validation_parameters no_constraints_int16_constraints_validation_params{ no_constraints_int16_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + BST_REQUIRE_EQUAL(nmos::constraints_validation(int64_t(std::numeric_limits::min()) - 1, value::null(), value::null(), no_constraints_int16_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(int64_t(std::numeric_limits::max()) + 1, value::null(), value::null(), no_constraints_int16_constraints_validation_params), false); + BST_REQUIRE(nmos::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_int16_constraints_validation_params)); + BST_REQUIRE(nmos::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_int16_constraints_validation_params)); + // int32 datatype constraints validation + const nmos::datatype_constraints_validation_parameters no_constraints_int32_constraints_validation_params{ no_constraints_int32_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + BST_REQUIRE_EQUAL(nmos::constraints_validation(int64_t(std::numeric_limits::min()) - 1, value::null(), value::null(), no_constraints_int32_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(int64_t(std::numeric_limits::max()) + 1, value::null(), value::null(), no_constraints_int32_constraints_validation_params), false); + BST_REQUIRE(nmos::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_int32_constraints_validation_params)); + BST_REQUIRE(nmos::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_int32_constraints_validation_params)); + // int64 datatype constraints validation + const nmos::datatype_constraints_validation_parameters no_constraints_int64_constraints_validation_params{ no_constraints_int64_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + BST_REQUIRE_EQUAL(nmos::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_int64_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_int64_constraints_validation_params), false); + BST_REQUIRE(nmos::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_int64_constraints_validation_params)); + BST_REQUIRE(nmos::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_int64_constraints_validation_params)); + // uint16 datatype constraints validation + const nmos::datatype_constraints_validation_parameters no_constraints_uint16_constraints_validation_params{ no_constraints_uint16_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + BST_REQUIRE_EQUAL(nmos::constraints_validation(-1, value::null(), value::null(), no_constraints_uint16_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(uint64_t(std::numeric_limits::max()) + 1, value::null(), value::null(), no_constraints_uint16_constraints_validation_params), false); + BST_REQUIRE(nmos::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_uint16_constraints_validation_params)); + BST_REQUIRE(nmos::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_uint16_constraints_validation_params)); + // uint32 datatype constraints validation + const nmos::datatype_constraints_validation_parameters no_constraints_uint32_constraints_validation_params{ no_constraints_uint32_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + BST_REQUIRE_EQUAL(nmos::constraints_validation(-1, value::null(), value::null(), no_constraints_uint32_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(uint64_t(std::numeric_limits::max()) + 1, value::null(), value::null(), no_constraints_uint32_constraints_validation_params), false); + BST_REQUIRE(nmos::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_uint32_constraints_validation_params)); + BST_REQUIRE(nmos::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_uint32_constraints_validation_params)); + // uint64 datatype constraints validation + const nmos::datatype_constraints_validation_parameters no_constraints_uint64_constraints_validation_params{ no_constraints_uint64_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + BST_REQUIRE_EQUAL(nmos::constraints_validation(-1, value::null(), value::null(), no_constraints_uint64_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_int64_constraints_validation_params), false); + BST_REQUIRE(nmos::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_uint64_constraints_validation_params)); + BST_REQUIRE(nmos::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_uint64_constraints_validation_params)); + // float32 datatype constraints validation + const nmos::datatype_constraints_validation_parameters no_constraints_float32_constraints_validation_params{ no_constraints_float32_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + BST_REQUIRE_EQUAL(nmos::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_float32_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_float32_constraints_validation_params), false); + BST_REQUIRE(nmos::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_float32_constraints_validation_params)); + BST_REQUIRE(nmos::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_float32_constraints_validation_params)); + // float64 datatype constraints validation + const nmos::datatype_constraints_validation_parameters no_constraints_float64_constraints_validation_params{ no_constraints_float64_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + BST_REQUIRE_EQUAL(nmos::constraints_validation(1000, value::null(), value::null(), no_constraints_float64_constraints_validation_params), false); + BST_REQUIRE(nmos::constraints_validation(1000.0, value::null(), value::null(), no_constraints_float64_constraints_validation_params)); + BST_REQUIRE(nmos::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_float64_constraints_validation_params)); + BST_REQUIRE(nmos::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_float64_constraints_validation_params)); + // enum property datatype constraints validation + const nmos::datatype_constraints_validation_parameters enum_constraints_validation_params{ enum_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + BST_REQUIRE(nmos::constraints_validation(enum_value::foo, value::null(), value::null(), enum_constraints_validation_params)); + BST_REQUIRE_EQUAL(nmos::constraints_validation(4, value::null(), value::null(), enum_constraints_validation_params), false); + + // struct property datatype constraints validation + const auto good_struct = value_of({ + { U("enumProperty"), enum_value::baz }, + { U("stringProperty"), U("xy") }, + { U("numberProperty"), 100 }, + { U("booleanProperty"), true }, + { U("structProperty"), value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), true } + }) }, + { U("sequenceEnumProperty"), value_of({ enum_value::foo, enum_value::bar }) }, + { U("sequenceStringProperty"), value_of({ U("aa"), U("bb") }) }, + { U("sequenceNumberProperty"), value_of({ 100, 110 }) }, + { U("sequenceBooleanProperty"), value_of({ true, false }) }, + { U("sequenceStructProperty"), value_of({ + value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), true } + }), value_of({ + { U("simpleEnumProperty"), enum_value::foo }, + { U("simpleStringProperty"), U("ab") }, + { U("simpleNumberProperty"), 200 }, + { U("simpleBooleanProperty"), false } + }) }) } + }); + // missing field + const auto bad_struct1 = value_of({ + { U("stringProperty"), U("xy") }, + { U("numberProperty"), 100 }, + { U("booleanProperty"), true }, + { U("structProperty"), value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), true } + }) }, + { U("sequenceEnumProperty"), value_of({ enum_value::foo, enum_value::bar }) }, + { U("sequenceStringProperty"), value_of({ U("aa"), U("bb") }) }, + { U("sequenceNumberProperty"), value_of({ 100, 110 }) }, + { U("sequenceBooleanProperty"), value_of({ true, false }) }, + { U("sequenceStructProperty"), value_of({ + value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), true } + }), value_of({ + { U("simpleEnumProperty"), enum_value::foo }, + { U("simpleStringProperty"), U("ab") }, + { U("simpleNumberProperty"), 200 }, + { U("simpleBooleanProperty"), false } + }) }) } + }); + // invalid fields + const auto bad_struct2 = value_of({ + { U("enumProperty"), 3 }, // bad value + { U("stringProperty"), U("xy") }, + { U("numberProperty"), 100 }, + { U("booleanProperty"), true }, + { U("structProperty"), value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), true } + }) }, + { U("sequenceEnumProperty"), value_of({ enum_value::foo, enum_value::bar }) }, + { U("sequenceStringProperty"), value_of({ U("aa"), U("bb") }) }, + { U("sequenceNumberProperty"), value_of({ 100, 110 }) }, + { U("sequenceBooleanProperty"), value_of({ true, false }) }, + { U("sequenceStructProperty"), value_of({ + value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), true } + }), value_of({ + { U("simpleEnumProperty"), enum_value::foo }, + { U("simpleStringProperty"), U("ab") }, + { U("simpleNumberProperty"), 200 }, + { U("simpleBooleanProperty"), false } + }) }) } + }); + const auto bad_struct2_1 = value_of({ + { U("enumProperty"), enum_value::foo }, + { U("stringProperty"), U("xyz") }, // bad value + { U("numberProperty"), 100 }, + { U("booleanProperty"), true }, + { U("structProperty"), value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), true } + }) }, + { U("sequenceEnumProperty"), value_of({ enum_value::foo, enum_value::bar }) }, + { U("sequenceStringProperty"), value_of({ U("aa"), U("bb") }) }, + { U("sequenceNumberProperty"), value_of({ 100, 110 }) }, + { U("sequenceBooleanProperty"), value_of({ true, false }) }, + { U("sequenceStructProperty"), value_of({ + value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), true } + }), value_of({ + { U("simpleEnumProperty"), enum_value::foo }, + { U("simpleStringProperty"), U("ab") }, + { U("simpleNumberProperty"), 200 }, + { U("simpleBooleanProperty"), false } + }) }) } + }); + const auto bad_struct2_2 = value_of({ + { U("enumProperty"), enum_value::foo }, + { U("stringProperty"), U("x£") }, // bad value + { U("numberProperty"), 100 }, + { U("booleanProperty"), true }, + { U("structProperty"), value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), true } + }) }, + { U("sequenceEnumProperty"), value_of({ enum_value::foo, enum_value::bar }) }, + { U("sequenceStringProperty"), value_of({ U("aa"), U("bb") }) }, + { U("sequenceNumberProperty"), value_of({ 100, 110 }) }, + { U("sequenceBooleanProperty"), value_of({ true, false }) }, + { U("sequenceStructProperty"), value_of({ + value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), true } + }), value_of({ + { U("simpleEnumProperty"), enum_value::foo }, + { U("simpleStringProperty"), U("ab") }, + { U("simpleNumberProperty"), 200 }, + { U("simpleBooleanProperty"), false } + }) }) } + }); + const auto bad_struct2_3 = value_of({ + { U("enumProperty"), enum_value::foo }, + { U("stringProperty"), U("xy") }, + { U("numberProperty"), 99 }, // bad value + { U("booleanProperty"), true }, + { U("sequenceEnumProperty"), value_of({ enum_value::foo, enum_value::bar }) }, + { U("sequenceStringProperty"), value_of({ U("aa"), U("bb") }) }, + { U("sequenceNumberProperty"), value_of({ 100, 110 }) }, + { U("sequenceBooleanProperty"), value_of({ true, false }) }, + { U("sequenceStructProperty"), value_of({ + value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), true } + }), value_of({ + { U("simpleEnumProperty"), enum_value::foo }, + { U("simpleStringProperty"), U("ab") }, + { U("simpleNumberProperty"), 200 }, + { U("simpleBooleanProperty"), false } + }) }) } + }); + const auto bad_struct2_4 = value_of({ + { U("enumProperty"), enum_value::foo }, + { U("stringProperty"), U("xy") }, + { U("numberProperty"), 100 }, + { U("booleanProperty"), 0 }, // bad value + { U("structProperty"), value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), true } + }) }, + { U("sequenceEnumProperty"), value_of({ enum_value::foo, enum_value::bar }) }, + { U("sequenceStringProperty"), value_of({ U("aa"), U("bb") }) }, + { U("sequenceNumberProperty"), value_of({ 100, 110 }) }, + { U("sequenceBooleanProperty"), value_of({ true, false }) }, + { U("sequenceStructProperty"), value_of({ + value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), true } + }), value_of({ + { U("simpleEnumProperty"), enum_value::foo }, + { U("simpleStringProperty"), U("ab") }, + { U("simpleNumberProperty"), 200 }, + { U("simpleBooleanProperty"), false } + }) }) } + }); + const auto bad_struct2_5 = value_of({ + { U("enumProperty"), enum_value::foo }, + { U("stringProperty"), U("xy") }, + { U("numberProperty"), 100 }, + { U("booleanProperty"), true }, + { U("structProperty"), value_of({ + { U("simpleEnumProperty"), 3 }, // bad value + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), true } + }) }, + { U("sequenceEnumProperty"), value_of({ enum_value::foo, enum_value::bar }) }, + { U("sequenceStringProperty"), value_of({ U("aa"), U("bb") }) }, + { U("sequenceNumberProperty"), value_of({ 100, 110 }) }, + { U("sequenceBooleanProperty"), value_of({ true, false }) }, + { U("sequenceStructProperty"), value_of({ + value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), true } + }), value_of({ + { U("simpleEnumProperty"), enum_value::foo }, + { U("simpleStringProperty"), U("ab") }, + { U("simpleNumberProperty"), 200 }, + { U("simpleBooleanProperty"), false } + }) }) } + }); + const auto bad_struct2_5_1 = value_of({ + { U("enumProperty"), enum_value::foo }, + { U("stringProperty"), U("xy") }, + { U("numberProperty"), 100 }, + { U("booleanProperty"), true }, + { U("structProperty"), value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xyz") }, // bad value + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), true } + }) }, + { U("sequenceEnumProperty"), value_of({ enum_value::foo, enum_value::bar }) }, + { U("sequenceStringProperty"), value_of({ U("aa"), U("bb") }) }, + { U("sequenceNumberProperty"), value_of({ 100, 110 }) }, + { U("sequenceBooleanProperty"), value_of({ true, false }) }, + { U("sequenceStructProperty"), value_of({ + value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), true } + }), value_of({ + { U("simpleEnumProperty"), enum_value::foo }, + { U("simpleStringProperty"), U("ab") }, + { U("simpleNumberProperty"), 200 }, + { U("simpleBooleanProperty"), false } + }) }) } + }); + const auto bad_struct2_5_2 = value_of({ + { U("enumProperty"), enum_value::foo }, + { U("stringProperty"), U("xy") }, + { U("numberProperty"), 100 }, + { U("booleanProperty"), true }, + { U("structProperty"), value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 99 }, // bad value + { U("simpleBooleanProperty"), true } + }) }, + { U("sequenceEnumProperty"), value_of({ enum_value::foo, enum_value::bar }) }, + { U("sequenceStringProperty"), value_of({ U("aa"), U("bb") }) }, + { U("sequenceNumberProperty"), value_of({ 100, 110 }) }, + { U("sequenceBooleanProperty"), value_of({ true, false }) }, + { U("sequenceStructProperty"), value_of({ + value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), true } + }), value_of({ + { U("simpleEnumProperty"), enum_value::foo }, + { U("simpleStringProperty"), U("ab") }, + { U("simpleNumberProperty"), 200 }, + { U("simpleBooleanProperty"), false } + }) }) } + }); + const auto bad_struct2_5_3 = value_of({ + { U("enumProperty"), enum_value::foo }, + { U("stringProperty"), U("xy") }, + { U("numberProperty"), 100 }, + { U("booleanProperty"), true }, + { U("structProperty"), value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), 3 } // bad value + }) }, + { U("sequenceEnumProperty"), value_of({ enum_value::foo, enum_value::bar }) }, + { U("sequenceStringProperty"), value_of({ U("aa"), U("bb") }) }, + { U("sequenceNumberProperty"), value_of({ 100, 110 }) }, + { U("sequenceBooleanProperty"), value_of({ true, false }) }, + { U("sequenceStructProperty"), value_of({ + value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), true } + }), value_of({ + { U("simpleEnumProperty"), enum_value::foo }, + { U("simpleStringProperty"), U("ab") }, + { U("simpleNumberProperty"), 200 }, + { U("simpleBooleanProperty"), false } + }) }) } + }); + const auto bad_struct2_6 = value_of({ + { U("enumProperty"), enum_value::foo }, + { U("stringProperty"), U("xy") }, + { U("numberProperty"), 100 }, + { U("booleanProperty"), true }, + { U("structProperty"), value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), true } + }) }, + { U("sequenceEnumProperty"), value_of({ enum_value::foo, enum_value::bar, 4 }) }, // bad value + { U("sequenceStringProperty"), value_of({ U("aa"), U("bb") }) }, + { U("sequenceNumberProperty"), value_of({ 100, 110 }) }, + { U("sequenceBooleanProperty"), value_of({ true, false }) }, + { U("sequenceStructProperty"), value_of({ + value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), true } + }), value_of({ + { U("simpleEnumProperty"), enum_value::foo }, + { U("simpleStringProperty"), U("ab") }, + { U("simpleNumberProperty"), 200 }, + { U("simpleBooleanProperty"), false } + }) }) } + }); + const auto bad_struct2_6_1 = value_of({ + { U("enumProperty"), enum_value::foo }, + { U("stringProperty"), U("xy") }, + { U("numberProperty"), 100 }, + { U("booleanProperty"), true }, + { U("structProperty"), value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), true } + }) }, + { U("sequenceEnumProperty"), value_of({ enum_value::foo, enum_value::bar }) }, + { U("sequenceStringProperty"), value_of({ U("aa"), U("bbb") }) }, // bad value + { U("sequenceNumberProperty"), value_of({ 100, 110 }) }, + { U("sequenceBooleanProperty"), value_of({ true, false }) }, + { U("sequenceStructProperty"), value_of({ + value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), true } + }), value_of({ + { U("simpleEnumProperty"), enum_value::foo }, + { U("simpleStringProperty"), U("ab") }, + { U("simpleNumberProperty"), 200 }, + { U("simpleBooleanProperty"), false } + }) }) } + }); + const auto bad_struct2_6_2 = value_of({ + { U("enumProperty"), enum_value::foo }, + { U("stringProperty"), U("xy") }, + { U("numberProperty"), 100 }, + { U("booleanProperty"), true }, + { U("structProperty"), value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), true } + }) }, + { U("sequenceEnumProperty"), value_of({ enum_value::foo, enum_value::bar }) }, + { U("sequenceStringProperty"), value_of({ U("aa"), U("bb") }) }, + { U("sequenceNumberProperty"), value_of({ 99, 110 }) }, // bad value + { U("sequenceBooleanProperty"), value_of({ true, false }) }, + { U("sequenceStructProperty"), value_of({ + value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), true } + }), value_of({ + { U("simpleEnumProperty"), enum_value::foo }, + { U("simpleStringProperty"), U("ab") }, + { U("simpleNumberProperty"), 200 }, + { U("simpleBooleanProperty"), false } + }) }) } + }); + const auto bad_struct2_6_3 = value_of({ + { U("enumProperty"), enum_value::foo }, + { U("stringProperty"), U("xy") }, + { U("numberProperty"), 100 }, + { U("booleanProperty"), true }, + { U("structProperty"), value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), true } + }) }, + { U("sequenceEnumProperty"), value_of({ enum_value::foo, enum_value::bar }) }, + { U("sequenceStringProperty"), value_of({ U("aa"), U("bb") }) }, + { U("sequenceNumberProperty"), value_of({ 100, 110 }) }, + { U("sequenceBooleanProperty"), value_of({ true, 0 }) }, // bad value + { U("sequenceStructProperty"), value_of({ + value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), true } + }), value_of({ + { U("simpleEnumProperty"), enum_value::foo }, + { U("simpleStringProperty"), U("ab") }, + { U("simpleNumberProperty"), 200 }, + { U("simpleBooleanProperty"), false } + }) }) } + }); + const auto bad_struct2_7 = value_of({ + { U("enumProperty"), enum_value::foo }, + { U("stringProperty"), U("xy") }, + { U("numberProperty"), 100 }, + { U("booleanProperty"), true }, + { U("structProperty"), value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), true } + }) }, + { U("sequenceEnumProperty"), value_of({ enum_value::foo, enum_value::bar }) }, + { U("sequenceStringProperty"), value_of({ U("aa"), U("bb") }) }, + { U("sequenceNumberProperty"), value_of({ 100, 110 }) }, + { U("sequenceBooleanProperty"), value_of({ true, false }) }, + { U("sequenceStructProperty"), value_of({ + value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), true } + }), value_of({ + { U("simpleEnumProperty"), 3 }, // bad value + { U("simpleStringProperty"), U("ab") }, + { U("simpleNumberProperty"), 200 }, + { U("simpleBooleanProperty"), false } + }) }) } + }); + const auto bad_struct2_7_1 = value_of({ + { U("enumProperty"), enum_value::foo }, + { U("stringProperty"), U("xy") }, + { U("numberProperty"), 100 }, + { U("booleanProperty"), true }, + { U("structProperty"), value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), true } + }) }, + { U("sequenceEnumProperty"), value_of({ enum_value::foo, enum_value::bar }) }, + { U("sequenceStringProperty"), value_of({ U("aa"), U("bb") }) }, + { U("sequenceNumberProperty"), value_of({ 100, 110 }) }, + { U("sequenceBooleanProperty"), value_of({ true, false }) }, + { U("sequenceStructProperty"), value_of({ + value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), true } + }), value_of({ + { U("simpleEnumProperty"), enum_value::foo }, + { U("simpleStringProperty"), U("abc") }, // bad value + { U("simpleNumberProperty"), 200 }, + { U("simpleBooleanProperty"), false } + }) }) } + }); + const auto bad_struct2_7_2 = value_of({ + { U("enumProperty"), enum_value::foo }, + { U("stringProperty"), U("xy") }, + { U("numberProperty"), 100 }, + { U("booleanProperty"), true }, + { U("structProperty"), value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), true } + }) }, + { U("sequenceEnumProperty"), value_of({ enum_value::foo, enum_value::bar }) }, + { U("sequenceStringProperty"), value_of({ U("aa"), U("bb") }) }, + { U("sequenceNumberProperty"), value_of({ 100, 110 }) }, + { U("sequenceBooleanProperty"), value_of({ true, false }) }, + { U("sequenceStructProperty"), value_of({ + value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), true } + }), value_of({ + { U("simpleEnumProperty"), enum_value::foo }, + { U("simpleStringProperty"), U("ab") }, + { U("simpleNumberProperty"), 251 }, // bad value + { U("simpleBooleanProperty"), false } + }) }) } + }); + const auto bad_struct2_7_3 = value_of({ + { U("enumProperty"), enum_value::foo }, + { U("stringProperty"), U("xy") }, + { U("numberProperty"), 100 }, + { U("booleanProperty"), true }, + { U("structProperty"), value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), true } + }) }, + { U("sequenceEnumProperty"), value_of({ enum_value::foo, enum_value::bar }) }, + { U("sequenceStringProperty"), value_of({ U("aa"), U("bb") }) }, + { U("sequenceNumberProperty"), value_of({ 100, 110 }) }, + { U("sequenceBooleanProperty"), value_of({ true, false }) }, + { U("sequenceStructProperty"), value_of({ + value_of({ + { U("simpleEnumProperty"), enum_value::bar }, + { U("simpleStringProperty"), U("xy") }, + { U("simpleNumberProperty"), 100 }, + { U("simpleBooleanProperty"), true } + }), value_of({ + { U("simpleEnumProperty"), enum_value::foo }, + { U("simpleStringProperty"), U("ab") }, + { U("simpleNumberProperty"), 200 }, + { U("simpleBooleanProperty"), 0 } // bad value + }) }) } + }); + + const nmos::datatype_constraints_validation_parameters struct_constraints_validation_params{ struct_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + BST_REQUIRE(nmos::constraints_validation(good_struct, value::null(), value::null(), struct_constraints_validation_params)); + BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct1, value::null(), value::null(), struct_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct2, value::null(), value::null(), struct_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct2_1, value::null(), value::null(), struct_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct2_2, value::null(), value::null(), struct_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct2_3, value::null(), value::null(), struct_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct2_4, value::null(), value::null(), struct_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct2_5, value::null(), value::null(), struct_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct2_5_1, value::null(), value::null(), struct_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct2_5_2, value::null(), value::null(), struct_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct2_5_3, value::null(), value::null(), struct_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct2_6, value::null(), value::null(), struct_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct2_6_1, value::null(), value::null(), struct_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct2_6_2, value::null(), value::null(), struct_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct2_6_3, value::null(), value::null(), struct_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct2_7, value::null(), value::null(), struct_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct2_7_1, value::null(), value::null(), struct_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct2_7_2, value::null(), value::null(), struct_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct2_7_3, value::null(), value::null(), struct_constraints_validation_params), false); } From 0049eaa764a824972e118a24b5191822346bac1f Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 14 Nov 2023 15:30:49 +0000 Subject: [PATCH 072/106] Return property_deprecated(298) if property is marked as deprecated --- Development/nmos/control_protocol_methods.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Development/nmos/control_protocol_methods.cpp b/Development/nmos/control_protocol_methods.cpp index feba52442..c1426a3ab 100644 --- a/Development/nmos/control_protocol_methods.cpp +++ b/Development/nmos/control_protocol_methods.cpp @@ -26,7 +26,7 @@ namespace nmos const auto& property = find_property(parse_nc_property_id(property_id), parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), get_control_protocol_class); if (!property.is_null()) { - return make_control_protocol_message_response(handle, { nc_method_status::ok }, resource->data.at(nmos::fields::nc::name(property))); + return make_control_protocol_message_response(handle, { nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }, resource->data.at(nmos::fields::nc::name(property))); } // unknown property @@ -77,7 +77,7 @@ namespace nmos }, make_propertry_changed_event(nmos::fields::nc::oid(resource->data), { { property_id_, nc_property_change_type::type::value_changed, val } })); - return make_control_protocol_message_response(handle, { nc_method_status::ok }); + return make_control_protocol_message_response(handle, { nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }); } // unknown property @@ -112,7 +112,7 @@ namespace nmos if (data.as_array().size() > (size_t)index) { - return make_control_protocol_message_response(handle, { nc_method_status::ok }, data.at(index)); + return make_control_protocol_message_response(handle, { nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }, data.at(index)); } // out of bound @@ -173,7 +173,7 @@ namespace nmos }, make_propertry_changed_event(nmos::fields::nc::oid(resource->data), { { property_id_, nc_property_change_type::type::sequence_item_changed, val, nc_id(index) } })); - return make_control_protocol_message_response(handle, { nc_method_status::ok }); + return make_control_protocol_message_response(handle, { nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }); } // out of bound @@ -237,7 +237,7 @@ namespace nmos }, make_propertry_changed_event(nmos::fields::nc::oid(resource->data), { { property_id_, nc_property_change_type::type::sequence_item_added, val, sequence_item_index } })); - return make_control_protocol_message_response(handle, { nc_method_status::ok }, sequence_item_index); + return make_control_protocol_message_response(handle, { nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }, sequence_item_index); } // unknown property @@ -279,7 +279,7 @@ namespace nmos }, make_propertry_changed_event(nmos::fields::nc::oid(resource->data), { { parse_nc_property_id(property_id), nc_property_change_type::type::sequence_item_removed, nc_id(index) } })); - return make_control_protocol_message_response(handle, { nc_method_status::ok }); + return make_control_protocol_message_response(handle, { nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }); } // out of bound @@ -325,7 +325,7 @@ namespace nmos if (data.is_null()) { // null - return make_control_protocol_message_response(handle, { nc_method_status::ok }, value::null()); + return make_control_protocol_message_response(handle, { nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }, value::null()); } } else From cf492a4d2265b145e9a90d76fae5363363637ad0 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 14 Nov 2023 18:49:12 +0000 Subject: [PATCH 073/106] Code tidy-up --- Development/nmos/control_protocol_methods.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Development/nmos/control_protocol_methods.cpp b/Development/nmos/control_protocol_methods.cpp index c1426a3ab..c5f53037f 100644 --- a/Development/nmos/control_protocol_methods.cpp +++ b/Development/nmos/control_protocol_methods.cpp @@ -64,7 +64,7 @@ namespace nmos // do constraints validation if (!val.is_null()) { - if (!constraints_validation(val, get_runtime_property_constraints(property_id_, resource->data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), { get_datatype_descriptor(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype), get_control_protocol_datatype })) + if (!nmos::constraints_validation(val, get_runtime_property_constraints(property_id_, resource->data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), { get_datatype_descriptor(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype), get_control_protocol_datatype })) { return make_control_protocol_message_response(handle, { nc_method_status::parameter_error }); } @@ -100,7 +100,7 @@ namespace nmos const auto& property = find_property(parse_nc_property_id(property_id), parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), get_control_protocol_class); if (!property.is_null()) { - auto& data = resource->data.at(nmos::fields::nc::name(property)); + const auto& data = resource->data.at(nmos::fields::nc::name(property)); if (!nmos::fields::nc::is_sequence(property) || data.is_null() || !data.is_array()) { @@ -161,7 +161,7 @@ namespace nmos if (data.as_array().size() > (size_t)index) { // do constraints validation - if (!constraints_validation(val, get_runtime_property_constraints(property_id_, resource->data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), { get_datatype_descriptor(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype), get_control_protocol_datatype })) + if (!nmos::constraints_validation(val, get_runtime_property_constraints(property_id_, resource->data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), { get_datatype_descriptor(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype), get_control_protocol_datatype })) { return make_control_protocol_message_response(handle, { nc_method_status::parameter_error }); } @@ -223,7 +223,7 @@ namespace nmos const nc_id sequence_item_index = data.is_null() ? 0 : nc_id(data.as_array().size()); // do constraints validation - if (!constraints_validation(val, get_runtime_property_constraints(property_id_, resource->data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), { get_datatype_descriptor(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype), get_control_protocol_datatype })) + if (!nmos::constraints_validation(val, get_runtime_property_constraints(property_id_, resource->data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), { get_datatype_descriptor(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype), get_control_protocol_datatype })) { return make_control_protocol_message_response(handle, { nc_method_status::parameter_error }); } @@ -260,7 +260,7 @@ namespace nmos const auto& property = find_property(parse_nc_property_id(property_id), parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), get_control_protocol_class); if (!property.is_null()) { - auto& data = resource->data.at(nmos::fields::nc::name(property)); + const auto& data = resource->data.at(nmos::fields::nc::name(property)); if (!nmos::fields::nc::is_sequence(property) || data.is_null() || !data.is_array()) { @@ -317,7 +317,7 @@ namespace nmos return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); } - auto& data = resource->data.at(nmos::fields::nc::name(property)); + const auto& data = resource->data.at(nmos::fields::nc::name(property)); if (nmos::fields::nc::is_nullable(property)) { From 93f69c2325cd6a67d5c40bc63bb0d7d15477c3c6 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 14 Nov 2023 19:34:56 +0000 Subject: [PATCH 074/106] Enhance non-standard example control method handlers, add level 2 and level 0 constraints implementation to example control --- .../nmos-cpp-node/node_implementation.cpp | 92 +++++++++++++------ 1 file changed, 63 insertions(+), 29 deletions(-) diff --git a/Development/nmos-cpp-node/node_implementation.cpp b/Development/nmos-cpp-node/node_implementation.cpp index 31ad30004..f582d239d 100644 --- a/Development/nmos-cpp-node/node_implementation.cpp +++ b/Development/nmos-cpp-node/node_implementation.cpp @@ -977,13 +977,19 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr Gamma = 3 }; { + // following constraints are used for the example control class level 0 datatype, level 1 property constraints and the method parameters constraints + auto make_string_example_argument_constraints = []() {return nmos::details::make_nc_parameter_constraints_string(10, U("^[a-z]+$")); }; + auto make_number_example_argument_constraints = []() {return nmos::details::make_nc_parameter_constraints_number(0, 1000, 1); }; + // Example control class properties std::vector example_control_properties = { nmos::experimental::make_control_class_property(U("Example enum property"), { 3, 1 }, enum_property, U("ExampleEnum")), // create "Example string property" with level 1: property constraints, See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html - nmos::experimental::make_control_class_property(U("Example string property"), { 3, 2 }, string_property, U("NcString"), false, false, false, false, nmos::details::make_nc_parameter_constraints_string(10)), + // use nmos::details::make_nc_parameter_constraints_string to create datatype constraints + nmos::experimental::make_control_class_property(U("Example string property"), { 3, 2 }, string_property, U("NcString"), false, false, false, false, make_string_example_argument_constraints()), // create "Example numeric property" with level 1: property constraints, See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html - nmos::experimental::make_control_class_property(U("Example numeric property"), { 3, 3 }, number_property, U("NcUint64"), false, false, false, false, nmos::details::make_nc_parameter_constraints_number(0, 1000, 1)), + // use nmos::details::make_nc_parameter_constraints_number to create datatype constraints + nmos::experimental::make_control_class_property(U("Example numeric property"), { 3, 3 }, number_property, U("NcUint64"), false, false, false, false, make_number_example_argument_constraints()), nmos::experimental::make_control_class_property(U("Example boolean property"), { 3, 4 }, boolean_property, U("NcBoolean")), nmos::experimental::make_control_class_property(U("Example object property"), { 3, 5 }, object_property, U("ExampleDataType")), nmos::experimental::make_control_class_property(U("Method no args invoke counter"), { 3, 6 }, method_no_args_count, U("NcUint64"), true), @@ -996,10 +1002,6 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr nmos::experimental::make_control_class_property(U("Example object sequence property"), { 3, 13 }, object_sequence, U("ExampleDataType"), false, false, true) }; - // Example control class method handlers - auto make_string_example_argument_constraints = []() {return nmos::details::make_nc_parameter_constraints_string(80); }; - auto make_number_example_argument_constraints = []() {return nmos::details::make_nc_parameter_constraints_number(100, 1000, 1); }; - auto example_method_with_no_args = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -1012,32 +1014,64 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - slog::log(gate, SLOG_FLF) << "Executing the example method with simple arguments:" - << " enum_arg: " - << enum_arg(arguments).to_int32() - << " string_arg: " - << string_arg(arguments) - << " number_arg: " - << number_arg(arguments).to_uint64() - << " boolean_arg: " - << boolean_arg(arguments); + using web::json::value; + + slog::log(gate, SLOG_FLF) << "Executing the example method with simple arguments: " << arguments.serialize(); // example to do method arguments constraints validation - if (!nmos::constraints_validation(arguments.at(string_arg), make_string_example_argument_constraints()) - || !nmos::constraints_validation(arguments.at(number_arg), make_number_example_argument_constraints())) + if (!nmos::constraints_validation(arguments.at(enum_arg), value::null(), value::null(), { nmos::details::get_datatype_descriptor(value::string(U("ExampleEnum")), get_control_protocol_datatype), get_control_protocol_datatype })) { + slog::log(gate, SLOG_FLF) << "invalid enum_arg: " << arguments.at(enum_arg).serialize(); + return nmos::make_control_protocol_message_response(handle, { nmos::nc_method_status::parameter_error }); + } + if (!nmos::constraints_validation(arguments.at(string_arg), make_string_example_argument_constraints(), value::null(), {nmos::details::get_datatype_descriptor(value::string(U("NcString")), get_control_protocol_datatype), get_control_protocol_datatype})) + { + slog::log(gate, SLOG_FLF) << "invalid string_arg: " << arguments.at(string_arg).serialize(); + return nmos::make_control_protocol_message_response(handle, { nmos::nc_method_status::parameter_error }); + } + if (!nmos::constraints_validation(arguments.at(number_arg), make_number_example_argument_constraints(), value::null(), { nmos::details::get_datatype_descriptor(value::string(U("NcUint64")), get_control_protocol_datatype), get_control_protocol_datatype })) + { + slog::log(gate, SLOG_FLF) << "invalid number_arg: " << arguments.at(number_arg).serialize(); + return nmos::make_control_protocol_message_response(handle, { nmos::nc_method_status::parameter_error }); + } + if (!nmos::constraints_validation(arguments.at(boolean_arg), value::null(), value::null(), { nmos::details::get_datatype_descriptor(value::string(U("NcBoolean")), get_control_protocol_datatype), get_control_protocol_datatype })) + { + slog::log(gate, SLOG_FLF) << "invalid boolean_arg: " << arguments.at(boolean_arg).serialize(); return nmos::make_control_protocol_message_response(handle, { nmos::nc_method_status::parameter_error }); } return nmos::make_control_protocol_message_response(handle, { nmos::nc_method_status::ok }); }; - auto example_method_with_object_args = [obj_arg](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) + auto example_method_with_object_args = [obj_arg, enum_arg, string_arg, number_arg, boolean_arg, make_string_example_argument_constraints, make_number_example_argument_constraints](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - slog::log(gate, SLOG_FLF) << "Executing the example method with object argument:" - << " obj_arg: " - << obj_arg(arguments).serialize(); + using web::json::value; + + slog::log(gate, SLOG_FLF) << "Executing the example method with object argument: " << obj_arg(arguments).serialize(); + + // example to do method arguments constraints validation + const auto& obj_arg_ = obj_arg(arguments); + if (!nmos::constraints_validation(obj_arg_.at(enum_arg), value::null(), value::null(), { nmos::details::get_datatype_descriptor(value::string(U("ExampleEnum")), get_control_protocol_datatype), get_control_protocol_datatype })) + { + slog::log(gate, SLOG_FLF) << "invalid enum_arg: " << obj_arg_.at(enum_arg).serialize(); + return nmos::make_control_protocol_message_response(handle, { nmos::nc_method_status::parameter_error }); + } + if (!nmos::constraints_validation(obj_arg_.at(string_arg), make_string_example_argument_constraints(), value::null(), { nmos::details::get_datatype_descriptor(value::string(U("NcString")), get_control_protocol_datatype), get_control_protocol_datatype })) + { + slog::log(gate, SLOG_FLF) << "invalid string_arg: " << obj_arg_.at(string_arg).serialize(); + return nmos::make_control_protocol_message_response(handle, { nmos::nc_method_status::parameter_error }); + } + if (!nmos::constraints_validation(obj_arg_.at(number_arg), make_number_example_argument_constraints(), value::null(), { nmos::details::get_datatype_descriptor(value::string(U("NcUint64")), get_control_protocol_datatype), get_control_protocol_datatype })) + { + slog::log(gate, SLOG_FLF) << "invalid number_arg: " << obj_arg_.at(number_arg).serialize(); + return nmos::make_control_protocol_message_response(handle, { nmos::nc_method_status::parameter_error }); + } + if (!nmos::constraints_validation(obj_arg_.at(boolean_arg), value::null(), value::null(), { nmos::details::get_datatype_descriptor(value::string(U("NcBoolean")), get_control_protocol_datatype), get_control_protocol_datatype })) + { + slog::log(gate, SLOG_FLF) << "invalid boolean_arg: " << obj_arg_.at(boolean_arg).serialize(); + return nmos::make_control_protocol_message_response(handle, { nmos::nc_method_status::parameter_error }); + } return nmos::make_control_protocol_message_response(handle, { nmos::nc_method_status::ok }); }; @@ -1089,13 +1123,13 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr { // level 0: datatype constraints, See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html // use nmos::details::make_nc_parameter_constraints_string to create datatype constraints - value datatype_constraints = value::null(); + value datatype_constraints = make_string_example_argument_constraints(); web::json::push_back(fields, nmos::details::make_nc_field_descriptor(U("String property example"), string_property, U("NcString"), false, false, datatype_constraints)); } { // level 0: datatype constraints, See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html // use nmos::details::make_nc_parameter_constraints_number to create datatype constraints - value datatype_constraints = value::null(); + value datatype_constraints = make_number_example_argument_constraints(); web::json::push_back(fields, nmos::details::make_nc_field_descriptor(U("Number property example"), number_property, U("NcUint64"), false, false, datatype_constraints)); } web::json::push_back(fields, nmos::details::make_nc_field_descriptor(U("Boolean property example"), boolean_property, U("NcBoolean"), false, false, value::null())); @@ -1233,12 +1267,12 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr // example example-control auto example_control = make_example_control(++oid, nmos::root_block_oid, U("ExampleControl"), U("Example control worker"), U("Example control worker"), value::null(), - value::null(), // specify the level 2: runtime constraints, see https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html - // use of make_nc_property_constraints_string and make_nc_property_constraints_number to create runtime constraints - // e.g. value_of({ - // { nmos::details::make_nc_property_constraints_string({3, 2}, 10) }, - // { nmos::details::make_nc_property_constraints_number({3, 3}, 10, 100, 2) } - // }), + // specify the level 2: runtime constraints, see https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html + // use of make_nc_property_constraints_string and make_nc_property_constraints_number to create runtime constraints + value_of({ + { nmos::details::make_nc_property_constraints_string({3, 2}, 5, U("^[a-z]+$")) }, + { nmos::details::make_nc_property_constraints_number({3, 3}, 10, 100, 2) } + }), example_enum::Undefined, U("test"), 3, From d26bc325987bcd0da32496575ac92c2a13c76f85 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 14 Nov 2023 20:36:52 +0000 Subject: [PATCH 075/106] Prevent comparsion warning --- Development/nmos/control_protocol_utils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Development/nmos/control_protocol_utils.cpp b/Development/nmos/control_protocol_utils.cpp index d1f2f933f..f1f2f56b5 100644 --- a/Development/nmos/control_protocol_utils.cpp +++ b/Development/nmos/control_protocol_utils.cpp @@ -117,7 +117,7 @@ namespace nmos // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsstring if (constraints.has_field(nmos::fields::nc::max_characters) && !constraints.at(nmos::fields::nc::max_characters).is_null()) { - const auto max_characters = nmos::fields::nc::max_characters(constraints); + const size_t max_characters = nmos::fields::nc::max_characters(constraints); if (!value.is_string() || value.as_string().length() > max_characters) { return false; } } if (constraints.has_field(nmos::fields::nc::pattern) && !constraints.at(nmos::fields::nc::pattern).is_null()) From 2471b019f16a3e0c88f1407f8b5bd549e3dae3fb Mon Sep 17 00:00:00 2001 From: lo-simon Date: Wed, 15 Nov 2023 18:46:42 +0000 Subject: [PATCH 076/106] Reject Set on non-sequence value to sequence property --- Development/nmos/control_protocol_methods.cpp | 1 + Development/nmos/control_protocol_utils.cpp | 94 +++++++++++++------ .../nmos/test/control_protocol_test.cpp | 19 +++- 3 files changed, 82 insertions(+), 32 deletions(-) diff --git a/Development/nmos/control_protocol_methods.cpp b/Development/nmos/control_protocol_methods.cpp index c5f53037f..d3e4e8196 100644 --- a/Development/nmos/control_protocol_methods.cpp +++ b/Development/nmos/control_protocol_methods.cpp @@ -56,6 +56,7 @@ namespace nmos } if ((val.is_null() && !nmos::fields::nc::is_nullable(property)) + || (!val.is_array() && nmos::fields::nc::is_sequence(property)) || (val.is_array() && !nmos::fields::nc::is_sequence(property))) { return make_control_protocol_message_response(handle, { nc_method_status::parameter_error }); diff --git a/Development/nmos/control_protocol_utils.cpp b/Development/nmos/control_protocol_utils.cpp index f1f2f56b5..3e34bc034 100644 --- a/Development/nmos/control_protocol_utils.cpp +++ b/Development/nmos/control_protocol_utils.cpp @@ -138,44 +138,76 @@ namespace nmos { const auto& datatype_type = nmos::fields::nc::type(params.datatype_descriptor); - auto is_int16 = [](int32_t value) - { - return value >= (std::numeric_limits::min)() - && value <= (std::numeric_limits::max)(); - }; - auto is_uint16 = [](uint32_t value) - { - return value >= (std::numeric_limits::min)() - && value <= (std::numeric_limits::max)(); - }; - auto is_float32 = [](double value) - { - return value >= (std::numeric_limits::min)() - && value <= (std::numeric_limits::max)(); - }; - // do NcDatatypeDescriptorPrimitive constraints validation if (nc_datatype_type::Primitive == datatype_type) { // hmm, for the primitive type, it should not have datatype constraints specified via the datatype_descriptor but just in case const auto& datatype_constraints = nmos::fields::nc::constraints(params.datatype_descriptor); - if (!datatype_constraints.is_null()) { return constraints_validation(data, datatype_constraints); } + if (!datatype_constraints.is_null()) + { + if (data.is_array()) + { + for (const auto& val : data.as_array()) + { + if (!constraints_validation(val, datatype_constraints)) { return false; } + } + // reaching here, validation successfully + return true; + } + else + { + return constraints_validation(data, datatype_constraints); + } + } - // do primitive type constraints + auto primitive_validation = [](const nc_name& name, const web::json::value& val) + { + auto is_int16 = [](int32_t value) + { + return value >= (std::numeric_limits::min)() + && value <= (std::numeric_limits::max)(); + }; + auto is_uint16 = [](uint32_t value) + { + return value >= (std::numeric_limits::min)() + && value <= (std::numeric_limits::max)(); + }; + auto is_float32 = [](double value) + { + return value >= (std::numeric_limits::min)() + && value <= (std::numeric_limits::max)(); + }; + + if (U("NcBoolean") == name) { return val.is_boolean(); } + if (U("NcInt16") == name && val.is_number()) { return is_int16(val.as_number().to_int32()); } + if (U("NcInt32") == name && val.is_number()) { return val.as_number().is_int32(); } + if (U("NcInt64") == name && val.is_number()) { return val.as_number().is_int64(); } + if (U("NcUint16") == name && val.is_number()) { return is_uint16(val.as_number().to_uint32()); } + if (U("NcUint32") == name && val.is_number()) { return val.as_number().is_uint32(); } + if (U("NcUint64") == name && val.is_number()) { return val.as_number().is_uint64(); } + if (U("NcFloat32") == name && val.is_number()) { return is_float32(val.as_number().to_double()); } + if (U("NcFloat64") == name && val.is_number()) { return !val.as_number().is_integral(); } + if (U("NcString") == name) { return val.is_string(); } + + // invalid primitive type + return false; + }; + + // do primitive type constraints validation const auto& name = nmos::fields::nc::name(params.datatype_descriptor); - if (U("NcBoolean") == name) { return data.is_boolean(); } - if (U("NcInt16") == name && data.is_number()) { return is_int16(data.as_number().to_int32()); } - if (U("NcInt32") == name && data.is_number()) { return data.as_number().is_int32(); } - if (U("NcInt64") == name && data.is_number()) { return data.as_number().is_int64(); } - if (U("NcUint16") == name && data.is_number()) { return is_uint16(data.as_number().to_uint32()); } - if (U("NcUint32") == name && data.is_number()) { return data.as_number().is_uint32(); } - if (U("NcUint64") == name && data.is_number()) { return data.as_number().is_uint64(); } - if (U("NcFloat32") == name && data.is_number()) { return is_float32(data.as_number().to_double()); } - if (U("NcFloat64") == name && data.is_number()) { return !data.as_number().is_integral(); } - if (U("NcString") == name) { return data.is_string(); } - - // invalid primitive type - return false; + if (data.is_array()) + { + for (const auto& val : data.as_array()) + { + if (!primitive_validation(name, val)) { return false; } + } + // reaching here, validation successfully + return true; + } + else + { + return primitive_validation(name, data); + } } // do NcDatatypeDescriptorTypeDef constraints validation diff --git a/Development/nmos/test/control_protocol_test.cpp b/Development/nmos/test/control_protocol_test.cpp index 7ffd6d59f..fa13f3b83 100644 --- a/Development/nmos/test/control_protocol_test.cpp +++ b/Development/nmos/test/control_protocol_test.cpp @@ -742,6 +742,8 @@ BST_TEST_CASE(testConstraints) const auto no_constraints_string_datatype = nmos::details::make_nc_datatype_typedef(U("No constraints string datatype"), U("NoConstraintsString"), false, U("NcString"), value::null()); const auto with_constraints_string_datatype = nmos::details::make_nc_datatype_typedef(U("With constraints string datatype"), U("WithConstraintsString"), false, U("NcString"), datatype_string_constraints); const auto with_constraints_int32_datatype = nmos::details::make_nc_datatype_typedef(U("With constraints int32 datatype"), U("WithConstraintsInt32"), false, U("NcInt32"), datatype_int32_constraints); + const auto no_constraints_int32_seq_datatype = nmos::details::make_nc_datatype_typedef(U("No constraints int64 datatype"), U("NoConstraintsInt64"), true, U("NcInt32"), value::null()); + const auto no_constraints_string_seq_datatype = nmos::details::make_nc_datatype_typedef(U("No constraints string datatype"), U("NoConstraintsString"), true, U("NcString"), value::null()); enum enum_value { foo, bar, baz }; auto items = value::array(); @@ -783,7 +785,8 @@ BST_TEST_CASE(testConstraints) control_protocol_state.insert(nmos::experimental::datatype{ with_constraints_string_datatype }); control_protocol_state.insert(nmos::experimental::datatype{ enum_datatype }); control_protocol_state.insert(nmos::experimental::datatype{ simple_struct_datatype }); - control_protocol_state.insert(nmos::experimental::datatype{ struct_datatype }); + control_protocol_state.insert(nmos::experimental::datatype{ no_constraints_int32_seq_datatype }); + control_protocol_state.insert(nmos::experimental::datatype{ no_constraints_string_seq_datatype }); // test get_runtime_property_constraints BST_REQUIRE_EQUAL(nmos::details::get_runtime_property_constraints(property_string_id, runtime_property_constraints), runtime_property_string_constraints); @@ -880,6 +883,20 @@ BST_TEST_CASE(testConstraints) const nmos::datatype_constraints_validation_parameters enum_constraints_validation_params{ enum_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; BST_REQUIRE(nmos::constraints_validation(enum_value::foo, value::null(), value::null(), enum_constraints_validation_params)); BST_REQUIRE_EQUAL(nmos::constraints_validation(4, value::null(), value::null(), enum_constraints_validation_params), false); + // invalid data vs primitive datatype constraints + const nmos::datatype_constraints_validation_parameters no_constraints_string_seq_constraints_validation_params{ no_constraints_string_seq_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + BST_REQUIRE(nmos::constraints_validation(value_of({ value::string(U("1234567890-abcde-!\"£$%^&*()_+=")) }), value::null(), value::null(), no_constraints_string_seq_constraints_validation_params)); + BST_REQUIRE(nmos::constraints_validation(value_of({ value::string(U("1234567890-abcde-!\"£$%^&*()_+=")), value::string(U("1234567890-abcde-!\"£$%^&*()_+=")) }), value::null(), value::null(), no_constraints_string_seq_constraints_validation_params)); + BST_REQUIRE_EQUAL(nmos::constraints_validation(value_of({ 1 }), value::null(), value::null(), no_constraints_string_seq_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(1, value::null(), value::null(), no_constraints_string_seq_constraints_validation_params), false); + const nmos::datatype_constraints_validation_parameters no_constraints_int32_seq_constraints_validation_params{ no_constraints_int32_seq_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + BST_REQUIRE_EQUAL(nmos::constraints_validation(value_of({ value::string(U("1234567890-abcde-!\"£$%^&*()_+=")) }), value::null(), value::null(), no_constraints_int32_seq_constraints_validation_params), false); + BST_REQUIRE(nmos::constraints_validation(value_of({ 1 }), value::null(), value::null(), no_constraints_int32_seq_constraints_validation_params)); + BST_REQUIRE(nmos::constraints_validation(value_of({ 1, 2 }), value::null(), value::null(), no_constraints_int32_seq_constraints_validation_params)); + BST_REQUIRE_EQUAL(nmos::constraints_validation(value_of({ value::string(U("1234567890-abcde-!\"£$%^&*()_+=")) }), value::null(), value::null(), no_constraints_int32_seq_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(value::string(U("1234567890-abcde-!\"£$%^&*()_+=")), value::null(), value::null(), no_constraints_int32_seq_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(value_of({ 1, 2 }), value::null(), value::null(), with_constraints_int32_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(value_of({ 1, 2 }), value::null(), value::null(), with_constraints_string_constraints_validation_params), false); // struct property datatype constraints validation const auto good_struct = value_of({ From 4420e1eb5d9a5832b5ea68128c249c3896ac371b Mon Sep 17 00:00:00 2001 From: lo-simon Date: Wed, 15 Nov 2023 23:00:10 +0000 Subject: [PATCH 077/106] Fix runtime and property sequence constraints validation --- .../nmos-cpp-node/node_implementation.cpp | 12 +- Development/nmos/control_protocol_utils.cpp | 162 ++++++++---------- .../nmos/test/control_protocol_test.cpp | 14 ++ 3 files changed, 98 insertions(+), 90 deletions(-) diff --git a/Development/nmos-cpp-node/node_implementation.cpp b/Development/nmos-cpp-node/node_implementation.cpp index f582d239d..1d439f423 100644 --- a/Development/nmos-cpp-node/node_implementation.cpp +++ b/Development/nmos-cpp-node/node_implementation.cpp @@ -985,20 +985,24 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr std::vector example_control_properties = { nmos::experimental::make_control_class_property(U("Example enum property"), { 3, 1 }, enum_property, U("ExampleEnum")), // create "Example string property" with level 1: property constraints, See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html - // use nmos::details::make_nc_parameter_constraints_string to create datatype constraints + // use nmos::details::make_nc_parameter_constraints_string to create property constraints nmos::experimental::make_control_class_property(U("Example string property"), { 3, 2 }, string_property, U("NcString"), false, false, false, false, make_string_example_argument_constraints()), // create "Example numeric property" with level 1: property constraints, See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html - // use nmos::details::make_nc_parameter_constraints_number to create datatype constraints + // use nmos::details::make_nc_parameter_constraints_number to create property constraints nmos::experimental::make_control_class_property(U("Example numeric property"), { 3, 3 }, number_property, U("NcUint64"), false, false, false, false, make_number_example_argument_constraints()), nmos::experimental::make_control_class_property(U("Example boolean property"), { 3, 4 }, boolean_property, U("NcBoolean")), nmos::experimental::make_control_class_property(U("Example object property"), { 3, 5 }, object_property, U("ExampleDataType")), nmos::experimental::make_control_class_property(U("Method no args invoke counter"), { 3, 6 }, method_no_args_count, U("NcUint64"), true), nmos::experimental::make_control_class_property(U("Method simple args invoke counter"), { 3, 7 }, method_simple_args_count, U("NcUint64"), true), nmos::experimental::make_control_class_property(U("Method obj arg invoke counter"), { 3, 8 }, method_object_arg_count, U("NcUint64"), true), - nmos::experimental::make_control_class_property(U("Example string sequence property"), { 3, 9 }, string_sequence, U("NcString"), false, false, true), + // create "Example sequence string property" with level 1: property constraints, See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html + // use nmos::details::make_nc_parameter_constraints_string to create sequence property constraints + nmos::experimental::make_control_class_property(U("Example string sequence property"), { 3, 9 }, string_sequence, U("NcString"), false, false, true, false, make_string_example_argument_constraints()), nmos::experimental::make_control_class_property(U("Example boolean sequence property"), { 3, 10 }, boolean_sequence, U("NcBoolean"), false, false, true), nmos::experimental::make_control_class_property(U("Example enum sequence property"), { 3, 11 }, enum_sequence, U("ExampleEnum"), false, false, true), - nmos::experimental::make_control_class_property(U("Example number sequence property"), { 3, 12 }, number_sequence, U("NcUint64"), false, false, true), + // create "Example sequence numeric property" with level 1: property constraints, See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html + // use nmos::details::make_nc_parameter_constraints_number to create sequence property constraints + nmos::experimental::make_control_class_property(U("Example number sequence property"), { 3, 12 }, number_sequence, U("NcUint64"), false, false, true, false, make_number_example_argument_constraints()), nmos::experimental::make_control_class_property(U("Example object sequence property"), { 3, 13 }, object_sequence, U("ExampleDataType"), false, false, true) }; diff --git a/Development/nmos/control_protocol_utils.cpp b/Development/nmos/control_protocol_utils.cpp index 3e34bc034..07260eb60 100644 --- a/Development/nmos/control_protocol_utils.cpp +++ b/Development/nmos/control_protocol_utils.cpp @@ -77,59 +77,74 @@ namespace nmos // constraints validation // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsnumber // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsstring - bool constraints_validation(const web::json::value& value, const web::json::value& constraints) + bool constraints_validation(const web::json::value& data, const web::json::value& constraints) { - // is numeric constraints - // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsnumber - if (constraints.has_field(nmos::fields::nc::step) && !nmos::fields::nc::step(constraints).is_null()) + auto parameter_constraints_validation = [&constraints](const web::json::value& value) { - if (!value.is_integer()) { return false; } + // is numeric constraints + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsnumber + if (constraints.has_field(nmos::fields::nc::step) && !nmos::fields::nc::step(constraints).is_null()) + { + if (!value.is_integer()) { return false; } - const auto step = nmos::fields::nc::step(constraints).as_double(); - if (step <= 0) { return false; } + const auto step = nmos::fields::nc::step(constraints).as_double(); + if (step <= 0) { return false; } - const auto value_double = value.as_double(); + const auto value_double = value.as_double(); + if (constraints.has_field(nmos::fields::nc::minimum) && !nmos::fields::nc::minimum(constraints).is_null()) + { + auto min = nmos::fields::nc::minimum(constraints).as_double(); + if (0 != std::fmod(value_double - min, step)) { return false; } + } + else if (constraints.has_field(nmos::fields::nc::maximum) && !nmos::fields::nc::maximum(constraints).is_null()) + { + auto max = nmos::fields::nc::maximum(constraints).as_double(); + if (0 != std::fmod(max - value_double, step)) { return false; } + } + else + { + if (0 != std::fmod(value_double, step)) { return false; } + } + } if (constraints.has_field(nmos::fields::nc::minimum) && !nmos::fields::nc::minimum(constraints).is_null()) { - auto min = nmos::fields::nc::minimum(constraints).as_double(); - if (0 != std::fmod(value_double - min, step)) { return false; } + if (!value.is_integer() || value.as_double() < nmos::fields::nc::minimum(constraints).as_double()) { return false; } } - else if (constraints.has_field(nmos::fields::nc::maximum) && !nmos::fields::nc::maximum(constraints).is_null()) + if (constraints.has_field(nmos::fields::nc::maximum) && !nmos::fields::nc::maximum(constraints).is_null()) { - auto max = nmos::fields::nc::maximum(constraints).as_double(); - if (0 != std::fmod(max - value_double, step)) { return false; } + if (!value.is_integer() || value.as_double() > nmos::fields::nc::maximum(constraints).as_double()) { return false; } } - else + + // is string constraints + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsstring + if (constraints.has_field(nmos::fields::nc::max_characters) && !constraints.at(nmos::fields::nc::max_characters).is_null()) { - if (0 != std::fmod(value_double, step)) { return false; } + const size_t max_characters = nmos::fields::nc::max_characters(constraints); + if (!value.is_string() || value.as_string().length() > max_characters) { return false; } + } + if (constraints.has_field(nmos::fields::nc::pattern) && !constraints.at(nmos::fields::nc::pattern).is_null()) + { + if (!value.is_string()) { return false; } + const auto value_string = utility::us2s(value.as_string()); + bst::regex pattern(utility::us2s(nmos::fields::nc::pattern(constraints))); + if (!bst::regex_match(value_string, pattern)) { return false; } } - } - if (constraints.has_field(nmos::fields::nc::minimum) && !nmos::fields::nc::minimum(constraints).is_null()) - { - if (!value.is_integer() || value.as_double() < nmos::fields::nc::minimum(constraints).as_double()) { return false; } - } - if (constraints.has_field(nmos::fields::nc::maximum) && !nmos::fields::nc::maximum(constraints).is_null()) - { - if (!value.is_integer() || value.as_double() > nmos::fields::nc::maximum(constraints).as_double()) { return false; } - } - // is string constraints - // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsstring - if (constraints.has_field(nmos::fields::nc::max_characters) && !constraints.at(nmos::fields::nc::max_characters).is_null()) - { - const size_t max_characters = nmos::fields::nc::max_characters(constraints); - if (!value.is_string() || value.as_string().length() > max_characters) { return false; } - } - if (constraints.has_field(nmos::fields::nc::pattern) && !constraints.at(nmos::fields::nc::pattern).is_null()) + // reaching here, parameter validation successfully + return true; + }; + + if (data.is_array()) { - if (!value.is_string()) { return false; } - const auto value_string = utility::us2s(value.as_string()); - bst::regex pattern(utility::us2s(nmos::fields::nc::pattern(constraints))); - if (!bst::regex_match(value_string, pattern)) { return false; } + for (const auto& value : data.as_array()) + { + if (!parameter_constraints_validation(value)) { return false; } + } + // validation successfully + return true; } - // reaching here, no validation is required - return true; + return parameter_constraints_validation(data); } // level 0 datatype constraints validation @@ -145,22 +160,10 @@ namespace nmos const auto& datatype_constraints = nmos::fields::nc::constraints(params.datatype_descriptor); if (!datatype_constraints.is_null()) { - if (data.is_array()) - { - for (const auto& val : data.as_array()) - { - if (!constraints_validation(val, datatype_constraints)) { return false; } - } - // reaching here, validation successfully - return true; - } - else - { - return constraints_validation(data, datatype_constraints); - } + return constraints_validation(data, datatype_constraints); } - auto primitive_validation = [](const nc_name& name, const web::json::value& val) + auto primitive_validation = [](const nc_name& name, const web::json::value& value) { auto is_int16 = [](int32_t value) { @@ -178,16 +181,16 @@ namespace nmos && value <= (std::numeric_limits::max)(); }; - if (U("NcBoolean") == name) { return val.is_boolean(); } - if (U("NcInt16") == name && val.is_number()) { return is_int16(val.as_number().to_int32()); } - if (U("NcInt32") == name && val.is_number()) { return val.as_number().is_int32(); } - if (U("NcInt64") == name && val.is_number()) { return val.as_number().is_int64(); } - if (U("NcUint16") == name && val.is_number()) { return is_uint16(val.as_number().to_uint32()); } - if (U("NcUint32") == name && val.is_number()) { return val.as_number().is_uint32(); } - if (U("NcUint64") == name && val.is_number()) { return val.as_number().is_uint64(); } - if (U("NcFloat32") == name && val.is_number()) { return is_float32(val.as_number().to_double()); } - if (U("NcFloat64") == name && val.is_number()) { return !val.as_number().is_integral(); } - if (U("NcString") == name) { return val.is_string(); } + if (U("NcBoolean") == name) { return value.is_boolean(); } + if (U("NcInt16") == name && value.is_number()) { return is_int16(value.as_number().to_int32()); } + if (U("NcInt32") == name && value.is_number()) { return value.as_number().is_int32(); } + if (U("NcInt64") == name && value.is_number()) { return value.as_number().is_int64(); } + if (U("NcUint16") == name && value.is_number()) { return is_uint16(value.as_number().to_uint32()); } + if (U("NcUint32") == name && value.is_number()) { return value.as_number().is_uint32(); } + if (U("NcUint64") == name && value.is_number()) { return value.as_number().is_uint64(); } + if (U("NcFloat32") == name && value.is_number()) { return is_float32(value.as_number().to_double()); } + if (U("NcFloat64") == name && value.is_number()) { return !value.as_number().is_integral(); } + if (U("NcString") == name) { return value.is_string(); } // invalid primitive type return false; @@ -197,17 +200,15 @@ namespace nmos const auto& name = nmos::fields::nc::name(params.datatype_descriptor); if (data.is_array()) { - for (const auto& val : data.as_array()) + for (const auto& value : data.as_array()) { - if (!primitive_validation(name, val)) { return false; } + if (!primitive_validation(name, value)) { return false; } } - // reaching here, validation successfully + // reaching here, primitive validation successfully return true; } - else - { - return primitive_validation(name, data); - } + + return primitive_validation(name, data); } // do NcDatatypeDescriptorTypeDef constraints validation @@ -252,19 +253,8 @@ namespace nmos { auto value = data.at(name); - if (value.is_array()) - { - for (const auto& val : value.as_array()) - { - // do field constraints validation - if (!constraints_validation(val, constraints)) { return false; } - } - } - else - { - // do field constraints validation - if (!constraints_validation(value, constraints)) { return false; } - } + // do field constraints validation + if (!constraints_validation(value, constraints)) { return false; } } else { @@ -574,15 +564,15 @@ namespace nmos // multiple levels of constraints validation // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html - bool constraints_validation(const web::json::value& value, const web::json::value& runtime_property_constraints, const web::json::value& property_constraints, const datatype_constraints_validation_parameters& params) + bool constraints_validation(const web::json::value& data, const web::json::value& runtime_property_constraints, const web::json::value& property_constraints, const datatype_constraints_validation_parameters& params) { // do level 2 runtime property constraints validation - if (!runtime_property_constraints.is_null()) { return details::constraints_validation(value, runtime_property_constraints); } + if (!runtime_property_constraints.is_null()) { return details::constraints_validation(data, runtime_property_constraints); } // do level 1 property constraints validation - if (!property_constraints.is_null()) { return details::constraints_validation(value, property_constraints); } + if (!property_constraints.is_null()) { return details::constraints_validation(data, property_constraints); } // do level 0 datatype constraints validation - return details::datatype_constraints_validation(value, params); + return details::datatype_constraints_validation(data, params); } } diff --git a/Development/nmos/test/control_protocol_test.cpp b/Development/nmos/test/control_protocol_test.cpp index fa13f3b83..381433923 100644 --- a/Development/nmos/test/control_protocol_test.cpp +++ b/Development/nmos/test/control_protocol_test.cpp @@ -800,10 +800,16 @@ BST_TEST_CASE(testConstraints) BST_REQUIRE(nmos::constraints_validation(value::string(U("1234567890")), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params)); BST_REQUIRE_EQUAL(nmos::constraints_validation(value::string(U("12345678901")), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params), false); BST_REQUIRE_EQUAL(nmos::constraints_validation(value::string(U("123456789A")), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params), false); + BST_REQUIRE(nmos::constraints_validation(value_of({ value::string(U("1234567890")), value::string(U("1234567890")) }), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params)); + BST_REQUIRE_EQUAL(nmos::constraints_validation(value_of({ value::string(U("1234567890")), value::string(U("12345678901")) }), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(value_of({ value::string(U("1234567890")), 1 }), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params), false); // property constraints validation BST_REQUIRE(nmos::constraints_validation(value::string(U("abcde")), value::null(), property_string_constraints, with_constraints_string_constraints_validation_params)); BST_REQUIRE_EQUAL(nmos::constraints_validation(value::string(U("abcdef")), value::null(), property_string_constraints, with_constraints_string_constraints_validation_params), false); BST_REQUIRE_EQUAL(nmos::constraints_validation(value::string(U("abcd1")), value::null(), property_string_constraints, with_constraints_string_constraints_validation_params), false); + BST_REQUIRE(nmos::constraints_validation(value_of({ value::string(U("abcde")), value::string(U("abcde")) }), value::null(), property_string_constraints, with_constraints_string_constraints_validation_params)); + BST_REQUIRE_EQUAL(nmos::constraints_validation(value_of({ value::string(U("abcde")), value::string(U("abcdef")) }), value::null(), property_string_constraints, with_constraints_string_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(value_of({ value::string(U("abcde")), 1 }), value::null(), property_string_constraints, with_constraints_string_constraints_validation_params), false); // datatype constraints validation BST_REQUIRE(nmos::constraints_validation(value::string(U("1a")), value::null(), value::null(), with_constraints_string_constraints_validation_params)); BST_REQUIRE_EQUAL(nmos::constraints_validation(value::string(U("1a2")), value::null(), value::null(), with_constraints_string_constraints_validation_params), false); @@ -819,12 +825,20 @@ BST_TEST_CASE(testConstraints) BST_REQUIRE(nmos::constraints_validation(1000, runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params)); BST_REQUIRE_EQUAL(nmos::constraints_validation(9, runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params), false); BST_REQUIRE_EQUAL(nmos::constraints_validation(1001, runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params), false); + BST_REQUIRE(nmos::constraints_validation(value_of({ 10, 1000 }), runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params)); + BST_REQUIRE_EQUAL(nmos::constraints_validation(value_of({ 10, 1001 }), runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(value_of({ 10, value::string(U("a")) }), runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params), false); // property constraints validation BST_REQUIRE(nmos::constraints_validation(50, value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params)); BST_REQUIRE(nmos::constraints_validation(500, value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params)); BST_REQUIRE_EQUAL(nmos::constraints_validation(45, value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), false); BST_REQUIRE_EQUAL(nmos::constraints_validation(505, value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), false); BST_REQUIRE_EQUAL(nmos::constraints_validation(499, value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), false); + BST_REQUIRE(nmos::constraints_validation(value_of({ 50, 500 }), value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params)); + BST_REQUIRE_EQUAL(nmos::constraints_validation(value_of({ 49, 500 }), value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(value_of({ 50, 501 }), value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(value_of({ 45, 500 }), value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::constraints_validation(value_of({ 50, value::string(U("a")) }), value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), false); // datatype constraints validation BST_REQUIRE(nmos::constraints_validation(100, value::null(), value::null(), with_constraints_int32_constraints_validation_params)); BST_REQUIRE(nmos::constraints_validation(250, value::null(), value::null(), with_constraints_int32_constraints_validation_params)); From bc5e0f503bf6a30796df0b04dfe2ed1509657058 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Sat, 18 Nov 2023 13:12:03 +0000 Subject: [PATCH 078/106] Add method parameters constriants validation, and check method deprecation --- .../nmos-cpp-node/node_implementation.cpp | 67 +---- .../nmos/control_protocol_handlers.cpp | 17 +- Development/nmos/control_protocol_handlers.h | 19 +- Development/nmos/control_protocol_methods.cpp | 71 +++--- Development/nmos/control_protocol_methods.h | 26 +- .../nmos/control_protocol_resource.cpp | 12 +- Development/nmos/control_protocol_state.cpp | 28 +-- Development/nmos/control_protocol_state.h | 7 +- Development/nmos/control_protocol_utils.cpp | 50 +++- Development/nmos/control_protocol_utils.h | 22 +- Development/nmos/control_protocol_ws_api.cpp | 31 ++- .../nmos/test/control_protocol_test.cpp | 234 +++++++++--------- 12 files changed, 291 insertions(+), 293 deletions(-) diff --git a/Development/nmos-cpp-node/node_implementation.cpp b/Development/nmos-cpp-node/node_implementation.cpp index 1d439f423..cd27d1f04 100644 --- a/Development/nmos-cpp-node/node_implementation.cpp +++ b/Development/nmos-cpp-node/node_implementation.cpp @@ -1006,81 +1006,34 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr nmos::experimental::make_control_class_property(U("Example object sequence property"), { 3, 13 }, object_sequence, U("ExampleDataType"), false, false, true) }; - auto example_method_with_no_args = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) + auto example_method_with_no_args = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, const web::json::value& nc_method_descriptor, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... slog::log(gate, SLOG_FLF) << "Executing the example method with no arguments"; - return nmos::make_control_protocol_message_response(handle, { nmos::nc_method_status::ok }); + return nmos::make_control_protocol_message_response(handle, { nmos::fields::nc::is_deprecated(nc_method_descriptor) ? nmos::nc_method_status::method_deprecated : nmos::nc_method_status::ok }); }; - auto example_method_with_simple_args = [enum_arg, string_arg, number_arg, boolean_arg, make_string_example_argument_constraints, make_number_example_argument_constraints](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) + auto example_method_with_simple_args = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - - using web::json::value; + // and the method parameters constriants has already been validated by the outter function slog::log(gate, SLOG_FLF) << "Executing the example method with simple arguments: " << arguments.serialize(); - // example to do method arguments constraints validation - if (!nmos::constraints_validation(arguments.at(enum_arg), value::null(), value::null(), { nmos::details::get_datatype_descriptor(value::string(U("ExampleEnum")), get_control_protocol_datatype), get_control_protocol_datatype })) - { - slog::log(gate, SLOG_FLF) << "invalid enum_arg: " << arguments.at(enum_arg).serialize(); - return nmos::make_control_protocol_message_response(handle, { nmos::nc_method_status::parameter_error }); - } - if (!nmos::constraints_validation(arguments.at(string_arg), make_string_example_argument_constraints(), value::null(), {nmos::details::get_datatype_descriptor(value::string(U("NcString")), get_control_protocol_datatype), get_control_protocol_datatype})) - { - slog::log(gate, SLOG_FLF) << "invalid string_arg: " << arguments.at(string_arg).serialize(); - return nmos::make_control_protocol_message_response(handle, { nmos::nc_method_status::parameter_error }); - } - if (!nmos::constraints_validation(arguments.at(number_arg), make_number_example_argument_constraints(), value::null(), { nmos::details::get_datatype_descriptor(value::string(U("NcUint64")), get_control_protocol_datatype), get_control_protocol_datatype })) - { - slog::log(gate, SLOG_FLF) << "invalid number_arg: " << arguments.at(number_arg).serialize(); - return nmos::make_control_protocol_message_response(handle, { nmos::nc_method_status::parameter_error }); - } - if (!nmos::constraints_validation(arguments.at(boolean_arg), value::null(), value::null(), { nmos::details::get_datatype_descriptor(value::string(U("NcBoolean")), get_control_protocol_datatype), get_control_protocol_datatype })) - { - slog::log(gate, SLOG_FLF) << "invalid boolean_arg: " << arguments.at(boolean_arg).serialize(); - return nmos::make_control_protocol_message_response(handle, { nmos::nc_method_status::parameter_error }); - } - - return nmos::make_control_protocol_message_response(handle, { nmos::nc_method_status::ok }); + return nmos::make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::nc_method_status::ok }); }; - auto example_method_with_object_args = [obj_arg, enum_arg, string_arg, number_arg, boolean_arg, make_string_example_argument_constraints, make_number_example_argument_constraints](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) + auto example_method_with_object_args = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + // and the method parameters constriants has already been validated by the outter function - using web::json::value; - - slog::log(gate, SLOG_FLF) << "Executing the example method with object argument: " << obj_arg(arguments).serialize(); - - // example to do method arguments constraints validation - const auto& obj_arg_ = obj_arg(arguments); - if (!nmos::constraints_validation(obj_arg_.at(enum_arg), value::null(), value::null(), { nmos::details::get_datatype_descriptor(value::string(U("ExampleEnum")), get_control_protocol_datatype), get_control_protocol_datatype })) - { - slog::log(gate, SLOG_FLF) << "invalid enum_arg: " << obj_arg_.at(enum_arg).serialize(); - return nmos::make_control_protocol_message_response(handle, { nmos::nc_method_status::parameter_error }); - } - if (!nmos::constraints_validation(obj_arg_.at(string_arg), make_string_example_argument_constraints(), value::null(), { nmos::details::get_datatype_descriptor(value::string(U("NcString")), get_control_protocol_datatype), get_control_protocol_datatype })) - { - slog::log(gate, SLOG_FLF) << "invalid string_arg: " << obj_arg_.at(string_arg).serialize(); - return nmos::make_control_protocol_message_response(handle, { nmos::nc_method_status::parameter_error }); - } - if (!nmos::constraints_validation(obj_arg_.at(number_arg), make_number_example_argument_constraints(), value::null(), { nmos::details::get_datatype_descriptor(value::string(U("NcUint64")), get_control_protocol_datatype), get_control_protocol_datatype })) - { - slog::log(gate, SLOG_FLF) << "invalid number_arg: " << obj_arg_.at(number_arg).serialize(); - return nmos::make_control_protocol_message_response(handle, { nmos::nc_method_status::parameter_error }); - } - if (!nmos::constraints_validation(obj_arg_.at(boolean_arg), value::null(), value::null(), { nmos::details::get_datatype_descriptor(value::string(U("NcBoolean")), get_control_protocol_datatype), get_control_protocol_datatype })) - { - slog::log(gate, SLOG_FLF) << "invalid boolean_arg: " << obj_arg_.at(boolean_arg).serialize(); - return nmos::make_control_protocol_message_response(handle, { nmos::nc_method_status::parameter_error }); - } + slog::log(gate, SLOG_FLF) << "Executing the example method with object argument: " << arguments.serialize(); - return nmos::make_control_protocol_message_response(handle, { nmos::nc_method_status::ok }); + return nmos::make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::nc_method_status::ok }); }; // Example control class methods - std::vector> example_control_methods = + std::vector example_control_methods = { { nmos::experimental::make_control_class_method(U("Example method with no arguments"), { 3, 1 }, U("MethodNoArgs"), U("NcMethodResult"), {}, false), example_method_with_no_args }, { nmos::experimental::make_control_class_method(U("Example method with simple arguments"), { 3, 2 }, U("MethodSimpleArgs"), U("NcMethodResult"), diff --git a/Development/nmos/control_protocol_handlers.cpp b/Development/nmos/control_protocol_handlers.cpp index e650496aa..f4e0129dd 100644 --- a/Development/nmos/control_protocol_handlers.cpp +++ b/Development/nmos/control_protocol_handlers.cpp @@ -51,18 +51,21 @@ namespace nmos while (!class_id.empty()) { const auto& control_class = get_control_protocol_class(class_id); - auto& methods = control_class.method_handlers; - auto method_found = methods.find(method_id); + auto& methods = control_class.methods; + auto method_found = std::find_if(methods.begin(), methods.end(), [&method_id](const experimental::method& method) + { + return method_id == details::parse_nc_method_id(nmos::fields::nc::id(method.first)); + }); if (methods.end() != method_found) { - return method_found->second; + return *method_found; } class_id.pop_back(); } - return experimental::method_handler(nullptr); + return experimental::method(); }; } @@ -81,9 +84,9 @@ namespace nmos // hmm, maybe updating connectionStatusMessage, payloadStatus, and payloadStatusMessage too const auto propertry_changed_event = make_propertry_changed_event(nmos::fields::nc::oid(found->data), - { - { nc_receiver_monitor_connection_status_property_id, nc_property_change_type::type::value_changed, val } - }); + { + { nc_receiver_monitor_connection_status_property_id, nc_property_change_type::type::value_changed, val } + }); modify_control_protocol_resource(resources, found->id, [&](nmos::resource& resource) { diff --git a/Development/nmos/control_protocol_handlers.h b/Development/nmos/control_protocol_handlers.h index a21277612..580a7a2ca 100644 --- a/Development/nmos/control_protocol_handlers.h +++ b/Development/nmos/control_protocol_handlers.h @@ -34,19 +34,16 @@ namespace nmos namespace experimental { - // method handler defnition - typedef std::function method_handler; - // methods defnition - typedef std::map methods; // method_id vs method handler - } + // method handler definition + typedef std::function method_handler; - // callback to retrieve all the method handlers - // this callback should not throw exceptions - typedef std::function()> get_control_protocol_methods_handler; + // method definition (NcMethodDescriptor vs method handler) + typedef std::pair method; + } - // callback to retrieve a specific method handler + // callback to retrieve a specific method // this callback should not throw exceptions - typedef std::function get_control_protocol_method_handler; + typedef std::function get_control_protocol_method_handler; // construct callback to retrieve a specific control protocol class get_control_protocol_class_handler make_get_control_protocol_class_handler(experimental::control_protocol_state& control_protocol_state); @@ -54,7 +51,7 @@ namespace nmos // construct callback to retrieve a specific datatype get_control_protocol_datatype_handler make_get_control_protocol_datatype_handler(experimental::control_protocol_state& control_protocol_state); - // construct callback to retrieve a specific method handler + // construct callback to retrieve a specific method get_control_protocol_method_handler make_get_control_protocol_method_handler(experimental::control_protocol_state& control_protocol_state); // a control_protocol_connection_activation_handler is a notification that the active parameters for the specified (IS-05) sender/connection_sender or receiver/connection_receiver have changed diff --git a/Development/nmos/control_protocol_methods.cpp b/Development/nmos/control_protocol_methods.cpp index d3e4e8196..ae29aa632 100644 --- a/Development/nmos/control_protocol_methods.cpp +++ b/Development/nmos/control_protocol_methods.cpp @@ -14,7 +14,7 @@ namespace nmos { // NcObject methods implementation // Get property value - web::json::value get(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate) + web::json::value get(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -26,7 +26,7 @@ namespace nmos const auto& property = find_property(parse_nc_property_id(property_id), parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), get_control_protocol_class); if (!property.is_null()) { - return make_control_protocol_message_response(handle, { nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }, resource->data.at(nmos::fields::nc::name(property))); + return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }, resource->data.at(nmos::fields::nc::name(property))); } // unknown property @@ -36,7 +36,7 @@ namespace nmos } // Set property value - web::json::value set(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) + web::json::value set(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -62,10 +62,10 @@ namespace nmos return make_control_protocol_message_response(handle, { nc_method_status::parameter_error }); } - // do constraints validation + // do property constraints validation if (!val.is_null()) { - if (!nmos::constraints_validation(val, get_runtime_property_constraints(property_id_, resource->data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), { get_datatype_descriptor(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype), get_control_protocol_datatype })) + if (!nmos::details::constraints_validation(val, get_runtime_property_constraints(property_id_, resource->data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), { get_datatype_descriptor(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype), get_control_protocol_datatype })) { return make_control_protocol_message_response(handle, { nc_method_status::parameter_error }); } @@ -78,7 +78,7 @@ namespace nmos }, make_propertry_changed_event(nmos::fields::nc::oid(resource->data), { { property_id_, nc_property_change_type::type::value_changed, val } })); - return make_control_protocol_message_response(handle, { nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }); + return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }); } // unknown property @@ -88,7 +88,7 @@ namespace nmos } // Get sequence item - web::json::value get_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate) + web::json::value get_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -113,7 +113,7 @@ namespace nmos if (data.as_array().size() > (size_t)index) { - return make_control_protocol_message_response(handle, { nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }, data.at(index)); + return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }, data.at(index)); } // out of bound @@ -129,7 +129,7 @@ namespace nmos } // Set sequence item - web::json::value set_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) + web::json::value set_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -161,8 +161,8 @@ namespace nmos if (data.as_array().size() > (size_t)index) { - // do constraints validation - if (!nmos::constraints_validation(val, get_runtime_property_constraints(property_id_, resource->data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), { get_datatype_descriptor(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype), get_control_protocol_datatype })) + // do property constraints validation + if (!nmos::details::constraints_validation(val, get_runtime_property_constraints(property_id_, resource->data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), { get_datatype_descriptor(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype), get_control_protocol_datatype })) { return make_control_protocol_message_response(handle, { nc_method_status::parameter_error }); } @@ -174,7 +174,7 @@ namespace nmos }, make_propertry_changed_event(nmos::fields::nc::oid(resource->data), { { property_id_, nc_property_change_type::type::sequence_item_changed, val, nc_id(index) } })); - return make_control_protocol_message_response(handle, { nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }); + return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }); } // out of bound @@ -190,7 +190,7 @@ namespace nmos } // Add item to sequence - web::json::value add_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) + web::json::value add_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -223,8 +223,8 @@ namespace nmos const nc_id sequence_item_index = data.is_null() ? 0 : nc_id(data.as_array().size()); - // do constraints validation - if (!nmos::constraints_validation(val, get_runtime_property_constraints(property_id_, resource->data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), { get_datatype_descriptor(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype), get_control_protocol_datatype })) + // do property constraints validation + if (!nmos::details::constraints_validation(val, get_runtime_property_constraints(property_id_, resource->data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), { get_datatype_descriptor(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype), get_control_protocol_datatype })) { return make_control_protocol_message_response(handle, { nc_method_status::parameter_error }); } @@ -238,7 +238,7 @@ namespace nmos }, make_propertry_changed_event(nmos::fields::nc::oid(resource->data), { { property_id_, nc_property_change_type::type::sequence_item_added, val, sequence_item_index } })); - return make_control_protocol_message_response(handle, { nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }, sequence_item_index); + return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }, sequence_item_index); } // unknown property @@ -248,7 +248,7 @@ namespace nmos } // Delete sequence item - web::json::value remove_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate) + web::json::value remove_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -280,7 +280,7 @@ namespace nmos }, make_propertry_changed_event(nmos::fields::nc::oid(resource->data), { { parse_nc_property_id(property_id), nc_property_change_type::type::sequence_item_removed, nc_id(index) } })); - return make_control_protocol_message_response(handle, { nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }); + return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }); } // out of bound @@ -296,7 +296,7 @@ namespace nmos } // Get sequence length - web::json::value get_sequence_length(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate) + web::json::value get_sequence_length(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -326,7 +326,7 @@ namespace nmos if (data.is_null()) { // null - return make_control_protocol_message_response(handle, { nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }, value::null()); + return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }, value::null()); } } else @@ -340,7 +340,7 @@ namespace nmos return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); } } - return make_control_protocol_message_response(handle, { nc_method_status::ok }, uint32_t(data.as_array().size())); + return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }, uint32_t(data.as_array().size())); } // unknown property @@ -351,7 +351,7 @@ namespace nmos // NcBlock methods implementation // Gets descriptors of members of the block - web::json::value get_member_descriptors(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler, get_control_protocol_datatype_handler, slog::base_gate& gate) + web::json::value get_member_descriptors(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -364,11 +364,11 @@ namespace nmos auto descriptors = value::array(); nmos::get_member_descriptors(resources, resource, recurse, descriptors.as_array()); - return make_control_protocol_message_response(handle, { nc_method_status::ok }, descriptors); + return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nc_method_status::ok }, descriptors); } // Finds member(s) by path - web::json::value find_members_by_path(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler, get_control_protocol_datatype_handler, slog::base_gate& gate) + web::json::value find_members_by_path(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -422,11 +422,11 @@ namespace nmos } web::json::push_back(descriptors, descriptor); - return make_control_protocol_message_response(handle, { nc_method_status::ok }, descriptors); + return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nc_method_status::ok }, descriptors); } // Finds members with given role name or fragment - web::json::value find_members_by_role(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler, get_control_protocol_datatype_handler, slog::base_gate& gate) + web::json::value find_members_by_role(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -448,11 +448,11 @@ namespace nmos auto descriptors = value::array(); nmos::find_members_by_role(resources, resource, role, match_whole_string, case_sensitive, recurse, descriptors.as_array()); - return make_control_protocol_message_response(handle, { nc_method_status::ok }, descriptors); + return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nc_method_status::ok }, descriptors); } // Finds members with given class id - web::json::value find_members_by_class_id(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler, get_control_protocol_datatype_handler, slog::base_gate& gate) + web::json::value find_members_by_class_id(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -475,12 +475,12 @@ namespace nmos auto descriptors = value::array(); nmos::find_members_by_class_id(resources, resource, class_id, include_derived, recurse, descriptors.as_array()); - return make_control_protocol_message_response(handle, { nc_method_status::ok }, descriptors); + return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nc_method_status::ok }, descriptors); } // NcClassManager methods implementation // Get a single class descriptor - web::json::value get_control_class(nmos::resources&, nmos::resources::iterator, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate) + web::json::value get_control_class(nmos::resources&, nmos::resources::iterator, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate) { using web::json::value; @@ -504,7 +504,8 @@ namespace nmos auto& name = control_class.name; auto& fixed_role = control_class.fixed_role; auto properties = control_class.properties; - auto methods = control_class.methods; + auto methods = value::array(); + for (const auto& method : control_class.methods) { web::json::push_back(methods, method.first); } auto events = control_class.events; if (include_inherited) @@ -517,7 +518,7 @@ namespace nmos const auto& inherited_control_class = get_control_protocol_class(inherited_class_id); { for (const auto& property : inherited_control_class.properties.as_array()) { web::json::push_back(properties, property); } - for (const auto& method : inherited_control_class.methods.as_array()) { web::json::push_back(methods, method); } + for (const auto& method : inherited_control_class.methods) { web::json::push_back(methods, method.first); } for (const auto& event : inherited_control_class.events.as_array()) { web::json::push_back(events, event); } } inherited_class_id.pop_back(); @@ -527,14 +528,14 @@ namespace nmos ? details::make_nc_class_descriptor(description, class_id, name, properties, methods, events) : details::make_nc_class_descriptor(description, class_id, name, fixed_role.as_string(), properties, methods, events); - return make_control_protocol_message_response(handle, { nc_method_status::ok }, descriptor); + return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nc_method_status::ok }, descriptor); } return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("classId not found")); } // Get a single datatype descriptor - web::json::value get_datatype(nmos::resources&, nmos::resources::iterator, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler, get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) + web::json::value get_datatype(nmos::resources&, nmos::resources::iterator, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -586,7 +587,7 @@ namespace nmos } } - return make_control_protocol_message_response(handle, { nc_method_status::ok }, descriptor); + return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nc_method_status::ok }, descriptor); } return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("name not found")); diff --git a/Development/nmos/control_protocol_methods.h b/Development/nmos/control_protocol_methods.h index 3e7d136e5..d0eec3ca7 100644 --- a/Development/nmos/control_protocol_methods.h +++ b/Development/nmos/control_protocol_methods.h @@ -15,35 +15,35 @@ namespace nmos { // NcObject methods implementation // Get property value - web::json::value get(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate); + web::json::value get(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate); // Set property value - web::json::value set(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate); + web::json::value set(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate); // Get sequence item - web::json::value get_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate); + web::json::value get_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate); // Set sequence item - web::json::value set_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate); + web::json::value set_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate); // Add item to sequence - web::json::value add_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate); + web::json::value add_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate); // Delete sequence item - web::json::value remove_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate); + web::json::value remove_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate); // Get sequence length - web::json::value get_sequence_length(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate); + web::json::value get_sequence_length(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate); // NcBlock methods implementation // Get descriptors of members of the block - web::json::value get_member_descriptors(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler, get_control_protocol_datatype_handler, slog::base_gate& gate); + web::json::value get_member_descriptors(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, slog::base_gate& gate); // Finds member(s) by path - web::json::value find_members_by_path(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler, get_control_protocol_datatype_handler, slog::base_gate& gate); + web::json::value find_members_by_path(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, slog::base_gate& gate); // Finds members with given role name or fragment - web::json::value find_members_by_role(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler, get_control_protocol_datatype_handler, slog::base_gate& gate); + web::json::value find_members_by_role(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, slog::base_gate& gate); // Finds members with given class id - web::json::value find_members_by_class_id(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler, get_control_protocol_datatype_handler, slog::base_gate& gate); + web::json::value find_members_by_class_id(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, slog::base_gate& gate); // NcClassManager methods implementation // Get a single class descriptor - web::json::value get_control_class(nmos::resources&, nmos::resources::iterator, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate); + web::json::value get_control_class(nmos::resources&, nmos::resources::iterator, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate); // Get a single datatype descriptor - web::json::value get_datatype(nmos::resources&, nmos::resources::iterator, int32_t handle, const web::json::value& arguments, get_control_protocol_class_handler, get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate); + web::json::value get_datatype(nmos::resources&, nmos::resources::iterator, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate); } } diff --git a/Development/nmos/control_protocol_resource.cpp b/Development/nmos/control_protocol_resource.cpp index 61ab4b3ec..248b3aba5 100644 --- a/Development/nmos/control_protocol_resource.cpp +++ b/Development/nmos/control_protocol_resource.cpp @@ -65,7 +65,7 @@ namespace nmos { return make_nc_element_id(id); } - nc_event_id parse_nc_method_id(const web::json::value& id) + nc_method_id parse_nc_method_id(const web::json::value& id) { return parse_nc_element_id(id); } @@ -75,7 +75,7 @@ namespace nmos { return make_nc_element_id(id); } - nc_event_id parse_nc_property_id(const web::json::value& id) + nc_property_id parse_nc_property_id(const web::json::value& id) { return parse_nc_element_id(id); } @@ -781,9 +781,13 @@ namespace nmos for (const auto& control_class : control_protocol_state.control_classes) { auto& ctl_class = control_class.second; + + auto methods = value::array(); + for (const auto& method : ctl_class.methods) { web::json::push_back(methods, method.first); } + const auto class_description = ctl_class.fixed_role.is_null() - ? make_nc_class_descriptor(ctl_class.description, ctl_class.class_id, ctl_class.name, ctl_class.properties, ctl_class.methods, ctl_class.events) - : make_nc_class_descriptor(ctl_class.description, ctl_class.class_id, ctl_class.name, ctl_class.fixed_role.as_string(), ctl_class.properties, ctl_class.methods, ctl_class.events); + ? make_nc_class_descriptor(ctl_class.description, ctl_class.class_id, ctl_class.name, ctl_class.properties, methods, ctl_class.events) + : make_nc_class_descriptor(ctl_class.description, ctl_class.class_id, ctl_class.name, ctl_class.fixed_role.as_string(), ctl_class.properties, methods, ctl_class.events); web::json::push_back(control_classes, class_description); } diff --git a/Development/nmos/control_protocol_state.cpp b/Development/nmos/control_protocol_state.cpp index 60661b966..3cc3af38a 100644 --- a/Development/nmos/control_protocol_state.cpp +++ b/Development/nmos/control_protocol_state.cpp @@ -12,25 +12,18 @@ namespace nmos // create control class // where // properties: vector of NcPropertyDescriptor can be constructed using make_control_class_property - // methods: vector of NcMethodDescriptor can be constructed using make_nc_method_descriptor and the assoicated method handler + // methods: vector of NcMethodDescriptor vs assoicated method handler where NcMethodDescriptor can be constructed using make_nc_method_descriptor // events: vector of NcEventDescriptor can be constructed using make_nc_event_descriptor - control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const web::json::value& fixed_role, const std::vector& properties_, const std::vector>& methods_, const std::vector& events_) + control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const web::json::value& fixed_role, const std::vector& properties_, const std::vector& methods_, const std::vector& events_) { using web::json::value; web::json::value properties = value::array(); for (const auto& property : properties_) { web::json::push_back(properties, property); } - web::json::value methods = value::array(); - nmos::experimental::methods method_handlers; - for (const auto& method : methods_) - { - web::json::push_back(methods, method.first); - method_handlers[nmos::details::parse_nc_method_id(nmos::fields::nc::id(method.first))] = method.second; - } web::json::value events = value::array(); for (const auto& event : events_) { web::json::push_back(events, event); } - return { description, class_id, name, fixed_role, properties, methods, events, method_handlers }; + return { description, class_id, name, fixed_role, properties, methods_, events }; } } // create control class with fixed role @@ -38,7 +31,7 @@ namespace nmos // properties: vector of NcPropertyDescriptor which can be constructed using make_control_class_property // methods: vector of NcMethodDescriptor which can be constructed using make_nc_method_descriptor and the assoicated method handler // events: vector of NcEventDescriptor can be constructed using make_nc_event_descriptor - control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const utility::string_t& fixed_role, const std::vector& properties, const std::vector>& methods, const std::vector& events) + control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const utility::string_t& fixed_role, const std::vector& properties, const std::vector& methods, const std::vector& events) { using web::json::value; @@ -49,7 +42,7 @@ namespace nmos // properties: vector of NcPropertyDescriptor which can be constructed using make_control_class_property // methods: vector of NcMethodDescriptor which can be constructed using make_nc_method_descriptor and the assoicated method handler // events: vector of NcEventDescriptor can be constructed using make_nc_event_descriptor - control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const std::vector& properties, const std::vector>& methods, const std::vector& events) + control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const std::vector& properties, const std::vector& methods, const std::vector& events) { using web::json::value; @@ -98,15 +91,16 @@ namespace nmos return std::vector{}; }; - auto to_methods_vector = [](const web::json::value& method_data_array, const nmos::experimental::methods& method_handlers) + auto to_methods_vector = [](const web::json::value& nc_method_descriptors, const std::map& method_handlers) { - std::vector> methods; + // NcMethodDescriptor vs method_handler + std::vector methods; - if (!method_data_array.is_null()) + if (!nc_method_descriptors.is_null()) { - for (auto& method_data : method_data_array.as_array()) + for (const auto& nc_method_descriptor : nc_method_descriptors.as_array()) { - methods.push_back({ method_data, method_handlers.at(nmos::details::parse_nc_method_id(nmos::fields::nc::id(method_data))) }); + methods.push_back({ nc_method_descriptor, method_handlers.at(nmos::details::parse_nc_method_id(nmos::fields::nc::id(nc_method_descriptor))) }); } } return methods; diff --git a/Development/nmos/control_protocol_state.h b/Development/nmos/control_protocol_state.h index 54431fca8..a43d625e3 100644 --- a/Development/nmos/control_protocol_state.h +++ b/Development/nmos/control_protocol_state.h @@ -21,16 +21,14 @@ namespace nmos web::json::value fixed_role; web::json::value properties = web::json::value::array(); // array of NcPropertyDescriptor - web::json::value methods = web::json::value::array(); // array of NcMethodDescriptor + std::vector methods; // vector of NcMethodDescriptor and method_handler web::json::value events = web::json::value::array(); // array of NcEventDescriptor - nmos::experimental::methods method_handlers; // map of method handlers which are associated to this control_class (class_id), but not including its base class - control_class() : class_id({ 0 }) {} - control_class(utility::string_t description, nmos::nc_class_id class_id, nmos::nc_name name, web::json::value fixed_role, web::json::value properties, web::json::value methods, web::json::value events, nmos::experimental::methods method_handlers) + control_class(utility::string_t description, nmos::nc_class_id class_id, nmos::nc_name name, web::json::value fixed_role, web::json::value properties, std::vector methods, web::json::value events) : description(std::move(description)) , class_id(std::move(class_id)) , name(std::move(name)) @@ -38,7 +36,6 @@ namespace nmos , properties(std::move(properties)) , methods(std::move(methods)) , events(std::move(events)) - , method_handlers(std::move(method_handlers)) {} }; diff --git a/Development/nmos/control_protocol_utils.cpp b/Development/nmos/control_protocol_utils.cpp index 07260eb60..2923b189a 100644 --- a/Development/nmos/control_protocol_utils.cpp +++ b/Development/nmos/control_protocol_utils.cpp @@ -151,6 +151,9 @@ namespace nmos // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html bool datatype_constraints_validation(const web::json::value& data, const datatype_constraints_validation_parameters& params) { + // no constraints validation required + if (params.datatype_descriptor.is_null()) { return true; } + const auto& datatype_type = nmos::fields::nc::type(params.datatype_descriptor); // do NcDatatypeDescriptorPrimitive constraints validation @@ -287,6 +290,29 @@ namespace nmos // unsupport datatype_type, no validation is required return true; } + + // multiple levels of constraints validation + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html + bool constraints_validation(const web::json::value& data, const web::json::value& runtime_property_constraints, const web::json::value& property_constraints, const datatype_constraints_validation_parameters& params) + { + // do level 2 runtime property constraints validation + if (!runtime_property_constraints.is_null()) { return details::constraints_validation(data, runtime_property_constraints); } + + // do level 1 property constraints validation + if (!property_constraints.is_null()) { return details::constraints_validation(data, property_constraints); } + + // do level 0 datatype constraints validation + return details::datatype_constraints_validation(data, params); + } + + // method parameter constraints validation + bool method_parameter_constraints_validation(const web::json::value& data, const web::json::value& property_constraints, const datatype_constraints_validation_parameters& params) + { + using web::json::value; + + // do level 1 property constraints & level 0 datatype constraints validation + return constraints_validation(data, value::null(), property_constraints, params); + } } // is the given class_id a NcBlock @@ -562,17 +588,19 @@ namespace nmos }); } - // multiple levels of constraints validation - // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html - bool constraints_validation(const web::json::value& data, const web::json::value& runtime_property_constraints, const web::json::value& property_constraints, const datatype_constraints_validation_parameters& params) + // method parameters constraints validation + bool method_parameters_contraints_validation(const web::json::value& arguments, const web::json::value& nc_method_descriptor, get_control_protocol_datatype_handler get_control_protocol_datatype) { - // do level 2 runtime property constraints validation - if (!runtime_property_constraints.is_null()) { return details::constraints_validation(data, runtime_property_constraints); } - - // do level 1 property constraints validation - if (!property_constraints.is_null()) { return details::constraints_validation(data, property_constraints); } - - // do level 0 datatype constraints validation - return details::datatype_constraints_validation(data, params); + for (const auto& param : nmos::fields::nc::parameters(nc_method_descriptor)) + { + const auto& name = nmos::fields::nc::name(param); + const auto& constraints = nmos::fields::nc::constraints(param); + const auto& type_name = param.at(nmos::fields::nc::type_name); + if (!details::method_parameter_constraints_validation(arguments.at(name), constraints, { nmos::details::get_datatype_descriptor(type_name, get_control_protocol_datatype), get_control_protocol_datatype })) + { + return false; + } + } + return true; } } diff --git a/Development/nmos/control_protocol_utils.h b/Development/nmos/control_protocol_utils.h index 1718e01cc..34ad7c593 100644 --- a/Development/nmos/control_protocol_utils.h +++ b/Development/nmos/control_protocol_utils.h @@ -18,6 +18,18 @@ namespace nmos // get the datatype property constraints of a given type_name web::json::value get_datatype_constraints(const web::json::value& type_name, get_control_protocol_datatype_handler get_control_protocol_datatype); + + struct datatype_constraints_validation_parameters + { + web::json::value datatype_descriptor; + get_control_protocol_datatype_handler get_control_protocol_datatype; + }; + // multiple levels of constraints validation + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html + bool constraints_validation(const web::json::value& value, const web::json::value& runtime_property_constraints, const web::json::value& property_constraints, const datatype_constraints_validation_parameters& params); + + // method parameter constraints validation + bool method_parameter_constraints_validation(const web::json::value& data, const web::json::value& property_constraints, const datatype_constraints_validation_parameters& params); } // is the given class_id a NcBlock @@ -60,14 +72,8 @@ namespace nmos // find the control protocol resource which is assoicated with the given IS-04/IS-05/IS-08 resource id resources::const_iterator find_control_protocol_resource(resources& resources, type type, const id& id); - struct datatype_constraints_validation_parameters - { - web::json::value datatype_descriptor; - get_control_protocol_datatype_handler get_control_protocol_datatype; - }; - // multiple levels of constraints validation - // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html - bool constraints_validation(const web::json::value& value, const web::json::value& runtime_property_constraints, const web::json::value& property_constraints, const datatype_constraints_validation_parameters& params); + // method parameters constraints validation + bool method_parameters_contraints_validation(const web::json::value& arguments, const web::json::value& nc_method_descriptor, get_control_protocol_datatype_handler get_control_protocol_datatype); } #endif diff --git a/Development/nmos/control_protocol_ws_api.cpp b/Development/nmos/control_protocol_ws_api.cpp index beb54823d..06620a1fe 100644 --- a/Development/nmos/control_protocol_ws_api.cpp +++ b/Development/nmos/control_protocol_ws_api.cpp @@ -6,6 +6,7 @@ #include "nmos/api_utils.h" #include "nmos/control_protocol_resources.h" #include "nmos/control_protocol_resource.h" +#include "nmos/control_protocol_utils.h" #include "nmos/is12_versions.h" #include "nmos/json_schema.h" #include "nmos/model.h" @@ -245,6 +246,8 @@ namespace nmos // get arguments const auto& arguments = nmos::fields::nc::arguments(cmd); + value response; + auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); if (resources.end() != resource) { @@ -252,17 +255,28 @@ namespace nmos // find the relevent method handler to execute auto method = get_control_protocol_method(class_id, method_id); - if (method) + if (method.second) { - // execute the relevant method handler, then accumulating up their response to reponses - web::json::push_back(responses, method(resources, resource, handle, arguments, get_control_protocol_class, get_control_protocol_datatype, gate)); + // do method arguments constraints validation + if (method_parameters_contraints_validation(arguments, method.first, get_control_protocol_datatype)) + { + // execute the relevant method handler, then accumulating up their response to reponses + response = method.second(resources, resource, handle, arguments, nmos::fields::nc::is_deprecated(method.first), get_control_protocol_class, get_control_protocol_datatype, gate); + } + else + { + // invalid arguments + slog::log(gate, SLOG_FLF) << "invalid argument: " << arguments.serialize(); + response = make_control_protocol_message_response(handle, { nmos::nc_method_status::parameter_error }); + } } else { + // unknown methodId utility::stringstream_t ss; - ss << U("unsupported method id: ") << nmos::fields::nc::method_id(cmd).serialize(); - web::json::push_back(responses, - make_control_protocol_error_response(handle, { nc_method_status::method_not_implemented }, ss.str())); + ss << U("unsupported method_id: ") << nmos::fields::nc::method_id(cmd).serialize() + << U(" for control class class_id: ") << resource->data.at(nmos::fields::nc::class_id).serialize(); + response = make_control_protocol_error_response(handle, { nc_method_status::method_not_implemented }, ss.str()); } } else @@ -270,9 +284,10 @@ namespace nmos // resource not found for the given oid utility::stringstream_t ss; ss << U("unknown oid: ") << oid; - web::json::push_back(responses, - make_control_protocol_error_response(handle, { nc_method_status::bad_oid }, ss.str())); + response = make_control_protocol_error_response(handle, { nc_method_status::bad_oid }, ss.str()); } + // accumulating up response + web::json::push_back(responses, response); } // add command_response to the grain ready to transfer to the client in nmos::send_control_protocol_ws_messages_thread diff --git a/Development/nmos/test/control_protocol_test.cpp b/Development/nmos/test/control_protocol_test.cpp index 381433923..36c914809 100644 --- a/Development/nmos/test/control_protocol_test.cpp +++ b/Development/nmos/test/control_protocol_test.cpp @@ -796,121 +796,121 @@ BST_TEST_CASE(testConstraints) // string property constraints validation // runtime property constraints validation - const nmos::datatype_constraints_validation_parameters with_constraints_string_constraints_validation_params{ with_constraints_string_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; - BST_REQUIRE(nmos::constraints_validation(value::string(U("1234567890")), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params)); - BST_REQUIRE_EQUAL(nmos::constraints_validation(value::string(U("12345678901")), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(value::string(U("123456789A")), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params), false); - BST_REQUIRE(nmos::constraints_validation(value_of({ value::string(U("1234567890")), value::string(U("1234567890")) }), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params)); - BST_REQUIRE_EQUAL(nmos::constraints_validation(value_of({ value::string(U("1234567890")), value::string(U("12345678901")) }), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(value_of({ value::string(U("1234567890")), 1 }), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params), false); + const nmos::details::datatype_constraints_validation_parameters with_constraints_string_constraints_validation_params{ with_constraints_string_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + BST_REQUIRE(nmos::details::constraints_validation(value::string(U("1234567890")), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params)); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value::string(U("12345678901")), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value::string(U("123456789A")), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params), false); + BST_REQUIRE(nmos::details::constraints_validation(value_of({ value::string(U("1234567890")), value::string(U("1234567890")) }), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params)); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value_of({ value::string(U("1234567890")), value::string(U("12345678901")) }), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value_of({ value::string(U("1234567890")), 1 }), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params), false); // property constraints validation - BST_REQUIRE(nmos::constraints_validation(value::string(U("abcde")), value::null(), property_string_constraints, with_constraints_string_constraints_validation_params)); - BST_REQUIRE_EQUAL(nmos::constraints_validation(value::string(U("abcdef")), value::null(), property_string_constraints, with_constraints_string_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(value::string(U("abcd1")), value::null(), property_string_constraints, with_constraints_string_constraints_validation_params), false); - BST_REQUIRE(nmos::constraints_validation(value_of({ value::string(U("abcde")), value::string(U("abcde")) }), value::null(), property_string_constraints, with_constraints_string_constraints_validation_params)); - BST_REQUIRE_EQUAL(nmos::constraints_validation(value_of({ value::string(U("abcde")), value::string(U("abcdef")) }), value::null(), property_string_constraints, with_constraints_string_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(value_of({ value::string(U("abcde")), 1 }), value::null(), property_string_constraints, with_constraints_string_constraints_validation_params), false); + BST_REQUIRE(nmos::details::constraints_validation(value::string(U("abcde")), value::null(), property_string_constraints, with_constraints_string_constraints_validation_params)); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value::string(U("abcdef")), value::null(), property_string_constraints, with_constraints_string_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value::string(U("abcd1")), value::null(), property_string_constraints, with_constraints_string_constraints_validation_params), false); + BST_REQUIRE(nmos::details::constraints_validation(value_of({ value::string(U("abcde")), value::string(U("abcde")) }), value::null(), property_string_constraints, with_constraints_string_constraints_validation_params)); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value_of({ value::string(U("abcde")), value::string(U("abcdef")) }), value::null(), property_string_constraints, with_constraints_string_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value_of({ value::string(U("abcde")), 1 }), value::null(), property_string_constraints, with_constraints_string_constraints_validation_params), false); // datatype constraints validation - BST_REQUIRE(nmos::constraints_validation(value::string(U("1a")), value::null(), value::null(), with_constraints_string_constraints_validation_params)); - BST_REQUIRE_EQUAL(nmos::constraints_validation(value::string(U("1a2")), value::null(), value::null(), with_constraints_string_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(value::string(U("1*")), value::null(), value::null(), with_constraints_string_constraints_validation_params), false); - const nmos::datatype_constraints_validation_parameters no_constraints_string_constraints_validation_params{ no_constraints_string_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; - BST_REQUIRE(nmos::constraints_validation(value::string(U("1234567890-abcde-!\"£$%^&*()_+=")), value::null(), value::null(), no_constraints_string_constraints_validation_params)); + BST_REQUIRE(nmos::details::constraints_validation(value::string(U("1a")), value::null(), value::null(), with_constraints_string_constraints_validation_params)); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value::string(U("1a2")), value::null(), value::null(), with_constraints_string_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value::string(U("1*")), value::null(), value::null(), with_constraints_string_constraints_validation_params), false); + const nmos::details::datatype_constraints_validation_parameters no_constraints_string_constraints_validation_params{ no_constraints_string_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + BST_REQUIRE(nmos::details::constraints_validation(value::string(U("1234567890-abcde-!\"£$%^&*()_+=")), value::null(), value::null(), no_constraints_string_constraints_validation_params)); // number property constraints validation // runtime property constraints validation - const nmos::datatype_constraints_validation_parameters with_constraints_int32_constraints_validation_params{ with_constraints_int32_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; - BST_REQUIRE(nmos::constraints_validation(10, runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params)); - BST_REQUIRE(nmos::constraints_validation(1000, runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params)); - BST_REQUIRE_EQUAL(nmos::constraints_validation(9, runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(1001, runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params), false); - BST_REQUIRE(nmos::constraints_validation(value_of({ 10, 1000 }), runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params)); - BST_REQUIRE_EQUAL(nmos::constraints_validation(value_of({ 10, 1001 }), runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(value_of({ 10, value::string(U("a")) }), runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params), false); + const nmos::details::datatype_constraints_validation_parameters with_constraints_int32_constraints_validation_params{ with_constraints_int32_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + BST_REQUIRE(nmos::details::constraints_validation(10, runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params)); + BST_REQUIRE(nmos::details::constraints_validation(1000, runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params)); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(9, runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(1001, runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params), false); + BST_REQUIRE(nmos::details::constraints_validation(value_of({ 10, 1000 }), runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params)); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value_of({ 10, 1001 }), runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value_of({ 10, value::string(U("a")) }), runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params), false); // property constraints validation - BST_REQUIRE(nmos::constraints_validation(50, value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params)); - BST_REQUIRE(nmos::constraints_validation(500, value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params)); - BST_REQUIRE_EQUAL(nmos::constraints_validation(45, value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(505, value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(499, value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), false); - BST_REQUIRE(nmos::constraints_validation(value_of({ 50, 500 }), value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params)); - BST_REQUIRE_EQUAL(nmos::constraints_validation(value_of({ 49, 500 }), value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(value_of({ 50, 501 }), value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(value_of({ 45, 500 }), value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(value_of({ 50, value::string(U("a")) }), value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), false); + BST_REQUIRE(nmos::details::constraints_validation(50, value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params)); + BST_REQUIRE(nmos::details::constraints_validation(500, value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params)); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(45, value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(505, value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(499, value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), false); + BST_REQUIRE(nmos::details::constraints_validation(value_of({ 50, 500 }), value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params)); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value_of({ 49, 500 }), value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value_of({ 50, 501 }), value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value_of({ 45, 500 }), value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value_of({ 50, value::string(U("a")) }), value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), false); // datatype constraints validation - BST_REQUIRE(nmos::constraints_validation(100, value::null(), value::null(), with_constraints_int32_constraints_validation_params)); - BST_REQUIRE(nmos::constraints_validation(250, value::null(), value::null(), with_constraints_int32_constraints_validation_params)); - BST_REQUIRE_EQUAL(nmos::constraints_validation(90, value::null(), value::null(), with_constraints_int32_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(260, value::null(), value::null(), with_constraints_int32_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(99, value::null(), value::null(), with_constraints_int32_constraints_validation_params), false); + BST_REQUIRE(nmos::details::constraints_validation(100, value::null(), value::null(), with_constraints_int32_constraints_validation_params)); + BST_REQUIRE(nmos::details::constraints_validation(250, value::null(), value::null(), with_constraints_int32_constraints_validation_params)); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(90, value::null(), value::null(), with_constraints_int32_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(260, value::null(), value::null(), with_constraints_int32_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(99, value::null(), value::null(), with_constraints_int32_constraints_validation_params), false); // int16 datatype constraints validation - const nmos::datatype_constraints_validation_parameters no_constraints_int16_constraints_validation_params{ no_constraints_int16_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; - BST_REQUIRE_EQUAL(nmos::constraints_validation(int64_t(std::numeric_limits::min()) - 1, value::null(), value::null(), no_constraints_int16_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(int64_t(std::numeric_limits::max()) + 1, value::null(), value::null(), no_constraints_int16_constraints_validation_params), false); - BST_REQUIRE(nmos::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_int16_constraints_validation_params)); - BST_REQUIRE(nmos::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_int16_constraints_validation_params)); + const nmos::details::datatype_constraints_validation_parameters no_constraints_int16_constraints_validation_params{ no_constraints_int16_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(int64_t(std::numeric_limits::min()) - 1, value::null(), value::null(), no_constraints_int16_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(int64_t(std::numeric_limits::max()) + 1, value::null(), value::null(), no_constraints_int16_constraints_validation_params), false); + BST_REQUIRE(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_int16_constraints_validation_params)); + BST_REQUIRE(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_int16_constraints_validation_params)); // int32 datatype constraints validation - const nmos::datatype_constraints_validation_parameters no_constraints_int32_constraints_validation_params{ no_constraints_int32_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; - BST_REQUIRE_EQUAL(nmos::constraints_validation(int64_t(std::numeric_limits::min()) - 1, value::null(), value::null(), no_constraints_int32_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(int64_t(std::numeric_limits::max()) + 1, value::null(), value::null(), no_constraints_int32_constraints_validation_params), false); - BST_REQUIRE(nmos::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_int32_constraints_validation_params)); - BST_REQUIRE(nmos::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_int32_constraints_validation_params)); + const nmos::details::datatype_constraints_validation_parameters no_constraints_int32_constraints_validation_params{ no_constraints_int32_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(int64_t(std::numeric_limits::min()) - 1, value::null(), value::null(), no_constraints_int32_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(int64_t(std::numeric_limits::max()) + 1, value::null(), value::null(), no_constraints_int32_constraints_validation_params), false); + BST_REQUIRE(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_int32_constraints_validation_params)); + BST_REQUIRE(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_int32_constraints_validation_params)); // int64 datatype constraints validation - const nmos::datatype_constraints_validation_parameters no_constraints_int64_constraints_validation_params{ no_constraints_int64_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; - BST_REQUIRE_EQUAL(nmos::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_int64_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_int64_constraints_validation_params), false); - BST_REQUIRE(nmos::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_int64_constraints_validation_params)); - BST_REQUIRE(nmos::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_int64_constraints_validation_params)); + const nmos::details::datatype_constraints_validation_parameters no_constraints_int64_constraints_validation_params{ no_constraints_int64_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_int64_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_int64_constraints_validation_params), false); + BST_REQUIRE(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_int64_constraints_validation_params)); + BST_REQUIRE(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_int64_constraints_validation_params)); // uint16 datatype constraints validation - const nmos::datatype_constraints_validation_parameters no_constraints_uint16_constraints_validation_params{ no_constraints_uint16_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; - BST_REQUIRE_EQUAL(nmos::constraints_validation(-1, value::null(), value::null(), no_constraints_uint16_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(uint64_t(std::numeric_limits::max()) + 1, value::null(), value::null(), no_constraints_uint16_constraints_validation_params), false); - BST_REQUIRE(nmos::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_uint16_constraints_validation_params)); - BST_REQUIRE(nmos::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_uint16_constraints_validation_params)); + const nmos::details::datatype_constraints_validation_parameters no_constraints_uint16_constraints_validation_params{ no_constraints_uint16_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(-1, value::null(), value::null(), no_constraints_uint16_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(uint64_t(std::numeric_limits::max()) + 1, value::null(), value::null(), no_constraints_uint16_constraints_validation_params), false); + BST_REQUIRE(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_uint16_constraints_validation_params)); + BST_REQUIRE(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_uint16_constraints_validation_params)); // uint32 datatype constraints validation - const nmos::datatype_constraints_validation_parameters no_constraints_uint32_constraints_validation_params{ no_constraints_uint32_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; - BST_REQUIRE_EQUAL(nmos::constraints_validation(-1, value::null(), value::null(), no_constraints_uint32_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(uint64_t(std::numeric_limits::max()) + 1, value::null(), value::null(), no_constraints_uint32_constraints_validation_params), false); - BST_REQUIRE(nmos::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_uint32_constraints_validation_params)); - BST_REQUIRE(nmos::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_uint32_constraints_validation_params)); + const nmos::details::datatype_constraints_validation_parameters no_constraints_uint32_constraints_validation_params{ no_constraints_uint32_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(-1, value::null(), value::null(), no_constraints_uint32_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(uint64_t(std::numeric_limits::max()) + 1, value::null(), value::null(), no_constraints_uint32_constraints_validation_params), false); + BST_REQUIRE(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_uint32_constraints_validation_params)); + BST_REQUIRE(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_uint32_constraints_validation_params)); // uint64 datatype constraints validation - const nmos::datatype_constraints_validation_parameters no_constraints_uint64_constraints_validation_params{ no_constraints_uint64_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; - BST_REQUIRE_EQUAL(nmos::constraints_validation(-1, value::null(), value::null(), no_constraints_uint64_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_int64_constraints_validation_params), false); - BST_REQUIRE(nmos::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_uint64_constraints_validation_params)); - BST_REQUIRE(nmos::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_uint64_constraints_validation_params)); + const nmos::details::datatype_constraints_validation_parameters no_constraints_uint64_constraints_validation_params{ no_constraints_uint64_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(-1, value::null(), value::null(), no_constraints_uint64_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_int64_constraints_validation_params), false); + BST_REQUIRE(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_uint64_constraints_validation_params)); + BST_REQUIRE(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_uint64_constraints_validation_params)); // float32 datatype constraints validation - const nmos::datatype_constraints_validation_parameters no_constraints_float32_constraints_validation_params{ no_constraints_float32_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; - BST_REQUIRE_EQUAL(nmos::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_float32_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_float32_constraints_validation_params), false); - BST_REQUIRE(nmos::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_float32_constraints_validation_params)); - BST_REQUIRE(nmos::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_float32_constraints_validation_params)); + const nmos::details::datatype_constraints_validation_parameters no_constraints_float32_constraints_validation_params{ no_constraints_float32_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_float32_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_float32_constraints_validation_params), false); + BST_REQUIRE(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_float32_constraints_validation_params)); + BST_REQUIRE(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_float32_constraints_validation_params)); // float64 datatype constraints validation - const nmos::datatype_constraints_validation_parameters no_constraints_float64_constraints_validation_params{ no_constraints_float64_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; - BST_REQUIRE_EQUAL(nmos::constraints_validation(1000, value::null(), value::null(), no_constraints_float64_constraints_validation_params), false); - BST_REQUIRE(nmos::constraints_validation(1000.0, value::null(), value::null(), no_constraints_float64_constraints_validation_params)); - BST_REQUIRE(nmos::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_float64_constraints_validation_params)); - BST_REQUIRE(nmos::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_float64_constraints_validation_params)); + const nmos::details::datatype_constraints_validation_parameters no_constraints_float64_constraints_validation_params{ no_constraints_float64_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(1000, value::null(), value::null(), no_constraints_float64_constraints_validation_params), false); + BST_REQUIRE(nmos::details::constraints_validation(1000.0, value::null(), value::null(), no_constraints_float64_constraints_validation_params)); + BST_REQUIRE(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_float64_constraints_validation_params)); + BST_REQUIRE(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_float64_constraints_validation_params)); // enum property datatype constraints validation - const nmos::datatype_constraints_validation_parameters enum_constraints_validation_params{ enum_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; - BST_REQUIRE(nmos::constraints_validation(enum_value::foo, value::null(), value::null(), enum_constraints_validation_params)); - BST_REQUIRE_EQUAL(nmos::constraints_validation(4, value::null(), value::null(), enum_constraints_validation_params), false); + const nmos::details::datatype_constraints_validation_parameters enum_constraints_validation_params{ enum_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + BST_REQUIRE(nmos::details::constraints_validation(enum_value::foo, value::null(), value::null(), enum_constraints_validation_params)); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(4, value::null(), value::null(), enum_constraints_validation_params), false); // invalid data vs primitive datatype constraints - const nmos::datatype_constraints_validation_parameters no_constraints_string_seq_constraints_validation_params{ no_constraints_string_seq_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; - BST_REQUIRE(nmos::constraints_validation(value_of({ value::string(U("1234567890-abcde-!\"£$%^&*()_+=")) }), value::null(), value::null(), no_constraints_string_seq_constraints_validation_params)); - BST_REQUIRE(nmos::constraints_validation(value_of({ value::string(U("1234567890-abcde-!\"£$%^&*()_+=")), value::string(U("1234567890-abcde-!\"£$%^&*()_+=")) }), value::null(), value::null(), no_constraints_string_seq_constraints_validation_params)); - BST_REQUIRE_EQUAL(nmos::constraints_validation(value_of({ 1 }), value::null(), value::null(), no_constraints_string_seq_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(1, value::null(), value::null(), no_constraints_string_seq_constraints_validation_params), false); - const nmos::datatype_constraints_validation_parameters no_constraints_int32_seq_constraints_validation_params{ no_constraints_int32_seq_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; - BST_REQUIRE_EQUAL(nmos::constraints_validation(value_of({ value::string(U("1234567890-abcde-!\"£$%^&*()_+=")) }), value::null(), value::null(), no_constraints_int32_seq_constraints_validation_params), false); - BST_REQUIRE(nmos::constraints_validation(value_of({ 1 }), value::null(), value::null(), no_constraints_int32_seq_constraints_validation_params)); - BST_REQUIRE(nmos::constraints_validation(value_of({ 1, 2 }), value::null(), value::null(), no_constraints_int32_seq_constraints_validation_params)); - BST_REQUIRE_EQUAL(nmos::constraints_validation(value_of({ value::string(U("1234567890-abcde-!\"£$%^&*()_+=")) }), value::null(), value::null(), no_constraints_int32_seq_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(value::string(U("1234567890-abcde-!\"£$%^&*()_+=")), value::null(), value::null(), no_constraints_int32_seq_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(value_of({ 1, 2 }), value::null(), value::null(), with_constraints_int32_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(value_of({ 1, 2 }), value::null(), value::null(), with_constraints_string_constraints_validation_params), false); + const nmos::details::datatype_constraints_validation_parameters no_constraints_string_seq_constraints_validation_params{ no_constraints_string_seq_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + BST_REQUIRE(nmos::details::constraints_validation(value_of({ value::string(U("1234567890-abcde-!\"£$%^&*()_+=")) }), value::null(), value::null(), no_constraints_string_seq_constraints_validation_params)); + BST_REQUIRE(nmos::details::constraints_validation(value_of({ value::string(U("1234567890-abcde-!\"£$%^&*()_+=")), value::string(U("1234567890-abcde-!\"£$%^&*()_+=")) }), value::null(), value::null(), no_constraints_string_seq_constraints_validation_params)); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value_of({ 1 }), value::null(), value::null(), no_constraints_string_seq_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(1, value::null(), value::null(), no_constraints_string_seq_constraints_validation_params), false); + const nmos::details::datatype_constraints_validation_parameters no_constraints_int32_seq_constraints_validation_params{ no_constraints_int32_seq_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value_of({ value::string(U("1234567890-abcde-!\"£$%^&*()_+=")) }), value::null(), value::null(), no_constraints_int32_seq_constraints_validation_params), false); + BST_REQUIRE(nmos::details::constraints_validation(value_of({ 1 }), value::null(), value::null(), no_constraints_int32_seq_constraints_validation_params)); + BST_REQUIRE(nmos::details::constraints_validation(value_of({ 1, 2 }), value::null(), value::null(), no_constraints_int32_seq_constraints_validation_params)); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value_of({ value::string(U("1234567890-abcde-!\"£$%^&*()_+=")) }), value::null(), value::null(), no_constraints_int32_seq_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value::string(U("1234567890-abcde-!\"£$%^&*()_+=")), value::null(), value::null(), no_constraints_int32_seq_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value_of({ 1, 2 }), value::null(), value::null(), with_constraints_int32_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value_of({ 1, 2 }), value::null(), value::null(), with_constraints_string_constraints_validation_params), false); // struct property datatype constraints validation const auto good_struct = value_of({ @@ -1441,24 +1441,24 @@ BST_TEST_CASE(testConstraints) }) }) } }); - const nmos::datatype_constraints_validation_parameters struct_constraints_validation_params{ struct_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; - BST_REQUIRE(nmos::constraints_validation(good_struct, value::null(), value::null(), struct_constraints_validation_params)); - BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct1, value::null(), value::null(), struct_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct2, value::null(), value::null(), struct_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct2_1, value::null(), value::null(), struct_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct2_2, value::null(), value::null(), struct_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct2_3, value::null(), value::null(), struct_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct2_4, value::null(), value::null(), struct_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct2_5, value::null(), value::null(), struct_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct2_5_1, value::null(), value::null(), struct_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct2_5_2, value::null(), value::null(), struct_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct2_5_3, value::null(), value::null(), struct_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct2_6, value::null(), value::null(), struct_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct2_6_1, value::null(), value::null(), struct_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct2_6_2, value::null(), value::null(), struct_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct2_6_3, value::null(), value::null(), struct_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct2_7, value::null(), value::null(), struct_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct2_7_1, value::null(), value::null(), struct_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct2_7_2, value::null(), value::null(), struct_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::constraints_validation(bad_struct2_7_3, value::null(), value::null(), struct_constraints_validation_params), false); + const nmos::details::datatype_constraints_validation_parameters struct_constraints_validation_params{ struct_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + BST_REQUIRE(nmos::details::constraints_validation(good_struct, value::null(), value::null(), struct_constraints_validation_params)); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct1, value::null(), value::null(), struct_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct2, value::null(), value::null(), struct_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct2_1, value::null(), value::null(), struct_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct2_2, value::null(), value::null(), struct_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct2_3, value::null(), value::null(), struct_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct2_4, value::null(), value::null(), struct_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct2_5, value::null(), value::null(), struct_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct2_5_1, value::null(), value::null(), struct_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct2_5_2, value::null(), value::null(), struct_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct2_5_3, value::null(), value::null(), struct_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct2_6, value::null(), value::null(), struct_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct2_6_1, value::null(), value::null(), struct_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct2_6_2, value::null(), value::null(), struct_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct2_6_3, value::null(), value::null(), struct_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct2_7, value::null(), value::null(), struct_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct2_7_1, value::null(), value::null(), struct_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct2_7_2, value::null(), value::null(), struct_constraints_validation_params), false); + BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct2_7_3, value::null(), value::null(), struct_constraints_validation_params), false); } From 65e8ebbab15f41a55767e38f02d074c37849adf5 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Mon, 20 Nov 2023 12:28:39 +0000 Subject: [PATCH 079/106] Add comments --- Development/nmos/control_protocol_ws_api.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Development/nmos/control_protocol_ws_api.cpp b/Development/nmos/control_protocol_ws_api.cpp index 06620a1fe..3660a6d06 100644 --- a/Development/nmos/control_protocol_ws_api.cpp +++ b/Development/nmos/control_protocol_ws_api.cpp @@ -228,6 +228,7 @@ namespace nmos const auto msg_type = nmos::fields::nc::message_type(message); switch (msg_type) { + // See https://specs.amwa.tv/is-12/branches/v1.0.x/docs/Protocol_messaging.html#command-message-type case ncp_message_type::command: { // validate command-message @@ -299,6 +300,7 @@ namespace nmos }); } break; + // See https://specs.amwa.tv/is-12/branches/v1.0.x/docs/Protocol_messaging.html#subscription-message-type case ncp_message_type::subscription: { // validate subscription-message From 092519e58e042cd22e155404288a1a1ef54384d1 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Mon, 20 Nov 2023 12:39:05 +0000 Subject: [PATCH 080/106] No arguments object to those methods which do not require any arguments --- Development/nmos/control_protocol_utils.cpp | 5 +++++ Development/nmos/json_fields.h | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Development/nmos/control_protocol_utils.cpp b/Development/nmos/control_protocol_utils.cpp index 2923b189a..529ced833 100644 --- a/Development/nmos/control_protocol_utils.cpp +++ b/Development/nmos/control_protocol_utils.cpp @@ -596,6 +596,11 @@ namespace nmos const auto& name = nmos::fields::nc::name(param); const auto& constraints = nmos::fields::nc::constraints(param); const auto& type_name = param.at(nmos::fields::nc::type_name); + if (arguments.is_null() || !arguments.has_field(name)) + { + // missing argument parameter + return false; + } if (!details::method_parameter_constraints_validation(arguments.at(name), constraints, { nmos::details::get_datatype_descriptor(type_name, get_control_protocol_datatype), get_control_protocol_datatype })) { return false; diff --git a/Development/nmos/json_fields.h b/Development/nmos/json_fields.h index 12bfa9bbf..aab74e70d 100644 --- a/Development/nmos/json_fields.h +++ b/Development/nmos/json_fields.h @@ -238,10 +238,10 @@ namespace nmos // for control_protocol_ws_api commands const web::json::field_as_array commands{ U("commands") }; - const web::json::field_as_array subscriptions{ U("subscriptions")}; + const web::json::field_as_array subscriptions{ U("subscriptions") }; const web::json::field_as_integer oid{ U("oid") }; const web::json::field_as_value method_id{ U("methodId") }; - const web::json::field_as_value arguments{ U("arguments") }; + const web::json::field_as_value_or arguments{ U("arguments"), {} }; const web::json::field_as_value id{ U("id") }; const web::json::field_as_integer level{ U("level") }; const web::json::field_as_integer index{ U("index") }; From 14aa16f00af2fea6425fa97ca85ff27825d9d31a Mon Sep 17 00:00:00 2001 From: lo-simon Date: Mon, 20 Nov 2023 13:49:21 +0000 Subject: [PATCH 081/106] Add deprecated property and deprecated method to Example Control Class --- .../nmos-cpp-node/node_implementation.cpp | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/Development/nmos-cpp-node/node_implementation.cpp b/Development/nmos-cpp-node/node_implementation.cpp index cd27d1f04..035400aac 100644 --- a/Development/nmos-cpp-node/node_implementation.cpp +++ b/Development/nmos-cpp-node/node_implementation.cpp @@ -954,6 +954,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr const web::json::field_as_number enum_property{ U("enumProperty") }; const web::json::field_as_string string_property{ U("stringProperty") }; const web::json::field_as_number number_property{ U("numberProperty") }; + const web::json::field_as_number deprecated_number_property{ U("deprecatedNumberProperty") }; const web::json::field_as_bool boolean_property{ U("booleanProperty") }; const web::json::field_as_value object_property{ U("objectProperty") }; const web::json::field_as_number method_no_args_count{ U("methodNoArgsCount") }; @@ -990,29 +991,30 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr // create "Example numeric property" with level 1: property constraints, See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html // use nmos::details::make_nc_parameter_constraints_number to create property constraints nmos::experimental::make_control_class_property(U("Example numeric property"), { 3, 3 }, number_property, U("NcUint64"), false, false, false, false, make_number_example_argument_constraints()), - nmos::experimental::make_control_class_property(U("Example boolean property"), { 3, 4 }, boolean_property, U("NcBoolean")), - nmos::experimental::make_control_class_property(U("Example object property"), { 3, 5 }, object_property, U("ExampleDataType")), - nmos::experimental::make_control_class_property(U("Method no args invoke counter"), { 3, 6 }, method_no_args_count, U("NcUint64"), true), - nmos::experimental::make_control_class_property(U("Method simple args invoke counter"), { 3, 7 }, method_simple_args_count, U("NcUint64"), true), - nmos::experimental::make_control_class_property(U("Method obj arg invoke counter"), { 3, 8 }, method_object_arg_count, U("NcUint64"), true), + nmos::experimental::make_control_class_property(U("Example deprecated numeric property"), { 3, 4 }, deprecated_number_property, U("NcUint64"), false, false, false, true, make_number_example_argument_constraints()), + nmos::experimental::make_control_class_property(U("Example boolean property"), { 3, 5 }, boolean_property, U("NcBoolean")), + nmos::experimental::make_control_class_property(U("Example object property"), { 3, 6 }, object_property, U("ExampleDataType")), + nmos::experimental::make_control_class_property(U("Example method no args invoke counter"), { 3, 7 }, method_no_args_count, U("NcUint64"), true), + nmos::experimental::make_control_class_property(U("Example method simple args invoke counter"), { 3, 8 }, method_simple_args_count, U("NcUint64"), true), + nmos::experimental::make_control_class_property(U("Example method obj arg invoke counter"), { 3, 9 }, method_object_arg_count, U("NcUint64"), true), // create "Example sequence string property" with level 1: property constraints, See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html // use nmos::details::make_nc_parameter_constraints_string to create sequence property constraints - nmos::experimental::make_control_class_property(U("Example string sequence property"), { 3, 9 }, string_sequence, U("NcString"), false, false, true, false, make_string_example_argument_constraints()), - nmos::experimental::make_control_class_property(U("Example boolean sequence property"), { 3, 10 }, boolean_sequence, U("NcBoolean"), false, false, true), - nmos::experimental::make_control_class_property(U("Example enum sequence property"), { 3, 11 }, enum_sequence, U("ExampleEnum"), false, false, true), + nmos::experimental::make_control_class_property(U("Example string sequence property"), { 3, 10 }, string_sequence, U("NcString"), false, false, true, false, make_string_example_argument_constraints()), + nmos::experimental::make_control_class_property(U("Example boolean sequence property"), { 3, 11 }, boolean_sequence, U("NcBoolean"), false, false, true), + nmos::experimental::make_control_class_property(U("Example enum sequence property"), { 3, 12 }, enum_sequence, U("ExampleEnum"), false, false, true), // create "Example sequence numeric property" with level 1: property constraints, See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html // use nmos::details::make_nc_parameter_constraints_number to create sequence property constraints - nmos::experimental::make_control_class_property(U("Example number sequence property"), { 3, 12 }, number_sequence, U("NcUint64"), false, false, true, false, make_number_example_argument_constraints()), - nmos::experimental::make_control_class_property(U("Example object sequence property"), { 3, 13 }, object_sequence, U("ExampleDataType"), false, false, true) + nmos::experimental::make_control_class_property(U("Example number sequence property"), { 3, 13 }, number_sequence, U("NcUint64"), false, false, true, false, make_number_example_argument_constraints()), + nmos::experimental::make_control_class_property(U("Example object sequence property"), { 3, 14 }, object_sequence, U("ExampleDataType"), false, false, true) }; - auto example_method_with_no_args = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, const web::json::value& nc_method_descriptor, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) + auto example_method_with_no_args = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... slog::log(gate, SLOG_FLF) << "Executing the example method with no arguments"; - return nmos::make_control_protocol_message_response(handle, { nmos::fields::nc::is_deprecated(nc_method_descriptor) ? nmos::nc_method_status::method_deprecated : nmos::nc_method_status::ok }); + return nmos::make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::nc_method_status::ok }); }; auto example_method_with_simple_args = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) { @@ -1036,7 +1038,8 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr std::vector example_control_methods = { { nmos::experimental::make_control_class_method(U("Example method with no arguments"), { 3, 1 }, U("MethodNoArgs"), U("NcMethodResult"), {}, false), example_method_with_no_args }, - { nmos::experimental::make_control_class_method(U("Example method with simple arguments"), { 3, 2 }, U("MethodSimpleArgs"), U("NcMethodResult"), + { nmos::experimental::make_control_class_method(U("Example deprecated method with no arguments"), { 3, 2 }, U("MethodNoArgs"), U("NcMethodResult"), {}, true), example_method_with_no_args }, + { nmos::experimental::make_control_class_method(U("Example method with simple arguments"), { 3, 3 }, U("MethodSimpleArgs"), U("NcMethodResult"), { nmos::details::make_nc_parameter_descriptor(U("Enum example argument"), enum_arg, U("ExampleEnum"), false, false, value::null()), nmos::details::make_nc_parameter_descriptor(U("String example argument"), string_arg, U("NcString"), false, false, make_string_example_argument_constraints()), // e.g. include method property constraints @@ -1045,7 +1048,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr }, false), example_method_with_simple_args }, - { nmos::experimental::make_control_class_method(U("Example method with object argument"), { 3, 3 }, U("MethodObjectArg"), U("NcMethodResult"), + { nmos::experimental::make_control_class_method(U("Example method with object argument"), { 3, 4 }, U("MethodObjectArg"), U("NcMethodResult"), { nmos::details::make_nc_parameter_descriptor(U("Object example argument"), obj_arg, U("ExampleDataType"), false, false, value::null()) }, @@ -1114,6 +1117,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr example_enum enum_property_ = example_enum::Undefined, const utility::string_t& string_property_ = U(""), uint64_t number_property_ = 0, + uint64_t deprecated_number_property_ = 0, bool boolean_property_ = true, const value& object_property_ = value::null(), uint64_t method_no_args_count_ = 0, @@ -1129,6 +1133,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr data[enum_property] = value::number(enum_property_); data[string_property] = value::string(string_property_); data[number_property] = value::number(number_property_); + data[deprecated_number_property] = value::number(deprecated_number_property_); data[boolean_property] = value::boolean(boolean_property_); data[object_property] = object_property_; data[method_no_args_count] = value::number(method_no_args_count_); @@ -1233,6 +1238,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr example_enum::Undefined, U("test"), 3, + 10, false, make_example_datatype(example_enum::Undefined, U("default"), 5, false), 0, From 0bed427b470084c262093d5769c58b672dee2bbf Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 21 Nov 2023 00:33:25 +0000 Subject: [PATCH 082/106] Add logging for contraints validation --- Development/nmos/control_protocol_methods.cpp | 83 +++--- Development/nmos/control_protocol_utils.cpp | 240 ++++++++++-------- Development/nmos/control_protocol_utils.h | 17 +- Development/nmos/control_protocol_ws_api.cpp | 10 +- .../nmos/test/control_protocol_test.cpp | 204 +++++++-------- 5 files changed, 302 insertions(+), 252 deletions(-) diff --git a/Development/nmos/control_protocol_methods.cpp b/Development/nmos/control_protocol_methods.cpp index ae29aa632..bfde62701 100644 --- a/Development/nmos/control_protocol_methods.cpp +++ b/Development/nmos/control_protocol_methods.cpp @@ -62,23 +62,26 @@ namespace nmos return make_control_protocol_message_response(handle, { nc_method_status::parameter_error }); } - // do property constraints validation - if (!val.is_null()) + try { - if (!nmos::details::constraints_validation(val, get_runtime_property_constraints(property_id_, resource->data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), { get_datatype_descriptor(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype), get_control_protocol_datatype })) + // do property constraints validation + nmos::details::constraints_validation(val, get_runtime_property_constraints(property_id_, resource->data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), { get_datatype_descriptor(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype), get_control_protocol_datatype }); + + // update property + modify_control_protocol_resource(resources, resource->id, [&](nmos::resource& resource) { - return make_control_protocol_message_response(handle, { nc_method_status::parameter_error }); - } - } + resource.data[nmos::fields::nc::name(property)] = val; - // update property - modify_control_protocol_resource(resources, resource->id, [&](nmos::resource& resource) - { - resource.data[nmos::fields::nc::name(property)] = val; + }, make_propertry_changed_event(nmos::fields::nc::oid(resource->data), { { property_id_, nc_property_change_type::type::value_changed, val } })); - }, make_propertry_changed_event(nmos::fields::nc::oid(resource->data), { { property_id_, nc_property_change_type::type::value_changed, val } })); + return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }); + } + catch (const nmos::control_protocol_exception& e) + { + slog::log(gate, SLOG_FLF) << "Set property: " << property_id.serialize() << " value: " << val.serialize() << " error: " << e.what(); - return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }); + return make_control_protocol_message_response(handle, { nc_method_status::parameter_error }); + } } // unknown property @@ -161,20 +164,26 @@ namespace nmos if (data.as_array().size() > (size_t)index) { - // do property constraints validation - if (!nmos::details::constraints_validation(val, get_runtime_property_constraints(property_id_, resource->data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), { get_datatype_descriptor(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype), get_control_protocol_datatype })) + try { - return make_control_protocol_message_response(handle, { nc_method_status::parameter_error }); - } + // do property constraints validation + nmos::details::constraints_validation(val, get_runtime_property_constraints(property_id_, resource->data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), { get_datatype_descriptor(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype), get_control_protocol_datatype }); - // update property - modify_control_protocol_resource(resources, resource->id, [&](nmos::resource& resource) - { - resource.data[nmos::fields::nc::name(property)][index] = val; + // update property + modify_control_protocol_resource(resources, resource->id, [&](nmos::resource& resource) + { + resource.data[nmos::fields::nc::name(property)][index] = val; - }, make_propertry_changed_event(nmos::fields::nc::oid(resource->data), { { property_id_, nc_property_change_type::type::sequence_item_changed, val, nc_id(index) } })); + }, make_propertry_changed_event(nmos::fields::nc::oid(resource->data), { { property_id_, nc_property_change_type::type::sequence_item_changed, val, nc_id(index) } })); - return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }); + return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }); + } + catch (const nmos::control_protocol_exception& e) + { + slog::log(gate, SLOG_FLF) << "Set sequence item: " << property_id.serialize() << " index: " << index << " value: " << val.serialize() << " error: " << e.what(); + + return make_control_protocol_message_response(handle, { nc_method_status::parameter_error }); + } } // out of bound @@ -223,22 +232,28 @@ namespace nmos const nc_id sequence_item_index = data.is_null() ? 0 : nc_id(data.as_array().size()); - // do property constraints validation - if (!nmos::details::constraints_validation(val, get_runtime_property_constraints(property_id_, resource->data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), { get_datatype_descriptor(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype), get_control_protocol_datatype })) + try { - return make_control_protocol_message_response(handle, { nc_method_status::parameter_error }); - } + // do property constraints validation + nmos::details::constraints_validation(val, get_runtime_property_constraints(property_id_, resource->data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), { get_datatype_descriptor(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype), get_control_protocol_datatype }); - // update property - modify_control_protocol_resource(resources, resource->id, [&](nmos::resource& resource) - { - auto& sequence = resource.data[nmos::fields::nc::name(property)]; - if (data.is_null()) { sequence = value::array(); } - web::json::push_back(sequence, val); + // update property + modify_control_protocol_resource(resources, resource->id, [&](nmos::resource& resource) + { + auto& sequence = resource.data[nmos::fields::nc::name(property)]; + if (data.is_null()) { sequence = value::array(); } + web::json::push_back(sequence, val); - }, make_propertry_changed_event(nmos::fields::nc::oid(resource->data), { { property_id_, nc_property_change_type::type::sequence_item_added, val, sequence_item_index } })); + }, make_propertry_changed_event(nmos::fields::nc::oid(resource->data), { { property_id_, nc_property_change_type::type::sequence_item_added, val, sequence_item_index } })); - return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }, sequence_item_index); + return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }, sequence_item_index); + } + catch (const nmos::control_protocol_exception& e) + { + slog::log(gate, SLOG_FLF) << "Add sequence item: " << property_id.serialize() << " value: " << val.serialize() << " error: " << e.what(); + + return make_control_protocol_message_response(handle, { nc_method_status::parameter_error }); + } } // unknown property diff --git a/Development/nmos/control_protocol_utils.cpp b/Development/nmos/control_protocol_utils.cpp index 529ced833..1a0814530 100644 --- a/Development/nmos/control_protocol_utils.cpp +++ b/Development/nmos/control_protocol_utils.cpp @@ -74,10 +74,10 @@ namespace nmos return value::null(); } - // constraints validation + // constraints validation, may throw nmos::control_protocol_exception // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsnumber // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsstring - bool constraints_validation(const web::json::value& data, const web::json::value& constraints) + void constraints_validation(const web::json::value& data, const web::json::value& constraints) { auto parameter_constraints_validation = [&constraints](const web::json::value& value) { @@ -85,74 +85,83 @@ namespace nmos // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsnumber if (constraints.has_field(nmos::fields::nc::step) && !nmos::fields::nc::step(constraints).is_null()) { - if (!value.is_integer()) { return false; } + if (value.is_null()) { throw control_protocol_exception("value is null"); } + + if (!value.is_integer()) { throw control_protocol_exception("value is not an integer"); } const auto step = nmos::fields::nc::step(constraints).as_double(); - if (step <= 0) { return false; } + if (step <= 0) { throw control_protocol_exception("step is not a positive integer"); } const auto value_double = value.as_double(); if (constraints.has_field(nmos::fields::nc::minimum) && !nmos::fields::nc::minimum(constraints).is_null()) { auto min = nmos::fields::nc::minimum(constraints).as_double(); - if (0 != std::fmod(value_double - min, step)) { return false; } + if (0 != std::fmod(value_double - min, step)) { throw control_protocol_exception("value is not divisible by step"); } } else if (constraints.has_field(nmos::fields::nc::maximum) && !nmos::fields::nc::maximum(constraints).is_null()) { auto max = nmos::fields::nc::maximum(constraints).as_double(); - if (0 != std::fmod(max - value_double, step)) { return false; } + if (0 != std::fmod(max - value_double, step)) { throw control_protocol_exception("value is not divisible by step"); } } else { - if (0 != std::fmod(value_double, step)) { return false; } + if (0 != std::fmod(value_double, step)) { throw control_protocol_exception("value is not divisible by step"); } } } if (constraints.has_field(nmos::fields::nc::minimum) && !nmos::fields::nc::minimum(constraints).is_null()) { - if (!value.is_integer() || value.as_double() < nmos::fields::nc::minimum(constraints).as_double()) { return false; } + if (value.is_null()) { throw control_protocol_exception("value is null"); } + + if (!value.is_integer() || value.as_double() < nmos::fields::nc::minimum(constraints).as_double()) { throw control_protocol_exception("value is less than minimum"); } } if (constraints.has_field(nmos::fields::nc::maximum) && !nmos::fields::nc::maximum(constraints).is_null()) { - if (!value.is_integer() || value.as_double() > nmos::fields::nc::maximum(constraints).as_double()) { return false; } + if (value.is_null()) { throw control_protocol_exception("value is null"); } + + if (!value.is_integer() || value.as_double() > nmos::fields::nc::maximum(constraints).as_double()) { throw control_protocol_exception("value is greater than maximum"); } } // is string constraints // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncparameterconstraintsstring if (constraints.has_field(nmos::fields::nc::max_characters) && !constraints.at(nmos::fields::nc::max_characters).is_null()) { + if (value.is_null()) { throw control_protocol_exception("value is null"); } + const size_t max_characters = nmos::fields::nc::max_characters(constraints); - if (!value.is_string() || value.as_string().length() > max_characters) { return false; } + if (!value.is_string() || value.as_string().length() > max_characters) { throw control_protocol_exception("value is longer than maximum characters"); } } if (constraints.has_field(nmos::fields::nc::pattern) && !constraints.at(nmos::fields::nc::pattern).is_null()) { - if (!value.is_string()) { return false; } + if (value.is_null()) { throw control_protocol_exception("value is null"); } + + if (!value.is_string()) { throw control_protocol_exception("value is not a string"); } const auto value_string = utility::us2s(value.as_string()); bst::regex pattern(utility::us2s(nmos::fields::nc::pattern(constraints))); - if (!bst::regex_match(value_string, pattern)) { return false; } + if (!bst::regex_match(value_string, pattern)) { throw control_protocol_exception("value dose not match the pattern"); } } // reaching here, parameter validation successfully - return true; }; if (data.is_array()) { for (const auto& value : data.as_array()) { - if (!parameter_constraints_validation(value)) { return false; } + parameter_constraints_validation(value); } - // validation successfully - return true; } - - return parameter_constraints_validation(data); + else + { + parameter_constraints_validation(data); + } } - // level 0 datatype constraints validation + // level 0 datatype constraints validation, may throw nmos::control_protocol_exception // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html - bool datatype_constraints_validation(const web::json::value& data, const datatype_constraints_validation_parameters& params) + void datatype_constraints_validation(const web::json::value& data, const datatype_constraints_validation_parameters& params) { // no constraints validation required - if (params.datatype_descriptor.is_null()) { return true; } + if (params.datatype_descriptor.is_null()) { return; } const auto& datatype_type = nmos::fields::nc::type(params.datatype_descriptor); @@ -161,57 +170,67 @@ namespace nmos { // hmm, for the primitive type, it should not have datatype constraints specified via the datatype_descriptor but just in case const auto& datatype_constraints = nmos::fields::nc::constraints(params.datatype_descriptor); - if (!datatype_constraints.is_null()) - { - return constraints_validation(data, datatype_constraints); - } - - auto primitive_validation = [](const nc_name& name, const web::json::value& value) + if (datatype_constraints.is_null()) { - auto is_int16 = [](int32_t value) - { - return value >= (std::numeric_limits::min)() - && value <= (std::numeric_limits::max)(); - }; - auto is_uint16 = [](uint32_t value) + auto primitive_validation = [](const nc_name& name, const web::json::value& value) { - return value >= (std::numeric_limits::min)() - && value <= (std::numeric_limits::max)(); - }; - auto is_float32 = [](double value) - { - return value >= (std::numeric_limits::min)() - && value <= (std::numeric_limits::max)(); + auto is_int16 = [](int32_t value) + { + return value >= (std::numeric_limits::min)() + && value <= (std::numeric_limits::max)(); + }; + auto is_uint16 = [](uint32_t value) + { + return value >= (std::numeric_limits::min)() + && value <= (std::numeric_limits::max)(); + }; + auto is_float32 = [](double value) + { + return value >= (std::numeric_limits::min)() + && value <= (std::numeric_limits::max)(); + }; + + if (U("NcBoolean") == name) { return value.is_boolean(); } + if (U("NcInt16") == name && value.is_number()) { return is_int16(value.as_number().to_int32()); } + if (U("NcInt32") == name && value.is_number()) { return value.as_number().is_int32(); } + if (U("NcInt64") == name && value.is_number()) { return value.as_number().is_int64(); } + if (U("NcUint16") == name && value.is_number()) { return is_uint16(value.as_number().to_uint32()); } + if (U("NcUint32") == name && value.is_number()) { return value.as_number().is_uint32(); } + if (U("NcUint64") == name && value.is_number()) { return value.as_number().is_uint64(); } + if (U("NcFloat32") == name && value.is_number()) { return is_float32(value.as_number().to_double()); } + if (U("NcFloat64") == name && value.is_number()) { return !value.as_number().is_integral(); } + if (U("NcString") == name) { return value.is_string(); } + + // invalid primitive type + return false; }; - if (U("NcBoolean") == name) { return value.is_boolean(); } - if (U("NcInt16") == name && value.is_number()) { return is_int16(value.as_number().to_int32()); } - if (U("NcInt32") == name && value.is_number()) { return value.as_number().is_int32(); } - if (U("NcInt64") == name && value.is_number()) { return value.as_number().is_int64(); } - if (U("NcUint16") == name && value.is_number()) { return is_uint16(value.as_number().to_uint32()); } - if (U("NcUint32") == name && value.is_number()) { return value.as_number().is_uint32(); } - if (U("NcUint64") == name && value.is_number()) { return value.as_number().is_uint64(); } - if (U("NcFloat32") == name && value.is_number()) { return is_float32(value.as_number().to_double()); } - if (U("NcFloat64") == name && value.is_number()) { return !value.as_number().is_integral(); } - if (U("NcString") == name) { return value.is_string(); } - - // invalid primitive type - return false; - }; - - // do primitive type constraints validation - const auto& name = nmos::fields::nc::name(params.datatype_descriptor); - if (data.is_array()) - { - for (const auto& value : data.as_array()) + // do primitive type constraints validation + const auto& name = nmos::fields::nc::name(params.datatype_descriptor); + if (data.is_array()) { - if (!primitive_validation(name, value)) { return false; } + for (const auto& value : data.as_array()) + { + if (!primitive_validation(name, value)) + { + throw control_protocol_exception("value is not a " + utility::us2s(name) + " type"); + } + } + } + else + { + if (!primitive_validation(name, data)) + { + throw control_protocol_exception("value is not a " + utility::us2s(name) + " type");; + } } - // reaching here, primitive validation successfully - return true; + } + else + { + constraints_validation(data, datatype_constraints); } - return primitive_validation(name, data); + return; } // do NcDatatypeDescriptorTypeDef constraints validation @@ -219,99 +238,112 @@ namespace nmos { // do the datatype constraints specified via the datatype_descriptor if presented const auto& datatype_constraints = nmos::fields::nc::constraints(params.datatype_descriptor); - if (!datatype_constraints.is_null()) { return constraints_validation(data, datatype_constraints); } + if (datatype_constraints.is_null()) + { + // do parent typename constraints validation + const auto& type_name = params.datatype_descriptor.at(nmos::fields::nc::parent_type); // parent type_name + datatype_constraints_validation(data, { details::get_datatype_descriptor(type_name, params.get_control_protocol_datatype), params.get_control_protocol_datatype }); + } + else + { + constraints_validation(data, datatype_constraints); + } - // do parent typename constraints validation - const auto& type_name = params.datatype_descriptor.at(nmos::fields::nc::parent_type); // parent type_name - if (!datatype_constraints_validation(data, { details::get_datatype_descriptor(type_name, params.get_control_protocol_datatype), params.get_control_protocol_datatype })) { return false; } + return; } // do NcDatatypeDescriptorEnum constraints validation if (nc_datatype_type::Enum == datatype_type) { const auto& items = nmos::fields::nc::items(params.datatype_descriptor); - return (items.end() != std::find_if(items.begin(), items.end(), [&](const web::json::value& nc_enum_item_descriptor) { return nmos::fields::nc::value(nc_enum_item_descriptor) == data; })); + if (items.end() == std::find_if(items.begin(), items.end(), [&](const web::json::value& nc_enum_item_descriptor) { return nmos::fields::nc::value(nc_enum_item_descriptor) == data; })) + { + const auto& name = nmos::fields::nc::name(params.datatype_descriptor); + throw control_protocol_exception("value is not an enum " + utility::us2s(name) + " type"); + } + + return; } // do NcDatatypeDescriptorStruct constraints validation if (nc_datatype_type::Struct == datatype_type) { + const auto& datatype_name = nmos::fields::nc::name(params.datatype_descriptor); const auto& fields = nmos::fields::nc::fields(params.datatype_descriptor); // NcFieldDescriptor for (const web::json::value& nc_field_descriptor : fields) { - const auto& name = nmos::fields::nc::name(nc_field_descriptor); - // check is the specific element in value strurcture - if (!data.has_field(name)) { return false; } + const auto& field_name = nmos::fields::nc::name(nc_field_descriptor); + // is field in strurcture + if (!data.has_field(field_name)) { throw control_protocol_exception("missing " + utility::us2s(field_name) + " in " + utility::us2s(datatype_name)); } - // check is the element is a nullable field - if (nmos::fields::nc::is_nullable(nc_field_descriptor) != data.is_null()) { return false; } + // is field nullable + if (nmos::fields::nc::is_nullable(nc_field_descriptor) != data.is_null()) { throw control_protocol_exception(utility::us2s(field_name) + " is not nullable"); } - // check is the element is a sequence field - if (nmos::fields::nc::is_sequence(nc_field_descriptor) != data.is_array()) { return false; } + // is field sequenceable + if (nmos::fields::nc::is_sequence(nc_field_descriptor) != data.is_array()) { throw control_protocol_exception(utility::us2s(field_name) + " is not sequenceable"); } // check against field constraints if presented const auto& constraints = nmos::fields::nc::constraints(nc_field_descriptor); - if (!constraints.is_null()) - { - auto value = data.at(name); - - // do field constraints validation - if (!constraints_validation(value, constraints)) { return false; } - } - else + if (constraints.is_null()) { // no field constraints, move to check the constraints of its typeName - const auto& type_name = nc_field_descriptor.at(nmos::fields::nc::type_name); + const auto& field_type_name = nc_field_descriptor.at(nmos::fields::nc::type_name); - if (!type_name.is_null()) + if (!field_type_name.is_null()) { - auto value = data.at(name); + auto value = data.at(field_name); if (value.is_array()) { for (const auto& val : value.as_array()) { // do typename constraints validation - if (!datatype_constraints_validation(val, { details::get_datatype_descriptor(type_name, params.get_control_protocol_datatype), params.get_control_protocol_datatype })) { return false; } + datatype_constraints_validation(val, { details::get_datatype_descriptor(field_type_name, params.get_control_protocol_datatype), params.get_control_protocol_datatype }); } } else { // do typename constraints validation - if (!datatype_constraints_validation(value, { details::get_datatype_descriptor(type_name, params.get_control_protocol_datatype), params.get_control_protocol_datatype })) { return false; } + datatype_constraints_validation(value, { details::get_datatype_descriptor(field_type_name, params.get_control_protocol_datatype), params.get_control_protocol_datatype }); } } } + else + { + // do field constraints validation + const auto& value = data.at(field_name); + constraints_validation(value, constraints); + } } - return true; + + return; } // unsupport datatype_type, no validation is required - return true; } - // multiple levels of constraints validation + // multiple levels of constraints validation, may throw nmos::control_protocol_exception // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html - bool constraints_validation(const web::json::value& data, const web::json::value& runtime_property_constraints, const web::json::value& property_constraints, const datatype_constraints_validation_parameters& params) + void constraints_validation(const web::json::value& data, const web::json::value& runtime_property_constraints, const web::json::value& property_constraints, const datatype_constraints_validation_parameters& params) { // do level 2 runtime property constraints validation - if (!runtime_property_constraints.is_null()) { return details::constraints_validation(data, runtime_property_constraints); } + if (!runtime_property_constraints.is_null()) { constraints_validation(data, runtime_property_constraints); return; } // do level 1 property constraints validation - if (!property_constraints.is_null()) { return details::constraints_validation(data, property_constraints); } + if (!property_constraints.is_null()) { constraints_validation(data, property_constraints); return; } // do level 0 datatype constraints validation - return details::datatype_constraints_validation(data, params); + datatype_constraints_validation(data, params); } - // method parameter constraints validation - bool method_parameter_constraints_validation(const web::json::value& data, const web::json::value& property_constraints, const datatype_constraints_validation_parameters& params) + // method parameter constraints validation, may throw nmos::control_protocol_exception + void method_parameter_constraints_validation(const web::json::value& data, const web::json::value& property_constraints, const datatype_constraints_validation_parameters& params) { using web::json::value; // do level 1 property constraints & level 0 datatype constraints validation - return constraints_validation(data, value::null(), property_constraints, params); + constraints_validation(data, value::null(), property_constraints, params); } } @@ -589,7 +621,7 @@ namespace nmos } // method parameters constraints validation - bool method_parameters_contraints_validation(const web::json::value& arguments, const web::json::value& nc_method_descriptor, get_control_protocol_datatype_handler get_control_protocol_datatype) + void method_parameters_contraints_validation(const web::json::value& arguments, const web::json::value& nc_method_descriptor, get_control_protocol_datatype_handler get_control_protocol_datatype) { for (const auto& param : nmos::fields::nc::parameters(nc_method_descriptor)) { @@ -599,13 +631,9 @@ namespace nmos if (arguments.is_null() || !arguments.has_field(name)) { // missing argument parameter - return false; - } - if (!details::method_parameter_constraints_validation(arguments.at(name), constraints, { nmos::details::get_datatype_descriptor(type_name, get_control_protocol_datatype), get_control_protocol_datatype })) - { - return false; + throw control_protocol_exception("missing argument parameter " + utility::us2s(name)); } + details::method_parameter_constraints_validation(arguments.at(name), constraints, { nmos::details::get_datatype_descriptor(type_name, get_control_protocol_datatype), get_control_protocol_datatype }); } - return true; } } diff --git a/Development/nmos/control_protocol_utils.h b/Development/nmos/control_protocol_utils.h index 34ad7c593..9ec84379e 100644 --- a/Development/nmos/control_protocol_utils.h +++ b/Development/nmos/control_protocol_utils.h @@ -8,6 +8,11 @@ namespace nmos { struct control_protocol_resource; + struct control_protocol_exception : std::runtime_error + { + control_protocol_exception(const std::string& message) : std::runtime_error(message) {} + }; + namespace details { // get the runtime property constraints of a given property_id @@ -24,12 +29,12 @@ namespace nmos web::json::value datatype_descriptor; get_control_protocol_datatype_handler get_control_protocol_datatype; }; - // multiple levels of constraints validation + // multiple levels of constraints validation, may throw nmos::control_protocol_exception // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html - bool constraints_validation(const web::json::value& value, const web::json::value& runtime_property_constraints, const web::json::value& property_constraints, const datatype_constraints_validation_parameters& params); + void constraints_validation(const web::json::value& value, const web::json::value& runtime_property_constraints, const web::json::value& property_constraints, const datatype_constraints_validation_parameters& params); - // method parameter constraints validation - bool method_parameter_constraints_validation(const web::json::value& data, const web::json::value& property_constraints, const datatype_constraints_validation_parameters& params); + // method parameter constraints validation, may throw nmos::control_protocol_exception + void method_parameter_constraints_validation(const web::json::value& data, const web::json::value& property_constraints, const datatype_constraints_validation_parameters& params); } // is the given class_id a NcBlock @@ -72,8 +77,8 @@ namespace nmos // find the control protocol resource which is assoicated with the given IS-04/IS-05/IS-08 resource id resources::const_iterator find_control_protocol_resource(resources& resources, type type, const id& id); - // method parameters constraints validation - bool method_parameters_contraints_validation(const web::json::value& arguments, const web::json::value& nc_method_descriptor, get_control_protocol_datatype_handler get_control_protocol_datatype); + // method parameters constraints validation, may throw nmos::control_protocol_exception + void method_parameters_contraints_validation(const web::json::value& arguments, const web::json::value& nc_method_descriptor, get_control_protocol_datatype_handler get_control_protocol_datatype); } #endif diff --git a/Development/nmos/control_protocol_ws_api.cpp b/Development/nmos/control_protocol_ws_api.cpp index 3660a6d06..df18eef3f 100644 --- a/Development/nmos/control_protocol_ws_api.cpp +++ b/Development/nmos/control_protocol_ws_api.cpp @@ -258,16 +258,18 @@ namespace nmos auto method = get_control_protocol_method(class_id, method_id); if (method.second) { - // do method arguments constraints validation - if (method_parameters_contraints_validation(arguments, method.first, get_control_protocol_datatype)) + try { + // do method arguments constraints validation + method_parameters_contraints_validation(arguments, method.first, get_control_protocol_datatype); + // execute the relevant method handler, then accumulating up their response to reponses response = method.second(resources, resource, handle, arguments, nmos::fields::nc::is_deprecated(method.first), get_control_protocol_class, get_control_protocol_datatype, gate); } - else + catch (const nmos::control_protocol_exception& e) { // invalid arguments - slog::log(gate, SLOG_FLF) << "invalid argument: " << arguments.serialize(); + slog::log(gate, SLOG_FLF) << "invalid argument: " << arguments.serialize() << " error: " << e.what(); response = make_control_protocol_message_response(handle, { nmos::nc_method_status::parameter_error }); } } diff --git a/Development/nmos/test/control_protocol_test.cpp b/Development/nmos/test/control_protocol_test.cpp index 36c914809..65816413b 100644 --- a/Development/nmos/test/control_protocol_test.cpp +++ b/Development/nmos/test/control_protocol_test.cpp @@ -797,120 +797,120 @@ BST_TEST_CASE(testConstraints) // runtime property constraints validation const nmos::details::datatype_constraints_validation_parameters with_constraints_string_constraints_validation_params{ with_constraints_string_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; - BST_REQUIRE(nmos::details::constraints_validation(value::string(U("1234567890")), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params)); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value::string(U("12345678901")), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value::string(U("123456789A")), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params), false); - BST_REQUIRE(nmos::details::constraints_validation(value_of({ value::string(U("1234567890")), value::string(U("1234567890")) }), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params)); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value_of({ value::string(U("1234567890")), value::string(U("12345678901")) }), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value_of({ value::string(U("1234567890")), 1 }), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params), false); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(value::string(U("1234567890")), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params)); + BST_REQUIRE_THROW(nmos::details::constraints_validation(value::string(U("12345678901")), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(value::string(U("123456789A")), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(value_of({ value::string(U("1234567890")), value::string(U("1234567890")) }), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params)); + BST_REQUIRE_THROW(nmos::details::constraints_validation(value_of({ value::string(U("1234567890")), value::string(U("12345678901")) }), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(value_of({ value::string(U("1234567890")), 1 }), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params), nmos::control_protocol_exception); // property constraints validation - BST_REQUIRE(nmos::details::constraints_validation(value::string(U("abcde")), value::null(), property_string_constraints, with_constraints_string_constraints_validation_params)); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value::string(U("abcdef")), value::null(), property_string_constraints, with_constraints_string_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value::string(U("abcd1")), value::null(), property_string_constraints, with_constraints_string_constraints_validation_params), false); - BST_REQUIRE(nmos::details::constraints_validation(value_of({ value::string(U("abcde")), value::string(U("abcde")) }), value::null(), property_string_constraints, with_constraints_string_constraints_validation_params)); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value_of({ value::string(U("abcde")), value::string(U("abcdef")) }), value::null(), property_string_constraints, with_constraints_string_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value_of({ value::string(U("abcde")), 1 }), value::null(), property_string_constraints, with_constraints_string_constraints_validation_params), false); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(value::string(U("abcde")), value::null(), property_string_constraints, with_constraints_string_constraints_validation_params)); + BST_REQUIRE_THROW(nmos::details::constraints_validation(value::string(U("abcdef")), value::null(), property_string_constraints, with_constraints_string_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(value::string(U("abcd1")), value::null(), property_string_constraints, with_constraints_string_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(value_of({ value::string(U("abcde")), value::string(U("abcde")) }), value::null(), property_string_constraints, with_constraints_string_constraints_validation_params)); + BST_REQUIRE_THROW(nmos::details::constraints_validation(value_of({ value::string(U("abcde")), value::string(U("abcdef")) }), value::null(), property_string_constraints, with_constraints_string_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(value_of({ value::string(U("abcde")), 1 }), value::null(), property_string_constraints, with_constraints_string_constraints_validation_params), nmos::control_protocol_exception); // datatype constraints validation - BST_REQUIRE(nmos::details::constraints_validation(value::string(U("1a")), value::null(), value::null(), with_constraints_string_constraints_validation_params)); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value::string(U("1a2")), value::null(), value::null(), with_constraints_string_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value::string(U("1*")), value::null(), value::null(), with_constraints_string_constraints_validation_params), false); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(value::string(U("1a")), value::null(), value::null(), with_constraints_string_constraints_validation_params)); + BST_REQUIRE_THROW(nmos::details::constraints_validation(value::string(U("1a2")), value::null(), value::null(), with_constraints_string_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(value::string(U("1*")), value::null(), value::null(), with_constraints_string_constraints_validation_params), nmos::control_protocol_exception); const nmos::details::datatype_constraints_validation_parameters no_constraints_string_constraints_validation_params{ no_constraints_string_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; - BST_REQUIRE(nmos::details::constraints_validation(value::string(U("1234567890-abcde-!\"£$%^&*()_+=")), value::null(), value::null(), no_constraints_string_constraints_validation_params)); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(value::string(U("1234567890-abcde-!\"£$%^&*()_+=")), value::null(), value::null(), no_constraints_string_constraints_validation_params)); // number property constraints validation // runtime property constraints validation const nmos::details::datatype_constraints_validation_parameters with_constraints_int32_constraints_validation_params{ with_constraints_int32_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; - BST_REQUIRE(nmos::details::constraints_validation(10, runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params)); - BST_REQUIRE(nmos::details::constraints_validation(1000, runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params)); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(9, runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(1001, runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params), false); - BST_REQUIRE(nmos::details::constraints_validation(value_of({ 10, 1000 }), runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params)); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value_of({ 10, 1001 }), runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value_of({ 10, value::string(U("a")) }), runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params), false); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(10, runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params)); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(1000, runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params)); + BST_REQUIRE_THROW(nmos::details::constraints_validation(9, runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(1001, runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(value_of({ 10, 1000 }), runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params)); + BST_REQUIRE_THROW(nmos::details::constraints_validation(value_of({ 10, 1001 }), runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(value_of({ 10, value::string(U("a")) }), runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params), nmos::control_protocol_exception); // property constraints validation - BST_REQUIRE(nmos::details::constraints_validation(50, value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params)); - BST_REQUIRE(nmos::details::constraints_validation(500, value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params)); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(45, value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(505, value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(499, value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), false); - BST_REQUIRE(nmos::details::constraints_validation(value_of({ 50, 500 }), value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params)); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value_of({ 49, 500 }), value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value_of({ 50, 501 }), value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value_of({ 45, 500 }), value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value_of({ 50, value::string(U("a")) }), value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), false); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(50, value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params)); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(500, value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params)); + BST_REQUIRE_THROW(nmos::details::constraints_validation(45, value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(505, value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(499, value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(value_of({ 50, 500 }), value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params)); + BST_REQUIRE_THROW(nmos::details::constraints_validation(value_of({ 49, 500 }), value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(value_of({ 50, 501 }), value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(value_of({ 45, 500 }), value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(value_of({ 50, value::string(U("a")) }), value::null(), property_int32_constraints, with_constraints_int32_constraints_validation_params), nmos::control_protocol_exception); // datatype constraints validation - BST_REQUIRE(nmos::details::constraints_validation(100, value::null(), value::null(), with_constraints_int32_constraints_validation_params)); - BST_REQUIRE(nmos::details::constraints_validation(250, value::null(), value::null(), with_constraints_int32_constraints_validation_params)); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(90, value::null(), value::null(), with_constraints_int32_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(260, value::null(), value::null(), with_constraints_int32_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(99, value::null(), value::null(), with_constraints_int32_constraints_validation_params), false); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(100, value::null(), value::null(), with_constraints_int32_constraints_validation_params)); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(250, value::null(), value::null(), with_constraints_int32_constraints_validation_params)); + BST_REQUIRE_THROW(nmos::details::constraints_validation(90, value::null(), value::null(), with_constraints_int32_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(260, value::null(), value::null(), with_constraints_int32_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(99, value::null(), value::null(), with_constraints_int32_constraints_validation_params), nmos::control_protocol_exception); // int16 datatype constraints validation const nmos::details::datatype_constraints_validation_parameters no_constraints_int16_constraints_validation_params{ no_constraints_int16_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(int64_t(std::numeric_limits::min()) - 1, value::null(), value::null(), no_constraints_int16_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(int64_t(std::numeric_limits::max()) + 1, value::null(), value::null(), no_constraints_int16_constraints_validation_params), false); - BST_REQUIRE(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_int16_constraints_validation_params)); - BST_REQUIRE(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_int16_constraints_validation_params)); + BST_REQUIRE_THROW(nmos::details::constraints_validation(int64_t(std::numeric_limits::min()) - 1, value::null(), value::null(), no_constraints_int16_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(int64_t(std::numeric_limits::max()) + 1, value::null(), value::null(), no_constraints_int16_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_int16_constraints_validation_params)); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_int16_constraints_validation_params)); // int32 datatype constraints validation const nmos::details::datatype_constraints_validation_parameters no_constraints_int32_constraints_validation_params{ no_constraints_int32_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(int64_t(std::numeric_limits::min()) - 1, value::null(), value::null(), no_constraints_int32_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(int64_t(std::numeric_limits::max()) + 1, value::null(), value::null(), no_constraints_int32_constraints_validation_params), false); - BST_REQUIRE(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_int32_constraints_validation_params)); - BST_REQUIRE(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_int32_constraints_validation_params)); + BST_REQUIRE_THROW(nmos::details::constraints_validation(int64_t(std::numeric_limits::min()) - 1, value::null(), value::null(), no_constraints_int32_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(int64_t(std::numeric_limits::max()) + 1, value::null(), value::null(), no_constraints_int32_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_int32_constraints_validation_params)); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_int32_constraints_validation_params)); // int64 datatype constraints validation const nmos::details::datatype_constraints_validation_parameters no_constraints_int64_constraints_validation_params{ no_constraints_int64_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_int64_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_int64_constraints_validation_params), false); - BST_REQUIRE(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_int64_constraints_validation_params)); - BST_REQUIRE(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_int64_constraints_validation_params)); + BST_REQUIRE_THROW(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_int64_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_int64_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_int64_constraints_validation_params)); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_int64_constraints_validation_params)); // uint16 datatype constraints validation const nmos::details::datatype_constraints_validation_parameters no_constraints_uint16_constraints_validation_params{ no_constraints_uint16_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(-1, value::null(), value::null(), no_constraints_uint16_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(uint64_t(std::numeric_limits::max()) + 1, value::null(), value::null(), no_constraints_uint16_constraints_validation_params), false); - BST_REQUIRE(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_uint16_constraints_validation_params)); - BST_REQUIRE(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_uint16_constraints_validation_params)); + BST_REQUIRE_THROW(nmos::details::constraints_validation(-1, value::null(), value::null(), no_constraints_uint16_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(uint64_t(std::numeric_limits::max()) + 1, value::null(), value::null(), no_constraints_uint16_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_uint16_constraints_validation_params)); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_uint16_constraints_validation_params)); // uint32 datatype constraints validation const nmos::details::datatype_constraints_validation_parameters no_constraints_uint32_constraints_validation_params{ no_constraints_uint32_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(-1, value::null(), value::null(), no_constraints_uint32_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(uint64_t(std::numeric_limits::max()) + 1, value::null(), value::null(), no_constraints_uint32_constraints_validation_params), false); - BST_REQUIRE(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_uint32_constraints_validation_params)); - BST_REQUIRE(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_uint32_constraints_validation_params)); + BST_REQUIRE_THROW(nmos::details::constraints_validation(-1, value::null(), value::null(), no_constraints_uint32_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(uint64_t(std::numeric_limits::max()) + 1, value::null(), value::null(), no_constraints_uint32_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_uint32_constraints_validation_params)); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_uint32_constraints_validation_params)); // uint64 datatype constraints validation const nmos::details::datatype_constraints_validation_parameters no_constraints_uint64_constraints_validation_params{ no_constraints_uint64_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(-1, value::null(), value::null(), no_constraints_uint64_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_int64_constraints_validation_params), false); - BST_REQUIRE(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_uint64_constraints_validation_params)); - BST_REQUIRE(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_uint64_constraints_validation_params)); + BST_REQUIRE_THROW(nmos::details::constraints_validation(-1, value::null(), value::null(), no_constraints_uint64_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_int64_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_uint64_constraints_validation_params)); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_uint64_constraints_validation_params)); // float32 datatype constraints validation const nmos::details::datatype_constraints_validation_parameters no_constraints_float32_constraints_validation_params{ no_constraints_float32_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_float32_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_float32_constraints_validation_params), false); - BST_REQUIRE(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_float32_constraints_validation_params)); - BST_REQUIRE(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_float32_constraints_validation_params)); + BST_REQUIRE_THROW(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_float32_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_float32_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_float32_constraints_validation_params)); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_float32_constraints_validation_params)); // float64 datatype constraints validation const nmos::details::datatype_constraints_validation_parameters no_constraints_float64_constraints_validation_params{ no_constraints_float64_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(1000, value::null(), value::null(), no_constraints_float64_constraints_validation_params), false); - BST_REQUIRE(nmos::details::constraints_validation(1000.0, value::null(), value::null(), no_constraints_float64_constraints_validation_params)); - BST_REQUIRE(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_float64_constraints_validation_params)); - BST_REQUIRE(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_float64_constraints_validation_params)); + BST_REQUIRE_THROW(nmos::details::constraints_validation(1000, value::null(), value::null(), no_constraints_float64_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(1000.0, value::null(), value::null(), no_constraints_float64_constraints_validation_params)); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_float64_constraints_validation_params)); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_float64_constraints_validation_params)); // enum property datatype constraints validation const nmos::details::datatype_constraints_validation_parameters enum_constraints_validation_params{ enum_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; - BST_REQUIRE(nmos::details::constraints_validation(enum_value::foo, value::null(), value::null(), enum_constraints_validation_params)); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(4, value::null(), value::null(), enum_constraints_validation_params), false); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(enum_value::foo, value::null(), value::null(), enum_constraints_validation_params)); + BST_REQUIRE_THROW(nmos::details::constraints_validation(4, value::null(), value::null(), enum_constraints_validation_params), nmos::control_protocol_exception); // invalid data vs primitive datatype constraints const nmos::details::datatype_constraints_validation_parameters no_constraints_string_seq_constraints_validation_params{ no_constraints_string_seq_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; - BST_REQUIRE(nmos::details::constraints_validation(value_of({ value::string(U("1234567890-abcde-!\"£$%^&*()_+=")) }), value::null(), value::null(), no_constraints_string_seq_constraints_validation_params)); - BST_REQUIRE(nmos::details::constraints_validation(value_of({ value::string(U("1234567890-abcde-!\"£$%^&*()_+=")), value::string(U("1234567890-abcde-!\"£$%^&*()_+=")) }), value::null(), value::null(), no_constraints_string_seq_constraints_validation_params)); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value_of({ 1 }), value::null(), value::null(), no_constraints_string_seq_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(1, value::null(), value::null(), no_constraints_string_seq_constraints_validation_params), false); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(value_of({ value::string(U("1234567890-abcde-!\"£$%^&*()_+=")) }), value::null(), value::null(), no_constraints_string_seq_constraints_validation_params)); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(value_of({ value::string(U("1234567890-abcde-!\"£$%^&*()_+=")), value::string(U("1234567890-abcde-!\"£$%^&*()_+=")) }), value::null(), value::null(), no_constraints_string_seq_constraints_validation_params)); + BST_REQUIRE_THROW(nmos::details::constraints_validation(value_of({ 1 }), value::null(), value::null(), no_constraints_string_seq_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(1, value::null(), value::null(), no_constraints_string_seq_constraints_validation_params), nmos::control_protocol_exception); const nmos::details::datatype_constraints_validation_parameters no_constraints_int32_seq_constraints_validation_params{ no_constraints_int32_seq_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value_of({ value::string(U("1234567890-abcde-!\"£$%^&*()_+=")) }), value::null(), value::null(), no_constraints_int32_seq_constraints_validation_params), false); - BST_REQUIRE(nmos::details::constraints_validation(value_of({ 1 }), value::null(), value::null(), no_constraints_int32_seq_constraints_validation_params)); - BST_REQUIRE(nmos::details::constraints_validation(value_of({ 1, 2 }), value::null(), value::null(), no_constraints_int32_seq_constraints_validation_params)); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value_of({ value::string(U("1234567890-abcde-!\"£$%^&*()_+=")) }), value::null(), value::null(), no_constraints_int32_seq_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value::string(U("1234567890-abcde-!\"£$%^&*()_+=")), value::null(), value::null(), no_constraints_int32_seq_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value_of({ 1, 2 }), value::null(), value::null(), with_constraints_int32_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(value_of({ 1, 2 }), value::null(), value::null(), with_constraints_string_constraints_validation_params), false); + BST_REQUIRE_THROW(nmos::details::constraints_validation(value_of({ value::string(U("1234567890-abcde-!\"£$%^&*()_+=")) }), value::null(), value::null(), no_constraints_int32_seq_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(value_of({ 1 }), value::null(), value::null(), no_constraints_int32_seq_constraints_validation_params)); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(value_of({ 1, 2 }), value::null(), value::null(), no_constraints_int32_seq_constraints_validation_params)); + BST_REQUIRE_THROW(nmos::details::constraints_validation(value_of({ value::string(U("1234567890-abcde-!\"£$%^&*()_+=")) }), value::null(), value::null(), no_constraints_int32_seq_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(value::string(U("1234567890-abcde-!\"£$%^&*()_+=")), value::null(), value::null(), no_constraints_int32_seq_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(value_of({ 1, 2 }), value::null(), value::null(), with_constraints_int32_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(value_of({ 1, 2 }), value::null(), value::null(), with_constraints_string_constraints_validation_params), nmos::control_protocol_exception); // struct property datatype constraints validation const auto good_struct = value_of({ @@ -1442,23 +1442,23 @@ BST_TEST_CASE(testConstraints) }); const nmos::details::datatype_constraints_validation_parameters struct_constraints_validation_params{ struct_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; - BST_REQUIRE(nmos::details::constraints_validation(good_struct, value::null(), value::null(), struct_constraints_validation_params)); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct1, value::null(), value::null(), struct_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct2, value::null(), value::null(), struct_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct2_1, value::null(), value::null(), struct_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct2_2, value::null(), value::null(), struct_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct2_3, value::null(), value::null(), struct_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct2_4, value::null(), value::null(), struct_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct2_5, value::null(), value::null(), struct_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct2_5_1, value::null(), value::null(), struct_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct2_5_2, value::null(), value::null(), struct_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct2_5_3, value::null(), value::null(), struct_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct2_6, value::null(), value::null(), struct_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct2_6_1, value::null(), value::null(), struct_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct2_6_2, value::null(), value::null(), struct_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct2_6_3, value::null(), value::null(), struct_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct2_7, value::null(), value::null(), struct_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct2_7_1, value::null(), value::null(), struct_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct2_7_2, value::null(), value::null(), struct_constraints_validation_params), false); - BST_REQUIRE_EQUAL(nmos::details::constraints_validation(bad_struct2_7_3, value::null(), value::null(), struct_constraints_validation_params), false); + BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(good_struct, value::null(), value::null(), struct_constraints_validation_params)); + BST_REQUIRE_THROW(nmos::details::constraints_validation(bad_struct1, value::null(), value::null(), struct_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(bad_struct2, value::null(), value::null(), struct_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(bad_struct2_1, value::null(), value::null(), struct_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(bad_struct2_2, value::null(), value::null(), struct_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(bad_struct2_3, value::null(), value::null(), struct_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(bad_struct2_4, value::null(), value::null(), struct_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(bad_struct2_5, value::null(), value::null(), struct_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(bad_struct2_5_1, value::null(), value::null(), struct_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(bad_struct2_5_2, value::null(), value::null(), struct_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(bad_struct2_5_3, value::null(), value::null(), struct_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(bad_struct2_6, value::null(), value::null(), struct_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(bad_struct2_6_1, value::null(), value::null(), struct_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(bad_struct2_6_2, value::null(), value::null(), struct_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(bad_struct2_6_3, value::null(), value::null(), struct_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(bad_struct2_7, value::null(), value::null(), struct_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(bad_struct2_7_1, value::null(), value::null(), struct_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(bad_struct2_7_2, value::null(), value::null(), struct_constraints_validation_params), nmos::control_protocol_exception); + BST_REQUIRE_THROW(nmos::details::constraints_validation(bad_struct2_7_3, value::null(), value::null(), struct_constraints_validation_params), nmos::control_protocol_exception); } From 4f83f3822d47f98f9f3197733807c0600116e7c1 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Thu, 4 Jan 2024 10:49:51 +0000 Subject: [PATCH 083/106] Add property changed callback to perform application-specific operations to complete the property changed --- Development/nmos-cpp-node/main.cpp | 7 +-- .../nmos-cpp-node/node_implementation.cpp | 27 ++++++++++-- .../nmos/control_protocol_handlers.cpp | 7 +-- Development/nmos/control_protocol_handlers.h | 7 ++- Development/nmos/control_protocol_methods.cpp | 44 +++++++++++++------ Development/nmos/control_protocol_methods.h | 26 +++++------ Development/nmos/control_protocol_ws_api.cpp | 6 +-- Development/nmos/control_protocol_ws_api.h | 6 +-- Development/nmos/node_resources.cpp | 1 + Development/nmos/node_server.cpp | 2 +- Development/nmos/node_server.h | 5 ++- 11 files changed, 93 insertions(+), 45 deletions(-) diff --git a/Development/nmos-cpp-node/main.cpp b/Development/nmos-cpp-node/main.cpp index 159e45e12..d70a45958 100644 --- a/Development/nmos-cpp-node/main.cpp +++ b/Development/nmos-cpp-node/main.cpp @@ -139,9 +139,10 @@ int main(int argc, char* argv[]) nmos::experimental::control_protocol_state control_protocol_state; if (0 <= nmos::fields::control_protocol_ws_port(node_model.settings)) { - node_implementation.on_get_control_class(nmos::make_get_control_protocol_class_handler(control_protocol_state)); - node_implementation.on_get_control_datatype(nmos::make_get_control_protocol_datatype_handler(control_protocol_state)); - node_implementation.on_get_control_protocol_method(nmos::make_get_control_protocol_method_handler(control_protocol_state)); + node_implementation + .on_get_control_class(nmos::make_get_control_protocol_class_handler(control_protocol_state)) + .on_get_control_datatype(nmos::make_get_control_protocol_datatype_handler(control_protocol_state)) + .on_get_control_protocol_method(nmos::make_get_control_protocol_method_handler(control_protocol_state)); } // Set up the node server diff --git a/Development/nmos-cpp-node/node_implementation.cpp b/Development/nmos-cpp-node/node_implementation.cpp index 035400aac..be0359e69 100644 --- a/Development/nmos-cpp-node/node_implementation.cpp +++ b/Development/nmos-cpp-node/node_implementation.cpp @@ -1008,7 +1008,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr nmos::experimental::make_control_class_property(U("Example object sequence property"), { 3, 14 }, object_sequence, U("ExampleDataType"), false, false, true) }; - auto example_method_with_no_args = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) + auto example_method_with_no_args = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::control_protocol_property_changed_handler, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -1016,7 +1016,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr return nmos::make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::nc_method_status::ok }); }; - auto example_method_with_simple_args = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) + auto example_method_with_simple_args = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::control_protocol_property_changed_handler, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... // and the method parameters constriants has already been validated by the outter function @@ -1025,7 +1025,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr return nmos::make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::nc_method_status::ok }); }; - auto example_method_with_object_args = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) + auto example_method_with_object_args = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::control_protocol_property_changed_handler, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... // and the method parameters constriants has already been validated by the outter function @@ -1696,6 +1696,24 @@ nmos::channelmapping_activation_handler make_node_implementation_channelmapping_ }; } +// Example Control Protocol WebSocket API property changed callback to perform application-specific operations to complete the property changed +nmos::control_protocol_property_changed_handler make_node_implementation_control_protocol_property_changed_handler(slog::base_gate& gate) +{ + return [&gate](const nmos::resource& resource, const utility::string_t& property_name, int index) + { + if (index >= 0) + { + // sequence property + slog::log(gate, SLOG_FLF) << nmos::stash_category(impl::categories::node_implementation) << "Property: " << property_name << " index " << index << " has value changed to " << resource.data.at(property_name).at(index).serialize(); + } + else + { + // non-sequence property + slog::log(gate, SLOG_FLF) << nmos::stash_category(impl::categories::node_implementation) << "Property: " << property_name << " has value changed to " << resource.data.at(property_name).serialize(); + } + }; +} + namespace impl { nmos::interlace_mode get_interlace_mode(const nmos::settings& settings) @@ -1849,5 +1867,6 @@ nmos::experimental::node_implementation make_node_implementation(nmos::node_mode .on_set_transportfile(make_node_implementation_transportfile_setter(model.node_resources, model.settings)) .on_connection_activated(make_node_implementation_connection_activation_handler(model, gate)) .on_validate_channelmapping_output_map(make_node_implementation_map_validator()) // may be omitted if not required - .on_channelmapping_activated(make_node_implementation_channelmapping_activation_handler(gate)); + .on_channelmapping_activated(make_node_implementation_channelmapping_activation_handler(gate)) + .on_control_protocol_property_changed(make_node_implementation_control_protocol_property_changed_handler(gate)); // may be omitted if IS-12 not required } diff --git a/Development/nmos/control_protocol_handlers.cpp b/Development/nmos/control_protocol_handlers.cpp index f4e0129dd..f9650a21a 100644 --- a/Development/nmos/control_protocol_handlers.cpp +++ b/Development/nmos/control_protocol_handlers.cpp @@ -69,6 +69,7 @@ namespace nmos }; } + // Example Receiver-Monitor Connection activation callback to perform application-specific operations to complete activation control_protocol_connection_activation_handler make_receiver_monitor_connection_activation_handler(resources& resources) { return [&resources](const resource& connection_resource) @@ -79,18 +80,18 @@ namespace nmos // update receiver-monitor's connectionStatus propertry const auto active = nmos::fields::master_enable(nmos::fields::endpoint_active(connection_resource.data)); - const web::json::value val = active ? nc_connection_status::connected : nc_connection_status::disconnected; + const web::json::value value = active ? nc_connection_status::connected : nc_connection_status::disconnected; // hmm, maybe updating connectionStatusMessage, payloadStatus, and payloadStatusMessage too const auto propertry_changed_event = make_propertry_changed_event(nmos::fields::nc::oid(found->data), { - { nc_receiver_monitor_connection_status_property_id, nc_property_change_type::type::value_changed, val } + { nc_receiver_monitor_connection_status_property_id, nc_property_change_type::type::value_changed, value } }); modify_control_protocol_resource(resources, found->id, [&](nmos::resource& resource) { - resource.data[nmos::fields::nc::connection_status] = val; + resource.data[nmos::fields::nc::connection_status] = value; }, propertry_changed_event); } diff --git a/Development/nmos/control_protocol_handlers.h b/Development/nmos/control_protocol_handlers.h index 580a7a2ca..b98766b83 100644 --- a/Development/nmos/control_protocol_handlers.h +++ b/Development/nmos/control_protocol_handlers.h @@ -32,10 +32,15 @@ namespace nmos // this callback should not throw exceptions typedef std::function get_control_protocol_datatype_handler; + // a control_protocol_property_changed_handler is a notification that the specified (IS-12) property has changed + // index is set to -1 for non-sequence property + // this callback should not throw exceptions, as the relevant property will already has been changed and those changes will not be rolled back + typedef std::function control_protocol_property_changed_handler; + namespace experimental { // method handler definition - typedef std::function method_handler; + typedef std::function method_handler; // method definition (NcMethodDescriptor vs method handler) typedef std::pair method; diff --git a/Development/nmos/control_protocol_methods.cpp b/Development/nmos/control_protocol_methods.cpp index bfde62701..a6eed1807 100644 --- a/Development/nmos/control_protocol_methods.cpp +++ b/Development/nmos/control_protocol_methods.cpp @@ -14,7 +14,7 @@ namespace nmos { // NcObject methods implementation // Get property value - web::json::value get(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate) + web::json::value get(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -36,7 +36,7 @@ namespace nmos } // Set property value - web::json::value set(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) + web::json::value set(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler get_control_protocol_datatype, control_protocol_property_changed_handler property_changed, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -72,6 +72,12 @@ namespace nmos { resource.data[nmos::fields::nc::name(property)] = val; + // do notification that the specified property has changed + if (property_changed) + { + property_changed(resource, nmos::fields::nc::name(property), -1); + } + }, make_propertry_changed_event(nmos::fields::nc::oid(resource->data), { { property_id_, nc_property_change_type::type::value_changed, val } })); return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }); @@ -91,7 +97,7 @@ namespace nmos } // Get sequence item - web::json::value get_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate) + web::json::value get_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -132,7 +138,7 @@ namespace nmos } // Set sequence item - web::json::value set_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) + web::json::value set_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler get_control_protocol_datatype, control_protocol_property_changed_handler property_changed, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -174,6 +180,12 @@ namespace nmos { resource.data[nmos::fields::nc::name(property)][index] = val; + // do notification that the specified property has changed + if (property_changed) + { + property_changed(resource, nmos::fields::nc::name(property), index); + } + }, make_propertry_changed_event(nmos::fields::nc::oid(resource->data), { { property_id_, nc_property_change_type::type::sequence_item_changed, val, nc_id(index) } })); return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }); @@ -199,7 +211,7 @@ namespace nmos } // Add item to sequence - web::json::value add_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) + web::json::value add_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler get_control_protocol_datatype, control_protocol_property_changed_handler property_changed, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -244,6 +256,12 @@ namespace nmos if (data.is_null()) { sequence = value::array(); } web::json::push_back(sequence, val); + // do notification that the specified property has changed + if (property_changed) + { + property_changed(resource, nmos::fields::nc::name(property), sequence.as_array().size()-1); + } + }, make_propertry_changed_event(nmos::fields::nc::oid(resource->data), { { property_id_, nc_property_change_type::type::sequence_item_added, val, sequence_item_index } })); return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }, sequence_item_index); @@ -263,7 +281,7 @@ namespace nmos } // Delete sequence item - web::json::value remove_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate) + web::json::value remove_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -311,7 +329,7 @@ namespace nmos } // Get sequence length - web::json::value get_sequence_length(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate) + web::json::value get_sequence_length(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -366,7 +384,7 @@ namespace nmos // NcBlock methods implementation // Gets descriptors of members of the block - web::json::value get_member_descriptors(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, slog::base_gate& gate) + web::json::value get_member_descriptors(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -383,7 +401,7 @@ namespace nmos } // Finds member(s) by path - web::json::value find_members_by_path(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, slog::base_gate& gate) + web::json::value find_members_by_path(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -441,7 +459,7 @@ namespace nmos } // Finds members with given role name or fragment - web::json::value find_members_by_role(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, slog::base_gate& gate) + web::json::value find_members_by_role(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -467,7 +485,7 @@ namespace nmos } // Finds members with given class id - web::json::value find_members_by_class_id(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, slog::base_gate& gate) + web::json::value find_members_by_class_id(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -495,7 +513,7 @@ namespace nmos // NcClassManager methods implementation // Get a single class descriptor - web::json::value get_control_class(nmos::resources&, nmos::resources::iterator, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate) + web::json::value get_control_class(nmos::resources&, nmos::resources::iterator, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) { using web::json::value; @@ -550,7 +568,7 @@ namespace nmos } // Get a single datatype descriptor - web::json::value get_datatype(nmos::resources&, nmos::resources::iterator, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate) + web::json::value get_datatype(nmos::resources&, nmos::resources::iterator, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler get_control_protocol_datatype, control_protocol_property_changed_handler, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... diff --git a/Development/nmos/control_protocol_methods.h b/Development/nmos/control_protocol_methods.h index d0eec3ca7..e686c702b 100644 --- a/Development/nmos/control_protocol_methods.h +++ b/Development/nmos/control_protocol_methods.h @@ -15,35 +15,35 @@ namespace nmos { // NcObject methods implementation // Get property value - web::json::value get(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate); + web::json::value get(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); // Set property value - web::json::value set(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate); + web::json::value set(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler property_changed, slog::base_gate& gate); // Get sequence item - web::json::value get_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate); + web::json::value get_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); // Set sequence item - web::json::value set_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate); + web::json::value set_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler property_changed, slog::base_gate& gate); // Add item to sequence - web::json::value add_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate); + web::json::value add_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler property_changed, slog::base_gate& gate); // Delete sequence item - web::json::value remove_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate); + web::json::value remove_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); // Get sequence length - web::json::value get_sequence_length(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate); + web::json::value get_sequence_length(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); // NcBlock methods implementation // Get descriptors of members of the block - web::json::value get_member_descriptors(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, slog::base_gate& gate); + web::json::value get_member_descriptors(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); // Finds member(s) by path - web::json::value find_members_by_path(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, slog::base_gate& gate); + web::json::value find_members_by_path(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); // Finds members with given role name or fragment - web::json::value find_members_by_role(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, slog::base_gate& gate); + web::json::value find_members_by_role(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); // Finds members with given class id - web::json::value find_members_by_class_id(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, slog::base_gate& gate); + web::json::value find_members_by_class_id(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); // NcClassManager methods implementation // Get a single class descriptor - web::json::value get_control_class(nmos::resources&, nmos::resources::iterator, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, slog::base_gate& gate); + web::json::value get_control_class(nmos::resources&, nmos::resources::iterator, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); // Get a single datatype descriptor - web::json::value get_datatype(nmos::resources&, nmos::resources::iterator, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler get_control_protocol_datatype, slog::base_gate& gate); + web::json::value get_datatype(nmos::resources&, nmos::resources::iterator, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler get_control_protocol_datatype, control_protocol_property_changed_handler, slog::base_gate& gate); } } diff --git a/Development/nmos/control_protocol_ws_api.cpp b/Development/nmos/control_protocol_ws_api.cpp index df18eef3f..b6bc3f476 100644 --- a/Development/nmos/control_protocol_ws_api.cpp +++ b/Development/nmos/control_protocol_ws_api.cpp @@ -184,12 +184,12 @@ namespace nmos }; } - web::websockets::experimental::listener::message_handler make_control_protocol_ws_message_handler(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::get_control_protocol_method_handler get_control_protocol_method, slog::base_gate& gate_) + web::websockets::experimental::listener::message_handler make_control_protocol_ws_message_handler(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::get_control_protocol_method_handler get_control_protocol_method, nmos::control_protocol_property_changed_handler property_changed, slog::base_gate& gate_) { using web::json::value; using web::json::value_of; - return [&model, &websockets, get_control_protocol_class, get_control_protocol_datatype, get_control_protocol_method, &gate_](const web::uri& connection_uri, const web::websockets::experimental::listener::connection_id& connection_id, const web::websockets::websocket_incoming_message& msg_) + return [&model, &websockets, get_control_protocol_class, get_control_protocol_datatype, get_control_protocol_method, property_changed, &gate_](const web::uri& connection_uri, const web::websockets::experimental::listener::connection_id& connection_id, const web::websockets::websocket_incoming_message& msg_) { nmos::ws_api_gate gate(gate_, connection_uri); @@ -264,7 +264,7 @@ namespace nmos method_parameters_contraints_validation(arguments, method.first, get_control_protocol_datatype); // execute the relevant method handler, then accumulating up their response to reponses - response = method.second(resources, resource, handle, arguments, nmos::fields::nc::is_deprecated(method.first), get_control_protocol_class, get_control_protocol_datatype, gate); + response = method.second(resources, resource, handle, arguments, nmos::fields::nc::is_deprecated(method.first), get_control_protocol_class, get_control_protocol_datatype, property_changed, gate); } catch (const nmos::control_protocol_exception& e) { diff --git a/Development/nmos/control_protocol_ws_api.h b/Development/nmos/control_protocol_ws_api.h index bbb686272..1d8052cd8 100644 --- a/Development/nmos/control_protocol_ws_api.h +++ b/Development/nmos/control_protocol_ws_api.h @@ -16,15 +16,15 @@ namespace nmos web::websockets::experimental::listener::validate_handler make_control_protocol_ws_validate_handler(nmos::node_model& model, slog::base_gate& gate); web::websockets::experimental::listener::open_handler make_control_protocol_ws_open_handler(nmos::node_model& model, nmos::websockets& websockets, slog::base_gate& gate); web::websockets::experimental::listener::close_handler make_control_protocol_ws_close_handler(nmos::node_model& model, nmos::websockets& websockets, slog::base_gate& gate); - web::websockets::experimental::listener::message_handler make_control_protocol_ws_message_handler(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::get_control_protocol_method_handler get_control_protocol_method, slog::base_gate& gate); + web::websockets::experimental::listener::message_handler make_control_protocol_ws_message_handler(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::get_control_protocol_method_handler get_control_protocol_method, nmos::control_protocol_property_changed_handler property_changed, slog::base_gate& gate); - inline web::websockets::experimental::listener::websocket_listener_handlers make_control_protocol_ws_api(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::get_control_protocol_method_handler get_control_protocol_method, slog::base_gate& gate) + inline web::websockets::experimental::listener::websocket_listener_handlers make_control_protocol_ws_api(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::get_control_protocol_method_handler get_control_protocol_method, nmos::control_protocol_property_changed_handler property_changed, slog::base_gate& gate) { return{ nmos::make_control_protocol_ws_validate_handler(model, gate), nmos::make_control_protocol_ws_open_handler(model, websockets, gate), nmos::make_control_protocol_ws_close_handler(model, websockets, gate), - nmos::make_control_protocol_ws_message_handler(model, websockets, get_control_protocol_class, get_control_protocol_datatype, get_control_protocol_method, gate) + nmos::make_control_protocol_ws_message_handler(model, websockets, get_control_protocol_class, get_control_protocol_datatype, get_control_protocol_method, property_changed, gate) }; } diff --git a/Development/nmos/node_resources.cpp b/Development/nmos/node_resources.cpp index 9cd342137..216ef7db2 100644 --- a/Development/nmos/node_resources.cpp +++ b/Development/nmos/node_resources.cpp @@ -134,6 +134,7 @@ namespace nmos { for (const auto& version : nmos::is12_versions::from_settings(settings)) { + // See https://specs.amwa.tv/is-12/branches/v1.0.x/docs/IS-04_interactions.html auto ncp_uri = web::uri_builder() .set_scheme(nmos::ws_scheme(settings)) .set_port(nmos::fields::control_protocol_ws_port(settings)) diff --git a/Development/nmos/node_server.cpp b/Development/nmos/node_server.cpp index 277c448dd..3cb4836d0 100644 --- a/Development/nmos/node_server.cpp +++ b/Development/nmos/node_server.cpp @@ -78,7 +78,7 @@ namespace nmos { if (control_protocol_ws_port == events_ws_port) throw std::runtime_error("Same port used for events and control protocol websockets are not supported"); auto& control_protocol_ws_api = node_server.ws_handlers[{ {}, control_protocol_ws_port }]; - control_protocol_ws_api.first = nmos::make_control_protocol_ws_api(node_model, control_protocol_ws_api.second, node_implementation.get_control_protocol_class, node_implementation.get_control_protocol_datatype, node_implementation.get_control_protocol_method, gate); + control_protocol_ws_api.first = nmos::make_control_protocol_ws_api(node_model, control_protocol_ws_api.second, node_implementation.get_control_protocol_class, node_implementation.get_control_protocol_datatype, node_implementation.get_control_protocol_method, node_implementation.control_protocol_property_changed, gate); } // Set up the listeners for each HTTP API port diff --git a/Development/nmos/node_server.h b/Development/nmos/node_server.h index 01e4d44a5..1a7ecb77c 100644 --- a/Development/nmos/node_server.h +++ b/Development/nmos/node_server.h @@ -27,7 +27,7 @@ namespace nmos // underlying implementation into the server instance for the NMOS Node struct node_implementation { - node_implementation(nmos::load_server_certificates_handler load_server_certificates, nmos::load_dh_param_handler load_dh_param, nmos::load_ca_certificates_handler load_ca_certificates, nmos::system_global_handler system_changed, nmos::registration_handler registration_changed, nmos::transport_file_parser parse_transport_file, nmos::details::connection_resource_patch_validator validate_staged, nmos::connection_resource_auto_resolver resolve_auto, nmos::connection_sender_transportfile_setter set_transportfile, nmos::connection_activation_handler connection_activated, nmos::ocsp_response_handler get_ocsp_response, get_authorization_bearer_token_handler get_authorization_bearer_token, validate_authorization_handler validate_authorization, ws_validate_authorization_handler ws_validate_authorization, nmos::load_rsa_private_keys_handler load_rsa_private_keys, load_authorization_clients_handler load_authorization_clients, save_authorization_client_handler save_authorization_client, request_authorization_code_handler request_authorization_code, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::get_control_protocol_method_handler get_control_protocol_method) + node_implementation(nmos::load_server_certificates_handler load_server_certificates, nmos::load_dh_param_handler load_dh_param, nmos::load_ca_certificates_handler load_ca_certificates, nmos::system_global_handler system_changed, nmos::registration_handler registration_changed, nmos::transport_file_parser parse_transport_file, nmos::details::connection_resource_patch_validator validate_staged, nmos::connection_resource_auto_resolver resolve_auto, nmos::connection_sender_transportfile_setter set_transportfile, nmos::connection_activation_handler connection_activated, nmos::ocsp_response_handler get_ocsp_response, get_authorization_bearer_token_handler get_authorization_bearer_token, validate_authorization_handler validate_authorization, ws_validate_authorization_handler ws_validate_authorization, nmos::load_rsa_private_keys_handler load_rsa_private_keys, load_authorization_clients_handler load_authorization_clients, save_authorization_client_handler save_authorization_client, request_authorization_code_handler request_authorization_code, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::get_control_protocol_method_handler get_control_protocol_method, nmos::control_protocol_property_changed_handler control_protocol_property_changed) : load_server_certificates(std::move(load_server_certificates)) , load_dh_param(std::move(load_dh_param)) , load_ca_certificates(std::move(load_ca_certificates)) @@ -49,6 +49,7 @@ namespace nmos , get_control_protocol_class(std::move(get_control_protocol_class)) , get_control_protocol_datatype(std::move(get_control_protocol_datatype)) , get_control_protocol_method(std::move(get_control_protocol_method)) + , control_protocol_property_changed(std::move(control_protocol_property_changed)) {} // use the default constructor and chaining member functions for fluent initialization @@ -80,6 +81,7 @@ namespace nmos node_implementation& on_get_control_class(nmos::get_control_protocol_class_handler get_control_protocol_class) { this->get_control_protocol_class = std::move(get_control_protocol_class); return *this; } node_implementation& on_get_control_datatype(nmos::get_control_protocol_datatype_handler get_control_protocol_datatype) { this->get_control_protocol_datatype = std::move(get_control_protocol_datatype); return *this; } node_implementation& on_get_control_protocol_method(nmos::get_control_protocol_method_handler get_control_protocol_method) { this->get_control_protocol_method = std::move(get_control_protocol_method); return *this; } + node_implementation& on_control_protocol_property_changed(nmos::control_protocol_property_changed_handler control_protocol_property_changed) { this->control_protocol_property_changed = std::move(control_protocol_property_changed); return *this; } // deprecated, use on_validate_connection_resource_patch node_implementation& on_validate_merged(nmos::details::connection_resource_patch_validator validate_merged) { return on_validate_connection_resource_patch(std::move(validate_merged)); } @@ -121,6 +123,7 @@ namespace nmos nmos::get_control_protocol_class_handler get_control_protocol_class; nmos::get_control_protocol_datatype_handler get_control_protocol_datatype; nmos::get_control_protocol_method_handler get_control_protocol_method; + nmos::control_protocol_property_changed_handler control_protocol_property_changed; }; // Construct a server instance for an NMOS Node, implementing the IS-04 Node API, IS-05 Connection API, IS-07 Events API From ea732dac3e6d27f2d6123ce96406da82b9a54aeb Mon Sep 17 00:00:00 2001 From: lo-simon Date: Thu, 4 Jan 2024 12:04:31 +0000 Subject: [PATCH 084/106] Add authorization support to IS-12 --- Development/nmos-cpp-node/main.cpp | 2 +- Development/nmos/control_protocol_ws_api.cpp | 8 ++++++-- Development/nmos/control_protocol_ws_api.h | 7 ++++--- Development/nmos/node_server.cpp | 2 +- Development/nmos/scope.h | 3 +++ 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/Development/nmos-cpp-node/main.cpp b/Development/nmos-cpp-node/main.cpp index d70a45958..b08ba5ef8 100644 --- a/Development/nmos-cpp-node/main.cpp +++ b/Development/nmos-cpp-node/main.cpp @@ -118,7 +118,7 @@ int main(int argc, char* argv[]) #endif // only implement communication with Authorization server if IS-10/BCP-003-02 is required -// cf. preprocessor conditions in nmos::make_node_api, nmos::make_connection_api, nmos::make_events_api, nmos::make_channelmapping_api, make_events_ws_validate_handler +// cf. preprocessor conditions in nmos::make_node_api, nmos::make_connection_api, nmos::make_events_api, nmos::make_channelmapping_api, make_events_ws_validate_handler, make_control_protocol_ws_validate_handler nmos::experimental::authorization_state authorization_state; if (nmos::experimental::fields::server_authorization(node_model.settings)) { diff --git a/Development/nmos/control_protocol_ws_api.cpp b/Development/nmos/control_protocol_ws_api.cpp index b6bc3f476..890efe761 100644 --- a/Development/nmos/control_protocol_ws_api.cpp +++ b/Development/nmos/control_protocol_ws_api.cpp @@ -50,9 +50,9 @@ namespace nmos // IS-12 Control Protocol WebSocket API - web::websockets::experimental::listener::validate_handler make_control_protocol_ws_validate_handler(nmos::node_model& model, slog::base_gate& gate_) + web::websockets::experimental::listener::validate_handler make_control_protocol_ws_validate_handler(nmos::node_model& model, nmos::experimental::ws_validate_authorization_handler ws_validate_authorization, slog::base_gate& gate_) { - return [&model, &gate_](web::http::http_request req) + return [&model, ws_validate_authorization, &gate_](web::http::http_request req) { nmos::ws_api_gate gate(gate_, req.request_uri()); @@ -60,6 +60,10 @@ namespace nmos // Clients SHOULD use the "Authorization Request Header Field" method. // Clients MAY use a "URI Query Parameter". // See https://tools.ietf.org/html/rfc6750#section-2 + if (ws_validate_authorization) + { + if (!ws_validate_authorization(req, nmos::experimental::scopes::ncp)) { return false; } + } // For now just return true const auto& ws_ncp_path = req.request_uri().path(); diff --git a/Development/nmos/control_protocol_ws_api.h b/Development/nmos/control_protocol_ws_api.h index 1d8052cd8..1bf3c556a 100644 --- a/Development/nmos/control_protocol_ws_api.h +++ b/Development/nmos/control_protocol_ws_api.h @@ -3,6 +3,7 @@ #include "nmos/control_protocol_handlers.h" #include "nmos/websockets.h" +#include "nmos/ws_api_utils.h" namespace slog { @@ -13,15 +14,15 @@ namespace nmos { struct node_model; - web::websockets::experimental::listener::validate_handler make_control_protocol_ws_validate_handler(nmos::node_model& model, slog::base_gate& gate); + web::websockets::experimental::listener::validate_handler make_control_protocol_ws_validate_handler(nmos::node_model& model, nmos::experimental::ws_validate_authorization_handler ws_validate_authorization, slog::base_gate& gate); web::websockets::experimental::listener::open_handler make_control_protocol_ws_open_handler(nmos::node_model& model, nmos::websockets& websockets, slog::base_gate& gate); web::websockets::experimental::listener::close_handler make_control_protocol_ws_close_handler(nmos::node_model& model, nmos::websockets& websockets, slog::base_gate& gate); web::websockets::experimental::listener::message_handler make_control_protocol_ws_message_handler(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::get_control_protocol_method_handler get_control_protocol_method, nmos::control_protocol_property_changed_handler property_changed, slog::base_gate& gate); - inline web::websockets::experimental::listener::websocket_listener_handlers make_control_protocol_ws_api(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::get_control_protocol_method_handler get_control_protocol_method, nmos::control_protocol_property_changed_handler property_changed, slog::base_gate& gate) + inline web::websockets::experimental::listener::websocket_listener_handlers make_control_protocol_ws_api(nmos::node_model& model, nmos::websockets& websockets, nmos::experimental::ws_validate_authorization_handler ws_validate_authorization, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::get_control_protocol_method_handler get_control_protocol_method, nmos::control_protocol_property_changed_handler property_changed, slog::base_gate& gate) { return{ - nmos::make_control_protocol_ws_validate_handler(model, gate), + nmos::make_control_protocol_ws_validate_handler(model, ws_validate_authorization, gate), nmos::make_control_protocol_ws_open_handler(model, websockets, gate), nmos::make_control_protocol_ws_close_handler(model, websockets, gate), nmos::make_control_protocol_ws_message_handler(model, websockets, get_control_protocol_class, get_control_protocol_datatype, get_control_protocol_method, property_changed, gate) diff --git a/Development/nmos/node_server.cpp b/Development/nmos/node_server.cpp index 3cb4836d0..5cb290d50 100644 --- a/Development/nmos/node_server.cpp +++ b/Development/nmos/node_server.cpp @@ -78,7 +78,7 @@ namespace nmos { if (control_protocol_ws_port == events_ws_port) throw std::runtime_error("Same port used for events and control protocol websockets are not supported"); auto& control_protocol_ws_api = node_server.ws_handlers[{ {}, control_protocol_ws_port }]; - control_protocol_ws_api.first = nmos::make_control_protocol_ws_api(node_model, control_protocol_ws_api.second, node_implementation.get_control_protocol_class, node_implementation.get_control_protocol_datatype, node_implementation.get_control_protocol_method, node_implementation.control_protocol_property_changed, gate); + control_protocol_ws_api.first = nmos::make_control_protocol_ws_api(node_model, control_protocol_ws_api.second, node_implementation.ws_validate_authorization, node_implementation.get_control_protocol_class, node_implementation.get_control_protocol_datatype, node_implementation.get_control_protocol_method, node_implementation.control_protocol_property_changed, gate); } // Set up the listeners for each HTTP API port diff --git a/Development/nmos/scope.h b/Development/nmos/scope.h index 1f3999531..25d65004e 100644 --- a/Development/nmos/scope.h +++ b/Development/nmos/scope.h @@ -24,6 +24,8 @@ namespace nmos const scope events{ U("events") }; // IS-08 const scope channelmapping{ U("channelmapping") }; + // IS-12 + const scope ncp{ U("ncp") }; } inline utility::string_t make_scope(const scope& scope) @@ -40,6 +42,7 @@ namespace nmos if (scopes::netctrl.name == scope) { return scopes::netctrl; } if (scopes::events.name == scope) { return scopes::events; } if (scopes::channelmapping.name == scope) { return scopes::channelmapping; } + if (scopes::ncp.name == scope) { return scopes::ncp; } return{}; } } From 6fd4e7805cde125953d4fd6cb946350eb7d15d92 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Mon, 8 Jan 2024 23:48:59 +0000 Subject: [PATCH 085/106] Prevent warning C26800 --- .../nmos-cpp-node/node_implementation.cpp | 6 +- Development/nmos/control_protocol_handlers.h | 2 +- Development/nmos/control_protocol_methods.cpp | 816 +++++++++--------- Development/nmos/control_protocol_methods.h | 61 +- Development/nmos/control_protocol_state.cpp | 26 +- Development/nmos/control_protocol_utils.cpp | 39 +- Development/nmos/control_protocol_utils.h | 6 +- Development/nmos/control_protocol_ws_api.cpp | 2 +- 8 files changed, 482 insertions(+), 476 deletions(-) diff --git a/Development/nmos-cpp-node/node_implementation.cpp b/Development/nmos-cpp-node/node_implementation.cpp index be0359e69..486ac35d0 100644 --- a/Development/nmos-cpp-node/node_implementation.cpp +++ b/Development/nmos-cpp-node/node_implementation.cpp @@ -1008,7 +1008,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr nmos::experimental::make_control_class_property(U("Example object sequence property"), { 3, 14 }, object_sequence, U("ExampleDataType"), false, false, true) }; - auto example_method_with_no_args = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::control_protocol_property_changed_handler, slog::base_gate& gate) + auto example_method_with_no_args = [](nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::control_protocol_property_changed_handler, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -1016,7 +1016,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr return nmos::make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::nc_method_status::ok }); }; - auto example_method_with_simple_args = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::control_protocol_property_changed_handler, slog::base_gate& gate) + auto example_method_with_simple_args = [](nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::control_protocol_property_changed_handler, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... // and the method parameters constriants has already been validated by the outter function @@ -1025,7 +1025,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr return nmos::make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::nc_method_status::ok }); }; - auto example_method_with_object_args = [](nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::control_protocol_property_changed_handler, slog::base_gate& gate) + auto example_method_with_object_args = [](nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::control_protocol_property_changed_handler, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... // and the method parameters constriants has already been validated by the outter function diff --git a/Development/nmos/control_protocol_handlers.h b/Development/nmos/control_protocol_handlers.h index b98766b83..516d9c21a 100644 --- a/Development/nmos/control_protocol_handlers.h +++ b/Development/nmos/control_protocol_handlers.h @@ -40,7 +40,7 @@ namespace nmos namespace experimental { // method handler definition - typedef std::function method_handler; + typedef std::function method_handler; // method definition (NcMethodDescriptor vs method handler) typedef std::pair method; diff --git a/Development/nmos/control_protocol_methods.cpp b/Development/nmos/control_protocol_methods.cpp index a6eed1807..bfa3125a7 100644 --- a/Development/nmos/control_protocol_methods.cpp +++ b/Development/nmos/control_protocol_methods.cpp @@ -10,565 +10,566 @@ namespace nmos { - namespace details + // NcObject methods implementation + // Get property value + web::json::value get(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) { - // NcObject methods implementation - // Get property value - web::json::value get(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) - { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - const auto& property_id = nmos::fields::nc::id(arguments); + const auto& property_id = nmos::fields::nc::id(arguments); - slog::log(gate, SLOG_FLF) << "Get property: " << property_id.serialize(); - - // find the relevant nc_property_descriptor - const auto& property = find_property(parse_nc_property_id(property_id), parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), get_control_protocol_class); - if (!property.is_null()) - { - return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }, resource->data.at(nmos::fields::nc::name(property))); - } + slog::log(gate, SLOG_FLF) << "Get property: " << property_id.serialize(); - // unknown property - utility::stringstream_t ss; - ss << U("unknown property: ") << property_id.serialize() << U(" to do Get"); - return make_control_protocol_error_response(handle, { nc_method_status::property_not_implemented }, ss.str()); + // find the relevant nc_property_descriptor + const auto& property = find_property(details::parse_nc_property_id(property_id), details::parse_nc_class_id(nmos::fields::nc::class_id(resource.data)), get_control_protocol_class); + if (!property.is_null()) + { + return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }, resource.data.at(nmos::fields::nc::name(property))); } - // Set property value - web::json::value set(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler get_control_protocol_datatype, control_protocol_property_changed_handler property_changed, slog::base_gate& gate) - { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + // unknown property + utility::stringstream_t ss; + ss << U("unknown property: ") << property_id.serialize() << U(" to do Get"); + return make_control_protocol_error_response(handle, { nc_method_status::property_not_implemented }, ss.str()); + } + + // Set property value + web::json::value set(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler get_control_protocol_datatype, control_protocol_property_changed_handler property_changed, slog::base_gate& gate) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - const auto& property_id = nmos::fields::nc::id(arguments); - const auto& val = nmos::fields::nc::value(arguments); + const auto& property_id = nmos::fields::nc::id(arguments); + const auto& val = nmos::fields::nc::value(arguments); - slog::log(gate, SLOG_FLF) << "Set property: " << property_id.serialize() << " value: " << val.serialize(); + slog::log(gate, SLOG_FLF) << "Set property: " << property_id.serialize() << " value: " << val.serialize(); - // find the relevant nc_property_descriptor - const auto property_id_ = parse_nc_property_id(property_id); - const auto& property = find_property(property_id_, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), get_control_protocol_class); - if (!property.is_null()) + // find the relevant nc_property_descriptor + const auto property_id_ = details::parse_nc_property_id(property_id); + const auto& property = find_property(property_id_, details::parse_nc_class_id(nmos::fields::nc::class_id(resource.data)), get_control_protocol_class); + if (!property.is_null()) + { + if (nmos::fields::nc::is_read_only(property)) { - if (nmos::fields::nc::is_read_only(property)) - { - return make_control_protocol_message_response(handle, { nc_method_status::read_only }); - } + return make_control_protocol_message_response(handle, { nc_method_status::read_only }); + } - if ((val.is_null() && !nmos::fields::nc::is_nullable(property)) - || (!val.is_array() && nmos::fields::nc::is_sequence(property)) - || (val.is_array() && !nmos::fields::nc::is_sequence(property))) - { - return make_control_protocol_message_response(handle, { nc_method_status::parameter_error }); - } + if ((val.is_null() && !nmos::fields::nc::is_nullable(property)) + || (!val.is_array() && nmos::fields::nc::is_sequence(property)) + || (val.is_array() && !nmos::fields::nc::is_sequence(property))) + { + return make_control_protocol_message_response(handle, { nc_method_status::parameter_error }); + } - try + try + { + // do property constraints validation + nmos::details::constraints_validation(val, details::get_runtime_property_constraints(property_id_, resource.data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), { details::get_datatype_descriptor(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype), get_control_protocol_datatype }); + + // update property + modify_control_protocol_resource(resources, resource.id, [&](nmos::resource& resource) { - // do property constraints validation - nmos::details::constraints_validation(val, get_runtime_property_constraints(property_id_, resource->data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), { get_datatype_descriptor(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype), get_control_protocol_datatype }); + resource.data[nmos::fields::nc::name(property)] = val; - // update property - modify_control_protocol_resource(resources, resource->id, [&](nmos::resource& resource) + // do notification that the specified property has changed + if (property_changed) { - resource.data[nmos::fields::nc::name(property)] = val; - - // do notification that the specified property has changed - if (property_changed) - { - property_changed(resource, nmos::fields::nc::name(property), -1); - } - - }, make_propertry_changed_event(nmos::fields::nc::oid(resource->data), { { property_id_, nc_property_change_type::type::value_changed, val } })); + property_changed(resource, nmos::fields::nc::name(property), -1); + } - return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }); - } - catch (const nmos::control_protocol_exception& e) - { - slog::log(gate, SLOG_FLF) << "Set property: " << property_id.serialize() << " value: " << val.serialize() << " error: " << e.what(); + }, make_propertry_changed_event(nmos::fields::nc::oid(resource.data), { { property_id_, nc_property_change_type::type::value_changed, val } })); - return make_control_protocol_message_response(handle, { nc_method_status::parameter_error }); - } + return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }); } + catch (const nmos::control_protocol_exception& e) + { + slog::log(gate, SLOG_FLF) << "Set property: " << property_id.serialize() << " value: " << val.serialize() << " error: " << e.what(); - // unknown property - utility::stringstream_t ss; - ss << U("unknown property: ") << property_id.serialize() << " to do Set"; - return make_control_protocol_error_response(handle, { nc_method_status::property_not_implemented }, ss.str()); + return make_control_protocol_message_response(handle, { nc_method_status::parameter_error }); + } } - // Get sequence item - web::json::value get_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) - { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - - const auto& property_id = nmos::fields::nc::id(arguments); - const auto& index = nmos::fields::nc::index(arguments); + // unknown property + utility::stringstream_t ss; + ss << U("unknown property: ") << property_id.serialize() << " to do Set"; + return make_control_protocol_error_response(handle, { nc_method_status::property_not_implemented }, ss.str()); + } - slog::log(gate, SLOG_FLF) << "Get sequence item: " << property_id.serialize() << " index: " << index; + // Get sequence item + web::json::value get_sequence_item(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - // find the relevant nc_property_descriptor - const auto& property = find_property(parse_nc_property_id(property_id), parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), get_control_protocol_class); - if (!property.is_null()) - { - const auto& data = resource->data.at(nmos::fields::nc::name(property)); + const auto& property_id = nmos::fields::nc::id(arguments); + const auto& index = nmos::fields::nc::index(arguments); - if (!nmos::fields::nc::is_sequence(property) || data.is_null() || !data.is_array()) - { - // property is not a sequence - utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do GetSequenceItem"); - return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); - } + slog::log(gate, SLOG_FLF) << "Get sequence item: " << property_id.serialize() << " index: " << index; - if (data.as_array().size() > (size_t)index) - { - return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }, data.at(index)); - } + // find the relevant nc_property_descriptor + const auto& property = find_property(details::parse_nc_property_id(property_id), details::parse_nc_class_id(nmos::fields::nc::class_id(resource.data)), get_control_protocol_class); + if (!property.is_null()) + { + const auto& data = resource.data.at(nmos::fields::nc::name(property)); - // out of bound + if (!nmos::fields::nc::is_sequence(property) || data.is_null() || !data.is_array()) + { + // property is not a sequence utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << U(" is outside the available range to do GetSequenceItem"); - return make_control_protocol_error_response(handle, { nc_method_status::index_out_of_bounds }, ss.str()); + ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do GetSequenceItem"); + return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); } - // unknown property - utility::stringstream_t ss; - ss << U("unknown property: ") << property_id.serialize() << U(" to do GetSequenceItem"); - return make_control_protocol_error_response(handle, { nc_method_status::property_not_implemented }, ss.str()); - } - - // Set sequence item - web::json::value set_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler get_control_protocol_datatype, control_protocol_property_changed_handler property_changed, slog::base_gate& gate) - { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - - const auto& property_id = nmos::fields::nc::id(arguments); - const auto& index = nmos::fields::nc::index(arguments); - const auto& val = nmos::fields::nc::value(arguments); - - slog::log(gate, SLOG_FLF) << "Set sequence item: " << property_id.serialize() << " index: " << index << " value: " << val.serialize(); - - // find the relevant nc_property_descriptor - const auto property_id_ = parse_nc_property_id(property_id); - const auto& property = find_property(property_id_, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), get_control_protocol_class); - if (!property.is_null()) + if (data.as_array().size() > (size_t)index) { - if (nmos::fields::nc::is_read_only(property)) - { - return make_control_protocol_message_response(handle, { nc_method_status::read_only }); - } - - auto& data = resource->data.at(nmos::fields::nc::name(property)); - - if (!nmos::fields::nc::is_sequence(property) || data.is_null() || !data.is_array()) - { - // property is not a sequence - utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do SetSequenceItem"); - return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); - } - - if (data.as_array().size() > (size_t)index) - { - try - { - // do property constraints validation - nmos::details::constraints_validation(val, get_runtime_property_constraints(property_id_, resource->data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), { get_datatype_descriptor(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype), get_control_protocol_datatype }); - - // update property - modify_control_protocol_resource(resources, resource->id, [&](nmos::resource& resource) - { - resource.data[nmos::fields::nc::name(property)][index] = val; - - // do notification that the specified property has changed - if (property_changed) - { - property_changed(resource, nmos::fields::nc::name(property), index); - } - - }, make_propertry_changed_event(nmos::fields::nc::oid(resource->data), { { property_id_, nc_property_change_type::type::sequence_item_changed, val, nc_id(index) } })); - - return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }); - } - catch (const nmos::control_protocol_exception& e) - { - slog::log(gate, SLOG_FLF) << "Set sequence item: " << property_id.serialize() << " index: " << index << " value: " << val.serialize() << " error: " << e.what(); - - return make_control_protocol_message_response(handle, { nc_method_status::parameter_error }); - } - } - - // out of bound - utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << U(" is outside the available range to do SetSequenceItem"); - return make_control_protocol_error_response(handle, { nc_method_status::index_out_of_bounds }, ss.str()); + return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }, data.at(index)); } - // unknown property + // out of bound utility::stringstream_t ss; - ss << U("unknown property: ") << property_id.serialize() << U(" to do SetSequenceItem"); - return make_control_protocol_error_response(handle, { nc_method_status::property_not_implemented }, ss.str()); + ss << U("property: ") << property_id.serialize() << U(" is outside the available range to do GetSequenceItem"); + return make_control_protocol_error_response(handle, { nc_method_status::index_out_of_bounds }, ss.str()); } - // Add item to sequence - web::json::value add_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler get_control_protocol_datatype, control_protocol_property_changed_handler property_changed, slog::base_gate& gate) - { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + // unknown property + utility::stringstream_t ss; + ss << U("unknown property: ") << property_id.serialize() << U(" to do GetSequenceItem"); + return make_control_protocol_error_response(handle, { nc_method_status::property_not_implemented }, ss.str()); + } - using web::json::value; + // Set sequence item + web::json::value set_sequence_item(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler get_control_protocol_datatype, control_protocol_property_changed_handler property_changed, slog::base_gate& gate) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - const auto& property_id = nmos::fields::nc::id(arguments); - const auto& val = nmos::fields::nc::value(arguments); + const auto& property_id = nmos::fields::nc::id(arguments); + const auto& index = nmos::fields::nc::index(arguments); + const auto& val = nmos::fields::nc::value(arguments); - slog::log(gate, SLOG_FLF) << "Add sequence item: " << property_id.serialize() << " value: " << val.serialize(); + slog::log(gate, SLOG_FLF) << "Set sequence item: " << property_id.serialize() << " index: " << index << " value: " << val.serialize(); - // find the relevant nc_property_descriptor - const auto property_id_ = parse_nc_property_id(property_id); - const auto& property = find_property(property_id_, parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), get_control_protocol_class); - if (!property.is_null()) + // find the relevant nc_property_descriptor + const auto property_id_ = details::parse_nc_property_id(property_id); + const auto& property = find_property(property_id_, details::parse_nc_class_id(nmos::fields::nc::class_id(resource.data)), get_control_protocol_class); + if (!property.is_null()) + { + if (nmos::fields::nc::is_read_only(property)) { - if (nmos::fields::nc::is_read_only(property)) - { - return make_control_protocol_message_response(handle, { nc_method_status::read_only }); - } - - if (!nmos::fields::nc::is_sequence(property)) - { - // property is not a sequence - utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do AddSequenceItem"); - return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); - } + return make_control_protocol_message_response(handle, { nc_method_status::read_only }); + } - auto& data = resource->data.at(nmos::fields::nc::name(property)); + auto& data = resource.data.at(nmos::fields::nc::name(property)); - const nc_id sequence_item_index = data.is_null() ? 0 : nc_id(data.as_array().size()); + if (!nmos::fields::nc::is_sequence(property) || data.is_null() || !data.is_array()) + { + // property is not a sequence + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do SetSequenceItem"); + return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); + } + if (data.as_array().size() > (size_t)index) + { try { // do property constraints validation - nmos::details::constraints_validation(val, get_runtime_property_constraints(property_id_, resource->data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), { get_datatype_descriptor(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype), get_control_protocol_datatype }); + nmos::details::constraints_validation(val, details::get_runtime_property_constraints(property_id_, resource.data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), { details::get_datatype_descriptor(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype), get_control_protocol_datatype }); // update property - modify_control_protocol_resource(resources, resource->id, [&](nmos::resource& resource) + modify_control_protocol_resource(resources, resource.id, [&](nmos::resource& resource) { - auto& sequence = resource.data[nmos::fields::nc::name(property)]; - if (data.is_null()) { sequence = value::array(); } - web::json::push_back(sequence, val); + resource.data[nmos::fields::nc::name(property)][index] = val; // do notification that the specified property has changed if (property_changed) { - property_changed(resource, nmos::fields::nc::name(property), sequence.as_array().size()-1); + property_changed(resource, nmos::fields::nc::name(property), index); } - }, make_propertry_changed_event(nmos::fields::nc::oid(resource->data), { { property_id_, nc_property_change_type::type::sequence_item_added, val, sequence_item_index } })); + }, make_propertry_changed_event(nmos::fields::nc::oid(resource.data), { { property_id_, nc_property_change_type::type::sequence_item_changed, val, nc_id(index) } })); - return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }, sequence_item_index); + return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }); } catch (const nmos::control_protocol_exception& e) { - slog::log(gate, SLOG_FLF) << "Add sequence item: " << property_id.serialize() << " value: " << val.serialize() << " error: " << e.what(); + slog::log(gate, SLOG_FLF) << "Set sequence item: " << property_id.serialize() << " index: " << index << " value: " << val.serialize() << " error: " << e.what(); return make_control_protocol_message_response(handle, { nc_method_status::parameter_error }); } } - // unknown property + // out of bound utility::stringstream_t ss; - ss << U("unknown property: ") << property_id.serialize() << U(" to do AddSequenceItem"); - return make_control_protocol_error_response(handle, { nc_method_status::property_not_implemented }, ss.str()); + ss << U("property: ") << property_id.serialize() << U(" is outside the available range to do SetSequenceItem"); + return make_control_protocol_error_response(handle, { nc_method_status::index_out_of_bounds }, ss.str()); } - // Delete sequence item - web::json::value remove_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) + // unknown property + utility::stringstream_t ss; + ss << U("unknown property: ") << property_id.serialize() << U(" to do SetSequenceItem"); + return make_control_protocol_error_response(handle, { nc_method_status::property_not_implemented }, ss.str()); + } + + // Add item to sequence + web::json::value add_sequence_item(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler get_control_protocol_datatype, control_protocol_property_changed_handler property_changed, slog::base_gate& gate) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + using web::json::value; + + const auto& property_id = nmos::fields::nc::id(arguments); + const auto& val = nmos::fields::nc::value(arguments); + + slog::log(gate, SLOG_FLF) << "Add sequence item: " << property_id.serialize() << " value: " << val.serialize(); + + // find the relevant nc_property_descriptor + const auto property_id_ = details::parse_nc_property_id(property_id); + const auto& property = find_property(property_id_, details::parse_nc_class_id(nmos::fields::nc::class_id(resource.data)), get_control_protocol_class); + if (!property.is_null()) { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + if (nmos::fields::nc::is_read_only(property)) + { + return make_control_protocol_message_response(handle, { nc_method_status::read_only }); + } - const auto& property_id = nmos::fields::nc::id(arguments); - const auto& index = nmos::fields::nc::index(arguments); + if (!nmos::fields::nc::is_sequence(property)) + { + // property is not a sequence + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do AddSequenceItem"); + return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); + } - slog::log(gate, SLOG_FLF) << "Remove sequence item: " << property_id.serialize() << " index: " << index; + auto& data = resource.data.at(nmos::fields::nc::name(property)); - // find the relevant nc_property_descriptor - const auto& property = find_property(parse_nc_property_id(property_id), parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), get_control_protocol_class); - if (!property.is_null()) + const nc_id sequence_item_index = data.is_null() ? 0 : nc_id(data.as_array().size()); + + try { - const auto& data = resource->data.at(nmos::fields::nc::name(property)); + // do property constraints validation + nmos::details::constraints_validation(val, details::get_runtime_property_constraints(property_id_, resource.data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), { details::get_datatype_descriptor(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype), get_control_protocol_datatype }); - if (!nmos::fields::nc::is_sequence(property) || data.is_null() || !data.is_array()) + // update property + modify_control_protocol_resource(resources, resource.id, [&](nmos::resource& resource) { - // property is not a sequence - utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do RemoveSequenceItem"); - return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); - } + auto& sequence = resource.data[nmos::fields::nc::name(property)]; + if (data.is_null()) { sequence = value::array(); } + web::json::push_back(sequence, val); - if (data.as_array().size() > (size_t)index) - { - modify_control_protocol_resource(resources, resource->id, [&](nmos::resource& resource) + // do notification that the specified property has changed + if (property_changed) { - auto& sequence = resource.data[nmos::fields::nc::name(property)].as_array(); - sequence.erase(index); + property_changed(resource, nmos::fields::nc::name(property), (int)sequence.as_array().size()-1); + } - }, make_propertry_changed_event(nmos::fields::nc::oid(resource->data), { { parse_nc_property_id(property_id), nc_property_change_type::type::sequence_item_removed, nc_id(index) } })); + }, make_propertry_changed_event(nmos::fields::nc::oid(resource.data), { { property_id_, nc_property_change_type::type::sequence_item_added, val, sequence_item_index } })); - return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }); - } + return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }, sequence_item_index); + } + catch (const nmos::control_protocol_exception& e) + { + slog::log(gate, SLOG_FLF) << "Add sequence item: " << property_id.serialize() << " value: " << val.serialize() << " error: " << e.what(); + + return make_control_protocol_message_response(handle, { nc_method_status::parameter_error }); + } + } + + // unknown property + utility::stringstream_t ss; + ss << U("unknown property: ") << property_id.serialize() << U(" to do AddSequenceItem"); + return make_control_protocol_error_response(handle, { nc_method_status::property_not_implemented }, ss.str()); + } - // out of bound + // Delete sequence item + web::json::value remove_sequence_item(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + const auto& property_id = nmos::fields::nc::id(arguments); + const auto& index = nmos::fields::nc::index(arguments); + + slog::log(gate, SLOG_FLF) << "Remove sequence item: " << property_id.serialize() << " index: " << index; + + // find the relevant nc_property_descriptor + const auto& property = find_property(details::parse_nc_property_id(property_id), details::parse_nc_class_id(nmos::fields::nc::class_id(resource.data)), get_control_protocol_class); + if (!property.is_null()) + { + const auto& data = resource.data.at(nmos::fields::nc::name(property)); + + if (!nmos::fields::nc::is_sequence(property) || data.is_null() || !data.is_array()) + { + // property is not a sequence utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << U(" is outside the available range to do RemoveSequenceItem"); - return make_control_protocol_error_response(handle, { nc_method_status::index_out_of_bounds }, ss.str()); + ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do RemoveSequenceItem"); + return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); } - // unknown property + if (data.as_array().size() > (size_t)index) + { + modify_control_protocol_resource(resources, resource.id, [&](nmos::resource& resource) + { + auto& sequence = resource.data[nmos::fields::nc::name(property)].as_array(); + sequence.erase(index); + + }, make_propertry_changed_event(nmos::fields::nc::oid(resource.data), { { details::parse_nc_property_id(property_id), nc_property_change_type::type::sequence_item_removed, nc_id(index) } })); + + return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }); + } + + // out of bound utility::stringstream_t ss; - ss << U("unknown property: ") << property_id.serialize() << U(" to do RemoveSequenceItem"); - return make_control_protocol_error_response(handle, { nc_method_status::property_not_implemented }, ss.str()); + ss << U("property: ") << property_id.serialize() << U(" is outside the available range to do RemoveSequenceItem"); + return make_control_protocol_error_response(handle, { nc_method_status::index_out_of_bounds }, ss.str()); } - // Get sequence length - web::json::value get_sequence_length(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) - { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + // unknown property + utility::stringstream_t ss; + ss << U("unknown property: ") << property_id.serialize() << U(" to do RemoveSequenceItem"); + return make_control_protocol_error_response(handle, { nc_method_status::property_not_implemented }, ss.str()); + } + + // Get sequence length + web::json::value get_sequence_length(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - using web::json::value; + using web::json::value; - const auto& property_id = nmos::fields::nc::id(arguments); + const auto& property_id = nmos::fields::nc::id(arguments); - slog::log(gate, SLOG_FLF) << "Get sequence length: " << property_id.serialize(); + slog::log(gate, SLOG_FLF) << "Get sequence length: " << property_id.serialize(); - // find the relevant nc_property_descriptor - const auto& property = find_property(parse_nc_property_id(property_id), parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), get_control_protocol_class); - if (!property.is_null()) + // find the relevant nc_property_descriptor + const auto& property = find_property(details::parse_nc_property_id(property_id), details::parse_nc_class_id(nmos::fields::nc::class_id(resource.data)), get_control_protocol_class); + if (!property.is_null()) + { + if (!nmos::fields::nc::is_sequence(property)) { - if (!nmos::fields::nc::is_sequence(property)) - { - // property is not a sequence - utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do GetSequenceLength"); - return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); - } + // property is not a sequence + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << U(" is not a sequence to do GetSequenceLength"); + return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); + } - const auto& data = resource->data.at(nmos::fields::nc::name(property)); + const auto& data = resource.data.at(nmos::fields::nc::name(property)); - if (nmos::fields::nc::is_nullable(property)) + if (nmos::fields::nc::is_nullable(property)) + { + // can be null + if (data.is_null()) { - // can be null - if (data.is_null()) - { - // null - return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }, value::null()); - } + // null + return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }, value::null()); } - else + } + else + { + // cannot be null + if (data.is_null()) { - // cannot be null - if (data.is_null()) - { - // null - utility::stringstream_t ss; - ss << U("property: ") << property_id.serialize() << " is a null sequence to do GetSequenceLength"; - return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); - } + // null + utility::stringstream_t ss; + ss << U("property: ") << property_id.serialize() << " is a null sequence to do GetSequenceLength"; + return make_control_protocol_error_response(handle, { nc_method_status::invalid_request }, ss.str()); } - return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }, uint32_t(data.as_array().size())); } - - // unknown property - utility::stringstream_t ss; - ss << U("unknown property: ") << property_id.serialize() << " to do GetSequenceLength"; - return make_control_protocol_error_response(handle, { nc_method_status::property_not_implemented }, ss.str()); + return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }, uint32_t(data.as_array().size())); } - // NcBlock methods implementation - // Gets descriptors of members of the block - web::json::value get_member_descriptors(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) - { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + // unknown property + utility::stringstream_t ss; + ss << U("unknown property: ") << property_id.serialize() << " to do GetSequenceLength"; + return make_control_protocol_error_response(handle, { nc_method_status::property_not_implemented }, ss.str()); + } - using web::json::value; + // NcBlock methods implementation + // Gets descriptors of members of the block + web::json::value get_member_descriptors(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - const auto& recurse = nmos::fields::nc::recurse(arguments); // If recurse is set to true, nested members is to be retrieved + using web::json::value; - slog::log(gate, SLOG_FLF) << "Get descriptors of members of the block: " << "recurse: " << recurse; + const auto& recurse = nmos::fields::nc::recurse(arguments); // If recurse is set to true, nested members is to be retrieved - auto descriptors = value::array(); - nmos::get_member_descriptors(resources, resource, recurse, descriptors.as_array()); + slog::log(gate, SLOG_FLF) << "Get descriptors of members of the block: " << "recurse: " << recurse; - return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nc_method_status::ok }, descriptors); - } + auto descriptors = value::array(); + nmos::get_member_descriptors(resources, resource, recurse, descriptors.as_array()); - // Finds member(s) by path - web::json::value find_members_by_path(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) - { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nc_method_status::ok }, descriptors); + } - using web::json::value; + // Finds member(s) by path + web::json::value find_members_by_path(nmos::resources& resources, const nmos::resource& resource_, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - // Relative path to search for (MUST not include the role of the block targeted by oid) - const auto& path = arguments.at(nmos::fields::nc::path); + using web::json::value; - slog::log(gate, SLOG_FLF) << "Find member(s) by path: " << "path: " << path.serialize(); + // Relative path to search for (MUST not include the role of the block targeted by oid) + const auto& path = arguments.at(nmos::fields::nc::path); - if (0 == path.size()) - { - // empty path - return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("empty path to do FindMembersByPath")); - } + slog::log(gate, SLOG_FLF) << "Find member(s) by path: " << "path: " << path.serialize(); + + if (0 == path.size()) + { + // empty path + return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("empty path to do FindMembersByPath")); + } - auto descriptors = value::array(); - value descriptor; + auto descriptors = value::array(); + value descriptor; + + nmos::resource resource = resource_; + for (const auto& role : path.as_array()) + { + // look for the role in members - for (const auto& role : path.as_array()) + if (resource.data.has_field(nmos::fields::nc::members)) { - // look for the role in members - if (resource->data.has_field(nmos::fields::nc::members)) + auto& members = nmos::fields::nc::members(resource.data); + auto member_found = std::find_if(members.begin(), members.end(), [&](const web::json::value& nc_block_member_descriptor) { - auto& members = nmos::fields::nc::members(resource->data); - auto member_found = std::find_if(members.begin(), members.end(), [&](const web::json::value& nc_block_member_descriptor) - { - return role.as_string() == nmos::fields::nc::role(nc_block_member_descriptor); - }); + return role.as_string() == nmos::fields::nc::role(nc_block_member_descriptor); + }); - if (members.end() != member_found) - { - descriptor = *member_found; + if (members.end() != member_found) + { + descriptor = *member_found; - // use oid to look for the next resource - resource = nmos::find_resource(resources, utility::s2us(std::to_string(nmos::fields::nc::oid(*member_found)))); - } - else - { - // no role - utility::stringstream_t ss; - ss << U("role: ") << role.as_string() << U(" not found to do FindMembersByPath"); - return make_control_protocol_error_response(handle, { nc_method_status::bad_oid }, ss.str()); - } + // use oid to look for the next resource + resource = *nmos::find_resource(resources, utility::s2us(std::to_string(nmos::fields::nc::oid(*member_found)))); } else { - // no members - return make_control_protocol_error_response(handle, { nc_method_status::bad_oid }, U("no members to do FindMembersByPath")); + // no role + utility::stringstream_t ss; + ss << U("role: ") << role.as_string() << U(" not found to do FindMembersByPath"); + return make_control_protocol_error_response(handle, { nc_method_status::bad_oid }, ss.str()); } } - - web::json::push_back(descriptors, descriptor); - return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nc_method_status::ok }, descriptors); + else + { + // no members + return make_control_protocol_error_response(handle, { nc_method_status::bad_oid }, U("no members to do FindMembersByPath")); + } } - // Finds members with given role name or fragment - web::json::value find_members_by_role(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) - { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - - using web::json::value; - - const auto& role = nmos::fields::nc::role(arguments); // Role text to search for - const auto& case_sensitive = nmos::fields::nc::case_sensitive(arguments); // Signals if the comparison should be case sensitive - const auto& match_whole_string = nmos::fields::nc::match_whole_string(arguments); // TRUE to only return exact matches - const auto& recurse = nmos::fields::nc::recurse(arguments); // TRUE to search nested blocks + web::json::push_back(descriptors, descriptor); + return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nc_method_status::ok }, descriptors); + } - slog::log(gate, SLOG_FLF) << "Find members with given role name or fragment: " << "role: " << role; + // Finds members with given role name or fragment + web::json::value find_members_by_role(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - if (role.empty()) - { - // empty role - return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("empty role to do FindMembersByRole")); - } + using web::json::value; - auto descriptors = value::array(); - nmos::find_members_by_role(resources, resource, role, match_whole_string, case_sensitive, recurse, descriptors.as_array()); + const auto& role = nmos::fields::nc::role(arguments); // Role text to search for + const auto& case_sensitive = nmos::fields::nc::case_sensitive(arguments); // Signals if the comparison should be case sensitive + const auto& match_whole_string = nmos::fields::nc::match_whole_string(arguments); // TRUE to only return exact matches + const auto& recurse = nmos::fields::nc::recurse(arguments); // TRUE to search nested blocks - return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nc_method_status::ok }, descriptors); - } + slog::log(gate, SLOG_FLF) << "Find members with given role name or fragment: " << "role: " << role; - // Finds members with given class id - web::json::value find_members_by_class_id(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) + if (role.empty()) { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + // empty role + return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("empty role to do FindMembersByRole")); + } - using web::json::value; + auto descriptors = value::array(); + nmos::find_members_by_role(resources, resource, role, match_whole_string, case_sensitive, recurse, descriptors.as_array()); - const auto& class_id = parse_nc_class_id(nmos::fields::nc::class_id(arguments)); // Class id to search for - const auto& include_derived = nmos::fields::nc::include_derived(arguments); // If TRUE it will also include derived class descriptors - const auto& recurse = nmos::fields::nc::recurse(arguments); // TRUE to search nested blocks + return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nc_method_status::ok }, descriptors); + } - slog::log(gate, SLOG_FLF) << "Find members with given class id: " << "class_id: " << nmos::details::make_nc_class_id(class_id).serialize(); + // Finds members with given class id + web::json::value find_members_by_class_id(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) + { + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - if (class_id.empty()) - { - // empty class_id - return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("empty classId to do FindMembersByClassId")); - } + using web::json::value; - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + const auto& class_id = details::parse_nc_class_id(nmos::fields::nc::class_id(arguments)); // Class id to search for + const auto& include_derived = nmos::fields::nc::include_derived(arguments); // If TRUE it will also include derived class descriptors + const auto& recurse = nmos::fields::nc::recurse(arguments); // TRUE to search nested blocks - auto descriptors = value::array(); - nmos::find_members_by_class_id(resources, resource, class_id, include_derived, recurse, descriptors.as_array()); + slog::log(gate, SLOG_FLF) << "Find members with given class id: " << "class_id: " << nmos::details::make_nc_class_id(class_id).serialize(); - return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nc_method_status::ok }, descriptors); + if (class_id.empty()) + { + // empty class_id + return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("empty classId to do FindMembersByClassId")); } - // NcClassManager methods implementation - // Get a single class descriptor - web::json::value get_control_class(nmos::resources&, nmos::resources::iterator, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) - { - using web::json::value; + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - const auto& class_id = parse_nc_class_id(nmos::fields::nc::class_id(arguments)); // Class id to search for - const auto& include_inherited = nmos::fields::nc::include_inherited(arguments); // If set the descriptor would contain all inherited elements + auto descriptors = value::array(); + nmos::find_members_by_class_id(resources, resource, class_id, include_derived, recurse, descriptors.as_array()); +// auto descriptors = nmos::find_members_by_class_id(resources, resource, class_id, include_derived, recurse);// , descriptors.as_array()); - slog::log(gate, SLOG_FLF) << "Get a single class descriptor: " << "class_id: " << nmos::details::make_nc_class_id(class_id).serialize(); + return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nc_method_status::ok }, descriptors); + } - if (class_id.empty()) - { - // empty class_id - return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("empty classId to do GetControlClass")); - } + // NcClassManager methods implementation + // Get a single class descriptor + web::json::value get_control_class(nmos::resources&, const nmos::resource&, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) + { + using web::json::value; - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + const auto& class_id = details::parse_nc_class_id(nmos::fields::nc::class_id(arguments)); // Class id to search for + const auto& include_inherited = nmos::fields::nc::include_inherited(arguments); // If set the descriptor would contain all inherited elements - const auto& control_class = get_control_protocol_class(class_id); - if (!control_class.class_id.empty()) + slog::log(gate, SLOG_FLF) << "Get a single class descriptor: " << "class_id: " << nmos::details::make_nc_class_id(class_id).serialize(); + + if (class_id.empty()) + { + // empty class_id + return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("empty classId to do GetControlClass")); + } + + // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + + const auto& control_class = get_control_protocol_class(class_id); + if (!control_class.class_id.empty()) + { + auto& description = control_class.description; + auto& name = control_class.name; + auto& fixed_role = control_class.fixed_role; + auto properties = control_class.properties; + auto methods = value::array(); + for (const auto& method : control_class.methods) { web::json::push_back(methods, method.first); } + auto events = control_class.events; + + if (include_inherited) { - auto& description = control_class.description; - auto& name = control_class.name; - auto& fixed_role = control_class.fixed_role; - auto properties = control_class.properties; - auto methods = value::array(); - for (const auto& method : control_class.methods) { web::json::push_back(methods, method.first); } - auto events = control_class.events; + auto inherited_class_id = class_id; + inherited_class_id.pop_back(); - if (include_inherited) + while (!inherited_class_id.empty()) { - auto inherited_class_id = class_id; - inherited_class_id.pop_back(); - - while (!inherited_class_id.empty()) + const auto& inherited_control_class = get_control_protocol_class(inherited_class_id); { - const auto& inherited_control_class = get_control_protocol_class(inherited_class_id); - { - for (const auto& property : inherited_control_class.properties.as_array()) { web::json::push_back(properties, property); } - for (const auto& method : inherited_control_class.methods) { web::json::push_back(methods, method.first); } - for (const auto& event : inherited_control_class.events.as_array()) { web::json::push_back(events, event); } - } - inherited_class_id.pop_back(); + for (const auto& property : inherited_control_class.properties.as_array()) { web::json::push_back(properties, property); } + for (const auto& method : inherited_control_class.methods) { web::json::push_back(methods, method.first); } + for (const auto& event : inherited_control_class.events.as_array()) { web::json::push_back(events, event); } } + inherited_class_id.pop_back(); } - const auto descriptor = fixed_role.is_null() - ? details::make_nc_class_descriptor(description, class_id, name, properties, methods, events) - : details::make_nc_class_descriptor(description, class_id, name, fixed_role.as_string(), properties, methods, events); - - return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nc_method_status::ok }, descriptor); } + const auto descriptor = fixed_role.is_null() + ? details::make_nc_class_descriptor(description, class_id, name, properties, methods, events) + : details::make_nc_class_descriptor(description, class_id, name, fixed_role.as_string(), properties, methods, events); - return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("classId not found")); + return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nc_method_status::ok }, descriptor); } - // Get a single datatype descriptor - web::json::value get_datatype(nmos::resources&, nmos::resources::iterator, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler get_control_protocol_datatype, control_protocol_property_changed_handler, slog::base_gate& gate) + return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("classId not found")); + } + + // Get a single datatype descriptor + web::json::value get_datatype(nmos::resources&, const nmos::resource&, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler get_control_protocol_datatype, control_protocol_property_changed_handler, slog::base_gate& gate) { // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... @@ -625,5 +626,4 @@ namespace nmos return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("name not found")); } - } } diff --git a/Development/nmos/control_protocol_methods.h b/Development/nmos/control_protocol_methods.h index e686c702b..7d74c847a 100644 --- a/Development/nmos/control_protocol_methods.h +++ b/Development/nmos/control_protocol_methods.h @@ -11,40 +11,37 @@ namespace slog namespace nmos { - namespace details - { - // NcObject methods implementation - // Get property value - web::json::value get(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); - // Set property value - web::json::value set(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler property_changed, slog::base_gate& gate); - // Get sequence item - web::json::value get_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); - // Set sequence item - web::json::value set_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler property_changed, slog::base_gate& gate); - // Add item to sequence - web::json::value add_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler property_changed, slog::base_gate& gate); - // Delete sequence item - web::json::value remove_sequence_item(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); - // Get sequence length - web::json::value get_sequence_length(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); + // NcObject methods implementation + // Get property value + web::json::value get(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); + // Set property value + web::json::value set(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler property_changed, slog::base_gate& gate); + // Get sequence item + web::json::value get_sequence_item(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); + // Set sequence item + web::json::value set_sequence_item(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler property_changed, slog::base_gate& gate); + // Add item to sequence + web::json::value add_sequence_item(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler property_changed, slog::base_gate& gate); + // Delete sequence item + web::json::value remove_sequence_item(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); + // Get sequence length + web::json::value get_sequence_length(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); - // NcBlock methods implementation - // Get descriptors of members of the block - web::json::value get_member_descriptors(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); - // Finds member(s) by path - web::json::value find_members_by_path(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); - // Finds members with given role name or fragment - web::json::value find_members_by_role(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); - // Finds members with given class id - web::json::value find_members_by_class_id(nmos::resources& resources, nmos::resources::iterator resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); + // NcBlock methods implementation + // Get descriptors of members of the block + web::json::value get_member_descriptors(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); + // Finds member(s) by path + web::json::value find_members_by_path(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); + // Finds members with given role name or fragment + web::json::value find_members_by_role(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); + // Finds members with given class id + web::json::value find_members_by_class_id(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); - // NcClassManager methods implementation - // Get a single class descriptor - web::json::value get_control_class(nmos::resources&, nmos::resources::iterator, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); - // Get a single datatype descriptor - web::json::value get_datatype(nmos::resources&, nmos::resources::iterator, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler get_control_protocol_datatype, control_protocol_property_changed_handler, slog::base_gate& gate); - } + // NcClassManager methods implementation + // Get a single class descriptor + web::json::value get_control_class(nmos::resources&, const nmos::resource&, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); + // Get a single datatype descriptor + web::json::value get_datatype(nmos::resources&, const nmos::resource&, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler get_control_protocol_datatype, control_protocol_property_changed_handler, slog::base_gate& gate); } #endif diff --git a/Development/nmos/control_protocol_state.cpp b/Development/nmos/control_protocol_state.cpp index 3cc3af38a..153370a5e 100644 --- a/Development/nmos/control_protocol_state.cpp +++ b/Development/nmos/control_protocol_state.cpp @@ -120,13 +120,13 @@ namespace nmos to_methods_vector(make_nc_object_methods(), { // link NcObject method_ids with method functions - { nc_object_get_method_id, nmos::details::get }, - { nc_object_set_method_id, nmos::details::set }, - { nc_object_get_sequence_item_method_id, nmos::details::get_sequence_item }, - { nc_object_set_sequence_item_method_id, nmos::details::set_sequence_item }, - { nc_object_add_sequence_item_method_id, nmos::details::add_sequence_item }, - { nc_object_remove_sequence_item_method_id, nmos::details::remove_sequence_item }, - { nc_object_get_sequence_length_method_id, nmos::details::get_sequence_length } + { nc_object_get_method_id, get }, + { nc_object_set_method_id, set }, + { nc_object_get_sequence_item_method_id, get_sequence_item }, + { nc_object_set_sequence_item_method_id, set_sequence_item }, + { nc_object_add_sequence_item_method_id, add_sequence_item }, + { nc_object_remove_sequence_item_method_id, remove_sequence_item }, + { nc_object_get_sequence_length_method_id, get_sequence_length } }), // NcObject events to_vector(make_nc_object_events())) }, @@ -138,10 +138,10 @@ namespace nmos to_methods_vector(make_nc_block_methods(), { // link NcBlock method_ids with method functions - { nc_block_get_member_descriptors_method_id, nmos::details::get_member_descriptors }, - { nc_block_find_members_by_path_method_id, nmos::details::find_members_by_path }, - { nc_block_find_members_by_role_method_id, nmos::details::find_members_by_role }, - { nc_block_find_members_by_class_id_method_id, nmos::details::find_members_by_class_id } + { nc_block_get_member_descriptors_method_id, get_member_descriptors }, + { nc_block_find_members_by_path_method_id, find_members_by_path }, + { nc_block_find_members_by_role_method_id, find_members_by_role }, + { nc_block_find_members_by_class_id_method_id, find_members_by_class_id } }), // NcBlock events to_vector(make_nc_block_events())) }, @@ -177,8 +177,8 @@ namespace nmos to_methods_vector(make_nc_class_manager_methods(), { // link NcClassManager method_ids with method functions - { nc_class_manager_get_control_class_method_id, nmos::details::get_control_class }, - { nc_class_manager_get_datatype_method_id, nmos::details::get_datatype } + { nc_class_manager_get_control_class_method_id, get_control_class }, + { nc_class_manager_get_datatype_method_id, get_datatype } }), // NcClassManager events to_vector(make_nc_class_manager_events())) }, diff --git a/Development/nmos/control_protocol_utils.cpp b/Development/nmos/control_protocol_utils.cpp index 1a0814530..f89d4b2cd 100644 --- a/Development/nmos/control_protocol_utils.cpp +++ b/Development/nmos/control_protocol_utils.cpp @@ -414,11 +414,11 @@ namespace nmos } // get block member descriptors - void get_member_descriptors(const resources& resources, resources::iterator resource, bool recurse, web::json::array& descriptors) + void get_member_descriptors(const resources& resources, const resource& resource, bool recurse, web::json::array& descriptors) { - if (resource->data.has_field(nmos::fields::nc::members)) + if (resource.data.has_field(nmos::fields::nc::members)) { - const auto& members = nmos::fields::nc::members(resource->data); + const auto& members = nmos::fields::nc::members(resource.data); for (const auto& member : members) { @@ -434,8 +434,11 @@ namespace nmos { // get resource based on the oid const auto& oid = nmos::fields::nc::oid(member); - - get_member_descriptors(resources, find_resource(resources, utility::s2us(std::to_string(oid))), recurse, descriptors); + const auto& found = find_resource(resources, utility::s2us(std::to_string(oid))); + if (resources.end() != found) + { + get_member_descriptors(resources, *found, recurse, descriptors); + } } } } @@ -443,7 +446,7 @@ namespace nmos } // find members with given role name or fragment - void find_members_by_role(const resources& resources, resources::iterator resource, const utility::string_t& role, bool match_whole_string, bool case_sensitive, bool recurse, web::json::array& descriptors) + void find_members_by_role(const resources& resources, const resource& resource, const utility::string_t& role, bool match_whole_string, bool case_sensitive, bool recurse, web::json::array& descriptors) { auto find_members_by_matching_role = [&](const web::json::array& members) { @@ -466,9 +469,9 @@ namespace nmos return boost::make_iterator_range(boost::make_filter_iterator(match, members.begin(), members.end()), boost::make_filter_iterator(match, members.end(), members.end())); }; - if (resource->data.has_field(nmos::fields::nc::members)) + if (resource.data.has_field(nmos::fields::nc::members)) { - const auto& members = nmos::fields::nc::members(resource->data); + const auto& members = nmos::fields::nc::members(resource.data); auto members_found = find_members_by_matching_role(members); for (const auto& member : members_found) @@ -485,8 +488,11 @@ namespace nmos { // get resource based on the oid const auto& oid = nmos::fields::nc::oid(member); - - find_members_by_role(resources, find_resource(resources, utility::s2us(std::to_string(oid))), role, match_whole_string, case_sensitive, recurse, descriptors); + const auto& found = find_resource(resources, utility::s2us(std::to_string(oid))); + if (resources.end() != found) + { + find_members_by_role(resources, *found, role, match_whole_string, case_sensitive, recurse, descriptors); + } } } } @@ -494,7 +500,7 @@ namespace nmos } // find members with given class id - void find_members_by_class_id(const resources& resources, resources::iterator resource, const nc_class_id& class_id_, bool include_derived, bool recurse, web::json::array& descriptors) + void find_members_by_class_id(const resources& resources, const nmos::resource& resource, const nc_class_id& class_id_, bool include_derived, bool recurse, web::json::array& descriptors) { auto find_members_by_matching_class_id = [&](const web::json::array& members) { @@ -511,9 +517,9 @@ namespace nmos return boost::make_iterator_range(boost::make_filter_iterator(match, members.begin(), members.end()), boost::make_filter_iterator(match, members.end(), members.end())); }; - if (resource->data.has_field(nmos::fields::nc::members)) + if (resource.data.has_field(nmos::fields::nc::members)) { - auto& members = nmos::fields::nc::members(resource->data); + auto& members = nmos::fields::nc::members(resource.data); auto members_found = find_members_by_matching_class_id(members); for (const auto& member : members_found) @@ -530,8 +536,11 @@ namespace nmos { // get resource based on the oid const auto& oid = nmos::fields::nc::oid(member); - - find_members_by_class_id(resources, find_resource(resources, utility::s2us(std::to_string(oid))), class_id_, include_derived, recurse, descriptors); + const auto& found = find_resource(resources, utility::s2us(std::to_string(oid))); + if (resources.end() != found) + { + find_members_by_class_id(resources, *found, class_id_, include_derived, recurse, descriptors); + } } } } diff --git a/Development/nmos/control_protocol_utils.h b/Development/nmos/control_protocol_utils.h index 9ec84379e..9402e19e9 100644 --- a/Development/nmos/control_protocol_utils.h +++ b/Development/nmos/control_protocol_utils.h @@ -60,13 +60,13 @@ namespace nmos web::json::value find_property(const nc_property_id& property_id, const nc_class_id& class_id, get_control_protocol_class_handler get_control_protocol_class); // get block memeber descriptors - void get_member_descriptors(const resources& resources, resources::iterator resource, bool recurse, web::json::array& descriptors); + void get_member_descriptors(const resources& resources, const resource& resource, bool recurse, web::json::array& descriptors); // find members with given role name or fragment - void find_members_by_role(const resources& resources, resources::iterator resource, const utility::string_t& role, bool match_whole_string, bool case_sensitive, bool recurse, web::json::array& nc_block_member_descriptors); + void find_members_by_role(const resources& resources, const resource& resource, const utility::string_t& role, bool match_whole_string, bool case_sensitive, bool recurse, web::json::array& nc_block_member_descriptors); // find members with given class id - void find_members_by_class_id(const resources& resources, resources::iterator resource, const nc_class_id& class_id, bool include_derived, bool recurse, web::json::array& descriptors); + void find_members_by_class_id(const resources& resources, const resource& resource, const nc_class_id& class_id, bool include_derived, bool recurse, web::json::array& descriptors); // push control protocol resource into other control protocol NcBlock resource void push_back(control_protocol_resource& nc_block_resource, const control_protocol_resource& resource); diff --git a/Development/nmos/control_protocol_ws_api.cpp b/Development/nmos/control_protocol_ws_api.cpp index 890efe761..5f88ad66d 100644 --- a/Development/nmos/control_protocol_ws_api.cpp +++ b/Development/nmos/control_protocol_ws_api.cpp @@ -268,7 +268,7 @@ namespace nmos method_parameters_contraints_validation(arguments, method.first, get_control_protocol_datatype); // execute the relevant method handler, then accumulating up their response to reponses - response = method.second(resources, resource, handle, arguments, nmos::fields::nc::is_deprecated(method.first), get_control_protocol_class, get_control_protocol_datatype, property_changed, gate); + response = method.second(resources, *resource, handle, arguments, nmos::fields::nc::is_deprecated(method.first), get_control_protocol_class, get_control_protocol_datatype, property_changed, gate); } catch (const nmos::control_protocol_exception& e) { From 31321f7089dbe0e8028ec160bbbaa58a10a7da75 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Wed, 10 Jan 2024 12:56:47 +0000 Subject: [PATCH 086/106] Add ncp authorization field to IS-04 controls array of an NMOS Device --- Development/nmos/control_protocol_methods.cpp | 1 - Development/nmos/node_resources.cpp | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Development/nmos/control_protocol_methods.cpp b/Development/nmos/control_protocol_methods.cpp index bfa3125a7..b7d980a13 100644 --- a/Development/nmos/control_protocol_methods.cpp +++ b/Development/nmos/control_protocol_methods.cpp @@ -507,7 +507,6 @@ namespace nmos auto descriptors = value::array(); nmos::find_members_by_class_id(resources, resource, class_id, include_derived, recurse, descriptors.as_array()); -// auto descriptors = nmos::find_members_by_class_id(resources, resource, class_id, include_derived, recurse);// , descriptors.as_array()); return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nc_method_status::ok }, descriptors); } diff --git a/Development/nmos/node_resources.cpp b/Development/nmos/node_resources.cpp index 216ef7db2..2d6d8d232 100644 --- a/Development/nmos/node_resources.cpp +++ b/Development/nmos/node_resources.cpp @@ -145,7 +145,8 @@ namespace nmos { web::json::push_back(data[U("controls")], value_of({ { U("href"), ncp_uri.set_host(host).to_uri().to_string() }, - { U("type"), type } + { U("type"), type }, + { U("authorization"), nmos::experimental::fields::server_authorization(settings) } })); } } From 2fd6bdd029450c46806bbadba3b035eaad383c6a Mon Sep 17 00:00:00 2001 From: lo-simon Date: Fri, 12 Jan 2024 19:01:01 +0000 Subject: [PATCH 087/106] Update comments --- .../nmos-cpp-node/node_implementation.cpp | 16 +++++------ Development/nmos/control_protocol_methods.cpp | 28 +++++++++---------- Development/nmos/control_protocol_utils.cpp | 4 +++ 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/Development/nmos-cpp-node/node_implementation.cpp b/Development/nmos-cpp-node/node_implementation.cpp index 486ac35d0..9fcdc3a4a 100644 --- a/Development/nmos-cpp-node/node_implementation.cpp +++ b/Development/nmos-cpp-node/node_implementation.cpp @@ -1008,27 +1008,27 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr nmos::experimental::make_control_class_property(U("Example object sequence property"), { 3, 14 }, object_sequence, U("ExampleDataType"), false, false, true) }; - auto example_method_with_no_args = [](nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::control_protocol_property_changed_handler, slog::base_gate& gate) + auto example_method_with_no_args = [](nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::control_protocol_property_changed_handler property_changed, slog::base_gate& gate) { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + // note, model mutex is already locked by the outer function, so access to control_protocol_resources is OK... slog::log(gate, SLOG_FLF) << "Executing the example method with no arguments"; return nmos::make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::nc_method_status::ok }); }; - auto example_method_with_simple_args = [](nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::control_protocol_property_changed_handler, slog::base_gate& gate) + auto example_method_with_simple_args = [](nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::control_protocol_property_changed_handler property_changed, slog::base_gate& gate) { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - // and the method parameters constriants has already been validated by the outter function + // note, model mutex is already locked by the outer function, so access to control_protocol_resources is OK... + // and the method parameters constriants has already been validated by the outer function slog::log(gate, SLOG_FLF) << "Executing the example method with simple arguments: " << arguments.serialize(); return nmos::make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::nc_method_status::ok }); }; - auto example_method_with_object_args = [](nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::control_protocol_property_changed_handler, slog::base_gate& gate) + auto example_method_with_object_args = [](nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::control_protocol_property_changed_handler property_changed, slog::base_gate& gate) { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... - // and the method parameters constriants has already been validated by the outter function + // note, model mutex is already locked by the outer function, so access to control_protocol_resources is OK... + // and the method parameters constriants has already been validated by the outer function slog::log(gate, SLOG_FLF) << "Executing the example method with object argument: " << arguments.serialize(); diff --git a/Development/nmos/control_protocol_methods.cpp b/Development/nmos/control_protocol_methods.cpp index b7d980a13..13cd1dcca 100644 --- a/Development/nmos/control_protocol_methods.cpp +++ b/Development/nmos/control_protocol_methods.cpp @@ -14,7 +14,7 @@ namespace nmos // Get property value web::json::value get(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + // note, model mutex is already locked by the outer function, so access to control_protocol_resources is OK... const auto& property_id = nmos::fields::nc::id(arguments); @@ -36,7 +36,7 @@ namespace nmos // Set property value web::json::value set(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler get_control_protocol_datatype, control_protocol_property_changed_handler property_changed, slog::base_gate& gate) { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + // note, model mutex is already locked by the outer function, so access to control_protocol_resources is OK... const auto& property_id = nmos::fields::nc::id(arguments); const auto& val = nmos::fields::nc::value(arguments); @@ -97,7 +97,7 @@ namespace nmos // Get sequence item web::json::value get_sequence_item(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + // note, model mutex is already locked by the outer function, so access to control_protocol_resources is OK... const auto& property_id = nmos::fields::nc::id(arguments); const auto& index = nmos::fields::nc::index(arguments); @@ -138,7 +138,7 @@ namespace nmos // Set sequence item web::json::value set_sequence_item(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler get_control_protocol_datatype, control_protocol_property_changed_handler property_changed, slog::base_gate& gate) { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + // note, model mutex is already locked by the outer function, so access to control_protocol_resources is OK... const auto& property_id = nmos::fields::nc::id(arguments); const auto& index = nmos::fields::nc::index(arguments); @@ -211,7 +211,7 @@ namespace nmos // Add item to sequence web::json::value add_sequence_item(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler get_control_protocol_datatype, control_protocol_property_changed_handler property_changed, slog::base_gate& gate) { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + // note, model mutex is already locked by the outer function, so access to control_protocol_resources is OK... using web::json::value; @@ -281,7 +281,7 @@ namespace nmos // Delete sequence item web::json::value remove_sequence_item(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + // note, model mutex is already locked by the outer function, so access to control_protocol_resources is OK... const auto& property_id = nmos::fields::nc::id(arguments); const auto& index = nmos::fields::nc::index(arguments); @@ -329,7 +329,7 @@ namespace nmos // Get sequence length web::json::value get_sequence_length(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + // note, model mutex is already locked by the outer function, so access to control_protocol_resources is OK... using web::json::value; @@ -384,7 +384,7 @@ namespace nmos // Gets descriptors of members of the block web::json::value get_member_descriptors(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + // note, model mutex is already locked by the outer function, so access to control_protocol_resources is OK... using web::json::value; @@ -401,7 +401,7 @@ namespace nmos // Finds member(s) by path web::json::value find_members_by_path(nmos::resources& resources, const nmos::resource& resource_, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + // note, model mutex is already locked by the outer function, so access to control_protocol_resources is OK... using web::json::value; @@ -461,7 +461,7 @@ namespace nmos // Finds members with given role name or fragment web::json::value find_members_by_role(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + // note, model mutex is already locked by the outer function, so access to control_protocol_resources is OK... using web::json::value; @@ -487,7 +487,7 @@ namespace nmos // Finds members with given class id web::json::value find_members_by_class_id(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + // note, model mutex is already locked by the outer function, so access to control_protocol_resources is OK... using web::json::value; @@ -503,7 +503,7 @@ namespace nmos return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("empty classId to do FindMembersByClassId")); } - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + // note, model mutex is already locked by the outer function, so access to control_protocol_resources is OK... auto descriptors = value::array(); nmos::find_members_by_class_id(resources, resource, class_id, include_derived, recurse, descriptors.as_array()); @@ -528,7 +528,7 @@ namespace nmos return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("empty classId to do GetControlClass")); } - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + // note, model mutex is already locked by the outer function, so access to control_protocol_resources is OK... const auto& control_class = get_control_protocol_class(class_id); if (!control_class.class_id.empty()) @@ -570,7 +570,7 @@ namespace nmos // Get a single datatype descriptor web::json::value get_datatype(nmos::resources&, const nmos::resource&, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler get_control_protocol_datatype, control_protocol_property_changed_handler, slog::base_gate& gate) { - // note, model mutex is already locked by the outter function, so access to control_protocol_resources is OK... + // note, model mutex is already locked by the outer function, so access to control_protocol_resources is OK... const auto& name = nmos::fields::nc::name(arguments); // name of datatype const auto& include_inherited = nmos::fields::nc::include_inherited(arguments); // If set the descriptor would contain all inherited elements diff --git a/Development/nmos/control_protocol_utils.cpp b/Development/nmos/control_protocol_utils.cpp index f89d4b2cd..984677a6c 100644 --- a/Development/nmos/control_protocol_utils.cpp +++ b/Development/nmos/control_protocol_utils.cpp @@ -550,6 +550,8 @@ namespace nmos // push a control protocol resource into other control protocol NcBlock resource void push_back(control_protocol_resource& nc_block_resource, const control_protocol_resource& resource) { + // note, model write lock should aleady be applied by the outer function, so access to control_protocol_resources is OK... + using web::json::value; auto& parent = nc_block_resource.data; @@ -566,6 +568,8 @@ namespace nmos // modify a control protocol resource, and insert notification event to all subscriptions bool modify_control_protocol_resource(resources& resources, const id& id, std::function modifier, const web::json::value& notification_event) { + // note, model write lock should aleady be applied by the outer function, so access to control_protocol_resources is OK... + auto found = resources.find(id); if (resources.end() == found || !found->has_data()) return false; From 39118899e1aa7b2b6c2ac5d99c7284efae359f4d Mon Sep 17 00:00:00 2001 From: lo-simon Date: Fri, 12 Jan 2024 22:12:11 +0000 Subject: [PATCH 088/106] Return parameter_error (417) instead of bad_oid (404) in event of bad role while doing find_members_by_path --- Development/nmos/control_protocol_methods.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Development/nmos/control_protocol_methods.cpp b/Development/nmos/control_protocol_methods.cpp index 13cd1dcca..8c87b520d 100644 --- a/Development/nmos/control_protocol_methods.cpp +++ b/Development/nmos/control_protocol_methods.cpp @@ -444,13 +444,13 @@ namespace nmos // no role utility::stringstream_t ss; ss << U("role: ") << role.as_string() << U(" not found to do FindMembersByPath"); - return make_control_protocol_error_response(handle, { nc_method_status::bad_oid }, ss.str()); + return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, ss.str()); } } else { // no members - return make_control_protocol_error_response(handle, { nc_method_status::bad_oid }, U("no members to do FindMembersByPath")); + return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("no members to do FindMembersByPath")); } } From 2fbd8e1e4cf04da2b46e216576731a81e31c2be1 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Mon, 15 Jan 2024 17:44:32 +0000 Subject: [PATCH 089/106] Add non-standard class method with the necessary parameters --- .../nmos-cpp-node/node_implementation.cpp | 26 ++++++++-------- .../nmos/control_protocol_handlers.cpp | 2 +- Development/nmos/control_protocol_handlers.h | 20 +++++++++--- Development/nmos/control_protocol_methods.cpp | 4 +-- .../nmos/control_protocol_resource.cpp | 2 +- Development/nmos/control_protocol_state.cpp | 31 +++++++++++++------ Development/nmos/control_protocol_state.h | 27 ++++++++-------- Development/nmos/control_protocol_ws_api.cpp | 16 ++++++++-- 8 files changed, 81 insertions(+), 47 deletions(-) diff --git a/Development/nmos-cpp-node/node_implementation.cpp b/Development/nmos-cpp-node/node_implementation.cpp index 9fcdc3a4a..1cbebd415 100644 --- a/Development/nmos-cpp-node/node_implementation.cpp +++ b/Development/nmos-cpp-node/node_implementation.cpp @@ -1008,7 +1008,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr nmos::experimental::make_control_class_property(U("Example object sequence property"), { 3, 14 }, object_sequence, U("ExampleDataType"), false, false, true) }; - auto example_method_with_no_args = [](nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::control_protocol_property_changed_handler property_changed, slog::base_gate& gate) + auto example_method_with_no_args = [](nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, slog::base_gate& gate) { // note, model mutex is already locked by the outer function, so access to control_protocol_resources is OK... @@ -1016,7 +1016,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr return nmos::make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::nc_method_status::ok }); }; - auto example_method_with_simple_args = [](nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::control_protocol_property_changed_handler property_changed, slog::base_gate& gate) + auto example_method_with_simple_args = [](nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, slog::base_gate& gate) { // note, model mutex is already locked by the outer function, so access to control_protocol_resources is OK... // and the method parameters constriants has already been validated by the outer function @@ -1025,7 +1025,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr return nmos::make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::nc_method_status::ok }); }; - auto example_method_with_object_args = [](nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::control_protocol_property_changed_handler property_changed, slog::base_gate& gate) + auto example_method_with_object_args = [](nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, slog::base_gate& gate) { // note, model mutex is already locked by the outer function, so access to control_protocol_resources is OK... // and the method parameters constriants has already been validated by the outer function @@ -1037,22 +1037,22 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr // Example control class methods std::vector example_control_methods = { - { nmos::experimental::make_control_class_method(U("Example method with no arguments"), { 3, 1 }, U("MethodNoArgs"), U("NcMethodResult"), {}, false), example_method_with_no_args }, - { nmos::experimental::make_control_class_method(U("Example deprecated method with no arguments"), { 3, 2 }, U("MethodNoArgs"), U("NcMethodResult"), {}, true), example_method_with_no_args }, + { nmos::experimental::make_control_class_method(U("Example method with no arguments"), { 3, 1 }, U("MethodNoArgs"), U("NcMethodResult"), {}, false, example_method_with_no_args) }, + { nmos::experimental::make_control_class_method(U("Example deprecated method with no arguments"), { 3, 2 }, U("MethodNoArgs"), U("NcMethodResult"), {}, true, example_method_with_no_args) }, { nmos::experimental::make_control_class_method(U("Example method with simple arguments"), { 3, 3 }, U("MethodSimpleArgs"), U("NcMethodResult"), - { - nmos::details::make_nc_parameter_descriptor(U("Enum example argument"), enum_arg, U("ExampleEnum"), false, false, value::null()), - nmos::details::make_nc_parameter_descriptor(U("String example argument"), string_arg, U("NcString"), false, false, make_string_example_argument_constraints()), // e.g. include method property constraints - nmos::details::make_nc_parameter_descriptor(U("Number example argument"), number_arg, U("NcUint64"), false, false, make_number_example_argument_constraints()), // e.g. include method property constraints - nmos::details::make_nc_parameter_descriptor(U("Boolean example argument"), boolean_arg, U("NcBoolean"), false, false, value::null()) + { + nmos::experimental::make_control_class_method_parameter(U("Enum example argument"), enum_arg, U("ExampleEnum")), + nmos::experimental::make_control_class_method_parameter(U("String example argument"), string_arg, U("NcString"), false, false, make_string_example_argument_constraints()), // e.g. include method property constraints + nmos::experimental::make_control_class_method_parameter(U("Number example argument"), number_arg, U("NcUint64"), false, false, make_number_example_argument_constraints()), // e.g. include method property constraints + nmos::experimental::make_control_class_method_parameter(U("Boolean example argument"), boolean_arg, U("NcBoolean")) }, - false), example_method_with_simple_args + false, example_method_with_simple_args) }, { nmos::experimental::make_control_class_method(U("Example method with object argument"), { 3, 4 }, U("MethodObjectArg"), U("NcMethodResult"), { - nmos::details::make_nc_parameter_descriptor(U("Object example argument"), obj_arg, U("ExampleDataType"), false, false, value::null()) + nmos::experimental::make_control_class_method_parameter(U("Object example argument"), obj_arg, U("ExampleDataType")) }, - false), example_method_with_object_args + false, example_method_with_object_args) } }; diff --git a/Development/nmos/control_protocol_handlers.cpp b/Development/nmos/control_protocol_handlers.cpp index f9650a21a..9cf68e56f 100644 --- a/Development/nmos/control_protocol_handlers.cpp +++ b/Development/nmos/control_protocol_handlers.cpp @@ -55,7 +55,7 @@ namespace nmos auto& methods = control_class.methods; auto method_found = std::find_if(methods.begin(), methods.end(), [&method_id](const experimental::method& method) { - return method_id == details::parse_nc_method_id(nmos::fields::nc::id(method.first)); + return method_id == details::parse_nc_method_id(nmos::fields::nc::id(std::get<0>(method))); }); if (methods.end() != method_found) { diff --git a/Development/nmos/control_protocol_handlers.h b/Development/nmos/control_protocol_handlers.h index 516d9c21a..814a8266f 100644 --- a/Development/nmos/control_protocol_handlers.h +++ b/Development/nmos/control_protocol_handlers.h @@ -2,7 +2,6 @@ #define NMOS_CONTROL_PROTOCOL_HANDLERS_H #include -#include #include "nmos/control_protocol_typedefs.h" #include "nmos/resources.h" @@ -39,11 +38,24 @@ namespace nmos namespace experimental { - // method handler definition - typedef std::function method_handler; + // standard method handler definition + typedef std::function standard_method_handler; + + // non-standard method handler definition + typedef std::function non_standard_method_handler; // method definition (NcMethodDescriptor vs method handler) - typedef std::pair method; + typedef std::tuple method; + + inline method make_control_class_standard_method(const web::json::value& nc_method_descriptor, standard_method_handler method_handler) + { + return std::make_tuple(nc_method_descriptor, method_handler, nullptr); + } + + inline method make_control_class_non_standard_method(const web::json::value& nc_method_descriptor, non_standard_method_handler method_handler) + { + return std::make_tuple(nc_method_descriptor, nullptr, method_handler); + } } // callback to retrieve a specific method diff --git a/Development/nmos/control_protocol_methods.cpp b/Development/nmos/control_protocol_methods.cpp index 8c87b520d..7dd2fe92c 100644 --- a/Development/nmos/control_protocol_methods.cpp +++ b/Development/nmos/control_protocol_methods.cpp @@ -538,7 +538,7 @@ namespace nmos auto& fixed_role = control_class.fixed_role; auto properties = control_class.properties; auto methods = value::array(); - for (const auto& method : control_class.methods) { web::json::push_back(methods, method.first); } + for (const auto& method : control_class.methods) { web::json::push_back(methods, std::get<0>(method)); } auto events = control_class.events; if (include_inherited) @@ -551,7 +551,7 @@ namespace nmos const auto& inherited_control_class = get_control_protocol_class(inherited_class_id); { for (const auto& property : inherited_control_class.properties.as_array()) { web::json::push_back(properties, property); } - for (const auto& method : inherited_control_class.methods) { web::json::push_back(methods, method.first); } + for (const auto& method : inherited_control_class.methods) { web::json::push_back(methods, std::get<0>(method)); } for (const auto& event : inherited_control_class.events.as_array()) { web::json::push_back(events, event); } } inherited_class_id.pop_back(); diff --git a/Development/nmos/control_protocol_resource.cpp b/Development/nmos/control_protocol_resource.cpp index 248b3aba5..6e845fe28 100644 --- a/Development/nmos/control_protocol_resource.cpp +++ b/Development/nmos/control_protocol_resource.cpp @@ -783,7 +783,7 @@ namespace nmos auto& ctl_class = control_class.second; auto methods = value::array(); - for (const auto& method : ctl_class.methods) { web::json::push_back(methods, method.first); } + for (const auto& method : ctl_class.methods) { web::json::push_back(methods, std::get<0>(method)); } const auto class_description = ctl_class.fixed_role.is_null() ? make_nc_class_descriptor(ctl_class.description, ctl_class.class_id, ctl_class.name, ctl_class.properties, methods, ctl_class.events) diff --git a/Development/nmos/control_protocol_state.cpp b/Development/nmos/control_protocol_state.cpp index 153370a5e..16ca3e35b 100644 --- a/Development/nmos/control_protocol_state.cpp +++ b/Development/nmos/control_protocol_state.cpp @@ -61,15 +61,26 @@ namespace nmos return nmos::details::make_nc_parameter_descriptor(description, name, type_name, is_nullable, is_sequence, constraints); } - // create control class method - web::json::value make_control_class_method(const utility::string_t& description, const nc_method_id& id, const nc_name& name, const utility::string_t& result_datatype, const std::vector& parameters_, bool is_deprecated) + namespace details { - using web::json::value; + web::json::value make_control_class_method(const utility::string_t& description, const nc_method_id& id, const nc_name& name, const utility::string_t& result_datatype, const std::vector& parameters_, bool is_deprecated) + { + using web::json::value; - value parameters = value::array(); - for (const auto& parameter : parameters_) { web::json::push_back(parameters, parameter); } + value parameters = value::array(); + for (const auto& parameter : parameters_) { web::json::push_back(parameters, parameter); } - return nmos::details::make_nc_method_descriptor(description, id, name, result_datatype, parameters, is_deprecated); + return nmos::details::make_nc_method_descriptor(description, id, name, result_datatype, parameters, is_deprecated); + } + } + // create control class method + method make_control_class_method(const utility::string_t& description, const nc_method_id& id, const nc_name& name, const utility::string_t& result_datatype, const std::vector& parameters, bool is_deprecated, standard_method_handler method_handler) + { + return make_control_class_standard_method(details::make_control_class_method(description, id, name, result_datatype, parameters, is_deprecated), method_handler); + } + method make_control_class_method(const utility::string_t& description, const nc_method_id& id, const nc_name& name, const utility::string_t& result_datatype, const std::vector& parameters, bool is_deprecated, non_standard_method_handler method_handler) + { + return make_control_class_non_standard_method(details::make_control_class_method(description, id, name, result_datatype, parameters, is_deprecated), method_handler); } // create control class event @@ -91,16 +102,16 @@ namespace nmos return std::vector{}; }; - auto to_methods_vector = [](const web::json::value& nc_method_descriptors, const std::map& method_handlers) + auto to_methods_vector = [](const web::json::value& nc_method_descriptors, const std::map& method_handlers) { - // NcMethodDescriptor vs method_handler - std::vector methods; + // NcMethodDescriptor vs method + std::vector methods; if (!nc_method_descriptors.is_null()) { for (const auto& nc_method_descriptor : nc_method_descriptors.as_array()) { - methods.push_back({ nc_method_descriptor, method_handlers.at(nmos::details::parse_nc_method_id(nmos::fields::nc::id(nc_method_descriptor))) }); + methods.push_back(make_control_class_standard_method(nc_method_descriptor, method_handlers.at(nmos::details::parse_nc_method_id(nmos::fields::nc::id(nc_method_descriptor))))); } } return methods; diff --git a/Development/nmos/control_protocol_state.h b/Development/nmos/control_protocol_state.h index a43d625e3..f48826d04 100644 --- a/Development/nmos/control_protocol_state.h +++ b/Development/nmos/control_protocol_state.h @@ -21,7 +21,7 @@ namespace nmos web::json::value fixed_role; web::json::value properties = web::json::value::array(); // array of NcPropertyDescriptor - std::vector methods; // vector of NcMethodDescriptor and method_handler + std::vector methods; // vector of NcMethodDescriptor, standard_method_handler and non_standard_method_handler web::json::value events = web::json::value::array(); // array of NcEventDescriptor control_class() @@ -68,30 +68,31 @@ namespace nmos // insert datatype, false if datatype already presented bool insert(const experimental::datatype& datatype); // erase datatype of the given datatype name, false if the required datatype not found - bool erase(const utility::string_t& name); + bool erase(const utility::string_t& datatype_name); }; // helper functions to create non-standard control class // + + // create control class with fixed role + control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const utility::string_t& fixed_role, const std::vector& properties = {}, const std::vector& methods = {}, const std::vector& events = {}); + // create control class with no fixed role + control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const std::vector& properties = {}, const std::vector& methods = {}, const std::vector& events = {}); + + // create control class property + web::json::value make_control_class_property(const utility::string_t& description, const nc_property_id& id, const nc_name& name, const utility::string_t& type_name, + bool is_read_only = false, bool is_nullable = false, bool is_sequence = false, bool is_deprecated = false, const web::json::value& constraints = web::json::value::null()); + // create control class method parameter web::json::value make_control_class_method_parameter(const utility::string_t& description, const nc_name& name, const utility::string_t& type_name, bool is_nullable = false, bool is_sequence = false, const web::json::value& constraints = web::json::value::null()); // create control class method - web::json::value make_control_class_method(const utility::string_t& description, const nc_method_id& id, const nc_name& name, const utility::string_t& result_datatype, - const std::vector& parameters = {}, bool is_deprecated = false); + method make_control_class_method(const utility::string_t& description, const nc_method_id& id, const nc_name& name, const utility::string_t& result_datatype, + const std::vector& parameters, bool is_deprecated, non_standard_method_handler method_handler); // create control class event web::json::value make_control_class_event(const utility::string_t& description, const nc_event_id& id, const nc_name& name, const utility::string_t& event_datatype, bool is_deprecated = false); - - // create control class property - web::json::value make_control_class_property(const utility::string_t& description, const nc_property_id& id, const nc_name& name, const utility::string_t& type_name, - bool is_read_only = false, bool is_nullable = false, bool is_sequence = false, bool is_deprecated = false, const web::json::value& constraints = web::json::value::null()); - - // create control class with fixed role - control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const utility::string_t& fixed_role, const std::vector& properties = {}, const std::vector>& methods = {}, const std::vector& events = {}); - // create control class with no fixed role - control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const std::vector& properties = {}, const std::vector>& methods = {}, const std::vector& events = {}); } } diff --git a/Development/nmos/control_protocol_ws_api.cpp b/Development/nmos/control_protocol_ws_api.cpp index 5f88ad66d..56c9c0855 100644 --- a/Development/nmos/control_protocol_ws_api.cpp +++ b/Development/nmos/control_protocol_ws_api.cpp @@ -260,15 +260,25 @@ namespace nmos // find the relevent method handler to execute auto method = get_control_protocol_method(class_id, method_id); - if (method.second) + auto& nc_method_descriptor = std::get<0>(method); + auto& standard_method = std::get<1>(method); + auto& non_standard_method = std::get<2>(method); + if (standard_method || non_standard_method) { try { // do method arguments constraints validation - method_parameters_contraints_validation(arguments, method.first, get_control_protocol_datatype); + method_parameters_contraints_validation(arguments, nc_method_descriptor, get_control_protocol_datatype); // execute the relevant method handler, then accumulating up their response to reponses - response = method.second(resources, *resource, handle, arguments, nmos::fields::nc::is_deprecated(method.first), get_control_protocol_class, get_control_protocol_datatype, property_changed, gate); + if (standard_method) + { + response = standard_method(resources, *resource, handle, arguments, nmos::fields::nc::is_deprecated(nc_method_descriptor), get_control_protocol_class, get_control_protocol_datatype, property_changed, gate); + } + else // non_standard_method + { + response = non_standard_method(resources, *resource, handle, arguments, nmos::fields::nc::is_deprecated(nc_method_descriptor), gate); + } } catch (const nmos::control_protocol_exception& e) { From 6f025a8d8feebf6fafcac0d00d212bed19d4106b Mon Sep 17 00:00:00 2001 From: lo-simon Date: Thu, 15 Feb 2024 16:03:25 +0000 Subject: [PATCH 090/106] Update node config JSON to include is12_versions --- Development/nmos-cpp-node/config.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Development/nmos-cpp-node/config.json b/Development/nmos-cpp-node/config.json index 83fd40dad..37c2cbdf0 100644 --- a/Development/nmos-cpp-node/config.json +++ b/Development/nmos-cpp-node/config.json @@ -104,6 +104,9 @@ // is10_versions [registry, node]: used to specify the enabled API versions for a version-locked configuration //"is10_versions": ["v1.0"], + // is12_versions [node]: used to specify the enabled API versions for a version-locked configuration + //"is12_versions": ["v1.0"], + // pri [registry, node]: used for the 'pri' TXT record; specifying nmos::service_priorities::no_priority (maximum value) disables advertisement completely //"pri": 100, From 89ee998b7f6785859c71d0d57a5ec453c3fca296 Mon Sep 17 00:00:00 2001 From: Simon Lo Date: Fri, 23 Feb 2024 16:51:26 +0000 Subject: [PATCH 091/106] Apply suggestions from code review Co-authored-by: jonathan-r-thorpe <64410119+jonathan-r-thorpe@users.noreply.github.com> --- Development/nmos-cpp-node/config.json | 6 +-- .../nmos/control_protocol_resource.cpp | 8 ++++ Development/nmos/control_protocol_resource.h | 6 ++- Development/nmos/control_protocol_state.cpp | 43 ++++++++++--------- 4 files changed, 38 insertions(+), 25 deletions(-) diff --git a/Development/nmos-cpp-node/config.json b/Development/nmos-cpp-node/config.json index 37c2cbdf0..edcc5556d 100644 --- a/Development/nmos-cpp-node/config.json +++ b/Development/nmos-cpp-node/config.json @@ -372,17 +372,17 @@ // If the Resource Server fails to verify a token using all public keys available it MUST reject the token." //"service_unavailable_retry_after": 5, - // manufacturer_name [node]: the manufacturer name of the NcDeviceManager used for NMOS Control Protocol + // manufacturer_name [node]: the manufacturer name reported by the NcDeviceManager when using the NMOS Control Protocol // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdevicemanager //"manufacturer_name": "", - // product_name/product_key/product_revision_level [node]: the product description of the NcDeviceManager used for NMOS Control Protocol + // product_name/product_key/product_revision_level [node]: the product description reported by the NcDeviceManager when using the NMOS Control Protocol // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncproduct //"product_name": "", //"product_key": "", //"product_revision_level": "", - // serial_number [node]: the serial number of the NcDeviceManager used for NMOS Control Protocol + // serial_number [node]: the serial number reported by the NcDeviceManager when using the NMOS Control Protocol // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdevicemanager //"serial_number": "", diff --git a/Development/nmos/control_protocol_resource.cpp b/Development/nmos/control_protocol_resource.cpp index 6e845fe28..2c47e77a9 100644 --- a/Development/nmos/control_protocol_resource.cpp +++ b/Development/nmos/control_protocol_resource.cpp @@ -1284,6 +1284,8 @@ namespace nmos return details::make_nc_class_descriptor(U("NcClassManager class descriptor"), nc_class_manager_class_id, U("NcClassManager"), U("ClassManager"), make_nc_class_manager_properties(), make_nc_class_manager_methods(), make_nc_class_manager_events()); } + + // Identification feature set control classes // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/identification/#ncidentbeacon web::json::value make_nc_ident_beacon_class() { @@ -1292,6 +1294,8 @@ namespace nmos return details::make_nc_class_descriptor(U("NcIdentBeacon class descriptor"), nc_ident_beacon_class_id, U("NcIdentBeacon"), make_nc_ident_beacon_properties(), make_nc_ident_beacon_methods(), make_nc_ident_beacon_events()); } + + // Monitoring feature set control classes // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitor web::json::value make_nc_receiver_monitor_class() { @@ -1308,6 +1312,8 @@ namespace nmos return details::make_nc_class_descriptor(U("NcReceiverMonitorProtected class descriptor"), nc_receiver_monitor_protected_class_id, U("NcReceiverMonitorProtected"), make_nc_receiver_monitor_protected_properties(), make_nc_receiver_monitor_protected_methods(), make_nc_receiver_monitor_protected_events()); } + + // Primitive datatypes // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#primitives web::json::value make_nc_boolean_datatype() { @@ -1388,6 +1394,8 @@ namespace nmos return details::make_nc_datatype_descriptor_primitive(U("UTF-8 string"), U("NcString"), value::null()); } + + // Standard datatypes // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcBlockMemberDescriptor.html web::json::value make_nc_block_member_descriptor_datatype() { diff --git a/Development/nmos/control_protocol_resource.h b/Development/nmos/control_protocol_resource.h index 193e9a800..e1eb02cc3 100644 --- a/Development/nmos/control_protocol_resource.h +++ b/Development/nmos/control_protocol_resource.h @@ -264,10 +264,14 @@ namespace nmos web::json::value make_nc_receiver_monitor_properties(); web::json::value make_nc_receiver_monitor_methods(); web::json::value make_nc_receiver_monitor_events(); + + // Monitoring feature set control classes // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitorprotected web::json::value make_nc_receiver_monitor_protected_properties(); web::json::value make_nc_receiver_monitor_protected_methods(); web::json::value make_nc_receiver_monitor_protected_events(); + + // Identification feature set control classes // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/identification/#ncidentbeacon web::json::value make_nc_ident_beacon_properties(); web::json::value make_nc_ident_beacon_methods(); @@ -413,7 +417,7 @@ namespace nmos // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/NcVersionCode.html web::json::value make_nc_version_code_datatype(); - // Monitoring datatypes + // Monitoring feature set datatypes // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#datatypes // // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncconnectionstatus diff --git a/Development/nmos/control_protocol_state.cpp b/Development/nmos/control_protocol_state.cpp index 16ca3e35b..62c7fbd8e 100644 --- a/Development/nmos/control_protocol_state.cpp +++ b/Development/nmos/control_protocol_state.cpp @@ -11,9 +11,9 @@ namespace nmos { // create control class // where - // properties: vector of NcPropertyDescriptor can be constructed using make_control_class_property + // properties: vector of NcPropertyDescriptor where NcPropertyDescriptor can be constructed using make_control_class_property // methods: vector of NcMethodDescriptor vs assoicated method handler where NcMethodDescriptor can be constructed using make_nc_method_descriptor - // events: vector of NcEventDescriptor can be constructed using make_nc_event_descriptor + // events: vector of NcEventDescriptor where NcEventDescriptor can be constructed using make_nc_event_descriptor control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const web::json::value& fixed_role, const std::vector& properties_, const std::vector& methods_, const std::vector& events_) { using web::json::value; @@ -28,20 +28,20 @@ namespace nmos } // create control class with fixed role // where - // properties: vector of NcPropertyDescriptor which can be constructed using make_control_class_property - // methods: vector of NcMethodDescriptor which can be constructed using make_nc_method_descriptor and the assoicated method handler - // events: vector of NcEventDescriptor can be constructed using make_nc_event_descriptor + // properties: vector of NcPropertyDescriptor where NcPropertyDescriptor can be constructed using make_control_class_property + // methods: vector of NcMethodDescriptor where NcMethodDescriptor can be constructed using make_nc_method_descriptor and the assoicated method handler + // events: vector of NcEventDescriptor where NcEventDescriptor can be constructed using make_nc_event_descriptor control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const utility::string_t& fixed_role, const std::vector& properties, const std::vector& methods, const std::vector& events) { using web::json::value; return details::make_control_class(description, class_id, name, value::string(fixed_role), properties, methods, events); } - // create control class with no fixed role + // create control class without fixed role // where - // properties: vector of NcPropertyDescriptor which can be constructed using make_control_class_property - // methods: vector of NcMethodDescriptor which can be constructed using make_nc_method_descriptor and the assoicated method handler - // events: vector of NcEventDescriptor can be constructed using make_nc_event_descriptor + // properties: vector of NcPropertyDescriptor where NcPropertyDescriptor can be constructed using make_control_class_property + // methods: vector of NcMethodDescriptor where NcMethodDescriptor can be constructed using make_nc_method_descriptor and the assoicated method handler + // events: vector of NcEventDescriptor where NcEventDescriptor can be constructed using make_nc_event_descriptor control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const std::vector& properties, const std::vector& methods, const std::vector& events) { using web::json::value; @@ -73,11 +73,12 @@ namespace nmos return nmos::details::make_nc_method_descriptor(description, id, name, result_datatype, parameters, is_deprecated); } } - // create control class method + // create standard control class method method make_control_class_method(const utility::string_t& description, const nc_method_id& id, const nc_name& name, const utility::string_t& result_datatype, const std::vector& parameters, bool is_deprecated, standard_method_handler method_handler) { return make_control_class_standard_method(details::make_control_class_method(description, id, name, result_datatype, parameters, is_deprecated), method_handler); } + // create non-standard control class method method make_control_class_method(const utility::string_t& description, const nc_method_id& id, const nc_name& name, const utility::string_t& result_datatype, const std::vector& parameters, bool is_deprecated, non_standard_method_handler method_handler) { return make_control_class_non_standard_method(details::make_control_class_method(description, id, name, result_datatype, parameters, is_deprecated), method_handler); @@ -117,11 +118,11 @@ namespace nmos return methods; }; - // setup the core control classes + // setup the standard control classes control_classes = { // Control class models - // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/classes/#control-class-models-for-branch-v10-dev + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/classes/ // NcObject { nc_object_class_id, make_control_class(U("NcObject class descriptor"), nc_object_class_id, U("NcObject"), @@ -193,8 +194,8 @@ namespace nmos }), // NcClassManager events to_vector(make_nc_class_manager_events())) }, - // identification beacon model - // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/identification/#ncidentbeacon + // Identification feature set + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/identification/#control-classes // NcIdentBeacon { nc_ident_beacon_class_id, make_control_class(U("NcIdentBeacon class descriptor"), nc_ident_beacon_class_id, U("NcIdentBeacon"), // NcIdentBeacon properties @@ -203,8 +204,8 @@ namespace nmos to_methods_vector(make_nc_ident_beacon_methods(), {}), // NcIdentBeacon events to_vector(make_nc_ident_beacon_events())) }, - // Monitoring - // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitor + // Monitoring feature set + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#control-classes // NcReceiverMonitor { nc_receiver_monitor_class_id, make_control_class(U("NcReceiverMonitor class descriptor"), nc_receiver_monitor_class_id, U("NcReceiverMonitor"), // NcReceiverMonitor properties @@ -223,11 +224,11 @@ namespace nmos to_vector(make_nc_receiver_monitor_protected_events())) } }; - // setup the core datatypes + // setup the standard datatypes datatypes = { // Datatype models - // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/#datatype-models-for-branch-v10-dev + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/ { U("NcBoolean"), {make_nc_boolean_datatype()} }, { U("NcInt16"), {make_nc_int16_datatype()} }, { U("NcInt32"), {make_nc_int32_datatype()} }, @@ -296,14 +297,14 @@ namespace nmos { U("NcTouchpointResource"), {make_nc_touchpoint_resource_datatype()} }, { U("NcTouchpointResourceNmos"), {make_nc_touchpoint_resource_nmos_datatype()} }, { U("NcTouchpointResourceNmosChannelMapping"), {make_nc_touchpoint_resource_nmos_channel_mapping_datatype()} }, - // Monitoring + // Monitoring feature set // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#datatypes { U("NcConnectionStatus"), {make_nc_connection_status_datatype()} }, { U("NcPayloadStatus"), {make_nc_payload_status_datatype()} } }; } - // insert control class, false if class already presented + // insert control class, false if class already inserted bool control_protocol_state::insert(const experimental::control_class& control_class) { auto lock = write_lock(); @@ -329,7 +330,7 @@ namespace nmos return false; } - // insert datatype, false if datatype already presented + // insert datatype, false if datatype already inserted bool control_protocol_state::insert(const experimental::datatype& datatype) { const auto& name = nmos::fields::nc::name(datatype.descriptor); From c0244ad5e067d14fb1f6f8170e05acd393326baf Mon Sep 17 00:00:00 2001 From: Simon Lo Date: Mon, 26 Feb 2024 10:59:21 +0000 Subject: [PATCH 092/106] Update Development/nmos-cpp-node/node_implementation.cpp Co-authored-by: jonathan-r-thorpe <64410119+jonathan-r-thorpe@users.noreply.github.com> --- Development/nmos-cpp-node/node_implementation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Development/nmos-cpp-node/node_implementation.cpp b/Development/nmos-cpp-node/node_implementation.cpp index 1cbebd415..d888da2e3 100644 --- a/Development/nmos-cpp-node/node_implementation.cpp +++ b/Development/nmos-cpp-node/node_implementation.cpp @@ -1237,7 +1237,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr }), example_enum::Undefined, U("test"), - 3, + 4, 10, false, make_example_datatype(example_enum::Undefined, U("default"), 5, false), From 1c5fe1415e639808f4b8645c9c405c9a93117534 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Mon, 26 Feb 2024 19:50:47 +0000 Subject: [PATCH 093/106] Remove commented out code --- Development/nmos/control_protocol_resource.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Development/nmos/control_protocol_resource.h b/Development/nmos/control_protocol_resource.h index e1eb02cc3..719f92a2e 100644 --- a/Development/nmos/control_protocol_resource.h +++ b/Development/nmos/control_protocol_resource.h @@ -41,12 +41,10 @@ namespace nmos namespace details { // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncelementid - //web::json::value make_nc_element_id(uint16_t level, uint16_t index); web::json::value make_nc_element_id(const nc_element_id& element_id); nc_element_id parse_nc_element_id(const web::json::value& element_id); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#nceventid - //web::json::value make_nc_event_id(uint16_t level, uint16_t index); web::json::value make_nc_event_id(const nc_event_id& event_id); nc_event_id parse_nc_event_id(const web::json::value& event_id); @@ -264,7 +262,7 @@ namespace nmos web::json::value make_nc_receiver_monitor_properties(); web::json::value make_nc_receiver_monitor_methods(); web::json::value make_nc_receiver_monitor_events(); - + // Monitoring feature set control classes // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitorprotected web::json::value make_nc_receiver_monitor_protected_properties(); From 9c27c40b1f02da6f6088a7aa1a9d46bf956c764a Mon Sep 17 00:00:00 2001 From: lo-simon Date: Mon, 26 Feb 2024 19:51:17 +0000 Subject: [PATCH 094/106] Update comments --- Development/nmos-cpp-node/config.json | 6 +++--- Development/nmos/control_protocol_state.cpp | 2 +- Development/nmos/control_protocol_state.h | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Development/nmos-cpp-node/config.json b/Development/nmos-cpp-node/config.json index 25a677c1b..f7e5216e6 100644 --- a/Development/nmos-cpp-node/config.json +++ b/Development/nmos-cpp-node/config.json @@ -369,17 +369,17 @@ // If the Resource Server fails to verify a token using all public keys available it MUST reject the token." //"service_unavailable_retry_after": 5, - // manufacturer_name [node]: the manufacturer name reported by the NcDeviceManager when using the NMOS Control Protocol + // manufacturer_name [node]: the manufacturer name of the NcDeviceManager used for NMOS Control Protocol // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdevicemanager //"manufacturer_name": "", - // product_name/product_key/product_revision_level [node]: the product description reported by the NcDeviceManager when using the NMOS Control Protocol + // product_name/product_key/product_revision_level [node]: the product description of the NcDeviceManager used for NMOS Control Protocol // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncproduct //"product_name": "", //"product_key": "", //"product_revision_level": "", - // serial_number [node]: the serial number reported by the NcDeviceManager when using the NMOS Control Protocol + // serial_number [node]: the serial number of the NcDeviceManager used for NMOS Control Protocol // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncdevicemanager //"serial_number": "", diff --git a/Development/nmos/control_protocol_state.cpp b/Development/nmos/control_protocol_state.cpp index 62c7fbd8e..956ef946a 100644 --- a/Development/nmos/control_protocol_state.cpp +++ b/Development/nmos/control_protocol_state.cpp @@ -105,7 +105,7 @@ namespace nmos auto to_methods_vector = [](const web::json::value& nc_method_descriptors, const std::map& method_handlers) { - // NcMethodDescriptor vs method + // NcMethodDescriptor method handler array std::vector methods; if (!nc_method_descriptors.is_null()) diff --git a/Development/nmos/control_protocol_state.h b/Development/nmos/control_protocol_state.h index f48826d04..5887b6035 100644 --- a/Development/nmos/control_protocol_state.h +++ b/Development/nmos/control_protocol_state.h @@ -20,9 +20,9 @@ namespace nmos nmos::nc_name name; web::json::value fixed_role; - web::json::value properties = web::json::value::array(); // array of NcPropertyDescriptor - std::vector methods; // vector of NcMethodDescriptor, standard_method_handler and non_standard_method_handler - web::json::value events = web::json::value::array(); // array of NcEventDescriptor + web::json::value properties = web::json::value::array(); // NcPropertyDescriptor array + std::vector methods; // NcMethodDescriptor method handler array + web::json::value events = web::json::value::array(); // NcEventDescriptor array control_class() : class_id({ 0 }) From 9406d81db579e3644df01c0399976365b784b24f Mon Sep 17 00:00:00 2001 From: "Jonathan Thorpe (Sony)" Date: Mon, 26 Feb 2024 16:46:20 +0000 Subject: [PATCH 095/106] Added Receiver Monitor Protected and Ident Beacon workers to control_protocol_resources --- .../nmos/control_protocol_resources.cpp | 52 +++++++++++++++++-- Development/nmos/control_protocol_resources.h | 18 +++++++ Development/nmos/type.h | 1 + 3 files changed, 66 insertions(+), 5 deletions(-) diff --git a/Development/nmos/control_protocol_resources.cpp b/Development/nmos/control_protocol_resources.cpp index b1a267f7e..155e12730 100644 --- a/Development/nmos/control_protocol_resources.cpp +++ b/Development/nmos/control_protocol_resources.cpp @@ -64,18 +64,60 @@ namespace nmos return{ is12_versions::v1_0, types::nc_class_manager, std::move(data), true }; } + // Monitoring feature set control classes + // + namespace details + { + web::json::value make_receiver_monitor(const nc_class_id& class_id, nc_oid oid, nmos::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, + nc_connection_status::status connection_status, const utility::string_t& connection_status_message, nc_payload_status::status payload_status, const utility::string_t& payload_status_message) + { + using web::json::value; + + auto data = nmos::details::make_nc_worker(class_id, oid, true, owner, role, value::string(user_label), description, touchpoints, runtime_property_constraints, true); + data[nmos::fields::nc::connection_status] = value::number(connection_status); + data[nmos::fields::nc::connection_status_message] = value::string(connection_status_message); + data[nmos::fields::nc::payload_status] = value::number(payload_status); + data[nmos::fields::nc::payload_status_message] = value::string(payload_status_message); + + return data; + } + + } // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitor control_protocol_resource make_receiver_monitor(nc_oid oid, nmos::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, nc_connection_status::status connection_status, const utility::string_t& connection_status_message, nc_payload_status::status payload_status, const utility::string_t& payload_status_message) { using web::json::value; - auto data = nmos::details::make_nc_worker(nc_receiver_monitor_class_id, oid, true, owner, role, value::string(user_label), description, touchpoints, runtime_property_constraints, true); - data[nmos::fields::nc::connection_status] = value::number(connection_status); - data[nmos::fields::nc::connection_status_message] = value::string(connection_status_message); - data[nmos::fields::nc::payload_status] = value::number(payload_status); - data[nmos::fields::nc::payload_status_message] = value::string(payload_status_message); + auto data = nmos::details::make_receiver_monitor(nc_receiver_monitor_class_id, oid, owner, role, user_label, description, touchpoints, runtime_property_constraints, connection_status, connection_status_message, payload_status, payload_status_message); return{ is12_versions::v1_0, types::nc_receiver_monitor, std::move(data), true }; } + + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitorprotected + control_protocol_resource make_receiver_monitor_protected(nc_oid oid, nmos::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, + nc_connection_status::status connection_status, const utility::string_t& connection_status_message, nc_payload_status::status payload_status, const utility::string_t& payload_status_message, bool signal_protection_status) + { + using web::json::value; + + auto data = nmos::details::make_receiver_monitor(nc_receiver_monitor_protected_class_id, oid, owner, role, user_label, description, touchpoints, runtime_property_constraints, connection_status, connection_status_message, payload_status, payload_status_message); + data[nmos::fields::nc::signal_protection_status] = value::boolean(signal_protection_status); + + return{ is12_versions::v1_0, types::nc_receiver_monitor_protected, std::move(data), true }; + } + + // Identification feature set control classes + // + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/identification/#ncidentbeacon + control_protocol_resource make_ident_beacon(nc_oid oid, nmos::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, + bool active) + { + using web::json::value; + + auto data = nmos::details::make_nc_worker(nc_ident_beacon_class_id, oid, true, owner, role, value::string(user_label), description, touchpoints, runtime_property_constraints, true); + data[nmos::fields::nc::active] = value::boolean(active); + + return{ is12_versions::v1_0, types::nc_ident_beacon, std::move(data), true }; + } + } diff --git a/Development/nmos/control_protocol_resources.h b/Development/nmos/control_protocol_resources.h index c17edcc8d..eb9aedf83 100644 --- a/Development/nmos/control_protocol_resources.h +++ b/Development/nmos/control_protocol_resources.h @@ -25,6 +25,8 @@ namespace nmos // create Class manager resource control_protocol_resource make_class_manager(nc_oid oid, const nmos::experimental::control_protocol_state& control_protocol_state); + // Monitoring feature set control classes + // // create Receiver Monitor resource control_protocol_resource make_receiver_monitor(nc_oid oid, nmos::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null(), nc_connection_status::status connection_status = nc_connection_status::status::undefined, @@ -32,6 +34,22 @@ namespace nmos nc_payload_status::status payload_status = nc_payload_status::status::undefined, const utility::string_t& payload_status_message = U("") ); + + // create Receiver Monitor Protected resource + control_protocol_resource make_receiver_monitor_protected(nc_oid oid, nmos::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints = web::json::value::null(), + nc_connection_status::status connection_status = nc_connection_status::status::undefined, + const utility::string_t& connection_status_message = U(""), + nc_payload_status::status payload_status = nc_payload_status::status::undefined, + const utility::string_t& payload_status_message = U(""), + bool signal_protection_status = true + ); + + // Identification feature set control classes + // + // create Ident Beacon resource + control_protocol_resource make_ident_beacon(nc_oid oid, nmos::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null(), + bool active = false + ); } #endif diff --git a/Development/nmos/type.h b/Development/nmos/type.h index 3c2853ebe..8da37f685 100644 --- a/Development/nmos/type.h +++ b/Development/nmos/type.h @@ -48,6 +48,7 @@ namespace nmos const type nc_class_manager{ U("nc_class_manager") }; const type nc_receiver_monitor{ U("nc_receiver_monitor") }; const type nc_receiver_monitor_protected{ U("nc_receiver_monitor_protected") }; + const type nc_ident_beacon{ U("nc_ident_beacon") }; } } From 8794dd426298d6a2636e79e77252b7d11f199bb3 Mon Sep 17 00:00:00 2001 From: Simon Lo Date: Tue, 27 Feb 2024 19:01:38 +0000 Subject: [PATCH 096/106] Apply suggestions from code review Co-authored-by: jonathan-r-thorpe <64410119+jonathan-r-thorpe@users.noreply.github.com> --- Development/nmos-cpp-node/node_implementation.cpp | 4 ++-- Development/nmos/control_protocol_handlers.cpp | 2 +- Development/nmos/control_protocol_methods.cpp | 8 ++++---- Development/nmos/control_protocol_resource.cpp | 2 +- Development/nmos/control_protocol_resource.h | 2 +- Development/nmos/control_protocol_typedefs.h | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Development/nmos-cpp-node/node_implementation.cpp b/Development/nmos-cpp-node/node_implementation.cpp index d888da2e3..dc47f2a26 100644 --- a/Development/nmos-cpp-node/node_implementation.cpp +++ b/Development/nmos-cpp-node/node_implementation.cpp @@ -1365,7 +1365,7 @@ void node_implementation_run(nmos::node_model& model, slog::base_gate& gate) if (resources.end() != found) { - const auto propertry_changed_event = nmos::make_propertry_changed_event(nmos::fields::nc::oid(found->data), + const auto property_changed_event = nmos::make_property_changed_event(nmos::fields::nc::oid(found->data), { { {3, 1}, nmos::nc_property_change_type::type::value_changed, web::json::value(temp.scaled_value()) } }); @@ -1374,7 +1374,7 @@ void node_implementation_run(nmos::node_model& model, slog::base_gate& gate) { resource.data[temperature] = temp.scaled_value(); - }, propertry_changed_event); + }, property_changed_event); } } diff --git a/Development/nmos/control_protocol_handlers.cpp b/Development/nmos/control_protocol_handlers.cpp index 9cf68e56f..4f6263250 100644 --- a/Development/nmos/control_protocol_handlers.cpp +++ b/Development/nmos/control_protocol_handlers.cpp @@ -84,7 +84,7 @@ namespace nmos // hmm, maybe updating connectionStatusMessage, payloadStatus, and payloadStatusMessage too - const auto propertry_changed_event = make_propertry_changed_event(nmos::fields::nc::oid(found->data), + const auto property_changed_event = make_property_changed_event(nmos::fields::nc::oid(found->data), { { nc_receiver_monitor_connection_status_property_id, nc_property_change_type::type::value_changed, value } }); diff --git a/Development/nmos/control_protocol_methods.cpp b/Development/nmos/control_protocol_methods.cpp index 7dd2fe92c..00b7cdc0e 100644 --- a/Development/nmos/control_protocol_methods.cpp +++ b/Development/nmos/control_protocol_methods.cpp @@ -76,7 +76,7 @@ namespace nmos property_changed(resource, nmos::fields::nc::name(property), -1); } - }, make_propertry_changed_event(nmos::fields::nc::oid(resource.data), { { property_id_, nc_property_change_type::type::value_changed, val } })); + }, make_property_changed_event(nmos::fields::nc::oid(resource.data), { { property_id_, nc_property_change_type::type::value_changed, val } })); return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }); } @@ -184,7 +184,7 @@ namespace nmos property_changed(resource, nmos::fields::nc::name(property), index); } - }, make_propertry_changed_event(nmos::fields::nc::oid(resource.data), { { property_id_, nc_property_change_type::type::sequence_item_changed, val, nc_id(index) } })); + }, make_property_changed_event(nmos::fields::nc::oid(resource.data), { { property_id_, nc_property_change_type::type::sequence_item_changed, val, nc_id(index) } })); return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }); } @@ -260,7 +260,7 @@ namespace nmos property_changed(resource, nmos::fields::nc::name(property), (int)sequence.as_array().size()-1); } - }, make_propertry_changed_event(nmos::fields::nc::oid(resource.data), { { property_id_, nc_property_change_type::type::sequence_item_added, val, sequence_item_index } })); + }, make_property_changed_event(nmos::fields::nc::oid(resource.data), { { property_id_, nc_property_change_type::type::sequence_item_added, val, sequence_item_index } })); return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }, sequence_item_index); } @@ -309,7 +309,7 @@ namespace nmos auto& sequence = resource.data[nmos::fields::nc::name(property)].as_array(); sequence.erase(index); - }, make_propertry_changed_event(nmos::fields::nc::oid(resource.data), { { details::parse_nc_property_id(property_id), nc_property_change_type::type::sequence_item_removed, nc_id(index) } })); + }, make_property_changed_event(nmos::fields::nc::oid(resource.data), { { details::parse_nc_property_id(property_id), nc_property_change_type::type::sequence_item_removed, nc_id(index) } })); return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }); } diff --git a/Development/nmos/control_protocol_resource.cpp b/Development/nmos/control_protocol_resource.cpp index 2c47e77a9..cd46a3a80 100644 --- a/Development/nmos/control_protocol_resource.cpp +++ b/Development/nmos/control_protocol_resource.cpp @@ -899,7 +899,7 @@ namespace nmos // property changed notification event // See https://specs.amwa.tv/ms-05-01/branches/v1.0.x/docs/Core_Mechanisms.html#the-propertychanged-event // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/NcObject.html#propertychanged-event - web::json::value make_propertry_changed_event(nc_oid oid, const std::vector& property_changed_event_data_list) + web::json::value make_property_changed_event(nc_oid oid, const std::vector& property_changed_event_data_list) { using web::json::value; diff --git a/Development/nmos/control_protocol_resource.h b/Development/nmos/control_protocol_resource.h index 719f92a2e..80b45bc35 100644 --- a/Development/nmos/control_protocol_resource.h +++ b/Development/nmos/control_protocol_resource.h @@ -205,7 +205,7 @@ namespace nmos // property changed notification event // See https://specs.amwa.tv/ms-05-01/branches/v1.0.x/docs/Core_Mechanisms.html#the-propertychanged-event // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/NcObject.html#propertychanged-event - web::json::value make_propertry_changed_event(nc_oid oid, const std::vector& property_changed_event_data_list); + web::json::value make_property_changed_event(nc_oid oid, const std::vector& property_changed_event_data_list); // error message // See https://specs.amwa.tv/is-12/branches/v1.0.x/docs/Protocol_messaging.html#error-messages diff --git a/Development/nmos/control_protocol_typedefs.h b/Development/nmos/control_protocol_typedefs.h index f31ca98df..7afcefedb 100644 --- a/Development/nmos/control_protocol_typedefs.h +++ b/Development/nmos/control_protocol_typedefs.h @@ -32,7 +32,7 @@ namespace nmos property_deprecated = 298, // Method call was successful but targeted property is deprecated method_deprecated = 299, // Method call was successful but method is deprecated bad_command_format = 400, // Badly-formed command - unathorized = 401, // Client is not authorized + unauthorized = 401, // Client is not authorized bad_oid = 404, // Command addresses a nonexistent object read_only = 405, // Attempt to change read-only state invalid_request = 406, // Method call is invalid in current operating context @@ -146,7 +146,7 @@ namespace nmos // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#nceventid typedef nc_element_id nc_event_id; // NcEventIds for NcObject - // SEe https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncobject + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncobject const nc_event_id nc_object_property_changed_event_id(1, 1); // NcMethodId From 60f6204b40c8e89ba63a2f3ae8274d4c6effa87e Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 27 Feb 2024 19:10:54 +0000 Subject: [PATCH 097/106] Typo --- Development/nmos/control_protocol_handlers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Development/nmos/control_protocol_handlers.cpp b/Development/nmos/control_protocol_handlers.cpp index 4f6263250..ec8a2e65c 100644 --- a/Development/nmos/control_protocol_handlers.cpp +++ b/Development/nmos/control_protocol_handlers.cpp @@ -93,7 +93,7 @@ namespace nmos { resource.data[nmos::fields::nc::connection_status] = value; - }, propertry_changed_event); + }, property_changed_event); } }; } From af5dce0534b350cf691b05b64d688cf559b4a257 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 27 Feb 2024 20:19:23 +0000 Subject: [PATCH 098/106] Fix example_control to use the number within the level 2 runtime constraints --- Development/nmos-cpp-node/node_implementation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Development/nmos-cpp-node/node_implementation.cpp b/Development/nmos-cpp-node/node_implementation.cpp index dc47f2a26..06655e589 100644 --- a/Development/nmos-cpp-node/node_implementation.cpp +++ b/Development/nmos-cpp-node/node_implementation.cpp @@ -1237,7 +1237,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr }), example_enum::Undefined, U("test"), - 4, + 30, 10, false, make_example_datatype(example_enum::Undefined, U("default"), 5, false), From 201374dda6711b1655004317b389d742b14e6b69 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 27 Feb 2024 22:01:57 +0000 Subject: [PATCH 099/106] Add nc_ident_beacon resource type --- Development/nmos/api_utils.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Development/nmos/api_utils.cpp b/Development/nmos/api_utils.cpp index e2eb10caa..899d759d6 100644 --- a/Development/nmos/api_utils.cpp +++ b/Development/nmos/api_utils.cpp @@ -169,7 +169,8 @@ namespace nmos { U("nc_device_manager"), nmos::types::nc_device_manager }, { U("nc_class_manager"), nmos::types::nc_class_manager }, { U("nc_receiver_monitor"), nmos::types::nc_receiver_monitor }, - { U("nc_receiver_monitor_protected"), nmos::types::nc_receiver_monitor_protected } + { U("nc_receiver_monitor_protected"), nmos::types::nc_receiver_monitor_protected }, + { U("nc_ident_beacon"), nmos::types::nc_ident_beacon } }; return types_from_resourceType.at(resourceType); } @@ -195,7 +196,8 @@ namespace nmos { nmos::types::nc_device_manager, U("nc_device_manager") }, { nmos::types::nc_class_manager, U("nc_class_manager") }, { nmos::types::nc_receiver_monitor, U("nc_receiver_monitor") }, - { nmos::types::nc_receiver_monitor_protected, U("nc_receiver_monitor_protected") } + { nmos::types::nc_receiver_monitor_protected, U("nc_receiver_monitor_protected") }, + { nmos::types::nc_ident_beacon, U("nc_ident_beacon") } }; return resourceTypes_from_type.at(type); } From 64e2187dd483bdc824337341613bb6f3ef4ee83d Mon Sep 17 00:00:00 2001 From: lo-simon Date: Tue, 27 Feb 2024 22:06:43 +0000 Subject: [PATCH 100/106] Tidy up receiver_monitor, receiver_monitor_protected and ident_beacon resources --- .../nmos-cpp-node/node_implementation.cpp | 2 +- .../nmos/control_protocol_resource.cpp | 20 ++++++++--- Development/nmos/control_protocol_resource.h | 6 +++- .../nmos/control_protocol_resources.cpp | 34 ++++--------------- Development/nmos/control_protocol_resources.h | 11 +++--- 5 files changed, 33 insertions(+), 40 deletions(-) diff --git a/Development/nmos-cpp-node/node_implementation.cpp b/Development/nmos-cpp-node/node_implementation.cpp index 06655e589..365f09213 100644 --- a/Development/nmos-cpp-node/node_implementation.cpp +++ b/Development/nmos-cpp-node/node_implementation.cpp @@ -1263,7 +1263,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr utility::stringstream_t role; role << U("monitor-") << ++count; const auto& receiver = nmos::find_resource(model.node_resources, receiver_id); - const auto receiver_monitor = nmos::make_receiver_monitor(++oid, nmos::root_block_oid, role.str(), nmos::fields::label(receiver->data), nmos::fields::description(receiver->data), value_of({ { nmos::details::make_nc_touchpoint_nmos({nmos::ncp_nmos_resource_types::receiver, receiver_id}) } })); + const auto receiver_monitor = nmos::make_receiver_monitor(++oid, true, nmos::root_block_oid, role.str(), nmos::fields::label(receiver->data), nmos::fields::description(receiver->data), value_of({ { nmos::details::make_nc_touchpoint_nmos({nmos::ncp_nmos_resource_types::receiver, receiver_id}) } })); // add receiver-monitor to root-block nmos::push_back(root_block, receiver_monitor); diff --git a/Development/nmos/control_protocol_resource.cpp b/Development/nmos/control_protocol_resource.cpp index cd46a3a80..29b6b4344 100644 --- a/Development/nmos/control_protocol_resource.cpp +++ b/Development/nmos/control_protocol_resource.cpp @@ -728,7 +728,7 @@ namespace nmos } // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncworker - web::json::value make_nc_worker(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled) + web::json::value make_nc_worker(const nc_class_id& class_id, nc_oid oid, bool constant_oid, nc_oid owner, const utility::string_t& role, const web::json::value& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled) { using web::json::value; @@ -738,6 +738,21 @@ namespace nmos return data; } + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitor + web::json::value make_receiver_monitor(const nc_class_id& class_id, nc_oid oid, bool constant_oid, nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled, + nc_connection_status::status connection_status, const utility::string_t& connection_status_message, nc_payload_status::status payload_status, const utility::string_t& payload_status_message) + { + using web::json::value; + + auto data = make_nc_worker(class_id, oid, constant_oid, owner, role, value::string(user_label), description, touchpoints, runtime_property_constraints, enabled); + data[nmos::fields::nc::connection_status] = value::number(connection_status); + data[nmos::fields::nc::connection_status_message] = value::string(connection_status_message); + data[nmos::fields::nc::payload_status] = value::number(payload_status); + data[nmos::fields::nc::payload_status_message] = value::string(payload_status_message); + + return data; + } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncmanager web::json::value make_nc_manager(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints) { @@ -1284,7 +1299,6 @@ namespace nmos return details::make_nc_class_descriptor(U("NcClassManager class descriptor"), nc_class_manager_class_id, U("NcClassManager"), U("ClassManager"), make_nc_class_manager_properties(), make_nc_class_manager_methods(), make_nc_class_manager_events()); } - // Identification feature set control classes // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/identification/#ncidentbeacon web::json::value make_nc_ident_beacon_class() @@ -1294,7 +1308,6 @@ namespace nmos return details::make_nc_class_descriptor(U("NcIdentBeacon class descriptor"), nc_ident_beacon_class_id, U("NcIdentBeacon"), make_nc_ident_beacon_properties(), make_nc_ident_beacon_methods(), make_nc_ident_beacon_events()); } - // Monitoring feature set control classes // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitor web::json::value make_nc_receiver_monitor_class() @@ -1312,7 +1325,6 @@ namespace nmos return details::make_nc_class_descriptor(U("NcReceiverMonitorProtected class descriptor"), nc_receiver_monitor_protected_class_id, U("NcReceiverMonitorProtected"), make_nc_receiver_monitor_protected_properties(), make_nc_receiver_monitor_protected_methods(), make_nc_receiver_monitor_protected_events()); } - // Primitive datatypes // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#primitives web::json::value make_nc_boolean_datatype() diff --git a/Development/nmos/control_protocol_resource.h b/Development/nmos/control_protocol_resource.h index 80b45bc35..a03542264 100644 --- a/Development/nmos/control_protocol_resource.h +++ b/Development/nmos/control_protocol_resource.h @@ -170,7 +170,11 @@ namespace nmos web::json::value make_nc_block(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled, const web::json::value& members); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncworker - web::json::value make_nc_worker(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled); + web::json::value make_nc_worker(const nc_class_id& class_id, nc_oid oid, bool constant_oid, nc_oid owner, const utility::string_t& role, const web::json::value& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled); + + // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitor + web::json::value make_receiver_monitor(const nc_class_id& class_id, nc_oid oid, bool constant_oid, nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled, + nc_connection_status::status connection_status, const utility::string_t& connection_status_message, nc_payload_status::status payload_status, const utility::string_t& payload_status_message); // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncmanager web::json::value make_nc_manager(const nc_class_id& class_id, nc_oid oid, bool constant_oid, const web::json::value& owner, const utility::string_t& role, const web::json::value& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints); diff --git a/Development/nmos/control_protocol_resources.cpp b/Development/nmos/control_protocol_resources.cpp index 155e12730..0fde54c33 100644 --- a/Development/nmos/control_protocol_resources.cpp +++ b/Development/nmos/control_protocol_resources.cpp @@ -2,7 +2,6 @@ #include "nmos/control_protocol_resource.h" #include "nmos/control_protocol_utils.h" -#include "nmos/resource.h" #include "nmos/is12_versions.h" namespace nmos @@ -66,41 +65,21 @@ namespace nmos // Monitoring feature set control classes // - namespace details - { - web::json::value make_receiver_monitor(const nc_class_id& class_id, nc_oid oid, nmos::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, - nc_connection_status::status connection_status, const utility::string_t& connection_status_message, nc_payload_status::status payload_status, const utility::string_t& payload_status_message) - { - using web::json::value; - - auto data = nmos::details::make_nc_worker(class_id, oid, true, owner, role, value::string(user_label), description, touchpoints, runtime_property_constraints, true); - data[nmos::fields::nc::connection_status] = value::number(connection_status); - data[nmos::fields::nc::connection_status_message] = value::string(connection_status_message); - data[nmos::fields::nc::payload_status] = value::number(payload_status); - data[nmos::fields::nc::payload_status_message] = value::string(payload_status_message); - - return data; - } - - } // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitor - control_protocol_resource make_receiver_monitor(nc_oid oid, nmos::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, + control_protocol_resource make_receiver_monitor(nc_oid oid, bool constant_oid, nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled, nc_connection_status::status connection_status, const utility::string_t& connection_status_message, nc_payload_status::status payload_status, const utility::string_t& payload_status_message) { - using web::json::value; - - auto data = nmos::details::make_receiver_monitor(nc_receiver_monitor_class_id, oid, owner, role, user_label, description, touchpoints, runtime_property_constraints, connection_status, connection_status_message, payload_status, payload_status_message); + auto data = details::make_receiver_monitor(nc_receiver_monitor_class_id, oid, constant_oid, owner, role, user_label, description, touchpoints, runtime_property_constraints, enabled, connection_status, connection_status_message, payload_status, payload_status_message); return{ is12_versions::v1_0, types::nc_receiver_monitor, std::move(data), true }; } - // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#ncreceivermonitorprotected - control_protocol_resource make_receiver_monitor_protected(nc_oid oid, nmos::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, + control_protocol_resource make_receiver_monitor_protected(nc_oid oid, bool constant_oid, nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled, nc_connection_status::status connection_status, const utility::string_t& connection_status_message, nc_payload_status::status payload_status, const utility::string_t& payload_status_message, bool signal_protection_status) { using web::json::value; - auto data = nmos::details::make_receiver_monitor(nc_receiver_monitor_protected_class_id, oid, owner, role, user_label, description, touchpoints, runtime_property_constraints, connection_status, connection_status_message, payload_status, payload_status_message); + auto data = details::make_receiver_monitor(nc_receiver_monitor_protected_class_id, oid, constant_oid, owner, role, user_label, description, touchpoints, runtime_property_constraints, enabled, connection_status, connection_status_message, payload_status, payload_status_message); data[nmos::fields::nc::signal_protection_status] = value::boolean(signal_protection_status); return{ is12_versions::v1_0, types::nc_receiver_monitor_protected, std::move(data), true }; @@ -109,15 +88,14 @@ namespace nmos // Identification feature set control classes // // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/identification/#ncidentbeacon - control_protocol_resource make_ident_beacon(nc_oid oid, nmos::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, + control_protocol_resource make_ident_beacon(nc_oid oid, bool constant_oid, nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints, bool enabled, bool active) { using web::json::value; - auto data = nmos::details::make_nc_worker(nc_ident_beacon_class_id, oid, true, owner, role, value::string(user_label), description, touchpoints, runtime_property_constraints, true); + auto data = nmos::details::make_nc_worker(nc_ident_beacon_class_id, oid, constant_oid, owner, role, value::string(user_label), description, touchpoints, runtime_property_constraints, enabled); data[nmos::fields::nc::active] = value::boolean(active); return{ is12_versions::v1_0, types::nc_ident_beacon, std::move(data), true }; } - } diff --git a/Development/nmos/control_protocol_resources.h b/Development/nmos/control_protocol_resources.h index eb9aedf83..4ad7d85da 100644 --- a/Development/nmos/control_protocol_resources.h +++ b/Development/nmos/control_protocol_resources.h @@ -26,17 +26,16 @@ namespace nmos control_protocol_resource make_class_manager(nc_oid oid, const nmos::experimental::control_protocol_state& control_protocol_state); // Monitoring feature set control classes - // + // // create Receiver Monitor resource - control_protocol_resource make_receiver_monitor(nc_oid oid, nmos::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null(), + control_protocol_resource make_receiver_monitor(nc_oid oid, bool constant_oid, nmos::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null(), bool enabled = true, nc_connection_status::status connection_status = nc_connection_status::status::undefined, const utility::string_t& connection_status_message = U(""), nc_payload_status::status payload_status = nc_payload_status::status::undefined, const utility::string_t& payload_status_message = U("") ); - // create Receiver Monitor Protected resource - control_protocol_resource make_receiver_monitor_protected(nc_oid oid, nmos::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints = web::json::value::null(), + control_protocol_resource make_receiver_monitor_protected(nc_oid oid, bool constant_oid, nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints = web::json::value::null(), bool enabled = true, nc_connection_status::status connection_status = nc_connection_status::status::undefined, const utility::string_t& connection_status_message = U(""), nc_payload_status::status payload_status = nc_payload_status::status::undefined, @@ -45,9 +44,9 @@ namespace nmos ); // Identification feature set control classes - // + // // create Ident Beacon resource - control_protocol_resource make_ident_beacon(nc_oid oid, nmos::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null(), + control_protocol_resource make_ident_beacon(nc_oid oid, bool constant_oid, nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null(), bool enabled = true, bool active = false ); } From 2484b29f8da21225048ccb6ee3cf4526f6f3010e Mon Sep 17 00:00:00 2001 From: Simon Lo Date: Wed, 28 Feb 2024 11:45:51 +0000 Subject: [PATCH 101/106] Update Development/nmos/control_protocol_ws_api.cpp Co-authored-by: jonathan-r-thorpe <64410119+jonathan-r-thorpe@users.noreply.github.com> --- Development/nmos/control_protocol_ws_api.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Development/nmos/control_protocol_ws_api.cpp b/Development/nmos/control_protocol_ws_api.cpp index 56c9c0855..dc7ae2006 100644 --- a/Development/nmos/control_protocol_ws_api.cpp +++ b/Development/nmos/control_protocol_ws_api.cpp @@ -259,6 +259,7 @@ namespace nmos const auto& class_id = nmos::details::parse_nc_class_id(nmos::fields::nc::class_id(resource->data)); // find the relevent method handler to execute + // method tuple definition described in control_protocol_handlers.h auto method = get_control_protocol_method(class_id, method_id); auto& nc_method_descriptor = std::get<0>(method); auto& standard_method = std::get<1>(method); From 2bdb171b584bec80adc5d6f6d9ba775f3812872e Mon Sep 17 00:00:00 2001 From: Simon Lo Date: Wed, 28 Feb 2024 12:48:26 +0000 Subject: [PATCH 102/106] Update Development/nmos/json_fields.h Co-authored-by: jonathan-r-thorpe <64410119+jonathan-r-thorpe@users.noreply.github.com> --- Development/nmos/json_fields.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Development/nmos/json_fields.h b/Development/nmos/json_fields.h index 5bc499006..7374c5a90 100644 --- a/Development/nmos/json_fields.h +++ b/Development/nmos/json_fields.h @@ -230,7 +230,7 @@ namespace nmos const web::json::field_as_string hostname{ U("hostname") }; // hostname, ipv4 or ipv6 const web::json::field_as_integer port{ U("port") }; // 1..65535 - // IS-12 Control Protocol + // IS-12 Control Protocol and MS-05 model definitions namespace nc { // for control_protocol_ws_api From bb4480aa7212cb6e79e36739df395dbcb6ec7d76 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Thu, 29 Feb 2024 20:44:00 +0000 Subject: [PATCH 103/106] Change varaible names and function names for better description --- Development/nmos-cpp-node/main.cpp | 6 +- .../nmos-cpp-node/node_implementation.cpp | 100 +++++++++--------- .../nmos/control_protocol_handlers.cpp | 32 +++--- Development/nmos/control_protocol_handlers.h | 30 +++--- Development/nmos/control_protocol_methods.cpp | 72 ++++++------- Development/nmos/control_protocol_methods.h | 26 ++--- .../nmos/control_protocol_resource.cpp | 14 +-- Development/nmos/control_protocol_state.cpp | 96 ++++++++--------- Development/nmos/control_protocol_state.h | 62 +++++------ Development/nmos/control_protocol_utils.cpp | 41 ++++--- Development/nmos/control_protocol_utils.h | 12 +-- Development/nmos/control_protocol_ws_api.cpp | 10 +- Development/nmos/control_protocol_ws_api.h | 6 +- Development/nmos/node_server.cpp | 2 +- Development/nmos/node_server.h | 20 ++-- .../nmos/test/control_protocol_test.cpp | 66 ++++++------ 16 files changed, 297 insertions(+), 298 deletions(-) diff --git a/Development/nmos-cpp-node/main.cpp b/Development/nmos-cpp-node/main.cpp index 9d77916b7..720cafd36 100644 --- a/Development/nmos-cpp-node/main.cpp +++ b/Development/nmos-cpp-node/main.cpp @@ -143,9 +143,9 @@ int main(int argc, char* argv[]) if (0 <= nmos::fields::control_protocol_ws_port(node_model.settings)) { node_implementation - .on_get_control_class(nmos::make_get_control_protocol_class_handler(control_protocol_state)) - .on_get_control_datatype(nmos::make_get_control_protocol_datatype_handler(control_protocol_state)) - .on_get_control_protocol_method(nmos::make_get_control_protocol_method_handler(control_protocol_state)); + .on_get_control_class_descriptor(nmos::make_get_control_protocol_class_descriptor_handler(control_protocol_state)) + .on_get_control_datatype_descriptor(nmos::make_get_control_protocol_datatype_descriptor_handler(control_protocol_state)) + .on_get_control_protocol_method_descriptor(nmos::make_get_control_protocol_method_descriptor_handler(control_protocol_state)); } // Set up the node server diff --git a/Development/nmos-cpp-node/node_implementation.cpp b/Development/nmos-cpp-node/node_implementation.cpp index 365f09213..ab1a686ff 100644 --- a/Development/nmos-cpp-node/node_implementation.cpp +++ b/Development/nmos-cpp-node/node_implementation.cpp @@ -931,16 +931,16 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr const auto gain_control_class_id = nmos::make_nc_class_id(nmos::nc_worker_class_id, 0, { 1 }); const web::json::field_as_number gain_value{ U("gainValue") }; { - // Gain control class properties - std::vector gain_control_properties = { nmos::experimental::make_control_class_property(U("Gain value"), { 3, 1 }, gain_value, U("NcFloat32")) }; + // Gain control class property descriptors + std::vector gain_control_property_descriptors = { nmos::experimental::make_control_class_property_descriptor(U("Gain value"), { 3, 1 }, gain_value, U("NcFloat32")) }; - // create Gain control class - auto gain_control_class = nmos::experimental::make_control_class(U("Gain control class descriptor"), gain_control_class_id, U("GainControl"), gain_control_properties); + // create Gain control class descriptor + auto gain_control_class_descriptor = nmos::experimental::make_control_class_descriptor(U("Gain control class descriptor"), gain_control_class_id, U("GainControl"), gain_control_property_descriptors); - // insert Gain control class to global state, which will be used by the control_protocol_ws_message_handler to process incoming ws message - control_protocol_state.insert(gain_control_class); + // insert Gain control class descriptor to global state, which will be used by the control_protocol_ws_message_handler to process incoming ws message + control_protocol_state.insert(gain_control_class_descriptor); } - // helper function to create Gain control + // helper function to create Gain control instance auto make_gain_control = [&gain_value, &gain_control_class_id](nmos::nc_oid oid, nmos::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null(), float gain = 0.0) { auto data = nmos::details::make_nc_worker(gain_control_class_id, oid, true, owner, role, value::string(user_label), description, touchpoints, runtime_property_constraints, true); @@ -982,30 +982,30 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr auto make_string_example_argument_constraints = []() {return nmos::details::make_nc_parameter_constraints_string(10, U("^[a-z]+$")); }; auto make_number_example_argument_constraints = []() {return nmos::details::make_nc_parameter_constraints_number(0, 1000, 1); }; - // Example control class properties - std::vector example_control_properties = { - nmos::experimental::make_control_class_property(U("Example enum property"), { 3, 1 }, enum_property, U("ExampleEnum")), + // Example control class property descriptors + std::vector example_control_property_descriptors = { + nmos::experimental::make_control_class_property_descriptor(U("Example enum property"), { 3, 1 }, enum_property, U("ExampleEnum")), // create "Example string property" with level 1: property constraints, See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html // use nmos::details::make_nc_parameter_constraints_string to create property constraints - nmos::experimental::make_control_class_property(U("Example string property"), { 3, 2 }, string_property, U("NcString"), false, false, false, false, make_string_example_argument_constraints()), + nmos::experimental::make_control_class_property_descriptor(U("Example string property"), { 3, 2 }, string_property, U("NcString"), false, false, false, false, make_string_example_argument_constraints()), // create "Example numeric property" with level 1: property constraints, See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html // use nmos::details::make_nc_parameter_constraints_number to create property constraints - nmos::experimental::make_control_class_property(U("Example numeric property"), { 3, 3 }, number_property, U("NcUint64"), false, false, false, false, make_number_example_argument_constraints()), - nmos::experimental::make_control_class_property(U("Example deprecated numeric property"), { 3, 4 }, deprecated_number_property, U("NcUint64"), false, false, false, true, make_number_example_argument_constraints()), - nmos::experimental::make_control_class_property(U("Example boolean property"), { 3, 5 }, boolean_property, U("NcBoolean")), - nmos::experimental::make_control_class_property(U("Example object property"), { 3, 6 }, object_property, U("ExampleDataType")), - nmos::experimental::make_control_class_property(U("Example method no args invoke counter"), { 3, 7 }, method_no_args_count, U("NcUint64"), true), - nmos::experimental::make_control_class_property(U("Example method simple args invoke counter"), { 3, 8 }, method_simple_args_count, U("NcUint64"), true), - nmos::experimental::make_control_class_property(U("Example method obj arg invoke counter"), { 3, 9 }, method_object_arg_count, U("NcUint64"), true), + nmos::experimental::make_control_class_property_descriptor(U("Example numeric property"), { 3, 3 }, number_property, U("NcUint64"), false, false, false, false, make_number_example_argument_constraints()), + nmos::experimental::make_control_class_property_descriptor(U("Example deprecated numeric property"), { 3, 4 }, deprecated_number_property, U("NcUint64"), false, false, false, true, make_number_example_argument_constraints()), + nmos::experimental::make_control_class_property_descriptor(U("Example boolean property"), { 3, 5 }, boolean_property, U("NcBoolean")), + nmos::experimental::make_control_class_property_descriptor(U("Example object property"), { 3, 6 }, object_property, U("ExampleDataType")), + nmos::experimental::make_control_class_property_descriptor(U("Example method no args invoke counter"), { 3, 7 }, method_no_args_count, U("NcUint64"), true), + nmos::experimental::make_control_class_property_descriptor(U("Example method simple args invoke counter"), { 3, 8 }, method_simple_args_count, U("NcUint64"), true), + nmos::experimental::make_control_class_property_descriptor(U("Example method obj arg invoke counter"), { 3, 9 }, method_object_arg_count, U("NcUint64"), true), // create "Example sequence string property" with level 1: property constraints, See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html // use nmos::details::make_nc_parameter_constraints_string to create sequence property constraints - nmos::experimental::make_control_class_property(U("Example string sequence property"), { 3, 10 }, string_sequence, U("NcString"), false, false, true, false, make_string_example_argument_constraints()), - nmos::experimental::make_control_class_property(U("Example boolean sequence property"), { 3, 11 }, boolean_sequence, U("NcBoolean"), false, false, true), - nmos::experimental::make_control_class_property(U("Example enum sequence property"), { 3, 12 }, enum_sequence, U("ExampleEnum"), false, false, true), + nmos::experimental::make_control_class_property_descriptor(U("Example string sequence property"), { 3, 10 }, string_sequence, U("NcString"), false, false, true, false, make_string_example_argument_constraints()), + nmos::experimental::make_control_class_property_descriptor(U("Example boolean sequence property"), { 3, 11 }, boolean_sequence, U("NcBoolean"), false, false, true), + nmos::experimental::make_control_class_property_descriptor(U("Example enum sequence property"), { 3, 12 }, enum_sequence, U("ExampleEnum"), false, false, true), // create "Example sequence numeric property" with level 1: property constraints, See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html // use nmos::details::make_nc_parameter_constraints_number to create sequence property constraints - nmos::experimental::make_control_class_property(U("Example number sequence property"), { 3, 13 }, number_sequence, U("NcUint64"), false, false, true, false, make_number_example_argument_constraints()), - nmos::experimental::make_control_class_property(U("Example object sequence property"), { 3, 14 }, object_sequence, U("ExampleDataType"), false, false, true) + nmos::experimental::make_control_class_property_descriptor(U("Example number sequence property"), { 3, 13 }, number_sequence, U("NcUint64"), false, false, true, false, make_number_example_argument_constraints()), + nmos::experimental::make_control_class_property_descriptor(U("Example object sequence property"), { 3, 14 }, object_sequence, U("ExampleDataType"), false, false, true) }; auto example_method_with_no_args = [](nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, slog::base_gate& gate) @@ -1034,33 +1034,33 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr return nmos::make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::nc_method_status::ok }); }; - // Example control class methods - std::vector example_control_methods = + // Example control class method descriptors + std::vector example_control_method_descriptors = { - { nmos::experimental::make_control_class_method(U("Example method with no arguments"), { 3, 1 }, U("MethodNoArgs"), U("NcMethodResult"), {}, false, example_method_with_no_args) }, - { nmos::experimental::make_control_class_method(U("Example deprecated method with no arguments"), { 3, 2 }, U("MethodNoArgs"), U("NcMethodResult"), {}, true, example_method_with_no_args) }, - { nmos::experimental::make_control_class_method(U("Example method with simple arguments"), { 3, 3 }, U("MethodSimpleArgs"), U("NcMethodResult"), + { nmos::experimental::make_control_class_method_descriptor(U("Example method with no arguments"), { 3, 1 }, U("MethodNoArgs"), U("NcMethodResult"), {}, false, example_method_with_no_args) }, + { nmos::experimental::make_control_class_method_descriptor(U("Example deprecated method with no arguments"), { 3, 2 }, U("MethodNoArgs"), U("NcMethodResult"), {}, true, example_method_with_no_args) }, + { nmos::experimental::make_control_class_method_descriptor(U("Example method with simple arguments"), { 3, 3 }, U("MethodSimpleArgs"), U("NcMethodResult"), { - nmos::experimental::make_control_class_method_parameter(U("Enum example argument"), enum_arg, U("ExampleEnum")), - nmos::experimental::make_control_class_method_parameter(U("String example argument"), string_arg, U("NcString"), false, false, make_string_example_argument_constraints()), // e.g. include method property constraints - nmos::experimental::make_control_class_method_parameter(U("Number example argument"), number_arg, U("NcUint64"), false, false, make_number_example_argument_constraints()), // e.g. include method property constraints - nmos::experimental::make_control_class_method_parameter(U("Boolean example argument"), boolean_arg, U("NcBoolean")) + nmos::experimental::make_control_class_method_parameter_descriptor(U("Enum example argument"), enum_arg, U("ExampleEnum")), + nmos::experimental::make_control_class_method_parameter_descriptor(U("String example argument"), string_arg, U("NcString"), false, false, make_string_example_argument_constraints()), // e.g. include method property constraints + nmos::experimental::make_control_class_method_parameter_descriptor(U("Number example argument"), number_arg, U("NcUint64"), false, false, make_number_example_argument_constraints()), // e.g. include method property constraints + nmos::experimental::make_control_class_method_parameter_descriptor(U("Boolean example argument"), boolean_arg, U("NcBoolean")) }, false, example_method_with_simple_args) }, - { nmos::experimental::make_control_class_method(U("Example method with object argument"), { 3, 4 }, U("MethodObjectArg"), U("NcMethodResult"), + { nmos::experimental::make_control_class_method_descriptor(U("Example method with object argument"), { 3, 4 }, U("MethodObjectArg"), U("NcMethodResult"), { - nmos::experimental::make_control_class_method_parameter(U("Object example argument"), obj_arg, U("ExampleDataType")) + nmos::experimental::make_control_class_method_parameter_descriptor(U("Object example argument"), obj_arg, U("ExampleDataType")) }, false, example_method_with_object_args) } }; - // create Example control class - auto example_control_class = nmos::experimental::make_control_class(U("Example control class descriptor"), example_control_class_id, U("ExampleControl"), example_control_properties, example_control_methods); + // create Example control class descriptor + auto example_control_class_descriptor = nmos::experimental::make_control_class_descriptor(U("Example control class descriptor"), example_control_class_id, U("ExampleControl"), example_control_property_descriptors, example_control_method_descriptors); - // insert Example control class to global state, which will be used by the control_protocol_ws_message_handler to process incoming ws message - control_protocol_state.insert(example_control_class); + // insert Example control class descriptor to global state, which will be used by the control_protocol_ws_message_handler to process incoming ws message + control_protocol_state.insert(example_control_class_descriptor); // create/insert Example datatypes to global state, which will be used by the control_protocol_ws_message_handler to process incoming ws message auto make_example_enum_datatype = [&]() @@ -1095,8 +1095,8 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr web::json::push_back(fields, nmos::details::make_nc_field_descriptor(U("Boolean property example"), boolean_property, U("NcBoolean"), false, false, value::null())); return nmos::details::make_nc_datatype_descriptor_struct(U("Example data type"), U("ExampleDataType"), fields, value::null()); }; - control_protocol_state.insert(nmos::experimental::datatype{ make_example_enum_datatype() }); - control_protocol_state.insert(nmos::experimental::datatype{ make_example_datatype_datatype() }); + control_protocol_state.insert(nmos::experimental::datatype_descriptor{ make_example_enum_datatype() }); + control_protocol_state.insert(nmos::experimental::datatype_descriptor{ make_example_datatype_datatype() }); } // helper function to create Example datatype auto make_example_datatype = [&](example_enum enum_property_, const utility::string_t& string_property_, uint64_t number_property_, bool boolean_property_) @@ -1110,7 +1110,7 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr { boolean_property, boolean_property_ } }); }; - // helper function to create Example control + // helper function to create Example control instance auto make_example_control = [&](nmos::nc_oid oid, nmos::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const value& touchpoints = value::null(), const value& runtime_property_constraints = value::null(), // level 2: runtime constraints. See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html // use of make_nc_property_constraints_string and make_nc_property_constraints_number to create runtime constraints @@ -1173,19 +1173,19 @@ void node_implementation_init(nmos::node_model& model, nmos::experimental::contr const web::json::field_as_number temperature{ U("temperature") }; const web::json::field_as_string unit{ U("uint") }; { - // Temperature Sensor control class properties - std::vector temperature_sensor_properties = { - nmos::experimental::make_control_class_property(U("Temperature"), { 3, 1 }, temperature, U("NcFloat32"), true), - nmos::experimental::make_control_class_property(U("Unit"), { 3, 2 }, unit, U("NcString"), true) + // Temperature Sensor control class property descriptors + std::vector temperature_sensor_property_descriptors = { + nmos::experimental::make_control_class_property_descriptor(U("Temperature"), { 3, 1 }, temperature, U("NcFloat32"), true), + nmos::experimental::make_control_class_property_descriptor(U("Unit"), { 3, 2 }, unit, U("NcString"), true) }; - // create Temperature Sensor control class - auto temperature_sensor_control_class = nmos::experimental::make_control_class(U("Temperature Sensor control class descriptor"), temperature_sensor_control_class_id, U("TemperatureSensor"), temperature_sensor_properties); + // create Temperature Sensor control class descriptor + auto temperature_sensor_control_class_descriptor = nmos::experimental::make_control_class_descriptor(U("Temperature Sensor control class descriptor"), temperature_sensor_control_class_id, U("TemperatureSensor"), temperature_sensor_property_descriptors); - // insert Temperature Sensor control class to global state, which will be used by the control_protocol_ws_message_handler to process incoming ws message - control_protocol_state.insert(temperature_sensor_control_class); + // insert Temperature Sensor control class descriptor to global state, which will be used by the control_protocol_ws_message_handler to process incoming ws message + control_protocol_state.insert(temperature_sensor_control_class_descriptor); } - // helper function to create Temperature Sensor control + // helper function to create Temperature Sensor control instance auto make_temperature_sensor = [&temperature, &unit, temperature_sensor_control_class_id](nmos::nc_oid oid, nmos::nc_oid owner, const utility::string_t& role, const utility::string_t& user_label, const utility::string_t& description, const web::json::value& touchpoints = web::json::value::null(), const web::json::value& runtime_property_constraints = web::json::value::null(), float temperature_ = 0.0, const utility::string_t& unit_ = U("Celsius")) { auto data = nmos::details::make_nc_worker(temperature_sensor_control_class_id, oid, true, owner, role, value::string(user_label), description, touchpoints, runtime_property_constraints, true); diff --git a/Development/nmos/control_protocol_handlers.cpp b/Development/nmos/control_protocol_handlers.cpp index ec8a2e65c..a248d62f9 100644 --- a/Development/nmos/control_protocol_handlers.cpp +++ b/Development/nmos/control_protocol_handlers.cpp @@ -7,59 +7,59 @@ namespace nmos { - get_control_protocol_class_handler make_get_control_protocol_class_handler(nmos::experimental::control_protocol_state& control_protocol_state) + get_control_protocol_class_descriptor_handler make_get_control_protocol_class_descriptor_handler(nmos::experimental::control_protocol_state& control_protocol_state) { return [&](const nc_class_id& class_id) { auto lock = control_protocol_state.read_lock(); - auto& control_classes = control_protocol_state.control_classes; - auto found = control_classes.find(class_id); - if (control_classes.end() != found) + auto& control_class_descriptors = control_protocol_state.control_class_descriptors; + auto found = control_class_descriptors.find(class_id); + if (control_class_descriptors.end() != found) { return found->second; } - return nmos::experimental::control_class{}; + return nmos::experimental::control_class_descriptor{}; }; } - get_control_protocol_datatype_handler make_get_control_protocol_datatype_handler(nmos::experimental::control_protocol_state& control_protocol_state) + get_control_protocol_datatype_descriptor_handler make_get_control_protocol_datatype_descriptor_handler(nmos::experimental::control_protocol_state& control_protocol_state) { return [&](const nmos::nc_name& name) { auto lock = control_protocol_state.read_lock(); - auto found = control_protocol_state.datatypes.find(name); - if (control_protocol_state.datatypes.end() != found) + auto found = control_protocol_state.datatype_descriptors.find(name); + if (control_protocol_state.datatype_descriptors.end() != found) { return found->second; } - return nmos::experimental::datatype{}; + return nmos::experimental::datatype_descriptor{}; }; } - get_control_protocol_method_handler make_get_control_protocol_method_handler(experimental::control_protocol_state& control_protocol_state) + get_control_protocol_method_descriptor_handler make_get_control_protocol_method_descriptor_handler(experimental::control_protocol_state& control_protocol_state) { return [&](const nc_class_id& class_id_, const nc_method_id& method_id) { auto class_id = class_id_; - auto get_control_protocol_class = make_get_control_protocol_class_handler(control_protocol_state); + auto get_control_protocol_class_descriptor = make_get_control_protocol_class_descriptor_handler(control_protocol_state); auto lock = control_protocol_state.read_lock(); while (!class_id.empty()) { - const auto& control_class = get_control_protocol_class(class_id); + const auto& control_class_descriptor = get_control_protocol_class_descriptor(class_id); - auto& methods = control_class.methods; - auto method_found = std::find_if(methods.begin(), methods.end(), [&method_id](const experimental::method& method) + auto& method_descriptors = control_class_descriptor.method_descriptors; + auto found = std::find_if(method_descriptors.begin(), method_descriptors.end(), [&method_id](const experimental::method& method) { return method_id == details::parse_nc_method_id(nmos::fields::nc::id(std::get<0>(method))); }); - if (methods.end() != method_found) + if (method_descriptors.end() != found) { - return *method_found; + return *found; } class_id.pop_back(); diff --git a/Development/nmos/control_protocol_handlers.h b/Development/nmos/control_protocol_handlers.h index 814a8266f..43a2a3ba1 100644 --- a/Development/nmos/control_protocol_handlers.h +++ b/Development/nmos/control_protocol_handlers.h @@ -15,21 +15,21 @@ namespace nmos namespace experimental { struct control_protocol_state; - struct control_class; - struct datatype; + struct control_class_descriptor; + struct datatype_descriptor; } - // callback to retrieve a specific control protocol classe + // callback to retrieve a specific control protocol classs descriptor // this callback should not throw exceptions - typedef std::function get_control_protocol_class_handler; + typedef std::function get_control_protocol_class_descriptor_handler; - // callback to add user control protocol class + // callback to add user control protocol class descriptor // this callback should not throw exceptions - typedef std::function add_control_protocol_class_handler; + typedef std::function add_control_protocol_class_descriptor_handler; - // callback to retrieve a control protocol datatype + // callback to retrieve a control protocol datatype descriptor // this callback should not throw exceptions - typedef std::function get_control_protocol_datatype_handler; + typedef std::function get_control_protocol_datatype_descriptor_handler; // a control_protocol_property_changed_handler is a notification that the specified (IS-12) property has changed // index is set to -1 for non-sequence property @@ -39,7 +39,7 @@ namespace nmos namespace experimental { // standard method handler definition - typedef std::function standard_method_handler; + typedef std::function standard_method_handler; // non-standard method handler definition typedef std::function non_standard_method_handler; @@ -60,16 +60,16 @@ namespace nmos // callback to retrieve a specific method // this callback should not throw exceptions - typedef std::function get_control_protocol_method_handler; + typedef std::function get_control_protocol_method_descriptor_handler; - // construct callback to retrieve a specific control protocol class - get_control_protocol_class_handler make_get_control_protocol_class_handler(experimental::control_protocol_state& control_protocol_state); + // construct callback to retrieve a specific control protocol class descriptor + get_control_protocol_class_descriptor_handler make_get_control_protocol_class_descriptor_handler(experimental::control_protocol_state& control_protocol_state); - // construct callback to retrieve a specific datatype - get_control_protocol_datatype_handler make_get_control_protocol_datatype_handler(experimental::control_protocol_state& control_protocol_state); + // construct callback to retrieve a specific datatype descriptor + get_control_protocol_datatype_descriptor_handler make_get_control_protocol_datatype_descriptor_handler(experimental::control_protocol_state& control_protocol_state); // construct callback to retrieve a specific method - get_control_protocol_method_handler make_get_control_protocol_method_handler(experimental::control_protocol_state& control_protocol_state); + get_control_protocol_method_descriptor_handler make_get_control_protocol_method_descriptor_handler(experimental::control_protocol_state& control_protocol_state); // a control_protocol_connection_activation_handler is a notification that the active parameters for the specified (IS-05) sender/connection_sender or receiver/connection_receiver have changed // this callback should not throw exceptions diff --git a/Development/nmos/control_protocol_methods.cpp b/Development/nmos/control_protocol_methods.cpp index 00b7cdc0e..8bdd673c8 100644 --- a/Development/nmos/control_protocol_methods.cpp +++ b/Development/nmos/control_protocol_methods.cpp @@ -12,7 +12,7 @@ namespace nmos { // NcObject methods implementation // Get property value - web::json::value get(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) + web::json::value get(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor_handler, control_protocol_property_changed_handler, slog::base_gate& gate) { // note, model mutex is already locked by the outer function, so access to control_protocol_resources is OK... @@ -21,7 +21,7 @@ namespace nmos slog::log(gate, SLOG_FLF) << "Get property: " << property_id.serialize(); // find the relevant nc_property_descriptor - const auto& property = find_property(details::parse_nc_property_id(property_id), details::parse_nc_class_id(nmos::fields::nc::class_id(resource.data)), get_control_protocol_class); + const auto& property = find_property_descriptor(details::parse_nc_property_id(property_id), details::parse_nc_class_id(nmos::fields::nc::class_id(resource.data)), get_control_protocol_class_descriptor); if (!property.is_null()) { return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nmos::fields::nc::is_deprecated(property) ? nc_method_status::property_deprecated : nc_method_status::ok }, resource.data.at(nmos::fields::nc::name(property))); @@ -34,7 +34,7 @@ namespace nmos } // Set property value - web::json::value set(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler get_control_protocol_datatype, control_protocol_property_changed_handler property_changed, slog::base_gate& gate) + web::json::value set(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor, control_protocol_property_changed_handler property_changed, slog::base_gate& gate) { // note, model mutex is already locked by the outer function, so access to control_protocol_resources is OK... @@ -45,7 +45,7 @@ namespace nmos // find the relevant nc_property_descriptor const auto property_id_ = details::parse_nc_property_id(property_id); - const auto& property = find_property(property_id_, details::parse_nc_class_id(nmos::fields::nc::class_id(resource.data)), get_control_protocol_class); + const auto& property = find_property_descriptor(property_id_, details::parse_nc_class_id(nmos::fields::nc::class_id(resource.data)), get_control_protocol_class_descriptor); if (!property.is_null()) { if (nmos::fields::nc::is_read_only(property)) @@ -63,7 +63,7 @@ namespace nmos try { // do property constraints validation - nmos::details::constraints_validation(val, details::get_runtime_property_constraints(property_id_, resource.data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), { details::get_datatype_descriptor(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype), get_control_protocol_datatype }); + nmos::details::constraints_validation(val, details::get_runtime_property_constraints(property_id_, resource.data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), { details::get_datatype_descriptor(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype_descriptor), get_control_protocol_datatype_descriptor }); // update property modify_control_protocol_resource(resources, resource.id, [&](nmos::resource& resource) @@ -95,7 +95,7 @@ namespace nmos } // Get sequence item - web::json::value get_sequence_item(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) + web::json::value get_sequence_item(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor_handler, control_protocol_property_changed_handler, slog::base_gate& gate) { // note, model mutex is already locked by the outer function, so access to control_protocol_resources is OK... @@ -105,7 +105,7 @@ namespace nmos slog::log(gate, SLOG_FLF) << "Get sequence item: " << property_id.serialize() << " index: " << index; // find the relevant nc_property_descriptor - const auto& property = find_property(details::parse_nc_property_id(property_id), details::parse_nc_class_id(nmos::fields::nc::class_id(resource.data)), get_control_protocol_class); + const auto& property = find_property_descriptor(details::parse_nc_property_id(property_id), details::parse_nc_class_id(nmos::fields::nc::class_id(resource.data)), get_control_protocol_class_descriptor); if (!property.is_null()) { const auto& data = resource.data.at(nmos::fields::nc::name(property)); @@ -136,7 +136,7 @@ namespace nmos } // Set sequence item - web::json::value set_sequence_item(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler get_control_protocol_datatype, control_protocol_property_changed_handler property_changed, slog::base_gate& gate) + web::json::value set_sequence_item(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor, control_protocol_property_changed_handler property_changed, slog::base_gate& gate) { // note, model mutex is already locked by the outer function, so access to control_protocol_resources is OK... @@ -148,7 +148,7 @@ namespace nmos // find the relevant nc_property_descriptor const auto property_id_ = details::parse_nc_property_id(property_id); - const auto& property = find_property(property_id_, details::parse_nc_class_id(nmos::fields::nc::class_id(resource.data)), get_control_protocol_class); + const auto& property = find_property_descriptor(property_id_, details::parse_nc_class_id(nmos::fields::nc::class_id(resource.data)), get_control_protocol_class_descriptor); if (!property.is_null()) { if (nmos::fields::nc::is_read_only(property)) @@ -171,7 +171,7 @@ namespace nmos try { // do property constraints validation - nmos::details::constraints_validation(val, details::get_runtime_property_constraints(property_id_, resource.data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), { details::get_datatype_descriptor(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype), get_control_protocol_datatype }); + nmos::details::constraints_validation(val, details::get_runtime_property_constraints(property_id_, resource.data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), { details::get_datatype_descriptor(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype_descriptor), get_control_protocol_datatype_descriptor }); // update property modify_control_protocol_resource(resources, resource.id, [&](nmos::resource& resource) @@ -209,7 +209,7 @@ namespace nmos } // Add item to sequence - web::json::value add_sequence_item(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler get_control_protocol_datatype, control_protocol_property_changed_handler property_changed, slog::base_gate& gate) + web::json::value add_sequence_item(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor, control_protocol_property_changed_handler property_changed, slog::base_gate& gate) { // note, model mutex is already locked by the outer function, so access to control_protocol_resources is OK... @@ -222,7 +222,7 @@ namespace nmos // find the relevant nc_property_descriptor const auto property_id_ = details::parse_nc_property_id(property_id); - const auto& property = find_property(property_id_, details::parse_nc_class_id(nmos::fields::nc::class_id(resource.data)), get_control_protocol_class); + const auto& property = find_property_descriptor(property_id_, details::parse_nc_class_id(nmos::fields::nc::class_id(resource.data)), get_control_protocol_class_descriptor); if (!property.is_null()) { if (nmos::fields::nc::is_read_only(property)) @@ -245,7 +245,7 @@ namespace nmos try { // do property constraints validation - nmos::details::constraints_validation(val, details::get_runtime_property_constraints(property_id_, resource.data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), { details::get_datatype_descriptor(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype), get_control_protocol_datatype }); + nmos::details::constraints_validation(val, details::get_runtime_property_constraints(property_id_, resource.data.at(nmos::fields::nc::runtime_property_constraints)), nmos::fields::nc::constraints(property), { details::get_datatype_descriptor(property.at(nmos::fields::nc::type_name), get_control_protocol_datatype_descriptor), get_control_protocol_datatype_descriptor }); // update property modify_control_protocol_resource(resources, resource.id, [&](nmos::resource& resource) @@ -279,7 +279,7 @@ namespace nmos } // Delete sequence item - web::json::value remove_sequence_item(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) + web::json::value remove_sequence_item(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor_handler, control_protocol_property_changed_handler, slog::base_gate& gate) { // note, model mutex is already locked by the outer function, so access to control_protocol_resources is OK... @@ -289,7 +289,7 @@ namespace nmos slog::log(gate, SLOG_FLF) << "Remove sequence item: " << property_id.serialize() << " index: " << index; // find the relevant nc_property_descriptor - const auto& property = find_property(details::parse_nc_property_id(property_id), details::parse_nc_class_id(nmos::fields::nc::class_id(resource.data)), get_control_protocol_class); + const auto& property = find_property_descriptor(details::parse_nc_property_id(property_id), details::parse_nc_class_id(nmos::fields::nc::class_id(resource.data)), get_control_protocol_class_descriptor); if (!property.is_null()) { const auto& data = resource.data.at(nmos::fields::nc::name(property)); @@ -327,7 +327,7 @@ namespace nmos } // Get sequence length - web::json::value get_sequence_length(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) + web::json::value get_sequence_length(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor_handler, control_protocol_property_changed_handler, slog::base_gate& gate) { // note, model mutex is already locked by the outer function, so access to control_protocol_resources is OK... @@ -338,7 +338,7 @@ namespace nmos slog::log(gate, SLOG_FLF) << "Get sequence length: " << property_id.serialize(); // find the relevant nc_property_descriptor - const auto& property = find_property(details::parse_nc_property_id(property_id), details::parse_nc_class_id(nmos::fields::nc::class_id(resource.data)), get_control_protocol_class); + const auto& property = find_property_descriptor(details::parse_nc_property_id(property_id), details::parse_nc_class_id(nmos::fields::nc::class_id(resource.data)), get_control_protocol_class_descriptor); if (!property.is_null()) { if (!nmos::fields::nc::is_sequence(property)) @@ -382,7 +382,7 @@ namespace nmos // NcBlock methods implementation // Gets descriptors of members of the block - web::json::value get_member_descriptors(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) + web::json::value get_member_descriptors(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_descriptor_handler, get_control_protocol_datatype_descriptor_handler, control_protocol_property_changed_handler, slog::base_gate& gate) { // note, model mutex is already locked by the outer function, so access to control_protocol_resources is OK... @@ -399,7 +399,7 @@ namespace nmos } // Finds member(s) by path - web::json::value find_members_by_path(nmos::resources& resources, const nmos::resource& resource_, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) + web::json::value find_members_by_path(nmos::resources& resources, const nmos::resource& resource_, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_descriptor_handler, get_control_protocol_datatype_descriptor_handler, control_protocol_property_changed_handler, slog::base_gate& gate) { // note, model mutex is already locked by the outer function, so access to control_protocol_resources is OK... @@ -459,7 +459,7 @@ namespace nmos } // Finds members with given role name or fragment - web::json::value find_members_by_role(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) + web::json::value find_members_by_role(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_descriptor_handler, get_control_protocol_datatype_descriptor_handler, control_protocol_property_changed_handler, slog::base_gate& gate) { // note, model mutex is already locked by the outer function, so access to control_protocol_resources is OK... @@ -485,7 +485,7 @@ namespace nmos } // Finds members with given class id - web::json::value find_members_by_class_id(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) + web::json::value find_members_by_class_id(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_descriptor_handler, get_control_protocol_datatype_descriptor_handler, control_protocol_property_changed_handler, slog::base_gate& gate) { // note, model mutex is already locked by the outer function, so access to control_protocol_resources is OK... @@ -513,7 +513,7 @@ namespace nmos // NcClassManager methods implementation // Get a single class descriptor - web::json::value get_control_class(nmos::resources&, const nmos::resource&, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate) + web::json::value get_control_class(nmos::resources&, const nmos::resource&, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor_handler, control_protocol_property_changed_handler, slog::base_gate& gate) { using web::json::value; @@ -530,16 +530,16 @@ namespace nmos // note, model mutex is already locked by the outer function, so access to control_protocol_resources is OK... - const auto& control_class = get_control_protocol_class(class_id); + const auto& control_class = get_control_protocol_class_descriptor(class_id); if (!control_class.class_id.empty()) { auto& description = control_class.description; auto& name = control_class.name; auto& fixed_role = control_class.fixed_role; - auto properties = control_class.properties; - auto methods = value::array(); - for (const auto& method : control_class.methods) { web::json::push_back(methods, std::get<0>(method)); } - auto events = control_class.events; + auto property_descriptors = control_class.property_descriptors; + auto method_descriptors = value::array(); + for (const auto& method_descriptor : control_class.method_descriptors) { web::json::push_back(method_descriptors, std::get<0>(method_descriptor)); } + auto event_descriptors = control_class.event_descriptors; if (include_inherited) { @@ -548,18 +548,18 @@ namespace nmos while (!inherited_class_id.empty()) { - const auto& inherited_control_class = get_control_protocol_class(inherited_class_id); + const auto& inherited_control_class = get_control_protocol_class_descriptor(inherited_class_id); { - for (const auto& property : inherited_control_class.properties.as_array()) { web::json::push_back(properties, property); } - for (const auto& method : inherited_control_class.methods) { web::json::push_back(methods, std::get<0>(method)); } - for (const auto& event : inherited_control_class.events.as_array()) { web::json::push_back(events, event); } + for (const auto& property_descriptor : inherited_control_class.property_descriptors.as_array()) { web::json::push_back(property_descriptors, property_descriptor); } + for (const auto& method_descriptor : inherited_control_class.method_descriptors) { web::json::push_back(method_descriptors, std::get<0>(method_descriptor)); } + for (const auto& event_descriptor : inherited_control_class.event_descriptors.as_array()) { web::json::push_back(event_descriptors, event_descriptor); } } inherited_class_id.pop_back(); } } const auto descriptor = fixed_role.is_null() - ? details::make_nc_class_descriptor(description, class_id, name, properties, methods, events) - : details::make_nc_class_descriptor(description, class_id, name, fixed_role.as_string(), properties, methods, events); + ? details::make_nc_class_descriptor(description, class_id, name, property_descriptors, method_descriptors, event_descriptors) + : details::make_nc_class_descriptor(description, class_id, name, fixed_role.as_string(), property_descriptors, method_descriptors, event_descriptors); return make_control_protocol_message_response(handle, { is_deprecated ? nmos::nc_method_status::method_deprecated : nc_method_status::ok }, descriptor); } @@ -568,7 +568,7 @@ namespace nmos } // Get a single datatype descriptor - web::json::value get_datatype(nmos::resources&, const nmos::resource&, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler get_control_protocol_datatype, control_protocol_property_changed_handler, slog::base_gate& gate) + web::json::value get_datatype(nmos::resources&, const nmos::resource&, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_descriptor_handler, get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor, control_protocol_property_changed_handler, slog::base_gate& gate) { // note, model mutex is already locked by the outer function, so access to control_protocol_resources is OK... @@ -583,7 +583,7 @@ namespace nmos return make_control_protocol_error_response(handle, { nc_method_status::parameter_error }, U("empty name to do GetDatatype")); } - const auto& datatype = get_control_protocol_datatype(name); + const auto& datatype = get_control_protocol_datatype_descriptor(name); if (datatype.descriptor.size()) { auto descriptor = datatype.descriptor; @@ -600,7 +600,7 @@ namespace nmos const auto& parent_type = descriptor_.at(nmos::fields::nc::parent_type); if (!parent_type.is_null()) { - const auto& parent_datatype = get_control_protocol_datatype(parent_type.as_string()); + const auto& parent_datatype = get_control_protocol_datatype_descriptor(parent_type.as_string()); if (parent_datatype.descriptor.size()) { descriptor_ = parent_datatype.descriptor; diff --git a/Development/nmos/control_protocol_methods.h b/Development/nmos/control_protocol_methods.h index 7d74c847a..fe44d77c7 100644 --- a/Development/nmos/control_protocol_methods.h +++ b/Development/nmos/control_protocol_methods.h @@ -13,35 +13,35 @@ namespace nmos { // NcObject methods implementation // Get property value - web::json::value get(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); + web::json::value get(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor_handler, control_protocol_property_changed_handler, slog::base_gate& gate); // Set property value - web::json::value set(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler property_changed, slog::base_gate& gate); + web::json::value set(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor_handler, control_protocol_property_changed_handler property_changed, slog::base_gate& gate); // Get sequence item - web::json::value get_sequence_item(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); + web::json::value get_sequence_item(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor_handler, control_protocol_property_changed_handler, slog::base_gate& gate); // Set sequence item - web::json::value set_sequence_item(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler property_changed, slog::base_gate& gate); + web::json::value set_sequence_item(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor_handler, control_protocol_property_changed_handler property_changed, slog::base_gate& gate); // Add item to sequence - web::json::value add_sequence_item(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler property_changed, slog::base_gate& gate); + web::json::value add_sequence_item(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor_handler, control_protocol_property_changed_handler property_changed, slog::base_gate& gate); // Delete sequence item - web::json::value remove_sequence_item(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); + web::json::value remove_sequence_item(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor_handler, control_protocol_property_changed_handler, slog::base_gate& gate); // Get sequence length - web::json::value get_sequence_length(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); + web::json::value get_sequence_length(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor_handler, control_protocol_property_changed_handler, slog::base_gate& gate); // NcBlock methods implementation // Get descriptors of members of the block - web::json::value get_member_descriptors(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); + web::json::value get_member_descriptors(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_descriptor_handler, get_control_protocol_datatype_descriptor_handler, control_protocol_property_changed_handler, slog::base_gate& gate); // Finds member(s) by path - web::json::value find_members_by_path(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); + web::json::value find_members_by_path(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_descriptor_handler, get_control_protocol_datatype_descriptor_handler, control_protocol_property_changed_handler, slog::base_gate& gate); // Finds members with given role name or fragment - web::json::value find_members_by_role(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); + web::json::value find_members_by_role(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_descriptor_handler, get_control_protocol_datatype_descriptor_handler, control_protocol_property_changed_handler, slog::base_gate& gate); // Finds members with given class id - web::json::value find_members_by_class_id(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); + web::json::value find_members_by_class_id(nmos::resources& resources, const nmos::resource& resource, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_descriptor_handler, get_control_protocol_datatype_descriptor_handler, control_protocol_property_changed_handler, slog::base_gate& gate); // NcClassManager methods implementation // Get a single class descriptor - web::json::value get_control_class(nmos::resources&, const nmos::resource&, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler get_control_protocol_class, get_control_protocol_datatype_handler, control_protocol_property_changed_handler, slog::base_gate& gate); + web::json::value get_control_class(nmos::resources&, const nmos::resource&, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor_handler, control_protocol_property_changed_handler, slog::base_gate& gate); // Get a single datatype descriptor - web::json::value get_datatype(nmos::resources&, const nmos::resource&, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_handler, get_control_protocol_datatype_handler get_control_protocol_datatype, control_protocol_property_changed_handler, slog::base_gate& gate); + web::json::value get_datatype(nmos::resources&, const nmos::resource&, int32_t handle, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_descriptor_handler, get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype, control_protocol_property_changed_handler, slog::base_gate& gate); } #endif diff --git a/Development/nmos/control_protocol_resource.cpp b/Development/nmos/control_protocol_resource.cpp index 29b6b4344..890e13631 100644 --- a/Development/nmos/control_protocol_resource.cpp +++ b/Development/nmos/control_protocol_resource.cpp @@ -793,25 +793,25 @@ namespace nmos // add control classes data[nmos::fields::nc::control_classes] = value::array(); auto& control_classes = data[nmos::fields::nc::control_classes]; - for (const auto& control_class : control_protocol_state.control_classes) + for (const auto& control_class : control_protocol_state.control_class_descriptors) { auto& ctl_class = control_class.second; - auto methods = value::array(); - for (const auto& method : ctl_class.methods) { web::json::push_back(methods, std::get<0>(method)); } + auto method_descriptors = value::array(); + for (const auto& method_descriptor : ctl_class.method_descriptors) { web::json::push_back(method_descriptors, std::get<0>(method_descriptor)); } const auto class_description = ctl_class.fixed_role.is_null() - ? make_nc_class_descriptor(ctl_class.description, ctl_class.class_id, ctl_class.name, ctl_class.properties, methods, ctl_class.events) - : make_nc_class_descriptor(ctl_class.description, ctl_class.class_id, ctl_class.name, ctl_class.fixed_role.as_string(), ctl_class.properties, methods, ctl_class.events); + ? make_nc_class_descriptor(ctl_class.description, ctl_class.class_id, ctl_class.name, ctl_class.property_descriptors, method_descriptors, ctl_class.event_descriptors) + : make_nc_class_descriptor(ctl_class.description, ctl_class.class_id, ctl_class.name, ctl_class.fixed_role.as_string(), ctl_class.property_descriptors, method_descriptors, ctl_class.event_descriptors); web::json::push_back(control_classes, class_description); } // add datatypes data[nmos::fields::nc::datatypes] = value::array(); auto& datatypes = data[nmos::fields::nc::datatypes]; - for (const auto& datatype : control_protocol_state.datatypes) + for (const auto& datatype_descriptor : control_protocol_state.datatype_descriptors) { - web::json::push_back(datatypes, datatype.second.descriptor); + web::json::push_back(datatypes, datatype_descriptor.second.descriptor); } return data; diff --git a/Development/nmos/control_protocol_state.cpp b/Development/nmos/control_protocol_state.cpp index 956ef946a..b611c2ed1 100644 --- a/Development/nmos/control_protocol_state.cpp +++ b/Development/nmos/control_protocol_state.cpp @@ -9,12 +9,12 @@ namespace nmos { namespace details { - // create control class + // create control class descriptor // where // properties: vector of NcPropertyDescriptor where NcPropertyDescriptor can be constructed using make_control_class_property // methods: vector of NcMethodDescriptor vs assoicated method handler where NcMethodDescriptor can be constructed using make_nc_method_descriptor // events: vector of NcEventDescriptor where NcEventDescriptor can be constructed using make_nc_event_descriptor - control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const web::json::value& fixed_role, const std::vector& properties_, const std::vector& methods_, const std::vector& events_) + control_class_descriptor make_control_class_descriptor(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const web::json::value& fixed_role, const std::vector& properties_, const std::vector& methods_, const std::vector& events_) { using web::json::value; @@ -26,44 +26,44 @@ namespace nmos return { description, class_id, name, fixed_role, properties, methods_, events }; } } - // create control class with fixed role + // create control class descriptor with fixed role // where // properties: vector of NcPropertyDescriptor where NcPropertyDescriptor can be constructed using make_control_class_property // methods: vector of NcMethodDescriptor where NcMethodDescriptor can be constructed using make_nc_method_descriptor and the assoicated method handler // events: vector of NcEventDescriptor where NcEventDescriptor can be constructed using make_nc_event_descriptor - control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const utility::string_t& fixed_role, const std::vector& properties, const std::vector& methods, const std::vector& events) + control_class_descriptor make_control_class_descriptor(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const utility::string_t& fixed_role, const std::vector& properties, const std::vector& methods, const std::vector& events) { using web::json::value; - return details::make_control_class(description, class_id, name, value::string(fixed_role), properties, methods, events); + return details::make_control_class_descriptor(description, class_id, name, value::string(fixed_role), properties, methods, events); } - // create control class without fixed role + // create control class descriptor without fixed role // where // properties: vector of NcPropertyDescriptor where NcPropertyDescriptor can be constructed using make_control_class_property // methods: vector of NcMethodDescriptor where NcMethodDescriptor can be constructed using make_nc_method_descriptor and the assoicated method handler // events: vector of NcEventDescriptor where NcEventDescriptor can be constructed using make_nc_event_descriptor - control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const std::vector& properties, const std::vector& methods, const std::vector& events) + control_class_descriptor make_control_class_descriptor(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const std::vector& properties, const std::vector& methods, const std::vector& events) { using web::json::value; - return details::make_control_class(description, class_id, name, value::null(), properties, methods, events); + return details::make_control_class_descriptor(description, class_id, name, value::null(), properties, methods, events); } - // create control class property - web::json::value make_control_class_property(const utility::string_t& description, const nc_property_id& id, const nc_name& name, const utility::string_t& type_name, bool is_read_only, bool is_nullable, bool is_sequence, bool is_deprecated, const web::json::value& constraints) + // create control class property descriptor + web::json::value make_control_class_property_descriptor(const utility::string_t& description, const nc_property_id& id, const nc_name& name, const utility::string_t& type_name, bool is_read_only, bool is_nullable, bool is_sequence, bool is_deprecated, const web::json::value& constraints) { return nmos::details::make_nc_property_descriptor(description, id, name, type_name, is_read_only, is_nullable, is_sequence, is_deprecated, constraints); } - // create control class method parameter - web::json::value make_control_class_method_parameter(const utility::string_t& description, const nc_name& name, const utility::string_t& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints) + // create control class method parameter descriptor + web::json::value make_control_class_method_parameter_descriptor(const utility::string_t& description, const nc_name& name, const utility::string_t& type_name, bool is_nullable, bool is_sequence, const web::json::value& constraints) { return nmos::details::make_nc_parameter_descriptor(description, name, type_name, is_nullable, is_sequence, constraints); } namespace details { - web::json::value make_control_class_method(const utility::string_t& description, const nc_method_id& id, const nc_name& name, const utility::string_t& result_datatype, const std::vector& parameters_, bool is_deprecated) + web::json::value make_control_class_method_descriptor(const utility::string_t& description, const nc_method_id& id, const nc_name& name, const utility::string_t& result_datatype, const std::vector& parameters_, bool is_deprecated) { using web::json::value; @@ -73,19 +73,19 @@ namespace nmos return nmos::details::make_nc_method_descriptor(description, id, name, result_datatype, parameters, is_deprecated); } } - // create standard control class method - method make_control_class_method(const utility::string_t& description, const nc_method_id& id, const nc_name& name, const utility::string_t& result_datatype, const std::vector& parameters, bool is_deprecated, standard_method_handler method_handler) + // create standard control class method descriptor + method make_control_class_method_descriptor(const utility::string_t& description, const nc_method_id& id, const nc_name& name, const utility::string_t& result_datatype, const std::vector& parameters, bool is_deprecated, standard_method_handler method_handler) { - return make_control_class_standard_method(details::make_control_class_method(description, id, name, result_datatype, parameters, is_deprecated), method_handler); + return make_control_class_standard_method(details::make_control_class_method_descriptor(description, id, name, result_datatype, parameters, is_deprecated), method_handler); } - // create non-standard control class method - method make_control_class_method(const utility::string_t& description, const nc_method_id& id, const nc_name& name, const utility::string_t& result_datatype, const std::vector& parameters, bool is_deprecated, non_standard_method_handler method_handler) + // create non-standard control class method descriptor + method make_control_class_method_descriptor(const utility::string_t& description, const nc_method_id& id, const nc_name& name, const utility::string_t& result_datatype, const std::vector& parameters, bool is_deprecated, non_standard_method_handler method_handler) { - return make_control_class_non_standard_method(details::make_control_class_method(description, id, name, result_datatype, parameters, is_deprecated), method_handler); + return make_control_class_non_standard_method(details::make_control_class_method_descriptor(description, id, name, result_datatype, parameters, is_deprecated), method_handler); } - // create control class event - web::json::value make_control_class_event(const utility::string_t& description, const nc_event_id& id, const nc_name& name, const utility::string_t& event_datatype, bool is_deprecated) + // create control class event descriptor + web::json::value make_control_class_event_descriptor(const utility::string_t& description, const nc_event_id& id, const nc_name& name, const utility::string_t& event_datatype, bool is_deprecated) { return nmos::details::make_nc_event_descriptor(description, id, name, event_datatype, is_deprecated); } @@ -119,13 +119,13 @@ namespace nmos }; // setup the standard control classes - control_classes = + control_class_descriptors = { // Control class models // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/classes/ // NcObject - { nc_object_class_id, make_control_class(U("NcObject class descriptor"), nc_object_class_id, U("NcObject"), + { nc_object_class_id, make_control_class_descriptor(U("NcObject class descriptor"), nc_object_class_id, U("NcObject"), // NcObject properties to_vector(make_nc_object_properties()), // NcObject methods @@ -143,7 +143,7 @@ namespace nmos // NcObject events to_vector(make_nc_object_events())) }, // NcBlock - { nc_block_class_id, make_control_class(U("NcBlock class descriptor"), nc_block_class_id, U("NcBlock"), + { nc_block_class_id, make_control_class_descriptor(U("NcBlock class descriptor"), nc_block_class_id, U("NcBlock"), // NcBlock properties to_vector(make_nc_block_properties()), // NcBlock methods @@ -158,7 +158,7 @@ namespace nmos // NcBlock events to_vector(make_nc_block_events())) }, // NcWorker - { nc_worker_class_id, make_control_class(U("NcWorker class descriptor"), nc_worker_class_id, U("NcWorker"), + { nc_worker_class_id, make_control_class_descriptor(U("NcWorker class descriptor"), nc_worker_class_id, U("NcWorker"), // NcWorker properties to_vector(make_nc_worker_properties()), // NcWorker methods @@ -166,7 +166,7 @@ namespace nmos // NcWorker events to_vector(make_nc_worker_events())) }, // NcManager - { nc_manager_class_id, make_control_class(U("NcManager class descriptor"), nc_manager_class_id, U("NcManager"), + { nc_manager_class_id, make_control_class_descriptor(U("NcManager class descriptor"), nc_manager_class_id, U("NcManager"), // NcManager properties to_vector(make_nc_manager_properties()), // NcManager methods @@ -174,7 +174,7 @@ namespace nmos // NcManager events to_vector(make_nc_manager_events())) }, // NcDeviceManager - { nc_device_manager_class_id, make_control_class(U("NcDeviceManager class descriptor"), nc_device_manager_class_id, U("NcDeviceManager"), U("DeviceManager"), + { nc_device_manager_class_id, make_control_class_descriptor(U("NcDeviceManager class descriptor"), nc_device_manager_class_id, U("NcDeviceManager"), U("DeviceManager"), // NcDeviceManager properties to_vector(make_nc_device_manager_properties()), // NcDeviceManager methods @@ -182,7 +182,7 @@ namespace nmos // NcDeviceManager events to_vector(make_nc_device_manager_events())) }, // NcClassManager - { nc_class_manager_class_id, make_control_class(U("NcClassManager class descriptor"), nc_class_manager_class_id, U("NcClassManager"), U("ClassManager"), + { nc_class_manager_class_id, make_control_class_descriptor(U("NcClassManager class descriptor"), nc_class_manager_class_id, U("NcClassManager"), U("ClassManager"), // NcClassManager properties to_vector(make_nc_class_manager_properties()), // NcClassManager methods @@ -197,7 +197,7 @@ namespace nmos // Identification feature set // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/identification/#control-classes // NcIdentBeacon - { nc_ident_beacon_class_id, make_control_class(U("NcIdentBeacon class descriptor"), nc_ident_beacon_class_id, U("NcIdentBeacon"), + { nc_ident_beacon_class_id, make_control_class_descriptor(U("NcIdentBeacon class descriptor"), nc_ident_beacon_class_id, U("NcIdentBeacon"), // NcIdentBeacon properties to_vector(make_nc_ident_beacon_properties()), // NcIdentBeacon methods @@ -207,7 +207,7 @@ namespace nmos // Monitoring feature set // See https://specs.amwa.tv/nmos-control-feature-sets/branches/main/monitoring/#control-classes // NcReceiverMonitor - { nc_receiver_monitor_class_id, make_control_class(U("NcReceiverMonitor class descriptor"), nc_receiver_monitor_class_id, U("NcReceiverMonitor"), + { nc_receiver_monitor_class_id, make_control_class_descriptor(U("NcReceiverMonitor class descriptor"), nc_receiver_monitor_class_id, U("NcReceiverMonitor"), // NcReceiverMonitor properties to_vector(make_nc_receiver_monitor_properties()), // NcReceiverMonitor methods @@ -215,7 +215,7 @@ namespace nmos // NcReceiverMonitor events to_vector(make_nc_receiver_monitor_events())) }, // NcReceiverMonitorProtected - { nc_receiver_monitor_protected_class_id, make_control_class(U("NcReceiverMonitorProtected class descriptor"), nc_receiver_monitor_protected_class_id, U("NcReceiverMonitorProtected"), + { nc_receiver_monitor_protected_class_id, make_control_class_descriptor(U("NcReceiverMonitorProtected class descriptor"), nc_receiver_monitor_protected_class_id, U("NcReceiverMonitorProtected"), // NcReceiverMonitorProtected properties to_vector(make_nc_receiver_monitor_protected_properties()), // NcReceiverMonitorProtected methods @@ -225,7 +225,7 @@ namespace nmos }; // setup the standard datatypes - datatypes = + datatype_descriptors = { // Datatype models // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/models/datatypes/ @@ -304,55 +304,55 @@ namespace nmos }; } - // insert control class, false if class already inserted - bool control_protocol_state::insert(const experimental::control_class& control_class) + // insert control class descriptor, false if class descriptor already inserted + bool control_protocol_state::insert(const experimental::control_class_descriptor& control_class_descriptor) { auto lock = write_lock(); - if (control_classes.end() == control_classes.find(control_class.class_id)) + if (control_class_descriptors.end() == control_class_descriptors.find(control_class_descriptor.class_id)) { - control_classes[control_class.class_id] = control_class; + control_class_descriptors[control_class_descriptor.class_id] = control_class_descriptor; return true; } return false; } - // erase control class of the given class id, false if the required class not found + // erase control class descriptor of the given class id, false if the required class descriptor not found bool control_protocol_state::erase(nc_class_id class_id) { auto lock = write_lock(); - if (control_classes.end() != control_classes.find(class_id)) + if (control_class_descriptors.end() != control_class_descriptors.find(class_id)) { - control_classes.erase(class_id); + control_class_descriptors.erase(class_id); return true; } return false; } - // insert datatype, false if datatype already inserted - bool control_protocol_state::insert(const experimental::datatype& datatype) + // insert datatype descriptor, false if datatype descriptor already inserted + bool control_protocol_state::insert(const experimental::datatype_descriptor& datatype_descriptor) { - const auto& name = nmos::fields::nc::name(datatype.descriptor); + const auto& name = nmos::fields::nc::name(datatype_descriptor.descriptor); auto lock = write_lock(); - if (datatypes.end() == datatypes.find(name)) + if (datatype_descriptors.end() == datatype_descriptors.find(name)) { - datatypes[name] = datatype; + datatype_descriptors[name] = datatype_descriptor; return true; } return false; } - // erase datatype of the given datatype name, false if the required datatype not found - bool control_protocol_state::erase(const utility::string_t& name) + // erase datatype descriptor of the given datatype name, false if the required datatype descriptor not found + bool control_protocol_state::erase(const utility::string_t& datatype_name) { auto lock = write_lock(); - if (datatypes.end() != datatypes.find(name)) + if (datatype_descriptors.end() != datatype_descriptors.find(datatype_name)) { - datatypes.erase(name); + datatype_descriptors.erase(datatype_name); return true; } return false; diff --git a/Development/nmos/control_protocol_state.h b/Development/nmos/control_protocol_state.h index 5887b6035..121a75ae7 100644 --- a/Development/nmos/control_protocol_state.h +++ b/Development/nmos/control_protocol_state.h @@ -13,85 +13,85 @@ namespace nmos { namespace experimental { - struct control_class // NcClassDescriptor + struct control_class_descriptor // NcClassDescriptor { utility::string_t description; nmos::nc_class_id class_id; nmos::nc_name name; web::json::value fixed_role; - web::json::value properties = web::json::value::array(); // NcPropertyDescriptor array - std::vector methods; // NcMethodDescriptor method handler array - web::json::value events = web::json::value::array(); // NcEventDescriptor array + web::json::value property_descriptors = web::json::value::array(); // NcPropertyDescriptor array + std::vector method_descriptors; // NcMethodDescriptor method handler array + web::json::value event_descriptors = web::json::value::array(); // NcEventDescriptor array - control_class() + control_class_descriptor() : class_id({ 0 }) {} - control_class(utility::string_t description, nmos::nc_class_id class_id, nmos::nc_name name, web::json::value fixed_role, web::json::value properties, std::vector methods, web::json::value events) + control_class_descriptor(utility::string_t description, nmos::nc_class_id class_id, nmos::nc_name name, web::json::value fixed_role, web::json::value property_descriptors, std::vector method_descriptors, web::json::value event_descriptors) : description(std::move(description)) , class_id(std::move(class_id)) , name(std::move(name)) , fixed_role(std::move(fixed_role)) - , properties(std::move(properties)) - , methods(std::move(methods)) - , events(std::move(events)) + , property_descriptors(std::move(property_descriptors)) + , method_descriptors(std::move(method_descriptors)) + , event_descriptors(std::move(event_descriptors)) {} }; - struct datatype // NcDatatypeDescriptorEnum/NcDatatypeDescriptorPrimitive/NcDatatypeDescriptorStruct/NcDatatypeDescriptorTypeDef + struct datatype_descriptor // NcDatatypeDescriptorEnum/NcDatatypeDescriptorPrimitive/NcDatatypeDescriptorStruct/NcDatatypeDescriptorTypeDef { web::json::value descriptor; }; - typedef std::map control_classes; - typedef std::map datatypes; + typedef std::map control_class_descriptors; + typedef std::map datatype_descriptors; struct control_protocol_state { // mutex to be used to protect the members from simultaneous access by multiple threads mutable nmos::mutex mutex; - experimental::control_classes control_classes; - experimental::datatypes datatypes; + experimental::control_class_descriptors control_class_descriptors; + experimental::datatype_descriptors datatype_descriptors; nmos::read_lock read_lock() const { return nmos::read_lock{ mutex }; } nmos::write_lock write_lock() const { return nmos::write_lock{ mutex }; } control_protocol_state(); - // insert control class, false if class already presented - bool insert(const experimental::control_class& control_class); + // insert control class descriptor, false if class descriptor already inserted + bool insert(const experimental::control_class_descriptor& control_class_descriptor); // erase control class of the given class id, false if the required class not found bool erase(nc_class_id class_id); - // insert datatype, false if datatype already presented - bool insert(const experimental::datatype& datatype); - // erase datatype of the given datatype name, false if the required datatype not found + // insert datatype descriptor, false if datatype descriptor already inserted + bool insert(const experimental::datatype_descriptor& datatype_descriptor); + // erase datatype descriptor of the given datatype name, false if the required datatype descriptor not found bool erase(const utility::string_t& datatype_name); }; // helper functions to create non-standard control class // - // create control class with fixed role - control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const utility::string_t& fixed_role, const std::vector& properties = {}, const std::vector& methods = {}, const std::vector& events = {}); - // create control class with no fixed role - control_class make_control_class(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const std::vector& properties = {}, const std::vector& methods = {}, const std::vector& events = {}); + // create control class descriptor with fixed role + control_class_descriptor make_control_class_descriptor(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const utility::string_t& fixed_role, const std::vector& properties = {}, const std::vector& methods = {}, const std::vector& events = {}); + // create control class descriptor with no fixed role + control_class_descriptor make_control_class_descriptor(const utility::string_t& description, const nc_class_id& class_id, const nc_name& name, const std::vector& properties = {}, const std::vector& methods = {}, const std::vector& events = {}); - // create control class property - web::json::value make_control_class_property(const utility::string_t& description, const nc_property_id& id, const nc_name& name, const utility::string_t& type_name, + // create control class property descriptor + web::json::value make_control_class_property_descriptor(const utility::string_t& description, const nc_property_id& id, const nc_name& name, const utility::string_t& type_name, bool is_read_only = false, bool is_nullable = false, bool is_sequence = false, bool is_deprecated = false, const web::json::value& constraints = web::json::value::null()); - // create control class method parameter - web::json::value make_control_class_method_parameter(const utility::string_t& description, const nc_name& name, const utility::string_t& type_name, + // create control class method parameter descriptor + web::json::value make_control_class_method_parameter_descriptor(const utility::string_t& description, const nc_name& name, const utility::string_t& type_name, bool is_nullable = false, bool is_sequence = false, const web::json::value& constraints = web::json::value::null()); - // create control class method - method make_control_class_method(const utility::string_t& description, const nc_method_id& id, const nc_name& name, const utility::string_t& result_datatype, + // create control class method descriptor + method make_control_class_method_descriptor(const utility::string_t& description, const nc_method_id& id, const nc_name& name, const utility::string_t& result_datatype, const std::vector& parameters, bool is_deprecated, non_standard_method_handler method_handler); - // create control class event - web::json::value make_control_class_event(const utility::string_t& description, const nc_event_id& id, const nc_name& name, const utility::string_t& event_datatype, + // create control class event descriptor + web::json::value make_control_class_event_descriptor(const utility::string_t& description, const nc_event_id& id, const nc_name& name, const utility::string_t& event_datatype, bool is_deprecated = false); } } diff --git a/Development/nmos/control_protocol_utils.cpp b/Development/nmos/control_protocol_utils.cpp index 984677a6c..d22718bef 100644 --- a/Development/nmos/control_protocol_utils.cpp +++ b/Development/nmos/control_protocol_utils.cpp @@ -35,10 +35,9 @@ namespace nmos { auto& runtime_prop_constraints = runtime_property_constraints.as_array(); auto found_constraints = std::find_if(runtime_prop_constraints.begin(), runtime_prop_constraints.end(), [&property_id](const web::json::value& constraints) - { - //return nmos::fields::nc::id(property) == nmos::fields::nc::property_id(constraints); - return property_id == parse_nc_property_id(nmos::fields::nc::property_id(constraints)); - }); + { + return property_id == parse_nc_property_id(nmos::fields::nc::property_id(constraints)); + }); if (runtime_prop_constraints.end() != found_constraints) { @@ -49,24 +48,24 @@ namespace nmos } // get the datatype descriptor of a specific type_name - web::json::value get_datatype_descriptor(const web::json::value& type_name, get_control_protocol_datatype_handler get_control_protocol_datatype) + web::json::value get_datatype_descriptor(const web::json::value& type_name, get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor) { using web::json::value; if (!type_name.is_null()) { - return get_control_protocol_datatype(type_name.as_string()).descriptor; + return get_control_protocol_datatype_descriptor(type_name.as_string()).descriptor; } return value::null(); } // get the datatype property constraints of a specific type_name - web::json::value get_datatype_constraints(const web::json::value& type_name, get_control_protocol_datatype_handler get_control_protocol_datatype) + web::json::value get_datatype_constraints(const web::json::value& type_name, get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor) { using web::json::value; // NcDatatypeDescriptor - const auto& datatype_descriptor = get_datatype_descriptor(type_name, get_control_protocol_datatype); + const auto& datatype_descriptor = get_datatype_descriptor(type_name, get_control_protocol_datatype_descriptor); if (!datatype_descriptor.is_null()) { return nmos::fields::nc::constraints(datatype_descriptor); @@ -242,7 +241,7 @@ namespace nmos { // do parent typename constraints validation const auto& type_name = params.datatype_descriptor.at(nmos::fields::nc::parent_type); // parent type_name - datatype_constraints_validation(data, { details::get_datatype_descriptor(type_name, params.get_control_protocol_datatype), params.get_control_protocol_datatype }); + datatype_constraints_validation(data, { details::get_datatype_descriptor(type_name, params.get_control_protocol_datatype_descriptor), params.get_control_protocol_datatype_descriptor }); } else { @@ -299,13 +298,13 @@ namespace nmos for (const auto& val : value.as_array()) { // do typename constraints validation - datatype_constraints_validation(val, { details::get_datatype_descriptor(field_type_name, params.get_control_protocol_datatype), params.get_control_protocol_datatype }); + datatype_constraints_validation(val, { details::get_datatype_descriptor(field_type_name, params.get_control_protocol_datatype_descriptor), params.get_control_protocol_datatype_descriptor }); } } else { // do typename constraints validation - datatype_constraints_validation(value, { details::get_datatype_descriptor(field_type_name, params.get_control_protocol_datatype), params.get_control_protocol_datatype }); + datatype_constraints_validation(value, { details::get_datatype_descriptor(field_type_name, params.get_control_protocol_datatype_descriptor), params.get_control_protocol_datatype_descriptor }); } } } @@ -320,7 +319,7 @@ namespace nmos return; } - // unsupport datatype_type, no validation is required + // unsupported datatype_type, no validation is required } // multiple levels of constraints validation, may throw nmos::control_protocol_exception @@ -390,8 +389,8 @@ namespace nmos return make_nc_class_id(prefix, 0, suffix); } - // find control class property (NcPropertyDescriptor) - web::json::value find_property(const nc_property_id& property_id, const nc_class_id& class_id_, get_control_protocol_class_handler get_control_protocol_class) + // find control class property descriptor (NcPropertyDescriptor) + web::json::value find_property_descriptor(const nc_property_id& property_id, const nc_class_id& class_id_, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor) { using web::json::value; @@ -399,13 +398,13 @@ namespace nmos while (!class_id.empty()) { - const auto& control_class = get_control_protocol_class(class_id); - auto& properties = control_class.properties.as_array(); - auto found = std::find_if(properties.begin(), properties.end(), [&property_id](const web::json::value& property) + const auto& control_class = get_control_protocol_class_descriptor(class_id); + auto& property_descriptors = control_class.property_descriptors.as_array(); + auto found = std::find_if(property_descriptors.begin(), property_descriptors.end(), [&property_id](const web::json::value& property_descriptor) { - return (property_id == nmos::details::parse_nc_property_id(nmos::fields::nc::id(property))); + return (property_id == nmos::details::parse_nc_property_id(nmos::fields::nc::id(property_descriptor))); }); - if (properties.end() != found) { return *found; } + if (property_descriptors.end() != found) { return *found; } class_id.pop_back(); } @@ -634,7 +633,7 @@ namespace nmos } // method parameters constraints validation - void method_parameters_contraints_validation(const web::json::value& arguments, const web::json::value& nc_method_descriptor, get_control_protocol_datatype_handler get_control_protocol_datatype) + void method_parameters_contraints_validation(const web::json::value& arguments, const web::json::value& nc_method_descriptor, get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor) { for (const auto& param : nmos::fields::nc::parameters(nc_method_descriptor)) { @@ -646,7 +645,7 @@ namespace nmos // missing argument parameter throw control_protocol_exception("missing argument parameter " + utility::us2s(name)); } - details::method_parameter_constraints_validation(arguments.at(name), constraints, { nmos::details::get_datatype_descriptor(type_name, get_control_protocol_datatype), get_control_protocol_datatype }); + details::method_parameter_constraints_validation(arguments.at(name), constraints, { nmos::details::get_datatype_descriptor(type_name, get_control_protocol_datatype_descriptor), get_control_protocol_datatype_descriptor }); } } } diff --git a/Development/nmos/control_protocol_utils.h b/Development/nmos/control_protocol_utils.h index 9402e19e9..6d7060851 100644 --- a/Development/nmos/control_protocol_utils.h +++ b/Development/nmos/control_protocol_utils.h @@ -19,15 +19,15 @@ namespace nmos web::json::value get_runtime_property_constraints(const nc_property_id& property_id, const web::json::value& runtime_property_constraints_list); // get the datatype descriptor of a specific type_name - web::json::value get_datatype_descriptor(const web::json::value& type_name, get_control_protocol_datatype_handler get_control_protocol_datatype); + web::json::value get_datatype_descriptor(const web::json::value& type_name, get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype); // get the datatype property constraints of a given type_name - web::json::value get_datatype_constraints(const web::json::value& type_name, get_control_protocol_datatype_handler get_control_protocol_datatype); + web::json::value get_datatype_constraints(const web::json::value& type_name, get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype); struct datatype_constraints_validation_parameters { web::json::value datatype_descriptor; - get_control_protocol_datatype_handler get_control_protocol_datatype; + get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor; }; // multiple levels of constraints validation, may throw nmos::control_protocol_exception // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Constraints.html @@ -56,8 +56,8 @@ namespace nmos nc_class_id make_nc_class_id(const nc_class_id& prefix, int32_t authority_key, const std::vector& suffix); nc_class_id make_nc_class_id(const nc_class_id& prefix, const std::vector& suffix); // using default authority_key 0 - // find control class property (NcPropertyDescriptor) - web::json::value find_property(const nc_property_id& property_id, const nc_class_id& class_id, get_control_protocol_class_handler get_control_protocol_class); + // find control class property descriptor (NcPropertyDescriptor) + web::json::value find_property_descriptor(const nc_property_id& property_id, const nc_class_id& class_id, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor); // get block memeber descriptors void get_member_descriptors(const resources& resources, const resource& resource, bool recurse, web::json::array& descriptors); @@ -78,7 +78,7 @@ namespace nmos resources::const_iterator find_control_protocol_resource(resources& resources, type type, const id& id); // method parameters constraints validation, may throw nmos::control_protocol_exception - void method_parameters_contraints_validation(const web::json::value& arguments, const web::json::value& nc_method_descriptor, get_control_protocol_datatype_handler get_control_protocol_datatype); + void method_parameters_contraints_validation(const web::json::value& arguments, const web::json::value& nc_method_descriptor, get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor); } #endif diff --git a/Development/nmos/control_protocol_ws_api.cpp b/Development/nmos/control_protocol_ws_api.cpp index dc7ae2006..30f15ab69 100644 --- a/Development/nmos/control_protocol_ws_api.cpp +++ b/Development/nmos/control_protocol_ws_api.cpp @@ -188,12 +188,12 @@ namespace nmos }; } - web::websockets::experimental::listener::message_handler make_control_protocol_ws_message_handler(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::get_control_protocol_method_handler get_control_protocol_method, nmos::control_protocol_property_changed_handler property_changed, slog::base_gate& gate_) + web::websockets::experimental::listener::message_handler make_control_protocol_ws_message_handler(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, nmos::get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor, nmos::get_control_protocol_method_descriptor_handler get_control_protocol_method_descriptor, nmos::control_protocol_property_changed_handler property_changed, slog::base_gate& gate_) { using web::json::value; using web::json::value_of; - return [&model, &websockets, get_control_protocol_class, get_control_protocol_datatype, get_control_protocol_method, property_changed, &gate_](const web::uri& connection_uri, const web::websockets::experimental::listener::connection_id& connection_id, const web::websockets::websocket_incoming_message& msg_) + return [&model, &websockets, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_control_protocol_method_descriptor, property_changed, &gate_](const web::uri& connection_uri, const web::websockets::experimental::listener::connection_id& connection_id, const web::websockets::websocket_incoming_message& msg_) { nmos::ws_api_gate gate(gate_, connection_uri); @@ -260,7 +260,7 @@ namespace nmos // find the relevent method handler to execute // method tuple definition described in control_protocol_handlers.h - auto method = get_control_protocol_method(class_id, method_id); + auto method = get_control_protocol_method_descriptor(class_id, method_id); auto& nc_method_descriptor = std::get<0>(method); auto& standard_method = std::get<1>(method); auto& non_standard_method = std::get<2>(method); @@ -269,12 +269,12 @@ namespace nmos try { // do method arguments constraints validation - method_parameters_contraints_validation(arguments, nc_method_descriptor, get_control_protocol_datatype); + method_parameters_contraints_validation(arguments, nc_method_descriptor, get_control_protocol_datatype_descriptor); // execute the relevant method handler, then accumulating up their response to reponses if (standard_method) { - response = standard_method(resources, *resource, handle, arguments, nmos::fields::nc::is_deprecated(nc_method_descriptor), get_control_protocol_class, get_control_protocol_datatype, property_changed, gate); + response = standard_method(resources, *resource, handle, arguments, nmos::fields::nc::is_deprecated(nc_method_descriptor), get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, property_changed, gate); } else // non_standard_method { diff --git a/Development/nmos/control_protocol_ws_api.h b/Development/nmos/control_protocol_ws_api.h index 1bf3c556a..3cfee6d50 100644 --- a/Development/nmos/control_protocol_ws_api.h +++ b/Development/nmos/control_protocol_ws_api.h @@ -17,15 +17,15 @@ namespace nmos web::websockets::experimental::listener::validate_handler make_control_protocol_ws_validate_handler(nmos::node_model& model, nmos::experimental::ws_validate_authorization_handler ws_validate_authorization, slog::base_gate& gate); web::websockets::experimental::listener::open_handler make_control_protocol_ws_open_handler(nmos::node_model& model, nmos::websockets& websockets, slog::base_gate& gate); web::websockets::experimental::listener::close_handler make_control_protocol_ws_close_handler(nmos::node_model& model, nmos::websockets& websockets, slog::base_gate& gate); - web::websockets::experimental::listener::message_handler make_control_protocol_ws_message_handler(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::get_control_protocol_method_handler get_control_protocol_method, nmos::control_protocol_property_changed_handler property_changed, slog::base_gate& gate); + web::websockets::experimental::listener::message_handler make_control_protocol_ws_message_handler(nmos::node_model& model, nmos::websockets& websockets, nmos::get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, nmos::get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor, nmos::get_control_protocol_method_descriptor_handler get_control_protocol_method_descriptor, nmos::control_protocol_property_changed_handler property_changed, slog::base_gate& gate); - inline web::websockets::experimental::listener::websocket_listener_handlers make_control_protocol_ws_api(nmos::node_model& model, nmos::websockets& websockets, nmos::experimental::ws_validate_authorization_handler ws_validate_authorization, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::get_control_protocol_method_handler get_control_protocol_method, nmos::control_protocol_property_changed_handler property_changed, slog::base_gate& gate) + inline web::websockets::experimental::listener::websocket_listener_handlers make_control_protocol_ws_api(nmos::node_model& model, nmos::websockets& websockets, nmos::experimental::ws_validate_authorization_handler ws_validate_authorization, nmos::get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, nmos::get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor, nmos::get_control_protocol_method_descriptor_handler get_control_protocol_method_descriptor, nmos::control_protocol_property_changed_handler property_changed, slog::base_gate& gate) { return{ nmos::make_control_protocol_ws_validate_handler(model, ws_validate_authorization, gate), nmos::make_control_protocol_ws_open_handler(model, websockets, gate), nmos::make_control_protocol_ws_close_handler(model, websockets, gate), - nmos::make_control_protocol_ws_message_handler(model, websockets, get_control_protocol_class, get_control_protocol_datatype, get_control_protocol_method, property_changed, gate) + nmos::make_control_protocol_ws_message_handler(model, websockets, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, get_control_protocol_method_descriptor, property_changed, gate) }; } diff --git a/Development/nmos/node_server.cpp b/Development/nmos/node_server.cpp index 23634dfdc..00258389d 100644 --- a/Development/nmos/node_server.cpp +++ b/Development/nmos/node_server.cpp @@ -85,7 +85,7 @@ namespace nmos { if (control_protocol_ws_port == events_ws_port) throw std::runtime_error("Same port used for events and control protocol websockets are not supported"); auto& control_protocol_ws_api = node_server.ws_handlers[{ {}, control_protocol_ws_port }]; - control_protocol_ws_api.first = nmos::make_control_protocol_ws_api(node_model, control_protocol_ws_api.second, node_implementation.ws_validate_authorization, node_implementation.get_control_protocol_class, node_implementation.get_control_protocol_datatype, node_implementation.get_control_protocol_method, node_implementation.control_protocol_property_changed, gate); + control_protocol_ws_api.first = nmos::make_control_protocol_ws_api(node_model, control_protocol_ws_api.second, node_implementation.ws_validate_authorization, node_implementation.get_control_protocol_class_descriptor, node_implementation.get_control_protocol_datatype_descriptor, node_implementation.get_control_protocol_method_descriptor, node_implementation.control_protocol_property_changed, gate); } // Set up the listeners for each HTTP API port diff --git a/Development/nmos/node_server.h b/Development/nmos/node_server.h index 1a7ecb77c..25a15d4b7 100644 --- a/Development/nmos/node_server.h +++ b/Development/nmos/node_server.h @@ -27,7 +27,7 @@ namespace nmos // underlying implementation into the server instance for the NMOS Node struct node_implementation { - node_implementation(nmos::load_server_certificates_handler load_server_certificates, nmos::load_dh_param_handler load_dh_param, nmos::load_ca_certificates_handler load_ca_certificates, nmos::system_global_handler system_changed, nmos::registration_handler registration_changed, nmos::transport_file_parser parse_transport_file, nmos::details::connection_resource_patch_validator validate_staged, nmos::connection_resource_auto_resolver resolve_auto, nmos::connection_sender_transportfile_setter set_transportfile, nmos::connection_activation_handler connection_activated, nmos::ocsp_response_handler get_ocsp_response, get_authorization_bearer_token_handler get_authorization_bearer_token, validate_authorization_handler validate_authorization, ws_validate_authorization_handler ws_validate_authorization, nmos::load_rsa_private_keys_handler load_rsa_private_keys, load_authorization_clients_handler load_authorization_clients, save_authorization_client_handler save_authorization_client, request_authorization_code_handler request_authorization_code, nmos::get_control_protocol_class_handler get_control_protocol_class, nmos::get_control_protocol_datatype_handler get_control_protocol_datatype, nmos::get_control_protocol_method_handler get_control_protocol_method, nmos::control_protocol_property_changed_handler control_protocol_property_changed) + node_implementation(nmos::load_server_certificates_handler load_server_certificates, nmos::load_dh_param_handler load_dh_param, nmos::load_ca_certificates_handler load_ca_certificates, nmos::system_global_handler system_changed, nmos::registration_handler registration_changed, nmos::transport_file_parser parse_transport_file, nmos::details::connection_resource_patch_validator validate_staged, nmos::connection_resource_auto_resolver resolve_auto, nmos::connection_sender_transportfile_setter set_transportfile, nmos::connection_activation_handler connection_activated, nmos::ocsp_response_handler get_ocsp_response, get_authorization_bearer_token_handler get_authorization_bearer_token, validate_authorization_handler validate_authorization, ws_validate_authorization_handler ws_validate_authorization, nmos::load_rsa_private_keys_handler load_rsa_private_keys, load_authorization_clients_handler load_authorization_clients, save_authorization_client_handler save_authorization_client, request_authorization_code_handler request_authorization_code, nmos::get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, nmos::get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor, nmos::get_control_protocol_method_descriptor_handler get_control_protocol_method_descriptor, nmos::control_protocol_property_changed_handler control_protocol_property_changed) : load_server_certificates(std::move(load_server_certificates)) , load_dh_param(std::move(load_dh_param)) , load_ca_certificates(std::move(load_ca_certificates)) @@ -46,9 +46,9 @@ namespace nmos , load_authorization_clients(std::move(load_authorization_clients)) , save_authorization_client(std::move(save_authorization_client)) , request_authorization_code(std::move(request_authorization_code)) - , get_control_protocol_class(std::move(get_control_protocol_class)) - , get_control_protocol_datatype(std::move(get_control_protocol_datatype)) - , get_control_protocol_method(std::move(get_control_protocol_method)) + , get_control_protocol_class_descriptor(std::move(get_control_protocol_class_descriptor)) + , get_control_protocol_datatype_descriptor(std::move(get_control_protocol_datatype_descriptor)) + , get_control_protocol_method_descriptor(std::move(get_control_protocol_method_descriptor)) , control_protocol_property_changed(std::move(control_protocol_property_changed)) {} @@ -78,9 +78,9 @@ namespace nmos node_implementation& on_load_authorization_clients(load_authorization_clients_handler load_authorization_clients) { this->load_authorization_clients = std::move(load_authorization_clients); return *this; } node_implementation& on_save_authorization_client(save_authorization_client_handler save_authorization_client) { this->save_authorization_client = std::move(save_authorization_client); return *this; } node_implementation& on_request_authorization_code(request_authorization_code_handler request_authorization_code) { this->request_authorization_code = std::move(request_authorization_code); return *this; } - node_implementation& on_get_control_class(nmos::get_control_protocol_class_handler get_control_protocol_class) { this->get_control_protocol_class = std::move(get_control_protocol_class); return *this; } - node_implementation& on_get_control_datatype(nmos::get_control_protocol_datatype_handler get_control_protocol_datatype) { this->get_control_protocol_datatype = std::move(get_control_protocol_datatype); return *this; } - node_implementation& on_get_control_protocol_method(nmos::get_control_protocol_method_handler get_control_protocol_method) { this->get_control_protocol_method = std::move(get_control_protocol_method); return *this; } + node_implementation& on_get_control_class_descriptor(nmos::get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor) { this->get_control_protocol_class_descriptor = std::move(get_control_protocol_class_descriptor); return *this; } + node_implementation& on_get_control_datatype_descriptor(nmos::get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor) { this->get_control_protocol_datatype_descriptor = std::move(get_control_protocol_datatype_descriptor); return *this; } + node_implementation& on_get_control_protocol_method_descriptor(nmos::get_control_protocol_method_descriptor_handler get_control_protocol_method_descriptor) { this->get_control_protocol_method_descriptor = std::move(get_control_protocol_method_descriptor); return *this; } node_implementation& on_control_protocol_property_changed(nmos::control_protocol_property_changed_handler control_protocol_property_changed) { this->control_protocol_property_changed = std::move(control_protocol_property_changed); return *this; } // deprecated, use on_validate_connection_resource_patch @@ -120,9 +120,9 @@ namespace nmos save_authorization_client_handler save_authorization_client; request_authorization_code_handler request_authorization_code; - nmos::get_control_protocol_class_handler get_control_protocol_class; - nmos::get_control_protocol_datatype_handler get_control_protocol_datatype; - nmos::get_control_protocol_method_handler get_control_protocol_method; + nmos::get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor; + nmos::get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor; + nmos::get_control_protocol_method_descriptor_handler get_control_protocol_method_descriptor; nmos::control_protocol_property_changed_handler control_protocol_property_changed; }; diff --git a/Development/nmos/test/control_protocol_test.cpp b/Development/nmos/test/control_protocol_test.cpp index 65816413b..2d4aeba6e 100644 --- a/Development/nmos/test/control_protocol_test.cpp +++ b/Development/nmos/test/control_protocol_test.cpp @@ -677,26 +677,26 @@ BST_TEST_CASE(testFindProperty) const auto invalid_class_id = nmos::nc_class_id({ 1000, 1000 }); nmos::experimental::control_protocol_state control_protocol_state; - auto get_control_protocol_class = nmos::make_get_control_protocol_class_handler(control_protocol_state); + auto get_control_protocol_class_descriptor = nmos::make_get_control_protocol_class_descriptor_handler(control_protocol_state); { // valid - find members property in NcBlock - auto property = nmos::find_property(nc_block_members_property_id, nc_block_class_id, get_control_protocol_class); + auto property = nmos::find_property_descriptor(nc_block_members_property_id, nc_block_class_id, get_control_protocol_class_descriptor); BST_REQUIRE(!property.is_null()); } { // invalid - find members property in NcWorker - auto property = nmos::find_property(nc_block_members_property_id, nc_worker_class_id, get_control_protocol_class); + auto property = nmos::find_property_descriptor(nc_block_members_property_id, nc_worker_class_id, get_control_protocol_class_descriptor); BST_REQUIRE(property.is_null()); } { // invalid - find unknown propertry in NcBlock - auto property = nmos::find_property(invalid_property_id, nc_block_class_id, get_control_protocol_class); + auto property = nmos::find_property_descriptor(invalid_property_id, nc_block_class_id, get_control_protocol_class_descriptor); BST_REQUIRE(property.is_null()); } { // invalid - find unknown property in unknown class - auto property = nmos::find_property(invalid_property_id, invalid_class_id, get_control_protocol_class); + auto property = nmos::find_property_descriptor(invalid_property_id, invalid_class_id, get_control_protocol_class_descriptor); BST_REQUIRE(property.is_null()); } } @@ -774,19 +774,19 @@ BST_TEST_CASE(testConstraints) // setup datatypes in control_protocol_state nmos::experimental::control_protocol_state control_protocol_state; - control_protocol_state.insert(nmos::experimental::datatype{ no_constraints_int16_datatype }); - control_protocol_state.insert(nmos::experimental::datatype{ no_constraints_int32_datatype }); - control_protocol_state.insert(nmos::experimental::datatype{ no_constraints_int64_datatype }); - control_protocol_state.insert(nmos::experimental::datatype{ no_constraints_uint16_datatype }); - control_protocol_state.insert(nmos::experimental::datatype{ no_constraints_uint32_datatype }); - control_protocol_state.insert(nmos::experimental::datatype{ no_constraints_uint64_datatype }); - control_protocol_state.insert(nmos::experimental::datatype{ no_constraints_string_datatype }); - control_protocol_state.insert(nmos::experimental::datatype{ with_constraints_int32_datatype }); - control_protocol_state.insert(nmos::experimental::datatype{ with_constraints_string_datatype }); - control_protocol_state.insert(nmos::experimental::datatype{ enum_datatype }); - control_protocol_state.insert(nmos::experimental::datatype{ simple_struct_datatype }); - control_protocol_state.insert(nmos::experimental::datatype{ no_constraints_int32_seq_datatype }); - control_protocol_state.insert(nmos::experimental::datatype{ no_constraints_string_seq_datatype }); + control_protocol_state.insert(nmos::experimental::datatype_descriptor{ no_constraints_int16_datatype }); + control_protocol_state.insert(nmos::experimental::datatype_descriptor{ no_constraints_int32_datatype }); + control_protocol_state.insert(nmos::experimental::datatype_descriptor{ no_constraints_int64_datatype }); + control_protocol_state.insert(nmos::experimental::datatype_descriptor{ no_constraints_uint16_datatype }); + control_protocol_state.insert(nmos::experimental::datatype_descriptor{ no_constraints_uint32_datatype }); + control_protocol_state.insert(nmos::experimental::datatype_descriptor{ no_constraints_uint64_datatype }); + control_protocol_state.insert(nmos::experimental::datatype_descriptor{ no_constraints_string_datatype }); + control_protocol_state.insert(nmos::experimental::datatype_descriptor{ with_constraints_int32_datatype }); + control_protocol_state.insert(nmos::experimental::datatype_descriptor{ with_constraints_string_datatype }); + control_protocol_state.insert(nmos::experimental::datatype_descriptor{ enum_datatype }); + control_protocol_state.insert(nmos::experimental::datatype_descriptor{ simple_struct_datatype }); + control_protocol_state.insert(nmos::experimental::datatype_descriptor{ no_constraints_int32_seq_datatype }); + control_protocol_state.insert(nmos::experimental::datatype_descriptor{ no_constraints_string_seq_datatype }); // test get_runtime_property_constraints BST_REQUIRE_EQUAL(nmos::details::get_runtime_property_constraints(property_string_id, runtime_property_constraints), runtime_property_string_constraints); @@ -796,7 +796,7 @@ BST_TEST_CASE(testConstraints) // string property constraints validation // runtime property constraints validation - const nmos::details::datatype_constraints_validation_parameters with_constraints_string_constraints_validation_params{ with_constraints_string_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + const nmos::details::datatype_constraints_validation_parameters with_constraints_string_constraints_validation_params{ with_constraints_string_datatype, nmos::make_get_control_protocol_datatype_descriptor_handler(control_protocol_state) }; BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(value::string(U("1234567890")), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params)); BST_REQUIRE_THROW(nmos::details::constraints_validation(value::string(U("12345678901")), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params), nmos::control_protocol_exception); BST_REQUIRE_THROW(nmos::details::constraints_validation(value::string(U("123456789A")), runtime_property_string_constraints, property_string_constraints, with_constraints_string_constraints_validation_params), nmos::control_protocol_exception); @@ -814,13 +814,13 @@ BST_TEST_CASE(testConstraints) BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(value::string(U("1a")), value::null(), value::null(), with_constraints_string_constraints_validation_params)); BST_REQUIRE_THROW(nmos::details::constraints_validation(value::string(U("1a2")), value::null(), value::null(), with_constraints_string_constraints_validation_params), nmos::control_protocol_exception); BST_REQUIRE_THROW(nmos::details::constraints_validation(value::string(U("1*")), value::null(), value::null(), with_constraints_string_constraints_validation_params), nmos::control_protocol_exception); - const nmos::details::datatype_constraints_validation_parameters no_constraints_string_constraints_validation_params{ no_constraints_string_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + const nmos::details::datatype_constraints_validation_parameters no_constraints_string_constraints_validation_params{ no_constraints_string_datatype, nmos::make_get_control_protocol_datatype_descriptor_handler(control_protocol_state) }; BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(value::string(U("1234567890-abcde-!\"£$%^&*()_+=")), value::null(), value::null(), no_constraints_string_constraints_validation_params)); // number property constraints validation // runtime property constraints validation - const nmos::details::datatype_constraints_validation_parameters with_constraints_int32_constraints_validation_params{ with_constraints_int32_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + const nmos::details::datatype_constraints_validation_parameters with_constraints_int32_constraints_validation_params{ with_constraints_int32_datatype, nmos::make_get_control_protocol_datatype_descriptor_handler(control_protocol_state) }; BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(10, runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params)); BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(1000, runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params)); BST_REQUIRE_THROW(nmos::details::constraints_validation(9, runtime_property_int32_constraints, property_int32_constraints, with_constraints_int32_constraints_validation_params), nmos::control_protocol_exception); @@ -846,64 +846,64 @@ BST_TEST_CASE(testConstraints) BST_REQUIRE_THROW(nmos::details::constraints_validation(260, value::null(), value::null(), with_constraints_int32_constraints_validation_params), nmos::control_protocol_exception); BST_REQUIRE_THROW(nmos::details::constraints_validation(99, value::null(), value::null(), with_constraints_int32_constraints_validation_params), nmos::control_protocol_exception); // int16 datatype constraints validation - const nmos::details::datatype_constraints_validation_parameters no_constraints_int16_constraints_validation_params{ no_constraints_int16_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + const nmos::details::datatype_constraints_validation_parameters no_constraints_int16_constraints_validation_params{ no_constraints_int16_datatype, nmos::make_get_control_protocol_datatype_descriptor_handler(control_protocol_state) }; BST_REQUIRE_THROW(nmos::details::constraints_validation(int64_t(std::numeric_limits::min()) - 1, value::null(), value::null(), no_constraints_int16_constraints_validation_params), nmos::control_protocol_exception); BST_REQUIRE_THROW(nmos::details::constraints_validation(int64_t(std::numeric_limits::max()) + 1, value::null(), value::null(), no_constraints_int16_constraints_validation_params), nmos::control_protocol_exception); BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_int16_constraints_validation_params)); BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_int16_constraints_validation_params)); // int32 datatype constraints validation - const nmos::details::datatype_constraints_validation_parameters no_constraints_int32_constraints_validation_params{ no_constraints_int32_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + const nmos::details::datatype_constraints_validation_parameters no_constraints_int32_constraints_validation_params{ no_constraints_int32_datatype, nmos::make_get_control_protocol_datatype_descriptor_handler(control_protocol_state) }; BST_REQUIRE_THROW(nmos::details::constraints_validation(int64_t(std::numeric_limits::min()) - 1, value::null(), value::null(), no_constraints_int32_constraints_validation_params), nmos::control_protocol_exception); BST_REQUIRE_THROW(nmos::details::constraints_validation(int64_t(std::numeric_limits::max()) + 1, value::null(), value::null(), no_constraints_int32_constraints_validation_params), nmos::control_protocol_exception); BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_int32_constraints_validation_params)); BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_int32_constraints_validation_params)); // int64 datatype constraints validation - const nmos::details::datatype_constraints_validation_parameters no_constraints_int64_constraints_validation_params{ no_constraints_int64_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + const nmos::details::datatype_constraints_validation_parameters no_constraints_int64_constraints_validation_params{ no_constraints_int64_datatype, nmos::make_get_control_protocol_datatype_descriptor_handler(control_protocol_state) }; BST_REQUIRE_THROW(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_int64_constraints_validation_params), nmos::control_protocol_exception); BST_REQUIRE_THROW(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_int64_constraints_validation_params), nmos::control_protocol_exception); BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_int64_constraints_validation_params)); BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_int64_constraints_validation_params)); // uint16 datatype constraints validation - const nmos::details::datatype_constraints_validation_parameters no_constraints_uint16_constraints_validation_params{ no_constraints_uint16_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + const nmos::details::datatype_constraints_validation_parameters no_constraints_uint16_constraints_validation_params{ no_constraints_uint16_datatype, nmos::make_get_control_protocol_datatype_descriptor_handler(control_protocol_state) }; BST_REQUIRE_THROW(nmos::details::constraints_validation(-1, value::null(), value::null(), no_constraints_uint16_constraints_validation_params), nmos::control_protocol_exception); BST_REQUIRE_THROW(nmos::details::constraints_validation(uint64_t(std::numeric_limits::max()) + 1, value::null(), value::null(), no_constraints_uint16_constraints_validation_params), nmos::control_protocol_exception); BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_uint16_constraints_validation_params)); BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_uint16_constraints_validation_params)); // uint32 datatype constraints validation - const nmos::details::datatype_constraints_validation_parameters no_constraints_uint32_constraints_validation_params{ no_constraints_uint32_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + const nmos::details::datatype_constraints_validation_parameters no_constraints_uint32_constraints_validation_params{ no_constraints_uint32_datatype, nmos::make_get_control_protocol_datatype_descriptor_handler(control_protocol_state) }; BST_REQUIRE_THROW(nmos::details::constraints_validation(-1, value::null(), value::null(), no_constraints_uint32_constraints_validation_params), nmos::control_protocol_exception); BST_REQUIRE_THROW(nmos::details::constraints_validation(uint64_t(std::numeric_limits::max()) + 1, value::null(), value::null(), no_constraints_uint32_constraints_validation_params), nmos::control_protocol_exception); BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_uint32_constraints_validation_params)); BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_uint32_constraints_validation_params)); // uint64 datatype constraints validation - const nmos::details::datatype_constraints_validation_parameters no_constraints_uint64_constraints_validation_params{ no_constraints_uint64_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + const nmos::details::datatype_constraints_validation_parameters no_constraints_uint64_constraints_validation_params{ no_constraints_uint64_datatype, nmos::make_get_control_protocol_datatype_descriptor_handler(control_protocol_state) }; BST_REQUIRE_THROW(nmos::details::constraints_validation(-1, value::null(), value::null(), no_constraints_uint64_constraints_validation_params), nmos::control_protocol_exception); BST_REQUIRE_THROW(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_int64_constraints_validation_params), nmos::control_protocol_exception); BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_uint64_constraints_validation_params)); BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_uint64_constraints_validation_params)); // float32 datatype constraints validation - const nmos::details::datatype_constraints_validation_parameters no_constraints_float32_constraints_validation_params{ no_constraints_float32_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + const nmos::details::datatype_constraints_validation_parameters no_constraints_float32_constraints_validation_params{ no_constraints_float32_datatype, nmos::make_get_control_protocol_datatype_descriptor_handler(control_protocol_state) }; BST_REQUIRE_THROW(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_float32_constraints_validation_params), nmos::control_protocol_exception); BST_REQUIRE_THROW(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_float32_constraints_validation_params), nmos::control_protocol_exception); BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_float32_constraints_validation_params)); BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_float32_constraints_validation_params)); // float64 datatype constraints validation - const nmos::details::datatype_constraints_validation_parameters no_constraints_float64_constraints_validation_params{ no_constraints_float64_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + const nmos::details::datatype_constraints_validation_parameters no_constraints_float64_constraints_validation_params{ no_constraints_float64_datatype, nmos::make_get_control_protocol_datatype_descriptor_handler(control_protocol_state) }; BST_REQUIRE_THROW(nmos::details::constraints_validation(1000, value::null(), value::null(), no_constraints_float64_constraints_validation_params), nmos::control_protocol_exception); BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(1000.0, value::null(), value::null(), no_constraints_float64_constraints_validation_params)); BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(std::numeric_limits::min(), value::null(), value::null(), no_constraints_float64_constraints_validation_params)); BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(std::numeric_limits::max(), value::null(), value::null(), no_constraints_float64_constraints_validation_params)); // enum property datatype constraints validation - const nmos::details::datatype_constraints_validation_parameters enum_constraints_validation_params{ enum_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + const nmos::details::datatype_constraints_validation_parameters enum_constraints_validation_params{ enum_datatype, nmos::make_get_control_protocol_datatype_descriptor_handler(control_protocol_state) }; BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(enum_value::foo, value::null(), value::null(), enum_constraints_validation_params)); BST_REQUIRE_THROW(nmos::details::constraints_validation(4, value::null(), value::null(), enum_constraints_validation_params), nmos::control_protocol_exception); // invalid data vs primitive datatype constraints - const nmos::details::datatype_constraints_validation_parameters no_constraints_string_seq_constraints_validation_params{ no_constraints_string_seq_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + const nmos::details::datatype_constraints_validation_parameters no_constraints_string_seq_constraints_validation_params{ no_constraints_string_seq_datatype, nmos::make_get_control_protocol_datatype_descriptor_handler(control_protocol_state) }; BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(value_of({ value::string(U("1234567890-abcde-!\"£$%^&*()_+=")) }), value::null(), value::null(), no_constraints_string_seq_constraints_validation_params)); BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(value_of({ value::string(U("1234567890-abcde-!\"£$%^&*()_+=")), value::string(U("1234567890-abcde-!\"£$%^&*()_+=")) }), value::null(), value::null(), no_constraints_string_seq_constraints_validation_params)); BST_REQUIRE_THROW(nmos::details::constraints_validation(value_of({ 1 }), value::null(), value::null(), no_constraints_string_seq_constraints_validation_params), nmos::control_protocol_exception); BST_REQUIRE_THROW(nmos::details::constraints_validation(1, value::null(), value::null(), no_constraints_string_seq_constraints_validation_params), nmos::control_protocol_exception); - const nmos::details::datatype_constraints_validation_parameters no_constraints_int32_seq_constraints_validation_params{ no_constraints_int32_seq_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + const nmos::details::datatype_constraints_validation_parameters no_constraints_int32_seq_constraints_validation_params{ no_constraints_int32_seq_datatype, nmos::make_get_control_protocol_datatype_descriptor_handler(control_protocol_state) }; BST_REQUIRE_THROW(nmos::details::constraints_validation(value_of({ value::string(U("1234567890-abcde-!\"£$%^&*()_+=")) }), value::null(), value::null(), no_constraints_int32_seq_constraints_validation_params), nmos::control_protocol_exception); BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(value_of({ 1 }), value::null(), value::null(), no_constraints_int32_seq_constraints_validation_params)); BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(value_of({ 1, 2 }), value::null(), value::null(), no_constraints_int32_seq_constraints_validation_params)); @@ -1441,7 +1441,7 @@ BST_TEST_CASE(testConstraints) }) }) } }); - const nmos::details::datatype_constraints_validation_parameters struct_constraints_validation_params{ struct_datatype, nmos::make_get_control_protocol_datatype_handler(control_protocol_state) }; + const nmos::details::datatype_constraints_validation_parameters struct_constraints_validation_params{ struct_datatype, nmos::make_get_control_protocol_datatype_descriptor_handler(control_protocol_state) }; BST_REQUIRE_NO_THROW(nmos::details::constraints_validation(good_struct, value::null(), value::null(), struct_constraints_validation_params)); BST_REQUIRE_THROW(nmos::details::constraints_validation(bad_struct1, value::null(), value::null(), struct_constraints_validation_params), nmos::control_protocol_exception); BST_REQUIRE_THROW(nmos::details::constraints_validation(bad_struct2, value::null(), value::null(), struct_constraints_validation_params), nmos::control_protocol_exception); From c17ade3d990ce2f449235357f1e483c80cb8faf8 Mon Sep 17 00:00:00 2001 From: lo-simon Date: Thu, 29 Feb 2024 21:05:28 +0000 Subject: [PATCH 104/106] Update IS-12 Readme --- Development/third_party/is-12/README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Development/third_party/is-12/README.md b/Development/third_party/is-12/README.md index 84e840adb..3f207891f 100644 --- a/Development/third_party/is-12/README.md +++ b/Development/third_party/is-12/README.md @@ -1 +1,9 @@ -This directory is for JSON Schemas +# AMWA IS-12 NMOS Control & Monitoring Protocol Specification + +This directory contains files from the [AMWA NMOS Control & Monitoring Protocol](https://github.com/AMWA-TV/is-12), in particular tagged versions of the JSON schemas used by the API specifications. + +Original source code: + +- (c) AMWA 2018 +- Licensed under the Apache License, Version 2.0; http://www.apache.org/licenses/LICENSE-2.0 + From f80caad42dac0e7ab730c878181ed447846c30ca Mon Sep 17 00:00:00 2001 From: lo-simon Date: Fri, 1 Mar 2024 09:32:09 +0000 Subject: [PATCH 105/106] Update IS-12 Readme --- Development/third_party/is-12/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Development/third_party/is-12/README.md b/Development/third_party/is-12/README.md index 3f207891f..44ab19110 100644 --- a/Development/third_party/is-12/README.md +++ b/Development/third_party/is-12/README.md @@ -4,6 +4,6 @@ This directory contains files from the [AMWA NMOS Control & Monitoring Protocol] Original source code: -- (c) AMWA 2018 +- (c) AMWA 2023 - Licensed under the Apache License, Version 2.0; http://www.apache.org/licenses/LICENSE-2.0 From f41032a50d7ab571e6a566102af0f3d6b8395f9d Mon Sep 17 00:00:00 2001 From: Simon Lo Date: Tue, 5 Mar 2024 16:57:05 +0000 Subject: [PATCH 106/106] Update Development/nmos/control_protocol_handlers.h Co-authored-by: jonathan-r-thorpe <64410119+jonathan-r-thorpe@users.noreply.github.com> --- Development/nmos/control_protocol_handlers.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Development/nmos/control_protocol_handlers.h b/Development/nmos/control_protocol_handlers.h index 43a2a3ba1..89c6dd032 100644 --- a/Development/nmos/control_protocol_handlers.h +++ b/Development/nmos/control_protocol_handlers.h @@ -19,7 +19,7 @@ namespace nmos struct datatype_descriptor; } - // callback to retrieve a specific control protocol classs descriptor + // callback to retrieve a specific control protocol class descriptor // this callback should not throw exceptions typedef std::function get_control_protocol_class_descriptor_handler;