#include #include #include /* Returns the crc-16 for the given data. Note: the high and low bytes are * swapped in order to make the printf() call, below, easier. :^) */ unsigned short calc_crc(unsigned char* buf, int buf_len) { unsigned short crc = ~0; int i, j; for (i = 0; i < buf_len; ++i) { crc ^= buf[i]; for (j = 0; j < 8; ++j) { if (crc & 1) crc = (crc >> 1) ^ 0x8408; else crc = crc >> 1; } } return (((crc >> 8) & 255) << 0) | (((crc >> 0) & 255) << 8); } int main(int argc, char** argv) { int i, state, val, digit, retval; char c; unsigned char* line = NULL; int line_cap = 0; int line_len; unsigned char* data = NULL; int data_cap = 0; int data_len; if (argc != 1) { fprintf(stderr, "Usage: crc-16 < data\n"); return EXIT_FAILURE; } while (1) { line_len = getline(&line, &line_cap, stdin); if (line_len == -1) { if (feof(stdin)) { retval = EXIT_SUCCESS; } else { perror("getline"); retval = EXIT_FAILURE; } break; } /* Make sure there's enough space in the output buffer. */ if (line_len / 2 > data_cap) { data_cap = line_len / 2; data = realloc(data, data_cap); } state = val = data_len = 0; for (i = 0; i < line_len; ++i) { switch (c = line[i]) { default: continue; /* Skip this character. */ case 'a' ... 'f': digit = c - 'a' + 10; break; case 'A' ... 'F': digit = c - 'A' + 10; break; case '0' ... '9': digit = c - '0' + 0; break; } val = (val * 16) | (digit); ++state; if (state == 2) { data[data_len] = val; state = val = 0; ++data_len; } } /* Fix the first byte to equal the packet length. */ if (data_len > 0) { data[0] = data_len + 2; } /* Display the whole packet. */ for (i = 0; i < data_len; ++i) { printf("%02x", data[i]); } printf("%04x\n", calc_crc(data, data_len)); } free(line); free(data); return retval; } /* vim: set ts=4 sts=4 sw=4 tw=80 et: */