blob: c3ab8959ef5f52e38999adf8ba68508ee4848f11 [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>
Brian Silverman04fac622014-01-26 18:32:15 -08004#include <string.h>
5
Brian Silverman8cbf8332013-12-11 13:59:42 -08006#include "aos/common/once.h"
Brian Silverman04fac622014-01-26 18:32:15 -08007#include "aos/common/logging/logging.h"
8
9#include "bbb/byte_io.h"
Brian Silverman8cbf8332013-12-11 13:59:42 -080010
11// There are various implementations that look a lot like this scattered around
12// the internet.
13
14namespace cape {
15namespace {
16
17const uint32_t kPolynomial = 0x04c11db7;
18
19const uint32_t *GenerateTable() {
20 static uint32_t table[256];
21
22 for (int i = 0; i < 256; ++i) {
23 uint32_t c = i << 24;
24 for (int j = 8; j > 0; --j) {
25 c = c & 0x80000000 ? ((c << 1) ^ kPolynomial) : (c << 1);
26 }
27 table[i] = c;
28 }
29
30 return table;
31}
32
33} // namespace
34
Brian Silverman8dc9fd42014-02-10 13:35:43 -080035uint32_t CalculateChecksum(const uint8_t *data, size_t length,
36 uint32_t initial) {
Brian Silverman04fac622014-01-26 18:32:15 -080037 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) {
Brian Silvermand7844882014-05-10 23:35:39 -070062 PLOG(FATAL, "reader %p failed to read", reader);
Brian Silverman04fac622014-01-26 18:32:15 -080063 }
64 size_t checksum_bytes = (read / 4) * 4;
65 checksum = CalculateChecksum(buffer, checksum_bytes, checksum);
66 remainder_bytes = read - checksum_bytes;
67 memmove(buffer, &buffer[checksum_bytes], remainder_bytes);
68 }
69}
70
Brian Silverman8cbf8332013-12-11 13:59:42 -080071} // namespace cape