mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-30 06:50:06 +00:00 
			
		
		
		
	Parse Digital Radar Data (Message Type 31)
This commit is contained in:
		
							parent
							
								
									6acb6a8c9d
								
							
						
					
					
						commit
						f0386cda27
					
				
					 8 changed files with 589 additions and 28 deletions
				
			
		
							
								
								
									
										37
									
								
								wxdata/include/scwx/wsr88d/rda/digital_radar_data.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								wxdata/include/scwx/wsr88d/rda/digital_radar_data.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,37 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <scwx/wsr88d/rda/message.hpp> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace wsr88d | ||||
| { | ||||
| namespace rda | ||||
| { | ||||
| 
 | ||||
| class DigitalRadarDataImpl; | ||||
| 
 | ||||
| class DigitalRadarData : public Message | ||||
| { | ||||
| public: | ||||
|    explicit DigitalRadarData(); | ||||
|    ~DigitalRadarData(); | ||||
| 
 | ||||
|    DigitalRadarData(const Message&) = delete; | ||||
|    DigitalRadarData& operator=(const DigitalRadarData&) = delete; | ||||
| 
 | ||||
|    DigitalRadarData(DigitalRadarData&&) noexcept; | ||||
|    DigitalRadarData& operator=(DigitalRadarData&&) noexcept; | ||||
| 
 | ||||
|    bool Parse(std::istream& is); | ||||
| 
 | ||||
|    static std::unique_ptr<DigitalRadarData> Create(MessageHeader&& header, | ||||
|                                                    std::istream&   is); | ||||
| 
 | ||||
| private: | ||||
|    std::unique_ptr<DigitalRadarDataImpl> p; | ||||
| }; | ||||
| 
 | ||||
| } // namespace rda
 | ||||
| } // namespace wsr88d
 | ||||
| } // namespace scwx
 | ||||
|  | @ -36,6 +36,18 @@ protected: | |||
| 
 | ||||
|    bool ValidateMessage(std::istream& is, size_t bytesRead) const; | ||||
| 
 | ||||
| public: | ||||
|    virtual ~Message(); | ||||
| 
 | ||||
|    const MessageHeader& header() const; | ||||
| 
 | ||||
|    void set_header(MessageHeader&& header); | ||||
| 
 | ||||
|    virtual bool Parse(std::istream& is) = 0; | ||||
| 
 | ||||
|    static constexpr double ANGLE_DATA_SCALE      = 0.005493125; | ||||
|    static constexpr double AZ_EL_RATE_DATA_SCALE = 0.001373291015625; | ||||
| 
 | ||||
|    static void ReadBoolean(std::istream& is, bool& value) | ||||
|    { | ||||
|       std::string data(4, ' '); | ||||
|  | @ -56,45 +68,43 @@ protected: | |||
|    } | ||||
| 
 | ||||
|    template<size_t _Size> | ||||
|    static void SwapFloatArray(std::array<float, _Size>& arr) | ||||
|    static void SwapArray(std::array<float, _Size>& arr, size_t size = _Size) | ||||
|    { | ||||
|       std::transform(std::execution::par_unseq, | ||||
|                      arr.begin(), | ||||
|                      arr.end(), | ||||
|                      arr.begin() + size, | ||||
|                      arr.begin(), | ||||
|                      [](float f) { return SwapFloat(f); }); | ||||
|    } | ||||
| 
 | ||||
|    template<size_t _Size> | ||||
|    static void SwapUInt16Array(std::array<uint16_t, _Size>& arr) | ||||
|    static void SwapArray(std::array<uint16_t, _Size>& arr, size_t size = _Size) | ||||
|    { | ||||
|       std::transform(std::execution::par_unseq, | ||||
|                      arr.begin(), | ||||
|                      arr.end(), | ||||
|                      arr.begin() + size, | ||||
|                      arr.begin(), | ||||
|                      [](uint16_t u) { return ntohs(u); }); | ||||
|    } | ||||
| 
 | ||||
|    template<size_t _Size> | ||||
|    static void SwapArray(std::array<uint32_t, _Size>& arr, size_t size = _Size) | ||||
|    { | ||||
|       std::transform(std::execution::par_unseq, | ||||
|                      arr.begin(), | ||||
|                      arr.begin() + size, | ||||
|                      arr.begin(), | ||||
|                      [](uint32_t u) { return ntohl(u); }); | ||||
|    } | ||||
| 
 | ||||
|    template<typename T> | ||||
|    static void SwapFloatMap(std::map<T, float>& m) | ||||
|    static void SwapMap(std::map<T, float>& m) | ||||
|    { | ||||
|       std::for_each(std::execution::par_unseq, m.begin(), m.end(), [](auto& p) { | ||||
|          p.second = SwapFloat(p.second); | ||||
|       }); | ||||
|    } | ||||
| 
 | ||||
| public: | ||||
|    virtual ~Message(); | ||||
| 
 | ||||
|    const MessageHeader& header() const; | ||||
| 
 | ||||
|    void set_header(MessageHeader&& header); | ||||
| 
 | ||||
|    virtual bool Parse(std::istream& is) = 0; | ||||
| 
 | ||||
