Add a parser for Intel HEX files.
This commit is contained in:
parent
456365366c
commit
222ba81157
@ -39,6 +39,7 @@ libdivecomputer_la_SOURCES = \
|
||||
mares_puck.c \
|
||||
mares_darwin.c mares_darwin_parser.c \
|
||||
mares_iconhd.c mares_iconhd_parser.c \
|
||||
ihex.h ihex.c \
|
||||
hw_ostc.c hw_ostc_parser.c \
|
||||
hw_frog.c \
|
||||
hw_ostc3.c \
|
||||
|
||||
206
src/ihex.c
Normal file
206
src/ihex.c
Normal file
@ -0,0 +1,206 @@
|
||||
/*
|
||||
* libdivecomputer
|
||||
*
|
||||
* Copyright (C) 2013 Jef Driesen
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ihex.h"
|
||||
#include "context-private.h"
|
||||
#include "checksum.h"
|
||||
#include "array.h"
|
||||
|
||||
struct dc_ihex_file_t {
|
||||
dc_context_t *context;
|
||||
FILE *fp;
|
||||
};
|
||||
|
||||
dc_status_t
|
||||
dc_ihex_file_open (dc_ihex_file_t **result, dc_context_t *context, const char *filename)
|
||||
{
|
||||
dc_ihex_file_t *file = NULL;
|
||||
|
||||
if (result == NULL || filename == NULL) {
|
||||
ERROR (context, "Invalid arguments.");
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
}
|
||||
|
||||
file = malloc (sizeof (dc_ihex_file_t));
|
||||
if (file == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
file->context = context;
|
||||
|
||||
file->fp = fopen (filename, "rb");
|
||||
if (file->fp == NULL) {
|
||||
ERROR (context, "Failed to open the file.");
|
||||
free (file);
|
||||
return DC_STATUS_IO;
|
||||
}
|
||||
|
||||
*result = file;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
dc_ihex_file_read (dc_ihex_file_t *file, dc_ihex_entry_t *entry)
|
||||
{
|
||||
unsigned char ascii[9 + 2 * 255 + 2] = {0};
|
||||
unsigned char data[4 + 255 + 1] = {0};
|
||||
unsigned int type, length, address;
|
||||
unsigned char csum_a, csum_b;
|
||||
size_t n;
|
||||
|
||||
if (file == NULL || entry == NULL) {
|
||||
ERROR (file ? file->context : NULL, "Invalid arguments.");
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
}
|
||||
|
||||
/* Read the start code. */
|
||||
while (1) {
|
||||
n = fread (ascii, 1, 1, file->fp);
|
||||
if (n != 1) {
|
||||
if (feof (file->fp)) {
|
||||
return DC_STATUS_DONE;
|
||||
} else {
|
||||
ERROR (file->context, "Failed to read the start code.");
|
||||
return DC_STATUS_IO;
|
||||
}
|
||||
}
|
||||
|
||||
if (ascii[0] == ':')
|
||||
break;
|
||||
|
||||
/* Ignore CR and LF characters. */
|
||||
if (ascii[0] != '\n' && ascii[0] != '\r') {
|
||||
ERROR (file->context, "Unexpected character (0x%02).", ascii[0]);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read the record length, address and type. */
|
||||
n = fread (ascii + 1, 1, 8, file->fp);
|
||||
if (n != 8) {
|
||||
ERROR (file->context, "Failed to read the header.");
|
||||
return DC_STATUS_IO;
|
||||
}
|
||||
|
||||
/* Convert to binary representation. */
|
||||
if (array_convert_hex2bin (ascii + 1, 8, data, 4) != 0) {
|
||||
ERROR (file->context, "Invalid hexadecimal character.");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
/* Get the record length. */
|
||||
length = data[0];
|
||||
|
||||
/* Read the record payload. */
|
||||
n = fread (ascii + 9, 1, 2 * length + 2, file->fp);
|
||||
if (n != 2 * length + 2) {
|
||||
ERROR (file->context, "Failed to read the data.");
|
||||
return DC_STATUS_IO;
|
||||
}
|
||||
|
||||
/* Convert to binary representation. */
|
||||
if (array_convert_hex2bin (ascii + 9, 2 * length + 2, data + 4, length + 1) != 0) {
|
||||
ERROR (file->context, "Invalid hexadecimal character.");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
/* Verify the checksum. */
|
||||
csum_a = data[4 + length];
|
||||
csum_b = ~checksum_add_uint8 (data, 4 + length, 0x00) + 1;
|
||||
if (csum_a != csum_b) {
|
||||
ERROR (file->context, "Unexpected checksum (0x%02x, 0x%02x).", csum_a, csum_b);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
/* Get the record address. */
|
||||
address = array_uint16_be (data + 1);
|
||||
|
||||
/* Get the record type. */
|
||||
type = data[3];
|
||||
if (type < 0 || type > 5) {
|
||||
ERROR (file->context, "Invalid record type (0x%02x).", type);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
/* Verify the length and address. */
|
||||
if (type != 0) {
|
||||
unsigned int len = 0;
|
||||
switch (type) {
|
||||
case 1: /* End of file record. */
|
||||
len = 0;
|
||||
break;
|
||||
case 2: /* Extended segment address record. */
|
||||
case 4: /* Extended linear address record. */
|
||||
len = 2;
|
||||
break;
|
||||
case 3: /* Start segment address record. */
|
||||
case 5: /* Start linear address record. */
|
||||
len = 4;
|
||||
break;
|
||||
}
|
||||
if (length != len || address != 0) {
|
||||
ERROR (file->context, "Invalid record length or address.");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the record fields. */
|
||||
entry->type = type;
|
||||
entry->address = address;
|
||||
entry->length = length;
|
||||
|
||||
/* Copy the record data. */
|
||||
memcpy (entry->data, data + 4, entry->length);
|
||||
memset (entry->data + entry->length, 0, sizeof (entry->data) - entry->length);
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
dc_ihex_file_reset (dc_ihex_file_t *file)
|
||||
{
|
||||
if (file == NULL) {
|
||||
ERROR (NULL, "Invalid arguments.");
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
}
|
||||
|
||||
rewind (file->fp);
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
dc_ihex_file_close (dc_ihex_file_t *file)
|
||||
{
|
||||
if (file) {
|
||||
fclose (file->fp);
|
||||
free (file);
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
56
src/ihex.h
Normal file
56
src/ihex.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* libdivecomputer
|
||||
*
|
||||
* Copyright (C) 2013 Jef Driesen
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef DC_IHEX_H
|
||||
#define DC_IHEX_H
|
||||
|
||||
#include <libdivecomputer/common.h>
|
||||
#include <libdivecomputer/context.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct dc_ihex_file_t dc_ihex_file_t;
|
||||
|
||||
typedef struct dc_ihex_entry_t {
|
||||
unsigned int type;
|
||||
unsigned int address;
|
||||
unsigned int length;
|
||||
unsigned char data[255];
|
||||
} dc_ihex_entry_t;
|
||||
|
||||
dc_status_t
|
||||
dc_ihex_file_open (dc_ihex_file_t **file, dc_context_t *context, const char *filename);
|
||||
|
||||
dc_status_t
|
||||
dc_ihex_file_read (dc_ihex_file_t *file, dc_ihex_entry_t *entry);
|
||||
|
||||
dc_status_t
|
||||
dc_ihex_file_reset (dc_ihex_file_t *file);
|
||||
|
||||
dc_status_t
|
||||
dc_ihex_file_close (dc_ihex_file_t *file);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* DC_IHEX_H */
|
||||
Loading…
x
Reference in New Issue
Block a user