diff --git a/Development/nmos/control_protocol_behaviour.cpp b/Development/nmos/control_protocol_behaviour.cpp index e3333a71..2d381a29 100644 --- a/Development/nmos/control_protocol_behaviour.cpp +++ b/Development/nmos/control_protocol_behaviour.cpp @@ -10,49 +10,19 @@ namespace nmos { namespace experimental { - struct domain_status_properties - { - domain_status_properties(const nc_property_id& status_property_id, const nc_property_id& status_message_property_id, const nc_property_id& status_transition_counter_property_id, const utility::string_t& status_pending_field_name, const utility::string_t& status_message_pending_field_name, const utility::string_t& status_pending_received_time_field_name) - : status_property_id(status_property_id) - , status_message_property_id(status_message_property_id) - , status_transition_counter_property_id(status_transition_counter_property_id) - , status_pending_field_name(status_pending_field_name) - , status_message_pending_field_name(status_message_pending_field_name) - , status_pending_received_time_field_name(status_pending_received_time_field_name) - {} - - nc_property_id status_property_id; - nc_property_id status_message_property_id; - nc_property_id status_transition_counter_property_id; - utility::string_t status_pending_field_name; - utility::string_t status_message_pending_field_name; - utility::string_t status_pending_received_time_field_name; - }; - void control_protocol_behaviour_thread(nmos::node_model& model, control_protocol_state& state, slog::base_gate& gate_) { nmos::details::omanip_gate gate(gate_, nmos::stash_category(nmos::categories::control_protocol_behaviour)); slog::log(gate, SLOG_FLF) << "Starting control protocol behaviour thread"; - std::vector receiver_monitor_domain_statuses; - receiver_monitor_domain_statuses.push_back(domain_status_properties(nc_receiver_monitor_stream_status_property_id, nc_receiver_monitor_stream_status_message_property_id, nc_receiver_monitor_stream_status_transition_counter_property_id, nmos::fields::nc::stream_status_pending, nmos::fields::nc::stream_status_message_pending, nmos::fields::nc::stream_status_pending_received_time)); - receiver_monitor_domain_statuses.push_back(domain_status_properties(nc_receiver_monitor_connection_status_property_id, nc_receiver_monitor_connection_status_message_property_id, nc_receiver_monitor_connection_status_transition_counter_property_id, nmos::fields::nc::connection_status_pending, nmos::fields::nc::connection_status_message_pending, nmos::fields::nc::connection_status_pending_received_time)); - receiver_monitor_domain_statuses.push_back(domain_status_properties(nc_receiver_monitor_link_status_property_id, nc_receiver_monitor_link_status_message_property_id, nc_receiver_monitor_link_status_transition_counter_property_id, nmos::fields::nc::link_status_pending, nmos::fields::nc::link_status_message_pending, nmos::fields::nc::link_status_pending_received_time)); - receiver_monitor_domain_statuses.push_back(domain_status_properties(nc_receiver_monitor_external_synchronization_status_property_id, nc_receiver_monitor_external_synchronization_status_message_property_id, nc_receiver_monitor_external_synchronization_status_transition_counter_property_id, nmos::fields::nc::external_synchronization_status_pending, nmos::fields::nc::external_synchronization_status_message_pending, nmos::fields::nc::external_synchronization_status_pending_received_time)); - - std::vector sender_monitor_domain_statuses; - sender_monitor_domain_statuses.push_back(domain_status_properties(nc_sender_monitor_essence_status_property_id, nc_sender_monitor_essence_status_message_property_id, nc_sender_monitor_essence_status_transition_counter_property_id, nmos::fields::nc::essence_status_pending, nmos::fields::nc::essence_status_message_pending, nmos::fields::nc::essence_status_pending_received_time)); - sender_monitor_domain_statuses.push_back(domain_status_properties(nc_sender_monitor_transmission_status_property_id, nc_sender_monitor_transmission_status_message_property_id, nc_sender_monitor_transmission_status_transition_counter_property_id, nmos::fields::nc::transmission_status_pending, nmos::fields::nc::transmission_status_message_pending, nmos::fields::nc::transmission_status_pending_received_time)); - sender_monitor_domain_statuses.push_back(domain_status_properties(nc_sender_monitor_link_status_property_id, nc_sender_monitor_link_status_message_property_id, nc_sender_monitor_link_status_transition_counter_property_id, nmos::fields::nc::link_status_pending, nmos::fields::nc::link_status_message_pending, nmos::fields::nc::link_status_pending_received_time)); - sender_monitor_domain_statuses.push_back(domain_status_properties(nc_sender_monitor_external_synchronization_status_property_id, nc_sender_monitor_external_synchronization_status_message_property_id, nc_sender_monitor_external_synchronization_status_transition_counter_property_id, nmos::fields::nc::external_synchronization_status_pending, nmos::fields::nc::external_synchronization_status_message_pending, nmos::fields::nc::external_synchronization_status_pending_received_time)); - auto lock = model.write_lock(); auto& condition = model.condition; auto& shutdown = model.shutdown; auto& control_protocol_resources = model.control_protocol_resources; auto get_control_protocol_class_descriptor = nmos::make_get_control_protocol_class_descriptor_handler(state); + auto get_monitor_domains = nmos::make_get_monitor_domains_handler(state); // continue until the server is being shut down for (;;) { @@ -91,7 +61,7 @@ namespace nmos auto status_reporting_delay = nc::get_property(control_protocol_resources, oid, nc_status_monitor_status_reporting_delay, get_control_protocol_class_descriptor, gate); - const auto& domain_statuses = nmos::nc::is_sender_monitor(class_id) ? sender_monitor_domain_statuses : receiver_monitor_domain_statuses; + const auto domain_statuses = nmos::nc::get_monitor_domains(class_id, get_monitor_domains); for (const auto& domain_status : domain_statuses) { @@ -128,7 +98,7 @@ namespace nmos const auto status_reporting_delay = nc::get_property(control_protocol_resources, oid, nc_status_monitor_status_reporting_delay, get_control_protocol_class_descriptor, gate); - const auto& domain_statuses = nmos::nc::is_sender_monitor(class_id) ? sender_monitor_domain_statuses : receiver_monitor_domain_statuses; + const auto domain_statuses = nmos::nc::get_monitor_domains(class_id, get_monitor_domains); for (const auto& domain_status : domain_statuses) { @@ -150,6 +120,7 @@ namespace nmos domain_status.status_transition_counter_property_id, domain_status.status_pending_received_time_field_name, get_control_protocol_class_descriptor, + get_monitor_domains, gate); model.notify(); diff --git a/Development/nmos/control_protocol_handlers.cpp b/Development/nmos/control_protocol_handlers.cpp index 8ec66b32..23217fe5 100644 --- a/Development/nmos/control_protocol_handlers.cpp +++ b/Development/nmos/control_protocol_handlers.cpp @@ -82,9 +82,10 @@ namespace nmos { auto get_control_protocol_class_descriptor = nmos::make_get_control_protocol_class_descriptor_handler(control_protocol_state); auto get_control_protocol_method_descriptor = nmos::make_get_control_protocol_method_descriptor_handler(control_protocol_state); + auto get_monitor_domains = nmos::make_get_monitor_domains_handler(control_protocol_state); auto monitor_status_pending = nmos::make_monitor_status_pending_handler(control_protocol_state); - return [&resources, monitor_status_pending, get_control_protocol_class_descriptor, get_control_protocol_method_descriptor, &gate](const nmos::resource& resource, const nmos::resource& connection_resource) + return [&resources, monitor_status_pending, get_control_protocol_class_descriptor, get_control_protocol_method_descriptor, get_monitor_domains, &gate](const nmos::resource& resource, const nmos::resource& connection_resource) { if (nmos::types::receiver != resource.type && nmos::types::sender != resource.type) return; @@ -99,12 +100,12 @@ namespace nmos if (active) { // Activate monitor - nc::activate_monitor(resources, oid, get_control_protocol_class_descriptor, get_control_protocol_method_descriptor, gate); + nc::activate_monitor(resources, oid, get_control_protocol_class_descriptor, get_control_protocol_method_descriptor, get_monitor_domains, gate); } else { // deactivate monitor - nc::deactivate_monitor(resources, oid, get_control_protocol_class_descriptor, gate); + nc::deactivate_monitor(resources, oid, get_control_protocol_class_descriptor, get_monitor_domains, gate); } } }; @@ -133,11 +134,12 @@ namespace nmos set_receiver_monitor_link_status_handler make_set_receiver_monitor_link_status_handler(resources& resources, experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate) { auto get_control_protocol_class_descriptor = nmos::make_get_control_protocol_class_descriptor_handler(control_protocol_state); + auto get_monitor_domains = nmos::make_get_monitor_domains_handler(control_protocol_state); auto monitor_status_pending = nmos::make_monitor_status_pending_handler(control_protocol_state); - return [&resources, monitor_status_pending, get_control_protocol_class_descriptor, &gate](nc_oid oid, nmos::nc_link_status::status link_status, const utility::string_t& link_status_message) + return [&resources, monitor_status_pending, get_control_protocol_class_descriptor, get_monitor_domains, &gate](nc_oid oid, nmos::nc_link_status::status link_status, const utility::string_t& link_status_message) { - return nc::set_receiver_monitor_link_status_with_delay(resources, oid, link_status, link_status_message, monitor_status_pending, get_control_protocol_class_descriptor, gate); + return nc::set_receiver_monitor_link_status_with_delay(resources, oid, link_status, link_status_message, monitor_status_pending, get_control_protocol_class_descriptor, get_monitor_domains, gate); }; } @@ -145,11 +147,12 @@ namespace nmos set_receiver_monitor_connection_status_handler make_set_receiver_monitor_connection_status_handler(resources& resources, experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate) { auto get_control_protocol_class_descriptor = nmos::make_get_control_protocol_class_descriptor_handler(control_protocol_state); + auto get_monitor_domains = nmos::make_get_monitor_domains_handler(control_protocol_state); auto monitor_status_pending = nmos::make_monitor_status_pending_handler(control_protocol_state); - return [&resources, monitor_status_pending, get_control_protocol_class_descriptor, &gate](nc_oid oid, nmos::nc_connection_status::status connection_status, const utility::string_t& connection_status_message) + return [&resources, monitor_status_pending, get_control_protocol_class_descriptor, get_monitor_domains, &gate](nc_oid oid, nmos::nc_connection_status::status connection_status, const utility::string_t& connection_status_message) { - return nc::set_receiver_monitor_connection_status_with_delay(resources, oid, connection_status, connection_status_message, monitor_status_pending, get_control_protocol_class_descriptor, gate); + return nc::set_receiver_monitor_connection_status_with_delay(resources, oid, connection_status, connection_status_message, monitor_status_pending, get_control_protocol_class_descriptor, get_monitor_domains, gate); }; } @@ -157,11 +160,12 @@ namespace nmos set_receiver_monitor_external_synchronization_status_handler make_set_receiver_monitor_external_synchronization_status_handler(resources& resources, experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate) { auto get_control_protocol_class_descriptor = nmos::make_get_control_protocol_class_descriptor_handler(control_protocol_state); + auto get_monitor_domains = nmos::make_get_monitor_domains_handler(control_protocol_state); auto monitor_status_pending = nmos::make_monitor_status_pending_handler(control_protocol_state); - return [&resources, monitor_status_pending, get_control_protocol_class_descriptor, &gate](nc_oid oid, nmos::nc_synchronization_status::status external_synchronization_status, const utility::string_t& external_synchronization_status_message) + return [&resources, monitor_status_pending, get_control_protocol_class_descriptor, get_monitor_domains, &gate](nc_oid oid, nmos::nc_synchronization_status::status external_synchronization_status, const utility::string_t& external_synchronization_status_message) { - return nc::set_receiver_monitor_external_synchronization_status_with_delay(resources, oid, external_synchronization_status, external_synchronization_status_message, monitor_status_pending, get_control_protocol_class_descriptor, gate); + return nc::set_receiver_monitor_external_synchronization_status_with_delay(resources, oid, external_synchronization_status, external_synchronization_status_message, monitor_status_pending, get_control_protocol_class_descriptor, get_monitor_domains, gate); }; } @@ -169,11 +173,12 @@ namespace nmos set_receiver_monitor_stream_status_handler make_set_receiver_monitor_stream_status_handler(resources& resources, experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate) { auto get_control_protocol_class_descriptor = nmos::make_get_control_protocol_class_descriptor_handler(control_protocol_state); + auto get_monitor_domains = nmos::make_get_monitor_domains_handler(control_protocol_state); auto monitor_status_pending = nmos::make_monitor_status_pending_handler(control_protocol_state); - return [&resources, monitor_status_pending, get_control_protocol_class_descriptor, &gate](nc_oid oid, nmos::nc_stream_status::status stream_status, const utility::string_t& stream_status_message) + return [&resources, monitor_status_pending, get_control_protocol_class_descriptor, get_monitor_domains, &gate](nc_oid oid, nmos::nc_stream_status::status stream_status, const utility::string_t& stream_status_message) { - return nc::set_receiver_monitor_stream_status_with_delay(resources, oid, stream_status, stream_status_message, monitor_status_pending, get_control_protocol_class_descriptor, gate); + return nc::set_receiver_monitor_stream_status_with_delay(resources, oid, stream_status, stream_status_message, monitor_status_pending, get_control_protocol_class_descriptor, get_monitor_domains, gate); }; } @@ -192,11 +197,12 @@ namespace nmos set_sender_monitor_link_status_handler make_set_sender_monitor_link_status_handler(resources& resources, experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate) { auto get_control_protocol_class_descriptor = nmos::make_get_control_protocol_class_descriptor_handler(control_protocol_state); + auto get_monitor_domains = nmos::make_get_monitor_domains_handler(control_protocol_state); auto monitor_status_pending = nmos::make_monitor_status_pending_handler(control_protocol_state); - return [&resources, monitor_status_pending, get_control_protocol_class_descriptor, &gate](nc_oid oid, nmos::nc_link_status::status link_status, const utility::string_t& link_status_message) + return [&resources, monitor_status_pending, get_control_protocol_class_descriptor, get_monitor_domains, &gate](nc_oid oid, nmos::nc_link_status::status link_status, const utility::string_t& link_status_message) { - return nc::set_sender_monitor_link_status_with_delay(resources, oid, link_status, link_status_message, monitor_status_pending, get_control_protocol_class_descriptor, gate); + return nc::set_sender_monitor_link_status_with_delay(resources, oid, link_status, link_status_message, monitor_status_pending, get_control_protocol_class_descriptor, get_monitor_domains, gate); }; } @@ -204,11 +210,12 @@ namespace nmos set_sender_monitor_transmission_status_handler make_set_sender_monitor_transmission_status_handler(resources& resources, experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate) { auto get_control_protocol_class_descriptor = nmos::make_get_control_protocol_class_descriptor_handler(control_protocol_state); + auto get_monitor_domains = nmos::make_get_monitor_domains_handler(control_protocol_state); auto monitor_status_pending = nmos::make_monitor_status_pending_handler(control_protocol_state); - return [&resources, monitor_status_pending, get_control_protocol_class_descriptor, &gate](nc_oid oid, nmos::nc_transmission_status::status transmission_status, const utility::string_t& transmission_status_message) + return [&resources, monitor_status_pending, get_control_protocol_class_descriptor, get_monitor_domains, &gate](nc_oid oid, nmos::nc_transmission_status::status transmission_status, const utility::string_t& transmission_status_message) { - return nc::set_sender_monitor_transmission_status_with_delay(resources, oid, transmission_status, transmission_status_message, monitor_status_pending, get_control_protocol_class_descriptor, gate); + return nc::set_sender_monitor_transmission_status_with_delay(resources, oid, transmission_status, transmission_status_message, monitor_status_pending, get_control_protocol_class_descriptor, get_monitor_domains, gate); }; } @@ -216,11 +223,12 @@ namespace nmos set_sender_monitor_external_synchronization_status_handler make_set_sender_monitor_external_synchronization_status_handler(resources& resources, experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate) { auto get_control_protocol_class_descriptor = nmos::make_get_control_protocol_class_descriptor_handler(control_protocol_state); + auto get_monitor_domains = nmos::make_get_monitor_domains_handler(control_protocol_state); auto monitor_status_pending = nmos::make_monitor_status_pending_handler(control_protocol_state); - return [&resources, monitor_status_pending, get_control_protocol_class_descriptor, &gate](nc_oid oid, nmos::nc_synchronization_status::status external_synchronization_status, const utility::string_t& external_synchronization_status_message) + return [&resources, monitor_status_pending, get_control_protocol_class_descriptor, get_monitor_domains, &gate](nc_oid oid, nmos::nc_synchronization_status::status external_synchronization_status, const utility::string_t& external_synchronization_status_message) { - return nc::set_sender_monitor_external_synchronization_status_with_delay(resources, oid, external_synchronization_status, external_synchronization_status_message, monitor_status_pending, get_control_protocol_class_descriptor, gate); + return nc::set_sender_monitor_external_synchronization_status_with_delay(resources, oid, external_synchronization_status, external_synchronization_status_message, monitor_status_pending, get_control_protocol_class_descriptor, get_monitor_domains, gate); }; } @@ -228,11 +236,12 @@ namespace nmos set_sender_monitor_essence_status_handler make_set_sender_monitor_essence_status_handler(resources& resources, experimental::control_protocol_state& control_protocol_state, slog::base_gate& gate) { auto get_control_protocol_class_descriptor = nmos::make_get_control_protocol_class_descriptor_handler(control_protocol_state); + auto get_monitor_domains = nmos::make_get_monitor_domains_handler(control_protocol_state); auto monitor_status_pending = nmos::make_monitor_status_pending_handler(control_protocol_state); - return [&resources, monitor_status_pending, get_control_protocol_class_descriptor, &gate](nc_oid oid, nmos::nc_essence_status::status essence_status, const utility::string_t& essence_status_message) + return [&resources, monitor_status_pending, get_control_protocol_class_descriptor, get_monitor_domains, &gate](nc_oid oid, nmos::nc_essence_status::status essence_status, const utility::string_t& essence_status_message) { - return nc::set_sender_monitor_essence_status_with_delay(resources, oid, essence_status, essence_status_message, monitor_status_pending, get_control_protocol_class_descriptor, gate); + return nc::set_sender_monitor_essence_status_with_delay(resources, oid, essence_status, essence_status_message, monitor_status_pending, get_control_protocol_class_descriptor, get_monitor_domains, gate); }; } diff --git a/Development/nmos/control_protocol_methods.cpp b/Development/nmos/control_protocol_methods.cpp index 04da4685..b49a1acb 100644 --- a/Development/nmos/control_protocol_methods.cpp +++ b/Development/nmos/control_protocol_methods.cpp @@ -721,38 +721,19 @@ namespace nmos } // Resets the packet counters and messages - web::json::value reset_monitor(nmos::resources& resources, const nmos::resource& resource, const web::json::value&, bool is_deprecated, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, control_protocol_property_changed_handler property_changed, reset_monitor_handler reset_monitor, slog::base_gate& gate) + web::json::value reset_monitor(nmos::resources& resources, const nmos::resource& resource, const web::json::value&, bool is_deprecated, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, control_protocol_property_changed_handler property_changed, reset_monitor_handler reset_monitor, get_monitor_domains_handler get_monitor_domains, slog::base_gate& gate) { slog::log(gate, SLOG_FLF) << "Resets the packet counters"; - const std::vector> receiver_property_values = { - std::pair(nc_receiver_monitor_connection_status_transition_counter_property_id, web::json::value::number(0)), - std::pair(nc_receiver_monitor_external_synchronization_status_transition_counter_property_id, web::json::value::number(0)), - std::pair(nc_receiver_monitor_link_status_transition_counter_property_id, web::json::value::number(0)), - std::pair(nc_receiver_monitor_stream_status_transition_counter_property_id, web::json::value::number(0)), - std::pair(nc_receiver_monitor_connection_status_message_property_id, web::json::value::null()), - std::pair(nc_receiver_monitor_external_synchronization_status_message_property_id, web::json::value::null()), - std::pair(nc_receiver_monitor_link_status_message_property_id, web::json::value::null()), - std::pair(nc_receiver_monitor_stream_status_message_property_id, web::json::value::null()), - std::pair(nc_status_monitor_overall_status_message_property_id, web::json::value::null()), - }; - - const std::vector> sender_property_values = { - std::pair(nc_sender_monitor_transmission_status_transition_counter_property_id, web::json::value::number(0)), - std::pair(nc_sender_monitor_external_synchronization_status_transition_counter_property_id, web::json::value::number(0)), - std::pair(nc_sender_monitor_link_status_transition_counter_property_id, web::json::value::number(0)), - std::pair(nc_sender_monitor_essence_status_transition_counter_property_id, web::json::value::number(0)), - std::pair(nc_sender_monitor_transmission_status_message_property_id, web::json::value::null()), - std::pair(nc_sender_monitor_external_synchronization_status_message_property_id, web::json::value::null()), - std::pair(nc_sender_monitor_link_status_message_property_id, web::json::value::null()), - std::pair(nc_sender_monitor_essence_status_message_property_id, web::json::value::null()), - std::pair(nc_status_monitor_overall_status_message_property_id, web::json::value::null()), - }; - const auto& class_id = details::parse_class_id(nmos::fields::nc::class_id(resource.data)); - // reset all counters - const std::vector> property_values = nmos::nc::is_sender_monitor(class_id) ? sender_property_values : receiver_property_values; + std::vector> property_values; + for (const auto& monitor_domain : nc::get_monitor_domains(class_id, get_monitor_domains)) + { + property_values.push_back({ monitor_domain.status_transition_counter_property_id, web::json::value::number(0) }); + property_values.push_back({ monitor_domain.status_message_property_id, web::json::value::null() }); + } + property_values.push_back({ nc_status_monitor_overall_status_message_property_id, web::json::value::null() }); for (const auto& property_value : property_values) { diff --git a/Development/nmos/control_protocol_methods.h b/Development/nmos/control_protocol_methods.h index 5f0e51d1..81ab9d4f 100644 --- a/Development/nmos/control_protocol_methods.h +++ b/Development/nmos/control_protocol_methods.h @@ -2,6 +2,7 @@ #define NMOS_CONTROL_PROTOCOL_METHODS_H #include "nmos/control_protocol_handlers.h" +#include "nmos/control_protocol_state.h" #include "nmos/resources.h" namespace slog @@ -52,7 +53,12 @@ namespace nmos // Gets the lost packet counters web::json::value get_lost_packet_counters(nmos::resources& resources, const nmos::resource& resource, const web::json::value& arguments, bool is_deprecated, get_packet_counters_handler get_lost_packet_counters, slog::base_gate& gate); // Resets the packet counters and messages - web::json::value reset_monitor(nmos::resources& resources, const nmos::resource& resource, const web::json::value&, bool is_deprecated, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, control_protocol_property_changed_handler property_changed, reset_monitor_handler reset_monitor, slog::base_gate& gate); + web::json::value reset_monitor(nmos::resources& resources, const nmos::resource& resource, const web::json::value&, bool is_deprecated, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, control_protocol_property_changed_handler property_changed, reset_monitor_handler reset_monitor, get_monitor_domains_handler get_monitor_domains, slog::base_gate& gate); + // Deprecated: use the overload with get_monitor_domains_handler to reset custom monitor domains + inline web::json::value reset_monitor(nmos::resources& resources, const nmos::resource& resource, const web::json::value& arguments, bool is_deprecated, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, control_protocol_property_changed_handler property_changed, reset_monitor_handler reset_monitor_callback, slog::base_gate& gate) + { + return reset_monitor(resources, resource, arguments, is_deprecated, get_control_protocol_class_descriptor, property_changed, reset_monitor_callback, {}, gate); + } } } #endif diff --git a/Development/nmos/control_protocol_state.cpp b/Development/nmos/control_protocol_state.cpp index 8f68b6eb..d7f8ebc8 100644 --- a/Development/nmos/control_protocol_state.cpp +++ b/Development/nmos/control_protocol_state.cpp @@ -87,6 +87,122 @@ namespace nmos return nc::details::make_event_descriptor(description, id, name, event_datatype, is_deprecated); } + // Domains ordered from lowest to highest overallStatusMessage priority: sync, payload, transport, link + std::vector make_receiver_monitor_domains() + { + return + { + // External synchronization status + { + nc_receiver_monitor_external_synchronization_status_property_id, // status_property_id + nc_receiver_monitor_external_synchronization_status_message_property_id, // status_message_property_id + nc_receiver_monitor_external_synchronization_status_transition_counter_property_id, // status_transition_counter_property_id + nmos::fields::nc::external_synchronization_status_pending, // status_pending_field_name + nmos::fields::nc::external_synchronization_status_message_pending, // status_message_pending_field_name + nmos::fields::nc::external_synchronization_status_pending_received_time, // status_pending_received_time_field_name + {}, // inactive_status + nc_synchronization_status::status::not_used // ignored_status + }, + // Stream status + { + nc_receiver_monitor_stream_status_property_id, // status_property_id + nc_receiver_monitor_stream_status_message_property_id, // status_message_property_id + nc_receiver_monitor_stream_status_transition_counter_property_id, // status_transition_counter_property_id + nmos::fields::nc::stream_status_pending, // status_pending_field_name + nmos::fields::nc::stream_status_message_pending, // status_message_pending_field_name + nmos::fields::nc::stream_status_pending_received_time, // status_pending_received_time_field_name + nc_stream_status::status::inactive, // inactive_status + {}, // ignored_status + nc_stream_status::status::healthy, // activation_status + U("Receiver activated"), // activation_message + nc_stream_status::status::inactive, // deactivation_status + U("Receiver deactivated") // deactivation_message + }, + // Connection status + { + nc_receiver_monitor_connection_status_property_id, // status_property_id + nc_receiver_monitor_connection_status_message_property_id, // status_message_property_id + nc_receiver_monitor_connection_status_transition_counter_property_id, // status_transition_counter_property_id + nmos::fields::nc::connection_status_pending, // status_pending_field_name + nmos::fields::nc::connection_status_message_pending, // status_message_pending_field_name + nmos::fields::nc::connection_status_pending_received_time, // status_pending_received_time_field_name + nc_connection_status::status::inactive, // inactive_status + {}, // ignored_status + nc_connection_status::status::healthy, // activation_status + U("Receiver activated"), // activation_message + nc_connection_status::status::inactive, // deactivation_status + U("Receiver deactivated") // deactivation_message + }, + // Link status + { + nc_receiver_monitor_link_status_property_id, // status_property_id + nc_receiver_monitor_link_status_message_property_id, // status_message_property_id + nc_receiver_monitor_link_status_transition_counter_property_id, // status_transition_counter_property_id + nmos::fields::nc::link_status_pending, // status_pending_field_name + nmos::fields::nc::link_status_message_pending, // status_message_pending_field_name + nmos::fields::nc::link_status_pending_received_time // status_pending_received_time_field_name + } + }; + } + + // Domains ordered from lowest to highest overallStatusMessage priority: sync, payload, transport, link + std::vector make_sender_monitor_domains() + { + return + { + // External synchronization status + { + nc_sender_monitor_external_synchronization_status_property_id, // status_property_id + nc_sender_monitor_external_synchronization_status_message_property_id, // status_message_property_id + nc_sender_monitor_external_synchronization_status_transition_counter_property_id, // status_transition_counter_property_id + nmos::fields::nc::external_synchronization_status_pending, // status_pending_field_name + nmos::fields::nc::external_synchronization_status_message_pending, // status_message_pending_field_name + nmos::fields::nc::external_synchronization_status_pending_received_time, // status_pending_received_time_field_name + {}, // inactive_status + nc_synchronization_status::status::not_used // ignored_status + }, + // Essence status + { + nc_sender_monitor_essence_status_property_id, // status_property_id + nc_sender_monitor_essence_status_message_property_id, // status_message_property_id + nc_sender_monitor_essence_status_transition_counter_property_id, // status_transition_counter_property_id + nmos::fields::nc::essence_status_pending, // status_pending_field_name + nmos::fields::nc::essence_status_message_pending, // status_message_pending_field_name + nmos::fields::nc::essence_status_pending_received_time, // status_pending_received_time_field_name + nc_essence_status::status::inactive, // inactive_status + {}, // ignored_status + nc_essence_status::status::healthy, // activation_status + U("Sender activated"), // activation_message + nc_essence_status::status::inactive, // deactivation_status + U("Sender deactivated") // deactivation_message + }, + // Transmission status + { + nc_sender_monitor_transmission_status_property_id, // status_property_id + nc_sender_monitor_transmission_status_message_property_id, // status_message_property_id + nc_sender_monitor_transmission_status_transition_counter_property_id, // status_transition_counter_property_id + nmos::fields::nc::transmission_status_pending, // status_pending_field_name + nmos::fields::nc::transmission_status_message_pending, // status_message_pending_field_name + nmos::fields::nc::transmission_status_pending_received_time, // status_pending_received_time_field_name + nc_transmission_status::status::inactive, // inactive_status + {}, // ignored_status + nc_transmission_status::status::healthy, // activation_status + U("Sender activated"), // activation_message + nc_transmission_status::status::inactive, // deactivation_status + U("Sender deactivated") // deactivation_message + }, + // Link status + { + nc_sender_monitor_link_status_property_id, // status_property_id + nc_sender_monitor_link_status_message_property_id, // status_message_property_id + nc_sender_monitor_link_status_transition_counter_property_id, // status_transition_counter_property_id + nmos::fields::nc::link_status_pending, // status_pending_field_name + nmos::fields::nc::link_status_message_pending, // status_message_pending_field_name + nmos::fields::nc::link_status_pending_received_time // status_pending_received_time_field_name + } + }; + } + namespace details { nmos::experimental::control_protocol_method_handler make_nc_get_handler(get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor) @@ -258,11 +374,11 @@ namespace nmos return nc::get_late_packet_counters(resources, resource, arguments, is_deprecated, get_late_packet_counters, gate); }; } - nmos::experimental::control_protocol_method_handler make_nc_reset_monitor_handler(get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, control_protocol_property_changed_handler property_changed, reset_monitor_handler reset_monitor) + nmos::experimental::control_protocol_method_handler make_nc_reset_monitor_handler(get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_monitor_domains_handler get_monitor_domains, control_protocol_property_changed_handler property_changed, reset_monitor_handler reset_monitor) { - return [get_control_protocol_class_descriptor, property_changed, reset_monitor](nmos::resources& resources, const nmos::resource& resource, const web::json::value& arguments, bool is_deprecated, slog::base_gate& gate) + return [get_control_protocol_class_descriptor, get_monitor_domains, property_changed, reset_monitor](nmos::resources& resources, const nmos::resource& resource, const web::json::value& arguments, bool is_deprecated, slog::base_gate& gate) { - return nc::reset_monitor(resources, resource, arguments, is_deprecated, get_control_protocol_class_descriptor, property_changed, reset_monitor, gate); + return nc::reset_monitor(resources, resource, arguments, is_deprecated, get_control_protocol_class_descriptor, property_changed, reset_monitor, get_monitor_domains, gate); }; } } @@ -297,6 +413,7 @@ namespace nmos }; auto get_control_protocol_class_descriptor = make_get_control_protocol_class_descriptor_handler(*this); + auto get_monitor_domains = make_get_monitor_domains_handler(*this); auto get_control_protocol_datatype_descriptor = make_get_control_protocol_datatype_descriptor_handler(*this); // setup the standard control classes @@ -405,7 +522,7 @@ namespace nmos // link NcReceiverMonitor method_ids with method functions { nc_receiver_monitor_get_lost_packet_counters_method_id, details::make_nc_get_lost_packet_counters_handler(get_lost_packet_counters)}, { nc_receiver_monitor_get_late_packet_counters_method_id, details::make_nc_get_late_packet_counters_handler(get_late_packet_counters)}, - { nc_receiver_monitor_reset_monitor_method_id, details::make_nc_reset_monitor_handler(get_control_protocol_class_descriptor, property_changed, reset_monitor)} + { nc_receiver_monitor_reset_monitor_method_id, details::make_nc_reset_monitor_handler(get_control_protocol_class_descriptor, get_monitor_domains, property_changed, reset_monitor)} }), // NcReceiverMonitor events to_vector(nc::make_receiver_monitor_events())) }, @@ -418,7 +535,7 @@ namespace nmos { // link NcSenderMonitor method_ids with method functions { nc_sender_monitor_get_transmission_error_counters_method_id, details::make_nc_get_lost_packet_counters_handler(get_lost_packet_counters)}, - { nc_sender_monitor_reset_monitor_method_id, details::make_nc_reset_monitor_handler(get_control_protocol_class_descriptor, property_changed, reset_monitor)} + { nc_sender_monitor_reset_monitor_method_id, details::make_nc_reset_monitor_handler(get_control_protocol_class_descriptor, get_monitor_domains, property_changed, reset_monitor)} }), // NcSenderMonitor events to_vector(nc::make_sender_monitor_events())) }, @@ -434,6 +551,13 @@ namespace nmos to_vector(nc::make_bulk_properties_manager_events())) } }; + // Private status-domain metadata for standard BCP-008 monitor classes + monitor_domain_profiles = + { + { nc_receiver_monitor_class_id, make_receiver_monitor_domains() }, + { nc_sender_monitor_class_id, make_sender_monitor_domains() } + }; + // setup the standard datatypes datatype_descriptors = { @@ -586,5 +710,43 @@ namespace nmos } return false; } + + bool control_protocol_state::insert(const nc_class_id& class_id, const std::vector& monitor_domains) + { + auto lock = write_lock(); + + if (monitor_domain_profiles.end() == monitor_domain_profiles.find(class_id)) + { + monitor_domain_profiles[class_id] = monitor_domains; + return true; + } + return false; + } + + bool control_protocol_state::erase_monitor_domains(const nc_class_id& class_id) + { + auto lock = write_lock(); + return 0 < monitor_domain_profiles.erase(class_id); + } + } + + get_monitor_domains_handler make_get_monitor_domains_handler(experimental::control_protocol_state& control_protocol_state) + { + return [&](const nc_class_id& class_id) + { + std::vector monitor_domains; + auto lock = control_protocol_state.read_lock(); + + for (size_t class_id_size = 1; class_id_size <= class_id.size(); ++class_id_size) + { + const nc_class_id ancestor_class_id(class_id.begin(), class_id.begin() + class_id_size); + const auto found = control_protocol_state.monitor_domain_profiles.find(ancestor_class_id); + if (control_protocol_state.monitor_domain_profiles.end() != found) + { + monitor_domains.insert(monitor_domains.end(), found->second.begin(), found->second.end()); + } + } + return monitor_domains; + }; } } \ No newline at end of file diff --git a/Development/nmos/control_protocol_state.h b/Development/nmos/control_protocol_state.h index d0b13fcf..1d67068a 100644 --- a/Development/nmos/control_protocol_state.h +++ b/Development/nmos/control_protocol_state.h @@ -2,6 +2,7 @@ #define NMOS_CONTROL_PROTOCOL_STATE_H #include +#include "bst/optional.h" #include "cpprest/json_utils.h" #include "nmos/configuration_handlers.h" #include "nmos/control_protocol_handlers.h" @@ -14,6 +15,46 @@ namespace nmos { namespace experimental { + // Library-only metadata describing a status domain. + // This is not included in the NcClassDescriptor exposed by the control protocol. + struct monitor_domain + { + // Status values which contribute to overall status must use NcOverallStatus-compatible values. + nc_property_id status_property_id; + nc_property_id status_message_property_id; + nc_property_id status_transition_counter_property_id; + utility::string_t status_pending_field_name; + utility::string_t status_message_pending_field_name; + utility::string_t status_pending_received_time_field_name; + // A matching inactive status forces the overall status to Inactive. + bst::optional inactive_status; + // A matching ignored status is neutral and is omitted from the overall status calculation. + bst::optional ignored_status; + bst::optional activation_status; + utility::string_t activation_message; + bst::optional deactivation_status; + utility::string_t deactivation_message; + + monitor_domain(const nc_property_id& status_property_id, const nc_property_id& status_message_property_id, const nc_property_id& status_transition_counter_property_id, + const utility::string_t& status_pending_field_name, const utility::string_t& status_message_pending_field_name, const utility::string_t& status_pending_received_time_field_name, + const bst::optional& inactive_status = {}, const bst::optional& ignored_status = {}, + const bst::optional& activation_status = {}, const utility::string_t& activation_message = {}, + const bst::optional& deactivation_status = {}, const utility::string_t& deactivation_message = {}) + : status_property_id(status_property_id) + , status_message_property_id(status_message_property_id) + , status_transition_counter_property_id(status_transition_counter_property_id) + , status_pending_field_name(status_pending_field_name) + , status_message_pending_field_name(status_message_pending_field_name) + , status_pending_received_time_field_name(status_pending_received_time_field_name) + , inactive_status(inactive_status) + , ignored_status(ignored_status) + , activation_status(activation_status) + , activation_message(activation_message) + , deactivation_status(deactivation_status) + , deactivation_message(deactivation_message) + {} + }; + struct control_class_descriptor // NcClassDescriptor { utility::string_t description; @@ -47,6 +88,7 @@ namespace nmos typedef std::map control_class_descriptors; typedef std::map datatype_descriptors; + typedef std::map> monitor_domain_profiles; struct control_protocol_state { @@ -59,6 +101,7 @@ namespace nmos experimental::control_class_descriptors control_class_descriptors; experimental::datatype_descriptors datatype_descriptors; + experimental::monitor_domain_profiles monitor_domain_profiles; nmos::read_lock read_lock() const { return nmos::read_lock{ mutex }; } nmos::write_lock write_lock() const { return nmos::write_lock{ mutex }; } @@ -73,8 +116,16 @@ namespace nmos 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); + + // insert monitor domains for the given class id, false if a profile already exists + bool insert(const nc_class_id& class_id, const std::vector& monitor_domains); + // erase monitor domains for the given class id, false if a profile was not found + bool erase_monitor_domains(const nc_class_id& class_id); }; + std::vector make_receiver_monitor_domains(); + std::vector make_sender_monitor_domains(); + // helper functions to create non-standard control class // @@ -98,6 +149,11 @@ namespace nmos 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); } + + typedef std::function(const nc_class_id& class_id)> get_monitor_domains_handler; + + // construct callback to retrieve monitor domains declared by a class and its ancestors + get_monitor_domains_handler make_get_monitor_domains_handler(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 c87f63d6..7ece9e13 100644 --- a/Development/nmos/control_protocol_utils.cpp +++ b/Development/nmos/control_protocol_utils.cpp @@ -393,6 +393,7 @@ namespace nmos const nc_property_id& status_transition_counter_property_id, const utility::string_t& status_pending_received_time_field_name, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, + get_monitor_domains_handler get_monitor_domains, slog::base_gate& gate) { auto current_connection_status = get_property(resources, oid, status_property_id, get_control_protocol_class_descriptor, gate); @@ -414,11 +415,7 @@ namespace nmos const auto found = find_resource(resources, utility::s2us(std::to_string(oid))); if (resources.end() != found) { - if (nmos::nc::is_sender_monitor(parse_class_id(nmos::fields::nc::class_id(found->data)))) - { - return details::update_sender_monitor_overall_status(resources, oid, get_control_protocol_class_descriptor, gate); - } - return details::update_receiver_monitor_overall_status(resources, oid, get_control_protocol_class_descriptor, gate); + return details::update_monitor_overall_status(resources, oid, get_control_protocol_class_descriptor, get_monitor_domains, gate); } return false; } @@ -434,6 +431,7 @@ namespace nmos long long now_time, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, + get_monitor_domains_handler get_monitor_domains, slog::base_gate& gate) { const auto& current_status = get_property(resources, oid, status_property_id, get_control_protocol_class_descriptor, gate); @@ -454,9 +452,10 @@ namespace nmos const auto& current_status_message = get_property(resources, oid, status_message_property_id, get_control_protocol_class_descriptor, gate); if ((current_status_message.is_null() && status_message.size()) || (!current_status_message.is_null() && current_status_message.as_string() != status_message)) { - // If the status message has changed then update only that + // If the status message has changed then update it and recalculate the overall status message web::json::value json_status_message = status_message.size() ? web::json::value::string(status_message) : web::json::value::null(); - return set_property_and_notify(resources, oid, status_message_property_id, json_status_message, get_control_protocol_class_descriptor, gate); + if (!set_property_and_notify(resources, oid, status_message_property_id, json_status_message, get_control_protocol_class_descriptor, gate)) return false; + return update_monitor_overall_status(resources, oid, get_control_protocol_class_descriptor, get_monitor_domains, gate); } // no update required, no changes on status or status message return true; @@ -482,7 +481,7 @@ namespace nmos // if status or current state is "inactive" (0), update status and status message immediately if (0 == status || 0 == current_status.as_integer()) { - return set_monitor_status(resources, oid, status, updated_status_message, status_property_id, status_message_property_id, status_transition_counter_property_id, status_pending_received_time_field_name, get_control_protocol_class_descriptor, gate); + return set_monitor_status(resources, oid, status, updated_status_message, status_property_id, status_message_property_id, status_transition_counter_property_id, status_pending_received_time_field_name, get_control_protocol_class_descriptor, get_monitor_domains, gate); } else { @@ -493,7 +492,7 @@ namespace nmos { // becoming less health and not in the initial activation state // immediately set the status - return set_monitor_status(resources, oid, status, updated_status_message, status_property_id, status_message_property_id, status_transition_counter_property_id, status_pending_received_time_field_name, get_control_protocol_class_descriptor, gate); + return set_monitor_status(resources, oid, status, updated_status_message, status_property_id, status_message_property_id, status_transition_counter_property_id, status_pending_received_time_field_name, get_control_protocol_class_descriptor, get_monitor_domains, gate); } else { @@ -547,80 +546,34 @@ namespace nmos return overall_status_message; } - bool update_receiver_monitor_overall_status(resources& resources, nc_oid oid, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate) + bool update_monitor_overall_status(resources& resources, nc_oid oid, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_monitor_domains_handler get_monitor_domains, slog::base_gate& gate) { - std::vector> status_message_property_ids = { - std::pair(nc_receiver_monitor_external_synchronization_status_property_id, nc_receiver_monitor_external_synchronization_status_message_property_id), - std::pair(nc_receiver_monitor_stream_status_property_id, nc_receiver_monitor_stream_status_message_property_id), - std::pair(nc_receiver_monitor_connection_status_property_id, nc_receiver_monitor_connection_status_message_property_id), - std::pair(nc_receiver_monitor_link_status_property_id, nc_receiver_monitor_link_status_message_property_id)}; - - // Update Overall Status - auto connection_status = get_property(resources, oid, nc_receiver_monitor_connection_status_property_id, get_control_protocol_class_descriptor, gate); - auto stream_status = get_property(resources, oid, nc_receiver_monitor_stream_status_property_id, get_control_protocol_class_descriptor, gate); - const auto& overall_status_message = get_overall_status_message(resources, oid, status_message_property_ids, get_control_protocol_class_descriptor, gate); - - // if connection or stream status is Inactive - if (nc_connection_status::status::inactive == connection_status.as_integer() || nc_stream_status::status::inactive == stream_status.as_integer()) - { - // Overall status is set to Inactive - bool success = set_property_and_notify(resources, oid, nc_status_monitor_overall_status_property_id, nc_overall_status::status::inactive, get_control_protocol_class_descriptor, gate); - return success && set_property_and_notify(resources, oid, nc_status_monitor_overall_status_message_property_id, overall_status_message, get_control_protocol_class_descriptor, gate); - } + const auto found = find_resource(resources, utility::s2us(std::to_string(oid))); + if (resources.end() == found) return false; - auto link_status = get_property(resources, oid, nc_receiver_monitor_link_status_property_id, get_control_protocol_class_descriptor, gate); - auto external_synchronization_status = get_property(resources, oid, nc_receiver_monitor_external_synchronization_status_property_id, get_control_protocol_class_descriptor, gate); + const auto class_id = parse_class_id(nmos::fields::nc::class_id(found->data)); + const auto monitor_domains = nmos::nc::get_monitor_domains(class_id, get_monitor_domains); + if (monitor_domains.empty()) return false; - // otherwise take the least healthy status as the overall status - std::vector statuses = {link_status.as_integer(), connection_status.as_integer(), stream_status.as_integer()}; + std::vector> status_message_property_ids; + std::vector statuses; + bool inactive = false; - // Ignore external synchronization status if it is not used - if (nc_synchronization_status::status::not_used != external_synchronization_status.as_integer()) + for (const auto& monitor_domain : monitor_domains) { - statuses.push_back(external_synchronization_status.as_integer()); - } - // Find most unhealthy status - auto overall_status = *std::max_element(statuses.begin(), statuses.end()); - bool success = set_property_and_notify(resources, oid, nc_status_monitor_overall_status_property_id, web::json::value::number(overall_status), get_control_protocol_class_descriptor, gate); - return success && set_property_and_notify(resources, oid, nc_status_monitor_overall_status_message_property_id, overall_status_message, get_control_protocol_class_descriptor, gate); - } - - bool update_sender_monitor_overall_status(resources& resources, nc_oid oid, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate) - { - std::vector> status_message_property_ids = { - std::pair(nc_sender_monitor_external_synchronization_status_property_id, nc_sender_monitor_external_synchronization_status_message_property_id), - std::pair(nc_sender_monitor_essence_status_property_id, nc_sender_monitor_essence_status_message_property_id), - std::pair(nc_sender_monitor_transmission_status_property_id, nc_sender_monitor_transmission_status_message_property_id), - std::pair(nc_sender_monitor_link_status_property_id, nc_sender_monitor_link_status_message_property_id)}; - - // Update Overall Status - auto transmission_status = get_property(resources, oid, nc_sender_monitor_transmission_status_property_id, get_control_protocol_class_descriptor, gate); - auto essence_status = get_property(resources, oid, nc_sender_monitor_essence_status_property_id, get_control_protocol_class_descriptor, gate); + status_message_property_ids.push_back({ monitor_domain.status_property_id, monitor_domain.status_message_property_id }); - const auto& overall_status_message = get_overall_status_message(resources, oid, status_message_property_ids, get_control_protocol_class_descriptor, gate); - - // if transmission or stream status is Inactive - if (nc_transmission_status::status::inactive == transmission_status.as_integer() || nc_essence_status::status::inactive == essence_status.as_integer()) - { - // Overall status is set to Inactive - bool success = set_property_and_notify(resources, oid, nc_status_monitor_overall_status_property_id, nc_overall_status::status::inactive, get_control_protocol_class_descriptor, gate); - return success && set_property_and_notify(resources, oid, nc_status_monitor_overall_status_message_property_id, overall_status_message, get_control_protocol_class_descriptor, gate); + const auto status = get_property(resources, oid, monitor_domain.status_property_id, get_control_protocol_class_descriptor, gate).as_integer(); + if (monitor_domain.inactive_status && *monitor_domain.inactive_status == status) inactive = true; + if (!monitor_domain.ignored_status || *monitor_domain.ignored_status != status) statuses.push_back(status); } - auto link_status = get_property(resources, oid, nc_receiver_monitor_link_status_property_id, get_control_protocol_class_descriptor, gate); - auto external_synchronization_status = get_property(resources, oid, nc_receiver_monitor_external_synchronization_status_property_id, get_control_protocol_class_descriptor, gate); - - // otherwise take the least healthy status as the overall status - std::vector statuses = {link_status.as_integer(), transmission_status.as_integer(), essence_status.as_integer()}; + const auto overall_status_message = get_overall_status_message(resources, oid, status_message_property_ids, get_control_protocol_class_descriptor, gate); + const auto overall_status = inactive + ? nc_overall_status::status::inactive + : statuses.empty() ? nc_overall_status::status::healthy : *std::max_element(statuses.begin(), statuses.end()); - // Ignore external synchronization status if it is not used - if (nc_synchronization_status::status::not_used != external_synchronization_status.as_integer()) - { - statuses.push_back(external_synchronization_status.as_integer()); - } - // Find most unhealthy status - auto overall_status = *std::max_element(statuses.begin(), statuses.end()); - bool success = set_property_and_notify(resources, oid, nc_status_monitor_overall_status_property_id, web::json::value::number(overall_status), get_control_protocol_class_descriptor, gate); + const auto success = set_property_and_notify(resources, oid, nc_status_monitor_overall_status_property_id, web::json::value::number(overall_status), get_control_protocol_class_descriptor, gate); return success && set_property_and_notify(resources, oid, nc_status_monitor_overall_status_message_property_id, overall_status_message, get_control_protocol_class_descriptor, gate); } } @@ -661,12 +614,26 @@ namespace nmos return details::is_control_class(nc_status_monitor_class_id, class_id); } - // is the given class_id a NcStatusMonitor + // is the given class_id a NcReceiverMonitor + bool is_receiver_monitor(const nc_class_id& class_id) + { + return details::is_control_class(nc_receiver_monitor_class_id, class_id); + } + + // is the given class_id a NcSenderMonitor bool is_sender_monitor(const nc_class_id& class_id) { return details::is_control_class(nc_sender_monitor_class_id, class_id); } + std::vector get_monitor_domains(const nc_class_id& class_id, get_monitor_domains_handler get_monitor_domains_) + { + if (get_monitor_domains_) return get_monitor_domains_(class_id); + if (is_sender_monitor(class_id)) return experimental::make_sender_monitor_domains(); + if (is_receiver_monitor(class_id)) return experimental::make_receiver_monitor_domains(); + return {}; + } + // construct NcClassId nc_class_id make_class_id(const nc_class_id& prefix, int32_t authority_key, const std::vector& suffix) { @@ -1198,6 +1165,36 @@ namespace nmos return web::json::value::null(); } + bool set_monitor_status(resources& resources, nc_oid oid, int status, const utility::string_t& status_message, const experimental::monitor_domain& domain, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_monitor_domains_handler get_monitor_domains, slog::base_gate& gate) + { + return details::set_monitor_status(resources, oid, status, status_message, + domain.status_property_id, + domain.status_message_property_id, + domain.status_transition_counter_property_id, + domain.status_pending_received_time_field_name, + get_control_protocol_class_descriptor, + get_monitor_domains, + gate); + } + + bool set_monitor_status_with_delay(resources& resources, nc_oid oid, int status, const utility::string_t& status_message, const experimental::monitor_domain& domain, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_monitor_domains_handler get_monitor_domains, slog::base_gate& gate) + { + const auto current_time = std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count(); + + return details::set_monitor_status_with_delay(resources, oid, status, status_message, + domain.status_property_id, + domain.status_message_property_id, + domain.status_transition_counter_property_id, + domain.status_pending_field_name, + domain.status_message_pending_field_name, + domain.status_pending_received_time_field_name, + current_time, + monitor_status_pending, + get_control_protocol_class_descriptor, + get_monitor_domains, + gate); + } + // Set link status and link status message bool set_receiver_monitor_link_status(resources& resources, nc_oid oid, nmos::nc_link_status::status link_status, const utility::string_t& link_status_message, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate) { @@ -1207,10 +1204,11 @@ namespace nmos nc_receiver_monitor_link_status_transition_counter_property_id, nmos::fields::nc::link_status_pending_received_time, get_control_protocol_class_descriptor, + {}, gate); } - bool set_receiver_monitor_link_status_with_delay(resources& resources, nc_oid oid, nmos::nc_link_status::status link_status, const utility::string_t& link_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate) + bool set_receiver_monitor_link_status_with_delay(resources& resources, nc_oid oid, nmos::nc_link_status::status link_status, const utility::string_t& link_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_monitor_domains_handler get_monitor_domains, slog::base_gate& gate) { const auto now_time = std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count(); @@ -1224,6 +1222,7 @@ namespace nmos now_time, monitor_status_pending, get_control_protocol_class_descriptor, + get_monitor_domains, gate); } @@ -1235,10 +1234,11 @@ namespace nmos nc_receiver_monitor_connection_status_transition_counter_property_id, nmos::fields::nc::connection_status_pending_received_time, get_control_protocol_class_descriptor, + {}, gate); } - bool set_receiver_monitor_connection_status_with_delay(resources& resources, nc_oid oid, nmos::nc_connection_status::status connection_status, const utility::string_t& connection_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate) + bool set_receiver_monitor_connection_status_with_delay(resources& resources, nc_oid oid, nmos::nc_connection_status::status connection_status, const utility::string_t& connection_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_monitor_domains_handler get_monitor_domains, slog::base_gate& gate) { const auto now_time = std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count(); @@ -1252,6 +1252,7 @@ namespace nmos now_time, monitor_status_pending, get_control_protocol_class_descriptor, + get_monitor_domains, gate); } @@ -1264,10 +1265,11 @@ namespace nmos nc_receiver_monitor_external_synchronization_status_transition_counter_property_id, nmos::fields::nc::external_synchronization_status_pending_received_time, get_control_protocol_class_descriptor, + {}, gate); } - bool set_receiver_monitor_external_synchronization_status_with_delay(resources& resources, nc_oid oid, nmos::nc_synchronization_status::status external_synchronization_status, const utility::string_t& external_synchronization_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate) + bool set_receiver_monitor_external_synchronization_status_with_delay(resources& resources, nc_oid oid, nmos::nc_synchronization_status::status external_synchronization_status, const utility::string_t& external_synchronization_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_monitor_domains_handler get_monitor_domains, slog::base_gate& gate) { const auto now_time = std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count(); @@ -1281,6 +1283,7 @@ namespace nmos now_time, monitor_status_pending, get_control_protocol_class_descriptor, + get_monitor_domains, gate); } @@ -1293,10 +1296,11 @@ namespace nmos nc_receiver_monitor_stream_status_transition_counter_property_id, nmos::fields::nc::stream_status_pending_received_time, get_control_protocol_class_descriptor, + {}, gate); } - bool set_receiver_monitor_stream_status_with_delay(resources& resources, nc_oid oid, nmos::nc_stream_status::status stream_status, const utility::string_t& stream_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate) + bool set_receiver_monitor_stream_status_with_delay(resources& resources, nc_oid oid, nmos::nc_stream_status::status stream_status, const utility::string_t& stream_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_monitor_domains_handler get_monitor_domains, slog::base_gate& gate) { const auto now_time = std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count(); @@ -1310,6 +1314,7 @@ namespace nmos now_time, monitor_status_pending, get_control_protocol_class_descriptor, + get_monitor_domains, gate); } @@ -1320,7 +1325,7 @@ namespace nmos return set_property_and_notify(resources, oid, nc_receiver_monitor_synchronization_source_id_property_id, source_id, get_control_protocol_class_descriptor, gate); } - bool activate_monitor(resources& resources, nc_oid oid, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, nmos::get_control_protocol_method_descriptor_handler get_control_protocol_method_descriptor, slog::base_gate& gate) + bool activate_monitor(resources& resources, nc_oid oid, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, nmos::get_control_protocol_method_descriptor_handler get_control_protocol_method_descriptor, get_monitor_domains_handler get_monitor_domains_, slog::base_gate& gate) { // A monitor is expected to go through a period of instability upon activation. Therefore, on monitor activation // domain specific statuses offering an Inactive option MUST transition immediately to the Healthy state. @@ -1336,20 +1341,20 @@ namespace nmos // If autoResetCountersAndMessages set to true then reset the transition counters bool auto_reset_monitor{false}; - if (nc::is_sender_monitor(class_id)) - { - if (succeed) succeed = set_sender_monitor_transmission_status(resources, oid, nmos::nc_transmission_status::status::healthy, U("Sender activated"), get_control_protocol_class_descriptor, gate); - if (succeed) succeed = set_sender_monitor_essence_status(resources, oid, nmos::nc_essence_status::status::healthy, U("Sender activated"), get_control_protocol_class_descriptor, gate); - } - else + const auto monitor_domains = get_monitor_domains(class_id, get_monitor_domains_); + for (auto monitor_domain_iterator = monitor_domains.rbegin(); monitor_domain_iterator != monitor_domains.rend(); ++monitor_domain_iterator) { - if (succeed) succeed = set_receiver_monitor_connection_status(resources, oid, nmos::nc_connection_status::status::healthy, U("Receiver activated"), get_control_protocol_class_descriptor, gate); - if (succeed) succeed = set_receiver_monitor_stream_status(resources, oid, nmos::nc_stream_status::status::healthy, U("Receiver activated"), get_control_protocol_class_descriptor, gate); + if (succeed && monitor_domain_iterator->activation_status) + { + succeed = set_monitor_status(resources, oid, *monitor_domain_iterator->activation_status, monitor_domain_iterator->activation_message, *monitor_domain_iterator, get_control_protocol_class_descriptor, get_monitor_domains_, gate); + } } - if (succeed) + const auto sender_monitor = nc::is_sender_monitor(class_id); + const auto receiver_monitor = nc::is_receiver_monitor(class_id); + if (succeed && (sender_monitor || receiver_monitor)) { - auto auto_reset_property_id = nc::is_sender_monitor(class_id) ? nmos::nc_sender_monitor_auto_reset_monitor_property_id : nmos::nc_receiver_monitor_auto_reset_monitor_property_id; + auto auto_reset_property_id = sender_monitor ? nmos::nc_sender_monitor_auto_reset_monitor_property_id : nmos::nc_receiver_monitor_auto_reset_monitor_property_id; auto auto_reset_monitor_ = get_property(resources, oid, auto_reset_property_id, get_control_protocol_class_descriptor, gate); if (auto_reset_monitor_.is_null()) succeed = false; else auto_reset_monitor = auto_reset_monitor_.as_bool(); @@ -1357,7 +1362,7 @@ namespace nmos if (succeed && auto_reset_monitor) { - auto reset_monitor_method_id = nc::is_sender_monitor(class_id) ? nmos::nc_sender_monitor_reset_monitor_method_id : nmos::nc_receiver_monitor_reset_monitor_method_id; + auto reset_monitor_method_id = sender_monitor ? nmos::nc_sender_monitor_reset_monitor_method_id : nmos::nc_receiver_monitor_reset_monitor_method_id; // find the method_handler for the reset monitor method auto method = get_control_protocol_method_descriptor(class_id, reset_monitor_method_id); auto& nc_method_descriptor = method.first; @@ -1383,7 +1388,7 @@ namespace nmos return false; } - bool deactivate_monitor(resources& resources, nc_oid oid, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate) + bool deactivate_monitor(resources& resources, nc_oid oid, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_monitor_domains_handler get_monitor_domains_, slog::base_gate& gate) { const auto found = find_resource(resources, utility::s2us(std::to_string(oid))); if (resources.end() != found && nc::is_status_monitor(nc::details::parse_class_id(nmos::fields::nc::class_id(found->data)))) @@ -1392,15 +1397,13 @@ namespace nmos auto succeed = set_property(resources, oid, nmos::fields::nc::monitor_activation_time, web::json::value::number(0), gate); - if (nc::is_sender_monitor(class_id)) + const auto monitor_domains = get_monitor_domains(class_id, get_monitor_domains_); + for (auto monitor_domain_iterator = monitor_domains.rbegin(); monitor_domain_iterator != monitor_domains.rend(); ++monitor_domain_iterator) { - if (succeed) succeed = set_sender_monitor_transmission_status(resources, oid, nmos::nc_transmission_status::status::inactive, U("Sender deactivated"), get_control_protocol_class_descriptor, gate); - if (succeed) succeed = set_sender_monitor_essence_status(resources, oid, nmos::nc_essence_status::status::inactive, U("Sender deactivated"), get_control_protocol_class_descriptor, gate); - } - else - { - if (succeed) succeed = set_receiver_monitor_connection_status(resources, oid, nmos::nc_connection_status::status::inactive, U("Receiver deactivated"), get_control_protocol_class_descriptor, gate); - if (succeed) succeed = set_receiver_monitor_stream_status(resources, oid, nmos::nc_stream_status::status::inactive, U("Receiver deactivated"), get_control_protocol_class_descriptor, gate); + if (succeed && monitor_domain_iterator->deactivation_status) + { + succeed = set_monitor_status(resources, oid, *monitor_domain_iterator->deactivation_status, monitor_domain_iterator->deactivation_message, *monitor_domain_iterator, get_control_protocol_class_descriptor, get_monitor_domains_, gate); + } } return succeed; } @@ -1421,10 +1424,11 @@ namespace nmos nc_sender_monitor_link_status_transition_counter_property_id, nmos::fields::nc::link_status_pending_received_time, get_control_protocol_class_descriptor, + {}, gate); } // Set link status and status message and apply status reporting delay - bool set_sender_monitor_link_status_with_delay(resources& resources, nc_oid oid, nmos::nc_link_status::status link_status, const utility::string_t& link_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate) + bool set_sender_monitor_link_status_with_delay(resources& resources, nc_oid oid, nmos::nc_link_status::status link_status, const utility::string_t& link_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_monitor_domains_handler get_monitor_domains, slog::base_gate& gate) { const auto now_time = std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count(); @@ -1438,6 +1442,7 @@ namespace nmos now_time, monitor_status_pending, get_control_protocol_class_descriptor, + get_monitor_domains, gate); } @@ -1450,10 +1455,11 @@ namespace nmos nc_sender_monitor_transmission_status_transition_counter_property_id, nmos::fields::nc::connection_status_pending_received_time, get_control_protocol_class_descriptor, + {}, gate); } // Set transmission status and status message and apply status reporting delay - bool set_sender_monitor_transmission_status_with_delay(resources& resources, nc_oid oid, nmos::nc_transmission_status::status transmission_status, const utility::string_t& transmission_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate) + bool set_sender_monitor_transmission_status_with_delay(resources& resources, nc_oid oid, nmos::nc_transmission_status::status transmission_status, const utility::string_t& transmission_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_monitor_domains_handler get_monitor_domains, slog::base_gate& gate) { const auto now_time = std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count(); @@ -1467,6 +1473,7 @@ namespace nmos now_time, monitor_status_pending, get_control_protocol_class_descriptor, + get_monitor_domains, gate); } @@ -1479,10 +1486,11 @@ namespace nmos nc_sender_monitor_external_synchronization_status_transition_counter_property_id, nmos::fields::nc::external_synchronization_status_pending_received_time, get_control_protocol_class_descriptor, + {}, gate); } // Set external synchronization status and status message and apply status reporting delay - bool set_sender_monitor_external_synchronization_status_with_delay(resources& resources, nc_oid oid, nmos::nc_synchronization_status::status external_synchronization_status, const utility::string_t& external_synchronization_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate) + bool set_sender_monitor_external_synchronization_status_with_delay(resources& resources, nc_oid oid, nmos::nc_synchronization_status::status external_synchronization_status, const utility::string_t& external_synchronization_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_monitor_domains_handler get_monitor_domains, slog::base_gate& gate) { const auto now_time = std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count(); @@ -1496,6 +1504,7 @@ namespace nmos now_time, monitor_status_pending, get_control_protocol_class_descriptor, + get_monitor_domains, gate); } @@ -1508,10 +1517,11 @@ namespace nmos nc_sender_monitor_essence_status_transition_counter_property_id, nmos::fields::nc::stream_status_pending_received_time, get_control_protocol_class_descriptor, + {}, gate); } // Set essence status and status message and apply status reporting delay - bool set_sender_monitor_essence_status_with_delay(resources& resources, nc_oid oid, nmos::nc_essence_status::status essence_status, const utility::string_t& essence_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate) + bool set_sender_monitor_essence_status_with_delay(resources& resources, nc_oid oid, nmos::nc_essence_status::status essence_status, const utility::string_t& essence_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_monitor_domains_handler get_monitor_domains, slog::base_gate& gate) { const auto now_time = std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count(); @@ -1525,6 +1535,7 @@ namespace nmos now_time, monitor_status_pending, get_control_protocol_class_descriptor, + get_monitor_domains, gate); } } diff --git a/Development/nmos/control_protocol_utils.h b/Development/nmos/control_protocol_utils.h index 517bf2a9..e63f250e 100644 --- a/Development/nmos/control_protocol_utils.h +++ b/Development/nmos/control_protocol_utils.h @@ -3,6 +3,7 @@ #include "cpprest/basic_utils.h" #include "nmos/control_protocol_handlers.h" +#include "nmos/control_protocol_state.h" namespace nmos { @@ -46,7 +47,19 @@ namespace nmos const nc_property_id& status_transition_counter_property_id, const utility::string_t& status_pending_received_time_field_name, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, - slog::base_gate& gate); + get_monitor_domains_handler get_monitor_domains, + slog::base_gate& gate); + // Deprecated: use the overload with get_monitor_domains_handler to include custom monitor domains + inline bool set_monitor_status(resources& resources, nc_oid oid, int status, const utility::string_t& status_message, const nc_property_id& status_property_id, + const nc_property_id& status_message_property_id, + const nc_property_id& status_transition_counter_property_id, + const utility::string_t& status_pending_received_time_field_name, + get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, + slog::base_gate& gate) + { + return set_monitor_status(resources, oid, status, status_message, status_property_id, status_message_property_id, + status_transition_counter_property_id, status_pending_received_time_field_name, get_control_protocol_class_descriptor, {}, gate); + } bool set_monitor_status_with_delay(resources& resources, nc_oid oid, int status, const utility::string_t& status_message, const nc_property_id& status_property_id, const nc_property_id& status_message_property_id, @@ -57,9 +70,36 @@ namespace nmos long long current_time, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, - slog::base_gate& gate); - bool update_receiver_monitor_overall_status(resources& resources, nc_oid oid, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate); - bool update_sender_monitor_overall_status(resources& resources, nc_oid oid, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate); + get_monitor_domains_handler get_monitor_domains, + slog::base_gate& gate); + // Deprecated: use the overload with get_monitor_domains_handler to include custom monitor domains + inline bool set_monitor_status_with_delay(resources& resources, nc_oid oid, int status, const utility::string_t& status_message, + const nc_property_id& status_property_id, + const nc_property_id& status_message_property_id, + const nc_property_id& status_transition_counter_property_id, + const utility::string_t& status_pending_field_name, + const utility::string_t& status_message_pending_time_field_name, + const utility::string_t& status_pending_received_time_field_name, + long long current_time, + monitor_status_pending_handler monitor_status_pending, + get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, + slog::base_gate& gate) + { + return set_monitor_status_with_delay(resources, oid, status, status_message, status_property_id, status_message_property_id, + status_transition_counter_property_id, status_pending_field_name, status_message_pending_time_field_name, + status_pending_received_time_field_name, current_time, monitor_status_pending, get_control_protocol_class_descriptor, {}, gate); + } + bool update_monitor_overall_status(resources& resources, nc_oid oid, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_monitor_domains_handler get_monitor_domains, slog::base_gate& gate); + // Deprecated: use update_monitor_overall_status with get_monitor_domains_handler to include custom monitor domains + inline bool update_receiver_monitor_overall_status(resources& resources, nc_oid oid, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate) + { + return update_monitor_overall_status(resources, oid, get_control_protocol_class_descriptor, {}, gate); + } + // Deprecated: use update_monitor_overall_status with get_monitor_domains_handler to include custom monitor domains + inline bool update_sender_monitor_overall_status(resources& resources, nc_oid oid, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate) + { + return update_monitor_overall_status(resources, oid, get_control_protocol_class_descriptor, {}, gate); + } } // is the given class_id a NcBlock @@ -80,9 +120,15 @@ namespace nmos // is the given class_id a NcStatusMonitor bool is_status_monitor(const nc_class_id& class_id); + // is the given class_id a NcReceiverMonitor + bool is_receiver_monitor(const nc_class_id& class_id); + // is the given class_id a NcSenderMonitor bool is_sender_monitor(const nc_class_id& class_id); + // get status domains declared by the given class and its ancestors + std::vector get_monitor_domains(const nc_class_id& class_id, get_monitor_domains_handler get_monitor_domains = {}); + // construct NcClassId nc_class_id make_class_id(const nc_class_id& prefix, int32_t authority_key, const std::vector& suffix); nc_class_id make_class_id(const nc_class_id& prefix, const std::vector& suffix); // using default authority_key 0 @@ -143,53 +189,118 @@ namespace nmos // set hidden property but don't notify, as property isn't part of class definition bool set_property(resources& resources, nc_oid oid, const utility::string_t& property_name, const web::json::value& value, slog::base_gate& gate); + // Set a user-defined monitor domain status + bool set_monitor_status(resources& resources, nc_oid oid, int status, const utility::string_t& status_message, const experimental::monitor_domain& domain, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_monitor_domains_handler get_monitor_domains, slog::base_gate& gate); + // Deprecated: use the overload with get_monitor_domains_handler to include custom monitor domains + inline bool set_monitor_status(resources& resources, nc_oid oid, int status, const utility::string_t& status_message, const experimental::monitor_domain& domain, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate) + { + return set_monitor_status(resources, oid, status, status_message, domain, get_control_protocol_class_descriptor, {}, gate); + } + // Set a user-defined monitor domain status and apply status reporting delay + bool set_monitor_status_with_delay(resources& resources, nc_oid oid, int status, const utility::string_t& status_message, const experimental::monitor_domain& domain, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_monitor_domains_handler get_monitor_domains, slog::base_gate& gate); + // Deprecated: use the overload with get_monitor_domains_handler to include custom monitor domains + inline bool set_monitor_status_with_delay(resources& resources, nc_oid oid, int status, const utility::string_t& status_message, const experimental::monitor_domain& domain, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate) + { + return set_monitor_status_with_delay(resources, oid, status, status_message, domain, monitor_status_pending, get_control_protocol_class_descriptor, {}, gate); + } + // Set link status and link status message bool set_receiver_monitor_link_status(resources& resources, nc_oid oid, nmos::nc_link_status::status link_status, const utility::string_t& link_status_message, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate); // Set link status and status message and apply status reporting delay - bool set_receiver_monitor_link_status_with_delay(resources& resources, nc_oid oid, nmos::nc_link_status::status link_status, const utility::string_t& link_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate); + bool set_receiver_monitor_link_status_with_delay(resources& resources, nc_oid oid, nmos::nc_link_status::status link_status, const utility::string_t& link_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_monitor_domains_handler get_monitor_domains, slog::base_gate& gate); + // Deprecated: use the overload with get_monitor_domains_handler to include custom monitor domains + inline bool set_receiver_monitor_link_status_with_delay(resources& resources, nc_oid oid, nmos::nc_link_status::status link_status, const utility::string_t& link_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate) + { + return set_receiver_monitor_link_status_with_delay(resources, oid, link_status, link_status_message, monitor_status_pending, get_control_protocol_class_descriptor, {}, gate); + } // Set connection status and connection status message bool set_receiver_monitor_connection_status(resources& resources, nc_oid oid, nmos::nc_connection_status::status connection_status, const utility::string_t& connection_status_message, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate); // Set connection status and status message and apply status reporting delay - bool set_receiver_monitor_connection_status_with_delay(resources& resources, nc_oid oid, nmos::nc_connection_status::status connection_status, const utility::string_t& connection_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate); + bool set_receiver_monitor_connection_status_with_delay(resources& resources, nc_oid oid, nmos::nc_connection_status::status connection_status, const utility::string_t& connection_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_monitor_domains_handler get_monitor_domains, slog::base_gate& gate); + // Deprecated: use the overload with get_monitor_domains_handler to include custom monitor domains + inline bool set_receiver_monitor_connection_status_with_delay(resources& resources, nc_oid oid, nmos::nc_connection_status::status connection_status, const utility::string_t& connection_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate) + { + return set_receiver_monitor_connection_status_with_delay(resources, oid, connection_status, connection_status_message, monitor_status_pending, get_control_protocol_class_descriptor, {}, gate); + } // Set external synchronization status and external synchronization status message bool set_receiver_monitor_external_synchronization_status(resources& resources, nc_oid oid, nmos::nc_synchronization_status::status external_synchronization_status, const utility::string_t& external_synchronization_status_message, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate); // Set external synchronization status and status message and apply status reporting delay - bool set_receiver_monitor_external_synchronization_status_with_delay(resources& resources, nc_oid oid, nmos::nc_synchronization_status::status external_synchronization_status, const utility::string_t& external_synchronization_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate); + bool set_receiver_monitor_external_synchronization_status_with_delay(resources& resources, nc_oid oid, nmos::nc_synchronization_status::status external_synchronization_status, const utility::string_t& external_synchronization_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_monitor_domains_handler get_monitor_domains, slog::base_gate& gate); + // Deprecated: use the overload with get_monitor_domains_handler to include custom monitor domains + inline bool set_receiver_monitor_external_synchronization_status_with_delay(resources& resources, nc_oid oid, nmos::nc_synchronization_status::status external_synchronization_status, const utility::string_t& external_synchronization_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate) + { + return set_receiver_monitor_external_synchronization_status_with_delay(resources, oid, external_synchronization_status, external_synchronization_status_message, monitor_status_pending, get_control_protocol_class_descriptor, {}, gate); + } // Set stream status and stream status message bool set_receiver_monitor_stream_status(resources& resources, nc_oid oid, nmos::nc_stream_status::status stream_status, const utility::string_t& stream_status_message, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate); // Set stream status and status message and apply status reporting delay - bool set_receiver_monitor_stream_status_with_delay(resources& resources, nc_oid oid, nmos::nc_stream_status::status stream_status, const utility::string_t& stream_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate); + bool set_receiver_monitor_stream_status_with_delay(resources& resources, nc_oid oid, nmos::nc_stream_status::status stream_status, const utility::string_t& stream_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_monitor_domains_handler get_monitor_domains, slog::base_gate& gate); + // Deprecated: use the overload with get_monitor_domains_handler to include custom monitor domains + inline bool set_receiver_monitor_stream_status_with_delay(resources& resources, nc_oid oid, nmos::nc_stream_status::status stream_status, const utility::string_t& stream_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate) + { + return set_receiver_monitor_stream_status_with_delay(resources, oid, stream_status, stream_status_message, monitor_status_pending, get_control_protocol_class_descriptor, {}, gate); + } // Set synchronization source id bool set_monitor_synchronization_source_id(resources& resources, nc_oid oid, const bst::optional& source_id, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate); // Call when monitor is activated - bool activate_monitor(resources& resources, nc_oid oid, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, nmos::get_control_protocol_method_descriptor_handler get_control_protocol_method_descriptor, slog::base_gate& gate); + bool activate_monitor(resources& resources, nc_oid oid, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, nmos::get_control_protocol_method_descriptor_handler get_control_protocol_method_descriptor, get_monitor_domains_handler get_monitor_domains, slog::base_gate& gate); + // Deprecated: use the overload with get_monitor_domains_handler to include custom monitor domains + inline bool activate_monitor(resources& resources, nc_oid oid, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, nmos::get_control_protocol_method_descriptor_handler get_control_protocol_method_descriptor, slog::base_gate& gate) + { + return activate_monitor(resources, oid, get_control_protocol_class_descriptor, get_control_protocol_method_descriptor, {}, gate); + } // Call when monitor is deactivated - bool deactivate_monitor(resources& resources, nc_oid oid, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate); + bool deactivate_monitor(resources& resources, nc_oid oid, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_monitor_domains_handler get_monitor_domains, slog::base_gate& gate); + // Deprecated: use the overload with get_monitor_domains_handler to include custom monitor domains + inline bool deactivate_monitor(resources& resources, nc_oid oid, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate) + { + return deactivate_monitor(resources, oid, get_control_protocol_class_descriptor, {}, gate); + } // Set link status and link status message bool set_sender_monitor_link_status(resources& resources, nc_oid oid, nmos::nc_link_status::status link_status, const utility::string_t& link_status_message, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate); // Set link status and status message and apply status reporting delay - bool set_sender_monitor_link_status_with_delay(resources& resources, nc_oid oid, nmos::nc_link_status::status link_status, const utility::string_t& link_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate); + bool set_sender_monitor_link_status_with_delay(resources& resources, nc_oid oid, nmos::nc_link_status::status link_status, const utility::string_t& link_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_monitor_domains_handler get_monitor_domains, slog::base_gate& gate); + // Deprecated: use the overload with get_monitor_domains_handler to include custom monitor domains + inline bool set_sender_monitor_link_status_with_delay(resources& resources, nc_oid oid, nmos::nc_link_status::status link_status, const utility::string_t& link_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate) + { + return set_sender_monitor_link_status_with_delay(resources, oid, link_status, link_status_message, monitor_status_pending, get_control_protocol_class_descriptor, {}, gate); + } // Set transmission status and transmission status message bool set_sender_monitor_transmission_status(resources& resources, nc_oid oid, nmos::nc_transmission_status::status transmission_status, const utility::string_t& transmission_status_message, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate); // Set transmission status and status message and apply status reporting delay - bool set_sender_monitor_transmission_status_with_delay(resources& resources, nc_oid oid, nmos::nc_transmission_status::status transmission_status, const utility::string_t& transmission_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate); + bool set_sender_monitor_transmission_status_with_delay(resources& resources, nc_oid oid, nmos::nc_transmission_status::status transmission_status, const utility::string_t& transmission_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_monitor_domains_handler get_monitor_domains, slog::base_gate& gate); + // Deprecated: use the overload with get_monitor_domains_handler to include custom monitor domains + inline bool set_sender_monitor_transmission_status_with_delay(resources& resources, nc_oid oid, nmos::nc_transmission_status::status transmission_status, const utility::string_t& transmission_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate) + { + return set_sender_monitor_transmission_status_with_delay(resources, oid, transmission_status, transmission_status_message, monitor_status_pending, get_control_protocol_class_descriptor, {}, gate); + } // Set external synchronization status and external synchronization status message bool set_sender_monitor_external_synchronization_status(resources& resources, nc_oid oid, nmos::nc_synchronization_status::status external_synchronization_status, const utility::string_t& external_synchronization_status_message, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate); // Set external synchronization status and status message and apply status reporting delay - bool set_sender_monitor_external_synchronization_status_with_delay(resources& resources, nc_oid oid, nmos::nc_synchronization_status::status external_synchronization_status, const utility::string_t& external_synchronization_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate); + bool set_sender_monitor_external_synchronization_status_with_delay(resources& resources, nc_oid oid, nmos::nc_synchronization_status::status external_synchronization_status, const utility::string_t& external_synchronization_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_monitor_domains_handler get_monitor_domains, slog::base_gate& gate); + // Deprecated: use the overload with get_monitor_domains_handler to include custom monitor domains + inline bool set_sender_monitor_external_synchronization_status_with_delay(resources& resources, nc_oid oid, nmos::nc_synchronization_status::status external_synchronization_status, const utility::string_t& external_synchronization_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate) + { + return set_sender_monitor_external_synchronization_status_with_delay(resources, oid, external_synchronization_status, external_synchronization_status_message, monitor_status_pending, get_control_protocol_class_descriptor, {}, gate); + } // Set essence status and stream status message bool set_sender_monitor_essence_status(resources& resources, nc_oid oid, nmos::nc_essence_status::status essence_status, const utility::string_t& essence_status_message, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate); // Set essence status and status message and apply status reporting delay - bool set_sender_monitor_essence_status_with_delay(resources& resources, nc_oid oid, nmos::nc_essence_status::status essence_status, const utility::string_t& essence_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate); + bool set_sender_monitor_essence_status_with_delay(resources& resources, nc_oid oid, nmos::nc_essence_status::status essence_status, const utility::string_t& essence_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, get_monitor_domains_handler get_monitor_domains, slog::base_gate& gate); + // Deprecated: use the overload with get_monitor_domains_handler to include custom monitor domains + inline bool set_sender_monitor_essence_status_with_delay(resources& resources, nc_oid oid, nmos::nc_essence_status::status essence_status, const utility::string_t& essence_status_message, monitor_status_pending_handler monitor_status_pending, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, slog::base_gate& gate) + { + return set_sender_monitor_essence_status_with_delay(resources, oid, essence_status, essence_status_message, monitor_status_pending, get_control_protocol_class_descriptor, {}, gate); + } // Get property by name, rather than by property id. Used to get "hidden" resource properties web::json::value get_property(const resources& resources, nc_oid oid, const utility::string_t& property_name, slog::base_gate& gate); diff --git a/Development/nmos/test/control_protocol_utils_test.cpp b/Development/nmos/test/control_protocol_utils_test.cpp index 2ea90b5f..e314dc53 100644 --- a/Development/nmos/test/control_protocol_utils_test.cpp +++ b/Development/nmos/test/control_protocol_utils_test.cpp @@ -1,6 +1,7 @@ // The first "test" is of course whether the header compiles standalone #include "boost/iostreams/stream.hpp" #include "boost/iostreams/device/null.hpp" +#include "nmos/control_protocol_behaviour.h" #include "nmos/control_protocol_resource.h" #include "nmos/control_protocol_resources.h" #include "nmos/control_protocol_state.h" @@ -9,6 +10,7 @@ #include "nmos/is04_versions.h" #include "nmos/is12_versions.h" #include "nmos/log_gate.h" +#include "nmos/model.h" #include "nmos/slog.h" #include "bst/test/test.h" @@ -678,6 +680,196 @@ BST_TEST_CASE(testSetSenderMonitorStatuses) } } +////////////////////////////////////////////////////////////////////////////////////////////// +BST_TEST_CASE(testSetDerivedMonitorDomainStatus) +{ + using web::json::value; + + nmos::node_model model; + auto& resources = model.control_protocol_resources; + nmos::experimental::control_protocol_state control_protocol_state; + const auto get_control_protocol_class_descriptor = nmos::make_get_control_protocol_class_descriptor_handler(control_protocol_state); + const auto get_control_protocol_method_descriptor = nmos::make_get_control_protocol_method_descriptor_handler(control_protocol_state); + const auto get_monitor_domains = nmos::make_get_monitor_domains_handler(control_protocol_state); + const auto set_monitor_status_pending = nmos::make_monitor_status_pending_handler(control_protocol_state); + + boost::iostreams::stream< boost::iostreams::null_sink > null_ostream((boost::iostreams::null_sink())); + nmos::experimental::log_model log_model; + nmos::experimental::log_gate gate(null_ostream, null_ostream, log_model); + + const auto derived_monitor_class_id = nmos::nc::make_class_id(nmos::nc_receiver_monitor_class_id, -1234, { 1 }); + const nmos::nc_property_id custom_status_property_id{ 5, 1 }; + const nmos::nc_property_id custom_status_message_property_id{ 5, 2 }; + const nmos::nc_property_id custom_status_transition_counter_property_id{ 5, 3 }; + const utility::string_t custom_status_name{ U("customStatus") }; + const utility::string_t custom_status_message_name{ U("customStatusMessage") }; + const utility::string_t custom_status_transition_counter_name{ U("customStatusTransitionCounter") }; + const utility::string_t custom_status_pending_name{ U("customStatusPending") }; + const utility::string_t custom_status_message_pending_name{ U("customStatusMessagePending") }; + const utility::string_t custom_status_pending_received_time_name{ U("customStatusPendingReceivedTime") }; + + const nmos::experimental::monitor_domain custom_monitor_domain{ + custom_status_property_id, + custom_status_message_property_id, + custom_status_transition_counter_property_id, + custom_status_pending_name, + custom_status_message_pending_name, + custom_status_pending_received_time_name, + nmos::nc_overall_status::inactive, + {}, + nmos::nc_overall_status::healthy, + U("Custom monitor activated"), + nmos::nc_overall_status::inactive, + U("Custom monitor deactivated") + }; + + auto derived_monitor_class_descriptor = nmos::experimental::make_control_class_descriptor( + U("Derived receiver monitor"), + derived_monitor_class_id, + U("DerivedReceiverMonitor"), + { + nmos::experimental::make_control_class_property_descriptor(U("Custom status"), custom_status_property_id, custom_status_name, U("NcInt32"), true), + nmos::experimental::make_control_class_property_descriptor(U("Custom status message"), custom_status_message_property_id, custom_status_message_name, U("NcString"), true, true), + nmos::experimental::make_control_class_property_descriptor(U("Custom status transition counter"), custom_status_transition_counter_property_id, custom_status_transition_counter_name, U("NcUint64"), true) + }); + BST_REQUIRE(control_protocol_state.insert(derived_monitor_class_descriptor)); + BST_REQUIRE(control_protocol_state.insert(derived_monitor_class_id, { custom_monitor_domain })); + + auto root_block = nmos::make_root_block(); + auto monitor_data = nmos::nc::details::make_receiver_monitor( + derived_monitor_class_id, 2, true, nmos::root_block_oid, U("monitor"), U("monitor"), U("monitor"), value::null(), value::null(), true, + nmos::nc_overall_status::healthy, U(""), nmos::nc_link_status::all_up, U(""), nmos::nc_connection_status::healthy, U(""), + nmos::nc_synchronization_status::not_used, U(""), value::null(), nmos::nc_stream_status::healthy, U(""), 3, true); + monitor_data[custom_status_name] = value::number(nmos::nc_overall_status::healthy); + monitor_data[custom_status_message_name] = value::null(); + monitor_data[custom_status_transition_counter_name] = value::number(0); + monitor_data[custom_status_pending_name] = value::number(nmos::nc_overall_status::healthy); + monitor_data[custom_status_message_pending_name] = value::null(); + monitor_data[custom_status_pending_received_time_name] = value::number(0); + + nmos::control_protocol_resource monitor{ nmos::is12_versions::v1_0, nmos::types::nc_status_monitor, std::move(monitor_data), true }; + nmos::nc::push_back(root_block, monitor); + insert_resource(resources, std::move(root_block)); + insert_resource(resources, std::move(monitor)); + + const auto monitor_domains = nmos::nc::get_monitor_domains(derived_monitor_class_id, get_monitor_domains); + BST_CHECK_EQUAL(5, monitor_domains.size()); + + BST_REQUIRE(nmos::nc::set_monitor_status(resources, 2, nmos::nc_overall_status::unhealthy, U("Custom failure"), custom_monitor_domain, get_control_protocol_class_descriptor, get_monitor_domains, gate)); + const auto overall_status = nmos::nc::get_property(resources, 2, nmos::nc_status_monitor_overall_status_property_id, get_control_protocol_class_descriptor, gate); + BST_CHECK_EQUAL(nmos::nc_overall_status::unhealthy, overall_status.as_integer()); + const auto overall_status_message = nmos::nc::get_property(resources, 2, nmos::nc_status_monitor_overall_status_message_property_id, get_control_protocol_class_descriptor, gate); + BST_CHECK_EQUAL(U("Custom failure"), overall_status_message.as_string()); + + // BCP-008 permits the overall status message to change while overall status remains unchanged + bool monitor_status_pending = false; + BST_REQUIRE(nmos::nc::set_monitor_status_with_delay(resources, 2, nmos::nc_overall_status::unhealthy, U("Updated custom failure"), custom_monitor_domain, [&] { monitor_status_pending = true; set_monitor_status_pending(); }, get_control_protocol_class_descriptor, get_monitor_domains, gate)); + BST_CHECK(!monitor_status_pending); + const auto updated_overall_status_message = nmos::nc::get_property(resources, 2, nmos::nc_status_monitor_overall_status_message_property_id, get_control_protocol_class_descriptor, gate); + BST_CHECK_EQUAL(U("Updated custom failure"), updated_overall_status_message.as_string()); + + // Custom domains participate in monitor activation, deactivation and automatic reset + BST_REQUIRE(nmos::nc::deactivate_monitor(resources, 2, get_control_protocol_class_descriptor, get_monitor_domains, gate)); + BST_CHECK_EQUAL(nmos::nc_overall_status::inactive, nmos::nc::get_property(resources, 2, custom_status_property_id, get_control_protocol_class_descriptor, gate).as_integer()); + BST_CHECK_EQUAL(nmos::nc_overall_status::inactive, nmos::nc::get_property(resources, 2, nmos::nc_status_monitor_overall_status_property_id, get_control_protocol_class_descriptor, gate).as_integer()); + + BST_REQUIRE(nmos::nc::activate_monitor(resources, 2, get_control_protocol_class_descriptor, get_control_protocol_method_descriptor, get_monitor_domains, gate)); + BST_CHECK_EQUAL(nmos::nc_overall_status::healthy, nmos::nc::get_property(resources, 2, custom_status_property_id, get_control_protocol_class_descriptor, gate).as_integer()); + BST_CHECK_EQUAL(0, nmos::nc::get_property(resources, 2, custom_status_transition_counter_property_id, get_control_protocol_class_descriptor, gate).as_integer()); + BST_CHECK(nmos::nc::get_property(resources, 2, custom_status_message_property_id, get_control_protocol_class_descriptor, gate).is_null()); + + // The behaviour thread applies delayed custom-domain updates and recalculates overall status + BST_REQUIRE(nmos::nc::set_monitor_status(resources, 2, nmos::nc_overall_status::unhealthy, U("Custom failure"), custom_monitor_domain, get_control_protocol_class_descriptor, get_monitor_domains, gate)); + std::thread behaviour_thread([&model, &control_protocol_state, &gate] + { + nmos::experimental::control_protocol_behaviour_thread(model, control_protocol_state, gate); + }); + + monitor_status_pending = false; + BST_REQUIRE(nmos::nc::set_monitor_status_with_delay(resources, 2, nmos::nc_overall_status::healthy, U(""), custom_monitor_domain, [&] { monitor_status_pending = true; set_monitor_status_pending(); }, get_control_protocol_class_descriptor, get_monitor_domains, gate)); + BST_CHECK(monitor_status_pending); + BST_CHECK(nmos::nc::get_property(resources, 2, custom_status_pending_received_time_name, gate).as_integer() > 0); + BST_CHECK_EQUAL(nmos::nc_overall_status::unhealthy, nmos::nc::get_property(resources, 2, custom_status_property_id, get_control_protocol_class_descriptor, gate).as_integer()); + + model.notify(); + std::this_thread::sleep_for(std::chrono::seconds(4)); + BST_CHECK_EQUAL(nmos::nc_overall_status::healthy, nmos::nc::get_property(resources, 2, custom_status_property_id, get_control_protocol_class_descriptor, gate).as_integer()); + BST_CHECK_EQUAL(nmos::nc_overall_status::healthy, nmos::nc::get_property(resources, 2, nmos::nc_status_monitor_overall_status_property_id, get_control_protocol_class_descriptor, gate).as_integer()); + BST_CHECK_EQUAL(0, nmos::nc::get_property(resources, 2, custom_status_pending_received_time_name, gate).as_integer()); + + model.controlled_shutdown(); + behaviour_thread.join(); +} + +////////////////////////////////////////////////////////////////////////////////////////////// +BST_TEST_CASE(testSetDerivedSenderMonitorDomainStatus) +{ + using web::json::value; + + nmos::resources resources; + nmos::experimental::control_protocol_state control_protocol_state; + const auto get_control_protocol_class_descriptor = nmos::make_get_control_protocol_class_descriptor_handler(control_protocol_state); + const auto get_monitor_domains = nmos::make_get_monitor_domains_handler(control_protocol_state); + + boost::iostreams::stream< boost::iostreams::null_sink > null_ostream((boost::iostreams::null_sink())); + nmos::experimental::log_model log_model; + nmos::experimental::log_gate gate(null_ostream, null_ostream, log_model); + + const auto derived_monitor_class_id = nmos::nc::make_class_id(nmos::nc_sender_monitor_class_id, -1234, { 1 }); + const nmos::nc_property_id custom_status_property_id{ 5, 1 }; + const nmos::nc_property_id custom_status_message_property_id{ 5, 2 }; + const nmos::nc_property_id custom_status_transition_counter_property_id{ 5, 3 }; + const utility::string_t custom_status_name{ U("customStatus") }; + const utility::string_t custom_status_message_name{ U("customStatusMessage") }; + const utility::string_t custom_status_transition_counter_name{ U("customStatusTransitionCounter") }; + const utility::string_t custom_status_pending_name{ U("customStatusPending") }; + const utility::string_t custom_status_message_pending_name{ U("customStatusMessagePending") }; + const utility::string_t custom_status_pending_received_time_name{ U("customStatusPendingReceivedTime") }; + + const nmos::experimental::monitor_domain custom_monitor_domain{ + custom_status_property_id, + custom_status_message_property_id, + custom_status_transition_counter_property_id, + custom_status_pending_name, + custom_status_message_pending_name, + custom_status_pending_received_time_name + }; + + auto derived_monitor_class_descriptor = nmos::experimental::make_control_class_descriptor( + U("Derived sender monitor"), + derived_monitor_class_id, + U("DerivedSenderMonitor"), + { + nmos::experimental::make_control_class_property_descriptor(U("Custom status"), custom_status_property_id, custom_status_name, U("NcInt32"), true), + nmos::experimental::make_control_class_property_descriptor(U("Custom status message"), custom_status_message_property_id, custom_status_message_name, U("NcString"), true, true), + nmos::experimental::make_control_class_property_descriptor(U("Custom status transition counter"), custom_status_transition_counter_property_id, custom_status_transition_counter_name, U("NcUint64"), true) + }); + BST_REQUIRE(control_protocol_state.insert(derived_monitor_class_descriptor)); + BST_REQUIRE(control_protocol_state.insert(derived_monitor_class_id, { custom_monitor_domain })); + + auto root_block = nmos::make_root_block(); + auto monitor_data = nmos::nc::details::make_sender_monitor( + derived_monitor_class_id, 2, true, nmos::root_block_oid, U("monitor"), U("monitor"), U("monitor"), value::null(), value::null(), true, + nmos::nc_overall_status::healthy, U(""), nmos::nc_link_status::all_up, U(""), nmos::nc_transmission_status::healthy, U(""), + nmos::nc_synchronization_status::not_used, U(""), value::null(), nmos::nc_essence_status::healthy, U(""), 3, true); + monitor_data[custom_status_name] = value::number(nmos::nc_overall_status::healthy); + monitor_data[custom_status_message_name] = value::null(); + monitor_data[custom_status_transition_counter_name] = value::number(0); + monitor_data[custom_status_pending_name] = value::number(nmos::nc_overall_status::healthy); + monitor_data[custom_status_message_pending_name] = value::null(); + monitor_data[custom_status_pending_received_time_name] = value::number(0); + + nmos::control_protocol_resource monitor{ nmos::is12_versions::v1_0, nmos::types::nc_status_monitor, std::move(monitor_data), true }; + nmos::nc::push_back(root_block, monitor); + insert_resource(resources, std::move(root_block)); + insert_resource(resources, std::move(monitor)); + + BST_CHECK_EQUAL(5, nmos::nc::get_monitor_domains(derived_monitor_class_id, get_monitor_domains).size()); + BST_REQUIRE(nmos::nc::set_monitor_status(resources, 2, nmos::nc_overall_status::unhealthy, U("Custom sender failure"), custom_monitor_domain, get_control_protocol_class_descriptor, get_monitor_domains, gate)); + BST_CHECK_EQUAL(nmos::nc_overall_status::unhealthy, nmos::nc::get_property(resources, 2, nmos::nc_status_monitor_overall_status_property_id, get_control_protocol_class_descriptor, gate).as_integer()); + BST_CHECK_EQUAL(U("Custom sender failure"), nmos::nc::get_property(resources, 2, nmos::nc_status_monitor_overall_status_message_property_id, get_control_protocol_class_descriptor, gate).as_string()); +} + ////////////////////////////////////////////////////////////////////////////////////////////// BST_TEST_CASE(testActivateDeactivateSenderMonitor) { @@ -817,6 +1009,43 @@ BST_TEST_CASE(testActivateDeactivateSenderMonitor) } } +////////////////////////////////////////////////////////////////////////////////////////////// +BST_TEST_CASE(testDeprecatedMonitorStatusOverloads) +{ + nmos::resources resources; + nmos::experimental::control_protocol_state control_protocol_state; + const auto get_control_protocol_class_descriptor = nmos::make_get_control_protocol_class_descriptor_handler(control_protocol_state); + + boost::iostreams::stream< boost::iostreams::null_sink > null_ostream((boost::iostreams::null_sink())); + nmos::experimental::log_model log_model; + nmos::experimental::log_gate gate(null_ostream, null_ostream, log_model); + + auto root_block = nmos::make_root_block(); + auto receiver_monitor = nmos::make_receiver_monitor(2, true, nmos::root_block_oid, U("receiver"), U("receiver"), U("receiver"), web::json::value::null()); + auto sender_monitor = nmos::make_sender_monitor(3, true, nmos::root_block_oid, U("sender"), U("sender"), U("sender"), web::json::value::null()); + + nmos::nc::push_back(root_block, receiver_monitor); + nmos::nc::push_back(root_block, sender_monitor); + insert_resource(resources, std::move(root_block)); + insert_resource(resources, std::move(receiver_monitor)); + insert_resource(resources, std::move(sender_monitor)); + + bool monitor_status_pending = false; + BST_REQUIRE(nmos::nc::set_receiver_monitor_stream_status_with_delay(resources, 2, nmos::nc_stream_status::inactive, U("Receiver inactive"), + [&] { monitor_status_pending = true; }, get_control_protocol_class_descriptor, gate)); + BST_REQUIRE(nmos::nc::set_sender_monitor_essence_status_with_delay(resources, 3, nmos::nc_essence_status::inactive, U("Sender inactive"), + [&] { monitor_status_pending = true; }, get_control_protocol_class_descriptor, gate)); + + BST_CHECK(!monitor_status_pending); + BST_CHECK_EQUAL(nmos::nc_stream_status::inactive, nmos::nc::get_property(resources, 2, nmos::nc_receiver_monitor_stream_status_property_id, get_control_protocol_class_descriptor, gate).as_integer()); + BST_CHECK_EQUAL(nmos::nc_overall_status::inactive, nmos::nc::get_property(resources, 2, nmos::nc_status_monitor_overall_status_property_id, get_control_protocol_class_descriptor, gate).as_integer()); + BST_CHECK_EQUAL(nmos::nc_essence_status::inactive, nmos::nc::get_property(resources, 3, nmos::nc_sender_monitor_essence_status_property_id, get_control_protocol_class_descriptor, gate).as_integer()); + BST_CHECK_EQUAL(nmos::nc_overall_status::inactive, nmos::nc::get_property(resources, 3, nmos::nc_status_monitor_overall_status_property_id, get_control_protocol_class_descriptor, gate).as_integer()); + + BST_REQUIRE(nmos::nc::details::update_receiver_monitor_overall_status(resources, 2, get_control_protocol_class_descriptor, gate)); + BST_REQUIRE(nmos::nc::details::update_sender_monitor_overall_status(resources, 3, get_control_protocol_class_descriptor, gate)); +} + ////////////////////////////////////////////////////////////////////////////////////////////// BST_TEST_CASE(testSetMonitorStatusWithDelay) {