|    static constexpr double ANGLE_DATA_SCALE      = 0.005493125; | ||||
|    static constexpr double AZ_EL_RATE_DATA_SCALE = 0.001373291015625; | ||||
| 
 | ||||
| private: | ||||
|    std::unique_ptr<MessageImpl> p; | ||||
| }; | ||||
|  |  | |||
							
								
								
									
										510
									
								
								wxdata/source/scwx/wsr88d/rda/digital_radar_data.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										510
									
								
								wxdata/source/scwx/wsr88d/rda/digital_radar_data.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,510 @@ | |||
| #include <scwx/wsr88d/rda/digital_radar_data.hpp> | ||||
| 
 | ||||
| #include <boost/log/trivial.hpp> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace wsr88d | ||||
| { | ||||
| namespace rda | ||||
| { | ||||
| 
 | ||||
| static const std::string logPrefix_ = | ||||
|    "[scwx::wsr88d::rda::digital_radar_data] "; | ||||
| 
 | ||||
| enum class DataBlockType | ||||
| { | ||||
|    Volume, | ||||
|    Elevation, | ||||
|    Radial, | ||||
|    MomentRef, | ||||
|    MomentVel, | ||||
|    MomentSw, | ||||
|    MomentZdr, | ||||
|    MomentPhi, | ||||
|    MomentRho, | ||||
|    MomentCfp, | ||||
|    Unknown | ||||
| }; | ||||
| 
 | ||||
| static const std::unordered_map<std::string, DataBlockType> strToDataBlock_ { | ||||
|    {"VOL", DataBlockType::Volume}, | ||||
|    {"ELV", DataBlockType::Elevation}, | ||||
|    {"RAD", DataBlockType::Radial}, | ||||
|    {"REF", DataBlockType::MomentRef}, | ||||
|    {"VEL", DataBlockType::MomentVel}, | ||||
|    {"SW ", DataBlockType::MomentSw}, | ||||
|    {"ZDR", DataBlockType::MomentZdr}, | ||||
|    {"PHI", DataBlockType::MomentPhi}, | ||||
|    {"RHO", DataBlockType::MomentRho}, | ||||
|    {"CFP", DataBlockType::MomentCfp}}; | ||||
| 
 | ||||
| struct DataBlock | ||||
| { | ||||
|    explicit DataBlock(const std::string& dataBlockType, | ||||
|                       const std::string& dataName) : | ||||
|        dataBlockType_ {dataBlockType}, dataName_ {dataName} | ||||
|    { | ||||
|    } | ||||
| 
 | ||||
|    std::string dataBlockType_; | ||||
|    std::string dataName_; | ||||
| }; | ||||
| 
 | ||||
| struct MomentDataBlock : DataBlock | ||||
| { | ||||
|    explicit MomentDataBlock(const std::string& dataBlockType, | ||||
|                             const std::string& dataName) : | ||||
|        DataBlock(dataBlockType, dataName), | ||||
|        numberOfDataMomentGates_ {0}, | ||||
|        dataMomentRange_ {0}, | ||||
|        dataMomentRangeSampleInterval_ {0}, | ||||
|        tover_ {0}, | ||||
|        snrThreshold_ {0}, | ||||
|        controlFlags_ {0}, | ||||
|        dataWordSize_ {0}, | ||||
|        scale_ {0.0f}, | ||||
|        offset_ {0.0f} | ||||
|    { | ||||
|    } | ||||
| 
 | ||||
|    uint16_t numberOfDataMomentGates_; | ||||
|    uint16_t dataMomentRange_; | ||||
|    uint16_t dataMomentRangeSampleInterval_; | ||||
|    uint16_t tover_; | ||||
|    int16_t  snrThreshold_; | ||||
|    uint8_t  controlFlags_; | ||||
|    uint8_t  dataWordSize_; | ||||
|    float    scale_; | ||||
|    float    offset_; | ||||
| 
 | ||||
|    static std::unique_ptr<MomentDataBlock> | ||||
|    Create(const std::string& dataBlockType, | ||||
|           const std::string& dataName, | ||||
|           std::istream&      is) | ||||
|    { | ||||
|       std::unique_ptr<MomentDataBlock> p = | ||||
|          std::make_unique<MomentDataBlock>(dataBlockType, dataName); | ||||
| 
 | ||||
|       is.seekg(4, std::ios_base::cur);                                   // 4-7
 | ||||
|       is.read(reinterpret_cast<char*>(&p->numberOfDataMomentGates_), 2); // 8-9
 | ||||
|       is.read(reinterpret_cast<char*>(&p->dataMomentRange_), 2); // 10-11
 | ||||
|       is.read(reinterpret_cast<char*>(&p->dataMomentRangeSampleInterval_), | ||||
|               2);                                             // 12-13
 | ||||
|       is.read(reinterpret_cast<char*>(&p->tover_), 2);        // 14-15
 | ||||
|       is.read(reinterpret_cast<char*>(&p->snrThreshold_), 2); // 16-17
 | ||||
|       is.read(reinterpret_cast<char*>(&p->controlFlags_), 1); // 18
 | ||||
|       is.read(reinterpret_cast<char*>(&p->dataWordSize_), 1); // 19
 | ||||
|       is.read(reinterpret_cast<char*>(&p->scale_), 4);        // 20-23
 | ||||
|       is.read(reinterpret_cast<char*>(&p->offset_), 4);       // 24-27
 | ||||
| 
 | ||||
|       p->numberOfDataMomentGates_ = ntohs(p->numberOfDataMomentGates_); | ||||
|       p->dataMomentRange_         = ntohs(p->dataMomentRange_); | ||||
|       p->dataMomentRangeSampleInterval_ = | ||||
|          ntohs(p->dataMomentRangeSampleInterval_); | ||||
|       p->tover_        = ntohs(p->tover_); | ||||
|       p->snrThreshold_ = ntohs(p->snrThreshold_); | ||||
|       p->scale_        = Message::SwapFloat(p->scale_); | ||||
|       p->offset_       = Message::SwapFloat(p->offset_); | ||||
| 
 | ||||
|       // TODO: Moment gates
 | ||||
| 
 | ||||
|       return p; | ||||
|    } | ||||
| }; | ||||
| 
 | ||||
| struct VolumeDataBlock : DataBlock | ||||
| { | ||||
|    explicit VolumeDataBlock(const std::string& dataBlockType, | ||||
|                             const std::string& dataName) : | ||||
|        DataBlock(dataBlockType, dataName), | ||||
|        lrtup_ {0}, | ||||
|        versionNumberMajor_ {0}, | ||||
|        versionNumberMinor_ {0}, | ||||
|        latitude_ {0.0f}, | ||||
|        longitude_ {0.0f}, | ||||
|        siteHeight_ {0}, | ||||
|        feedhornHeight_ {0}, | ||||
|        calibrationConstant_ {0.0f}, | ||||
|        horizontaShvTxPower_ {0.0f}, | ||||
|        verticalShvTxPower_ {0.0f}, | ||||
|        systemDifferentialReflectivity_ {0.0f}, | ||||
|        initialSystemDifferentialPhase_ {0.0f}, | ||||
|        volumeCoveragePatternNumber_ {0}, | ||||
|        processingStatus_ {0} | ||||
|    { | ||||
|    } | ||||
| 
 | ||||
|    uint16_t lrtup_; | ||||
|    uint8_t  versionNumberMajor_; | ||||
|    uint8_t  versionNumberMinor_; | ||||
|    float    latitude_; | ||||
|    float    longitude_; | ||||
|    int16_t  siteHeight_; | ||||
|    uint16_t feedhornHeight_; | ||||
|    float    calibrationConstant_; | ||||
|    float    horizontaShvTxPower_; | ||||
|    float    verticalShvTxPower_; | ||||
|    float    systemDifferentialReflectivity_; | ||||
|    float    initialSystemDifferentialPhase_; | ||||
|    uint16_t volumeCoveragePatternNumber_; | ||||
|    uint16_t processingStatus_; | ||||
| 
 | ||||
|    static std::unique_ptr<VolumeDataBlock> | ||||
|    Create(const std::string& dataBlockType, | ||||
|           const std::string& dataName, | ||||
|           std::istream&      is) | ||||
|    { | ||||
|       std::unique_ptr<VolumeDataBlock> p = | ||||
|          std::make_unique<VolumeDataBlock>(dataBlockType, dataName); | ||||
| 
 | ||||
|       is.read(reinterpret_cast<char*>(&p->lrtup_), 2);               // 4-5
 | ||||
|       is.read(reinterpret_cast<char*>(&p->versionNumberMajor_), 1);  // 6
 | ||||
|       is.read(reinterpret_cast<char*>(&p->versionNumberMinor_), 1);  // 7
 | ||||
|       is.read(reinterpret_cast<char*>(&p->latitude_), 4);            // 8-11
 | ||||
|       is.read(reinterpret_cast<char*>(&p->longitude_), 4);           // 12-15
 | ||||
|       is.read(reinterpret_cast<char*>(&p->siteHeight_), 2);          // 16-17
 | ||||
|       is.read(reinterpret_cast<char*>(&p->feedhornHeight_), 2);      // 18-19
 | ||||
|       is.read(reinterpret_cast<char*>(&p->calibrationConstant_), 4); // 20-23
 | ||||
|       is.read(reinterpret_cast<char*>(&p->horizontaShvTxPower_), 4); // 24-27
 | ||||
|       is.read(reinterpret_cast<char*>(&p->verticalShvTxPower_), 4);  // 28-31
 | ||||
|       is.read(reinterpret_cast<char*>(&p->systemDifferentialReflectivity_), | ||||
|               4); // 32-35
 | ||||
|       is.read(reinterpret_cast<char*>(&p->initialSystemDifferentialPhase_), | ||||
|               4); // 36-39
 | ||||
|       is.read(reinterpret_cast<char*>(&p->volumeCoveragePatternNumber_), | ||||
|               2);                                                 // 40-41
 | ||||
|       is.read(reinterpret_cast<char*>(&p->processingStatus_), 2); // 42-43
 | ||||
| 
 | ||||
|       p->lrtup_               = ntohs(p->lrtup_); | ||||
|       p->latitude_            = Message::SwapFloat(p->latitude_); | ||||
|       p->longitude_           = Message::SwapFloat(p->longitude_); | ||||
|       p->siteHeight_          = ntohs(p->siteHeight_); | ||||
|       p->feedhornHeight_      = ntohs(p->feedhornHeight_); | ||||
|       p->calibrationConstant_ = Message::SwapFloat(p->calibrationConstant_); | ||||
|       p->horizontaShvTxPower_ = Message::SwapFloat(p->horizontaShvTxPower_); | ||||
|       p->verticalShvTxPower_  = Message::SwapFloat(p->verticalShvTxPower_); | ||||
|       p->systemDifferentialReflectivity_ = | ||||
|          Message::SwapFloat(p->systemDifferentialReflectivity_); | ||||
|       p->initialSystemDifferentialPhase_ = | ||||
|          Message::SwapFloat(p->initialSystemDifferentialPhase_); | ||||
|       p->volumeCoveragePatternNumber_ = ntohs(p->volumeCoveragePatternNumber_); | ||||
|       p->processingStatus_            = ntohs(p->processingStatus_); | ||||
| 
 | ||||
|       return p; | ||||
|    } | ||||
| }; | ||||
| 
 | ||||
| struct ElevationDataBlock : DataBlock | ||||
| { | ||||
|    explicit ElevationDataBlock(const std::string& dataBlockType, | ||||
|                                const std::string& dataName) : | ||||
|        DataBlock(dataBlockType, dataName), | ||||
|        lrtup_ {0}, | ||||
|        atmos_ {0}, | ||||
|        calibrationConstant_ {0.0f} | ||||
|    { | ||||
|    } | ||||
| 
 | ||||
|    uint16_t lrtup_; | ||||
|    int16_t  atmos_; | ||||
|    float    calibrationConstant_; | ||||
| 
 | ||||
|    static std::unique_ptr<ElevationDataBlock> | ||||
|    Create(const std::string& dataBlockType, | ||||
|           const std::string& dataName, | ||||
|           std::istream&      is) | ||||
|    { | ||||
|       std::unique_ptr<ElevationDataBlock> p = | ||||
|          std::make_unique<ElevationDataBlock>(dataBlockType, dataName); | ||||
| 
 | ||||
|       is.read(reinterpret_cast<char*>(&p->lrtup_), 2);               // 4-5
 | ||||
|       is.read(reinterpret_cast<char*>(&p->atmos_), 2);               // 6-7
 | ||||
|       is.read(reinterpret_cast<char*>(&p->calibrationConstant_), 4); // 8-11
 | ||||
| 
 | ||||
|       p->lrtup_               = ntohs(p->lrtup_); | ||||
|       p->atmos_               = ntohs(p->atmos_); | ||||
|       p->calibrationConstant_ = Message::SwapFloat(p->calibrationConstant_); | ||||
| 
 | ||||
|       return p; | ||||
|    } | ||||
| }; | ||||
| 
 | ||||
| struct RadialDataBlock : DataBlock | ||||
| { | ||||
|    explicit RadialDataBlock(const std::string& dataBlockType, | ||||
|                             const std::string& dataName) : | ||||
|        DataBlock(dataBlockType, dataName), | ||||
|        lrtup_ {0}, | ||||
|        unambigiousRange_ {0}, | ||||
|        noiseLevelHorizontal_ {0.0f}, | ||||
|        noiseLevelVertical_ {0.0f}, | ||||
|        nyquistVelocity_ {0}, | ||||
|        radialFlags_ {0}, | ||||
|        calibrationConstantHorizontal_ {0.0f}, | ||||
|        calibrationConstantVertical_ {0.0f} | ||||
|    { | ||||
|    } | ||||
| 
 | ||||
|    uint16_t lrtup_; | ||||
|    uint16_t unambigiousRange_; | ||||
|    float    noiseLevelHorizontal_; | ||||
|    float    noiseLevelVertical_; | ||||
|    uint16_t nyquistVelocity_; | ||||
|    uint16_t radialFlags_; | ||||
|    float    calibrationConstantHorizontal_; | ||||
|    float    calibrationConstantVertical_; | ||||
| 
 | ||||
|    static std::unique_ptr<RadialDataBlock> | ||||
|    Create(const std::string& dataBlockType, | ||||
|           const std::string& dataName, | ||||
|           std::istream&      is) | ||||
|    { | ||||
|       std::unique_ptr<RadialDataBlock> p = | ||||
|          std::make_unique<RadialDataBlock>(dataBlockType, dataName); | ||||
| 
 | ||||
|       is.read(reinterpret_cast<char*>(&p->lrtup_), 2);                // 4-5
 | ||||
|       is.read(reinterpret_cast<char*>(&p->unambigiousRange_), 2);     // 6-7
 | ||||
|       is.read(reinterpret_cast<char*>(&p->noiseLevelHorizontal_), 4); // 8-11
 | ||||
|       is.read(reinterpret_cast<char*>(&p->noiseLevelVertical_), 4);   // 12-15
 | ||||
|       is.read(reinterpret_cast<char*>(&p->nyquistVelocity_), 2);      // 16-17
 | ||||
|       is.read(reinterpret_cast<char*>(&p->radialFlags_), 2);          // 18-19
 | ||||
|       is.read(reinterpret_cast<char*>(&p->calibrationConstantHorizontal_), | ||||
|               4); // 20-23
 | ||||
|       is.read(reinterpret_cast<char*>(&p->calibrationConstantVertical_), | ||||
|               4); // 24-27
 | ||||
| 
 | ||||
|       p->lrtup_                = ntohs(p->lrtup_); | ||||
|       p->unambigiousRange_     = ntohs(p->unambigiousRange_); | ||||
|       p->noiseLevelHorizontal_ = Message::SwapFloat(p->noiseLevelHorizontal_); | ||||
|       p->noiseLevelVertical_   = Message::SwapFloat(p->noiseLevelVertical_); | ||||
|       p->nyquistVelocity_      = ntohs(p->nyquistVelocity_); | ||||
|       p->radialFlags_          = ntohs(p->radialFlags_); | ||||
|       p->calibrationConstantHorizontal_ = | ||||
|          Message::SwapFloat(p->calibrationConstantHorizontal_); | ||||
|       p->calibrationConstantVertical_ = | ||||
|          Message::SwapFloat(p->calibrationConstantVertical_); | ||||
| 
 | ||||
|       return p; | ||||
|    } | ||||
| }; | ||||
| 
 | ||||
| class DigitalRadarDataImpl | ||||
| { | ||||
| public: | ||||
|    explicit DigitalRadarDataImpl() : | ||||
|        radarIdentifier_ {}, | ||||
|        collectionTime_ {0}, | ||||
|        modifiedJulianDate_ {0}, | ||||
|        azimuthNumber_ {0}, | ||||
|        azimuthAngle_ {0.0f}, | ||||
|        compressionIndicator_ {0}, | ||||
|        radialLength_ {0}, | ||||
|        azimuthResolutionSpacing_ {0}, | ||||
|        radialStatus_ {0}, | ||||
|        elevationNumber_ {0}, | ||||
|        cutSectorNumber_ {0}, | ||||
|        elevationAngle_ {0.0f}, | ||||
|        radialSpotBlankingStatus_ {0}, | ||||
|        azimuthIndexingMode_ {0}, | ||||
|        dataBlockCount_ {0}, | ||||
|        dataBlockPointer_ {0}, | ||||
|        volumeDataBlock_ {nullptr}, | ||||
|        elevationDataBlock_ {nullptr}, | ||||
|        radialDataBlock_ {nullptr}, | ||||
|        momentRefDataBlock_ {nullptr}, | ||||
|        momentVelDataBlock_ {nullptr}, | ||||
|        momentSwDataBlock_ {nullptr}, | ||||
|        momentZdrDataBlock_ {nullptr}, | ||||
|        momentPhiDataBlock_ {nullptr}, | ||||
|        momentRhoDataBlock_ {nullptr}, | ||||
|        momentCfpDataBlock_ {nullptr} {}; | ||||
|    ~DigitalRadarDataImpl() = default; | ||||
| 
 | ||||
|    std::string              radarIdentifier_; | ||||
|    uint32_t                 collectionTime_; | ||||
|    uint16_t                 modifiedJulianDate_; | ||||
|    uint16_t                 azimuthNumber_; | ||||
|    float                    azimuthAngle_; | ||||
|    uint8_t                  compressionIndicator_; | ||||
|    uint16_t                 radialLength_; | ||||
|    uint8_t                  azimuthResolutionSpacing_; | ||||
|    uint8_t                  radialStatus_; | ||||
|    uint8_t                  elevationNumber_; | ||||
|    uint8_t                  cutSectorNumber_; | ||||
|    float                    elevationAngle_; | ||||
|    uint8_t                  radialSpotBlankingStatus_; | ||||
|    uint8_t                  azimuthIndexingMode_; | ||||
|    uint16_t                 dataBlockCount_; | ||||
|    std::array<uint32_t, 10> dataBlockPointer_; | ||||
| 
 | ||||
|    std::unique_ptr<VolumeDataBlock>    volumeDataBlock_; | ||||
|    std::unique_ptr<ElevationDataBlock> elevationDataBlock_; | ||||
|    std::unique_ptr<RadialDataBlock>    radialDataBlock_; | ||||
|    std::unique_ptr<MomentDataBlock>    momentRefDataBlock_; | ||||
|    std::unique_ptr<MomentDataBlock>    momentVelDataBlock_; | ||||
|    std::unique_ptr<MomentDataBlock>    momentSwDataBlock_; | ||||
|    std::unique_ptr<MomentDataBlock>    momentZdrDataBlock_; | ||||
|    std::unique_ptr<MomentDataBlock>    momentPhiDataBlock_; | ||||
|    std::unique_ptr<MomentDataBlock>    momentRhoDataBlock_; | ||||
|    std::unique_ptr<MomentDataBlock>    momentCfpDataBlock_; | ||||
| }; | ||||
| 
 | ||||
| DigitalRadarData::DigitalRadarData() : | ||||
|     Message(), p(std::make_unique<DigitalRadarDataImpl>()) | ||||
| { | ||||
| } | ||||
| DigitalRadarData::~DigitalRadarData() = default; | ||||
| 
 | ||||
| DigitalRadarData::DigitalRadarData(DigitalRadarData&&) noexcept = default; | ||||
| DigitalRadarData& | ||||
| DigitalRadarData::operator=(DigitalRadarData&&) noexcept = default; | ||||
| 
 | ||||
| bool DigitalRadarData::Parse(std::istream& is) | ||||
| { | ||||
|    BOOST_LOG_TRIVIAL(debug) | ||||
|       << logPrefix_ << "Parsing Digital Radar Data (Message Type 31)"; | ||||
| 
 | ||||
|    bool   messageValid = true; | ||||
|    size_t bytesRead    = 0; | ||||
| 
 | ||||
|    std::streampos isBegin = is.tellg(); | ||||
| 
 | ||||
|    p->radarIdentifier_.resize(4); | ||||
| 
 | ||||
|    is.read(&p->radarIdentifier_[0], 4);                                // 0-3
 | ||||
|    is.read(reinterpret_cast<char*>(&p->collectionTime_), 4);           // 4-7
 | ||||
|    is.read(reinterpret_cast<char*>(&p->modifiedJulianDate_), 2);       // 8-9
 | ||||
|    is.read(reinterpret_cast<char*>(&p->azimuthNumber_), 2);            // 10-11
 | ||||
|    is.read(reinterpret_cast<char*>(&p->azimuthAngle_), 4);             // 12-15
 | ||||
|    is.read(reinterpret_cast<char*>(&p->compressionIndicator_), 1);     // 16
 | ||||
|    is.seekg(1, std::ios_base::cur);                                    // 17
 | ||||
|    is.read(reinterpret_cast<char*>(&p->radialLength_), 2);             // 18-19
 | ||||
|    is.read(reinterpret_cast<char*>(&p->azimuthResolutionSpacing_), 1); // 20
 | ||||
|    is.read(reinterpret_cast<char*>(&p->radialStatus_), 1);             // 21
 | ||||
|    is.read(reinterpret_cast<char*>(&p->elevationNumber_), 1);          // 22
 | ||||
|    is.read(reinterpret_cast<char*>(&p->cutSectorNumber_), 1);          // 23
 | ||||
|    is.read(reinterpret_cast<char*>(&p->elevationAngle_), 4);           // 24-27
 | ||||
|    is.read(reinterpret_cast<char*>(&p->radialSpotBlankingStatus_), 1); // 28
 | ||||
|    is.read(reinterpret_cast<char*>(&p->azimuthIndexingMode_), 1);      // 29
 | ||||
|    is.read(reinterpret_cast<char*>(&p->dataBlockCount_), 2);           // 30-31
 | ||||
| 
 | ||||
|    p->collectionTime_     = ntohl(p->collectionTime_); | ||||
|    p->modifiedJulianDate_ = ntohs(p->modifiedJulianDate_); | ||||
|    p->azimuthNumber_      = ntohs(p->azimuthNumber_); | ||||
|    p->azimuthAngle_       = SwapFloat(p->azimuthAngle_); | ||||
|    p->radialLength_       = ntohs(p->radialLength_); | ||||
|    p->elevationAngle_     = SwapFloat(p->elevationAngle_); | ||||
|    p->dataBlockCount_     = ntohs(p->dataBlockCount_); | ||||
| 
 | ||||
|    if (p->dataBlockCount_ < 4 || p->dataBlockCount_ > 10) | ||||
|    { | ||||
|       BOOST_LOG_TRIVIAL(warning) | ||||
|          << logPrefix_ | ||||
|          << "Invalid number of data blocks: " << p->dataBlockCount_; | ||||
|       p->dataBlockCount_ = 0; | ||||
|       messageValid       = false; | ||||
|    } | ||||
|    if (p->compressionIndicator_ != 0) | ||||
|    { | ||||
|       BOOST_LOG_TRIVIAL(warning) << logPrefix_ << "Compression not supported"; | ||||
|       p->dataBlockCount_ = 0; | ||||
|       messageValid       = false; | ||||
|    } | ||||
| 
 | ||||
|    is.read(reinterpret_cast<char*>(&p->dataBlockPointer_), | ||||
|            p->dataBlockCount_ * 4); | ||||
| 
 | ||||
|    SwapArray(p->dataBlockPointer_, p->dataBlockCount_); | ||||
| 
 | ||||
|    for (uint16_t b = 0; b < p->dataBlockCount_; ++b) | ||||
|    { | ||||
|       is.seekg(isBegin + std::streamoff(p->dataBlockPointer_[b]), | ||||
|                std::ios_base::beg); | ||||
| 
 | ||||
|       std::string dataBlockType(1, 0); | ||||
|       std::string dataName(3, 0); | ||||
| 
 | ||||
|       is.read(&dataBlockType[0], 1); | ||||
|       is.read(&dataName[0], 3); | ||||
| 
 | ||||
|       DataBlockType dataBlock = DataBlockType::Unknown; | ||||
|       try | ||||
|       { | ||||
|          dataBlock = strToDataBlock_.at(dataName); | ||||
|       } | ||||
|       catch (const std::exception&) | ||||
|       { | ||||
|       } | ||||
| 
 | ||||
|       switch (dataBlock) | ||||
|       { | ||||
|       case DataBlockType::Volume: | ||||
|          p->volumeDataBlock_ = | ||||
|             std::move(VolumeDataBlock::Create(dataBlockType, dataName, is)); | ||||
|          break; | ||||
|       case DataBlockType::Elevation: | ||||
|          p->elevationDataBlock_ = | ||||
|             std::move(ElevationDataBlock::Create(dataBlockType, dataName, is)); | ||||
|          break; | ||||
|       case DataBlockType::Radial: | ||||
|          p->radialDataBlock_ = | ||||
|             std::move(RadialDataBlock::Create(dataBlockType, dataName, is)); | ||||
|          break; | ||||
|       case DataBlockType::MomentRef: | ||||
|          p->momentRefDataBlock_ = | ||||
|             std::move(MomentDataBlock::Create(dataBlockType, dataName, is)); | ||||
|          break; | ||||
|       case DataBlockType::MomentVel: | ||||
|          p->momentVelDataBlock_ = | ||||
|             std::move(MomentDataBlock::Create(dataBlockType, dataName, is)); | ||||
|          break; | ||||
|       case DataBlockType::MomentSw: | ||||
|          p->momentSwDataBlock_ = | ||||
|             std::move(MomentDataBlock::Create(dataBlockType, dataName, is)); | ||||
|          break; | ||||
|       case DataBlockType::MomentZdr: | ||||
|          p->momentZdrDataBlock_ = | ||||
|             std::move(MomentDataBlock::Create(dataBlockType, dataName, is)); | ||||
|          break; | ||||
|       case DataBlockType::MomentPhi: | ||||
|          p->momentPhiDataBlock_ = | ||||
|             std::move(MomentDataBlock::Create(dataBlockType, dataName, is)); | ||||
|          break; | ||||
|       case DataBlockType::MomentRho: | ||||
|          p->momentRhoDataBlock_ = | ||||
|             std::move(MomentDataBlock::Create(dataBlockType, dataName, is)); | ||||
|          break; | ||||
|       case DataBlockType::MomentCfp: | ||||
|          p->momentCfpDataBlock_ = | ||||
|             std::move(MomentDataBlock::Create(dataBlockType, dataName, is)); | ||||
|          break; | ||||
|       default: | ||||
|          BOOST_LOG_TRIVIAL(warning) | ||||
|             << logPrefix_ << "Unknown data name: " << dataName; | ||||
|          break; | ||||
|       } | ||||
|    } | ||||
| 
 | ||||
|    is.seekg(isBegin, std::ios_base::beg); | ||||
|    if (!ValidateMessage(is, bytesRead)) | ||||
|    { | ||||
|       messageValid = false; | ||||
|    } | ||||
| 
 | ||||
|    return messageValid; | ||||
| } | ||||
| 
 | ||||
| std::unique_ptr<DigitalRadarData> | ||||
| DigitalRadarData::Create(MessageHeader&& header, std::istream& is) | ||||
| { | ||||
|    std::unique_ptr<DigitalRadarData> message = | ||||
|       std::make_unique<DigitalRadarData>(); | ||||
|    message->set_header(std::move(header)); | ||||
|    message->Parse(is); | ||||
|    return message; | ||||
| } | ||||
| 
 | ||||
| } // namespace rda
 | ||||
| } // namespace wsr88d
 | ||||
