mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 03:10:05 +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; |    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) |    static void ReadBoolean(std::istream& is, bool& value) | ||||||
|    { |    { | ||||||
|       std::string data(4, ' '); |       std::string data(4, ' '); | ||||||
|  | @ -56,45 +68,43 @@ protected: | ||||||
|    } |    } | ||||||
| 
 | 
 | ||||||
|    template<size_t _Size> |    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, |       std::transform(std::execution::par_unseq, | ||||||
|                      arr.begin(), |                      arr.begin(), | ||||||
|                      arr.end(), |                      arr.begin() + size, | ||||||
|                      arr.begin(), |                      arr.begin(), | ||||||
|                      [](float f) { return SwapFloat(f); }); |                      [](float f) { return SwapFloat(f); }); | ||||||
|    } |    } | ||||||
| 
 | 
 | ||||||
|    template<size_t _Size> |    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, |       std::transform(std::execution::par_unseq, | ||||||
|                      arr.begin(), |                      arr.begin(), | ||||||
|                      arr.end(), |                      arr.begin() + size, | ||||||
|                      arr.begin(), |                      arr.begin(), | ||||||
|                      [](uint16_t u) { return ntohs(u); }); |                      [](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> |    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) { |       std::for_each(std::execution::par_unseq, m.begin(), m.end(), [](auto& p) { | ||||||
|          p.second = SwapFloat(p.second); |          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: | private: | ||||||
|    std::unique_ptr<MessageImpl> p; |    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/util/vectorbuf.hpp> | ||||||
| #include <scwx/wsr88d/rda/clutter_filter_map.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/performance_maintenance_data.hpp> | ||||||
| #include <scwx/wsr88d/rda/rda_adaptation_data.hpp> | #include <scwx/wsr88d/rda/rda_adaptation_data.hpp> | ||||||
| #include <scwx/wsr88d/rda/rda_status_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}, |    {3, PerformanceMaintenanceData::Create}, | ||||||
|    {5, VolumeCoveragePatternData::Create}, |    {5, VolumeCoveragePatternData::Create}, | ||||||
|    {15, ClutterFilterMap::Create}, |    {15, ClutterFilterMap::Create}, | ||||||
|    {18, RdaAdaptationData::Create}}; |    {18, RdaAdaptationData::Create}, | ||||||
|  |    {31, DigitalRadarData::Create}}; | ||||||
| 
 | 
 | ||||||
| static std::vector<char> messageData_; | static std::vector<char> messageData_; | ||||||
| static size_t            bufferedSize_; | static size_t            bufferedSize_; | ||||||
|  |  | ||||||
|  | @ -2294,8 +2294,8 @@ bool PerformanceMaintenanceData::Parse(std::istream& is) | ||||||
|    p->transmitterRecyclingSummary_ = htons(p->transmitterRecyclingSummary_); |    p->transmitterRecyclingSummary_ = htons(p->transmitterRecyclingSummary_); | ||||||
|    p->transmitterInoperable_       = htons(p->transmitterInoperable_); |    p->transmitterInoperable_       = htons(p->transmitterInoperable_); | ||||||
|    p->transmitterAirFilter_        = htons(p->transmitterAirFilter_); |    p->transmitterAirFilter_        = htons(p->transmitterAirFilter_); | ||||||
|    SwapUInt16Array(p->zeroTestBit_); |    SwapArray(p->zeroTestBit_); | ||||||
|    SwapUInt16Array(p->oneTestBit_); |    SwapArray(p->oneTestBit_); | ||||||
|    p->xmtrSpipInterface_        = htons(p->xmtrSpipInterface_); |    p->xmtrSpipInterface_        = htons(p->xmtrSpipInterface_); | ||||||
|    p->transmitterSummaryStatus_ = htons(p->transmitterSummaryStatus_); |    p->transmitterSummaryStatus_ = htons(p->transmitterSummaryStatus_); | ||||||
|    p->transmitterRfPower_       = SwapFloat(p->transmitterRfPower_); |    p->transmitterRfPower_       = SwapFloat(p->transmitterRfPower_); | ||||||
|  |  | ||||||
|  | @ -1582,7 +1582,7 @@ bool RdaAdaptationData::Parse(std::istream& is) | ||||||
|    p->parkaz_        = SwapFloat(p->parkaz_); |    p->parkaz_        = SwapFloat(p->parkaz_); | ||||||
|    p->parkel_        = SwapFloat(p->parkel_); |    p->parkel_        = SwapFloat(p->parkel_); | ||||||
| 
 | 
 | ||||||
|    SwapFloatArray(p->aFuelConv_); |    SwapArray(p->aFuelConv_); | ||||||
| 
 | 
 | ||||||
|    p->aMinShelterTemp_       = SwapFloat(p->aMinShelterTemp_); |    p->aMinShelterTemp_       = SwapFloat(p->aMinShelterTemp_); | ||||||
|    p->aMaxShelterTemp_       = SwapFloat(p->aMaxShelterTemp_); |    p->aMaxShelterTemp_       = SwapFloat(p->aMaxShelterTemp_); | ||||||
|  | @ -1605,14 +1605,14 @@ bool RdaAdaptationData::Parse(std::istream& is) | ||||||
|    p->configChanNumber_      = ntohl(p->configChanNumber_); |    p->configChanNumber_      = ntohl(p->configChanNumber_); | ||||||
|    p->redundantChanConfig_   = ntohl(p->redundantChanConfig_); |    p->redundantChanConfig_   = ntohl(p->redundantChanConfig_); | ||||||
| 
 | 
 | ||||||
|    SwapFloatArray(p->attenTable_); |    SwapArray(p->attenTable_); | ||||||
|    SwapFloatMap(p->pathLosses_); |    SwapMap(p->pathLosses_); | ||||||
| 
 | 
 | ||||||
|    p->vTsCw_ = SwapFloat(p->vTsCw_); |    p->vTsCw_ = SwapFloat(p->vTsCw_); | ||||||
| 
 | 
 | ||||||
|    SwapFloatArray(p->hRnscale_); |    SwapArray(p->hRnscale_); | ||||||
|    SwapFloatArray(p->atmos_); |    SwapArray(p->atmos_); | ||||||
|    SwapFloatArray(p->elIndex_); |    SwapArray(p->elIndex_); | ||||||
| 
 | 
 | ||||||
|    p->tfreqMhz_                  = ntohl(p->tfreqMhz_); |    p->tfreqMhz_                  = ntohl(p->tfreqMhz_); | ||||||
|    p->baseDataTcn_               = SwapFloat(p->baseDataTcn_); |    p->baseDataTcn_               = SwapFloat(p->baseDataTcn_); | ||||||
|  | @ -1687,7 +1687,7 @@ bool RdaAdaptationData::Parse(std::istream& is) | ||||||
|    p->elInertia_                 = SwapFloat(p->elInertia_); |    p->elInertia_                 = SwapFloat(p->elInertia_); | ||||||
|    p->rvp8nvIwaveguideLength_    = ntohl(p->rvp8nvIwaveguideLength_); |    p->rvp8nvIwaveguideLength_    = ntohl(p->rvp8nvIwaveguideLength_); | ||||||
| 
 | 
 | ||||||
|    SwapFloatArray(p->vRnscale_); |    SwapArray(p->vRnscale_); | ||||||
| 
 | 
 | ||||||
|    p->velDataTover_         = SwapFloat(p->velDataTover_); |    p->velDataTover_         = SwapFloat(p->velDataTover_); | ||||||
|    p->widthDataTover_       = SwapFloat(p->widthDataTover_); |    p->widthDataTover_       = SwapFloat(p->widthDataTover_); | ||||||
|  |  | ||||||
|  | @ -310,7 +310,7 @@ bool RdaStatusData::Parse(std::istream& is) | ||||||
|    p->transitionPowerSourceStatus_ = htons(p->transitionPowerSourceStatus_); |    p->transitionPowerSourceStatus_ = htons(p->transitionPowerSourceStatus_); | ||||||
|    p->rmsControlStatus_            = htons(p->rmsControlStatus_); |    p->rmsControlStatus_            = htons(p->rmsControlStatus_); | ||||||
|    p->performanceCheckStatus_      = htons(p->performanceCheckStatus_); |    p->performanceCheckStatus_      = htons(p->performanceCheckStatus_); | ||||||
|    SwapUInt16Array(p->alarmCodes_); |    SwapArray(p->alarmCodes_); | ||||||
|    p->signalProcessingOptions_ = htons(p->signalProcessingOptions_); |    p->signalProcessingOptions_ = htons(p->signalProcessingOptions_); | ||||||
|    p->statusVersion_           = htons(p->statusVersion_); |    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(HDR_WSR88D include/scwx/wsr88d/ar2v_file.hpp) | ||||||
| set(SRC_WSR88D source/scwx/wsr88d/ar2v_file.cpp) | set(SRC_WSR88D source/scwx/wsr88d/ar2v_file.cpp) | ||||||
| set(HDR_WSR88D_RDA include/scwx/wsr88d/rda/clutter_filter_map.hpp | 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.hpp | ||||||
|                    include/scwx/wsr88d/rda/message_factory.hpp |                    include/scwx/wsr88d/rda/message_factory.hpp | ||||||
|                    include/scwx/wsr88d/rda/message_header.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/rda_status_data.hpp | ||||||
|                    include/scwx/wsr88d/rda/volume_coverage_pattern_data.hpp) |                    include/scwx/wsr88d/rda/volume_coverage_pattern_data.hpp) | ||||||
| set(SRC_WSR88D_RDA source/scwx/wsr88d/rda/clutter_filter_map.cpp | 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.cpp | ||||||
|                    source/scwx/wsr88d/rda/message_factory.cpp |                    source/scwx/wsr88d/rda/message_factory.cpp | ||||||
|                    source/scwx/wsr88d/rda/message_header.cpp |                    source/scwx/wsr88d/rda/message_header.cpp | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dan Paulat
						Dan Paulat