mirror of
https://github.com/ciphervance/supercell-wx.git
synced 2025-10-30 09:10: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;
|
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