blob: 7c14706e7825394a3760d9293227cae816948a52 [file] [log] [blame]
Brian Silverman1662a0e2013-12-19 17:50:01 -08001#include "bbb/crc.h"
Brian Silverman8cbf8332013-12-11 13:59:42 -08002
Brian Silverman04fac622014-01-26 18:32:15 -08003#include <assert.h>
4#include <errno.h>
5#include <string.h>
6
Brian Silverman8cbf8332013-12-11 13:59:42 -08007#include "aos/common/once.h"
Brian Silverman04fac622014-01-26 18:32:15 -08008#include "aos/common/logging/logging.h"
9
10#include "bbb/byte_io.h"
Brian Silverman8cbf8332013-12-11 13:59:42 -080011
12// There are various implementations that look a lot like this scattered around
13// the internet.
14
15namespace cape {
16namespace {
17
18const uint32_t kPolynomial = 0x04c11db7;
19
20const uint32_t *GenerateTable() {
21 static uint32_t table[256];
22
23 for (int i = 0; i < 256; ++i) {
24 uint32_t c = i << 24;
25 for (int j = 8; j > 0; --j) {
26 c = c & 0x80000000 ? ((c << 1) ^ kPolynomial) : (c << 1);
27 }
28 table[i] = c;
29 }
30
31 return table;
32}
33
34} // namespace
35
Brian Silverman04fac622014-01-26 18:32:15 -080036uint32_t CalculateChecksum(uint8_t *data, size_t length, uint32_t initial) {
37 assert((length % 4) == 0);
38
Daniel Petti059be422013-12-14 19:47:42 -080039 static ::aos::Once<const uint32_t> table_once(GenerateTable);
Brian Silverman8cbf8332013-12-11 13:59:42 -080040 const uint32_t *const table = table_once.Get();
41
Brian Silverman04fac622014-01-26 18:32:15 -080042 uint32_t r = initial;
Brian Silverman8cbf8332013-12-11 13:59:42 -080043
Brian Silverman53f29182013-12-21 15:16:27 -080044 for (size_t i = 0; i < (length / 4); ++i) {
45 for (int ii = 3; ii >= 0; --ii) {
46 r = (r << 8) ^ table[(r >> 24) ^ data[i * 4 + ii]];
47 }
Brian Silverman8cbf8332013-12-11 13:59:42 -080048 }
49
Brian Silverman53f29182013-12-21 15:16:27 -080050 return r;
Brian Silverman8cbf8332013-12-11 13:59:42 -080051}
52
Brian Silverman04fac622014-01-26 18:32:15 -080053uint32_t CalculateChecksum(::bbb::ByteReaderInterface *reader) {
54 uint8_t buffer[256];
55 int remainder_bytes = 0;
56 uint32_t checksum = 0xFFFFFFFF;
57 while (true) {
58 ssize_t read = reader->ReadBytes(&buffer[remainder_bytes],
59 sizeof(buffer) - remainder_bytes);
60 if (read == -2) return checksum;
61 if (read == -1) {
62 LOG(FATAL, "reader %p failed to read with %d: %s\n",
63 reader, errno, strerror(errno));
64 }
65 size_t checksum_bytes = (read / 4) * 4;
66 checksum = CalculateChecksum(buffer, checksum_bytes, checksum);
67 remainder_bytes = read - checksum_bytes;
68 memmove(buffer, &buffer[checksum_bytes], remainder_bytes);
69 }
70}
71
Brian Silverman8cbf8332013-12-11 13:59:42 -080072} // namespace cape