| } // namespace scwx
 | ||||
|  | @ -2,6 +2,7 @@ | |||
| 
 | ||||
| #include <scwx/util/vectorbuf.hpp> | ||||
| #include <scwx/wsr88d/rda/clutter_filter_map.hpp> | ||||
| #include <scwx/wsr88d/rda/digital_radar_data.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> | ||||
|  | @ -29,7 +30,8 @@ static const std::unordered_map<uint8_t, CreateMessageFunction> create_ { | |||
|    {3, PerformanceMaintenanceData::Create}, | ||||
|    {5, VolumeCoveragePatternData::Create}, | ||||
|    {15, ClutterFilterMap::Create}, | ||||
|    {18, RdaAdaptationData::Create}}; | ||||
|    {18, RdaAdaptationData::Create}, | ||||
|    {31, DigitalRadarData::Create}}; | ||||
| 
 | ||||
| static std::vector<char> messageData_; | ||||
| static size_t            bufferedSize_; | ||||
|  |  | |||
|  | @ -2294,8 +2294,8 @@ bool PerformanceMaintenanceData::Parse(std::istream& is) | |||
|    p->transmitterRecyclingSummary_ = htons(p->transmitterRecyclingSummary_); | ||||
|    p->transmitterInoperable_       = htons(p->transmitterInoperable_); | ||||
|    p->transmitterAirFilter_        = htons(p->transmitterAirFilter_); | ||||
|    SwapUInt16Array(p->zeroTestBit_); | ||||
|    SwapUInt16Array(p->oneTestBit_); | ||||
|    SwapArray(p->zeroTestBit_); | ||||
|    SwapArray(p->oneTestBit_); | ||||
|    p->xmtrSpipInterface_        = htons(p->xmtrSpipInterface_); | ||||
|    p->transmitterSummaryStatus_ = htons(p->transmitterSummaryStatus_); | ||||
|    p->transmitterRfPower_       = SwapFloat(p->transmitterRfPower_); | ||||
|  |  | |||
|  | @ -1582,7 +1582,7 @@ bool RdaAdaptationData::Parse(std::istream& is) | |||
|    p->parkaz_        = SwapFloat(p->parkaz_); | ||||
|    p->parkel_        = SwapFloat(p->parkel_); | ||||
| 
 | ||||
