From ef56f555298b5b1b00618b70c6ca1a1059adecee Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Fri, 7 Jan 2022 19:51:42 -0600 Subject: [PATCH] Raster data packet --- .../scwx/wsr88d/rpg/raster_data_packet.hpp | 52 ++++ .../source/scwx/wsr88d/rpg/packet_factory.cpp | 5 +- .../scwx/wsr88d/rpg/raster_data_packet.cpp | 241 ++++++++++++++++++ wxdata/wxdata.cmake | 2 + 4 files changed, 299 insertions(+), 1 deletion(-) create mode 100644 wxdata/include/scwx/wsr88d/rpg/raster_data_packet.hpp create mode 100644 wxdata/source/scwx/wsr88d/rpg/raster_data_packet.cpp diff --git a/wxdata/include/scwx/wsr88d/rpg/raster_data_packet.hpp b/wxdata/include/scwx/wsr88d/rpg/raster_data_packet.hpp new file mode 100644 index 00000000..db1e0726 --- /dev/null +++ b/wxdata/include/scwx/wsr88d/rpg/raster_data_packet.hpp @@ -0,0 +1,52 @@ +#pragma once + +#include + +#include +#include + +namespace scwx +{ +namespace wsr88d +{ +namespace rpg +{ + +class RasterDataPacketImpl; + +class RasterDataPacket : public Packet +{ +public: + explicit RasterDataPacket(); + ~RasterDataPacket(); + + RasterDataPacket(const RasterDataPacket&) = delete; + RasterDataPacket& operator=(const RasterDataPacket&) = delete; + + RasterDataPacket(RasterDataPacket&&) noexcept; + RasterDataPacket& operator=(RasterDataPacket&&) noexcept; + + uint16_t packet_code() const; + uint16_t op_flag(size_t i) const; + int16_t i_coordinate_start() const; + int16_t j_coordinate_start() const; + uint16_t x_scale_int() const; + uint16_t x_scale_fractional() const; + uint16_t y_scale_int() const; + uint16_t y_scale_fractional() const; + uint16_t number_of_rows() const; + uint16_t packaging_descriptor() 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 1a9b742a..ed02c776 100644 --- a/wxdata/source/scwx/wsr88d/rpg/packet_factory.cpp +++ b/wxdata/source/scwx/wsr88d/rpg/packet_factory.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -35,7 +36,9 @@ static const std::unordered_map create_ { {0x0802, SetColorLevelPacket::Create}, {0x0E03, LinkedContourVectorPacket::Create}, {0x3501, UnlinkedContourVectorPacket::Create}, - {0xAF1F, RadialDataPacket::Create}}; + {0xAF1F, RadialDataPacket::Create}, + {0xBA07, RasterDataPacket::Create}, + {0xBA0F, RasterDataPacket::Create}}; std::shared_ptr PacketFactory::Create(std::istream& is) { diff --git a/wxdata/source/scwx/wsr88d/rpg/raster_data_packet.cpp b/wxdata/source/scwx/wsr88d/rpg/raster_data_packet.cpp new file mode 100644 index 00000000..ecb271d3 --- /dev/null +++ b/wxdata/source/scwx/wsr88d/rpg/raster_data_packet.cpp @@ -0,0 +1,241 @@ +#include + +#include +#include + +#include + +namespace scwx +{ +namespace wsr88d +{ +namespace rpg +{ + +static const std::string logPrefix_ = + "[scwx::wsr88d::rpg::raster_data_packet] "; + +struct Row +{ + uint16_t numberOfBytes_; + std::vector data_; + + Row() : numberOfBytes_ {0}, data_ {} {} +}; + +class RasterDataPacketImpl +{ +public: + explicit RasterDataPacketImpl() : + packetCode_ {}, + opFlag_ {}, + iCoordinateStart_ {}, + jCoordinateStart_ {}, + xScaleInt_ {}, + xScaleFractional_ {}, + yScaleInt_ {}, + yScaleFractional_ {}, + numberOfRows_ {}, + packagingDescriptor_ {}, + row_ {}, + dataSize_ {} {}; + ~RasterDataPacketImpl() = default; + + uint16_t packetCode_; + std::array opFlag_; + int16_t iCoordinateStart_; + int16_t jCoordinateStart_; + uint16_t xScaleInt_; + uint16_t xScaleFractional_; + uint16_t yScaleInt_; + uint16_t yScaleFractional_; + uint16_t numberOfRows_; + uint16_t packagingDescriptor_; + + // Repeat for each radial + std::vector row_; + + size_t dataSize_; +}; + +RasterDataPacket::RasterDataPacket() : + p(std::make_unique()) +{ +} +RasterDataPacket::~RasterDataPacket() = default; + +RasterDataPacket::RasterDataPacket(RasterDataPacket&&) noexcept = default; +RasterDataPacket& +RasterDataPacket::operator=(RasterDataPacket&&) noexcept = default; + +uint16_t RasterDataPacket::packet_code() const +{ + return p->packetCode_; +} + +uint16_t RasterDataPacket::op_flag(size_t i) const +{ + return p->opFlag_[i]; +} + +int16_t RasterDataPacket::i_coordinate_start() const +{ + return p->iCoordinateStart_; +} + +int16_t RasterDataPacket::j_coordinate_start() const +{ + return p->jCoordinateStart_; +} + +uint16_t RasterDataPacket::x_scale_int() const +{ + return p->xScaleInt_; +} + +uint16_t RasterDataPacket::x_scale_fractional() const +{ + return p->xScaleFractional_; +} + +uint16_t RasterDataPacket::y_scale_int() const +{ + return p->yScaleInt_; +} + +uint16_t RasterDataPacket::y_scale_fractional() const +{ + return p->yScaleFractional_; +} + +uint16_t RasterDataPacket::number_of_rows() const +{ + return p->numberOfRows_; +} + +uint16_t RasterDataPacket::packaging_descriptor() const +{ + return p->packagingDescriptor_; +} + +size_t RasterDataPacket::data_size() const +{ + return p->dataSize_; +} + +bool RasterDataPacket::Parse(std::istream& is) +{ + bool blockValid = true; + size_t bytesRead = 0; + + is.read(reinterpret_cast(&p->packetCode_), 2); + is.read(reinterpret_cast(p->opFlag_.data()), 4); + is.read(reinterpret_cast(&p->iCoordinateStart_), 2); + is.read(reinterpret_cast(&p->jCoordinateStart_), 2); + is.read(reinterpret_cast(&p->xScaleInt_), 2); + is.read(reinterpret_cast(&p->xScaleFractional_), 2); + is.read(reinterpret_cast(&p->yScaleInt_), 2); + is.read(reinterpret_cast(&p->yScaleFractional_), 2); + is.read(reinterpret_cast(&p->numberOfRows_), 2); + is.read(reinterpret_cast(&p->packagingDescriptor_), 2); + bytesRead += 22; + + p->packetCode_ = ntohs(p->packetCode_); + p->iCoordinateStart_ = ntohs(p->iCoordinateStart_); + p->jCoordinateStart_ = ntohs(p->jCoordinateStart_); + p->xScaleInt_ = ntohs(p->xScaleInt_); + p->xScaleFractional_ = ntohs(p->xScaleFractional_); + p->yScaleInt_ = ntohs(p->yScaleInt_); + p->yScaleFractional_ = ntohs(p->yScaleFractional_); + p->numberOfRows_ = ntohs(p->numberOfRows_); + p->packagingDescriptor_ = ntohs(p->packagingDescriptor_); + + SwapArray(p->opFlag_); + + if (is.eof()) + { + BOOST_LOG_TRIVIAL(debug) << logPrefix_ << "Reached end of file"; + blockValid = false; + } + else + { + if (p->packetCode_ != 0xBA0F && p->packetCode_ != 0xBA07) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ << "Invalid packet code: " << p->packetCode_; + blockValid = false; + } + if (p->numberOfRows_ < 1 || p->numberOfRows_ > 464) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ << "Invalid number of rows: " << p->numberOfRows_; + blockValid = false; + } + } + + if (blockValid) + { + p->row_.resize(p->numberOfRows_); + + for (uint16_t r = 0; r < p->numberOfRows_; r++) + { + size_t rowBytesRead = 0; + + Row& row = p->row_[r]; + + is.read(reinterpret_cast(&row.numberOfBytes_), 2); + bytesRead += 2; + + row.numberOfBytes_ = ntohs(row.numberOfBytes_); + + if (row.numberOfBytes_ < 2 || row.numberOfBytes_ > 920 || + row.numberOfBytes_ % 2 != 0) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ + << "Invalid number of bytes in row: " << row.numberOfBytes_ + << " (Row " << r << ")"; + blockValid = false; + break; + } + + // Read row data + size_t dataSize = row.numberOfBytes_; + row.data_.resize(dataSize); + is.read(reinterpret_cast(row.data_.data()), dataSize); + bytesRead += dataSize; + + // If the final byte is 0, truncate it + if (row.data_.back() == 0) + { + row.data_.pop_back(); + } + } + } + + p->dataSize_ = bytesRead; + + if (!ValidateMessage(is, bytesRead)) + { + blockValid = false; + } + + return blockValid; +} + +std::shared_ptr RasterDataPacket::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 2fc3c8c3..30ef1e41 100644 --- a/wxdata/wxdata.cmake +++ b/wxdata/wxdata.cmake @@ -54,6 +54,7 @@ set(HDR_WSR88D_RPG include/scwx/wsr88d/rpg/level3_message_header.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/raster_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 @@ -67,6 +68,7 @@ set(SRC_WSR88D_RPG source/scwx/wsr88d/rpg/level3_message_header.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/raster_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