diff --git a/wxdata/include/scwx/wsr88d/message.hpp b/wxdata/include/scwx/wsr88d/message.hpp index b8883f62..89409bb3 100644 --- a/wxdata/include/scwx/wsr88d/message.hpp +++ b/wxdata/include/scwx/wsr88d/message.hpp @@ -68,6 +68,16 @@ public: [](float f) { return SwapFloat(f); }); } + template + static void SwapArray(std::array& arr, size_t size = _Size) + { + std::transform(std::execution::par_unseq, + arr.begin(), + arr.begin() + size, + arr.begin(), + [](int16_t u) { return ntohs(u); }); + } + template static void SwapArray(std::array& arr, size_t size = _Size) { diff --git a/wxdata/include/scwx/wsr88d/rpg/general_status_message.hpp b/wxdata/include/scwx/wsr88d/rpg/general_status_message.hpp new file mode 100644 index 00000000..c10fe4b7 --- /dev/null +++ b/wxdata/include/scwx/wsr88d/rpg/general_status_message.hpp @@ -0,0 +1,66 @@ +#pragma once + +#include +#include + +#include +#include + +namespace scwx +{ +namespace wsr88d +{ +namespace rpg +{ + +class GeneralStatusMessageImpl; + +class GeneralStatusMessage : public Level3Message +{ +public: + explicit GeneralStatusMessage(); + ~GeneralStatusMessage(); + + GeneralStatusMessage(const GeneralStatusMessage&) = delete; + GeneralStatusMessage& operator=(const GeneralStatusMessage&) = delete; + + GeneralStatusMessage(GeneralStatusMessage&&) noexcept; + GeneralStatusMessage& operator=(GeneralStatusMessage&&) noexcept; + + int16_t block_divider() const; + uint16_t length_of_block() const; + uint16_t mode_of_operation() const; + uint16_t rda_operability_status() const; + uint16_t volume_coverage_pattern() const; + uint16_t number_of_elevation_cuts() const; + float elevation(uint16_t e) const; + uint16_t rda_status() const; + uint16_t rda_alarms() const; + uint16_t data_transmission_enabled() const; + uint16_t rpg_operability_status() const; + uint16_t rpg_alarms() const; + uint16_t rpg_status() const; + uint16_t rpg_narrowband_status() const; + float horizontal_reflectivity_calibration_correction() const; + uint16_t product_availiability() const; + uint16_t super_resolution_elevation_cuts() const; + uint16_t clutter_mitigation_decision_status() const; + float vertical_reflectivity_calibration_correction() const; + uint16_t rda_build_number() const; + uint16_t rda_channel_number() const; + uint16_t build_version() const; + uint16_t vcp_supplemental_data() const; + uint32_t supplemental_cut_map() const; + + bool Parse(std::istream& is) override; + + static std::shared_ptr + Create(Level3MessageHeader&& header, std::istream& is); + +private: + std::unique_ptr p; +}; + +} // namespace rpg +} // namespace wsr88d +} // namespace scwx diff --git a/wxdata/source/scwx/wsr88d/rpg/general_status_message.cpp b/wxdata/source/scwx/wsr88d/rpg/general_status_message.cpp new file mode 100644 index 00000000..bdc7b869 --- /dev/null +++ b/wxdata/source/scwx/wsr88d/rpg/general_status_message.cpp @@ -0,0 +1,302 @@ +#include +#include + +#include +#include + +#include + +namespace scwx +{ +namespace wsr88d +{ +namespace rpg +{ + +static const std::string logPrefix_ = + "[scwx::wsr88d::rpg::general_status_message] "; + +class GeneralStatusMessageImpl +{ +public: + explicit GeneralStatusMessageImpl() : + blockDivider_ {0}, + lengthOfBlock_ {0}, + modeOfOperation_ {0}, + rdaOperabilityStatus_ {0}, + volumeCoveragePattern_ {0}, + numberOfElevationCuts_ {0}, + elevation_ {0}, + rdaStatus_ {0}, + rdaAlarms_ {0}, + dataTransmissionEnabled_ {0}, + rpgOperabilityStatus_ {0}, + rpgAlarms_ {0}, + rpgStatus_ {0}, + rpgNarrowbandStatus_ {0}, + horizontalReflectivityCalibrationCorrection_ {0}, + productAvailiability_ {0}, + superResolutionElevationCuts_ {0}, + clutterMitigationDecisionStatus_ {0}, + verticalReflectivityCalibrationCorrection_ {0}, + rdaBuildNumber_ {0}, + rdaChannelNumber_ {0}, + buildVersion_ {0}, + vcpSupplementalData_ {0}, + supplementalCutMap_ {0} + { + } + ~GeneralStatusMessageImpl() = default; + + int16_t blockDivider_; + uint16_t lengthOfBlock_; + uint16_t modeOfOperation_; + uint16_t rdaOperabilityStatus_; + uint16_t volumeCoveragePattern_; + uint16_t numberOfElevationCuts_; + std::array elevation_; + uint16_t rdaStatus_; + uint16_t rdaAlarms_; + uint16_t dataTransmissionEnabled_; + uint16_t rpgOperabilityStatus_; + uint16_t rpgAlarms_; + uint16_t rpgStatus_; + uint16_t rpgNarrowbandStatus_; + int16_t horizontalReflectivityCalibrationCorrection_; + uint16_t productAvailiability_; + uint16_t superResolutionElevationCuts_; + uint16_t clutterMitigationDecisionStatus_; + int16_t verticalReflectivityCalibrationCorrection_; + uint16_t rdaBuildNumber_; + uint16_t rdaChannelNumber_; + uint16_t buildVersion_; + uint16_t vcpSupplementalData_; + uint32_t supplementalCutMap_; +}; + +GeneralStatusMessage::GeneralStatusMessage() : + p(std::make_unique()) +{ +} +GeneralStatusMessage::~GeneralStatusMessage() = default; + +GeneralStatusMessage::GeneralStatusMessage(GeneralStatusMessage&&) noexcept = + default; +GeneralStatusMessage& +GeneralStatusMessage::operator=(GeneralStatusMessage&&) noexcept = default; + +int16_t GeneralStatusMessage::block_divider() const +{ + return p->blockDivider_; +} + +uint16_t GeneralStatusMessage::length_of_block() const +{ + return p->lengthOfBlock_; +} + +uint16_t GeneralStatusMessage::mode_of_operation() const +{ + return p->modeOfOperation_; +} + +uint16_t GeneralStatusMessage::rda_operability_status() const +{ + return p->rdaOperabilityStatus_; +} + +uint16_t GeneralStatusMessage::volume_coverage_pattern() const +{ + return p->volumeCoveragePattern_; +} + +uint16_t GeneralStatusMessage::number_of_elevation_cuts() const +{ + return p->numberOfElevationCuts_; +} + +float GeneralStatusMessage::elevation(uint16_t e) const +{ + return p->elevation_[e] * 0.1f; +} + +uint16_t GeneralStatusMessage::rda_status() const +{ + return p->rdaStatus_; +} + +uint16_t GeneralStatusMessage::rda_alarms() const +{ + return p->rdaAlarms_; +} + +uint16_t GeneralStatusMessage::data_transmission_enabled() const +{ + return p->dataTransmissionEnabled_; +} + +uint16_t GeneralStatusMessage::rpg_operability_status() const +{ + return p->rpgOperabilityStatus_; +} + +uint16_t GeneralStatusMessage::rpg_alarms() const +{ + return p->rpgAlarms_; +} + +uint16_t GeneralStatusMessage::rpg_status() const +{ + return p->rpgStatus_; +} + +uint16_t GeneralStatusMessage::rpg_narrowband_status() const +{ + return p->rpgNarrowbandStatus_; +} + +float GeneralStatusMessage::horizontal_reflectivity_calibration_correction() + const +{ + return p->horizontalReflectivityCalibrationCorrection_ * 0.25f; +} + +uint16_t GeneralStatusMessage::product_availiability() const +{ + return p->productAvailiability_; +} + +uint16_t GeneralStatusMessage::super_resolution_elevation_cuts() const +{ + return p->superResolutionElevationCuts_; +} + +uint16_t GeneralStatusMessage::clutter_mitigation_decision_status() const +{ + return p->clutterMitigationDecisionStatus_; +} + +float GeneralStatusMessage::vertical_reflectivity_calibration_correction() const +{ + return p->verticalReflectivityCalibrationCorrection_ * 0.25f; +} + +uint16_t GeneralStatusMessage::rda_build_number() const +{ + return p->rdaBuildNumber_; +} + +uint16_t GeneralStatusMessage::rda_channel_number() const +{ + return p->rdaChannelNumber_; +} + +uint16_t GeneralStatusMessage::build_version() const +{ + return p->buildVersion_; +} + +uint16_t GeneralStatusMessage::vcp_supplemental_data() const +{ + return p->vcpSupplementalData_; +} + +uint32_t GeneralStatusMessage::supplemental_cut_map() const +{ + return p->supplementalCutMap_; +} + +bool GeneralStatusMessage::Parse(std::istream& is) +{ + bool dataValid = true; + + const std::streampos dataStart = is.tellg(); + + is.read(reinterpret_cast(&p->blockDivider_), 2); + is.read(reinterpret_cast(&p->lengthOfBlock_), 2); + is.read(reinterpret_cast(&p->modeOfOperation_), 2); + is.read(reinterpret_cast(&p->rdaOperabilityStatus_), 2); + is.read(reinterpret_cast(&p->volumeCoveragePattern_), 2); + is.read(reinterpret_cast(&p->numberOfElevationCuts_), 2); + is.read(reinterpret_cast(p->elevation_.data()), 40); + is.read(reinterpret_cast(&p->rdaStatus_), 2); + is.read(reinterpret_cast(&p->rdaAlarms_), 2); + is.read(reinterpret_cast(&p->dataTransmissionEnabled_), 2); + is.read(reinterpret_cast(&p->rpgOperabilityStatus_), 2); + is.read(reinterpret_cast(&p->rpgAlarms_), 2); + is.read(reinterpret_cast(&p->rpgStatus_), 2); + is.read(reinterpret_cast(&p->rpgNarrowbandStatus_), 2); + is.read( + reinterpret_cast(&p->horizontalReflectivityCalibrationCorrection_), + 2); + is.read(reinterpret_cast(&p->productAvailiability_), 2); + is.read(reinterpret_cast(&p->superResolutionElevationCuts_), 2); + is.read(reinterpret_cast(&p->clutterMitigationDecisionStatus_), 2); + is.read( + reinterpret_cast(&p->verticalReflectivityCalibrationCorrection_), + 2); + is.read(reinterpret_cast(&p->rdaBuildNumber_), 2); + is.read(reinterpret_cast(&p->rdaChannelNumber_), 2); + is.seekg(4, std::ios_base::cur); + is.read(reinterpret_cast(&p->buildVersion_), 2); + is.read(reinterpret_cast(&p->elevation_[20]), 10); + is.read(reinterpret_cast(&p->vcpSupplementalData_), 2); + is.read(reinterpret_cast(&p->supplementalCutMap_), 4); + is.seekg(80, std::ios_base::cur); + + p->blockDivider_ = ntohs(p->blockDivider_); + p->lengthOfBlock_ = ntohs(p->lengthOfBlock_); + p->modeOfOperation_ = ntohs(p->modeOfOperation_); + p->rdaOperabilityStatus_ = ntohs(p->rdaOperabilityStatus_); + p->volumeCoveragePattern_ = ntohs(p->volumeCoveragePattern_); + p->numberOfElevationCuts_ = ntohs(p->numberOfElevationCuts_); + p->rdaStatus_ = ntohs(p->rdaStatus_); + p->rdaAlarms_ = ntohs(p->rdaAlarms_); + p->dataTransmissionEnabled_ = ntohs(p->dataTransmissionEnabled_); + p->rpgOperabilityStatus_ = ntohs(p->rpgOperabilityStatus_); + p->rpgAlarms_ = ntohs(p->rpgAlarms_); + p->rpgStatus_ = ntohs(p->rpgStatus_); + p->rpgNarrowbandStatus_ = ntohs(p->rpgNarrowbandStatus_); + p->horizontalReflectivityCalibrationCorrection_ = + ntohs(p->horizontalReflectivityCalibrationCorrection_); + p->productAvailiability_ = ntohs(p->productAvailiability_); + p->superResolutionElevationCuts_ = ntohs(p->superResolutionElevationCuts_); + p->clutterMitigationDecisionStatus_ = + ntohs(p->clutterMitigationDecisionStatus_); + p->verticalReflectivityCalibrationCorrection_ = + ntohs(p->verticalReflectivityCalibrationCorrection_); + p->rdaBuildNumber_ = ntohs(p->rdaBuildNumber_); + p->rdaChannelNumber_ = ntohs(p->rdaChannelNumber_); + p->buildVersion_ = ntohs(p->buildVersion_); + p->vcpSupplementalData_ = ntohs(p->vcpSupplementalData_); + p->supplementalCutMap_ = ntohl(p->supplementalCutMap_); + + SwapArray(p->elevation_); + + const std::streampos dataEnd = is.tellg(); + if (!ValidateMessage(is, dataEnd - dataStart)) + { + dataValid = false; + } + + return dataValid; +} + +std::shared_ptr +GeneralStatusMessage::Create(Level3MessageHeader&& header, std::istream& is) +{ + std::shared_ptr message = + std::make_shared(); + message->set_header(std::move(header)); + + if (!message->Parse(is)) + { + message.reset(); + } + + return message; +} + +} // namespace rpg +} // namespace wsr88d +} // namespace scwx diff --git a/wxdata/source/scwx/wsr88d/rpg/level3_message_factory.cpp b/wxdata/source/scwx/wsr88d/rpg/level3_message_factory.cpp index 3c120184..2a159f36 100644 --- a/wxdata/source/scwx/wsr88d/rpg/level3_message_factory.cpp +++ b/wxdata/source/scwx/wsr88d/rpg/level3_message_factory.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include @@ -24,7 +25,8 @@ typedef std::function(Level3MessageHeader&&, CreateLevel3MessageFunction; static const std::unordered_map // - create_ {{19, GraphicProductMessage::Create}, + create_ {{2, GeneralStatusMessage::Create}, + {19, GraphicProductMessage::Create}, {20, GraphicProductMessage::Create}, {27, GraphicProductMessage::Create}, {30, GraphicProductMessage::Create}, diff --git a/wxdata/wxdata.cmake b/wxdata/wxdata.cmake index a48604bb..6291f5d3 100644 --- a/wxdata/wxdata.cmake +++ b/wxdata/wxdata.cmake @@ -51,6 +51,7 @@ set(HDR_WSR88D_RPG include/scwx/wsr88d/rpg/ccb_header.hpp include/scwx/wsr88d/rpg/cell_trend_volume_scan_times.hpp include/scwx/wsr88d/rpg/digital_precipitation_data_array_packet.hpp include/scwx/wsr88d/rpg/digital_radial_data_array_packet.hpp + include/scwx/wsr88d/rpg/general_status_message.hpp include/scwx/wsr88d/rpg/generic_data_packet.hpp include/scwx/wsr88d/rpg/graphic_alphanumeric_block.hpp include/scwx/wsr88d/rpg/graphic_product_message.hpp @@ -88,6 +89,7 @@ set(SRC_WSR88D_RPG source/scwx/wsr88d/rpg/ccb_header.cpp source/scwx/wsr88d/rpg/cell_trend_volume_scan_times.cpp source/scwx/wsr88d/rpg/digital_precipitation_data_array_packet.cpp source/scwx/wsr88d/rpg/digital_radial_data_array_packet.cpp + source/scwx/wsr88d/rpg/general_status_message.cpp source/scwx/wsr88d/rpg/generic_data_packet.cpp source/scwx/wsr88d/rpg/graphic_alphanumeric_block.cpp source/scwx/wsr88d/rpg/graphic_product_message.cpp