|    SwapFloatArray(p->aFuelConv_); | ||||
|    SwapArray(p->aFuelConv_); | ||||
| 
 | ||||
|    p->aMinShelterTemp_       = SwapFloat(p->aMinShelterTemp_); | ||||
|    p->aMaxShelterTemp_       = SwapFloat(p->aMaxShelterTemp_); | ||||
|  | @ -1605,14 +1605,14 @@ bool RdaAdaptationData::Parse(std::istream& is) | |||
|    p->configChanNumber_      = ntohl(p->configChanNumber_); | ||||
|    p->redundantChanConfig_   = ntohl(p->redundantChanConfig_); | ||||
| 
 | ||||
|    SwapFloatArray(p->attenTable_); | ||||
|    SwapFloatMap(p->pathLosses_); | ||||
|    SwapArray(p->attenTable_); | ||||
|    SwapMap(p->pathLosses_); | ||||
| 
 | ||||
|    p->vTsCw_ = SwapFloat(p->vTsCw_); | ||||
| 
 | ||||
|    SwapFloatArray(p->hRnscale_); | ||||
|    SwapFloatArray(p->atmos_); | ||||
|    SwapFloatArray(p->elIndex_); | ||||
|    SwapArray(p->hRnscale_); | ||||
|    SwapArray(p->atmos_); | ||||
|    SwapArray(p->elIndex_); | ||||
| 
 | ||||
