mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 04:30:05 +00:00 
			
		
		
		
	Update Archive II processing to better handle older data sets
This commit is contained in:
		
							parent
							
								
									fdd09011f4
								
							
						
					
					
						commit
						243a7c870c
					
				
					 4 changed files with 110 additions and 65 deletions
				
			
		|  | @ -19,6 +19,7 @@ | |||
| #   pragma GCC diagnostic ignored "-Wdeprecated-copy" | ||||
| #endif | ||||
| 
 | ||||
| #include <boost/algorithm/string/trim.hpp> | ||||
| #include <boost/iostreams/copy.hpp> | ||||
| #include <boost/iostreams/filtering_streambuf.hpp> | ||||
| #include <boost/iostreams/filter/bzip2.hpp> | ||||
|  | @ -42,16 +43,7 @@ static const auto        logger_    = util::Logger::Create(logPrefix_); | |||
| class Ar2vFileImpl | ||||
| { | ||||
| public: | ||||
|    explicit Ar2vFileImpl() : | ||||
|        tapeFilename_ {}, | ||||
|        extensionNumber_ {}, | ||||
|        julianDate_ {0}, | ||||
|        milliseconds_ {0}, | ||||
|        icao_ {}, | ||||
|        vcpData_ {nullptr}, | ||||
|        radarData_ {}, | ||||
|        index_ {}, | ||||
|        rawRecords_ {} {}; | ||||
|    explicit Ar2vFileImpl() {}; | ||||
|    ~Ar2vFileImpl() = default; | ||||
| 
 | ||||
|    std::size_t DecompressLDMRecords(std::istream& is); | ||||
|  | @ -61,20 +53,22 @@ public: | |||
|    void        ParseLDMRecord(std::istream& is); | ||||
|    void ProcessRadarData(const std::shared_ptr<rda::GenericRadarData>& message); | ||||
| 
 | ||||
|    std::string   tapeFilename_; | ||||
|    std::string   extensionNumber_; | ||||
|    std::uint32_t julianDate_; | ||||
|    std::uint32_t milliseconds_; | ||||
|    std::string   icao_; | ||||
|    std::string   tapeFilename_ {}; | ||||
|    std::string   extensionNumber_ {}; | ||||
|    std::uint32_t julianDate_ {0}; | ||||
|    std::uint32_t milliseconds_ {0}; | ||||
|    std::string   icao_ {}; | ||||
| 
 | ||||
|    std::shared_ptr<rda::VolumeCoveragePatternData>              vcpData_; | ||||
|    std::map<std::uint16_t, std::shared_ptr<rda::ElevationScan>> radarData_; | ||||
|    std::size_t messageCount_ {0}; | ||||
| 
 | ||||
|    std::shared_ptr<rda::VolumeCoveragePatternData>              vcpData_ {}; | ||||
|    std::map<std::uint16_t, std::shared_ptr<rda::ElevationScan>> radarData_ {}; | ||||
| 
 | ||||
|    std::map<rda::DataBlockType, | ||||
|             std::map<std::uint16_t, std::shared_ptr<rda::ElevationScan>>> | ||||
|       index_; | ||||
|       index_ {}; | ||||
| 
 | ||||
|    std::list<std::stringstream> rawRecords_; | ||||
|    std::list<std::stringstream> rawRecords_ {}; | ||||
| }; | ||||
| 
 | ||||
| Ar2vFile::Ar2vFile() : p(std::make_unique<Ar2vFileImpl>()) {} | ||||
|  | @ -98,6 +92,11 @@ std::string Ar2vFile::icao() const | |||
|    return p->icao_; | ||||
| } | ||||
| 
 | ||||
| std::size_t Ar2vFile::message_count() const | ||||
| { | ||||
|    return p->messageCount_; | ||||
| } | ||||
| 
 | ||||
| std::chrono::system_clock::time_point Ar2vFile::start_time() const | ||||
| { | ||||
|    return util::TimePoint(p->julianDate_, p->milliseconds_); | ||||
|  | @ -235,6 +234,10 @@ bool Ar2vFile::LoadData(std::istream& is) | |||
|       dataValid = false; | ||||
|    } | ||||
| 
 | ||||
