hmcfgusb: add possibility to use a specific HM-CFG-USB with -S
[hmcfgusb] / firmware.c
1 /* generic firmware-functions for HomeMatic
2 *
3 * Copyright (c) 2014 Michael Gernoth <michael@gernoth.net>
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to
7 * deal in the Software without restriction, including without limitation the
8 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 * sell copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <stdint.h>
28 #include <string.h>
29 #include <strings.h>
30 #include <errno.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34 #include <sys/time.h>
35
36 #include "util.h"
37 #include "firmware.h"
38
39 /* This might be wrong, but it works for current fw */
40 #define MAX_BLOCK_LENGTH 512
41
42 struct firmware* firmware_read_firmware(char *filename, int debug)
43 {
44 struct firmware *fw;
45 struct stat stat_buf;
46 uint8_t buf[4096];
47 uint16_t len;
48 int fd;
49 int r;
50 int i;
51
52 fw = malloc(sizeof(struct firmware));
53 if (!fw) {
54 perror("malloc(fw)");
55 return NULL;
56 }
57
58 memset(fw, 0, sizeof(struct firmware));
59
60 if (stat(filename, &stat_buf) == -1) {
61 fprintf(stderr, "Can't stat %s: %s\n", filename, strerror(errno));
62 exit(EXIT_FAILURE);
63 }
64
65 fd = open(filename, O_RDONLY);
66 if (fd < 0) {
67 fprintf(stderr, "Can't open %s: %s", filename, strerror(errno));
68 exit(EXIT_FAILURE);
69 }
70
71 printf("Reading firmware from %s...\n", filename);
72 do {
73 memset(buf, 0, sizeof(buf));
74 r = read(fd, buf, 4);
75 if (r < 0) {
76 perror("read");
77 exit(EXIT_FAILURE);
78 } else if (r == 0) {
79 break;
80 } else if (r != 4) {
81 printf("can't get length information!\n");
82 exit(EXIT_FAILURE);
83 }
84
85 for (i = 0; i < r; i++) {
86 if (!validate_nibble(buf[i])) {
87 fprintf(stderr, "Firmware file not valid!\n");
88 exit(EXIT_FAILURE);
89 }
90 }
91
92 len = (ascii_to_nibble(buf[0]) & 0xf)<< 4;
93 len |= ascii_to_nibble(buf[1]) & 0xf;
94 len <<= 8;
95 len |= (ascii_to_nibble(buf[2]) & 0xf)<< 4;
96 len |= ascii_to_nibble(buf[3]) & 0xf;
97
98 if (len > MAX_BLOCK_LENGTH) {
99 fprintf(stderr, "Invalid block-length %u > %u for block %d!\n", len, MAX_BLOCK_LENGTH, fw->fw_blocks+1);
100 exit(EXIT_FAILURE);
101 }
102
103 fw->fw = realloc(fw->fw, sizeof(uint8_t*) * (fw->fw_blocks + 1));
104 if (fw->fw == NULL) {
105 perror("Can't reallocate fw->fw-blocklist");
106 exit(EXIT_FAILURE);
107 }
108
109 fw->fw[fw->fw_blocks] = malloc(len + 4);
110 if (fw->fw[fw->fw_blocks] == NULL) {
111 perror("Can't allocate memory for fw->fw-block");
112 exit(EXIT_FAILURE);
113 }
114
115 fw->fw[fw->fw_blocks][0] = (fw->fw_blocks >> 8) & 0xff;
116 fw->fw[fw->fw_blocks][1] = fw->fw_blocks & 0xff;
117 fw->fw[fw->fw_blocks][2] = (len >> 8) & 0xff;
118 fw->fw[fw->fw_blocks][3] = len & 0xff;
119
120 r = read(fd, buf, len * 2);
121 if (r < 0) {
122 perror("read");
123 exit(EXIT_FAILURE);
124 } else if (r < len * 2) {
125 fprintf(stderr, "short read, aborting (%d < %d)\n", r, len * 2);
126 exit(EXIT_FAILURE);
127 }
128
129 for (i = 0; i < r; i+=2) {
130 if ((!validate_nibble(buf[i])) ||
131 (!validate_nibble(buf[i+1]))) {
132 fprintf(stderr, "Firmware file not valid!\n");
133 exit(EXIT_FAILURE);
134 }
135
136 fw->fw[fw->fw_blocks][(i/2) + 4] = (ascii_to_nibble(buf[i]) & 0xf)<< 4;
137 fw->fw[fw->fw_blocks][(i/2) + 4] |= ascii_to_nibble(buf[i+1]) & 0xf;
138 }
139
140 fw->fw_blocks++;
141 if (debug)
142 printf("Firmware block %d with length %u read.\n", fw->fw_blocks, len);
143 } while(r > 0);
144
145 if (fw->fw_blocks == 0) {
146 fprintf(stderr, "Firmware file not valid!\n");
147 exit(EXIT_FAILURE);
148 }
149
150 printf("Firmware with %d blocks successfully read.\n", fw->fw_blocks);
151
152 return fw;
153 }
154
155 void firmware_free(struct firmware *fw)
156 {
157 int i;
158
159 for (i = 0; i < fw->fw_blocks; i++)
160 free(fw->fw[i]);
161
162 free(fw->fw);
163 free(fw);
164 }
Impressum, Datenschutz