-
Notifications
You must be signed in to change notification settings - Fork 92
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add dfu-convert.c + Makefile ANSI C multi-platform Fix #132
- Loading branch information
Showing
5 changed files
with
288 additions
and
159 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# Compiler | ||
CC = gcc | ||
# Compiler flags | ||
CFLAGS = -Wall -Wextra -std=c99 | ||
|
||
# Source files | ||
SRCS = dfu-convert.c | ||
|
||
# Output executable | ||
TARGET = dfu-convert | ||
|
||
# Default target | ||
all: $(TARGET) | ||
|
||
# Build the target | ||
$(TARGET): $(SRCS) | ||
$(CC) $(CFLAGS) -o $(TARGET) $(SRCS) | ||
|
||
# Clean up | ||
clean: | ||
rm -f $(TARGET) | ||
|
||
# Phony targets | ||
.PHONY: all clean |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,263 @@ | ||
/* gcc -Wall -O3 -o dfu-convert dfu-convert.c see also Makefile | ||
* Python3 version Written by Antonio Galea - 2010/11/18 Distributed under Gnu LGPL 3.0 | ||
* | ||
* Copyright (C) 2024 Benjamin VERNOUX (C version) | ||
* Distributed under Gnu LGPL 3.0 | ||
*/ | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <stdint.h> | ||
#include <string.h> | ||
#include <errno.h> | ||
#include <unistd.h> | ||
|
||
#define DEFAULT_DEVICE "0x0483:0xdf11" | ||
#define DEFAULT_REVISION "0.0" | ||
#define MAX_DATA_SIZE 1048576 // 1 MB buffer for static allocation | ||
#define MAX_LINE_LENGTH 256 | ||
#define MAX_FILES 10 | ||
|
||
static uint8_t data[MAX_DATA_SIZE]; | ||
|
||
typedef struct { | ||
char signature[5]; | ||
uint8_t version; | ||
uint32_t size; | ||
uint8_t targets; | ||
} Prefix; | ||
|
||
typedef struct { | ||
uint32_t address; | ||
uint32_t size; | ||
} ElementPrefix; | ||
|
||
typedef struct { | ||
uint16_t device; | ||
uint16_t product; | ||
uint16_t vendor; | ||
uint16_t dfu; | ||
char ufd[3]; | ||
uint8_t len; | ||
uint32_t crc; | ||
} Suffix; | ||
|
||
static uint32_t crc_table[256] = { | ||
0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL, 0x076DC419L, 0x706AF48FL, | ||
0xE963A535L, 0x9E6495A3L, 0x0EDB8832L, 0x79DCB8A4L, 0xE0D5E91EL, 0x97D2D988L, | ||
0x09B64C2BL, 0x7EB17CBDL, 0xE7B82D07L, 0x90BF1D91L, 0x1DB71064L, 0x6AB020F2L, | ||
0xF3B97148L, 0x84BE41DEL, 0x1ADAD47DL, 0x6DDDE4EBL, 0xF4D4B551L, 0x83D385C7L, | ||
0x136C9856L, 0x646BA8C0L, 0xFD62F97AL, 0x8A65C9ECL, 0x14015C4FL, 0x63066CD9L, | ||
0xFA0F3D63L, 0x8D080DF5L, 0x3B6E20C8L, 0x4C69105EL, 0xD56041E4L, 0xA2677172L, | ||
0x3C03E4D1L, 0x4B04D447L, 0xD20D85FDL, 0xA50AB56BL, 0x35B5A8FAL, 0x42B2986CL, | ||
0xDBBBC9D6L, 0xACBCF940L, 0x32D86CE3L, 0x45DF5C75L, 0xDCD60DCFL, 0xABD13D59L, | ||
0x26D930ACL, 0x51DE003AL, 0xC8D75180L, 0xBFD06116L, 0x21B4F4B5L, 0x56B3C423L, | ||
0xCFBA9599L, 0xB8BDA50FL, 0x2802B89EL, 0x5F058808L, 0xC60CD9B2L, 0xB10BE924L, | ||
0x2F6F7C87L, 0x58684C11L, 0xC1611DABL, 0xB6662D3DL, 0x76DC4190L, 0x01DB7106L, | ||
0x98D220BCL, 0xEFD5102AL, 0x71B18589L, 0x06B6B51FL, 0x9FBFE4A5L, 0xE8B8D433L, | ||
0x7807C9A2L, 0x0F00F934L, 0x9609A88EL, 0xE10E9818L, 0x7F6A0DBBL, 0x086D3D2DL, | ||
0x91646C97L, 0xE6635C01L, 0x6B6B51F4L, 0x1C6C6162L, 0x856530D8L, 0xF262004EL, | ||
0x6C0695EDL, 0x1B01A57BL, 0x8208F4C1L, 0xF50FC457L, 0x65B0D9C6L, 0x12B7E950L, | ||
0x8BBEB8EAL, 0xFCB9887CL, 0x62DD1DDFL, 0x15DA2D49L, 0x8CD37CF3L, 0xFBD44C65L, | ||
0x4DB26158L, 0x3AB551CEL, 0xA3BC0074L, 0xD4BB30E2L, 0x4ADFA541L, 0x3DD895D7L, | ||
0xA4D1C46DL, 0xD3D6F4FBL, 0x4369E96AL, 0x346ED9FCL, 0xAD678846L, 0xDA60B8D0L, | ||
0x44042D73L, 0x33031DE5L, 0xAA0A4C5FL, 0xDD0D7CC9L, 0x5005713CL, 0x270241AAL, | ||
0xBE0B1010L, 0xC90C2086L, 0x5768B525L, 0x206F85B3L, 0xB966D409L, 0xCE61E49FL, | ||
0x5EDEF90EL, 0x29D9C998L, 0xB0D09822L, 0xC7D7A8B4L, 0x59B33D17L, 0x2EB40D81L, | ||
0xB7BD5C3BL, 0xC0BA6CADL, 0xEDB88320L, 0x9ABFB3B6L, 0x03B6E20CL, 0x74B1D29AL, | ||
0xEAD54739L, 0x9DD277AFL, 0x04DB2615L, 0x73DC1683L, 0xE3630B12L, 0x94643B84L, | ||
0x0D6D6A3EL, 0x7A6A5AA8L, 0xE40ECF0BL, 0x9309FF9DL, 0x0A00AE27L, 0x7D079EB1L, | ||
0xF00F9344L, 0x8708A3D2L, 0x1E01F268L, 0x6906C2FEL, 0xF762575DL, 0x806567CBL, | ||
0x196C3671L, 0x6E6B06E7L, 0xFED41B76L, 0x89D32BE0L, 0x10DA7A5AL, 0x67DD4ACCL, | ||
0xF9B9DF6FL, 0x8EBEEFF9L, 0x17B7BE43L, 0x60B08ED5L, 0xD6D6A3E8L, 0xA1D1937EL, | ||
0x38D8C2C4L, 0x4FDFF252L, 0xD1BB67F1L, 0xA6BC5767L, 0x3FB506DDL, 0x48B2364BL, | ||
0xD80D2BDAL, 0xAF0A1B4CL, 0x36034AF6L, 0x41047A60L, 0xDF60EFC3L, 0xA867DF55L, | ||
0x316E8EEFL, 0x4669BE79L, 0xCB61B38CL, 0xBC66831AL, 0x256FD2A0L, 0x5268E236L, | ||
0xCC0C7795L, 0xBB0B4703L, 0x220216B9L, 0x5505262FL, 0xC5BA3BBEL, 0xB2BD0B28L, | ||
0x2BB45A92L, 0x5CB36A04L, 0xC2D7FFA7L, 0xB5D0CF31L, 0x2CD99E8BL, 0x5BDEAE1DL, | ||
0x9B64C2B0L, 0xEC63F226L, 0x756AA39CL, 0x026D930AL, 0x9C0906A9L, 0xEB0E363FL, | ||
0x72076785L, 0x05005713L, 0x95BF4A82L, 0xE2B87A14L, 0x7BB12BAEL, 0x0CB61B38L, | ||
0x92D28E9BL, 0xE5D5BE0DL, 0x7CDCEFB7L, 0x0BDBDF21L, 0x86D3D2D4L, 0xF1D4E242L, | ||
0x68DDB3F8L, 0x1FDA836EL, 0x81BE16CDL, 0xF6B9265BL, 0x6FB077E1L, 0x18B74777L, | ||
0x88085AE6L, 0xFF0F6A70L, 0x66063BCAL, 0x11010B5CL, 0x8F659EFFL, 0xF862AE69L, | ||
0x616BFFD3L, 0x166CCF45L, 0xA00AE278L, 0xD70DD2EEL, 0x4E048354L, 0x3903B3C2L, | ||
0xA7672661L, 0xD06016F7L, 0x4969474DL, 0x3E6E77DBL, 0xAED16A4AL, 0xD9D65ADCL, | ||
0x40DF0B66L, 0x37D83BF0L, 0xA9BCAE53L, 0xDEBB9EC5L, 0x47B2CF7FL, 0x30B5FFE9L, | ||
0xBDBDF21CL, 0xCABAC28AL, 0x53B39330L, 0x24B4A3A6L, 0xBAD03605L, 0xCDD70693L, | ||
0x54DE5729L, 0x23D967BFL, 0xB3667A2EL, 0xC4614AB8L, 0x5D681B02L, 0x2A6F2B94L, | ||
0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL, 0x2D02EF8DL | ||
}; | ||
|
||
uint32_t compute_crc(const uint8_t *buf_data, size_t length) { | ||
uint32_t crc = 0xFFFFFFFF; | ||
|
||
for (size_t i = 0; i < length; i++) { | ||
uint8_t byte = buf_data[i]; | ||
uint32_t lookup_index = (crc ^ byte) & 0xFF; | ||
crc = (crc >> 8) ^ crc_table[lookup_index]; | ||
} | ||
|
||
return ~crc; | ||
} | ||
|
||
int parse_device(const char *device, uint16_t *vendor_id, uint16_t *product_id) { | ||
if (sscanf(device, "0x%4hx:0x%4hx", vendor_id, product_id) != 2) { | ||
return -1; | ||
} | ||
return 0; | ||
} | ||
|
||
void print_help(const char *progname) { | ||
printf("Usage: %s {-i|--ihex} file.hex [-i file.hex ...] [{-D|--device} vendor:device] outfile.dfu\n", progname); | ||
printf("\n"); | ||
printf("Options:\n"); | ||
printf(" -i, --ihex Build a DFU file from given HEXFILES\n"); | ||
printf(" -D, --device Build for DEVICE, defaults to %s\n", DEFAULT_DEVICE); | ||
printf(" -r, --revision Revision number, defaults to %s\n", DEFAULT_REVISION); | ||
} | ||
|
||
// Simple function to convert hex character to integer | ||
uint8_t hex_char_to_int(char c) { | ||
if (c >= '0' && c <= '9') return c - '0'; | ||
if (c >= 'A' && c <= 'F') return c - 'A' + 10; | ||
if (c >= 'a' && c <= 'f') return c - 'a' + 10; | ||
return 0; | ||
} | ||
|
||
// Function to parse a line from Intel HEX file | ||
int parse_hex_line(const char *line, uint32_t *address, uint8_t *buf_data, size_t *data_len) { | ||
if (line[0] != ':') return -1; | ||
int len = (hex_char_to_int(line[1]) << 4) | hex_char_to_int(line[2]); | ||
*address = (hex_char_to_int(line[3]) << 12) | (hex_char_to_int(line[4]) << 8) | (hex_char_to_int(line[5]) << 4) | hex_char_to_int(line[6]); | ||
int type = (hex_char_to_int(line[7]) << 4) | hex_char_to_int(line[8]); | ||
|
||
if (type != 0) return -1; // Only support data records | ||
|
||
for (int i = 0; i < len; i++) { | ||
buf_data[i] = (hex_char_to_int(line[9 + i * 2]) << 4) | hex_char_to_int(line[10 + i * 2]); | ||
} | ||
*data_len = len; | ||
return 0; | ||
} | ||
|
||
void build_from_hex(const char *file, char **hexfiles, int hexfile_count, const char *device, const char *revision) { | ||
size_t data_size = 0; | ||
|
||
for (int i = 0; i < hexfile_count; ++i) { | ||
const char *hexfile = hexfiles[i]; | ||
FILE *f = fopen(hexfile, "r"); | ||
if (!f) { | ||
fprintf(stderr, "Error opening file: %s\n", strerror(errno)); | ||
exit(EXIT_FAILURE); | ||
} | ||
|
||
char line[MAX_LINE_LENGTH]; | ||
while (fgets(line, sizeof(line), f)) { | ||
uint32_t address; | ||
uint8_t line_data[MAX_LINE_LENGTH]; | ||
size_t line_data_len; | ||
|
||
if (parse_hex_line(line, &address, line_data, &line_data_len) == 0) { | ||
if (data_size + sizeof(ElementPrefix) + line_data_len > MAX_DATA_SIZE) { | ||
fprintf(stderr, "Data buffer overflow\n"); | ||
fclose(f); | ||
exit(EXIT_FAILURE); | ||
} | ||
ElementPrefix eprefix = {address, line_data_len}; | ||
memcpy(data + data_size, &eprefix, sizeof(ElementPrefix)); | ||
memcpy(data + data_size + sizeof(ElementPrefix), line_data, line_data_len); | ||
data_size += sizeof(ElementPrefix) + line_data_len; | ||
} | ||
} | ||
fclose(f); | ||
} | ||
|
||
uint16_t device_id, product_id; | ||
if (parse_device(device, &device_id, &product_id) != 0) { | ||
fprintf(stderr, "Invalid device format: %s\n", device); | ||
exit(EXIT_FAILURE); | ||
} | ||
|
||
uint16_t revision_number; | ||
if (sscanf(revision, "%hx.%hx", &revision_number, &revision_number) != 2) { | ||
fprintf(stderr, "Invalid revision format: %s\n", revision); | ||
exit(EXIT_FAILURE); | ||
} | ||
|
||
Suffix suffix = {device_id, product_id, 0x0483, 0x011a, {'U', 'F', 'D'}, 16, 0}; | ||
if (data_size + sizeof(Suffix) > MAX_DATA_SIZE) { | ||
fprintf(stderr, "Data buffer overflow\n"); | ||
exit(EXIT_FAILURE); | ||
} | ||
|
||
memcpy(data + data_size, &suffix, sizeof(Suffix)); | ||
data_size += sizeof(Suffix); | ||
|
||
suffix.crc = compute_crc(data, data_size); | ||
memcpy(data + data_size - sizeof(uint32_t), &suffix.crc, sizeof(uint32_t)); | ||
|
||
FILE *outfile = fopen(file, "wb"); | ||
if (!outfile) { | ||
fprintf(stderr, "Error opening output file: %s\n", strerror(errno)); | ||
exit(EXIT_FAILURE); | ||
} | ||
|
||
fwrite(data, 1, data_size, outfile); | ||
fclose(outfile); | ||
} | ||
|
||
int main(int argc, char *argv[]) { | ||
if (argc < 2) { | ||
print_help(argv[0]); | ||
return EXIT_FAILURE; | ||
} | ||
|
||
const char *infile = NULL; | ||
int ihex_mode = 0; | ||
const char *device = DEFAULT_DEVICE; | ||
const char *revision = DEFAULT_REVISION; | ||
char *hexfiles[MAX_FILES]; | ||
int hexfile_count = 0; | ||
const char *outfile = NULL; | ||
|
||
for (int i = 1; i < argc; ++i) { | ||
if (strcmp(argv[i], "-i") == 0 || strcmp(argv[i], "--ihex") == 0) { | ||
ihex_mode = 1; | ||
if (i + 1 < argc && hexfile_count < MAX_FILES) { | ||
hexfiles[hexfile_count++] = argv[++i]; | ||
} else { | ||
fprintf(stderr, "Option -i requires an argument or exceeds maximum number of files\n"); | ||
return EXIT_FAILURE; | ||
} | ||
} else if (strcmp(argv[i], "-D") == 0 || strcmp(argv[i], "--device") == 0) { | ||
if (i + 1 < argc) { | ||
device = argv[++i]; | ||
} else { | ||
fprintf(stderr, "Option -D requires an argument\n"); | ||
return EXIT_FAILURE; | ||
} | ||
} else if (strcmp(argv[i], "-r") == 0 || strcmp(argv[i], "--revision") == 0) { | ||
if (i + 1 < argc) { | ||
revision = argv[++i]; | ||
} else { | ||
fprintf(stderr, "Option -r requires an argument\n"); | ||
return EXIT_FAILURE; | ||
} | ||
} else { | ||
infile = argv[i]; | ||
} | ||
} | ||
|
||
if (infile) { | ||
if (ihex_mode) { | ||
build_from_hex(outfile, hexfiles, hexfile_count, device, revision); | ||
} else { | ||
print_help(argv[0]); | ||
return EXIT_FAILURE; | ||
} | ||
} else { | ||
print_help(argv[0]); | ||
return EXIT_FAILURE; | ||
} | ||
|
||
return EXIT_SUCCESS; | ||
} |
Binary file not shown.
Oops, something went wrong.