Refactoring generic message components to awips namespace

This commit is contained in:
Dan Paulat 2022-01-14 19:34:47 -06:00
parent a76103650e
commit 7a9582a689
14 changed files with 64 additions and 65 deletions

View file

@ -0,0 +1,67 @@
#include <scwx/awips/message.hpp>
#include <boost/log/trivial.hpp>
namespace scwx
{
namespace awips
{
static const std::string logPrefix_ = "[scwx::awips::message] ";
class MessageImpl
{
public:
explicit MessageImpl() {};
~MessageImpl() = default;
};
Message::Message() : p(std::make_unique<MessageImpl>()) {}
Message::~Message() = default;
Message::Message(Message&&) noexcept = default;
Message& Message::operator=(Message&&) noexcept = default;
bool Message::ValidateMessage(std::istream& is, size_t bytesRead) const
{
bool messageValid = true;
const size_t dataSize = data_size();
if (is.eof())
{
BOOST_LOG_TRIVIAL(warning) << logPrefix_ << "Reached end of data stream";
messageValid = false;
}
else if (is.fail())
{
BOOST_LOG_TRIVIAL(warning)
<< logPrefix_ << "Could not read from input stream";
messageValid = false;
}
else 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;
}
} // namespace awips
} // namespace scwx

View file

@ -0,0 +1,251 @@
#include <scwx/awips/wmo_header.hpp>
#include <scwx/util/streams.hpp>
#include <istream>
#include <sstream>
#include <string>
#include <boost/log/trivial.hpp>
#ifdef WIN32
# include <WinSock2.h>
#else
# include <arpa/inet.h>
#endif
namespace scwx
{
namespace awips
{
static const std::string logPrefix_ = "[scwx::awips::wmo_header] ";
class WmoHeaderImpl
{
public:
explicit WmoHeaderImpl() :
sequenceNumber_ {},
dataType_ {},
geographicDesignator_ {},
bulletinId_ {},
icao_ {},
dateTime_ {},
bbbIndicator_ {},
productCategory_ {},
productDesignator_ {}
{
}
~WmoHeaderImpl() = default;
std::string sequenceNumber_;
std::string dataType_;
std::string geographicDesignator_;
std::string bulletinId_;
std::string icao_;
std::string dateTime_;
std::string bbbIndicator_;
std::string productCategory_;
std::string productDesignator_;
};
WmoHeader::WmoHeader() : p(std::make_unique<WmoHeaderImpl>()) {}
WmoHeader::~WmoHeader() = default;
WmoHeader::WmoHeader(WmoHeader&&) noexcept = default;
WmoHeader& WmoHeader::operator=(WmoHeader&&) noexcept = default;
const std::string& WmoHeader::sequence_number() const
{
return p->sequenceNumber_;
}
const std::string& WmoHeader::data_type() const
{
return p->dataType_;
}
const std::string& WmoHeader::geographic_designator() const
{
return p->geographicDesignator_;
}
const std::string& WmoHeader::bulletin_id() const
{
return p->bulletinId_;
}
const std::string& WmoHeader::icao() const
{
return p->icao_;
}
const std::string& WmoHeader::date_time() const
{
return p->dateTime_;
}
const std::string& WmoHeader::bbb_indicator() const
{
return p->bbbIndicator_;
}
const std::string& WmoHeader::product_category() const
{
return p->productCategory_;
}
const std::string& WmoHeader::product_designator() const
{
return p->productDesignator_;
}
bool WmoHeader::Parse(std::istream& is)
{
bool headerValid = true;
std::string sohLine;
std::string sequenceLine;
std::string wmoLine;
std::string awipsLine;
if (is.peek() == 0x01)
{
std::getline(is, sohLine);
std::getline(is, sequenceLine);
}
std::getline(is, wmoLine);
std::getline(is, awipsLine);
if (is.eof())
{
BOOST_LOG_TRIVIAL(debug) << logPrefix_ << "Reached end of file";
headerValid = false;
}
else if (!sohLine.empty() && !sohLine.ends_with("\r\r"))
{
BOOST_LOG_TRIVIAL(debug)
<< logPrefix_ << "Start of Heading Line is malformed";
headerValid = false;
}
else if (!sequenceLine.empty() && !sequenceLine.ends_with(" \r\r"))
{
BOOST_LOG_TRIVIAL(debug) << logPrefix_ << "Sequence Line is malformed";
headerValid = false;
}
else if (!wmoLine.ends_with("\r\r"))
{
BOOST_LOG_TRIVIAL(debug)
<< logPrefix_ << "WMO Abbreviated Heading Line is malformed";
headerValid = false;
}
else if (!awipsLine.ends_with("\r\r"))
{
BOOST_LOG_TRIVIAL(debug)
<< logPrefix_ << "AWIPS Identifier Line is malformed";
headerValid = false;
}
else
{
// Remove delimiters from the end of the line
if (!sequenceLine.empty())
{
sequenceLine.erase(sequenceLine.length() - 3);
}
wmoLine.erase(wmoLine.length() - 2);
awipsLine.erase(awipsLine.length() - 2);
}
// Transmission Header:
// [SOH]
// nnn
if (headerValid && !sequenceLine.empty())
{
p->sequenceNumber_ = sequenceLine;
}
// WMO Abbreviated Heading Line:
// T1T2A1A2ii CCCC YYGGgg (BBB)
if (headerValid)
{
std::string token;
std::istringstream wmoTokens(wmoLine);
std::vector<std::string> wmoTokenList;
while (wmoTokens >> token)
{
wmoTokenList.push_back(std::move(token));
}
if (wmoTokenList.size() < 3 || wmoTokenList.size() > 4)
{
BOOST_LOG_TRIVIAL(debug)
<< logPrefix_ << "Invalid number of WMO tokens";
headerValid = false;
}
else if (wmoTokenList[0].size() != 6)
{
BOOST_LOG_TRIVIAL(debug) << logPrefix_ << "WMO identifier malformed";
headerValid = false;
}
else if (wmoTokenList[1].size() != 4)
{
BOOST_LOG_TRIVIAL(debug) << logPrefix_ << "ICAO malformed";
headerValid = false;
}
else if (wmoTokenList[2].size() != 6)
{
BOOST_LOG_TRIVIAL(debug) << logPrefix_ << "Date/time malformed";
headerValid = false;
}
else if (wmoTokenList.size() == 4 && wmoTokenList[3].size() != 3)
{
// BBB indicator is optional
BOOST_LOG_TRIVIAL(debug) << logPrefix_ << "BBB indicator malformed";
headerValid = false;
}
else
{
p->dataType_ = wmoTokenList[0].substr(0, 2);
p->geographicDesignator_ = wmoTokenList[0].substr(2, 2);
p->bulletinId_ = wmoTokenList[0].substr(4, 2);
p->icao_ = wmoTokenList[1];
p->dateTime_ = wmoTokenList[2];
if (wmoTokenList.size() == 4)
{
p->bbbIndicator_ = wmoTokenList[3];
}
else
{
p->bbbIndicator_ = "";
}
}
}
// AWIPS Identifer Line:
// NNNxxx
if (headerValid)
{
if (awipsLine.size() != 6)
{
BOOST_LOG_TRIVIAL(debug)
<< logPrefix_ << "AWIPS Identifier Line bad size";
headerValid = false;
}
else
{
p->productCategory_ = awipsLine.substr(0, 3);
p->productDesignator_ = awipsLine.substr(3, 3);
}
}
return headerValid;
}
} // namespace awips
} // namespace scwx