aqhome: added lib for hexfiles and flash records.
This commit is contained in:
85
aqhome/hexfile/0BUILD
Normal file
85
aqhome/hexfile/0BUILD
Normal file
@@ -0,0 +1,85 @@
|
||||
<?xml?>
|
||||
|
||||
<gwbuild>
|
||||
|
||||
<target type="ConvenienceLibrary" name="aqhhexfile" >
|
||||
|
||||
<includes type="c" >
|
||||
$(gwenhywfar_cflags)
|
||||
-I$(topsrcdir)
|
||||
-I$(topbuilddir)
|
||||
</includes>
|
||||
|
||||
<includes type="tm2" >
|
||||
--include=$(builddir)
|
||||
--include=$(srcdir)
|
||||
</includes>
|
||||
|
||||
|
||||
<define name="BUILDING_AQHOME" />
|
||||
|
||||
<setVar name="local/cflags">$(visibility_cflags)</setVar>
|
||||
|
||||
|
||||
<setVar name="tm2flags" >
|
||||
--api=AQHOME_API
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/typefiles" >
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/built_sources" >
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/built_headers_pub">
|
||||
</setVar>
|
||||
|
||||
|
||||
<setVar name="local/built_headers_priv" >
|
||||
</setVar>
|
||||
|
||||
|
||||
<headers dist="false" install="$(pkgincludedir)/hexfile" >
|
||||
$(local/built_headers_pub)
|
||||
</headers>
|
||||
|
||||
|
||||
<headers dist="true" install="$(pkgincludedir)/hexfile" >
|
||||
hexfilerecord.h
|
||||
hexfilerecord_p.h
|
||||
hexfile.h
|
||||
hexfile_p.h
|
||||
flashrecord.h
|
||||
flashrecord_p.h
|
||||
</headers>
|
||||
|
||||
|
||||
<headers dist="true" >
|
||||
</headers>
|
||||
|
||||
|
||||
<sources>
|
||||
$(local/typefiles)
|
||||
|
||||
hexfile.c
|
||||
hexfilerecord.c
|
||||
flashrecord.c
|
||||
</sources>
|
||||
|
||||
|
||||
<extradist>
|
||||
</extradist>
|
||||
|
||||
|
||||
<useTargets>
|
||||
</useTargets>
|
||||
|
||||
<subdirs>
|
||||
</subdirs>
|
||||
|
||||
|
||||
|
||||
|
||||
</target>
|
||||
|
||||
</gwbuild>
|
||||
215
aqhome/hexfile/flashrecord.c
Normal file
215
aqhome/hexfile/flashrecord.c
Normal file
@@ -0,0 +1,215 @@
|
||||
/****************************************************************************
|
||||
* 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 "./flashrecord_p.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/misc.h>
|
||||
|
||||
|
||||
|
||||
GWEN_LIST_FUNCTIONS(AQH_FLASHRECORD, AQH_FlashRecord)
|
||||
|
||||
|
||||
AQH_HEXFILERECORD *_sampleAdjacentHexfileRecords(AQH_FLASHRECORD *fr, AQH_HEXFILERECORD *hrStart);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
AQH_FLASHRECORD *AQH_FlashRecord_new()
|
||||
{
|
||||
AQH_FLASHRECORD *fr;
|
||||
|
||||
GWEN_NEW_OBJECT(AQH_FLASHRECORD, fr);
|
||||
GWEN_LIST_INIT(AQH_FLASHRECORD, fr);
|
||||
return fr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_FlashRecord_free(AQH_FLASHRECORD *fr)
|
||||
{
|
||||
if (fr) {
|
||||
GWEN_LIST_FINI(AQH_FLASHRECORD, fr);
|
||||
if (fr->dataPointer)
|
||||
free(fr->dataPointer);
|
||||
fr->dataPointer=NULL;
|
||||
GWEN_FREE_OBJECT(fr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint32_t AQH_FlashRecord_GetAddress(const AQH_FLASHRECORD *fr)
|
||||
{
|
||||
if (fr)
|
||||
return fr->address;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_FlashRecord_SetAddress(AQH_FLASHRECORD *fr, uint32_t a)
|
||||
{
|
||||
if (fr)
|
||||
fr->address=a;
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint32_t AQH_FlashRecord_GetDataLength(const AQH_FLASHRECORD *fr)
|
||||
{
|
||||
if (fr)
|
||||
return fr->dataLength;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint8_t *AQH_FlashRecord_GetDataPointer(const AQH_FLASHRECORD *fr)
|
||||
{
|
||||
if (fr)
|
||||
return fr->dataPointer;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_FlashRecord_DirectlySetData(AQH_FLASHRECORD *fr, uint32_t dataLength, uint8_t *dataPtr)
|
||||
{
|
||||
if (fr->dataPointer)
|
||||
free(fr->dataPointer);
|
||||
fr->dataPointer=dataPtr;
|
||||
fr->dataLength=dataLength;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_FlashRecord_CopyAndSetData(AQH_FLASHRECORD *fr, uint32_t dataLength, const uint8_t *dataPtr)
|
||||
{
|
||||
if (fr) {
|
||||
if (fr->dataPointer)
|
||||
free(fr->dataPointer);
|
||||
if (dataLength) {
|
||||
fr->dataPointer=(uint8_t*) malloc(dataLength);
|
||||
if (fr->dataPointer) {
|
||||
if (dataPtr)
|
||||
memmove(fr->dataPointer, dataPtr, dataLength);
|
||||
else
|
||||
memset(fr->dataPointer, 0, dataLength);
|
||||
}
|
||||
else {
|
||||
fr->dataPointer=NULL;
|
||||
fr->dataLength=0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
fr->dataPointer=NULL;
|
||||
fr->dataLength=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_FLASHRECORD_LIST *AQH_FlashRecord_fromHexfileRecords(AQH_HEXFILERECORD_LIST *hexFileRecordList)
|
||||
{
|
||||
AQH_FLASHRECORD_LIST *flashRecordList;
|
||||
AQH_HEXFILERECORD *hr;
|
||||
uint32_t currentOffset=0;
|
||||
|
||||
flashRecordList=AQH_FlashRecord_List_new();
|
||||
hr=AQH_HexfileRecord_List_First(hexFileRecordList);
|
||||
while(hr) {
|
||||
uint8_t t;
|
||||
|
||||
t=AQH_HexfileRecord_GetRecordType(hr);
|
||||
if (t==AQH_HEXFILERECORD_TYPE_DATA) {
|
||||
AQH_FLASHRECORD *fr;
|
||||
|
||||
fr=AQH_FlashRecord_new();
|
||||
AQH_FlashRecord_SetAddress(fr, currentOffset+AQH_HexfileRecord_GetAddress(hr));
|
||||
hr=_sampleAdjacentHexfileRecords(fr, hr);
|
||||
AQH_FlashRecord_List_Add(fr, flashRecordList);
|
||||
}
|
||||
else {
|
||||
if (t==AQH_HEXFILERECORD_TYPE_EXTSEG) {
|
||||
const uint8_t *ptr;
|
||||
|
||||
if (AQH_HexfileRecord_GetByteCount(hr)<2) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Invalid EXTSEG record (02) in file (too few data bytes)");
|
||||
AQH_FlashRecord_List_free(flashRecordList);
|
||||
return NULL;
|
||||
}
|
||||
ptr=AQH_HexfileRecord_GetDataPointer(hr);
|
||||
currentOffset=((ptr[0]<<8)+ptr[1])<<4;
|
||||
}
|
||||
else if (t==AQH_HEXFILERECORD_TYPE_EOF) {
|
||||
break;
|
||||
}
|
||||
|
||||
hr=AQH_HexfileRecord_List_Next(hr);
|
||||
}
|
||||
} /* while */
|
||||
|
||||
if (AQH_FlashRecord_List_GetCount(flashRecordList)<1) {
|
||||
AQH_FlashRecord_List_free(flashRecordList);
|
||||
return NULL;
|
||||
}
|
||||
return flashRecordList;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_HEXFILERECORD *_sampleAdjacentHexfileRecords(AQH_FLASHRECORD *fr, AQH_HEXFILERECORD *hrStart)
|
||||
{
|
||||
AQH_HEXFILERECORD *hrNext;
|
||||
AQH_HEXFILERECORD *hr;
|
||||
uint32_t len=0;
|
||||
|
||||
hrNext=AQH_HexfileRecord_List_FindNonAdjacentDataRecord(hrStart);
|
||||
/* sample number of contiguous bytes */
|
||||
hr=hrStart;
|
||||
while(hr && hr!=hrNext) {
|
||||
len+=AQH_HexfileRecord_GetByteCount(hr);
|
||||
hr=AQH_HexfileRecord_List_Next(hr);
|
||||
}
|
||||
|
||||
if (len) {
|
||||
uint8_t *ptr;
|
||||
uint32_t offs=0;
|
||||
|
||||
ptr=(uint8_t*) malloc(len);
|
||||
hr=hrStart;
|
||||
while(hr && hr!=hrNext) {
|
||||
memmove(ptr+offs, AQH_HexfileRecord_GetDataPointer(hr), AQH_HexfileRecord_GetByteCount(hr));
|
||||
offs+=AQH_HexfileRecord_GetByteCount(hr);
|
||||
hr=AQH_HexfileRecord_List_Next(hr);
|
||||
}
|
||||
AQH_FlashRecord_DirectlySetData(fr, len, ptr);
|
||||
}
|
||||
|
||||
return hrNext;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
42
aqhome/hexfile/flashrecord.h
Normal file
42
aqhome/hexfile/flashrecord.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/****************************************************************************
|
||||
* 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.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQH_FLASHRECORD_H
|
||||
#define AQH_FLASHRECORD_H
|
||||
|
||||
|
||||
#include <aqhome/api.h>
|
||||
#include <aqhome/hexfile/hexfilerecord.h>
|
||||
|
||||
#include <gwenhywfar/list.h>
|
||||
|
||||
|
||||
typedef struct AQH_FLASHRECORD AQH_FLASHRECORD;
|
||||
GWEN_LIST_FUNCTION_LIB_DEFS(AQH_FLASHRECORD, AQH_FlashRecord, AQHOME_API)
|
||||
|
||||
|
||||
AQHOME_API AQH_FLASHRECORD *AQH_FlashRecord_new();
|
||||
AQHOME_API AQH_FLASHRECORD_LIST *AQH_FlashRecord_fromHexfileRecords(AQH_HEXFILERECORD_LIST *hexFileRecordList);
|
||||
|
||||
AQHOME_API void AQH_FlashRecord_free(AQH_FLASHRECORD *fr);
|
||||
|
||||
AQHOME_API uint32_t AQH_FlashRecord_GetAddress(const AQH_FLASHRECORD *fr);
|
||||
AQHOME_API void AQH_FlashRecord_SetAddress(AQH_FLASHRECORD *fr, uint32_t a);
|
||||
|
||||
AQHOME_API uint32_t AQH_FlashRecord_GetDataLength(const AQH_FLASHRECORD *fr);
|
||||
AQHOME_API uint8_t *AQH_FlashRecord_GetDataPointer(const AQH_FLASHRECORD *fr);
|
||||
AQHOME_API void AQH_FlashRecord_DirectlySetData(AQH_FLASHRECORD *fr, uint32_t dataLength, uint8_t *dataPtr);
|
||||
AQHOME_API void AQH_FlashRecord_CopyAndSetData(AQH_FLASHRECORD *fr, uint32_t dataLength, const uint8_t *dataPtr);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
30
aqhome/hexfile/flashrecord_p.h
Normal file
30
aqhome/hexfile/flashrecord_p.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/****************************************************************************
|
||||
* 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.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQH_FLASHRECORD_P_H
|
||||
#define AQH_FLASHRECORD_P_H
|
||||
|
||||
|
||||
#include "./flashrecord.h"
|
||||
|
||||
|
||||
|
||||
struct AQH_FLASHRECORD
|
||||
{
|
||||
GWEN_LIST_ELEMENT(AQH_FLASHRECORD)
|
||||
|
||||
uint32_t address;
|
||||
uint32_t dataLength;
|
||||
uint8_t *dataPointer;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
41
aqhome/hexfile/hexfile.h
Normal file
41
aqhome/hexfile/hexfile.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/****************************************************************************
|
||||
* 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.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQH_HEXFILE_H
|
||||
#define AQH_HEXFILE_H
|
||||
|
||||
|
||||
#include <aqhome/api.h>
|
||||
#include <aqhome/hexfile/hexfilerecord.h>
|
||||
|
||||
#include <gwenhywfar/list.h>
|
||||
#include <gwenhywfar/buffer.h>
|
||||
|
||||
|
||||
|
||||
typedef struct AQH_HEXFILE AQH_HEXFILE;
|
||||
|
||||
|
||||
AQHOME_API AQH_HEXFILE *AQH_Hexfile_new();
|
||||
AQHOME_API AQH_HEXFILE *AQH_Hexfile_fromString(const char *s);
|
||||
AQHOME_API AQH_HEXFILE *AQH_Hexfile_fromFile(const char *filename);
|
||||
|
||||
AQHOME_API void AQH_Hexfile_toBuffer(const AQH_HEXFILE *h, GWEN_BUFFER *buffer);
|
||||
|
||||
AQHOME_API void AQH_Hexfile_free(AQH_HEXFILE *h);
|
||||
|
||||
AQHOME_API AQH_HEXFILERECORD_LIST *AQH_Hexfile_GetRecordList(const AQH_HEXFILE *h);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
27
aqhome/hexfile/hexfile_p.h
Normal file
27
aqhome/hexfile/hexfile_p.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/****************************************************************************
|
||||
* 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.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQH_HEXFILE_P_H
|
||||
#define AQH_HEXFILE_P_H
|
||||
|
||||
|
||||
#include "aqhome/hexfile/hexfile.h"
|
||||
|
||||
|
||||
|
||||
struct AQH_HEXFILE {
|
||||
AQH_HEXFILERECORD_LIST *recordList;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
175
aqhome/hexfile/hexfilerecord.c
Normal file
175
aqhome/hexfile/hexfilerecord.c
Normal file
@@ -0,0 +1,175 @@
|
||||
/****************************************************************************
|
||||
* 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 "./hexfilerecord_p.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/misc.h>
|
||||
|
||||
|
||||
|
||||
GWEN_LIST_FUNCTIONS(AQH_HEXFILERECORD, AQH_HexfileRecord)
|
||||
|
||||
|
||||
|
||||
|
||||
AQH_HEXFILERECORD *AQH_HexfileRecord_new()
|
||||
{
|
||||
AQH_HEXFILERECORD *hr;
|
||||
|
||||
GWEN_NEW_OBJECT(AQH_HEXFILERECORD, hr);
|
||||
GWEN_LIST_INIT(AQH_HEXFILERECORD, hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_HexfileRecord_free(AQH_HEXFILERECORD *hr)
|
||||
{
|
||||
if (hr) {
|
||||
GWEN_LIST_FINI(AQH_HEXFILERECORD, hr);
|
||||
if (hr->dataPointer)
|
||||
free(hr->dataPointer);
|
||||
GWEN_FREE_OBJECT(hr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint8_t AQH_HexfileRecord_GetByteCount(const AQH_HEXFILERECORD *hr)
|
||||
{
|
||||
if (hr)
|
||||
return hr->byteCount;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_HexfileRecord_SetByteCount(AQH_HEXFILERECORD *hr, uint8_t b)
|
||||
{
|
||||
if (hr)
|
||||
hr->byteCount=b;
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint16_t AQH_HexfileRecord_GetAddress(const AQH_HEXFILERECORD *hr)
|
||||
{
|
||||
if (hr)
|
||||
return hr->address;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_HexfileRecord_SetAddress(AQH_HEXFILERECORD *hr, uint16_t a)
|
||||
{
|
||||
if (hr)
|
||||
hr->address=a;
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint8_t AQH_HexfileRecord_GetRecordType(const AQH_HEXFILERECORD *hr)
|
||||
{
|
||||
if (hr)
|
||||
return hr->recordType;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_HexfileRecord_SetRecordType(AQH_HEXFILERECORD *hr, uint8_t t)
|
||||
{
|
||||
if (hr)
|
||||
hr->recordType=t;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const uint8_t *AQH_HexfileRecord_GetDataPointer(const AQH_HEXFILERECORD *hr)
|
||||
{
|
||||
if (hr)
|
||||
return hr->dataPointer;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_HexfileRecord_SetDataPointer(AQH_HEXFILERECORD *hr, uint8_t *ptr)
|
||||
{
|
||||
if (hr) {
|
||||
if (hr->dataPointer)
|
||||
free(hr->dataPointer);
|
||||
hr->dataPointer=ptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_HexfileRecord_SetData(AQH_HEXFILERECORD *hr, const uint8_t *ptr, uint8_t len)
|
||||
{
|
||||
if (hr) {
|
||||
if (hr->dataPointer)
|
||||
free(hr->dataPointer);
|
||||
if (ptr && len) {
|
||||
hr->dataPointer=(uint8_t*) malloc(len);
|
||||
if (hr->dataPointer) {
|
||||
memmove(hr->dataPointer, ptr, len);
|
||||
hr->byteCount=len;
|
||||
}
|
||||
else {
|
||||
hr->dataPointer=NULL;
|
||||
hr->byteCount=0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
hr->dataPointer=NULL;
|
||||
hr->byteCount=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_HEXFILERECORD *AQH_HexfileRecord_List_FindNonAdjacentDataRecord(AQH_HEXFILERECORD *hr)
|
||||
{
|
||||
uint16_t expectedAddr;
|
||||
int cnt=0;
|
||||
|
||||
expectedAddr=AQH_HexfileRecord_GetAddress(hr)+AQH_HexfileRecord_GetByteCount(hr);
|
||||
hr=AQH_HexfileRecord_List_Next(hr);
|
||||
while(hr && AQH_HexfileRecord_GetRecordType(hr)==AQH_HEXFILERECORD_TYPE_DATA) {
|
||||
uint16_t addr;
|
||||
|
||||
addr=AQH_HexfileRecord_GetAddress(hr);
|
||||
if (addr!=expectedAddr)
|
||||
break;
|
||||
expectedAddr=addr+AQH_HexfileRecord_GetByteCount(hr);
|
||||
cnt++;
|
||||
hr=AQH_HexfileRecord_List_Next(hr);
|
||||
}
|
||||
|
||||
DBG_INFO(AQH_LOGDOMAIN, "- num of continuous records: %d", cnt);
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
65
aqhome/hexfile/hexfilerecord.h
Normal file
65
aqhome/hexfile/hexfilerecord.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/****************************************************************************
|
||||
* 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.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQH_HEXFILERECORD_H
|
||||
#define AQH_HEXFILERECORD_H
|
||||
|
||||
|
||||
#include <aqhome/api.h>
|
||||
|
||||
#include <gwenhywfar/list.h>
|
||||
|
||||
|
||||
#define AQH_HEXFILERECORD_TYPE_DATA 0x00
|
||||
#define AQH_HEXFILERECORD_TYPE_EOF 0x01
|
||||
#define AQH_HEXFILERECORD_TYPE_EXTSEG 0x02
|
||||
#define AQH_HEXFILERECORD_TYPE_STARTSEGADDR 0x03
|
||||
#define AQH_HEXFILERECORD_TYPE_EXTLINEARADDR 0x04
|
||||
#define AQH_HEXFILERECORD_TYPE_STARTLINEARADDR 0x05
|
||||
|
||||
|
||||
|
||||
typedef struct AQH_HEXFILERECORD AQH_HEXFILERECORD;
|
||||
GWEN_LIST_FUNCTION_LIB_DEFS(AQH_HEXFILERECORD, AQH_HexfileRecord, AQHOME_API)
|
||||
|
||||
|
||||
AQHOME_API AQH_HEXFILERECORD *AQH_HexfileRecord_new();
|
||||
AQHOME_API void AQH_HexfileRecord_free(AQH_HEXFILERECORD *hr);
|
||||
|
||||
|
||||
AQHOME_API uint8_t AQH_HexfileRecord_GetByteCount(const AQH_HEXFILERECORD *hr);
|
||||
AQHOME_API void AQH_HexfileRecord_SetByteCount(AQH_HEXFILERECORD *hr, uint8_t b);
|
||||
|
||||
AQHOME_API uint16_t AQH_HexfileRecord_GetAddress(const AQH_HEXFILERECORD *hr);
|
||||
AQHOME_API void AQH_HexfileRecord_SetAddress(AQH_HEXFILERECORD *hr, uint16_t a);
|
||||
|
||||
AQHOME_API uint8_t AQH_HexfileRecord_GetRecordType(const AQH_HEXFILERECORD *hr);
|
||||
AQHOME_API void AQH_HexfileRecord_SetRecordType(AQH_HEXFILERECORD *hr, uint8_t t);
|
||||
|
||||
AQHOME_API const uint8_t *AQH_HexfileRecord_GetDataPointer(const AQH_HEXFILERECORD *hr);
|
||||
AQHOME_API void AQH_HexfileRecord_SetDataPointer(AQH_HEXFILERECORD *hr, uint8_t *ptr);
|
||||
|
||||
AQHOME_API void AQH_HexfileRecord_SetData(AQH_HEXFILERECORD *hr, const uint8_t *ptr, uint8_t len);
|
||||
|
||||
|
||||
/**
|
||||
* Find the first record whose address is non-contiguous with the given record.
|
||||
* This can be used to reduce the number of data records.
|
||||
* This function stops at the next record whose address is non-continuous or whose type is not 00.
|
||||
*
|
||||
* @return next non-contiguous or non-data record (NULL if none)
|
||||
* @param hr record to start with (i.e. whose successor are checked for continuity)
|
||||
*/
|
||||
AQHOME_API AQH_HEXFILERECORD *AQH_HexfileRecord_List_FindNonAdjacentDataRecord(AQH_HEXFILERECORD *hr);
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
31
aqhome/hexfile/hexfilerecord_p.h
Normal file
31
aqhome/hexfile/hexfilerecord_p.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/****************************************************************************
|
||||
* 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.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQH_HEXFILERECORD_P_H
|
||||
#define AQH_HEXFILERECORD_P_H
|
||||
|
||||
|
||||
#include "./hexfilerecord.h"
|
||||
|
||||
|
||||
|
||||
struct AQH_HEXFILERECORD
|
||||
{
|
||||
GWEN_LIST_ELEMENT(AQH_HEXFILERECORD)
|
||||
|
||||
uint8_t byteCount;
|
||||
uint16_t address;
|
||||
uint8_t recordType;
|
||||
uint8_t *dataPointer;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user