Files
aqhomecontrol/aqhome/hexfile/hexfile.c
2023-04-18 21:17:56 +02:00

319 lines
5.7 KiB
C

/****************************************************************************
* 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); /* big endian */
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;
}