From 517c77cb5f4b9b9c70c2ba32ecf3a8e89926b000 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sun, 20 Jun 2021 00:27:13 -0500 Subject: [PATCH] Parse Volume Coverage Pattern Data (Message Type 5) --- wxdata/include/scwx/wsr88d/rda/message.hpp | 3 + .../rda/volume_coverage_pattern_data.hpp | 89 +++ .../scwx/wsr88d/rda/clutter_filter_map.cpp | 72 +-- wxdata/source/scwx/wsr88d/rda/message.cpp | 2 +- .../scwx/wsr88d/rda/message_factory.cpp | 2 + .../rda/volume_coverage_pattern_data.cpp | 513 ++++++++++++++++++ wxdata/wxdata.cmake | 6 +- 7 files changed, 635 insertions(+), 52 deletions(-) create mode 100644 wxdata/include/scwx/wsr88d/rda/volume_coverage_pattern_data.hpp create mode 100644 wxdata/source/scwx/wsr88d/rda/volume_coverage_pattern_data.cpp diff --git a/wxdata/include/scwx/wsr88d/rda/message.hpp b/wxdata/include/scwx/wsr88d/rda/message.hpp index 5479ddec..44b16a95 100644 --- a/wxdata/include/scwx/wsr88d/rda/message.hpp +++ b/wxdata/include/scwx/wsr88d/rda/message.hpp @@ -92,6 +92,9 @@ public: virtual bool Parse(std::istream& is) = 0; + static constexpr double ANGLE_DATA_SCALE = 0.005493125; + static constexpr double AZ_EL_RATE_DATA_SCALE = 0.001373291015625; + private: std::unique_ptr p; }; diff --git a/wxdata/include/scwx/wsr88d/rda/volume_coverage_pattern_data.hpp b/wxdata/include/scwx/wsr88d/rda/volume_coverage_pattern_data.hpp new file mode 100644 index 00000000..f461f4dc --- /dev/null +++ b/wxdata/include/scwx/wsr88d/rda/volume_coverage_pattern_data.hpp @@ -0,0 +1,89 @@ +#pragma once + +#include + +#include + +namespace scwx +{ +namespace wsr88d +{ +namespace rda +{ + +class VolumeCoveragePatternDataImpl; + +class VolumeCoveragePatternData : public Message +{ +public: + explicit VolumeCoveragePatternData(); + ~VolumeCoveragePatternData(); + + VolumeCoveragePatternData(const Message&) = delete; + VolumeCoveragePatternData& + operator=(const VolumeCoveragePatternData&) = delete; + + VolumeCoveragePatternData(VolumeCoveragePatternData&&) noexcept; + VolumeCoveragePatternData& operator=(VolumeCoveragePatternData&&) noexcept; + + uint16_t pattern_type() const; + uint16_t pattern_number() const; + uint16_t number_of_elevation_cuts() const; + uint8_t version() const; + uint8_t clutter_map_group_number() const; + float doppler_velocity_resolution() const; + uint8_t pulse_width() const; + uint16_t vcp_sequencing() const; + uint16_t number_of_elevations() const; + uint16_t maximum_sails_cuts() const; + bool sequence_active() const; + bool truncated_vcp() const; + uint16_t vcp_supplemental_data() const; + bool sails_vcp() const; + uint16_t number_of_sails_cuts() const; + bool mrle_vcp() const; + uint16_t number_of_mrle_cuts() const; + bool mpda_vcp() const; + bool base_tilt_vcp() const; + uint16_t number_of_base_tilts() const; + double elevation_angle(uint16_t e) const; + uint8_t channel_configuration(uint16_t e) const; + uint8_t waveform_type(uint16_t e) const; + uint8_t super_resolution_control(uint16_t e) const; + bool half_degree_azimuth(uint16_t e) const; + bool quarter_km_reflectivity(uint16_t e) const; + bool doppler_to_300km(uint16_t e) const; + bool dual_polarization_to_300km(uint16_t e) const; + uint8_t surveillance_prf_number(uint16_t e) const; + uint16_t surveillance_prf_pulse_count_radial(uint16_t e) const; + double azimuth_rate(uint16_t e) const; + float reflectivity_threshold(uint16_t e) const; + float velocity_threshold(uint16_t e) const; + float spectrum_width_threshold(uint16_t e) const; + float differential_reflectivity_threshold(uint16_t e) const; + float differential_phase_threshold(uint16_t e) const; + float correlation_coefficient_threshold(uint16_t e) const; + uint16_t supplemental_data(uint16_t e) const; + bool sails_cut(uint16_t e) const; + uint16_t sails_sequence_number(uint16_t e) const; + bool mrle_cut(uint16_t e) const; + uint16_t mrle_sequence_number(uint16_t e) const; + bool mpda_cut(uint16_t e) const; + bool base_tilt_cut(uint16_t e) const; + double ebc_angle(uint16_t e) const; + double edge_angle(uint16_t e, uint16_t s) const; + uint16_t doppler_prf_number(uint16_t e, uint16_t s) const; + uint16_t doppler_prf_pulse_count_radial(uint16_t e, uint16_t s) const; + + bool Parse(std::istream& is); + + static std::unique_ptr + Create(MessageHeader&& header, std::istream& is); + +private: + std::unique_ptr p; +}; + +} // namespace rda +} // namespace wsr88d +} // namespace scwx diff --git a/wxdata/source/scwx/wsr88d/rda/clutter_filter_map.cpp b/wxdata/source/scwx/wsr88d/rda/clutter_filter_map.cpp index 4a31f7ef..0df9818a 100644 --- a/wxdata/source/scwx/wsr88d/rda/clutter_filter_map.cpp +++ b/wxdata/source/scwx/wsr88d/rda/clutter_filter_map.cpp @@ -91,32 +91,24 @@ bool ClutterFilterMap::Parse(std::istream& is) p->mapGenerationTime_ = htons(p->mapGenerationTime_); numElevationSegments = htons(numElevationSegments); - if (is.eof()) + if (p->mapGenerationDate_ < 1) { - BOOST_LOG_TRIVIAL(warning) << logPrefix_ << "Reached end of file (1)"; + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ << "Invalid date: " << p->mapGenerationDate_; messageValid = false; } - else + if (p->mapGenerationTime_ > 1440) { - if (p->mapGenerationDate_ < 1) - { - BOOST_LOG_TRIVIAL(warning) - << logPrefix_ << "Invalid date: " << p->mapGenerationDate_; - messageValid = false; - } - if (p->mapGenerationTime_ > 1440) - { - BOOST_LOG_TRIVIAL(warning) - << logPrefix_ << "Invalid time: " << p->mapGenerationTime_; - messageValid = false; - } - if (numElevationSegments < 1 || numElevationSegments > 5) - { - BOOST_LOG_TRIVIAL(warning) - << logPrefix_ - << "Invalid number of elevation segments: " << numElevationSegments; - messageValid = false; - } + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ << "Invalid time: " << p->mapGenerationTime_; + messageValid = false; + } + if (numElevationSegments < 1 || numElevationSegments > 5) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ + << "Invalid number of elevation segments: " << numElevationSegments; + messageValid = false; } if (!messageValid) @@ -138,22 +130,13 @@ bool ClutterFilterMap::Parse(std::istream& is) numRangeZones = htons(numRangeZones); - if (is.eof()) + if (numRangeZones < 1 || numRangeZones > 20) { BOOST_LOG_TRIVIAL(warning) - << logPrefix_ << "Reached end of file (2)"; + << logPrefix_ + << "Invalid number of range zones: " << numRangeZones; messageValid = false; } - else - { - if (numRangeZones < 1 || numRangeZones > 20) - { - BOOST_LOG_TRIVIAL(warning) - << logPrefix_ - << "Invalid number of range zones: " << numRangeZones; - messageValid = false; - } - } if (!messageValid) { @@ -173,26 +156,17 @@ bool ClutterFilterMap::Parse(std::istream& is) zone.opCode = htons(zone.opCode); zone.endRange = htons(zone.endRange); - if (is.eof()) + if (zone.opCode > 2) { BOOST_LOG_TRIVIAL(warning) - << logPrefix_ << "Reached end of file (3)"; + << logPrefix_ << "Invalid op code: " << zone.opCode; messageValid = false; } - else + if (zone.endRange > 511) { - if (zone.opCode > 2) - { - BOOST_LOG_TRIVIAL(warning) - << logPrefix_ << "Invalid op code: " << zone.opCode; - messageValid = false; - } - if (zone.endRange > 511) - { - BOOST_LOG_TRIVIAL(warning) - << logPrefix_ << "Invalid end range: " << zone.endRange; - messageValid = false; - } + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ << "Invalid end range: " << zone.endRange; + messageValid = false; } } } diff --git a/wxdata/source/scwx/wsr88d/rda/message.cpp b/wxdata/source/scwx/wsr88d/rda/message.cpp index 4ea4ad9e..89915974 100644 --- a/wxdata/source/scwx/wsr88d/rda/message.cpp +++ b/wxdata/source/scwx/wsr88d/rda/message.cpp @@ -33,7 +33,7 @@ bool Message::ValidateMessage(std::istream& is, size_t bytesRead) const if (is.eof()) { - BOOST_LOG_TRIVIAL(warning) << logPrefix_ << "Reached end of file"; + BOOST_LOG_TRIVIAL(warning) << logPrefix_ << "Reached end of data stream"; messageValid = false; } else if (is.fail()) diff --git a/wxdata/source/scwx/wsr88d/rda/message_factory.cpp b/wxdata/source/scwx/wsr88d/rda/message_factory.cpp index 715d2f7b..6230c7f4 100644 --- a/wxdata/source/scwx/wsr88d/rda/message_factory.cpp +++ b/wxdata/source/scwx/wsr88d/rda/message_factory.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -24,6 +25,7 @@ typedef std::function(MessageHeader&&, std::istream&)> static const std::unordered_map create_ { {3, PerformanceMaintenanceData::Create}, + {5, VolumeCoveragePatternData::Create}, {15, ClutterFilterMap::Create}, {18, RdaAdaptationData::Create}}; diff --git a/wxdata/source/scwx/wsr88d/rda/volume_coverage_pattern_data.cpp b/wxdata/source/scwx/wsr88d/rda/volume_coverage_pattern_data.cpp new file mode 100644 index 00000000..6a560c6f --- /dev/null +++ b/wxdata/source/scwx/wsr88d/rda/volume_coverage_pattern_data.cpp @@ -0,0 +1,513 @@ +#include + +#include + +namespace scwx +{ +namespace wsr88d +{ +namespace rda +{ + +static const std::string logPrefix_ = + "[scwx::wsr88d::rda::volume_coverage_pattern_data] "; + +struct Sector; + +static void ReadSector(std::istream& is, Sector& s); +static void SwapSector(Sector& s); + +struct Sector +{ + uint16_t edgeAngle_; + uint16_t dopplerPrfNumber_; + uint16_t dopplerPrfPulseCountRadial_; + + Sector() : + edgeAngle_ {0}, dopplerPrfNumber_ {0}, dopplerPrfPulseCountRadial_ {0} + { + } +}; + +struct ElevationCut +{ + uint16_t elevationAngle_; + uint8_t channelConfiguration_; + uint8_t waveformType_; + uint8_t superResolutionControl_; + uint8_t surveillancePrfNumber_; + uint16_t surveillancePrfPulseCountRadial_; + int16_t azimuthRate_; + uint16_t reflectivityThreshold_; + uint16_t velocityThreshold_; + uint16_t spectrumWidthThreshold_; + uint16_t differentialReflectivityThreshold_; + uint16_t differentialPhaseThreshold_; + uint16_t correlationCoefficientThreshold_; + std::array sector_; + uint16_t supplementalData_; + uint16_t ebcAngle_; + + ElevationCut() : + elevationAngle_ {0}, + channelConfiguration_ {0}, + waveformType_ {0}, + superResolutionControl_ {0}, + surveillancePrfNumber_ {0}, + surveillancePrfPulseCountRadial_ {0}, + azimuthRate_ {0}, + reflectivityThreshold_ {0}, + velocityThreshold_ {0}, + spectrumWidthThreshold_ {0}, + differentialReflectivityThreshold_ {0}, + differentialPhaseThreshold_ {0}, + correlationCoefficientThreshold_ {0}, + sector_(), + supplementalData_ {0}, + ebcAngle_ {0} + { + } +}; + +class VolumeCoveragePatternDataImpl +{ +public: + explicit VolumeCoveragePatternDataImpl() : + patternType_ {0}, + patternNumber_ {0}, + version_ {0}, + clutterMapGroupNumber_ {0}, + dopplerVelocityResolution_ {0}, + pulseWidth_ {0}, + vcpSequencing_ {0}, + vcpSupplementalData_ {0}, + elevationCuts_() {}; + ~VolumeCoveragePatternDataImpl() = default; + + uint16_t patternType_; + uint16_t patternNumber_; + uint8_t version_; + uint8_t clutterMapGroupNumber_; + uint8_t dopplerVelocityResolution_; + uint8_t pulseWidth_; + uint16_t vcpSequencing_; + uint16_t vcpSupplementalData_; + std::vector elevationCuts_; +}; + +VolumeCoveragePatternData::VolumeCoveragePatternData() : + Message(), p(std::make_unique()) +{ +} +VolumeCoveragePatternData::~VolumeCoveragePatternData() = default; + +VolumeCoveragePatternData::VolumeCoveragePatternData( + VolumeCoveragePatternData&&) noexcept = default; +VolumeCoveragePatternData& VolumeCoveragePatternData::operator=( + VolumeCoveragePatternData&&) noexcept = default; + +uint16_t VolumeCoveragePatternData::pattern_type() const +{ + return p->patternType_; +} + +uint16_t VolumeCoveragePatternData::pattern_number() const +{ + return p->patternNumber_; +} + +uint16_t VolumeCoveragePatternData::number_of_elevation_cuts() const +{ + return static_cast(p->elevationCuts_.size()); +} + +uint8_t VolumeCoveragePatternData::version() const +{ + return p->version_; +} + +uint8_t VolumeCoveragePatternData::clutter_map_group_number() const +{ + return p->clutterMapGroupNumber_; +} + +float VolumeCoveragePatternData::doppler_velocity_resolution() const +{ + float resolution = 0.0f; + + switch (p->dopplerVelocityResolution_) + { + case 2: resolution = 0.5f; break; + case 4: resolution = 1.0f; break; + } + + return resolution; +} + +uint8_t VolumeCoveragePatternData::pulse_width() const +{ + return p->pulseWidth_; +} + +uint16_t VolumeCoveragePatternData::vcp_sequencing() const +{ + return p->vcpSequencing_; +} + +uint16_t VolumeCoveragePatternData::number_of_elevations() const +{ + return p->vcpSequencing_ & 0x001f; +} + +uint16_t VolumeCoveragePatternData::maximum_sails_cuts() const +{ + return (p->vcpSequencing_ & 0x0060) >> 5; +} + +bool VolumeCoveragePatternData::sequence_active() const +{ + return p->vcpSequencing_ & 0x2000; +} + +bool VolumeCoveragePatternData::truncated_vcp() const +{ + return p->vcpSequencing_ & 0x4000; +} + +uint16_t VolumeCoveragePatternData::vcp_supplemental_data() const +{ + return p->vcpSupplementalData_; +} + +bool VolumeCoveragePatternData::sails_vcp() const +{ + return p->vcpSupplementalData_ & 0x0001; +} + +uint16_t VolumeCoveragePatternData::number_of_sails_cuts() const +{ + return (p->vcpSupplementalData_ & 0x000E) >> 1; +} + +bool VolumeCoveragePatternData::mrle_vcp() const +{ + return p->vcpSupplementalData_ & 0x0010; +} + +uint16_t VolumeCoveragePatternData::number_of_mrle_cuts() const +{ + return (p->vcpSupplementalData_ & 0x00E0) >> 5; +} + +bool VolumeCoveragePatternData::mpda_vcp() const +{ + return p->vcpSupplementalData_ & 0x0800; +} + +bool VolumeCoveragePatternData::base_tilt_vcp() const +{ + return p->vcpSupplementalData_ & 0x1000; +} + +uint16_t VolumeCoveragePatternData::number_of_base_tilts() const +{ + return (p->vcpSupplementalData_ & 0xE000) >> 13; +} + +double VolumeCoveragePatternData::elevation_angle(uint16_t e) const +{ + return p->elevationCuts_[e].elevationAngle_ * ANGLE_DATA_SCALE; +} + +uint8_t VolumeCoveragePatternData::channel_configuration(uint16_t e) const +{ + return p->elevationCuts_[e].channelConfiguration_; +} + +uint8_t VolumeCoveragePatternData::waveform_type(uint16_t e) const +{ + return p->elevationCuts_[e].waveformType_; +} + +uint8_t VolumeCoveragePatternData::super_resolution_control(uint16_t e) const +{ + return p->elevationCuts_[e].superResolutionControl_; +} + +bool VolumeCoveragePatternData::half_degree_azimuth(uint16_t e) const +{ + return p->elevationCuts_[e].superResolutionControl_ & 0x0001; +} + +bool VolumeCoveragePatternData::quarter_km_reflectivity(uint16_t e) const +{ + return p->elevationCuts_[e].superResolutionControl_ & 0x0002; +} + +bool VolumeCoveragePatternData::doppler_to_300km(uint16_t e) const +{ + return p->elevationCuts_[e].superResolutionControl_ & 0x0004; +} + +bool VolumeCoveragePatternData::dual_polarization_to_300km(uint16_t e) const +{ + return p->elevationCuts_[e].superResolutionControl_ & 0x0008; +} + +uint8_t VolumeCoveragePatternData::surveillance_prf_number(uint16_t e) const +{ + return p->elevationCuts_[e].surveillancePrfNumber_; +} + +uint16_t +VolumeCoveragePatternData::surveillance_prf_pulse_count_radial(uint16_t e) const +{ + return p->elevationCuts_[e].surveillancePrfPulseCountRadial_; +} + +double VolumeCoveragePatternData::azimuth_rate(uint16_t e) const +{ + return p->elevationCuts_[e].azimuthRate_ * AZ_EL_RATE_DATA_SCALE; +} + +float VolumeCoveragePatternData::reflectivity_threshold(uint16_t e) const +{ + return p->elevationCuts_[e].reflectivityThreshold_ * 0.125f; +} + +float VolumeCoveragePatternData::velocity_threshold(uint16_t e) const +{ + return p->elevationCuts_[e].velocityThreshold_ * 0.125f; +} + +float VolumeCoveragePatternData::spectrum_width_threshold(uint16_t e) const +{ + return p->elevationCuts_[e].spectrumWidthThreshold_ * 0.125f; +} + +float VolumeCoveragePatternData::differential_reflectivity_threshold( + uint16_t e) const +{ + return p->elevationCuts_[e].differentialReflectivityThreshold_ * 0.125f; +} + +float VolumeCoveragePatternData::differential_phase_threshold(uint16_t e) const +{ + return p->elevationCuts_[e].differentialPhaseThreshold_ * 0.125f; +} + +float VolumeCoveragePatternData::correlation_coefficient_threshold( + uint16_t e) const +{ + return p->elevationCuts_[e].correlationCoefficientThreshold_ * 0.125f; +} + +uint16_t VolumeCoveragePatternData::supplemental_data(uint16_t e) const +{ + return p->elevationCuts_[e].supplementalData_; +} + +bool VolumeCoveragePatternData::sails_cut(uint16_t e) const +{ + return p->elevationCuts_[e].supplementalData_ & 0x0001; +} + +uint16_t VolumeCoveragePatternData::sails_sequence_number(uint16_t e) const +{ + return (p->elevationCuts_[e].supplementalData_ & 0x000E) >> 1; +} + +bool VolumeCoveragePatternData::mrle_cut(uint16_t e) const +{ + return p->elevationCuts_[e].supplementalData_ & 0x0010; +} + +uint16_t VolumeCoveragePatternData::mrle_sequence_number(uint16_t e) const +{ + return (p->elevationCuts_[e].supplementalData_ & 0x00E0) >> 5; +} + +bool VolumeCoveragePatternData::mpda_cut(uint16_t e) const +{ + return p->elevationCuts_[e].supplementalData_ & 0x0200; +} + +bool VolumeCoveragePatternData::base_tilt_cut(uint16_t e) const +{ + return p->elevationCuts_[e].supplementalData_ & 0x0400; +} + +double VolumeCoveragePatternData::ebc_angle(uint16_t e) const +{ + return p->elevationCuts_[e].ebcAngle_ * ANGLE_DATA_SCALE; +} + +double VolumeCoveragePatternData::edge_angle(uint16_t e, uint16_t s) const +{ + return p->elevationCuts_[e].sector_[s].edgeAngle_ * ANGLE_DATA_SCALE; +} + +uint16_t VolumeCoveragePatternData::doppler_prf_number(uint16_t e, + uint16_t s) const +{ + return p->elevationCuts_[e].sector_[s].dopplerPrfNumber_; +} + +uint16_t +VolumeCoveragePatternData::doppler_prf_pulse_count_radial(uint16_t e, + uint16_t s) const +{ + return p->elevationCuts_[e].sector_[s].dopplerPrfPulseCountRadial_; +} + +bool VolumeCoveragePatternData::Parse(std::istream& is) +{ + BOOST_LOG_TRIVIAL(debug) + << logPrefix_ << "Parsing Volume Coverage Pattern Data (Message Type 5)"; + + bool messageValid = true; + size_t bytesRead = 0; + + uint16_t messageSize = 0; + uint16_t numberOfElevationCuts = 0; + + is.read(reinterpret_cast(&messageSize), 2); // 1 + is.read(reinterpret_cast(&p->patternType_), 2); // 2 + is.read(reinterpret_cast(&p->patternNumber_), 2); // 3 + is.read(reinterpret_cast(&numberOfElevationCuts), 2); // 4 + is.read(reinterpret_cast(&p->version_), 1); // 5 + is.read(reinterpret_cast(&p->clutterMapGroupNumber_), 1); // 5 + is.read(reinterpret_cast(&p->dopplerVelocityResolution_), 1); // 6 + is.read(reinterpret_cast(&p->pulseWidth_), 1); // 6 + is.seekg(4, std::ios_base::cur); // 7-8 + is.read(reinterpret_cast(&p->vcpSequencing_), 2); // 9 + is.read(reinterpret_cast(&p->vcpSupplementalData_), 2); // 10 + is.seekg(2, std::ios_base::cur); // 11 + bytesRead += 22; + + messageSize = htons(messageSize); + p->patternType_ = htons(p->patternType_); + p->patternNumber_ = htons(p->patternNumber_); + numberOfElevationCuts = htons(numberOfElevationCuts); + p->vcpSequencing_ = htons(p->vcpSequencing_); + p->vcpSupplementalData_ = htons(p->vcpSupplementalData_); + + if (messageSize < 34 || messageSize > 747) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ << "Invalid message size: " << messageSize; + messageValid = false; + } + if (numberOfElevationCuts < 1 || numberOfElevationCuts > 32) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ + << "Invalid number of elevation cuts: " << numberOfElevationCuts; + messageValid = false; + } + + if (!messageValid) + { + numberOfElevationCuts = 0; + } + + p->elevationCuts_.resize(numberOfElevationCuts); + + for (uint16_t e = 0; e < numberOfElevationCuts; ++e) + { + ElevationCut& c = p->elevationCuts_[e]; + + is.read(reinterpret_cast(&c.elevationAngle_), 2); // E1 + is.read(reinterpret_cast(&c.channelConfiguration_), 1); // E2 + is.read(reinterpret_cast(&c.waveformType_), 1); // E2 + is.read(reinterpret_cast(&c.superResolutionControl_), 1); // E3 + is.read(reinterpret_cast(&c.surveillancePrfNumber_), 1); // E3 + is.read(reinterpret_cast(&c.surveillancePrfPulseCountRadial_), + 2); // E4 + is.read(reinterpret_cast(&c.azimuthRate_), 2); // E5 + is.read(reinterpret_cast(&c.reflectivityThreshold_), 2); // E6 + is.read(reinterpret_cast(&c.velocityThreshold_), 2); // E7 + is.read(reinterpret_cast(&c.spectrumWidthThreshold_), 2); // E8 + is.read(reinterpret_cast(&c.differentialReflectivityThreshold_), + 2); // E9 + is.read(reinterpret_cast(&c.differentialPhaseThreshold_), + 2); // E10 + is.read(reinterpret_cast(&c.correlationCoefficientThreshold_), + 2); // E11 + ReadSector(is, c.sector_[0]); // E12-E14 + is.read(reinterpret_cast(&c.supplementalData_), 2); // E15 + ReadSector(is, c.sector_[1]); // E16-E18 + is.read(reinterpret_cast(&c.ebcAngle_), 2); // E19 + ReadSector(is, c.sector_[2]); // E20-E22 + is.seekg(2, std::ios_base::cur); // E23 + bytesRead += 46; + + c.elevationAngle_ = htons(c.elevationAngle_); + c.surveillancePrfPulseCountRadial_ = + htons(c.surveillancePrfPulseCountRadial_); + c.azimuthRate_ = htons(c.azimuthRate_); + c.reflectivityThreshold_ = htons(c.reflectivityThreshold_); + c.velocityThreshold_ = htons(c.velocityThreshold_); + c.spectrumWidthThreshold_ = htons(c.spectrumWidthThreshold_); + c.differentialReflectivityThreshold_ = + htons(c.differentialReflectivityThreshold_); + c.differentialPhaseThreshold_ = htons(c.differentialPhaseThreshold_); + c.correlationCoefficientThreshold_ = + htons(c.correlationCoefficientThreshold_); + c.supplementalData_ = htons(c.supplementalData_); + c.ebcAngle_ = htons(c.ebcAngle_); + + for (size_t s = 0; s < c.sector_.size(); s++) + { + SwapSector(c.sector_[s]); + } + } + + if (messageValid && bytesRead != messageSize * 2) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ << "Bytes read (" << bytesRead + << ") not equal to message size (" << messageSize * 2 << ")"; + } + + if (!ValidateMessage(is, bytesRead)) + { + messageValid = false; + } + + if (!messageValid) + { + p->elevationCuts_.resize(0); + p->elevationCuts_.shrink_to_fit(); + } + + return messageValid; +} + +std::unique_ptr +VolumeCoveragePatternData::Create(MessageHeader&& header, std::istream& is) +{ + std::unique_ptr message = + std::make_unique(); + message->set_header(std::move(header)); + message->Parse(is); + return message; +} + +static void ReadSector(std::istream& is, Sector& s) +{ + is.read(reinterpret_cast(&s.edgeAngle_), 2); // S1 + is.read(reinterpret_cast(&s.dopplerPrfNumber_), 2); // S2 + is.read(reinterpret_cast(&s.dopplerPrfPulseCountRadial_), 2); // S3 +} + +static void SwapSector(Sector& s) +{ + s.edgeAngle_ = htons(s.edgeAngle_); + s.dopplerPrfNumber_ = htons(s.dopplerPrfNumber_); + s.dopplerPrfPulseCountRadial_ = htons(s.dopplerPrfPulseCountRadial_); +} + +} // namespace rda +} // namespace wsr88d +} // namespace scwx diff --git a/wxdata/wxdata.cmake b/wxdata/wxdata.cmake index 80ebf147..80ab7a2e 100644 --- a/wxdata/wxdata.cmake +++ b/wxdata/wxdata.cmake @@ -13,13 +13,15 @@ set(HDR_WSR88D_RDA include/scwx/wsr88d/rda/clutter_filter_map.hpp include/scwx/wsr88d/rda/message_factory.hpp include/scwx/wsr88d/rda/message_header.hpp include/scwx/wsr88d/rda/performance_maintenance_data.hpp - include/scwx/wsr88d/rda/rda_adaptation_data.hpp) + include/scwx/wsr88d/rda/rda_adaptation_data.hpp + include/scwx/wsr88d/rda/volume_coverage_pattern_data.hpp) set(SRC_WSR88D_RDA source/scwx/wsr88d/rda/clutter_filter_map.cpp source/scwx/wsr88d/rda/message.cpp source/scwx/wsr88d/rda/message_factory.cpp source/scwx/wsr88d/rda/message_header.cpp source/scwx/wsr88d/rda/performance_maintenance_data.cpp - source/scwx/wsr88d/rda/rda_adaptation_data.cpp) + source/scwx/wsr88d/rda/rda_adaptation_data.cpp + source/scwx/wsr88d/rda/volume_coverage_pattern_data.cpp) add_library(wxdata OBJECT ${HDR_UTIL} ${SRC_UTIL}