blob: 88c338d4a0a9388d9ee47058262363e003640e8b [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 Silverman8dc9fd42014-02-10 13:35:43 -080036uint32_t CalculateChecksum(const uint8_t *data, size_t length,
37 uint32_t initial) {
Brian Silverman04fac622014-01-26 18:32:15 -080038 assert((length % 4) == 0);
39
Daniel Petti059be422013-12-14 19:47:42 -080040 static ::aos::Once<const uint32_t> table_once(GenerateTable);
Brian Silverman8cbf8332013-12-11 13:59:42 -080041 const uint32_t *const table = table_once.Get();
42
Brian Silverman04fac622014-01-26 18:32:15 -080043 uint32_t r = initial;
Brian Silverman8cbf8332013-12-11 13:59:42 -080044
Brian Silverman53f29182013-12-21 15:16:27 -080045 for (size_t i = 0; i < (length / 4); ++i) {
46 for (int ii = 3; ii >= 0; --ii) {
47 r = (r << 8) ^ table[(r >> 24) ^ data[i * 4 + ii]];
48 }
Brian Silverman8cbf8332013-12-11 13:59:42 -080049 }
50
Brian Silverman53f29182013-12-21 15:16:27 -080051 return r;
Brian Silverman8cbf8332013-12-11 13:59:42 -080052}
53
Brian Silverman04fac622014-01-26 18:32:15 -080054uint32_t CalculateChecksum(::bbb::ByteReaderInterface *reader) {
55 uint8_t buffer[256];
56 int remainder_bytes = 0;
57 uint32_t checksum = 0xFFFFFFFF;
58 while (true) {
59 ssize_t read = reader->ReadBytes(&buffer[remainder_bytes],
60 sizeof(buffer) - remainder_bytes);
61 if (read == -2) return checksum;
62 if (read == -1) {
63 LOG(FATAL, "reader %p failed to read with %d: %s\n",
64 reader, errno, strerror(errno));
65 }
66 size_t checksum_bytes = (read / 4) * 4;
67 checksum = CalculateChecksum(buffer, checksum_bytes, checksum);
68 remainder_bytes = read - checksum_bytes;
69 memmove(buffer, &buffer[checksum_bytes], remainder_bytes);
70 }
71}
72
Brian Silverman8cbf8332013-12-11 13:59:42 -080073} // namespace cape