From 6c5c2df75ff018417dd6abb38196d998d5fa5b10 Mon Sep 17 00:00:00 2001 From: Michael Gernoth Date: Sat, 15 Feb 2014 11:26:41 +0100 Subject: [PATCH] split out firmware-reading into own module --- .gitignore | 2 + Makefile | 2 +- firmware.c | 189 +++++++++++++++++++++++++++++++++++++++++++++++ firmware.h | 30 ++++++++ flash-hmcfgusb.c | 149 ++++--------------------------------- 5 files changed, 235 insertions(+), 137 deletions(-) create mode 100644 firmware.c create mode 100644 firmware.h diff --git a/.gitignore b/.gitignore index d96fed7..7f65d5a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ flash-hmcfgusb flash-hmcfgusb.d flash-hmcfgusb.o +firmware.d +firmware.o hmcfgusb.d hmcfgusb.o hmland diff --git a/Makefile b/Makefile index b1c1556..e4e705d 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ CC=gcc HMLAN_OBJS=hmcfgusb.o hmland.o HMSNIFF_OBJS=hmcfgusb.o hmsniff.o -FLASH_HMCFGUSB_OBJS=hmcfgusb.o flash-hmcfgusb.o +FLASH_HMCFGUSB_OBJS=hmcfgusb.o firmware.o flash-hmcfgusb.o OBJS=$(HMLAN_OBJS) $(HMSNIFF_OBJS) $(FLASH_HMCFGUSB_OBJS) diff --git a/firmware.c b/firmware.c new file mode 100644 index 0000000..bd13dbe --- /dev/null +++ b/firmware.c @@ -0,0 +1,189 @@ +/* generic firmware-functions for HomeMatic + * + * Copyright (c) 2014 Michael Gernoth + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "firmware.h" + +/* This might be wrong, but it works for current fw */ +#define MAX_BLOCK_LENGTH 512 + +static uint8_t ascii_to_nibble(uint8_t a) +{ + uint8_t c = 0x00; + + if ((a >= '0') && (a <= '9')) { + c = a - '0'; + } else if ((a >= 'A') && (a <= 'F')) { + c = (a - 'A') + 10; + } else if ((a >= 'a') && (a <= 'f')) { + c = (a - 'a') + 10; + } + + return c; +} + +static int validate_nibble(uint8_t a) +{ + if (((a >= '0') && (a <= '9')) || + ((a >= 'A') && (a <= 'F')) || + ((a >= 'a') && (a <= 'f'))) + return 1; + + return 0; +} + +struct firmware* firmware_read_firmware(char *filename, int debug) +{ + struct firmware *fw; + struct stat stat_buf; + uint8_t buf[4096]; + uint16_t len; + int fd; + int r; + int i; + + fw = malloc(sizeof(struct firmware)); + if (!fw) { + perror("malloc(fw)"); + return NULL; + } + + memset(fw, 0, sizeof(struct firmware)); + + if (stat(filename, &stat_buf) == -1) { + fprintf(stderr, "Can't stat %s: %s\n", filename, strerror(errno)); + exit(EXIT_FAILURE); + } + + fd = open(filename, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "Can't open %s: %s", filename, strerror(errno)); + exit(EXIT_FAILURE); + } + + printf("Reading firmware from %s...\n", filename); + do { + memset(buf, 0, sizeof(buf)); + r = read(fd, buf, 4); + if (r < 0) { + perror("read"); + exit(EXIT_FAILURE); + } else if (r == 0) { + break; + } else if (r != 4) { + printf("can't get length information!\n"); + exit(EXIT_FAILURE); + } + + for (i = 0; i < r; i++) { + if (!validate_nibble(buf[i])) { + fprintf(stderr, "Firmware file not valid!\n"); + exit(EXIT_FAILURE); + } + } + + len = (ascii_to_nibble(buf[0]) & 0xf)<< 4; + len |= ascii_to_nibble(buf[1]) & 0xf; + len <<= 8; + len |= (ascii_to_nibble(buf[2]) & 0xf)<< 4; + len |= ascii_to_nibble(buf[3]) & 0xf; + + /* This might be wrong, but it works for current fw->fw */ + if (len > MAX_BLOCK_LENGTH) { + fprintf(stderr, "Invalid block-length %u > %u for block %d!\n", len, MAX_BLOCK_LENGTH, fw->fw_blocks+1); + exit(EXIT_FAILURE); + } + + fw->fw = realloc(fw->fw, sizeof(uint8_t*) * (fw->fw_blocks + 1)); + if (fw->fw == NULL) { + perror("Can't reallocate fw->fw-blocklist"); + exit(EXIT_FAILURE); + } + + fw->fw[fw->fw_blocks] = malloc(len + 4); + if (fw->fw[fw->fw_blocks] == NULL) { + perror("Can't allocate memory for fw->fw-block"); + exit(EXIT_FAILURE); + } + + fw->fw[fw->fw_blocks][0] = (fw->fw_blocks >> 8) & 0xff; + fw->fw[fw->fw_blocks][1] = fw->fw_blocks & 0xff; + fw->fw[fw->fw_blocks][2] = (len >> 8) & 0xff; + fw->fw[fw->fw_blocks][3] = len & 0xff; + + r = read(fd, buf, len * 2); + if (r < 0) { + perror("read"); + exit(EXIT_FAILURE); + } else if (r < len * 2) { + fprintf(stderr, "short read, aborting (%d < %d)\n", r, len * 2); + exit(EXIT_FAILURE); + } + + for (i = 0; i < r; i+=2) { + if ((!validate_nibble(buf[i])) || + (!validate_nibble(buf[i+1]))) { + fprintf(stderr, "Firmware file not valid!\n"); + exit(EXIT_FAILURE); + } + + fw->fw[fw->fw_blocks][(i/2) + 4] = (ascii_to_nibble(buf[i]) & 0xf)<< 4; + fw->fw[fw->fw_blocks][(i/2) + 4] |= ascii_to_nibble(buf[i+1]) & 0xf; + } + + fw->fw_blocks++; + if (debug) + printf("Firmware block %d with length %u read.\n", fw->fw_blocks, len); + } while(r > 0); + + if (fw->fw_blocks == 0) { + fprintf(stderr, "Firmware file not valid!\n"); + exit(EXIT_FAILURE); + } + + printf("Firmware with %d blocks successfully read.\n", fw->fw_blocks); + + return fw; +} + +void firmware_free(struct firmware *fw) +{ + int i; + + for (i = 0; i < fw->fw_blocks; i++) + free(fw->fw[i]); + + free(fw->fw); + free(fw); +} diff --git a/firmware.h b/firmware.h new file mode 100644 index 0000000..3952a29 --- /dev/null +++ b/firmware.h @@ -0,0 +1,30 @@ +/* generic firmware-functions for HomeMatic + * + * Copyright (c) 2014 Michael Gernoth + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +struct firmware { + uint8_t **fw; + int fw_blocks; +}; + +struct firmware* firmware_read_firmware(char *filename, int debug); +void firmware_free(struct firmware *fw); diff --git a/flash-hmcfgusb.c b/flash-hmcfgusb.c index b1f554c..571386f 100644 --- a/flash-hmcfgusb.c +++ b/flash-hmcfgusb.c @@ -1,6 +1,6 @@ /* flasher for HM-CFG-USB * - * Copyright (c) 2013 Michael Gernoth + * Copyright (c) 2013-14 Michael Gernoth * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to @@ -36,12 +36,10 @@ #include #include "hexdump.h" +#include "firmware.h" #include "version.h" #include "hmcfgusb.h" -/* This might be wrong, but it works for current fw */ -#define MAX_BLOCK_LENGTH 512 - struct recv_data { int ack; }; @@ -58,46 +56,15 @@ static int parse_hmcfgusb(uint8_t *buf, int buf_len, void *data) return 1; } -static uint8_t ascii_to_nibble(uint8_t a) -{ - uint8_t c = 0x00; - - if ((a >= '0') && (a <= '9')) { - c = a - '0'; - } else if ((a >= 'A') && (a <= 'F')) { - c = (a - 'A') + 10; - } else if ((a >= 'a') && (a <= 'f')) { - c = (a - 'a') + 10; - } - - return c; -} - -static int validate_nibble(uint8_t a) -{ - if (((a >= '0') && (a <= '9')) || - ((a >= 'A') && (a <= 'F')) || - ((a >= 'a') && (a <= 'f'))) - return 1; - - return 0; -} - int main(int argc, char **argv) { const char twiddlie[] = { '-', '\\', '|', '/' }; struct hmcfgusb_dev *dev; struct recv_data rdata; - struct stat stat_buf; - uint8_t buf[4096]; uint16_t len; - uint8_t **fw = NULL; - int fw_blocks = 0; + struct firmware *fw; int block; - int fd; int pfd; - int r; - int i; int debug = 0; printf("HM-CFG-USB flasher version " VERSION "\n\n"); @@ -110,98 +77,9 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } - if (stat(argv[1], &stat_buf) == -1) { - fprintf(stderr, "Can't stat %s: %s\n", argv[1], strerror(errno)); - exit(EXIT_FAILURE); - } - - fd = open(argv[1], O_RDONLY); - if (fd < 0) { - fprintf(stderr, "Can't open %s: %s", argv[1], strerror(errno)); + fw = firmware_read_firmware(argv[1], debug); + if (!fw) exit(EXIT_FAILURE); - } - - printf("Reading firmware from %s...\n", argv[1]); - do { - memset(buf, 0, sizeof(buf)); - r = read(fd, buf, 4); - if (r < 0) { - perror("read"); - exit(EXIT_FAILURE); - } else if (r == 0) { - break; - } else if (r != 4) { - printf("can't get length information!\n"); - exit(EXIT_FAILURE); - } - - for (i = 0; i < r; i++) { - if (!validate_nibble(buf[i])) { - fprintf(stderr, "Firmware file not valid!\n"); - exit(EXIT_FAILURE); - } - } - - len = (ascii_to_nibble(buf[0]) & 0xf)<< 4; - len |= ascii_to_nibble(buf[1]) & 0xf; - len <<= 8; - len |= (ascii_to_nibble(buf[2]) & 0xf)<< 4; - len |= ascii_to_nibble(buf[3]) & 0xf; - - /* This might be wrong, but it works for current fw */ - if (len > MAX_BLOCK_LENGTH) { - fprintf(stderr, "Invalid block-length %u > %u for block %d!\n", len, MAX_BLOCK_LENGTH, fw_blocks+1); - exit(EXIT_FAILURE); - } - - fw = realloc(fw, sizeof(uint8_t*) * (fw_blocks + 1)); - if (fw == NULL) { - perror("Can't reallocate fw-blocklist"); - exit(EXIT_FAILURE); - } - - fw[fw_blocks] = malloc(len + 4); - if (fw[fw_blocks] == NULL) { - perror("Can't allocate memory for fw-block"); - exit(EXIT_FAILURE); - } - - fw[fw_blocks][0] = (fw_blocks >> 8) & 0xff; - fw[fw_blocks][1] = fw_blocks & 0xff; - fw[fw_blocks][2] = (len >> 8) & 0xff; - fw[fw_blocks][3] = len & 0xff; - - r = read(fd, buf, len * 2); - if (r < 0) { - perror("read"); - exit(EXIT_FAILURE); - } else if (r < len * 2) { - fprintf(stderr, "short read, aborting (%d < %d)\n", r, len * 2); - exit(EXIT_FAILURE); - } - - for (i = 0; i < r; i+=2) { - if ((!validate_nibble(buf[i])) || - (!validate_nibble(buf[i+1]))) { - fprintf(stderr, "Firmware file not valid!\n"); - exit(EXIT_FAILURE); - } - - fw[fw_blocks][(i/2) + 4] = (ascii_to_nibble(buf[i]) & 0xf)<< 4; - fw[fw_blocks][(i/2) + 4] |= ascii_to_nibble(buf[i+1]) & 0xf; - } - - fw_blocks++; - if (debug) - printf("Firmware block %d with length %u read.\n", fw_blocks, len); - } while(r > 0); - - if (fw_blocks == 0) { - fprintf(stderr, "Firmware file not valid!\n"); - exit(EXIT_FAILURE); - } - - printf("Firmware with %d blocks successfully read.\n", fw_blocks); hmcfgusb_set_debug(debug); @@ -219,7 +97,7 @@ int main(int argc, char **argv) fprintf(stderr, "\nWaiting for device to reappear...\n"); do { - sleep(1); + sleep(2); } while ((dev = hmcfgusb_init(parse_hmcfgusb, &rdata)) == NULL); if (!dev->bootloader) { @@ -231,7 +109,7 @@ int main(int argc, char **argv) printf("\nHM-CFG-USB opened.\n\n"); - printf("Flashing %d blocks", fw_blocks); + printf("Flashing %d blocks", fw->fw_blocks); if (debug) { printf("\n"); } else { @@ -239,17 +117,17 @@ int main(int argc, char **argv) fflush(stdout); } - for (block = 0; block < fw_blocks; block++) { - len = fw[block][2] << 8; - len |= fw[block][3]; + for (block = 0; block < fw->fw_blocks; block++) { + len = fw->fw[block][2] << 8; + len |= fw->fw[block][3]; len += 4; /* block nr., length */ if (debug) - hexdump(fw[block], len, "F> "); + hexdump(fw->fw[block], len, "F> "); rdata.ack = 0; - if (!hmcfgusb_send(dev, fw[block], len, 0)) { + if (!hmcfgusb_send(dev, fw->fw[block], len, 0)) { perror("\n\nhmcfgusb_send"); exit(EXIT_FAILURE); } @@ -282,10 +160,9 @@ int main(int argc, char **argv) printf("\b%c", twiddlie[block % sizeof(twiddlie)]); fflush(stdout); } - free(fw[block]); } - free(fw); + firmware_free(fw); hmcfgusb_close(dev); -- 2.39.2