diff --git a/tools/Makefile b/tools/Makefile index 87333ed..cca21a7 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -2,7 +2,7 @@ CC = gcc CCFLAGS = -Wall -o BUILDDIR = output/ -all: create_build_dir $(BUILDDIR)injector $(BUILDDIR)fileadder $(BUILDDIR)httpd_sim +all: create_build_dir $(BUILDDIR)injector $(BUILDDIR)fileadder $(BUILDDIR)httpd_sim $(BUILDDIR)crc_calculator create_build_dir: mkdir -p $(BUILDDIR) @@ -16,5 +16,8 @@ $(BUILDDIR)injector: injector.c $(BUILDDIR)fileadder: fileadder.c gcc $^ $(CCFLAGS) $@ +$(BUILDDIR)crc_calculator: crc_calculator.c + gcc $^ $(CCFLAGS) $@ + $(BUILDDIR)httpd_sim: httpd_sim.c httpd_sim.h gcc $< $(CCFLAGS) $@ -I/usr/include/json-c -ljson-c diff --git a/tools/crc_calculator.c b/tools/crc_calculator.c new file mode 100644 index 0000000..4089fea --- /dev/null +++ b/tools/crc_calculator.c @@ -0,0 +1,179 @@ +/* + * Calculator for the CRC16 as described in AN27 by Dallas Semiconductor + * http://www.microshadow.com/files/files8051/app27.pdf + * The implementation in C is based on the code given in + * https://carta.tech/man-pages/man3/_crc_ibutton_update.3avr.html + * The polynomial of the CRC is 0xa001: x^16 + x^15 + x^2 + 1 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +// Use a 4MB buffer, the same as the flash rom size +#define BUFFER_SIZE 0x400000 +char buffer[BUFFER_SIZE]; + +struct arguments { + char *input_file; + char *output_file; + bool update; + bool verify; +}; + +const char *argp_program_version = "crc_calculator 0.1"; +const char *argp_program_bug_address = "https://github.com/logicog/RTLPlayground/issues"; +static char doc[] = "Calculate (and optionally update) the CRC of an image"; +static char args_doc[] = "crc_calculator [options] INPUT_IMAGE"; +static struct argp_option options[] = { + { "output", 'o', "FILE", 0, "Output image file name instead of overwriting input image"}, + { "update", 'u', 0, OPTION_ARG_OPTIONAL, "Update the image with the CRC"}, + { "verify", 'v', 0, OPTION_ARG_OPTIONAL, "Verify the CRC of the file"}, + { 0 } +}; + + +uint16_t crc16_update(uint16_t crc, uint8_t a) +{ + crc ^= a; + for (int i = 0; i < 8; ++i) + crc = crc & 1 ? (crc >> 1) ^ 0xA001 : crc >> 1; + + return crc; +} + + +static error_t parse_opt(int key, char *arg, struct argp_state *state) +{ + struct arguments *arguments = state->input; + switch (key) { + case 'u': + arguments->update = true; + break; + case 'v': + arguments->verify = true; + break; + case 'o': + arguments->output_file = arg; + break; + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + + +static struct argp argp = { + options, parse_opt, args_doc, doc, 0, 0, 0 +}; + + +int main(int argc, char **argv) +{ + struct arguments arguments; + int arg_index; + char tmpfilename[] = "crc_XXXXXX"; + uint16_t crc = 0; + FILE *inptr; + int outptr; + int range; + + arguments.input_file = NULL; + arguments.output_file = NULL; + arguments.update = false; + arguments.verify = false; + + argp_parse(&argp, argc, argv, 0, &arg_index, &arguments); + if (!arg_index) + argp_usage (0); + + memset(buffer, 0, BUFFER_SIZE); + + size_t filesize = 0; + if (argv[arg_index]) { + inptr = fopen(argv[arg_index], "rb"); + if (inptr == NULL) { + printf("Cannot open input file %s\n", argv[arg_index]); + return 5; + } + + fseek(inptr, 0L, SEEK_END); + filesize = ftell(inptr); + rewind(inptr); + printf("Input file size: %ld\n", filesize); + if (filesize > BUFFER_SIZE) { + printf("File too large.\n"); + return 5; + } + size_t bytes_read = fread(buffer, 1, sizeof(buffer), inptr); + + printf("Bytes read: %ld\n", bytes_read); + + if (bytes_read != filesize) { + printf("Error reading input file.\n"); + return 5; + } + fclose(inptr); + } + + range = filesize; + if (!arguments.verify) { + if (arguments.update) { + range -= 2; + } else if (arguments.output_file) { + filesize += 2; + } + } + + for (int i = 0; i < range; i++) + crc = crc16_update(crc, buffer[i]); + + printf("CRC16 is: 0x%04x\n", crc); + + if (arguments.verify) { + if (crc == 0xb001) { + printf("Checksum OK\n"); + return 0; + } else { + printf("Checksum Incorrect\n"); + return 5; + } + } + + // We have to create a new image with updated CRC + if (arguments.update || arguments.output_file) { + crc ^= 0xffff; + printf("Setting CRC bytes at position: 0x%x to CRC 1s complement 0x%04x\n", range, crc); + // The CRC algorithm expects as input always first the LO-Byte + buffer[range] = crc; + buffer[range + 1] = crc >> 8; + + if (!arguments.update) + outptr = creat(arguments.output_file, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + else + outptr = mkstemp(tmpfilename); + + if (!outptr) { + printf("Cannot open %s\n", arguments.output_file); + return 5; + } + size_t written = write(outptr, buffer, filesize); + + if (written != filesize) { + printf("Error writing output file.\n"); + return 5; + } + close(outptr); + + if (arguments.update) + rename(tmpfilename, argv[arg_index]); + } + + return 0; +}