mirror of
https://github.com/ciphervance/supercell-wx.git
synced 2025-10-30 05:50:06 +00:00
Parse Clutter Filter Map (Message 15)
This commit is contained in:
parent
f36d57b71d
commit
3ab4ec4b9b
15 changed files with 682 additions and 22 deletions
37
test/source/scwx/util/vectorbuf.test.cpp
Normal file
37
test/source/scwx/util/vectorbuf.test.cpp
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
#include <scwx/util/vectorbuf.hpp>
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
namespace scwx
|
||||||
|
{
|
||||||
|
namespace util
|
||||||
|
{
|
||||||
|
|
||||||
|
TEST(vectorbuf, smiles)
|
||||||
|
{
|
||||||
|
std::vector<char> v;
|
||||||
|
vectorbuf vb(v);
|
||||||
|
std::istream is(&vb);
|
||||||
|
|
||||||
|
v.reserve(7);
|
||||||
|
memcpy(v.data(), "smiles", 7);
|
||||||
|
vb.update_read_pointers(7);
|
||||||
|
|
||||||
|
EXPECT_EQ(is.eof(), false);
|
||||||
|
EXPECT_EQ(is.fail(), false);
|
||||||
|
|
||||||
|
char data[7];
|
||||||
|
is.read(data, 7);
|
||||||
|
|
||||||
|
EXPECT_EQ(std::string(data), std::string("smiles"));
|
||||||
|
EXPECT_EQ(is.eof(), false);
|
||||||
|
EXPECT_EQ(is.fail(), false);
|
||||||
|
|
||||||
|
is.read(data, 1);
|
||||||
|
|
||||||
|
EXPECT_EQ(is.eof(), true);
|
||||||
|
EXPECT_EQ(is.fail(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace util
|
||||||
|
} // namespace scwx
|
||||||
|
|
@ -8,7 +8,8 @@ find_package(BZip2)
|
||||||
find_package(GTest)
|
find_package(GTest)
|
||||||
|
|
||||||
set(SRC_MAIN source/scwx/wxtest.cpp)
|
set(SRC_MAIN source/scwx/wxtest.cpp)
|
||||||
set(SRC_UTIL_TESTS source/scwx/util/rangebuf.test.cpp)
|
set(SRC_UTIL_TESTS source/scwx/util/rangebuf.test.cpp
|
||||||
|
source/scwx/util/vectorbuf.test.cpp)
|
||||||
set(SRC_WSR88D_TESTS source/scwx/wsr88d/ar2v_file.test.cpp)
|
set(SRC_WSR88D_TESTS source/scwx/wsr88d/ar2v_file.test.cpp)
|
||||||
|
|
||||||
add_executable(wxtest ${SRC_MAIN}
|
add_executable(wxtest ${SRC_MAIN}
|
||||||
|
|
|
||||||
27
wxdata/include/scwx/util/vectorbuf.hpp
Normal file
27
wxdata/include/scwx/util/vectorbuf.hpp
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <streambuf>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace scwx
|
||||||
|
{
|
||||||
|
namespace util
|
||||||
|
{
|
||||||
|
|
||||||
|
class vectorbuf : public std::streambuf
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
vectorbuf(std::vector<char>& v);
|
||||||
|
~vectorbuf() = default;
|
||||||
|
|
||||||
|
vectorbuf(const vectorbuf&) = delete;
|
||||||
|
vectorbuf& operator=(const vectorbuf&) = delete;
|
||||||
|
|
||||||
|
void update_read_pointers(size_t size);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<char>& v_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace util
|
||||||
|
} // namespace scwx
|
||||||
|
|
@ -25,7 +25,7 @@ public:
|
||||||
Ar2vFile& operator=(const Ar2vFile&) = delete;
|
Ar2vFile& operator=(const Ar2vFile&) = delete;
|
||||||
|
|
||||||
Ar2vFile(Ar2vFile&&) noexcept;
|
Ar2vFile(Ar2vFile&&) noexcept;
|
||||||
Ar2vFile& operator=(Ar2vFile&&);
|
Ar2vFile& operator=(Ar2vFile&&) noexcept;
|
||||||
|
|
||||||
bool LoadFile(const std::string& filename);
|
bool LoadFile(const std::string& filename);
|
||||||
|
|
||||||
|
|
|
||||||
46
wxdata/include/scwx/wsr88d/rda/clutter_filter_map.hpp
Normal file
46
wxdata/include/scwx/wsr88d/rda/clutter_filter_map.hpp
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <scwx/wsr88d/rda/message.hpp>
|
||||||
|
|
||||||
|
namespace scwx
|
||||||
|
{
|
||||||
|
namespace wsr88d
|
||||||
|
{
|
||||||
|
namespace rda
|
||||||
|
{
|
||||||
|
|
||||||
|
class ClutterFilterMapImpl;
|
||||||
|
|
||||||
|
class ClutterFilterMap : public Message
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit ClutterFilterMap();
|
||||||
|
~ClutterFilterMap();
|
||||||
|
|
||||||
|
ClutterFilterMap(const Message&) = delete;
|
||||||
|
ClutterFilterMap& operator=(const ClutterFilterMap&) = delete;
|
||||||
|
|
||||||
|
ClutterFilterMap(ClutterFilterMap&&) noexcept;
|
||||||
|
ClutterFilterMap& operator=(ClutterFilterMap&&) noexcept;
|
||||||
|
|
||||||
|
uint16_t map_generation_date() const;
|
||||||
|
uint16_t map_generation_time() const;
|
||||||
|
uint16_t number_of_elevation_segments() const;
|
||||||
|
uint16_t number_of_range_zones(uint16_t e, uint16_t a) const;
|
||||||
|
uint16_t op_code(uint16_t e, uint16_t a, uint16_t z) const;
|
||||||
|
uint16_t end_range(uint16_t e, uint16_t a, uint16_t z) const;
|
||||||
|
|
||||||
|
bool Parse(std::istream& is);
|
||||||
|
|
||||||
|
static std::unique_ptr<ClutterFilterMap> Create(MessageHeader&& header,
|
||||||
|
std::istream& is);
|
||||||
|
|
||||||
|
static const size_t NUM_AZIMUTH_SEGMENTS = 360u;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<ClutterFilterMapImpl> p;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace rda
|
||||||
|
} // namespace wsr88d
|
||||||
|
} // namespace scwx
|
||||||
42
wxdata/include/scwx/wsr88d/rda/message.hpp
Normal file
42
wxdata/include/scwx/wsr88d/rda/message.hpp
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <scwx/wsr88d/rda/message_header.hpp>
|
||||||
|
|
||||||
|
namespace scwx
|
||||||
|
{
|
||||||
|
namespace wsr88d
|
||||||
|
{
|
||||||
|
namespace rda
|
||||||
|
{
|
||||||
|
|
||||||
|
class MessageImpl;
|
||||||
|
|
||||||
|
class Message
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
explicit Message();
|
||||||
|
|
||||||
|
Message(const Message&) = delete;
|
||||||
|
Message& operator=(const Message&) = delete;
|
||||||
|
|
||||||
|
Message(Message&&) noexcept;
|
||||||
|
Message& operator=(Message&&) noexcept;
|
||||||
|
|
||||||
|
bool ValidateSize(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;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<MessageImpl> p;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace rda
|
||||||
|
} // namespace wsr88d
|
||||||
|
} // namespace scwx
|
||||||
39
wxdata/include/scwx/wsr88d/rda/message_factory.hpp
Normal file
39
wxdata/include/scwx/wsr88d/rda/message_factory.hpp
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <scwx/wsr88d/rda/message.hpp>
|
||||||
|
|
||||||
|
namespace scwx
|
||||||
|
{
|
||||||
|
namespace wsr88d
|
||||||
|
{
|
||||||
|
namespace rda
|
||||||
|
{
|
||||||
|
|
||||||
|
struct MessageInfo
|
||||||
|
{
|
||||||
|
std::unique_ptr<Message> message;
|
||||||
|
bool headerValid;
|
||||||
|
bool messageValid;
|
||||||
|
|
||||||
|
MessageInfo() : message(nullptr), headerValid(false), messageValid(false) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class MessageFactory
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
explicit MessageFactory() = delete;
|
||||||
|
~MessageFactory() = delete;
|
||||||
|
|
||||||
|
MessageFactory(const Message&) = delete;
|
||||||
|
MessageFactory& operator=(const MessageFactory&) = delete;
|
||||||
|
|
||||||
|
MessageFactory(MessageFactory&&) noexcept = delete;
|
||||||
|
MessageFactory& operator=(MessageFactory&&) noexcept = delete;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static MessageInfo Create(std::istream& is);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace rda
|
||||||
|
} // namespace wsr88d
|
||||||
|
} // namespace scwx
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
|
@ -20,7 +22,7 @@ public:
|
||||||
MessageHeader& operator=(const MessageHeader&) = delete;
|
MessageHeader& operator=(const MessageHeader&) = delete;
|
||||||
|
|
||||||
MessageHeader(MessageHeader&&) noexcept;
|
MessageHeader(MessageHeader&&) noexcept;
|
||||||
MessageHeader& operator=(MessageHeader&&);
|
MessageHeader& operator=(MessageHeader&&) noexcept;
|
||||||
|
|
||||||
uint16_t message_size() const;
|
uint16_t message_size() const;
|
||||||
uint8_t rda_redundant_channel() const;
|
uint8_t rda_redundant_channel() const;
|
||||||
|
|
@ -31,6 +33,8 @@ public:
|
||||||
uint16_t number_of_message_segments() const;
|
uint16_t number_of_message_segments() const;
|
||||||
uint16_t message_segment_number() const;
|
uint16_t message_segment_number() const;
|
||||||
|
|
||||||
|
void set_message_size(uint16_t messageSize);
|
||||||
|
|
||||||
bool Parse(std::istream& is);
|
bool Parse(std::istream& is);
|
||||||
|
|
||||||
static const size_t SIZE = 16u;
|
static const size_t SIZE = 16u;
|
||||||
|
|
|
||||||
19
wxdata/source/scwx/util/vectorbuf.cpp
Normal file
19
wxdata/source/scwx/util/vectorbuf.cpp
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
#include <scwx/util/vectorbuf.hpp>
|
||||||
|
|
||||||
|
namespace scwx
|
||||||
|
{
|
||||||
|
namespace util
|
||||||
|
{
|
||||||
|
|
||||||
|
vectorbuf::vectorbuf(std::vector<char>& v) : v_(v)
|
||||||
|
{
|
||||||
|
update_read_pointers(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vectorbuf::update_read_pointers(size_t size)
|
||||||
|
{
|
||||||
|
setg(v_.data(), v_.data(), v_.data() + size);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace util
|
||||||
|
} // namespace scwx
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
#include <scwx/wsr88d/ar2v_file.hpp>
|
#include <scwx/wsr88d/ar2v_file.hpp>
|
||||||
#include <scwx/wsr88d/rda/message_header.hpp>
|
#include <scwx/wsr88d/rda/message_factory.hpp>
|
||||||
#include <scwx/util/rangebuf.hpp>
|
#include <scwx/util/rangebuf.hpp>
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
@ -54,7 +54,7 @@ Ar2vFile::Ar2vFile() : p(std::make_unique<Ar2vFileImpl>()) {}
|
||||||
Ar2vFile::~Ar2vFile() = default;
|
Ar2vFile::~Ar2vFile() = default;
|
||||||
|
|
||||||
Ar2vFile::Ar2vFile(Ar2vFile&&) noexcept = default;
|
Ar2vFile::Ar2vFile(Ar2vFile&&) noexcept = default;
|
||||||
Ar2vFile& Ar2vFile::operator=(Ar2vFile&&) = default;
|
Ar2vFile& Ar2vFile::operator=(Ar2vFile&&) noexcept = default;
|
||||||
|
|
||||||
bool Ar2vFile::LoadFile(const std::string& filename)
|
bool Ar2vFile::LoadFile(const std::string& filename)
|
||||||
{
|
{
|
||||||
|
|
@ -112,6 +112,8 @@ bool Ar2vFile::LoadFile(const std::string& filename)
|
||||||
|
|
||||||
void Ar2vFileImpl::LoadLDMRecords(std::ifstream& f)
|
void Ar2vFileImpl::LoadLDMRecords(std::ifstream& f)
|
||||||
{
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(debug) << logPrefix_ << "Loading LDM Records";
|
||||||
|
|
||||||
numRecords_ = 0;
|
numRecords_ = 0;
|
||||||
|
|
||||||
while (f.peek() != EOF)
|
while (f.peek() != EOF)
|
||||||
|
|
@ -163,6 +165,8 @@ void Ar2vFileImpl::LoadLDMRecords(std::ifstream& f)
|
||||||
|
|
||||||
void Ar2vFileImpl::ParseLDMRecords()
|
void Ar2vFileImpl::ParseLDMRecords()
|
||||||
{
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(debug) << logPrefix_ << "Parsing LDM Records";
|
||||||
|
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
|
|
||||||
for (auto it = rawRecords_.begin(); it != rawRecords_.end(); it++)
|
for (auto it = rawRecords_.begin(); it != rawRecords_.end(); it++)
|
||||||
|
|
@ -177,18 +181,13 @@ void Ar2vFileImpl::ParseLDMRecords()
|
||||||
|
|
||||||
while (!ss.eof())
|
while (!ss.eof())
|
||||||
{
|
{
|
||||||
// TODO: Parse message, not just header
|
rda::MessageInfo msgInfo = rda::MessageFactory::Create(ss);
|
||||||
rda::MessageHeader header;
|
if (!msgInfo.headerValid)
|
||||||
if (!header.Parse(ss))
|
|
||||||
{
|
{
|
||||||
// Invalid header
|
// Invalid message
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Seek to the end of the current message
|
|
||||||
ss.seekg(header.message_size() * 2 - rda::MessageHeader::SIZE,
|
|
||||||
std::ios_base::cur);
|
|
||||||
|
|
||||||
off_t offset = 0;
|
off_t offset = 0;
|
||||||
uint16_t nextSize = 0u;
|
uint16_t nextSize = 0u;
|
||||||
do
|
do
|
||||||
|
|
|
||||||
234
wxdata/source/scwx/wsr88d/rda/clutter_filter_map.cpp
Normal file
234
wxdata/source/scwx/wsr88d/rda/clutter_filter_map.cpp
Normal file
|
|
@ -0,0 +1,234 @@
|
||||||
|
#include <scwx/wsr88d/rda/clutter_filter_map.hpp>
|
||||||
|
|
||||||
|
#include <istream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <boost/log/trivial.hpp>
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
# include <WinSock2.h>
|
||||||
|
#else
|
||||||
|
# include <arpa/inet.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace scwx
|
||||||
|
{
|
||||||
|
namespace wsr88d
|
||||||
|
{
|
||||||
|
namespace rda
|
||||||
|
{
|
||||||
|
|
||||||
|
static const std::string logPrefix_ =
|
||||||
|
"[scwx::wsr88d::rda::clutter_filter_map] ";
|
||||||
|
|
||||||
|
struct RangeZone
|
||||||
|
{
|
||||||
|
uint16_t opCode;
|
||||||
|
uint16_t endRange;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ClutterFilterMapImpl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit ClutterFilterMapImpl() :
|
||||||
|
mapGenerationDate_(), mapGenerationTime_(), rangeZones_() {};
|
||||||
|
~ClutterFilterMapImpl() = default;
|
||||||
|
|
||||||
|
uint16_t mapGenerationDate_;
|
||||||
|
uint16_t mapGenerationTime_;
|
||||||
|
|
||||||
|
std::vector<std::vector<std::vector<RangeZone>>> rangeZones_;
|
||||||
|
};
|
||||||
|
|
||||||
|
ClutterFilterMap::ClutterFilterMap() :
|
||||||
|
Message(), p(std::make_unique<ClutterFilterMapImpl>())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
ClutterFilterMap::~ClutterFilterMap() = default;
|
||||||
|
|
||||||
|
ClutterFilterMap::ClutterFilterMap(ClutterFilterMap&&) noexcept = default;
|
||||||
|
ClutterFilterMap&
|
||||||
|
ClutterFilterMap::operator=(ClutterFilterMap&&) noexcept = default;
|
||||||
|
|
||||||
|
uint16_t ClutterFilterMap::map_generation_date() const
|
||||||
|
{
|
||||||
|
return p->mapGenerationDate_;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t ClutterFilterMap::map_generation_time() const
|
||||||
|
{
|
||||||
|
return p->mapGenerationTime_;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t ClutterFilterMap::number_of_elevation_segments() const
|
||||||
|
{
|
||||||
|
return static_cast<uint16_t>(p->rangeZones_.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t ClutterFilterMap::number_of_range_zones(uint16_t e, uint16_t a) const
|
||||||
|
{
|
||||||
|
return static_cast<uint16_t>(p->rangeZones_[e][a].size());
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t ClutterFilterMap::op_code(uint16_t e, uint16_t a, uint16_t z) const
|
||||||
|
{
|
||||||
|
return p->rangeZones_[e][a][z].opCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t ClutterFilterMap::end_range(uint16_t e, uint16_t a, uint16_t z) const
|
||||||
|
{
|
||||||
|
return p->rangeZones_[e][a][z].endRange;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClutterFilterMap::Parse(std::istream& is)
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(debug)
|
||||||
|
<< logPrefix_ << "Parsing Clutter Filter Map (Message Type 15)";
|
||||||
|
|
||||||
|
bool messageValid = true;
|
||||||
|
size_t bytesRead = 0;
|
||||||
|
uint16_t numElevationSegments = 0;
|
||||||
|
|
||||||
|
is.read(reinterpret_cast<char*>(&p->mapGenerationDate_), 2);
|
||||||
|
is.read(reinterpret_cast<char*>(&p->mapGenerationTime_), 2);
|
||||||
|
is.read(reinterpret_cast<char*>(&numElevationSegments), 2);
|
||||||
|
bytesRead += 6;
|
||||||
|
|
||||||
|
p->mapGenerationDate_ = htons(p->mapGenerationDate_);
|
||||||
|
p->mapGenerationTime_ = htons(p->mapGenerationTime_);
|
||||||
|
numElevationSegments = htons(numElevationSegments);
|
||||||
|
|
||||||
|
if (is.eof())
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(warning) << logPrefix_ << "Reached end of file (1)";
|
||||||
|
messageValid = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (p->mapGenerationDate_ < 1)
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(warning)
|
||||||
|
<< logPrefix_ << "Invalid date: " << p->mapGenerationDate_;
|
||||||
|
messageValid = false;
|
||||||
|
}
|
||||||
|
if (p->mapGenerationTime_ > 1440)
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(warning)
|
||||||
|
<< logPrefix_ << "Invalid time: " << p->mapGenerationTime_;
|
||||||
|
messageValid = false;
|
||||||
|
}
|
||||||
|
if (numElevationSegments < 1 || numElevationSegments > 5)
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(warning)
|
||||||
|
<< logPrefix_
|
||||||
|
<< "Invalid number of elevation segments: " << numElevationSegments;
|
||||||
|
messageValid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!messageValid)
|
||||||
|
{
|
||||||
|
numElevationSegments = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->rangeZones_.resize(numElevationSegments);
|
||||||
|
|
||||||
|
for (uint16_t e = 0; e < numElevationSegments && messageValid; e++)
|
||||||
|
{
|
||||||
|
p->rangeZones_[e].resize(NUM_AZIMUTH_SEGMENTS);
|
||||||
|
|
||||||
|
for (uint16_t a = 0; a < NUM_AZIMUTH_SEGMENTS && messageValid; a++)
|
||||||
|
{
|
||||||
|
uint16_t numRangeZones;
|
||||||
|
is.read(reinterpret_cast<char*>(&numRangeZones), 2);
|
||||||
|
bytesRead += 2;
|
||||||
|
|
||||||
|
numRangeZones = htons(numRangeZones);
|
||||||
|
|
||||||
|
if (is.eof())
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(warning)
|
||||||
|
<< logPrefix_ << "Reached end of file (2)";
|
||||||
|
messageValid = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (numRangeZones < 1 || numRangeZones > 20)
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(warning)
|
||||||
|
<< logPrefix_
|
||||||
|
<< "Invalid number of range zones: " << numRangeZones;
|
||||||
|
messageValid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!messageValid)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->rangeZones_[e][a].resize(numRangeZones);
|
||||||
|
|
||||||
|
for (uint16_t z = 0; z < numRangeZones && messageValid; z++)
|
||||||
|
{
|
||||||
|
RangeZone& zone = p->rangeZones_[e][a][z];
|
||||||
|
|
||||||
|
is.read(reinterpret_cast<char*>(&zone.opCode), 2);
|
||||||
|
is.read(reinterpret_cast<char*>(&zone.endRange), 2);
|
||||||
|
bytesRead += 4;
|
||||||
|
|
||||||
|
zone.opCode = htons(zone.opCode);
|
||||||
|
zone.endRange = htons(zone.endRange);
|
||||||
|
|
||||||
|
if (is.eof())
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(warning)
|
||||||
|
<< logPrefix_ << "Reached end of file (3)";
|
||||||
|
messageValid = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (zone.opCode > 2)
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(warning)
|
||||||
|
<< logPrefix_ << "Invalid op code: " << zone.opCode;
|
||||||
|
messageValid = false;
|
||||||
|
}
|
||||||
|
if (zone.endRange > 511)
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(warning)
|
||||||
|
<< logPrefix_ << "Invalid end range: " << zone.endRange;
|
||||||
|
messageValid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ValidateSize(is, bytesRead))
|
||||||
|
{
|
||||||
|
messageValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!messageValid)
|
||||||
|
{
|
||||||
|
p->rangeZones_.resize(0);
|
||||||
|
p->rangeZones_.shrink_to_fit();
|
||||||
|
}
|
||||||
|
|
||||||
|
return messageValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<ClutterFilterMap>
|
||||||
|
ClutterFilterMap::Create(MessageHeader&& header, std::istream& is)
|
||||||
|
{
|
||||||
|
std::unique_ptr<ClutterFilterMap> message =
|
||||||
|
std::make_unique<ClutterFilterMap>();
|
||||||
|
message->set_header(std::move(header));
|
||||||
|
message->Parse(is);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace rda
|
||||||
|
} // namespace wsr88d
|
||||||
|
} // namespace scwx
|
||||||
72
wxdata/source/scwx/wsr88d/rda/message.cpp
Normal file
72
wxdata/source/scwx/wsr88d/rda/message.cpp
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
#include <scwx/wsr88d/rda/message.hpp>
|
||||||
|
|
||||||
|
#include <istream>
|
||||||
|
|
||||||
|
#include <boost/log/trivial.hpp>
|
||||||
|
|
||||||
|
namespace scwx
|
||||||
|
{
|
||||||
|
namespace wsr88d
|
||||||
|
{
|
||||||
|
namespace rda
|
||||||
|
{
|
||||||
|
|
||||||
|
static const std::string logPrefix_ = "[scwx::wsr88d::rda::message] ";
|
||||||
|
|
||||||
|
class MessageImpl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit MessageImpl() : header_() {};
|
||||||
|
~MessageImpl() = default;
|
||||||
|
|
||||||
|
MessageHeader header_;
|
||||||
|
};
|
||||||
|
|
||||||
|
Message::Message() : p(std::make_unique<MessageImpl>()) {}
|
||||||
|
Message::~Message() = default;
|
||||||
|
|
||||||
|
Message::Message(Message&&) noexcept = default;
|
||||||
|
Message& Message::operator=(Message&&) noexcept = default;
|
||||||
|
|
||||||
|
bool Message::ValidateSize(std::istream& is, size_t bytesRead) const
|
||||||
|
{
|
||||||
|
bool messageValid = true;
|
||||||
|
size_t dataSize = header().message_size() * 2 - header().SIZE;
|
||||||
|
|
||||||
|
if (bytesRead != dataSize)
|
||||||
|
{
|
||||||
|
is.seekg(static_cast<std::streamoff>(dataSize) -
|
||||||
|
static_cast<std::streamoff>(bytesRead),
|
||||||
|
std::ios_base::cur);
|
||||||
|
|
||||||
|
if (bytesRead < dataSize)
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(trace)
|
||||||
|
<< logPrefix_ << "Message contents smaller than size: " << bytesRead
|
||||||
|
<< " < " << dataSize << " bytes";
|
||||||
|
}
|
||||||
|
if (bytesRead > dataSize)
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(warning)
|
||||||
|
<< logPrefix_ << "Message contents larger than size: " << bytesRead
|
||||||
|
<< " > " << dataSize << " bytes";
|
||||||
|
messageValid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return messageValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MessageHeader& Message::header() const
|
||||||
|
{
|
||||||
|
return p->header_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Message::set_header(MessageHeader&& header)
|
||||||
|
{
|
||||||
|
p->header_ = std::move(header);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace rda
|
||||||
|
} // namespace wsr88d
|
||||||
|
} // namespace scwx
|
||||||
130
wxdata/source/scwx/wsr88d/rda/message_factory.cpp
Normal file
130
wxdata/source/scwx/wsr88d/rda/message_factory.cpp
Normal file
|
|
@ -0,0 +1,130 @@
|
||||||
|
#include <scwx/wsr88d/rda/message_factory.hpp>
|
||||||
|
|
||||||
|
#include <scwx/util/vectorbuf.hpp>
|
||||||
|
#include <scwx/wsr88d/rda/clutter_filter_map.hpp>
|
||||||
|
|
||||||
|
#include <istream>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <boost/log/trivial.hpp>
|
||||||
|
|
||||||
|
namespace scwx
|
||||||
|
{
|
||||||
|
namespace wsr88d
|
||||||
|
{
|
||||||
|
namespace rda
|
||||||
|
{
|
||||||
|
|
||||||
|
static const std::string logPrefix_ = "[scwx::wsr88d::rda::message_factory] ";
|
||||||
|
|
||||||
|
typedef std::function<std::unique_ptr<Message>(MessageHeader&&, std::istream&)>
|
||||||
|
CreateMessageFunction;
|
||||||
|
|
||||||
|
static const std::unordered_map<uint8_t, CreateMessageFunction> create_ {
|
||||||
|
{15, ClutterFilterMap::Create}};
|
||||||
|
|
||||||
|
static std::vector<char> messageData_;
|
||||||
|
static size_t bufferedSize_;
|
||||||
|
static util::vectorbuf messageBuffer_(messageData_);
|
||||||
|
static std::istream messageBufferStream_(&messageBuffer_);
|
||||||
|
|
||||||
|
MessageInfo MessageFactory::Create(std::istream& is)
|
||||||
|
{
|
||||||
|
MessageInfo info;
|
||||||
|
MessageHeader header;
|
||||||
|
info.headerValid = header.Parse(is);
|
||||||
|
info.messageValid = info.headerValid;
|
||||||
|
|
||||||
|
if (info.headerValid && create_.find(header.message_type()) == create_.end())
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(warning)
|
||||||
|
<< logPrefix_ << "Unknown message type: "
|
||||||
|
<< static_cast<unsigned>(header.message_type());
|
||||||
|
info.messageValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.messageValid)
|
||||||
|
{
|
||||||
|
uint16_t segment = header.message_segment_number();
|
||||||
|
uint16_t totalSegments = header.number_of_message_segments();
|
||||||
|
uint8_t messageType = header.message_type();
|
||||||
|
size_t dataSize = header.message_size() * 2 - MessageHeader::SIZE;
|
||||||
|
|
||||||
|
std::istream* messageStream = nullptr;
|
||||||
|
|
||||||
|
if (totalSegments == 1)
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(trace) << logPrefix_ << "Found Message "
|
||||||
|
<< static_cast<unsigned>(messageType);
|
||||||
|
messageStream = &is;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(trace)
|
||||||
|
<< logPrefix_ << "Found Message "
|
||||||
|
<< static_cast<unsigned>(messageType) << " Segment " << segment
|
||||||
|
<< "/" << totalSegments;
|
||||||
|
|
||||||
|
if (segment == 1)
|
||||||
|
{
|
||||||
|
// Estimate total message size
|
||||||
|
messageData_.reserve(dataSize * totalSegments);
|
||||||
|
bufferedSize_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (messageData_.capacity() < bufferedSize_ + dataSize)
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(debug)
|
||||||
|
<< logPrefix_ << "Bad size estimate, increasing size";
|
||||||
|
|
||||||
|
// Estimate remaining size
|
||||||
|
uint16_t remainingSegments =
|
||||||
|
std::max<uint16_t>(totalSegments - segment + 1, 100u);
|
||||||
|
size_t remainingSize = remainingSegments * dataSize;
|
||||||
|
|
||||||
|
messageData_.reserve(bufferedSize_ + remainingSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
is.read(messageData_.data() + bufferedSize_, dataSize);
|
||||||
|
bufferedSize_ += dataSize;
|
||||||
|
|
||||||
|
if (is.eof())
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(warning)
|
||||||
|
<< logPrefix_ << "End of file reached trying to buffer message";
|
||||||
|
info.messageValid = false;
|
||||||
|
messageData_.shrink_to_fit();
|
||||||
|
bufferedSize_ = 0;
|
||||||
|
}
|
||||||
|
else if (segment == totalSegments)
|
||||||
|
{
|
||||||
|
messageBuffer_.update_read_pointers(bufferedSize_);
|
||||||
|
header.set_message_size(
|
||||||
|
static_cast<uint16_t>(bufferedSize_ / 2 + MessageHeader::SIZE));
|
||||||
|
|
||||||
|
messageStream = &messageBufferStream_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (messageStream != nullptr)
|
||||||
|
{
|
||||||
|
info.message =
|
||||||
|
create_.at(messageType)(std::move(header), *messageStream);
|
||||||
|
messageData_.shrink_to_fit();
|
||||||
|
bufferedSize_ = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (info.headerValid)
|
||||||
|
{
|
||||||
|
// Seek to the end of the current message
|
||||||
|
is.seekg(header.message_size() * 2 - rda::MessageHeader::SIZE,
|
||||||
|
std::ios_base::cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace rda
|
||||||
|
} // namespace wsr88d
|
||||||
|
} // namespace scwx
|
||||||
|
|
@ -44,14 +44,11 @@ public:
|
||||||
uint16_t messageSegmentNumber_;
|
uint16_t messageSegmentNumber_;
|
||||||
};
|
};
|
||||||
|
|
||||||
MessageHeader::MessageHeader() :
|
MessageHeader::MessageHeader() : p(std::make_unique<MessageHeaderImpl>()) {}
|
||||||
p(std::make_unique<MessageHeaderImpl>())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
MessageHeader::~MessageHeader() = default;
|
MessageHeader::~MessageHeader() = default;
|
||||||
|
|
||||||
MessageHeader::MessageHeader(MessageHeader&&) noexcept = default;
|
MessageHeader::MessageHeader(MessageHeader&&) noexcept = default;
|
||||||
MessageHeader& MessageHeader::operator=(MessageHeader&&) = default;
|
MessageHeader& MessageHeader::operator=(MessageHeader&&) noexcept = default;
|
||||||
|
|
||||||
uint16_t MessageHeader::message_size() const
|
uint16_t MessageHeader::message_size() const
|
||||||
{
|
{
|
||||||
|
|
@ -93,6 +90,11 @@ uint16_t MessageHeader::message_segment_number() const
|
||||||
return p->messageSegmentNumber_;
|
return p->messageSegmentNumber_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MessageHeader::set_message_size(uint16_t messageSize)
|
||||||
|
{
|
||||||
|
p->messageSize_ = messageSize;
|
||||||
|
}
|
||||||
|
|
||||||
bool MessageHeader::Parse(std::istream& is)
|
bool MessageHeader::Parse(std::istream& is)
|
||||||
{
|
{
|
||||||
bool headerValid = true;
|
bool headerValid = true;
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,20 @@ project(scwx-data)
|
||||||
|
|
||||||
find_package(Boost)
|
find_package(Boost)
|
||||||
|
|
||||||
set(HDR_UTIL include/scwx/util/rangebuf.hpp)
|
set(HDR_UTIL include/scwx/util/rangebuf.hpp
|
||||||
set(SRC_UTIL source/scwx/util/rangebuf.cpp)
|
include/scwx/util/vectorbuf.hpp)
|
||||||
|
set(SRC_UTIL source/scwx/util/rangebuf.cpp
|
||||||
|
source/scwx/util/vectorbuf.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/message_header.hpp)
|
set(HDR_WSR88D_RDA include/scwx/wsr88d/rda/clutter_filter_map.hpp
|
||||||
set(SRC_WSR88D_RDA source/scwx/wsr88d/rda/message_header.cpp)
|
include/scwx/wsr88d/rda/message.hpp
|
||||||
|
include/scwx/wsr88d/rda/message_factory.hpp
|
||||||
|
include/scwx/wsr88d/rda/message_header.hpp)
|
||||||
|
set(SRC_WSR88D_RDA source/scwx/wsr88d/rda/clutter_filter_map.cpp
|
||||||
|
source/scwx/wsr88d/rda/message.cpp
|
||||||
|
source/scwx/wsr88d/rda/message_factory.cpp
|
||||||
|
source/scwx/wsr88d/rda/message_header.cpp)
|
||||||
|
|
||||||
add_library(wxdata OBJECT ${HDR_UTIL}
|
add_library(wxdata OBJECT ${HDR_UTIL}
|
||||||
${SRC_UTIL}
|
${SRC_UTIL}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue