From f1472275bc916cc67f6617726523719d90525232 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sat, 8 Jan 2022 18:19:00 -0600 Subject: [PATCH] Digital radial data array packet --- .../rpg/digital_radial_data_array_packet.hpp | 52 ++++ .../rpg/digital_radial_data_array_packet.cpp | 234 ++++++++++++++++++ .../source/scwx/wsr88d/rpg/packet_factory.cpp | 2 + wxdata/wxdata.cmake | 2 + 4 files changed, 290 insertions(+) create mode 100644 wxdata/include/scwx/wsr88d/rpg/digital_radial_data_array_packet.hpp create mode 100644 wxdata/source/scwx/wsr88d/rpg/digital_radial_data_array_packet.cpp diff --git a/wxdata/include/scwx/wsr88d/rpg/digital_radial_data_array_packet.hpp b/wxdata/include/scwx/wsr88d/rpg/digital_radial_data_array_packet.hpp new file mode 100644 index 00000000..75088204 --- /dev/null +++ b/wxdata/include/scwx/wsr88d/rpg/digital_radial_data_array_packet.hpp @@ -0,0 +1,52 @@ +#pragma once + +#include + +#include +#include + +namespace scwx +{ +namespace wsr88d +{ +namespace rpg +{ + +class DigitalRadialDataArrayPacketImpl; + +class DigitalRadialDataArrayPacket : public Packet +{ +public: + explicit DigitalRadialDataArrayPacket(); + ~DigitalRadialDataArrayPacket(); + + DigitalRadialDataArrayPacket(const DigitalRadialDataArrayPacket&) = delete; + DigitalRadialDataArrayPacket& + operator=(const DigitalRadialDataArrayPacket&) = delete; + + DigitalRadialDataArrayPacket(DigitalRadialDataArrayPacket&&) noexcept; + DigitalRadialDataArrayPacket& + operator=(DigitalRadialDataArrayPacket&&) noexcept; + + uint16_t packet_code() const; + uint16_t index_of_first_range_bin() const; + uint16_t number_of_range_bins() const; + int16_t i_center_of_sweep() const; + int16_t j_center_of_sweep() const; + float range_scale_factor() const; + uint16_t number_of_radials() const; + + size_t data_size() const override; + + bool Parse(std::istream& is) override; + + static std::shared_ptr + Create(std::istream& is); + +private: + std::unique_ptr p; +}; + +} // namespace rpg +} // namespace wsr88d +} // namespace scwx diff --git a/wxdata/source/scwx/wsr88d/rpg/digital_radial_data_array_packet.cpp b/wxdata/source/scwx/wsr88d/rpg/digital_radial_data_array_packet.cpp new file mode 100644 index 00000000..dda753d6 --- /dev/null +++ b/wxdata/source/scwx/wsr88d/rpg/digital_radial_data_array_packet.cpp @@ -0,0 +1,234 @@ +#include + +#include +#include + +#include + +namespace scwx +{ +namespace wsr88d +{ +namespace rpg +{ + +static const std::string logPrefix_ = + "[scwx::wsr88d::rpg::digital_radial_data_array_packet] "; + +class DigitalRadialDataArrayPacketImpl +{ +public: + struct Radial + { + uint16_t numberOfBytes_; + uint16_t startAngle_; + uint16_t deltaAngle_; + std::vector level_; + + Radial() : numberOfBytes_ {0}, startAngle_ {0}, deltaAngle_ {0}, level_ {} + { + } + }; + + explicit DigitalRadialDataArrayPacketImpl() : + packetCode_ {0}, + indexOfFirstRangeBin_ {0}, + numberOfRangeBins_ {0}, + iCenterOfSweep_ {0}, + jCenterOfSweep_ {0}, + rangeScaleFactor_ {0}, + radial_ {}, + dataSize_ {0} + { + } + ~DigitalRadialDataArrayPacketImpl() = default; + + uint16_t packetCode_; + uint16_t indexOfFirstRangeBin_; + uint16_t numberOfRangeBins_; + int16_t iCenterOfSweep_; + int16_t jCenterOfSweep_; + uint16_t rangeScaleFactor_; + uint16_t numberOfRadials_; + + // Repeat for each radial + std::vector radial_; + + size_t dataSize_; +}; + +DigitalRadialDataArrayPacket::DigitalRadialDataArrayPacket() : + p(std::make_unique()) +{ +} +DigitalRadialDataArrayPacket::~DigitalRadialDataArrayPacket() = default; + +DigitalRadialDataArrayPacket::DigitalRadialDataArrayPacket( + DigitalRadialDataArrayPacket&&) noexcept = default; +DigitalRadialDataArrayPacket& DigitalRadialDataArrayPacket::operator=( + DigitalRadialDataArrayPacket&&) noexcept = default; + +uint16_t DigitalRadialDataArrayPacket::packet_code() const +{ + return p->packetCode_; +} + +uint16_t DigitalRadialDataArrayPacket::index_of_first_range_bin() const +{ + return p->indexOfFirstRangeBin_; +} + +uint16_t DigitalRadialDataArrayPacket::number_of_range_bins() const +{ + return p->numberOfRangeBins_; +} + +int16_t DigitalRadialDataArrayPacket::i_center_of_sweep() const +{ + return p->iCenterOfSweep_; +} + +int16_t DigitalRadialDataArrayPacket::j_center_of_sweep() const +{ + return p->jCenterOfSweep_; +} + +float DigitalRadialDataArrayPacket::range_scale_factor() const +{ + return p->rangeScaleFactor_ * 0.001f; +} + +uint16_t DigitalRadialDataArrayPacket::number_of_radials() const +{ + return p->numberOfRadials_; +} + +size_t DigitalRadialDataArrayPacket::data_size() const +{ + return p->dataSize_; +} + +bool DigitalRadialDataArrayPacket::Parse(std::istream& is) +{ + bool blockValid = true; + size_t bytesRead = 0; + + is.read(reinterpret_cast(&p->packetCode_), 2); + is.read(reinterpret_cast(&p->indexOfFirstRangeBin_), 2); + is.read(reinterpret_cast(&p->numberOfRangeBins_), 2); + is.read(reinterpret_cast(&p->iCenterOfSweep_), 2); + is.read(reinterpret_cast(&p->jCenterOfSweep_), 2); + is.read(reinterpret_cast(&p->rangeScaleFactor_), 2); + is.read(reinterpret_cast(&p->numberOfRadials_), 2); + bytesRead += 14; + + p->packetCode_ = ntohs(p->packetCode_); + p->indexOfFirstRangeBin_ = ntohs(p->indexOfFirstRangeBin_); + p->numberOfRangeBins_ = ntohs(p->numberOfRangeBins_); + p->iCenterOfSweep_ = ntohs(p->iCenterOfSweep_); + p->jCenterOfSweep_ = ntohs(p->jCenterOfSweep_); + p->rangeScaleFactor_ = ntohs(p->rangeScaleFactor_); + p->numberOfRadials_ = ntohs(p->numberOfRadials_); + + if (is.eof()) + { + BOOST_LOG_TRIVIAL(debug) << logPrefix_ << "Reached end of file"; + blockValid = false; + } + else + { + if (p->packetCode_ != 16) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ << "Invalid packet code: " << p->packetCode_; + blockValid = false; + } + if (p->numberOfRangeBins_ < 0 || p->numberOfRangeBins_ > 1840) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ + << "Invalid number of range bins: " << p->numberOfRangeBins_; + blockValid = false; + } + if (p->numberOfRadials_ < 1 || p->numberOfRadials_ > 720) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ + << "Invalid number of radials: " << p->numberOfRadials_; + blockValid = false; + } + } + + if (blockValid) + { + p->radial_.resize(p->numberOfRadials_); + + for (uint16_t r = 0; r < p->numberOfRadials_; r++) + { + auto& radial = p->radial_[r]; + + is.read(reinterpret_cast(&radial.numberOfBytes_), 2); + is.read(reinterpret_cast(&radial.startAngle_), 2); + is.read(reinterpret_cast(&radial.deltaAngle_), 2); + bytesRead += 6; + + radial.numberOfBytes_ = ntohs(radial.numberOfBytes_); + radial.startAngle_ = ntohs(radial.startAngle_); + radial.deltaAngle_ = ntohs(radial.deltaAngle_); + + if (radial.numberOfBytes_ < 1 || radial.numberOfBytes_ > 1840) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ + << "Invalid number of bytes: " << radial.numberOfBytes_ + << " (Radial " << r << ")"; + blockValid = false; + break; + } + else if (radial.numberOfBytes_ < p->numberOfRangeBins_) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ << "Number of bytes < number of range bins: " + << radial.numberOfBytes_ << " < " << p->numberOfRangeBins_ + << " (Radial " << r << ")"; + blockValid = false; + break; + } + + // Read radial bins + size_t dataSize = p->numberOfRangeBins_; + radial.level_.resize(dataSize); + is.read(reinterpret_cast(radial.level_.data()), dataSize); + + is.seekg(radial.numberOfBytes_ - dataSize, std::ios_base::cur); + bytesRead += radial.numberOfBytes_; + } + } + + p->dataSize_ = bytesRead; + + if (!ValidateMessage(is, bytesRead)) + { + blockValid = false; + } + + return blockValid; +} + +std::shared_ptr +DigitalRadialDataArrayPacket::Create(std::istream& is) +{ + std::shared_ptr packet = + std::make_shared(); + + if (!packet->Parse(is)) + { + packet.reset(); + } + + return packet; +} + +} // namespace rpg +} // namespace wsr88d +} // namespace scwx diff --git a/wxdata/source/scwx/wsr88d/rpg/packet_factory.cpp b/wxdata/source/scwx/wsr88d/rpg/packet_factory.cpp index 88330bc6..3e525e57 100644 --- a/wxdata/source/scwx/wsr88d/rpg/packet_factory.cpp +++ b/wxdata/source/scwx/wsr88d/rpg/packet_factory.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -35,6 +36,7 @@ static const std::unordered_map create_ { {8, TextAndSpecialSymbolPacket::Create}, {9, LinkedVectorPacket::Create}, {10, UnlinkedVectorPacket::Create}, + {16, DigitalRadialDataArrayPacket::Create}, {17, DigitalPrecipitationDataArrayPacket::Create}, {18, PrecipitationRateDataArrayPacket::Create}, {0x0802, SetColorLevelPacket::Create}, diff --git a/wxdata/wxdata.cmake b/wxdata/wxdata.cmake index 7176d790..9bb95cce 100644 --- a/wxdata/wxdata.cmake +++ b/wxdata/wxdata.cmake @@ -47,6 +47,7 @@ set(SRC_WSR88D_RDA source/scwx/wsr88d/rda/clutter_filter_map.cpp source/scwx/wsr88d/rda/rda_status_data.cpp source/scwx/wsr88d/rda/volume_coverage_pattern_data.cpp) set(HDR_WSR88D_RPG include/scwx/wsr88d/rpg/digital_precipitation_data_array_packet.hpp + include/scwx/wsr88d/rpg/digital_radial_data_array_packet.hpp include/scwx/wsr88d/rpg/level3_message_header.hpp include/scwx/wsr88d/rpg/linked_contour_vector_packet.hpp include/scwx/wsr88d/rpg/linked_vector_packet.hpp @@ -63,6 +64,7 @@ set(HDR_WSR88D_RPG include/scwx/wsr88d/rpg/digital_precipitation_data_array_pack include/scwx/wsr88d/rpg/unlinked_vector_packet.hpp include/scwx/wsr88d/rpg/wmo_header.hpp) set(SRC_WSR88D_RPG source/scwx/wsr88d/rpg/digital_precipitation_data_array_packet.cpp + source/scwx/wsr88d/rpg/digital_radial_data_array_packet.cpp source/scwx/wsr88d/rpg/level3_message_header.cpp source/scwx/wsr88d/rpg/linked_contour_vector_packet.cpp source/scwx/wsr88d/rpg/linked_vector_packet.cpp