Merge pull request #30 from logicog/crc16

CRC-16 Calculation and verification
This commit is contained in:
René van Dorst
2025-10-26 21:59:50 +00:00
committed by GitHub
6 changed files with 407 additions and 46 deletions
+5 -1
View File
@@ -40,6 +40,9 @@ clean:
$(BUILDDIR)crtstart.rel: crtstart.asm
$(ASM) $(AFLAGS) -o $@ $<
$(BUILDDIR)crc16.rel: crc16.asm
$(ASM) $(AFLAGS) -o $@ $<
$(BUILDDIR)%.rel: %.c
$(CC) $(CC_FLAGS) -o $@ -c $<
@@ -47,7 +50,7 @@ $(BUILDDIR)%.rel: $(BUILDDIR)%.asm
${ASM} ${AFLAGS} -o $@ $<
# mv -f $(addprefix $(basename $^), .lst .rel .sym) .
$(BUILDDIR)rtlplayground.ihx: $(BUILDDIR)crtstart.rel $(OBJS)
$(BUILDDIR)rtlplayground.ihx: $(BUILDDIR)crtstart.rel $(OBJS) $(BUILDDIR)crc16.rel
$(CC) $(CC_FLAGS) -Wl-bHOME=${BOOTLOADER_ADDRESS} -Wl-bBANK1=0x14000 -Wl-r -o $@ $^
$(BUILDDIR)rtlplayground.img: $(BUILDDIR)rtlplayground.ihx
@@ -61,6 +64,7 @@ $(BUILDDIR)rtlplayground.bin: $(BUILDDIR)rtlplayground.img
dd if=$< skip=80 bs=1024 >>$@
tools/$(BUILDDIR)fileadder -a $(CONFIG_LOCATION) -s $(IMAGESIZE) -d config.txt $@
tools/$(BUILDDIR)fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -d html -p html_data $@
tools/$(BUILDDIR)crc_calculator -u $@
.PHONY: clean all $(SUBDIRS)
+121
View File
@@ -0,0 +1,121 @@
;
; CRC16 calculation module
;
.globl _crc_value
.globl _crc16
.equ BANK, 0x96
; .equ DPS, 0x86
; Variable in XMEM holding current CRC16 value, being updated
.area XSEG (XDATA)
_crc_value::
.ds 2
;-------------------------------------------------------
; CRC16 subroutine
; - dptr points to byte to be CRCd in xmem
; - algorithm uses table lookup
;-------------------------------------------------------
.area HOME (CODE)
.area CSEG (CODE)
; .area BANK1 (CODE)
_crc16:
mov BANK, #1
push dph
push dpl
movx a, @dptr
; inc DPS
mov b, a
mov dptr, #_crc_value
movx a, @dptr
xrl a, b ; create index into tables
push a ; save index
mov dptr, #crc16_table_l ; low part of table address
movc a, @a+dptr ; get low byte
mov b, a
mov dptr, #_crc_value + 1
movx a, @dptr
xrl a, b
mov dptr, #_crc_value
movx @dptr, a ; save result low part
mov dptr, #crc16_table_h ; high part of table address
pop a ; restore index
movc a, @a+dptr
mov dptr, #_crc_value+1
movx @dptr, a ; save result high part
pop dpl
pop dph
; clr DPS
ret
.area BANK1 (CODE)
crc16_table_l:
.byte #0x00, #0xc1, #0x81, #0x40, #0x01, #0xc0, #0x80, #0x41
.byte #0x01, #0xc0, #0x80, #0x41, #0x00, #0xc1, #0x81, #0x40
.byte #0x01, #0xc0, #0x80, #0x41, #0x00, #0xc1, #0x81, #0x40
.byte #0x00, #0xc1, #0x81, #0x40, #0x01, #0xc0, #0x80, #0x41
.byte #0x01, #0xc0, #0x80, #0x41, #0x00, #0xc1, #0x81, #0x40
.byte #0x00, #0xc1, #0x81, #0x40, #0x01, #0xc0, #0x80, #0x41
.byte #0x00, #0xc1, #0x81, #0x40, #0x01, #0xc0, #0x80, #0x41
.byte #0x01, #0xc0, #0x80, #0x41, #0x00, #0xc1, #0x81, #0x40
.byte #0x01, #0xc0, #0x80, #0x41, #0x00, #0xc1, #0x81, #0x40
.byte #0x00, #0xc1, #0x81, #0x40, #0x01, #0xc0, #0x80, #0x41
.byte #0x00, #0xc1, #0x81, #0x40, #0x01, #0xc0, #0x80, #0x41
.byte #0x01, #0xc0, #0x80, #0x41, #0x00, #0xc1, #0x81, #0x40
.byte #0x00, #0xc1, #0x81, #0x40, #0x01, #0xc0, #0x80, #0x41
.byte #0x01, #0xc0, #0x80, #0x41, #0x00, #0xc1, #0x81, #0x40
.byte #0x01, #0xc0, #0x80, #0x41, #0x00, #0xc1, #0x81, #0x40
.byte #0x00, #0xc1, #0x81, #0x40, #0x01, #0xc0, #0x80, #0x41
.byte #0x01, #0xc0, #0x80, #0x41, #0x00, #0xc1, #0x81, #0x40
.byte #0x00, #0xc1, #0x81, #0x40, #0x01, #0xc0, #0x80, #0x41
.byte #0x00, #0xc1, #0x81, #0x40, #0x01, #0xc0, #0x80, #0x41
.byte #0x01, #0xc0, #0x80, #0x41, #0x00, #0xc1, #0x81, #0x40
.byte #0x00, #0xc1, #0x81, #0x40, #0x01, #0xc0, #0x80, #0x41
.byte #0x01, #0xc0, #0x80, #0x41, #0x00, #0xc1, #0x81, #0x40
.byte #0x01, #0xc0, #0x80, #0x41, #0x00, #0xc1, #0x81, #0x40
.byte #0x00, #0xc1, #0x81, #0x40, #0x01, #0xc0, #0x80, #0x41
.byte #0x00, #0xc1, #0x81, #0x40, #0x01, #0xc0, #0x80, #0x41
.byte #0x01, #0xc0, #0x80, #0x41, #0x00, #0xc1, #0x81, #0x40
.byte #0x01, #0xc0, #0x80, #0x41, #0x00, #0xc1, #0x81, #0x40
.byte #0x00, #0xc1, #0x81, #0x40, #0x01, #0xc0, #0x80, #0x41
.byte #0x01, #0xc0, #0x80, #0x41, #0x00, #0xc1, #0x81, #0x40
.byte #0x00, #0xc1, #0x81, #0x40, #0x01, #0xc0, #0x80, #0x41
.byte #0x00, #0xc1, #0x81, #0x40, #0x01, #0xc0, #0x80, #0x41
.byte #0x01, #0xc0, #0x80, #0x41, #0x00, #0xc1, #0x81, #0x40
crc16_table_h:
.byte #0x00, #0xc0, #0xc1, #0x01, #0xc3, #0x03, #0x02, #0xc2
.byte #0xc6, #0x06, #0x07, #0xc7, #0x05, #0xc5, #0xc4, #0x04
.byte #0xcc, #0x0c, #0x0d, #0xcd, #0x0f, #0xcf, #0xce, #0x0e
.byte #0x0a, #0xca, #0xcb, #0x0b, #0xc9, #0x09, #0x08, #0xc8
.byte #0xd8, #0x18, #0x19, #0xd9, #0x1b, #0xdb, #0xda, #0x1a
.byte #0x1e, #0xde, #0xdf, #0x1f, #0xdd, #0x1d, #0x1c, #0xdc
.byte #0x14, #0xd4, #0xd5, #0x15, #0xd7, #0x17, #0x16, #0xd6
.byte #0xd2, #0x12, #0x13, #0xd3, #0x11, #0xd1, #0xd0, #0x10
.byte #0xf0, #0x30, #0x31, #0xf1, #0x33, #0xf3, #0xf2, #0x32
.byte #0x36, #0xf6, #0xf7, #0x37, #0xf5, #0x35, #0x34, #0xf4
.byte #0x3c, #0xfc, #0xfd, #0x3d, #0xff, #0x3f, #0x3e, #0xfe
.byte #0xfa, #0x3a, #0x3b, #0xfb, #0x39, #0xf9, #0xf8, #0x38
.byte #0x28, #0xe8, #0xe9, #0x29, #0xeb, #0x2b, #0x2a, #0xea
.byte #0xee, #0x2e, #0x2f, #0xef, #0x2d, #0xed, #0xec, #0x2c
.byte #0xe4, #0x24, #0x25, #0xe5, #0x27, #0xe7, #0xe6, #0x26
.byte #0x22, #0xe2, #0xe3, #0x23, #0xe1, #0x21, #0x20, #0xe0
.byte #0xa0, #0x60, #0x61, #0xa1, #0x63, #0xa3, #0xa2, #0x62
.byte #0x66, #0xa6, #0xa7, #0x67, #0xa5, #0x65, #0x64, #0xa4
.byte #0x6c, #0xac, #0xad, #0x6d, #0xaf, #0x6f, #0x6e, #0xae
.byte #0xaa, #0x6a, #0x6b, #0xab, #0x69, #0xa9, #0xa8, #0x68
.byte #0x78, #0xb8, #0xb9, #0x79, #0xbb, #0x7b, #0x7a, #0xba
.byte #0xbe, #0x7e, #0x7f, #0xbf, #0x7d, #0xbd, #0xbc, #0x7c
.byte #0xb4, #0x74, #0x75, #0xb5, #0x77, #0xb7, #0xb6, #0x76
.byte #0x72, #0xb2, #0xb3, #0x73, #0xb1, #0x71, #0x70, #0xb0
.byte #0x50, #0x90, #0x91, #0x51, #0x93, #0x53, #0x52, #0x92
.byte #0x96, #0x56, #0x57, #0x97, #0x55, #0x95, #0x94, #0x54
.byte #0x9c, #0x5c, #0x5d, #0x9d, #0x5f, #0x9f, #0x9e, #0x5e
.byte #0x5a, #0x9a, #0x9b, #0x5b, #0x99, #0x59, #0x58, #0x98
.byte #0x88, #0x48, #0x49, #0x89, #0x4b, #0x8b, #0x8a, #0x4a
.byte #0x4e, #0x8e, #0x8f, #0x4f, #0x8d, #0x4d, #0x4c, #0x8c
.byte #0x44, #0x84, #0x85, #0x45, #0x87, #0x47, #0x46, #0x86
.byte #0x82, #0x42, #0x43, #0x83, #0x41, #0x81, #0x80, #0x40
+23 -5
View File
@@ -49,6 +49,10 @@ __xdata uint16_t short_parsed;
#define TSTATE_CLOSED 3
#define TSTATE_POST 4
extern __xdata uint16_t crc_value;
__xdata uint16_t crc_final;
void crc16(__xdata uint8_t *v) __naked;
inline uint8_t is_separator(uint8_t c)
{
@@ -184,13 +188,15 @@ __xdata uint8_t *scan_header(__xdata uint8_t *p)
content_type += 30;
uint8_t i = 0;
while (content_type[i] != '\r' && content_type[i] != '\n') {
boundary[i + 2] = content_type[i];
boundary[i + 4] = content_type[i];
i++;
}
// The boundary between parts is "--" + the boundary given in the header
boundary[0] = '-';
boundary[1] = '-';
boundary[i + 2] = 0;
// The boundary between parts is "\r\n--" + the boundary given in the header
boundary[0] = '\r';
boundary[1] = '\n';
boundary[2] = '-';
boundary[3] = '-';
boundary[i + 4] = 0;
}
return p;
}
@@ -224,6 +230,12 @@ uint8_t stream_upload(uint16_t bptr)
uptr += write_len;
write_len = 0;
// TODO: This is a bit premature, what about a nice web-page saying the device will reset???
print_string("CRC16: "); print_short(crc_final); write_char('\n');
if (crc_final == 0xb001) {
print_string("Checksum OK.");
} else {
print_string("Checksum incorrect!");
}
print_string("Upload to flash done, will reset!\n");
reset_chip();
if (bptr >= uip_len)
@@ -231,6 +243,9 @@ uint8_t stream_upload(uint16_t bptr)
return 1;
}
if (p[bptr] == boundary[bindex]) {
if (!bindex)
crc_final = crc_value;
crc16(p + bptr);
bptr++;
bindex++;
} else {
@@ -239,9 +254,11 @@ uint8_t stream_upload(uint16_t bptr)
write_len += bindex;
bindex = 0;
}
crc16(p + bptr);
flash_buf[write_len++] = p[bptr++];
if (write_len >= FLASHMEM_PAGE_SIZE) {
print_string("len: "); print_short(write_len); write_char(' ');
print_string("CRC16: "); print_short(crc_value); write_char('\n');
flash_region.addr = uptr;
flash_region.len = FLASHMEM_PAGE_SIZE;
flash_write_bytes(flash_buf);
@@ -312,6 +329,7 @@ void handle_post(void)
p += 4; // Skip \r\n\r\n sequence at end of preamble of part
uptr = FIRMWARE_UPLOAD_START;
crc_value = 0;
bindex = 0;
write_len = 0;
stream_upload(p - uip_appdata);
+75 -39
View File
@@ -16,6 +16,10 @@
#include "uip/uip.h"
#include "uip/uip_arp.h"
extern __xdata uint16_t crc_value;
__xdata uint8_t crc_testbytes[10];
void crc16(__xdata uint8_t *v) __naked;
// Upload Firmware to 1M
#define FIRMWARE_UPLOAD_START 0x100000
@@ -1046,6 +1050,7 @@ void sleep(uint16_t t)
void reset_chip(void)
{
REG_SET(RTL837X_REG_RESET, 1);
while(1);
}
@@ -1705,45 +1710,6 @@ void bootloader(void)
print_string(" Flash controller\n");
flash_init(0);
// Check update in progress and move blocks
flash_region.addr = FIRMWARE_UPLOAD_START;
flash_region.len = 0x100;
flash_read_bulk(flash_buf);
if (flash_buf[0] == 0x00 && flash_buf[1] == 0x40) {
print_string("Update in progress, moving firmware to start of FLASH!\n");
__xdata uint32_t dest = 0x0;
__xdata uint32_t source = FIRMWARE_UPLOAD_START;
// A 512kByte = 4MBit Flash has 128*8=1024 512k blocks, we copy only 120
for (__xdata uint16_t i=0; i < 960; i++) {
print_string("Writing block: ");
print_short(dest);
flash_region.addr = source;
flash_region.len = 0x200;
flash_read_bulk(flash_buf);
write_char('\n');
if (!(i & 0x7)) {
flash_region.addr = dest;
flash_sector_erase();
}
flash_region.addr = dest;
flash_region.len = 0x200;
flash_write_bytes(flash_buf);
dest += 0x200;
source += 0x200;
}
print_string("Deleting uploaded flash image\n");
dest = FIRMWARE_UPLOAD_START;
for (register uint8_t i=0; i < 120; i++) {
flash_region.addr = dest;
flash_sector_erase();
dest += 0x1000;
}
print_string("Resetting now");
reset_chip();
}
// Reset NIC
reg_bit_set(0x24, 2);
do {
@@ -1762,6 +1728,76 @@ void bootloader(void)
rtl8372_init();
delay(1000);
// Check update in progress and move blocks
flash_region.addr = FIRMWARE_UPLOAD_START;
flash_region.len = 0x100;
flash_read_bulk(flash_buf);
if (flash_buf[0] == 0x00 && flash_buf[1] == 0x40) {
__xdata uint32_t dest = 0x0;
__xdata uint32_t source = FIRMWARE_UPLOAD_START;
__xdata uint16_t i = 0;
__xdata uint16_t j = 0;
__xdata uint8_t * __xdata bptr;
print_string("Identified update image. Checking integrity...\n");
crc_value = 0x0000;
for (i = 0; i < 1024; i++) {
flash_region.addr = source;
flash_region.len = 0x200;
flash_read_bulk(flash_buf);
bptr = flash_buf;
for (j = 0; j < 0x200; j++) {
print_byte(*bptr); write_char(' ');
crc16(bptr++);
print_short(crc_value); write_char(':');
}
source += 0x200;
write_char('\n'); print_short(crc_value); write_char(' ');
}
if (crc_value == 0xb001) {
print_string("Checksum OK\n");
print_string("Update in progress, moving firmware to start of FLASH!\n");
source = FIRMWARE_UPLOAD_START;
// A 512kByte = 4MBit Flash has 128*8=1024 512k blocks, we copy only 120
for (i = 0; i < 960; i++) {
print_string("Writing block: ");
print_short(dest);
flash_region.addr = source;
flash_region.len = 0x200;
flash_read_bulk(flash_buf);
write_char('\n');
if (!(i & 0x7)) {
flash_region.addr = dest;
flash_sector_erase();
}
flash_region.addr = dest;
flash_region.len = 0x200;
flash_write_bytes(flash_buf);
dest += 0x200;
source += 0x200;
}
print_string("Deleting uploaded flash image\n");
dest = FIRMWARE_UPLOAD_START;
for (register uint8_t i=0; i < 128; i++) {
flash_region.addr = dest;
flash_sector_erase();
dest += 0x1000;
}
print_string("Resetting now");
delay(200);
reset_chip();
}
print_string("Checksum incorrect, please upload the image again\n");
print_string("Erasing bad uploaded flash image\n");
dest = FIRMWARE_UPLOAD_START;
for (register uint8_t i=0; i < 128; i++) {
flash_region.addr = dest;
flash_sector_erase();
dest += 0x1000;
}
}
#ifdef DEBUG
// This register seems to work on the RTL8373 only if also the SDS
// Is correctly configured. Therefore, we can test it, here...
+4 -1
View File
@@ -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
+179
View File
@@ -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 <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <argp.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
// 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;
}