How do you interpret this phrase?
How do you interpret this phrase?
Checksum
This is the value to make zero on the addition of the lower 8 bits from the header to the checksum.
With this protocol description:
Protocol
Consist of header (1 byte) + data length (1 byte) + command data (13 bytes) + check sum (1 bytes) + connection ID (1 byte).
(I literally copied this protocol description, so I'dont know why there is 1 bytes
(in plural). But I can tell you it is only one byte)
Here are some sample TCP packets of this protocol:
HE:DL:-----开发者_运维知识库-------Command Data -------------:CS:ID
02:0d:be:ef:03:06:00:19:d3:02:00:00:60:00:00:ed:01
02:0d:be:ef:03:06:00:cd:d2:02:00:00:20:00:00:7a:01
02:0d:be:ef:03:06:00:10:f6:02:00:ba:30:00:00:49:01
02:0d:be:ef:03:06:00:c8:d8:02:00:20:30:00:00:49:01
// Requested Packets
02:0d:be:ef:03:06:00:13:d3:01:00:02:30:01:00:21:01
02:0d:be:ef:03:06:00:c2:ff:02:00:90:10:00:00:d8:01
Where
HE
is the HEader (which is fixed to0x02
)DL
is the DataLength (which is always0x0d
, because the packets are all the same length)CS
is the CheckSum (which is my question about)ID
is the connection ID (seems to be always 01 in my tests)
I can't figure out how the checksum is computed. I hope I gave enough info.
Thanks in advance.
I think there's just an error in the description. It looks like they are summing all the bytes between the header and the checksum. And the checksum is just a number that clears the lower 8 bits. So, for the first example, the sum of all bytes between the header and the checksum is 0x0313. Or
0x0313 0000 0011 0001 0011
0x00ED 0000 0000 1110 1101
When it's lined up like that, you can clearly see you'll be zeroing out the lower 8 bits and returning:
0x0400 0000 0100 0000 0000
You didn't specify a language, but you could also quickly calculate your own checksum by doing (0 XOR calculatedSum) + 1.
You
- Sum up all the bytes before the check sum field.
- Extract the low 8 bits of the sum
- Find the value("value to make zero"), that, when added to the computed sum becomes 0 (i.e. you solve "x + computed sum = 0")
Anyway, this C code computes the correct sum for all your 4 examples:
uint8_t silly_chksum(const uint8_t *data, size_t len)
{
size_t i;
unsigned int chk = -1;
for(i = 0; i < len ;i++)
{
chk += data[i];
}
return ~(chk & 0xff);
}
If you add up all the hex numbers in the Header, DataLength, CommandData, and CheckSum, it makes 1024.
For example, here's the sum of the second example (I skipped the 0x00's):
0x02+0x0d+0xbe+0xef+0x03+0x06+0xcd+0xd2+0x02+0x20+0x7a = 1024
Screenshot (sum is just a javascript function I wrote to sum the hex values automatically):
EDIT: It will not necessarily sum to 1024, rather, if it is valid it will sum to a number where the 8 lower bits are 0, such as 1024 (10000000000), 768 (1100000000), and 1280 (10100000000).
Just for fun, I took this as an exercise in writing a simple binary parser using Boost Spirit (c++). I included the conversion from the question format and the checksum verification.
I made the parser recognize actual datalength and arbitrary choice of STL container for the packet data. Output below:
#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;
}
Output
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
精彩评论