Brian Silverman | 1662a0e | 2013-12-19 17:50:01 -0800 | [diff] [blame] | 1 | #include "bbb/crc.h" |
Brian Silverman | 8cbf833 | 2013-12-11 13:59:42 -0800 | [diff] [blame] | 2 | |
Brian Silverman | 04fac62 | 2014-01-26 18:32:15 -0800 | [diff] [blame] | 3 | #include <assert.h> |
Brian Silverman | 04fac62 | 2014-01-26 18:32:15 -0800 | [diff] [blame] | 4 | #include <string.h> |
| 5 | |
Brian Silverman | 8cbf833 | 2013-12-11 13:59:42 -0800 | [diff] [blame] | 6 | #include "aos/common/once.h" |
Brian Silverman | 04fac62 | 2014-01-26 18:32:15 -0800 | [diff] [blame] | 7 | #include "aos/common/logging/logging.h" |
| 8 | |
| 9 | #include "bbb/byte_io.h" |
Brian Silverman | 8cbf833 | 2013-12-11 13:59:42 -0800 | [diff] [blame] | 10 | |
| 11 | // There are various implementations that look a lot like this scattered around |
| 12 | // the internet. |
| 13 | |
| 14 | namespace cape { |
| 15 | namespace { |
| 16 | |
| 17 | const uint32_t kPolynomial = 0x04c11db7; |
| 18 | |
| 19 | const 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 Silverman | 8dc9fd4 | 2014-02-10 13:35:43 -0800 | [diff] [blame] | 35 | uint32_t CalculateChecksum(const uint8_t *data, size_t length, |
| 36 | uint32_t initial) { |
Brian Silverman | 04fac62 | 2014-01-26 18:32:15 -0800 | [diff] [blame] | 37 | assert((length % 4) == 0); |
| 38 | |
Daniel Petti | 059be42 | 2013-12-14 19:47:42 -0800 | [diff] [blame] | 39 | static ::aos::Once<const uint32_t> table_once(GenerateTable); |
Brian Silverman | 8cbf833 | 2013-12-11 13:59:42 -0800 | [diff] [blame] | 40 | const uint32_t *const table = table_once.Get(); |
| 41 | |
Brian Silverman | 04fac62 | 2014-01-26 18:32:15 -0800 | [diff] [blame] | 42 | uint32_t r = initial; |
Brian Silverman | 8cbf833 | 2013-12-11 13:59:42 -0800 | [diff] [blame] | 43 | |
Brian Silverman | 53f2918 | 2013-12-21 15:16:27 -0800 | [diff] [blame] | 44 | 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 Silverman | 8cbf833 | 2013-12-11 13:59:42 -0800 | [diff] [blame] | 48 | } |
| 49 | |
Brian Silverman | 53f2918 | 2013-12-21 15:16:27 -0800 | [diff] [blame] | 50 | return r; |
Brian Silverman | 8cbf833 | 2013-12-11 13:59:42 -0800 | [diff] [blame] | 51 | } |
| 52 | |
Brian Silverman | 04fac62 | 2014-01-26 18:32:15 -0800 | [diff] [blame] | 53 | uint32_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 Silverman | d784488 | 2014-05-10 23:35:39 -0700 | [diff] [blame] | 62 | PLOG(FATAL, "reader %p failed to read", reader); |
Brian Silverman | 04fac62 | 2014-01-26 18:32:15 -0800 | [diff] [blame] | 63 | } |
| 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 Silverman | 8cbf833 | 2013-12-11 13:59:42 -0800 | [diff] [blame] | 71 | } // namespace cape |