diff --git a/wxdata/CMakeLists.txt b/wxdata/CMakeLists.txt index e4d5ce80..018d792b 100644 --- a/wxdata/CMakeLists.txt +++ b/wxdata/CMakeLists.txt @@ -1,2 +1,8 @@ cmake_minimum_required(VERSION 3.11) + +set_property(DIRECTORY + APPEND + PROPERTY CMAKE_CONFIGURE_DEPENDS + wxdata.cmake) + include(wxdata.cmake) diff --git a/wxdata/include/scwx/wsr88d/rda/clutter_filter_map.hpp b/wxdata/include/scwx/wsr88d/rda/clutter_filter_map.hpp index 930820bf..9ef41641 100644 --- a/wxdata/include/scwx/wsr88d/rda/clutter_filter_map.hpp +++ b/wxdata/include/scwx/wsr88d/rda/clutter_filter_map.hpp @@ -32,7 +32,7 @@ public: bool Parse(std::istream& is); - static std::unique_ptr Create(MessageHeader&& header, + static std::shared_ptr Create(MessageHeader&& header, std::istream& is); static const size_t NUM_AZIMUTH_SEGMENTS = 360u; diff --git a/wxdata/include/scwx/wsr88d/rda/digital_radar_data.hpp b/wxdata/include/scwx/wsr88d/rda/digital_radar_data.hpp index 196353d9..e7adf94d 100644 --- a/wxdata/include/scwx/wsr88d/rda/digital_radar_data.hpp +++ b/wxdata/include/scwx/wsr88d/rda/digital_radar_data.hpp @@ -41,7 +41,7 @@ public: bool Parse(std::istream& is); - static std::unique_ptr Create(MessageHeader&& header, + static std::shared_ptr Create(MessageHeader&& header, std::istream& is); private: diff --git a/wxdata/include/scwx/wsr88d/rda/message_factory.hpp b/wxdata/include/scwx/wsr88d/rda/message_factory.hpp index 6726e2c2..ac2d6e66 100644 --- a/wxdata/include/scwx/wsr88d/rda/message_factory.hpp +++ b/wxdata/include/scwx/wsr88d/rda/message_factory.hpp @@ -11,7 +11,7 @@ namespace rda struct MessageInfo { - std::unique_ptr message; + std::shared_ptr message; bool headerValid; bool messageValid; diff --git a/wxdata/include/scwx/wsr88d/rda/performance_maintenance_data.hpp b/wxdata/include/scwx/wsr88d/rda/performance_maintenance_data.hpp index ce3448c3..cfd83373 100644 --- a/wxdata/include/scwx/wsr88d/rda/performance_maintenance_data.hpp +++ b/wxdata/include/scwx/wsr88d/rda/performance_maintenance_data.hpp @@ -278,7 +278,7 @@ public: bool Parse(std::istream& is); - static std::unique_ptr + static std::shared_ptr Create(MessageHeader&& header, std::istream& is); private: diff --git a/wxdata/include/scwx/wsr88d/rda/rda_adaptation_data.hpp b/wxdata/include/scwx/wsr88d/rda/rda_adaptation_data.hpp index 074861af..8cf2e262 100644 --- a/wxdata/include/scwx/wsr88d/rda/rda_adaptation_data.hpp +++ b/wxdata/include/scwx/wsr88d/rda/rda_adaptation_data.hpp @@ -203,7 +203,7 @@ public: bool Parse(std::istream& is); - static std::unique_ptr Create(MessageHeader&& header, + static std::shared_ptr Create(MessageHeader&& header, std::istream& is); private: diff --git a/wxdata/include/scwx/wsr88d/rda/rda_status_data.hpp b/wxdata/include/scwx/wsr88d/rda/rda_status_data.hpp index ef57ce3a..ccfa42b3 100644 --- a/wxdata/include/scwx/wsr88d/rda/rda_status_data.hpp +++ b/wxdata/include/scwx/wsr88d/rda/rda_status_data.hpp @@ -55,7 +55,7 @@ public: bool Parse(std::istream& is); - static std::unique_ptr Create(MessageHeader&& header, + static std::shared_ptr Create(MessageHeader&& header, std::istream& is); private: diff --git a/wxdata/include/scwx/wsr88d/rda/types.hpp b/wxdata/include/scwx/wsr88d/rda/types.hpp new file mode 100644 index 00000000..617054a2 --- /dev/null +++ b/wxdata/include/scwx/wsr88d/rda/types.hpp @@ -0,0 +1,22 @@ +#pragma once + +namespace scwx +{ +namespace wsr88d +{ +namespace rda +{ + +enum class MessageId : uint8_t +{ + RdaStatusData = 2, + PerformanceMaintenanceData = 3, + VolumeCoveragePatternData = 5, + ClutterFilterMap = 15, + RdaAdaptationData = 18, + DigitalRadarData = 31 +}; + +} // namespace rda +} // namespace wsr88d +} // namespace scwx diff --git a/wxdata/include/scwx/wsr88d/rda/volume_coverage_pattern_data.hpp b/wxdata/include/scwx/wsr88d/rda/volume_coverage_pattern_data.hpp index f461f4dc..e0748057 100644 --- a/wxdata/include/scwx/wsr88d/rda/volume_coverage_pattern_data.hpp +++ b/wxdata/include/scwx/wsr88d/rda/volume_coverage_pattern_data.hpp @@ -77,7 +77,7 @@ public: bool Parse(std::istream& is); - static std::unique_ptr + static std::shared_ptr Create(MessageHeader&& header, std::istream& is); private: diff --git a/wxdata/source/scwx/wsr88d/ar2v_file.cpp b/wxdata/source/scwx/wsr88d/ar2v_file.cpp index 395fc855..526c4100 100644 --- a/wxdata/source/scwx/wsr88d/ar2v_file.cpp +++ b/wxdata/source/scwx/wsr88d/ar2v_file.cpp @@ -1,5 +1,8 @@ #include +#include #include +#include +#include #include #include @@ -27,11 +30,16 @@ public: milliseconds_ {0}, icao_(), numRecords_ {0}, - rawRecords_() {}; + rawRecords_(), + vcpData_ {nullptr}, + radarData_ {} {}; ~Ar2vFileImpl() = default; + void HandleMessage(std::shared_ptr& message); void LoadLDMRecords(std::ifstream& f); void ParseLDMRecords(); + void ProcessRadarData(std::shared_ptr& message); + void ProcessVcpData(); std::string tapeFilename_; std::string extensionNumber_; @@ -41,6 +49,12 @@ public: size_t numRecords_; + std::shared_ptr vcpData_; + std::unordered_map< + uint16_t, + std::unordered_map>> + radarData_; + std::list rawRecords_; }; @@ -182,6 +196,11 @@ void Ar2vFileImpl::ParseLDMRecords() break; } + if (msgInfo.messageValid) + { + HandleMessage(msgInfo.message); + } + off_t offset = 0; uint16_t nextSize = 0u; do @@ -206,5 +225,51 @@ void Ar2vFileImpl::ParseLDMRecords() } } +void Ar2vFileImpl::HandleMessage(std::shared_ptr& message) +{ + switch (message->header().message_type()) + { + case static_cast(rda::MessageId::VolumeCoveragePatternData): + vcpData_ = + std::static_pointer_cast(message); + ProcessVcpData(); + break; + + case static_cast(rda::MessageId::DigitalRadarData): + ProcessRadarData( + std::static_pointer_cast(message)); + break; + + default: break; + } +} + +void Ar2vFileImpl::ProcessRadarData( + std::shared_ptr& message) +{ + uint16_t azimuthIndex = message->azimuth_number() - 1; + uint16_t elevationIndex = message->elevation_number() - 1; + + radarData_[elevationIndex][azimuthIndex] = message; +} + +void Ar2vFileImpl::ProcessVcpData() +{ + uint16_t numberOfElevationCuts = vcpData_->number_of_elevation_cuts(); + radarData_.reserve(numberOfElevationCuts); + + for (uint16_t e = 0; e < numberOfElevationCuts; ++e) + { + if (vcpData_->half_degree_azimuth(e)) + { + radarData_[e].reserve(720); + } + else + { + radarData_[e].reserve(360); + } + } +} + } // 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 a2fc679f..bc5ccebf 100644 --- a/wxdata/source/scwx/wsr88d/rda/clutter_filter_map.cpp +++ b/wxdata/source/scwx/wsr88d/rda/clutter_filter_map.cpp @@ -186,13 +186,18 @@ bool ClutterFilterMap::Parse(std::istream& is) return messageValid; } -std::unique_ptr +std::shared_ptr ClutterFilterMap::Create(MessageHeader&& header, std::istream& is) { - std::unique_ptr message = - std::make_unique(); + std::shared_ptr message = + std::make_shared(); message->set_header(std::move(header)); - message->Parse(is); + + if (!message->Parse(is)) + { + message.reset(); + } + return message; } diff --git a/wxdata/source/scwx/wsr88d/rda/digital_radar_data.cpp b/wxdata/source/scwx/wsr88d/rda/digital_radar_data.cpp index 1f755c9d..049eba22 100644 --- a/wxdata/source/scwx/wsr88d/rda/digital_radar_data.cpp +++ b/wxdata/source/scwx/wsr88d/rda/digital_radar_data.cpp @@ -501,19 +501,34 @@ bool DigitalRadarData::Parse(std::istream& is) p->elevationAngle_ = SwapFloat(p->elevationAngle_); p->dataBlockCount_ = ntohs(p->dataBlockCount_); + if (p->azimuthNumber_ < 1 || p->azimuthNumber_ > 720) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ << "Invalid azimuth number: " << p->azimuthNumber_; + messageValid = false; + } + if (p->elevationNumber_ < 1 || p->elevationNumber_ > 32) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ << "Invalid elevation number: " << p->elevationNumber_; + messageValid = false; + } if (p->dataBlockCount_ < 4 || p->dataBlockCount_ > 10) { BOOST_LOG_TRIVIAL(warning) << logPrefix_ << "Invalid number of data blocks: " << p->dataBlockCount_; - p->dataBlockCount_ = 0; - messageValid = false; + messageValid = false; } if (p->compressionIndicator_ != 0) { BOOST_LOG_TRIVIAL(warning) << logPrefix_ << "Compression not supported"; + messageValid = false; + } + + if (!messageValid) + { p->dataBlockCount_ = 0; - messageValid = false; } is.read(reinterpret_cast(&p->dataBlockPointer_), @@ -599,13 +614,18 @@ bool DigitalRadarData::Parse(std::istream& is) return messageValid; } -std::unique_ptr +std::shared_ptr DigitalRadarData::Create(MessageHeader&& header, std::istream& is) { - std::unique_ptr message = - std::make_unique(); + std::shared_ptr message = + std::make_shared(); message->set_header(std::move(header)); - message->Parse(is); + + if (!message->Parse(is)) + { + message.reset(); + } + return message; } diff --git a/wxdata/source/scwx/wsr88d/rda/message_factory.cpp b/wxdata/source/scwx/wsr88d/rda/message_factory.cpp index d698f302..9ad034ef 100644 --- a/wxdata/source/scwx/wsr88d/rda/message_factory.cpp +++ b/wxdata/source/scwx/wsr88d/rda/message_factory.cpp @@ -22,7 +22,7 @@ namespace rda static const std::string logPrefix_ = "[scwx::wsr88d::rda::message_factory] "; -typedef std::function(MessageHeader&&, std::istream&)> +typedef std::function(MessageHeader&&, std::istream&)> CreateMessageFunction; static const std::unordered_map create_ { @@ -133,6 +133,11 @@ MessageInfo MessageFactory::Create(std::istream& is) std::ios_base::cur); } + if (info.message == nullptr) + { + info.messageValid = false; + } + return info; } diff --git a/wxdata/source/scwx/wsr88d/rda/performance_maintenance_data.cpp b/wxdata/source/scwx/wsr88d/rda/performance_maintenance_data.cpp index c01f64de..e83572a9 100644 --- a/wxdata/source/scwx/wsr88d/rda/performance_maintenance_data.cpp +++ b/wxdata/source/scwx/wsr88d/rda/performance_maintenance_data.cpp @@ -2468,13 +2468,18 @@ bool PerformanceMaintenanceData::Parse(std::istream& is) return messageValid; } -std::unique_ptr +std::shared_ptr PerformanceMaintenanceData::Create(MessageHeader&& header, std::istream& is) { - std::unique_ptr message = - std::make_unique(); + std::shared_ptr message = + std::make_shared(); message->set_header(std::move(header)); - message->Parse(is); + + if (!message->Parse(is)) + { + message.reset(); + } + return message; } diff --git a/wxdata/source/scwx/wsr88d/rda/rda_adaptation_data.cpp b/wxdata/source/scwx/wsr88d/rda/rda_adaptation_data.cpp index bca58216..eb51698f 100644 --- a/wxdata/source/scwx/wsr88d/rda/rda_adaptation_data.cpp +++ b/wxdata/source/scwx/wsr88d/rda/rda_adaptation_data.cpp @@ -1746,13 +1746,18 @@ bool RdaAdaptationData::Parse(std::istream& is) return messageValid; } -std::unique_ptr +std::shared_ptr RdaAdaptationData::Create(MessageHeader&& header, std::istream& is) { - std::unique_ptr message = - std::make_unique(); + std::shared_ptr message = + std::make_shared(); message->set_header(std::move(header)); - message->Parse(is); + + if (!message->Parse(is)) + { + message.reset(); + } + return message; } diff --git a/wxdata/source/scwx/wsr88d/rda/rda_status_data.cpp b/wxdata/source/scwx/wsr88d/rda/rda_status_data.cpp index 264cb49f..18ed5085 100644 --- a/wxdata/source/scwx/wsr88d/rda/rda_status_data.cpp +++ b/wxdata/source/scwx/wsr88d/rda/rda_status_data.cpp @@ -322,12 +322,17 @@ bool RdaStatusData::Parse(std::istream& is) return messageValid; } -std::unique_ptr RdaStatusData::Create(MessageHeader&& header, +std::shared_ptr RdaStatusData::Create(MessageHeader&& header, std::istream& is) { - std::unique_ptr message = std::make_unique(); + std::shared_ptr message = std::make_shared(); message->set_header(std::move(header)); - message->Parse(is); + + if (!message->Parse(is)) + { + message.reset(); + } + return message; } diff --git a/wxdata/source/scwx/wsr88d/rda/volume_coverage_pattern_data.cpp b/wxdata/source/scwx/wsr88d/rda/volume_coverage_pattern_data.cpp index 87395800..7f5b49a7 100644 --- a/wxdata/source/scwx/wsr88d/rda/volume_coverage_pattern_data.cpp +++ b/wxdata/source/scwx/wsr88d/rda/volume_coverage_pattern_data.cpp @@ -236,22 +236,22 @@ uint8_t VolumeCoveragePatternData::super_resolution_control(uint16_t e) const bool VolumeCoveragePatternData::half_degree_azimuth(uint16_t e) const { - return p->elevationCuts_[e].superResolutionControl_ & 0x0001; + return p->elevationCuts_[e].superResolutionControl_ & 0x01; } bool VolumeCoveragePatternData::quarter_km_reflectivity(uint16_t e) const { - return p->elevationCuts_[e].superResolutionControl_ & 0x0002; + return p->elevationCuts_[e].superResolutionControl_ & 0x02; } bool VolumeCoveragePatternData::doppler_to_300km(uint16_t e) const { - return p->elevationCuts_[e].superResolutionControl_ & 0x0004; + return p->elevationCuts_[e].superResolutionControl_ & 0x04; } bool VolumeCoveragePatternData::dual_polarization_to_300km(uint16_t e) const { - return p->elevationCuts_[e].superResolutionControl_ & 0x0008; + return p->elevationCuts_[e].superResolutionControl_ & 0x08; } uint8_t VolumeCoveragePatternData::surveillance_prf_number(uint16_t e) const @@ -484,13 +484,18 @@ bool VolumeCoveragePatternData::Parse(std::istream& is) return messageValid; } -std::unique_ptr +std::shared_ptr VolumeCoveragePatternData::Create(MessageHeader&& header, std::istream& is) { - std::unique_ptr message = - std::make_unique(); + std::shared_ptr message = + std::make_shared(); message->set_header(std::move(header)); - message->Parse(is); + + if (!message->Parse(is)) + { + message.reset(); + } + return message; } diff --git a/wxdata/wxdata.cmake b/wxdata/wxdata.cmake index 8c78f184..5f904228 100644 --- a/wxdata/wxdata.cmake +++ b/wxdata/wxdata.cmake @@ -16,6 +16,7 @@ set(HDR_WSR88D_RDA include/scwx/wsr88d/rda/clutter_filter_map.hpp include/scwx/wsr88d/rda/performance_maintenance_data.hpp include/scwx/wsr88d/rda/rda_adaptation_data.hpp include/scwx/wsr88d/rda/rda_status_data.hpp + include/scwx/wsr88d/rda/types.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/digital_radar_data.cpp