|    p->tfreqMhz_                  = ntohl(p->tfreqMhz_); | ||||
|    p->baseDataTcn_               = SwapFloat(p->baseDataTcn_); | ||||
|  | @ -1687,7 +1687,7 @@ bool RdaAdaptationData::Parse(std::istream& is) | |||
|    p->elInertia_                 = SwapFloat(p->elInertia_); | ||||
|    p->rvp8nvIwaveguideLength_    = ntohl(p->rvp8nvIwaveguideLength_); | ||||
| 
 | ||||
|    SwapFloatArray(p->vRnscale_); | ||||
|    SwapArray(p->vRnscale_); | ||||
| 
 | ||||
|    p->velDataTover_         = SwapFloat(p->velDataTover_); | ||||
|    p->widthDataTover_       = SwapFloat(p->widthDataTover_); | ||||
|  |  | |||
|  | @ -310,7 +310,7 @@ bool RdaStatusData::Parse(std::istream& is) | |||
|    p->transitionPowerSourceStatus_ = htons(p->transitionPowerSourceStatus_); | ||||
|    p->rmsControlStatus_            = htons(p->rmsControlStatus_); | ||||
|    p->performanceCheckStatus_      = htons(p->performanceCheckStatus_); | ||||
|    SwapUInt16Array(p->alarmCodes_); | ||||
|    SwapArray(p->alarmCodes_); | ||||
|    p->signalProcessingOptions_ = htons(p->signalProcessingOptions_); | ||||
|    p->statusVersion_           = htons(p->statusVersion_); | ||||
| 
 | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ set(SRC_UTIL source/scwx/util/rangebuf.cpp | |||
| set(HDR_WSR88D include/scwx/wsr88d/ar2v_file.hpp) | ||||
| set(SRC_WSR88D source/scwx/wsr88d/ar2v_file.cpp) | ||||
| set(HDR_WSR88D_RDA include/scwx/wsr88d/rda/clutter_filter_map.hpp | ||||
|                    include/scwx/wsr88d/rda/digital_radar_data.hpp | ||||
|                    include/scwx/wsr88d/rda/message.hpp | ||||
|                    include/scwx/wsr88d/rda/message_factory.hpp | ||||
|                    include/scwx/wsr88d/rda/message_header.hpp | ||||
|  | @ -17,6 +18,7 @@ set(HDR_WSR88D_RDA include/scwx/wsr88d/rda/clutter_filter_map.hpp | |||
|                    include/scwx/wsr88d/rda/rda_status_data.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 | ||||
|                    source/scwx/wsr88d/rda/message.cpp | ||||
|                    source/scwx/wsr88d/rda/message_factory.cpp | ||||
|                    source/scwx/wsr88d/rda/message_header.cpp | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dan Paulat
						Dan Paulat