From c9617f13b026ecbf6694cc0db0b942195220b4d1 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Fri, 7 Jan 2022 01:10:41 -0600 Subject: [PATCH] Radial data packet --- .../scwx/wsr88d/rpg/radial_data_packet.hpp | 49 ++++ .../source/scwx/wsr88d/rpg/packet_factory.cpp | 7 +- .../wsr88d/rpg/product_symbology_block.cpp | 2 + .../scwx/wsr88d/rpg/radial_data_packet.cpp | 225 ++++++++++++++++++ wxdata/wxdata.cmake | 2 + 5 files changed, 284 insertions(+), 1 deletion(-) create mode 100644 wxdata/include/scwx/wsr88d/rpg/radial_data_packet.hpp create mode 100644 wxdata/source/scwx/wsr88d/rpg/radial_data_packet.cpp diff --git a/wxdata/include/scwx/wsr88d/rpg/radial_data_packet.hpp b/wxdata/include/scwx/wsr88d/rpg/radial_data_packet.hpp new file mode 100644 index 00000000..69296341 --- /dev/null +++ b/wxdata/include/scwx/wsr88d/rpg/radial_data_packet.hpp @@ -0,0 +1,49 @@ +#pragma once + +#include + +#include +#include + +namespace scwx +{ +namespace wsr88d +{ +namespace rpg +{ + +class RadialDataPacketImpl; + +class RadialDataPacket : public Packet +{ +public: + explicit RadialDataPacket(); + ~RadialDataPacket(); + + RadialDataPacket(const RadialDataPacket&) = delete; + RadialDataPacket& operator=(const RadialDataPacket&) = delete; + + RadialDataPacket(RadialDataPacket&&) noexcept; + RadialDataPacket& operator=(RadialDataPacket&&) 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 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/packet_factory.cpp b/wxdata/source/scwx/wsr88d/rpg/packet_factory.cpp index e689a035..1a9b742a 100644 --- a/wxdata/source/scwx/wsr88d/rpg/packet_factory.cpp +++ b/wxdata/source/scwx/wsr88d/rpg/packet_factory.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -33,7 +34,8 @@ static const std::unordered_map create_ { {10, UnlinkedVectorPacket::Create}, {0x0802, SetColorLevelPacket::Create}, {0x0E03, LinkedContourVectorPacket::Create}, - {0x3501, UnlinkedContourVectorPacket::Create}}; + {0x3501, UnlinkedContourVectorPacket::Create}, + {0xAF1F, RadialDataPacket::Create}}; std::shared_ptr PacketFactory::Create(std::istream& is) { @@ -62,6 +64,9 @@ std::shared_ptr PacketFactory::Create(std::istream& is) if (packetValid) { + BOOST_LOG_TRIVIAL(trace) + << logPrefix_ << "Found packet code: " << packetCode << " (0x" + << std::hex << packetCode << std::dec << ")"; packet = create_.at(packetCode)(is); } diff --git a/wxdata/source/scwx/wsr88d/rpg/product_symbology_block.cpp b/wxdata/source/scwx/wsr88d/rpg/product_symbology_block.cpp index 4d5f3d12..6515fae3 100644 --- a/wxdata/source/scwx/wsr88d/rpg/product_symbology_block.cpp +++ b/wxdata/source/scwx/wsr88d/rpg/product_symbology_block.cpp @@ -109,6 +109,8 @@ bool ProductSymbologyBlock::Parse(std::istream& is) for (uint16_t i = 0; i < p->numberOfLayers_; i++) { + BOOST_LOG_TRIVIAL(trace) << logPrefix_ << "Layer " << i; + std::vector> packetList; is.read(reinterpret_cast(&layerDivider), 2); diff --git a/wxdata/source/scwx/wsr88d/rpg/radial_data_packet.cpp b/wxdata/source/scwx/wsr88d/rpg/radial_data_packet.cpp new file mode 100644 index 00000000..f6669594 --- /dev/null +++ b/wxdata/source/scwx/wsr88d/rpg/radial_data_packet.cpp @@ -0,0 +1,225 @@ +#include + +#include +#include + +#include + +namespace scwx +{ +namespace wsr88d +{ +namespace rpg +{ + +static const std::string logPrefix_ = + "[scwx::wsr88d::rpg::radial_data_packet] "; + +struct Radial +{ + uint16_t numberOfRleHalfwords_; + uint16_t startAngle_; + uint16_t angleDelta_; + std::vector data_; + + Radial() : + numberOfRleHalfwords_ {0}, startAngle_ {0}, angleDelta_ {0}, data_ {} + { + } +}; + +class RadialDataPacketImpl +{ +public: + explicit RadialDataPacketImpl() : + packetCode_ {}, + indexOfFirstRangeBin_ {}, + numberOfRangeBins_ {}, + iCenterOfSweep_ {}, + jCenterOfSweep_ {}, + scaleFactor_ {}, + dataSize_ {} {}; + ~RadialDataPacketImpl() = default; + + uint16_t packetCode_; + uint16_t indexOfFirstRangeBin_; + uint16_t numberOfRangeBins_; + int16_t iCenterOfSweep_; + int16_t jCenterOfSweep_; + uint16_t scaleFactor_; + uint16_t numberOfRadials_; + + // Repeat for each radial + std::vector radial_; + + size_t dataSize_; +}; + +RadialDataPacket::RadialDataPacket() : + p(std::make_unique()) +{ +} +RadialDataPacket::~RadialDataPacket() = default; + +RadialDataPacket::RadialDataPacket(RadialDataPacket&&) noexcept = default; +RadialDataPacket& +RadialDataPacket::operator=(RadialDataPacket&&) noexcept = default; + +uint16_t RadialDataPacket::packet_code() const +{ + return p->packetCode_; +} + +uint16_t RadialDataPacket::index_of_first_range_bin() const +{ + return p->indexOfFirstRangeBin_; +} + +uint16_t RadialDataPacket::number_of_range_bins() const +{ + return p->numberOfRangeBins_; +} + +int16_t RadialDataPacket::i_center_of_sweep() const +{ + return p->iCenterOfSweep_; +} + +int16_t RadialDataPacket::j_center_of_sweep() const +{ + return p->jCenterOfSweep_; +} + +float RadialDataPacket::scale_factor() const +{ + return p->scaleFactor_ * 0.001f; +} + +uint16_t RadialDataPacket::number_of_radials() const +{ + return p->numberOfRadials_; +} + +size_t RadialDataPacket::data_size() const +{ + return p->dataSize_; +} + +bool RadialDataPacket::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->scaleFactor_), 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->scaleFactor_ = ntohs(p->scaleFactor_); + p->numberOfRadials_ = ntohs(p->numberOfRadials_); + + if (is.eof()) + { + BOOST_LOG_TRIVIAL(debug) << logPrefix_ << "Reached end of file"; + blockValid = false; + } + else + { + if (p->packetCode_ != 0xAF1F) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ << "Invalid packet code: " << p->packetCode_; + blockValid = false; + } + if (p->numberOfRangeBins_ < 1 || p->numberOfRangeBins_ > 460) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ + << "Invalid number of range bins: " << p->numberOfRangeBins_; + blockValid = false; + } + if (p->numberOfRadials_ < 1 || p->numberOfRadials_ > 400) + { + 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++) + { + Radial& radial = p->radial_[r]; + + is.read(reinterpret_cast(&radial.numberOfRleHalfwords_), 2); + is.read(reinterpret_cast(&radial.startAngle_), 2); + is.read(reinterpret_cast(&radial.angleDelta_), 2); + bytesRead += 6; + + radial.numberOfRleHalfwords_ = ntohs(radial.numberOfRleHalfwords_); + radial.startAngle_ = ntohs(radial.startAngle_); + radial.angleDelta_ = ntohs(radial.angleDelta_); + + if (radial.numberOfRleHalfwords_ < 1 || + radial.numberOfRleHalfwords_ > 230) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ << "Invalid number of RLE halfwords: " + << radial.numberOfRleHalfwords_ << " (Radial " << r << ")"; + blockValid = false; + break; + } + + // Read RLE halfwords + size_t dataSize = radial.numberOfRleHalfwords_ * 2; + radial.data_.resize(dataSize); + is.read(reinterpret_cast(radial.data_.data()), dataSize); + bytesRead += dataSize; + + // If the final byte is 0, truncate it + if (radial.data_.back() == 0) + { + radial.data_.pop_back(); + } + } + } + + p->dataSize_ = bytesRead; + + if (!ValidateMessage(is, bytesRead)) + { + blockValid = false; + } + + return blockValid; +} + +std::shared_ptr RadialDataPacket::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/wxdata.cmake b/wxdata/wxdata.cmake index 93c430ff..2fc3c8c3 100644 --- a/wxdata/wxdata.cmake +++ b/wxdata/wxdata.cmake @@ -53,6 +53,7 @@ set(HDR_WSR88D_RPG include/scwx/wsr88d/rpg/level3_message_header.hpp include/scwx/wsr88d/rpg/packet_factory.hpp include/scwx/wsr88d/rpg/product_description_block.hpp include/scwx/wsr88d/rpg/product_symbology_block.hpp + include/scwx/wsr88d/rpg/radial_data_packet.hpp include/scwx/wsr88d/rpg/set_color_level_packet.hpp include/scwx/wsr88d/rpg/text_and_special_symbol_packet.hpp include/scwx/wsr88d/rpg/unlinked_contour_vector_packet.hpp @@ -65,6 +66,7 @@ set(SRC_WSR88D_RPG source/scwx/wsr88d/rpg/level3_message_header.cpp source/scwx/wsr88d/rpg/packet_factory.cpp source/scwx/wsr88d/rpg/product_description_block.cpp source/scwx/wsr88d/rpg/product_symbology_block.cpp + source/scwx/wsr88d/rpg/radial_data_packet.cpp source/scwx/wsr88d/rpg/set_color_level_packet.cpp source/scwx/wsr88d/rpg/text_and_special_symbol_packet.cpp source/scwx/wsr88d/rpg/unlinked_contour_vector_packet.cpp