|    // Trim spaces and null characters from the end of the ICAO
 | ||||
|    boost::trim_right_if(p->icao_, | ||||
|                         [](char x) { return std::isspace(x) || x == '\0'; }); | ||||
| 
 | ||||
|    if (dataValid) | ||||
|    { | ||||
|       logger_->debug("Filename:  {}", p->tapeFilename_); | ||||
|  | @ -334,55 +337,71 @@ void Ar2vFileImpl::ParseLDMRecords() | |||
| 
 | ||||
| void Ar2vFileImpl::ParseLDMRecord(std::istream& is) | ||||
| { | ||||
|    static constexpr std::size_t kDefaultSegmentSize = 2432; | ||||
|    static constexpr std::size_t kCtmHeaderSize      = 12; | ||||
| 
 | ||||
|    auto ctx = rda::Level2MessageFactory::CreateContext(); | ||||
| 
 | ||||
|    // The communications manager inserts an extra 12 bytes at the beginning
 | ||||
|    // of each record
 | ||||
|    is.seekg(12, std::ios_base::cur); | ||||
| 
 | ||||
|    while (!is.eof()) | ||||
|    while (!is.eof() && !is.fail()) | ||||
|    { | ||||
|       off_t         offset   = 0; | ||||
|       std::uint16_t nextSize = 0u; | ||||
|       do | ||||
|       // The communications manager inserts an extra 12 bytes at the beginning
 | ||||
|       // of each record
 | ||||
|       is.seekg(kCtmHeaderSize, std::ios_base::cur); | ||||
| 
 | ||||
|       // Each message requires 2432 bytes of storage, with the exception of
 | ||||
|       // Message Types 29 and 31.
 | ||||
|       std::size_t messageSize = kDefaultSegmentSize - kCtmHeaderSize; | ||||
| 
 | ||||
|       // Mark current position
 | ||||
|       std::streampos messageStart = is.tellg(); | ||||
| 
 | ||||
|       // Parse the header
 | ||||
|       rda::Level2MessageHeader messageHeader; | ||||
|       bool                     headerValid = messageHeader.Parse(is); | ||||
|       is.seekg(messageStart, std::ios_base::beg); | ||||
| 
 | ||||
|       if (headerValid) | ||||
|       { | ||||
|          is.read(reinterpret_cast<char*>(&nextSize), 2); | ||||
|          if (nextSize == 0) | ||||
|          std::uint8_t messageType = messageHeader.message_type(); | ||||
| 
 | ||||
|          // Each message requires 2432 bytes of storage, with the exception of
 | ||||
|          // Message Types 29 and 31.
 | ||||
|          if (messageType == 29 || messageType == 31) | ||||
|          { | ||||
|             offset += 2; | ||||
|             if (messageHeader.message_size() == 65535) | ||||
|             { | ||||
|                messageSize = (static_cast<std::size_t>( | ||||
|                                  messageHeader.number_of_message_segments()) | ||||
|                               << 16) + | ||||
|                              messageHeader.message_segment_number(); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                messageSize = | ||||
|                   static_cast<std::size_t>(messageHeader.message_size()) * 2; | ||||
|             } | ||||
|          } | ||||
|          else | ||||
| 
 | ||||
|          // Parse the current message
 | ||||
|          rda::Level2MessageInfo msgInfo = | ||||
|             rda::Level2MessageFactory::Create(is, ctx); | ||||
| 
 | ||||
|          if (msgInfo.messageValid) | ||||
|          { | ||||
|             is.seekg(-2, std::ios_base::cur); | ||||
|             HandleMessage(msgInfo.message); | ||||
|          } | ||||
|       } while (!is.eof() && !is.fail() && nextSize == 0u); | ||||
| 
 | ||||
|       if (!is.eof() && !is.fail() && offset != 0) | ||||
|       { | ||||
|          logger_->trace("Next record offset by {} bytes", offset); | ||||
|       } | ||||
|       else if (is.eof() || is.fail()) | ||||
|       { | ||||
|          break; | ||||
|       } | ||||
| 
 | ||||
|       rda::Level2MessageInfo msgInfo = | ||||
|          rda::Level2MessageFactory::Create(is, ctx); | ||||
|       if (!msgInfo.headerValid) | ||||
|       { | ||||
|          // Invalid message
 | ||||
|          break; | ||||
|       } | ||||
| 
 | ||||
|       if (msgInfo.messageValid) | ||||
|       { | ||||
|          HandleMessage(msgInfo.message); | ||||
|       } | ||||
|       // Skip to next message
 | ||||
|       is.seekg(messageStart + static_cast<std::streampos>(messageSize), | ||||
|                std::ios_base::beg); | ||||
|    } | ||||
| } | ||||
| 
 | ||||
| void Ar2vFileImpl::HandleMessage(std::shared_ptr<rda::Level2Message>& message) | ||||
| { | ||||
|    ++messageCount_; | ||||
| 
 | ||||
|    switch (message->header().message_type()) | ||||
|    { | ||||
|    case static_cast<std::uint8_t>(rda::MessageId::VolumeCoveragePatternData): | ||||
|  |  | |||
|  | @ -70,6 +70,30 @@ Level2MessageInfo Level2MessageFactory::Create(std::istream&             is, | |||
|    info.headerValid  = header.Parse(is); | ||||
|    info.messageValid = info.headerValid; | ||||
| 
 | ||||
|    std::uint16_t segment       = 0; | ||||
|    std::uint16_t totalSegments = 0; | ||||
|    std::size_t   dataSize      = 0; | ||||
| 
 | ||||
|    if (info.headerValid) | ||||
|    { | ||||
|       if (header.message_size() == 65535) | ||||
|       { | ||||
|          segment       = 1; | ||||
|          totalSegments = 1; | ||||
|          dataSize = | ||||
|             (static_cast<std::size_t>(header.number_of_message_segments()) | ||||
|              << 16) + | ||||
|             header.message_segment_number(); | ||||
|       } | ||||
|       else | ||||
|       { | ||||
|          segment       = header.message_segment_number(); | ||||
|          totalSegments = header.number_of_message_segments(); | ||||
|          dataSize      = static_cast<std::size_t>(header.message_size()) * 2 - | ||||
|                     Level2MessageHeader::SIZE; | ||||
|       } | ||||
|    } | ||||
| 
 | ||||
|    if (info.headerValid && create_.find(header.message_type()) == create_.end()) | ||||
|    { | ||||
|       logger_->warn("Unknown message type: {}", | ||||
|  | @ -79,10 +103,7 @@ Level2MessageInfo Level2MessageFactory::Create(std::istream&             is, | |||
| 
 | ||||
|    if (info.messageValid) | ||||
|    { | ||||
|       uint16_t segment       = header.message_segment_number(); | ||||
|       uint16_t totalSegments = header.number_of_message_segments(); | ||||
|       uint8_t  messageType   = header.message_type(); | ||||
|       size_t   dataSize = header.message_size() * 2 - Level2MessageHeader::SIZE; | ||||
|       std::uint8_t messageType = header.message_type(); | ||||
| 
 | ||||
|       std::istream* messageStream = nullptr; | ||||
| 
 | ||||
|  | @ -165,8 +186,7 @@ Level2MessageInfo Level2MessageFactory::Create(std::istream&             is, | |||
|    else if (info.headerValid) | ||||
|    { | ||||
|       // Seek to the end of the current message
 | ||||
|       is.seekg(header.message_size() * 2 - rda::Level2MessageHeader::SIZE, | ||||
|                std::ios_base::cur); | ||||
|       is.seekg(dataSize, std::ios_base::cur); | ||||
|    } | ||||
| 
 | ||||
|    if (info.message == nullptr) | ||||
|  |  | |||
|  | @ -130,7 +130,10 @@ bool Level2MessageHeader::Parse(std::istream& is) | |||
|    { | ||||
|       if (p->messageSize_ < 9) | ||||
|       { | ||||
|          logger_->warn("Invalid message size: {}", p->messageSize_); | ||||
|          if (p->messageSize_ != 0) | ||||
|          { | ||||
|             logger_->warn("Invalid message size: {}", p->messageSize_); | ||||
|          } | ||||
|          headerValid = false; | ||||
|       } | ||||
|       if (p->millisecondsOfDay_ > 86'399'999u) | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dan Paulat
						Dan Paulat