Ради интереса, я взял это за упражнение при написании простого двоичного парсера с использованием Boost Spirit (c ++).Я включил преобразование из формата вопроса и проверку контрольной суммы.
Я заставил парсер распознавать фактическую длину данных и произвольный выбор контейнера STL для пакетных данных.Вывод ниже:
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
namespace qi=boost::spirit::qi;
namespace karma=boost::spirit::karma;
namespace phx=boost::phoenix;
typedef unsigned char uchar;
static const auto inbyte = qi::uint_parser<unsigned char, 16, 2, 2>();
static const auto outbyte = karma::right_align(2,'0') [ karma::hex ];
// for some reason the alignment doesn't 'take' with the above, so HACK:
#define outbyte karma::right_align(2,'0') [ karma::hex ]
struct packet_t
{
enum { HEADER = 0x02 };
uchar checksum, id;
typedef std::string data_t;
/// the following work without modification:
// typedef std::vector<uchar> data_t;
// typedef std::list<int> data_t;
data_t data;
uchar do_checksum() const
{
return (uchar) -std::accumulate(data.begin(), data.end(),
HEADER + data.size());
}
bool is_valid() const
{ return checksum == do_checksum(); }
};
BOOST_FUSION_ADAPT_STRUCT(packet_t,
(packet_t::data_t, data) (uchar, checksum) (uchar, id));
int main()
{
static const std::string input =
"02:0d:be:ef:03:06:00:19:d3:02:00:00:60:00:00:ed:01\n"
"02:0d:be:ef:03:06:00:cd:d2:02:00:00:20:00:00:7a:01\n"
"02:0d:be:ef:03:06:00:10:f6:02:00:ba:30:00:00:49:01\n"
"02:0d:be:ef:03:06:00:c8:d8:02:00:20:30:00:00:49:01\n"
"02:08:c8:d8:02:00:20:30:00:00:49:01\n"; // failure test case
// convert hex to bytes
std::vector<std::vector<char> > rawpackets;
if (!qi::parse(input.begin(), input.end(), (inbyte % ':') % qi::eol, rawpackets))
{ std::cerr << "bailing" << std::endl; return 255; }
// std::cout << karma::format(karma::eps << outbyte % ':' % karma::eol, rawpackets) << std::endl;
// analyze & checksum packets
for (auto raw: rawpackets)
{
std::cout << karma::format(karma::eps << outbyte % ':', raw);
using namespace qi;
rule<decltype(raw.begin()), packet_t(), locals<uchar> > parser;
parser %= byte_(packet_t::HEADER)
> omit[ byte_ [ _a = _1 ] ] // datalen
> repeat(_a)[byte_] // data
> byte_ // checksum
> byte_; // id
packet_t packet;
if (!parse(raw.begin(), raw.end(), parser, packet))
{ std::cerr << " bailing" << std::endl; return 255; }
std::cout << " do_checksum():\t" << karma::format(outbyte, packet.do_checksum());
std::cout << " is_valid():\t" << std::boolalpha << packet.is_valid() << std::endl;
}
return 0;
}
Вывод
02:0d:be:ef:03:06:00:19:d3:02:00:00:60:00:00:ed:01 do_checksum(): ed is_valid(): true
02:0d:be:ef:03:06:00:cd:d2:02:00:00:20:00:00:7a:01 do_checksum(): 7a is_valid(): true
02:0d:be:ef:03:06:00:10:f6:02:00:ba:30:00:00:49:01 do_checksum(): 49 is_valid(): true
02:0d:be:ef:03:06:00:c8:d8:02:00:20:30:00:00:49:01 do_checksum(): 49 is_valid(): true
02:08:c8:d8:02:00:20:30:00:00:49:01 do_checksum(): 04 is_valid(): false