diff --git a/aqhome/0BUILD b/aqhome/0BUILD index 0cf98a6..b4d4d4f 100644 --- a/aqhome/0BUILD +++ b/aqhome/0BUILD @@ -47,12 +47,21 @@ api.h serial.h serial_p.h + msg.h + msg_p.h + msg_value.h + msg_sendstats.h + msg_ping.h $(local/typefiles) serial.c + msg.c + msg_value.c + msg_sendstats.c + msg_ping.c diff --git a/aqhome/libtest.c b/aqhome/libtest.c index 71940fd..4c71251 100644 --- a/aqhome/libtest.c +++ b/aqhome/libtest.c @@ -4,6 +4,9 @@ #endif #include "aqhome/serial.h" +#include "aqhome/msg_value.h" +#include "aqhome/msg_sendstats.h" +#include "aqhome/msg_ping.h" #include #include @@ -101,38 +104,35 @@ int testSend() -void _packetReceived(AQH_SERIAL *sr, const uint8_t *ptr, uint8_t len) +void _packetReceived(AQH_SERIAL *sr, AQH_MSG *msg) { + const uint8_t *ptr; + uint8_t len; + uint8_t msgType; + int msgIsValid; GWEN_BUFFER *dbuf; GWEN_TIME *ti; dbuf=GWEN_Buffer_new(0, 256, 0, 1); ti=GWEN_CurrentTime(); - GWEN_Time_toString(ti, "YYYY-MM-DD hh:mm:ss", dbuf); - fprintf(stdout, " %s: Received:\n", GWEN_Buffer_GetStart(dbuf)); - GWEN_Text_DumpString(ptr, len, 6); + GWEN_Time_toString(ti, "YYYY-MM-DD hh:mm:ss ", dbuf); GWEN_Time_free(ti); - GWEN_Buffer_free(dbuf); + ti=NULL; - if (ptr[2]==1) { - fprintf(stdout, "-> PING\n"); - } - else if (ptr[2]==2) { - uint32_t secs; - int packetsOut; - int collisions; - int aborted; + msgIsValid=(AQH_Msg_IsChecksumValid(msg) && AQH_Msg_IsMsgComplete(msg)); + ptr=AQH_Msg_GetBuffer(msg); + len=AQH_Msg_GetBytesInBuffer(msg); + msgType=AQH_Msg_GetMsgType(msg); - /* send error stats */ - secs=(ptr[4])+(ptr[5]<<8)+(ptr[6]<<16)+(ptr[7]<<24); - packetsOut=(ptr[8])+(ptr[9]<<8); - collisions=(ptr[10])+(ptr[11]<<8); - aborted=(ptr[12])+(ptr[13]<<8); - fprintf(stdout, "-> SEND STATS: %08x packets sent=%d, collisions=%d, aborted=%d\n", - (unsigned int) secs, - packetsOut, collisions, aborted); + if (msgType==AQH_MSG_TYPE_PING) { + AQH_MsgPing_DumpToBuffer(msg, dbuf, "received"); + fprintf(stdout, "%s", GWEN_Buffer_GetStart(dbuf)); } - else if (ptr[2]==4) { + else if (msgType==AQH_MSG_TYPE_COMSENDSTATS) { /* CPRO_CMD_COMSENDSTATS */ + AQH_MsgSendStats_DumpToBuffer(msg, dbuf, "received"); + fprintf(stdout, "%s", GWEN_Buffer_GetStart(dbuf)); + } + else if (msgType==30) { /* CPRO_CMD_I2CBUSMEMBER */ int i2cAddr; int availability; @@ -140,7 +140,7 @@ void _packetReceived(AQH_SERIAL *sr, const uint8_t *ptr, uint8_t len) availability=ptr[5]; fprintf(stdout, "-> I2C DEVICE %02x: %s\n", i2cAddr, (availability==0)?"not available":"FOUND"); } - else if (ptr[2]==5) { + else if (msgType==40) { /* CPRO_CMD_DEBUG */ uint8_t param1; uint8_t param2; @@ -148,33 +148,86 @@ void _packetReceived(AQH_SERIAL *sr, const uint8_t *ptr, uint8_t len) param2=ptr[5]; fprintf(stdout, "-> Debug param1=%02x, param2=%02x\n", param1, param2); } - else if (ptr[2]==6) { - uint32_t secs; - int valueId; - int valueType; - double value; - double denom; - double calcValue; - int intDenom; - const char *tn; - - /* send error stats */ - secs=(ptr[4])+(ptr[5]<<8)+(ptr[6]<<16)+(ptr[7]<<24); - valueId=ptr[8]; - valueType=ptr[9]; - value=(double)((ptr[10])+(ptr[11]<<8)); - intDenom=(ptr[12])+(ptr[13]<<8); - denom=(double)(intDenom); - if (intDenom==0) - denom=1.0; - calcValue=value/denom; - switch(valueType) { - case 1: tn="temperature"; break; - case 2: tn="humidity"; break; - default: tn="unknown"; break; - } - fprintf(stdout, "-> VALUE: %08x %d=%.2f (%s)\n", (unsigned int) secs, valueId, calcValue, tn); + else if (msgType==AQH_MSG_TYPE_VALUE) { /* CPRO_CMD_VALUE */ + AQH_MsgValue_DumpToBuffer(msg, dbuf, "received"); + fprintf(stdout, "%s", GWEN_Buffer_GetStart(dbuf)); } + else { + fprintf(stdout, " %s: Received (%s):\n", GWEN_Buffer_GetStart(dbuf), msgIsValid?"valid":"invalid"); + GWEN_Text_DumpString(ptr, len, 6); + } + GWEN_Buffer_free(dbuf); + + AQH_Msg_free(msg); +} + + + +AQH_MSG *createPingMsg(AQH_SERIAL *sr, uint8_t destAddr) +{ + AQH_MSG *msg; + int rv; + + msg=AQH_Msg_new(); + rv=AQH_Msg_AddByte(msg, destAddr); + if (rv<0) { + fprintf(stderr, "ERROR1: %d\n", rv); + AQH_Msg_free(msg); + return NULL; + } + rv=AQH_Msg_AddByte(msg, 6); /* msglen */ + if (rv<0) { + fprintf(stderr, "ERROR2: %d\n", rv); + AQH_Msg_free(msg); + return NULL; + } + rv=AQH_Msg_AddByte(msg, 10); /* ping */ + if (rv<0) { + fprintf(stderr, "ERROR3: %d\n", rv); + AQH_Msg_free(msg); + return NULL; + } + rv=AQH_Msg_AddByte(msg, AQH_Serial_GetAddress(sr)); /* src addr */ + if (rv<0) { + fprintf(stderr, "ERROR4: %d\n", rv); + AQH_Msg_free(msg); + return NULL; + } + + rv=AQH_Msg_AddByte(msg, 0); /* timestamp */ + if (rv<0) { + fprintf(stderr, "ERROR5: %d\n", rv); + AQH_Msg_free(msg); + return NULL; + } + rv=AQH_Msg_AddByte(msg, 0); /* timestamp */ + if (rv<0) { + fprintf(stderr, "ERROR6: %d\n", rv); + AQH_Msg_free(msg); + return NULL; + } + rv=AQH_Msg_AddByte(msg, 0); /* timestamp */ + if (rv<0) { + fprintf(stderr, "ERROR7: %d\n", rv); + AQH_Msg_free(msg); + return NULL; + } + rv=AQH_Msg_AddByte(msg, 0); /* timestamp */ + if (rv<0) { + fprintf(stderr, "ERROR8: %d\n", rv); + AQH_Msg_free(msg); + return NULL; + } + + + rv=AQH_Msg_AddChecksum(msg); + if (rv<0) { + fprintf(stderr, "ERROR9: %d\n", rv); + AQH_Msg_free(msg); + return NULL; + } + + return msg; } @@ -185,8 +238,6 @@ int testLoop() int rv; int i; GWEN_BUFFER *dbuf; -// uint8_t sendBuf[5]={0x01, 0x02, 0xdb, 0x00, 0xd8 }; - uint8_t sendBuf[5]={0x01, 0x02, 0x01, 0xdb, 0xd9 }; time_t tLast; fprintf(stdout, "Opening device...\n"); @@ -212,16 +263,42 @@ int testLoop() } t=time(NULL); if (difftime(t, tLast)>10) { - rv=AQH_Serial_StartWriting(sr, sendBuf, 5); - if (rv==0) - fprintf(stdout, "+ Sending data\n"); - else if (rv==GWEN_ERROR_TRY_AGAIN) - fprintf(stdout, "W Outbuffer busy\n"); + AQH_MSG *msg; + + msg=createPingMsg(sr, 1); + if (msg) { + rv=AQH_Serial_AddMessageToSend(sr, msg); + if (rv<0) { + fprintf(stderr, "ERROR: %d\n", rv); + AQH_Msg_free(msg); + return rv; + } + + if (rv==0) { + GWEN_BUFFER *dbuf; + GWEN_TIME *ti; + + dbuf=GWEN_Buffer_new(0, 256, 0, 1); + ti=GWEN_CurrentTime(); + GWEN_Time_toString(ti, "YYYY-MM-DD hh:mm:ss ", dbuf); + GWEN_Time_free(ti); + ti=NULL; + AQH_MsgPing_DumpToBuffer(msg, dbuf, "enqueued"); + fprintf(stdout, "%s", GWEN_Buffer_GetStart(dbuf)); + GWEN_Buffer_free(dbuf); + } + else { + DBG_ERROR(NULL, "here (%d)", rv); + AQH_Serial_Close(sr); + AQH_Serial_free(sr); + return rv; + } + } else { DBG_ERROR(NULL, "here (%d)", rv); AQH_Serial_Close(sr); AQH_Serial_free(sr); - return rv; + return GWEN_ERROR_INTERNAL; } tLast=t; } diff --git a/aqhome/msg.c b/aqhome/msg.c new file mode 100644 index 0000000..d4c01cb --- /dev/null +++ b/aqhome/msg.c @@ -0,0 +1,247 @@ +/**************************************************************************** + * 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 +#endif + +#include "aqhome/msg_p.h" + +#include +#include +#include +#include + + + + +GWEN_LIST_FUNCTIONS(AQH_MSG, AQH_Msg) + + + + +static uint8_t _calcChecksum(const uint8_t *ptr, uint8_t len); + + + + +AQH_MSG *AQH_Msg_new() +{ + AQH_MSG *msg; + + GWEN_NEW_OBJECT(AQH_MSG, msg); + GWEN_LIST_INIT(AQH_MSG, msg); + return msg; +} + + + +void AQH_Msg_free(AQH_MSG *msg) +{ + if (msg) { + GWEN_LIST_FINI(AQH_MSG, msg); + GWEN_FREE_OBJECT(msg); + } +} + + + +uint8_t *AQH_Msg_GetBuffer(AQH_MSG *msg) +{ + if (msg) + return msg->buffer; + return NULL; +} + + + +const uint8_t *AQH_Msg_GetConstBuffer(const AQH_MSG *msg) +{ + if (msg) + return msg->buffer; + return NULL; +} + + + +uint8_t AQH_Msg_GetBytesInBuffer(const AQH_MSG *msg) +{ + if (msg) + return msg->bytesInBuffer; + else + return 0; +} + + + +uint8_t AQH_Msg_GetCurrentPos(const AQH_MSG *msg) +{ + if (msg) + return msg->currentPos; + else + return 0; +} + + + +int AQH_Msg_AddByte(AQH_MSG *msg, uint8_t b) +{ + if (msg) { + if ((msg->bytesInBuffercurrentPosbuffer[(msg->currentPos)++]=b; + msg->bytesInBuffer++; + return 0; + } + } + return GWEN_ERROR_MEMORY_FULL; +} + + + +int AQH_Msg_ReadNextByte(AQH_MSG *msg) +{ + if (msg) { + if ((msg->currentPoscurrentPosbytesInBuffer)) { + return ((int)(msg->buffer[(msg->currentPos)++])) & 0xff; + } + } + return GWEN_ERROR_EOF; +} + + + +int AQH_Msg_IncCurrentPos(AQH_MSG *msg, uint8_t i) +{ + if (msg) { + if (((msg->currentPos+i)currentPos+i)bytesInBuffer)) { + msg->currentPos+=i; + return 0; + } + } + return GWEN_ERROR_EOF; +} + + + +int AQH_Msg_RewindCurrentPos(AQH_MSG *msg) +{ + if (msg) { + msg->currentPos=0; + return 0; + } + return GWEN_ERROR_EOF; +} + + + +int AQH_Msg_GetRemainingBytes(const AQH_MSG *msg) +{ + if (msg) + return msg->bytesInBuffer-msg->currentPos; + return 0; +} + + + +uint8_t AQH_Msg_GetDestAddress(const AQH_MSG *msg) +{ + if (msg && msg->bytesInBuffer>AQH_MSG_OFFS_ALL_DEST_ADDRESS) + return msg->buffer[AQH_MSG_OFFS_ALL_DEST_ADDRESS]; + + return 0; +} + + + +uint8_t AQH_Msg_GetMsgType(const AQH_MSG *msg) +{ + if (msg && msg->bytesInBuffer>AQH_MSG_OFFS_ALL_MSG_TYPE) + return msg->buffer[AQH_MSG_OFFS_ALL_MSG_TYPE]; + return 0; +} + + + +uint8_t AQH_Msg_GetSourceAddress(const AQH_MSG *msg) +{ + if (msg && msg->bytesInBuffer>AQH_MSG_OFFS_ALL_SRC_ADDRESS) + return msg->buffer[AQH_MSG_OFFS_ALL_SRC_ADDRESS]; + return 0; +} + + + +uint8_t AQH_Msg_GetMsgPayloadLen(const AQH_MSG *msg) +{ + if (msg && msg->bytesInBuffer>AQH_MSG_OFFS_ALL_PAYLOAD_LEN) + return msg->buffer[AQH_MSG_OFFS_ALL_PAYLOAD_LEN]; + return 0; +} + + + +int AQH_Msg_IsMsgComplete(const AQH_MSG *msg) +{ + if (msg && msg->bytesInBuffer>AQH_MSG_OFFS_ALL_PAYLOAD_LEN) { + uint8_t len; + + len=msg->buffer[AQH_MSG_OFFS_ALL_PAYLOAD_LEN]+AQH_MSG_OFFS_ALL_PAYLOAD_BEGIN+1; + if (len>AQH_MAXMSGSIZE) + return -1; + else if (msg->bytesInBuffer>=len) + return 1; + } + return 0; +} + + + +int AQH_Msg_IsChecksumValid(const AQH_MSG *msg) +{ + if (msg && AQH_Msg_IsMsgComplete(msg)) + return (_calcChecksum(msg->buffer, msg->bytesInBuffer)==0)?1:0; + return 0; +} + + + +int AQH_Msg_AddChecksum(AQH_MSG *msg) +{ + if (msg) { + int rv; + + rv=AQH_Msg_AddByte(msg, _calcChecksum(msg->buffer, msg->bytesInBuffer)); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + return rv; + } + return 0; + } + return GWEN_ERROR_GENERIC; +} + + + +uint8_t _calcChecksum(const uint8_t *ptr, uint8_t len) +{ + int i; + uint8_t x=0; + + for (i=0; i + +#include + + + +#define AQH_MSG_OFFS_ALL_DEST_ADDRESS 0 +#define AQH_MSG_OFFS_ALL_PAYLOAD_LEN 1 +#define AQH_MSG_OFFS_ALL_PAYLOAD_BEGIN 2 +#define AQH_MSG_OFFS_ALL_MSG_TYPE 2 +#define AQH_MSG_OFFS_ALL_SRC_ADDRESS 3 +#define AQH_MSG_OFFS_ALL_DATA_BEGIN 4 + + +#define AQH_MSG_TYPE_PING 10 +#define AQH_MSG_TYPE_PONG 11 +#define AQH_MSG_TYPE_COMSENDSTATS 20 +#define AQH_MSG_TYPE_COMRECVSTATS 21 +#define AQH_MSG_TYPE_I2CBUSMEMBER 30 +#define AQH_MSG_TYPE_DEBUG 40 +#define AQH_MSG_TYPE_VALUE 50 +#define AQH_MSG_TYPE_NEED_ADDRESS 60 +#define AQH_MSG_TYPE_HAVE_ADDRESS 61 + + + + +typedef struct AQH_MSG AQH_MSG; +GWEN_LIST_FUNCTION_LIB_DEFS(AQH_MSG, AQH_Msg, AQHOME_API) + + +AQHOME_API AQH_MSG *AQH_Msg_new(); +AQHOME_API void AQH_Msg_free(AQH_MSG *msg); + +AQHOME_API uint8_t *AQH_Msg_GetBuffer(AQH_MSG *msg); +AQHOME_API const uint8_t *AQH_Msg_GetConstBuffer(const AQH_MSG *msg); +AQHOME_API uint8_t AQH_Msg_GetBytesInBuffer(const AQH_MSG *msg); +AQHOME_API uint8_t AQH_Msg_GetCurrentPos(const AQH_MSG *msg); +AQHOME_API int AQH_Msg_AddByte(AQH_MSG *msg, uint8_t b); +AQHOME_API int AQH_Msg_ReadNextByte(AQH_MSG *msg); +AQHOME_API int AQH_Msg_IncCurrentPos(AQH_MSG *msg, uint8_t i); +AQHOME_API int AQH_Msg_GetRemainingBytes(const AQH_MSG *msg); +AQHOME_API int AQH_Msg_RewindCurrentPos(AQH_MSG *msg); + +AQHOME_API uint8_t AQH_Msg_GetDestAddress(const AQH_MSG *msg); +AQHOME_API uint8_t AQH_Msg_GetMsgType(const AQH_MSG *msg); +AQHOME_API uint8_t AQH_Msg_GetSourceAddress(const AQH_MSG *msg); +AQHOME_API uint8_t AQH_Msg_GetMsgPayloadLen(const AQH_MSG *msg); + +AQHOME_API int AQH_Msg_IsMsgComplete(const AQH_MSG *msg); +AQHOME_API int AQH_Msg_IsChecksumValid(const AQH_MSG *msg); +AQHOME_API int AQH_Msg_AddChecksum(AQH_MSG *msg); + + +#endif + + + diff --git a/aqhome/msg_p.h b/aqhome/msg_p.h new file mode 100644 index 0000000..7833a4e --- /dev/null +++ b/aqhome/msg_p.h @@ -0,0 +1,32 @@ +/**************************************************************************** + * 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_MSG_P_H +#define AQH_MSG_P_H + + +#include "aqhome/msg.h" + + + + +struct AQH_MSG { + GWEN_LIST_ELEMENT(AQH_MSG) + + uint8_t buffer[AQH_MAXMSGSIZE]; + uint8_t bytesInBuffer; + uint8_t currentPos; +}; + + + + +#endif + + + diff --git a/aqhome/msg_ping.c b/aqhome/msg_ping.c new file mode 100644 index 0000000..ae429ff --- /dev/null +++ b/aqhome/msg_ping.c @@ -0,0 +1,53 @@ +/**************************************************************************** + * 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 +#endif + +#include "aqhome/msg_ping.h" + +#include +#include +#include +#include + + + +uint32_t AQH_MsgPing_GetTimestamp(const AQH_MSG *msg) +{ + if ((AQH_Msg_GetMsgType(msg)==AQH_MSG_TYPE_PING) && + (AQH_Msg_GetBytesInBuffer(msg)>=AQH_MSG_PING_MINSIZE)) { + const uint8_t *ptr; + + ptr=AQH_Msg_GetConstBuffer(msg)+AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_PING_TIMESTAMP; + return (uint32_t)(ptr[0])+(ptr[1]<<8)+(ptr[2]<<16)+(ptr[3]<<24); + } + return 0; +} + + + +void AQH_MsgPing_DumpToBuffer(const AQH_MSG *msg, GWEN_BUFFER *dbuf, const char *sText) +{ + if ((AQH_Msg_GetMsgType(msg)==AQH_MSG_TYPE_PING) && + (AQH_Msg_GetBytesInBuffer(msg)>=AQH_MSG_PING_MINSIZE)) { + GWEN_Buffer_AppendArgs(dbuf, + "0x%02x->0x%02x: PING %s (timestamp=0x%08x)\n", + AQH_Msg_GetSourceAddress(msg), + AQH_Msg_GetDestAddress(msg), + sText, + (unsigned int) AQH_MsgPing_GetTimestamp(msg)); + } +} + + + + + + diff --git a/aqhome/msg_ping.h b/aqhome/msg_ping.h new file mode 100644 index 0000000..ff2524a --- /dev/null +++ b/aqhome/msg_ping.h @@ -0,0 +1,37 @@ +/**************************************************************************** + * 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_MSG_PING_H +#define AQH_MSG_PING_H + + +#include + +#include "aqhome/msg.h" + +#include +#include + + + +#define AQH_MSG_OFFS_PING_TIMESTAMP 0 + +#define AQH_MSG_PING_MINSIZE (AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_PING_TIMESTAMP+4) + + + + +AQHOME_API uint32_t AQH_MsgPing_GetTimestamp(const AQH_MSG *msg); +AQHOME_API void AQH_MsgPing_DumpToBuffer(const AQH_MSG *msg, GWEN_BUFFER *dbuf, const char *sText); + + + +#endif + + + diff --git a/aqhome/msg_sendstats.c b/aqhome/msg_sendstats.c new file mode 100644 index 0000000..12ab513 --- /dev/null +++ b/aqhome/msg_sendstats.c @@ -0,0 +1,99 @@ +/**************************************************************************** + * 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 +#endif + +#include "aqhome/msg_sendstats.h" + +#include +#include +#include +#include + + + +uint32_t AQH_MsgSendStats_GetTimestamp(const AQH_MSG *msg) +{ + if ((AQH_Msg_GetMsgType(msg)==AQH_MSG_TYPE_COMSENDSTATS) && + (AQH_Msg_GetBytesInBuffer(msg)>=AQH_MSG_SENDSTATS_MINSIZE)) { + const uint8_t *ptr; + + ptr=AQH_Msg_GetConstBuffer(msg)+AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_SENDSTATS_TIMESTAMP; + return (uint32_t)(ptr[0])+(ptr[1]<<8)+(ptr[2]<<16)+(ptr[3]<<24); + } + return 0; +} + + + +uint16_t AQH_MsgSendStats_GetPacketsOut(const AQH_MSG *msg) +{ + if ((AQH_Msg_GetMsgType(msg)==AQH_MSG_TYPE_COMSENDSTATS) && + (AQH_Msg_GetBytesInBuffer(msg)>=AQH_MSG_SENDSTATS_MINSIZE)) { + const uint8_t *ptr; + + ptr=AQH_Msg_GetConstBuffer(msg)+AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_SENDSTATS_PACKETSOUT; + return (uint16_t)(ptr[0])+(ptr[1]<<8); + } + return 0; +} + + + +uint16_t AQH_MsgSendStats_GetCollisions(const AQH_MSG *msg) +{ + if ((AQH_Msg_GetMsgType(msg)==AQH_MSG_TYPE_COMSENDSTATS) && + (AQH_Msg_GetBytesInBuffer(msg)>=AQH_MSG_SENDSTATS_MINSIZE)) { + const uint8_t *ptr; + + ptr=AQH_Msg_GetConstBuffer(msg)+AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_SENDSTATS_COLLISIONS; + return (uint16_t)(ptr[0])+(ptr[1]<<8); + } + return 0; +} + + + +uint16_t AQH_MsgSendStats_GetAborted(const AQH_MSG *msg) +{ + if ((AQH_Msg_GetMsgType(msg)==AQH_MSG_TYPE_COMSENDSTATS) && + (AQH_Msg_GetBytesInBuffer(msg)>=AQH_MSG_SENDSTATS_MINSIZE)) { + const uint8_t *ptr; + + ptr=AQH_Msg_GetConstBuffer(msg)+AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_SENDSTATS_ABORTED; + return (uint16_t)(ptr[0])+(ptr[1]<<8); + } + return 0; +} + + + +void AQH_MsgSendStats_DumpToBuffer(const AQH_MSG *msg, GWEN_BUFFER *dbuf, const char *sText) +{ + if ((AQH_Msg_GetMsgType(msg)==AQH_MSG_TYPE_COMSENDSTATS) && + (AQH_Msg_GetBytesInBuffer(msg)>=AQH_MSG_SENDSTATS_MINSIZE)) { + GWEN_Buffer_AppendArgs(dbuf, + "0x%02x->0x%02x: SENDSTATS %s (timestamp=0x%08x, out=%d, collisions=%d, aborted=%d)\n", + AQH_Msg_GetSourceAddress(msg), + AQH_Msg_GetDestAddress(msg), + sText, + (unsigned int) AQH_MsgSendStats_GetTimestamp(msg), + AQH_MsgSendStats_GetPacketsOut(msg), + AQH_MsgSendStats_GetCollisions(msg), + AQH_MsgSendStats_GetAborted(msg)); + } +} + + + + + + + diff --git a/aqhome/msg_sendstats.h b/aqhome/msg_sendstats.h new file mode 100644 index 0000000..b9e629c --- /dev/null +++ b/aqhome/msg_sendstats.h @@ -0,0 +1,45 @@ +/**************************************************************************** + * 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_MSG_SENDSTATS_H +#define AQH_MSG_SENDSTATS_H + + +#include + +#include "aqhome/msg.h" + +#include +#include + + + +#define AQH_MSG_OFFS_SENDSTATS_TIMESTAMP 0 +#define AQH_MSG_OFFS_SENDSTATS_PACKETSOUT 4 +#define AQH_MSG_OFFS_SENDSTATS_COLLISIONS 6 +#define AQH_MSG_OFFS_SENDSTATS_ABORTED 8 + +#define AQH_MSG_SENDSTATS_MINSIZE (AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_SENDSTATS_ABORTED+2) + + + + +AQHOME_API uint32_t AQH_MsgSendStats_GetTimestamp(const AQH_MSG *msg); +AQHOME_API uint16_t AQH_MsgSendStats_GetPacketsOut(const AQH_MSG *msg); +AQHOME_API uint16_t AQH_MsgSendStats_GetCollisions(const AQH_MSG *msg); +AQHOME_API uint16_t AQH_MsgSendStats_GetAborted(const AQH_MSG *msg); + + +AQHOME_API void AQH_MsgSendStats_DumpToBuffer(const AQH_MSG *msg, GWEN_BUFFER *dbuf, const char *sText); + + + +#endif + + + diff --git a/aqhome/msg_value.c b/aqhome/msg_value.c new file mode 100644 index 0000000..7296ef3 --- /dev/null +++ b/aqhome/msg_value.c @@ -0,0 +1,121 @@ +/**************************************************************************** + * 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 +#endif + +#include "aqhome/msg_value.h" + +#include +#include +#include +#include + + + + +uint32_t AQH_MsgValue_GetTimestamp(const AQH_MSG *msg) +{ + if ((AQH_Msg_GetMsgType(msg)==AQH_MSG_TYPE_VALUE) && + (AQH_Msg_GetBytesInBuffer(msg)>=AQH_MSG_VALUE_MINSIZE)) { + const uint8_t *ptr; + + ptr=AQH_Msg_GetConstBuffer(msg)+AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_VALUE_TIMESTAMP; + return (uint32_t)(ptr[0])+(ptr[1]<<8)+(ptr[2]<<16)+(ptr[3]<<24); + } + return 0; +} + + + +uint8_t AQH_MsgValue_GetValueId(const AQH_MSG *msg) +{ + if ((AQH_Msg_GetMsgType(msg)==AQH_MSG_TYPE_VALUE) && + (AQH_Msg_GetBytesInBuffer(msg)>=AQH_MSG_VALUE_MINSIZE)) { + const uint8_t *ptr; + + ptr=AQH_Msg_GetConstBuffer(msg)+AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_VALUE_VALUEID; + return ptr[0]; + } + return 0; +} + + + +uint8_t AQH_MsgValue_GetValueType(const AQH_MSG *msg) +{ + if ((AQH_Msg_GetMsgType(msg)==AQH_MSG_TYPE_VALUE) && + (AQH_Msg_GetBytesInBuffer(msg)>=AQH_MSG_VALUE_MINSIZE)) { + const uint8_t *ptr; + + ptr=AQH_Msg_GetConstBuffer(msg)+AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_VALUE_VALUETYPE; + return ptr[0]; + } + return 0; +} + + + +const char *AQH_MsgValue_GetValueTypeName(const AQH_MSG *msg) +{ + uint8_t t; + + t=AQH_MsgValue_GetValueType(msg); + switch(t) { + case AQH_MSG_VALUE_TYPE_TEMP: return "temperature"; + case AQH_MSG_VALUE_TYPE_HUMIDITY: return "humidity"; + default: break; + } + return "unknown"; +} + + + +double AQH_MsgValue_GetValue(const AQH_MSG *msg) +{ + if ((AQH_Msg_GetMsgType(msg)==AQH_MSG_TYPE_VALUE) && + (AQH_Msg_GetBytesInBuffer(msg)>=AQH_MSG_VALUE_MINSIZE)) { + const uint8_t *ptr; + double value; + double denom; + uint16_t intDenom; + + ptr=AQH_Msg_GetConstBuffer(msg)+AQH_MSG_OFFS_ALL_DATA_BEGIN; + value=(double)((ptr[AQH_MSG_OFFS_VALUE_VALUE])+(ptr[AQH_MSG_OFFS_VALUE_VALUE+1]<<8)); + intDenom=(ptr[AQH_MSG_OFFS_VALUE_DENOM])+(ptr[AQH_MSG_OFFS_VALUE_DENOM+1]<<8); + denom=(double)(intDenom); + if (intDenom==0) + denom=1.0; + return (double)(value/denom); + + } + return 0.0; +} + + + +void AQH_MsgValue_DumpToBuffer(const AQH_MSG *msg, GWEN_BUFFER *dbuf, const char *sText) +{ + if ((AQH_Msg_GetMsgType(msg)==AQH_MSG_TYPE_VALUE) && + (AQH_Msg_GetBytesInBuffer(msg)>=AQH_MSG_VALUE_MINSIZE)) { + GWEN_Buffer_AppendArgs(dbuf, "0x%02x->0x%02x: VALUE %s (timestamp=0x%08x, value_id=0x%02x type=%s value=%f)\n", + AQH_Msg_GetSourceAddress(msg), + AQH_Msg_GetDestAddress(msg), + sText, + (unsigned int) AQH_MsgValue_GetTimestamp(msg), + AQH_MsgValue_GetValueId(msg), + AQH_MsgValue_GetValueTypeName(msg), + AQH_MsgValue_GetValue(msg)); + } +} + + + + + diff --git a/aqhome/msg_value.h b/aqhome/msg_value.h new file mode 100644 index 0000000..7c3e350 --- /dev/null +++ b/aqhome/msg_value.h @@ -0,0 +1,48 @@ +/**************************************************************************** + * 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_MSG_VALUE_H +#define AQH_MSG_VALUE_H + + +#include + +#include "aqhome/msg.h" + +#include +#include + + + +#define AQH_MSG_OFFS_VALUE_TIMESTAMP 0 +#define AQH_MSG_OFFS_VALUE_VALUEID 4 +#define AQH_MSG_OFFS_VALUE_VALUETYPE 5 +#define AQH_MSG_OFFS_VALUE_VALUE 6 +#define AQH_MSG_OFFS_VALUE_DENOM 8 + +#define AQH_MSG_VALUE_MINSIZE (AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_VALUE_DENOM+2) + +#define AQH_MSG_VALUE_TYPE_TEMP 1 +#define AQH_MSG_VALUE_TYPE_HUMIDITY 2 + + + +AQHOME_API uint32_t AQH_MsgValue_GetTimestamp(const AQH_MSG *msg); +AQHOME_API uint8_t AQH_MsgValue_GetValueId(const AQH_MSG *msg); +AQHOME_API uint8_t AQH_MsgValue_GetValueType(const AQH_MSG *msg); +AQHOME_API double AQH_MsgValue_GetValue(const AQH_MSG *msg); + + +AQHOME_API void AQH_MsgValue_DumpToBuffer(const AQH_MSG *msg, GWEN_BUFFER *dbuf, const char *sText); + + + +#endif + + + diff --git a/aqhome/serial.c b/aqhome/serial.c index 5264df2..fb41b69 100644 --- a/aqhome/serial.c +++ b/aqhome/serial.c @@ -37,11 +37,13 @@ int _attnLow(AQH_SERIAL *sr); int _attnHigh(AQH_SERIAL *sr); int _readForced(AQH_SERIAL *sr, uint8_t *buf, int len); int _writeForced(AQH_SERIAL *sr, const uint8_t *buf, uint8_t len); -int _check(const uint8_t *ptr, uint8_t len); -uint8_t _calcChecksum(const uint8_t *ptr, uint8_t len); +int _discardInput(AQH_SERIAL *sr); +#define AQH_SERIAL_BAUDRATE B19200 +#define AQH_SERIAL_BYTE_MICROSECS 520 + AQH_SERIAL *AQH_Serial_new(const char *deviceName, uint8_t addr) @@ -52,9 +54,10 @@ AQH_SERIAL *AQH_Serial_new(const char *deviceName, uint8_t addr) sr->deviceName=deviceName?strdup(deviceName):NULL; sr->address=addr; sr->fd=-1; + sr->intendedAttnState=1; - sr->bytesToRead=2; - + sr->receivedMessageList=AQH_Msg_List_new(); + sr->sendMessageList=AQH_Msg_List_new(); return sr; } @@ -63,6 +66,8 @@ AQH_SERIAL *AQH_Serial_new(const char *deviceName, uint8_t addr) void AQH_Serial_free(AQH_SERIAL *sr) { if (sr) { + AQH_Msg_List_free(sr->receivedMessageList); + AQH_Msg_List_free(sr->sendMessageList); free(sr->deviceName); GWEN_FREE_OBJECT(sr); } @@ -70,6 +75,13 @@ void AQH_Serial_free(AQH_SERIAL *sr) +uint8_t AQH_Serial_GetAddress(const AQH_SERIAL *sr) +{ + return sr->address; +} + + + int AQH_Serial_Open(AQH_SERIAL *sr) { int fd; @@ -78,37 +90,42 @@ int AQH_Serial_Open(AQH_SERIAL *sr) struct termios options; int rv; - fd=open(sr->deviceName,O_RDWR | O_NOCTTY ); + fd=open(sr->deviceName,O_RDWR | O_NOCTTY | O_NDELAY); if (fd<0) { DBG_ERROR(NULL, "Error on open(%s): %s (%d)", sr->deviceName, strerror(errno), errno); return GWEN_ERROR_IO; } - rv=tcgetattr(fd, &options); + rv=tcgetattr(fd, &(sr->previousOptions)); if (rv<0) { DBG_ERROR(NULL, "Error on tcgetattr(%s): %s (%d)", sr->deviceName, strerror(errno), errno); return GWEN_ERROR_IO; } - rv=cfsetispeed(&options, B19200); - //rv=cfsetispeed(&options, B9600); + memset(&options, 0, sizeof(options)); /* preset */ + + options.c_cflag=CLOCAL | CREAD | CS8; + options.c_iflag=IGNPAR | IGNBRK; + options.c_oflag=0; + options.c_lflag=0; + cfmakeraw(&options); + options.c_cc[VTIME]=0; /* read timeout in deciseconds */ + options.c_cc[VMIN]=0; /* no minimum number of receive bytes */ + + rv=cfsetispeed(&options, AQH_SERIAL_BAUDRATE); if (rv<0) { DBG_ERROR(NULL, "Error on cfsetispeed(%s): %s (%d)", sr->deviceName, strerror(errno), errno); return GWEN_ERROR_IO; } - rv=cfsetospeed(&options, B19200); + rv=cfsetospeed(&options, AQH_SERIAL_BAUDRATE); if (rv<0) { DBG_ERROR(NULL, "Error on cfsetospeed(%s): %s (%d)", sr->deviceName, strerror(errno), errno); return GWEN_ERROR_IO; } - options.c_cflag &= ~PARENB; - options.c_cflag &= ~CSTOPB; /* use one stopbit insteadof 2 */ - options.c_cflag &= ~CSIZE; - options.c_cflag |= CS8; - - options.c_cflag &= ~CRTSCTS; /* disable HW flow control */ - options.c_iflag &= ~(IXON | IXOFF | IXANY); /* disable SW flow control */ - - options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /* raw input */ + rv=tcflush(fd, TCIOFLUSH); + if (rv<0) { + DBG_ERROR(NULL, "Error on tcflush(%s): %s (%d)", sr->deviceName, strerror(errno), errno); + return GWEN_ERROR_IO; + } rv=tcsetattr(fd, TCSANOW, &options); if (rv<0) { @@ -135,8 +152,30 @@ void AQH_Serial_Close(AQH_SERIAL *sr) +int AQH_Serial_IsOpen(AQH_SERIAL *sr) +{ + if (sr->fd<0) { + DBG_ERROR(NULL, "Device not open"); + return GWEN_ERROR_NOT_OPEN; + } + else { + struct termios options; + int rv; + + rv=tcgetattr(sr->fd, &options); + if (rv<0) { + DBG_ERROR(NULL, "Error on tcgetattr(%s): %s (%d)", sr->deviceName, strerror(errno), errno); + return GWEN_ERROR_IO; + } + return 1; + } +} + + + int AQH_Serial_Recv(AQH_SERIAL *sr, uint8_t *buf, int len) { +#if 0 int rv; uint8_t *bufSaved; int bytesReceived=0; @@ -147,7 +186,7 @@ int AQH_Serial_Recv(AQH_SERIAL *sr, uint8_t *buf, int len) /* destination, msg length */ rv=_readForced(sr, buf, 2); if (rv<0) { - DBG_INFO(NULL, "here (%d)", rv); + DBG_ERROR(NULL, "here (%d)", rv); return rv; } msgLen=buf[1]; @@ -156,7 +195,7 @@ int AQH_Serial_Recv(AQH_SERIAL *sr, uint8_t *buf, int len) /* read message and XOR byte */ rv=_readForced(sr, buf, msgLen+1); /* add one byte for XOR checksum */ if (rv<0) { - DBG_INFO(NULL, "here (%d)", rv); + DBG_ERROR(NULL, "here (%d)", rv); return rv; } buf+=msgLen; @@ -164,28 +203,30 @@ int AQH_Serial_Recv(AQH_SERIAL *sr, uint8_t *buf, int len) bytesReceived=msgLen+3; rv=_check(bufSaved, bytesReceived); if (rv<0) { - DBG_INFO(NULL, "here (%d)", rv); + DBG_ERROR(NULL, "here (%d)", rv); return rv; } return bytesReceived; +#endif } int AQH_Serial_Send(AQH_SERIAL *sr, const uint8_t *ptr, uint8_t len) { +#if 0 int rv; rv=_check(ptr, len); if (rv<0) { - DBG_INFO(NULL, "here (%d)", rv); + DBG_ERROR(NULL, "here (%d)", rv); return rv; } rv=_attnLow(sr); if (rv<0) { - DBG_INFO(NULL, "here (%d)", rv); + DBG_ERROR(NULL, "here (%d)", rv); return rv; } @@ -193,13 +234,14 @@ int AQH_Serial_Send(AQH_SERIAL *sr, const uint8_t *ptr, uint8_t len) rv=_writeForced(sr, ptr, len); if (rv<0) { - DBG_INFO(NULL, "here (%d)", rv); + DBG_ERROR(NULL, "here (%d)", rv); _attnHigh(sr); return rv; } _attnHigh(sr); return 0; +#endif } @@ -211,7 +253,7 @@ int AQH_Serial_SendPacket(AQH_SERIAL *sr, uint8_t destAddr, const uint8_t *ptr, rv=_attnLow(sr); if (rv<0) { - DBG_INFO(NULL, "here (%d)", rv); + DBG_ERROR(NULL, "here (%d)", rv); return rv; } @@ -220,7 +262,7 @@ int AQH_Serial_SendPacket(AQH_SERIAL *sr, uint8_t destAddr, const uint8_t *ptr, /* send dest address */ rv=_writeForced(sr, &destAddr, 1); if (rv<0) { - DBG_INFO(NULL, "here (%d)", rv); + DBG_ERROR(NULL, "here (%d)", rv); _attnHigh(sr); return rv; } @@ -229,7 +271,7 @@ int AQH_Serial_SendPacket(AQH_SERIAL *sr, uint8_t destAddr, const uint8_t *ptr, /* send msg len */ rv=_writeForced(sr, &len, 1); if (rv<0) { - DBG_INFO(NULL, "here (%d)", rv); + DBG_ERROR(NULL, "here (%d)", rv); _attnHigh(sr); return rv; } @@ -241,7 +283,7 @@ int AQH_Serial_SendPacket(AQH_SERIAL *sr, uint8_t destAddr, const uint8_t *ptr, /* send message */ rv=_writeForced(sr, ptr, len); if (rv<0) { - DBG_INFO(NULL, "here (%d)", rv); + DBG_ERROR(NULL, "here (%d)", rv); _attnHigh(sr); return rv; } @@ -253,7 +295,7 @@ int AQH_Serial_SendPacket(AQH_SERIAL *sr, uint8_t destAddr, const uint8_t *ptr, /* send XOR checksum */ rv=_writeForced(sr, &x, 1); if (rv<0) { - DBG_INFO(NULL, "here (%d)", rv); + DBG_ERROR(NULL, "here (%d)", rv); _attnHigh(sr); return rv; } @@ -287,7 +329,7 @@ int _attnLow(AQH_SERIAL *sr) DBG_ERROR(NULL, "Error on ioctl(%s): %s (%d)", sr->deviceName, strerror(errno), errno); return GWEN_ERROR_IO; } - + sr->intendedAttnState=0; return 0; } @@ -311,6 +353,7 @@ int _attnHigh(AQH_SERIAL *sr) return GWEN_ERROR_IO; } + sr->intendedAttnState=1; return 0; } @@ -366,43 +409,10 @@ int _writeForced(AQH_SERIAL *sr, const uint8_t *buf, uint8_t len) -void AQH_Serial_PacketReceived(AQH_SERIAL *sr, const uint8_t *ptr, uint8_t len) +void AQH_Serial_PacketReceived(AQH_SERIAL *sr, AQH_MSG *msg) { if (sr->packetReceivedFn) - sr->packetReceivedFn(sr, ptr, len); -} - - - -int _check(const uint8_t *ptr, uint8_t len) -{ - int i; - uint8_t x=0; - - for (i=0; ipacketReceivedFn(sr, msg); } @@ -410,135 +420,180 @@ uint8_t _calcChecksum(const uint8_t *ptr, uint8_t len) int _readFromFd(AQH_SERIAL *sr) { int rv; - uint8_t pos; - uint8_t *buf; + uint8_t buffer[AQH_SERIAL_BUFFERSIZE*2]; int len; + int i; - pos=sr->readPos; - buf=sr->readBuffer+pos; - len=sr->bytesToRead; - rv=(int) read(sr->fd, buf, len); - if (rv<0) { - if (errno!=EINTR) { - DBG_ERROR(NULL, "Error on readFromFd(%s): %s (%d)", sr->deviceName, strerror(errno), errno); + do { + if (!AQH_Serial_IsOpen(sr)) { + DBG_ERROR(NULL, "Disconnected"); return GWEN_ERROR_IO; } - return 0; - } - else if (rv==0) { - DBG_ERROR(NULL, "EOF met on read(%s)", sr->deviceName); + rv=read(sr->fd, buffer, sizeof(buffer)); + } while( (rv<0) && errno==EINTR); + if (rv<0) { + DBG_ERROR(NULL, "Error on read(%s): %s (%d)", sr->deviceName, strerror(errno), errno); return GWEN_ERROR_IO; } - else { - sr->readPos+=rv; - sr->bytesToRead-=rv; + len=rv; - if (sr->readPos==2) { - uint8_t i; - - /* we have 2 bytes now, so we now the total msg len */ - i=sr->readBuffer[1]; - i++; /* remainder of message plus XOR byte */ - sr->bytesToRead=i; + for (i=0; icurrentlyReceivedMsg==NULL) + sr->currentlyReceivedMsg=AQH_Msg_new(); + rv=AQH_Msg_AddByte(sr->currentlyReceivedMsg, buffer[i]); + if (rv<0) { + DBG_ERROR(NULL, "here (%d)", rv); + return rv; } - else { - if (sr->bytesToRead==0) { - /* msg received, check */ - if (_check(sr->readBuffer, sr->readPos)<0) { - DBG_INFO(0, "here (%d)", rv); - sr->readPos=0; - sr->bytesToRead=2; - return 0; - } - /* valid msg received, handle */ - AQH_Serial_PacketReceived(sr, sr->readBuffer, sr->readPos); - sr->readPos=0; - sr->bytesToRead=2; + rv=AQH_Msg_IsMsgComplete(sr->currentlyReceivedMsg); + if (rv<0) { + /* invalid message */ + DBG_ERROR(NULL, "Invalid message, discarding"); + AQH_Msg_free(sr->currentlyReceivedMsg); + sr->currentlyReceivedMsg=NULL; + rv=_discardInput(sr); + if (rv<0) { + DBG_ERROR(NULL, "here (%d)", rv); + return rv; + } + } + else if (rv>0) { + if (!AQH_Msg_IsChecksumValid(sr->currentlyReceivedMsg)) { + DBG_ERROR(NULL, "Invalid checksum, discarding message"); + AQH_Msg_free(sr->currentlyReceivedMsg); + sr->currentlyReceivedMsg=NULL; + rv=_discardInput(sr); + if (rv<0) { + DBG_ERROR(NULL, "here (%d)", rv); + return rv; + } + } + else { + /* valid msg received, handle */ + AQH_Serial_PacketReceived(sr, sr->currentlyReceivedMsg); + //AQH_Msg_List_Add(sr->currentlyReceivedMsg, sr->receivedMessageList); + sr->currentlyReceivedMsg=NULL; } } - return 0; } + + return 0; } int _writeToFd(AQH_SERIAL *sr) { - if (sr->bytesToWrite) { - int rv; + AQH_MSG *msg; + + msg=AQH_Msg_List_First(sr->sendMessageList); + if (msg) { uint8_t pos; - uint8_t *buf; int len; - - pos=sr->writePos; - buf=sr->writeBuffer+pos; - len=sr->bytesToWrite; - rv=(int) write(sr->fd, buf, len); - if (rv<0) { - if (errno!=EINTR) { - DBG_ERROR(NULL, "Error on writeToFd(%s): %s (%d)", sr->deviceName, strerror(errno), errno); - return GWEN_ERROR_IO; + int remaining; + int rv; + + pos=AQH_Msg_GetCurrentPos(msg); + remaining=AQH_Msg_GetRemainingBytes(msg); + if (remaining>0) { + const uint8_t *buf; + + if (sr->intendedAttnState==1) { + rv=_attnLow(sr); + if (rv<0) { + DBG_ERROR(NULL, "here (%d)", rv); + return rv; + } + usleep(AQH_SERIAL_BYTE_MICROSECS/5); + } + + buf=AQH_Msg_GetBuffer(msg)+pos; + do { + if (!AQH_Serial_IsOpen(sr)) { + DBG_ERROR(NULL, "Disconnected"); + return GWEN_ERROR_IO; + } + rv=write(sr->fd, buf, remaining); + } while(rv<0 && errno==EINTR); + if (rv<0) { + DBG_ERROR(NULL, "Error on write(%s): %s (%d)", sr->deviceName, strerror(errno), errno); + return GWEN_ERROR_IO; + } + AQH_Msg_IncCurrentPos(msg, rv); + if (rv==remaining) { + rv=_attnHigh(sr); + // TODO: callback msg sent + AQH_Msg_List_Del(msg); + AQH_Msg_free(msg); + if (rv<0) { + DBG_ERROR(NULL, "here (%d)", rv); + return rv; + } } - return 0; - } - else { - sr->writePos+=rv; - sr->bytesToWrite-=rv; - if (sr->bytesToWrite==0) - _attnHigh(sr); - return 0; } } - return 0; } -int AQH_Serial_StartWriting(AQH_SERIAL *sr, const uint8_t *ptr, uint8_t len) +int _discardInput(AQH_SERIAL *sr) +{ + int rv; + uint8_t buffer[AQH_SERIAL_BUFFERSIZE]; + + do { + if (!AQH_Serial_IsOpen(sr)) { + DBG_ERROR(NULL, "Disconnected"); + return GWEN_ERROR_IO; + } + rv=read(sr->fd, buffer, sizeof(buffer)); + } while( (rv>0 || (rv<0) && errno==EINTR)); + return 0; +} + + + +int AQH_Serial_AddMessageToSend(AQH_SERIAL *sr, AQH_MSG *msg) { int rv; - if (sr->bytesToWrite) { - DBG_ERROR(NULL, "Write buffer in use"); - return GWEN_ERROR_TRY_AGAIN; + rv=AQH_Msg_IsMsgComplete(msg); + if (rv!=1) { + DBG_ERROR(NULL, "Message not complete"); + return GWEN_ERROR_BAD_DATA; } - - memmove(sr->writeBuffer, ptr, len); - sr->bytesToWrite=len; - sr->writePos=0; - - rv=_attnLow(sr); - if (rv<0) { - DBG_INFO(NULL, "here (%d)", rv); - return rv; + if (!AQH_Msg_IsChecksumValid(msg)) { + DBG_ERROR(NULL, "Checksum is invalid"); + return GWEN_ERROR_BAD_DATA; } - - usleep(50); + AQH_Msg_RewindCurrentPos(msg); + AQH_Msg_List_Add(msg, sr->sendMessageList); return 0; } - int AQH_Serial_Loop(AQH_SERIAL *sr) { fd_set readSet; fd_set writeSet; + int somethingToWrite; struct timeval tv; int rv; tv.tv_sec=2; tv.tv_usec=0; - if (sr->bytesToWrite) { + somethingToWrite=(AQH_Msg_List_First(sr->sendMessageList)!=NULL)?1:0; + if (somethingToWrite) { FD_ZERO(&writeSet); FD_SET(sr->fd, &writeSet); } FD_ZERO(&readSet); FD_SET(sr->fd, &readSet); - rv=select(sr->fd+1, &readSet, (sr->bytesToWrite)?(&writeSet):NULL, NULL, &tv); + rv=select(sr->fd+1, &readSet, somethingToWrite?(&writeSet):NULL, NULL, &tv); if (rv<0) { if (errno!=EINTR) { DBG_ERROR(NULL, "Error on select"); @@ -549,22 +604,29 @@ int AQH_Serial_Loop(AQH_SERIAL *sr) if (FD_ISSET(sr->fd, &readSet)) { rv=_readFromFd(sr); if (rv<0) { - DBG_INFO(NULL, "here (%d)", rv); + DBG_ERROR(NULL, "here (%d)", rv); return rv; } } - if (FD_ISSET(sr->fd, &writeSet)) { + if (somethingToWrite && FD_ISSET(sr->fd, &writeSet)) { rv=_writeToFd(sr); if (rv<0) { - DBG_INFO(NULL, "here (%d)", rv); - return rv; + DBG_ERROR(NULL, "here (%d)", rv); + return rv; } } } else if (rv==0) { /* timeout */ - sr->readPos=0; - sr->bytesToRead=2; + if (sr->currentlyReceivedMsg) { + AQH_Msg_free(sr->currentlyReceivedMsg); + sr->currentlyReceivedMsg=NULL; + rv=_discardInput(sr); + if (rv<0) { + DBG_ERROR(NULL, "here (%d)", rv); + return rv; + } + } } return 0; diff --git a/aqhome/serial.h b/aqhome/serial.h index c3baeb7..ba953ed 100644 --- a/aqhome/serial.h +++ b/aqhome/serial.h @@ -10,6 +10,7 @@ #define AQH_SERIAL_H #include +#include "aqhome/msg.h" #include @@ -24,7 +25,7 @@ extern "C" { typedef struct AQH_SERIAL AQH_SERIAL; -typedef void (*AQH_SERIAL_PACKETRECEIVED_FN)(AQH_SERIAL *sr, const uint8_t *ptr, uint8_t len); +typedef void (*AQH_SERIAL_PACKETRECEIVED_FN)(AQH_SERIAL *sr, AQH_MSG *msg); @@ -44,6 +45,8 @@ AQHOME_API int AQH_Serial_SendPacket(AQH_SERIAL *sr, uint8_t destAddr, const uin AQHOME_API int AQH_Serial_Loop(AQH_SERIAL *sr); +AQHOME_API int AQH_Serial_AddMessageToSend(AQH_SERIAL *sr, AQH_MSG *msg); + AQHOME_API int AQH_Serial_StartWriting(AQH_SERIAL *sr, const uint8_t *ptr, uint8_t len); diff --git a/aqhome/serial_p.h b/aqhome/serial_p.h index 5bf30d5..8f57695 100644 --- a/aqhome/serial_p.h +++ b/aqhome/serial_p.h @@ -11,6 +11,7 @@ #include "aqhome/serial.h" +#include #include @@ -22,14 +23,14 @@ struct AQH_SERIAL { char *deviceName; int fd; uint8_t address; + int intendedAttnState; - uint8_t readBuffer[AQH_SERIAL_BUFFERSIZE]; - uint8_t bytesToRead; - uint8_t readPos; + AQH_MSG *currentlyReceivedMsg; - uint8_t writeBuffer[AQH_SERIAL_BUFFERSIZE]; - uint8_t bytesToWrite; - uint8_t writePos; + AQH_MSG_LIST *receivedMessageList; + AQH_MSG_LIST *sendMessageList; + + struct termios previousOptions; AQH_SERIAL_PACKETRECEIVED_FN packetReceivedFn; };