aqhome: added lib for hexfiles and flash records.
This commit is contained in:
318
aqhome/hexfile/hexfile.c
Normal file
318
aqhome/hexfile/hexfile.c
Normal file
@@ -0,0 +1,318 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "aqhome/hexfile/hexfile_p.h"
|
||||
|
||||
#include <gwenhywfar/syncio.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
|
||||
|
||||
static const char *_readRecord(AQH_HEXFILERECORD *hr, const char *s);
|
||||
static void _writeRecord(AQH_HEXFILERECORD *hr, GWEN_BUFFER *buffer);
|
||||
static int _sumValuesForChecksum(const AQH_HEXFILERECORD *hr);
|
||||
static int _readWord(const char *s);
|
||||
static int _readByte(const char *s);
|
||||
static int _readNibble(const char *s);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
AQH_HEXFILE *AQH_Hexfile_new()
|
||||
{
|
||||
AQH_HEXFILE *h;
|
||||
|
||||
GWEN_NEW_OBJECT(AQH_HEXFILE, h);
|
||||
h->recordList=AQH_HexfileRecord_List_new();
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_HEXFILE *AQH_Hexfile_fromString(const char *s)
|
||||
{
|
||||
AQH_HEXFILE *h;
|
||||
AQH_HEXFILERECORD_LIST *recordList;
|
||||
|
||||
h=AQH_Hexfile_new();
|
||||
recordList=AQH_Hexfile_GetRecordList(h);
|
||||
while(s && *s) {
|
||||
AQH_HEXFILERECORD *hr;
|
||||
uint8_t rt;
|
||||
|
||||
while(s && *s && *s!=':')
|
||||
s++;
|
||||
hr=AQH_HexfileRecord_new();
|
||||
s=_readRecord(hr, s);
|
||||
if (s==NULL) {
|
||||
AQH_HexfileRecord_free(hr);
|
||||
AQH_Hexfile_free(h);
|
||||
return NULL;
|
||||
}
|
||||
rt=AQH_HexfileRecord_GetRecordType(hr);
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Adding record %02x", rt);
|
||||
AQH_HexfileRecord_List_Add(hr, recordList);
|
||||
if ((rt==AQH_HEXFILERECORD_TYPE_EOF) ||
|
||||
(rt==AQH_HEXFILERECORD_TYPE_DATA && AQH_HexfileRecord_GetByteCount(hr)==0)) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "End record found");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_HEXFILE *AQH_Hexfile_fromFile(const char *filename)
|
||||
{
|
||||
GWEN_BUFFER *buffer;
|
||||
int rv;
|
||||
AQH_HEXFILE *h;
|
||||
|
||||
buffer=GWEN_Buffer_new(0, 1024, 0, 1);
|
||||
rv=GWEN_SyncIo_Helper_ReadFile(filename, buffer);
|
||||
if (rv<0) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||
GWEN_Buffer_free(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
h=AQH_Hexfile_fromString(GWEN_Buffer_GetStart(buffer));
|
||||
GWEN_Buffer_free(buffer);
|
||||
if (h==NULL) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "here");
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_Hexfile_toBuffer(const AQH_HEXFILE *h, GWEN_BUFFER *buffer)
|
||||
{
|
||||
if (h && h->recordList) {
|
||||
AQH_HEXFILERECORD *hr;
|
||||
|
||||
hr=AQH_HexfileRecord_List_First(h->recordList);
|
||||
while(hr) {
|
||||
_writeRecord(hr, buffer);
|
||||
GWEN_Buffer_AppendString(buffer, "\r\n");
|
||||
hr=AQH_HexfileRecord_List_Next(hr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_Hexfile_free(AQH_HEXFILE *h)
|
||||
{
|
||||
if (h) {
|
||||
AQH_HexfileRecord_List_free(h->recordList);
|
||||
GWEN_FREE_OBJECT(h);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_HEXFILERECORD_LIST *AQH_Hexfile_GetRecordList(const AQH_HEXFILE *h)
|
||||
{
|
||||
if (h)
|
||||
return h->recordList;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const char *_readRecord(AQH_HEXFILERECORD *hr, const char *s)
|
||||
{
|
||||
int v;
|
||||
int dataLen;
|
||||
|
||||
/* find ":" */
|
||||
s=strchr(s, ':');
|
||||
if (s==NULL)
|
||||
return NULL;
|
||||
s++;
|
||||
|
||||
v=_readByte(s);
|
||||
if (v<0)
|
||||
return NULL;
|
||||
AQH_HexfileRecord_SetByteCount(hr, (uint8_t) v);
|
||||
dataLen=v;
|
||||
s+=2;
|
||||
|
||||
v=_readWord(s);
|
||||
if (v<0)
|
||||
return NULL;
|
||||
AQH_HexfileRecord_SetAddress(hr, (uint16_t) v);
|
||||
s+=4;
|
||||
|
||||
v=_readByte(s);
|
||||
if (v<0)
|
||||
return NULL;
|
||||
AQH_HexfileRecord_SetRecordType(hr, (uint8_t) v);
|
||||
s+=2;
|
||||
|
||||
if (dataLen) {
|
||||
uint8_t *ptr;
|
||||
int i;
|
||||
|
||||
ptr=(uint8_t*) malloc(dataLen);
|
||||
if (ptr==NULL) {
|
||||
return NULL;
|
||||
}
|
||||
AQH_HexfileRecord_SetDataPointer(hr, ptr);
|
||||
|
||||
for (i=0; i<dataLen; i++) {
|
||||
v=_readByte(s);
|
||||
if (v<0)
|
||||
return NULL;
|
||||
ptr[i]=(uint8_t) v;
|
||||
s+=2;
|
||||
}
|
||||
}
|
||||
|
||||
/* checksum */
|
||||
v=_readByte(s);
|
||||
if (v<0)
|
||||
return NULL;
|
||||
s+=2;
|
||||
|
||||
v+=_sumValuesForChecksum(hr);
|
||||
if (v & 0xff) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Invalid checksum (%d, %d)", (v & 0xff), -(v & 0xff));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _writeRecord(AQH_HEXFILERECORD *hr, GWEN_BUFFER *buffer)
|
||||
{
|
||||
uint8_t len;
|
||||
int v;
|
||||
|
||||
len=AQH_HexfileRecord_GetByteCount(hr);
|
||||
GWEN_Buffer_AppendArgs(buffer, ":%02X%04X%02X",
|
||||
AQH_HexfileRecord_GetByteCount(hr),
|
||||
AQH_HexfileRecord_GetAddress(hr),
|
||||
AQH_HexfileRecord_GetRecordType(hr));
|
||||
if (len) {
|
||||
const uint8_t *ptr;
|
||||
int i;
|
||||
|
||||
ptr=AQH_HexfileRecord_GetDataPointer(hr);
|
||||
for(i=0; i<len; i++)
|
||||
GWEN_Buffer_AppendArgs(buffer, "%02X", ptr[i]);
|
||||
}
|
||||
|
||||
v=_sumValuesForChecksum(hr);
|
||||
GWEN_Buffer_AppendArgs(buffer, "%02X", (-v) & 0xff);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _sumValuesForChecksum(const AQH_HEXFILERECORD *hr)
|
||||
{
|
||||
int v;
|
||||
int dataLen;
|
||||
|
||||
dataLen=AQH_HexfileRecord_GetByteCount(hr);
|
||||
v=AQH_HexfileRecord_GetByteCount(hr)+
|
||||
((AQH_HexfileRecord_GetAddress(hr)>>8) & 0xff)+(AQH_HexfileRecord_GetAddress(hr) & 0xff)+
|
||||
AQH_HexfileRecord_GetRecordType(hr);
|
||||
if (dataLen) {
|
||||
const uint8_t *ptr;
|
||||
int i;
|
||||
|
||||
ptr=AQH_HexfileRecord_GetDataPointer(hr);
|
||||
for(i=0; i<dataLen; i++)
|
||||
v+=ptr[i];
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int _readWord(const char *s)
|
||||
{
|
||||
uint16_t result;
|
||||
int b;
|
||||
|
||||
b=_readByte(s);
|
||||
if (b<0)
|
||||
return -1;
|
||||
result=(uint16_t)(b & 0xff);
|
||||
s+=2;
|
||||
|
||||
b=_readByte(s++);
|
||||
if (b<0)
|
||||
return -1;
|
||||
result<<=8;
|
||||
result|=(uint16_t)(b & 0xff);
|
||||
return (int) result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _readByte(const char *s)
|
||||
{
|
||||
uint8_t result;
|
||||
int c;
|
||||
|
||||
c=_readNibble(s++);
|
||||
if (c<0)
|
||||
return -1;
|
||||
result=(uint8_t) (c & 0xf);
|
||||
c=_readNibble(s);
|
||||
if (c<0)
|
||||
return -1;
|
||||
result<<=4;
|
||||
result|=(uint8_t) (c & 0xf);
|
||||
return (int) result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _readNibble(const char *s)
|
||||
{
|
||||
uint8_t c;
|
||||
|
||||
c=*s;
|
||||
if (c==0)
|
||||
return -1;
|
||||
if (c>='0' && c<='9')
|
||||
c-='0';
|
||||
else if (c>='A' && c<='F')
|
||||
c-='A'-10;
|
||||
else if (c>='a' && c<='f')
|
||||
c-='a'-10;
|
||||
else
|
||||
return -1;
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user