]>
cvs.zerfleddert.de Git - hmcfgusb/blob - firmware.c
1 /* generic firmware-functions for HomeMatic
3 * Copyright (c) 2014-20 Michael Gernoth <michael@gernoth.net>
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:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
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
31 #include <sys/types.h>
40 #define CRC16_INIT 0xFFFF
41 #define CRC16_POLY 0x1021
43 /* This might be wrong, but it works for current fw */
44 #define MAX_BLOCK_LENGTH 2048
46 #define HEX_BLOCK_LENGTH_328P 128
47 #define HEX_BLOCK_LENGTH_644P 256
48 #define HEX_IMAGE_SIZE_328P 0x7000
49 #define HEX_IMAGE_SIZE_644P 0xF000
50 #define HEX_IMAGE_SIZE_MAX 0x10000
52 static uint16_t crc16(uint8_t* buf
, int length
, uint16_t crc
)
58 for (i
= 0; i
< 8; i
++) {
75 static struct firmware
* firmware_read_ihex(int fd
, struct firmware
*fw
, int atmega
, int debug
)
77 uint8_t buf
[2*MAX_BLOCK_LENGTH
];
78 uint8_t image
[HEX_IMAGE_SIZE_MAX
];
83 uint32_t image_size
= HEX_IMAGE_SIZE_328P
;
84 uint32_t block_length
= HEX_BLOCK_LENGTH_328P
;
90 printf("Using Atmega644P values for direct hex flashing\n");
91 image_size
= HEX_IMAGE_SIZE_644P
;
92 block_length
= HEX_BLOCK_LENGTH_644P
;
95 printf("Using Atmega328P values for direct hex flashing\n");
96 image_size
= HEX_IMAGE_SIZE_328P
;
97 block_length
= HEX_BLOCK_LENGTH_328P
;
100 fprintf(stderr
, "Atmega-type (328P/644P) not specified for flashing hex files\n");
105 memset(image
, 0xff, sizeof(image
));
108 memset(buf
, 0, sizeof(buf
));
109 len
= 2 /* len */ + 4 /* len */ + 2 /* type */;
110 r
= read(fd
, buf
, len
);
115 fprintf(stderr
, "EOF without EOF record, Firmware file not valid!\n");
117 } else if (r
!= len
) {
118 printf("can't get record information!\n");
122 for (i
= 0; i
< r
; i
++) {
123 if (!validate_nibble(buf
[i
])) {
124 fprintf(stderr
, "Firmware file not valid!\n");
129 len
= (ascii_to_nibble(buf
[0]) & 0xf)<< 4;
130 len
|= ascii_to_nibble(buf
[1]) & 0xf;
132 addr
= (ascii_to_nibble(buf
[2]) & 0xf)<< 4;
133 addr
|= ascii_to_nibble(buf
[3]) & 0xf;
135 addr
|= (ascii_to_nibble(buf
[4]) & 0xf)<< 4;
136 addr
|= ascii_to_nibble(buf
[5]) & 0xf;
138 type
= (ascii_to_nibble(buf
[6]) & 0xf)<< 4;
139 type
|= ascii_to_nibble(buf
[7]) & 0xf;
142 printf("Length: %d, Address: 0x%04x, Type: 0x%02x\n", len
, addr
, type
);
144 if (len
> MAX_BLOCK_LENGTH
) {
145 fprintf(stderr
, "Invalid block-length %u > %u for block %d!\n", len
, MAX_BLOCK_LENGTH
, fw
->fw_blocks
+1);
150 r
= read(fd
, buf
, (len
* 2) + 2 /* crc */);
156 } else if (r
< ((len
* 2) + 2)) {
157 fprintf(stderr
, "short read, aborting (%d < %d)\n", r
, (len
* 2) + 2);
161 for (i
= 0; i
< len
* 2; i
+=2) {
162 if ((!validate_nibble(buf
[i
])) ||
163 (!validate_nibble(buf
[i
+1]))) {
164 fprintf(stderr
, "Firmware file not valid!\n");
168 image
[addr
+ (i
/2)] = (ascii_to_nibble(buf
[i
]) & 0xf)<< 4;
169 image
[addr
+ (i
/2)] |= ascii_to_nibble(buf
[i
+1]) & 0xf;
173 r
= read(fd
, buf
, 1);
185 } else if (type
== 0x01) {
188 fprintf(stderr
, "Can't handle iHex type 0x%02x\n", type
);
193 image
[image_size
-2] = 0x00;
194 image
[image_size
-1] = 0x00;
196 while (offset
< image_size
) {
197 fw
->fw
= realloc(fw
->fw
, sizeof(uint8_t*) * (fw
->fw_blocks
+ 1));
198 if (fw
->fw
== NULL
) {
199 perror("Can't reallocate fw->fw-blocklist");
205 fw
->fw
[fw
->fw_blocks
] = malloc(len
+ 4);
206 if (fw
->fw
[fw
->fw_blocks
] == NULL
) {
207 perror("Can't allocate memory for fw->fw-block");
211 fw
->fw
[fw
->fw_blocks
][0] = (fw
->fw_blocks
>> 8) & 0xff;
212 fw
->fw
[fw
->fw_blocks
][1] = fw
->fw_blocks
& 0xff;
213 fw
->fw
[fw
->fw_blocks
][2] = (len
>> 8) & 0xff;
214 fw
->fw
[fw
->fw_blocks
][3] = len
& 0xff;
216 memcpy(fw
->fw
[fw
->fw_blocks
] + 4, image
+ offset
, len
);
218 if ((len
+ offset
) == image_size
) {
221 crc
= crc16(image
, image_size
, CRC16_INIT
);
224 printf("CRC: %04x\n", crc
);
226 fw
->fw
[fw
->fw_blocks
][len
+3] = (crc
>> 8) & 0xff;
227 fw
->fw
[fw
->fw_blocks
][len
+2] = crc
& 0xff;
232 printf("Firmware block %d with length %u read.\n", fw
->fw_blocks
, len
);
237 if (fw
->fw_blocks
== 0) {
238 fprintf(stderr
, "Firmware file not valid!\n");
242 printf("Firmware with %d blocks successfully read.\n", fw
->fw_blocks
);
247 struct firmware
* firmware_read_firmware(char *filename
, int atmega
, int debug
)
250 struct stat stat_buf
;
251 uint8_t buf
[2*MAX_BLOCK_LENGTH
];
257 fw
= malloc(sizeof(struct firmware
));
259 perror("malloc(fw)");
263 memset(fw
, 0, sizeof(struct firmware
));
265 if (stat(filename
, &stat_buf
) == -1) {
266 fprintf(stderr
, "Can't stat %s: %s\n", filename
, strerror(errno
));
270 fd
= open(filename
, O_RDONLY
);
272 fprintf(stderr
, "Can't open %s: %s", filename
, strerror(errno
));
276 printf("Reading firmware from %s...\n", filename
);
278 memset(buf
, 0, sizeof(buf
));
279 r
= read(fd
, buf
, 1);
287 printf("HEX file detected (AsksinPP)\n");
288 return firmware_read_ihex(fd
, fw
, atmega
, debug
);
291 if (lseek(fd
, 0, SEEK_SET
) != 0) {
297 memset(buf
, 0, sizeof(buf
));
298 r
= read(fd
, buf
, 4);
305 printf("can't get length information!\n");
309 for (i
= 0; i
< r
; i
++) {
310 if (!validate_nibble(buf
[i
])) {
311 fprintf(stderr
, "Firmware file not valid!\n");
316 len
= (ascii_to_nibble(buf
[0]) & 0xf)<< 4;
317 len
|= ascii_to_nibble(buf
[1]) & 0xf;
319 len
|= (ascii_to_nibble(buf
[2]) & 0xf)<< 4;
320 len
|= ascii_to_nibble(buf
[3]) & 0xf;
322 if (len
> MAX_BLOCK_LENGTH
) {
323 fprintf(stderr
, "Invalid block-length %u > %u for block %d!\n", len
, MAX_BLOCK_LENGTH
, fw
->fw_blocks
+1);
327 fw
->fw
= realloc(fw
->fw
, sizeof(uint8_t*) * (fw
->fw_blocks
+ 1));
328 if (fw
->fw
== NULL
) {
329 perror("Can't reallocate fw->fw-blocklist");
333 fw
->fw
[fw
->fw_blocks
] = malloc(len
+ 4);
334 if (fw
->fw
[fw
->fw_blocks
] == NULL
) {
335 perror("Can't allocate memory for fw->fw-block");
339 fw
->fw
[fw
->fw_blocks
][0] = (fw
->fw_blocks
>> 8) & 0xff;
340 fw
->fw
[fw
->fw_blocks
][1] = fw
->fw_blocks
& 0xff;
341 fw
->fw
[fw
->fw_blocks
][2] = (len
>> 8) & 0xff;
342 fw
->fw
[fw
->fw_blocks
][3] = len
& 0xff;
344 r
= read(fd
, buf
, len
* 2);
348 } else if (r
< len
* 2) {
349 fprintf(stderr
, "short read, aborting (%d < %d)\n", r
, len
* 2);
353 for (i
= 0; i
< r
; i
+=2) {
354 if ((!validate_nibble(buf
[i
])) ||
355 (!validate_nibble(buf
[i
+1]))) {
356 fprintf(stderr
, "Firmware file not valid!\n");
360 fw
->fw
[fw
->fw_blocks
][(i
/2) + 4] = (ascii_to_nibble(buf
[i
]) & 0xf)<< 4;
361 fw
->fw
[fw
->fw_blocks
][(i
/2) + 4] |= ascii_to_nibble(buf
[i
+1]) & 0xf;
366 printf("Firmware block %d with length %u read.\n", fw
->fw_blocks
, len
);
369 if (fw
->fw_blocks
== 0) {
370 fprintf(stderr
, "Firmware file not valid!\n");
374 printf("Firmware with %d blocks successfully read.\n", fw
->fw_blocks
);
379 void firmware_free(struct firmware
*fw
)
383 for (i
= 0; i
< fw
->fw_blocks
; i
++)