diff --git a/apps/0BUILD b/apps/0BUILD index a418765..a064999 100644 --- a/apps/0BUILD +++ b/apps/0BUILD @@ -7,6 +7,7 @@ aqhome-tool aqhome-mqttlog aqhome-data + aqhome-nodes diff --git a/apps/aqhome-data/c_addvalue.c b/apps/aqhome-data/c_addvalue.c index 9c62122..4f68626 100644 --- a/apps/aqhome-data/c_addvalue.c +++ b/apps/aqhome-data/c_addvalue.c @@ -17,7 +17,7 @@ #include "aqhome/ipc/data/ipc_data.h" #include "aqhome/ipc/endpoint_ipc.h" #include "aqhome/ipc/msg_ipc_result.h" -#include "aqhome/ipc/data/msg_data_addvalue.h" +#include "aqhome/ipc/data/msg_data_value.h" #include "aqhome/ipc/msg_ipc_tag16.h" #include @@ -59,13 +59,13 @@ void AqHomeData_HandleAddValue(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GW if (tagList) { const GWEN_TAG16 *tag; - tag=GWEN_Tag16_List_FindFirstByTagType(tagList, AQH_MSGDATA_ADDVALUE_TAGS_NAME); + tag=GWEN_Tag16_List_FindFirstByTagType(tagList, AQH_MSGDATA_VALUE_TAGS_NAME); valueName=tag?GWEN_Tag16_GetTagDataAsNewString(tag, NULL):NULL; - tag=GWEN_Tag16_List_FindFirstByTagType(tagList, AQH_MSGDATA_ADDVALUE_TAGS_UNITS); + tag=GWEN_Tag16_List_FindFirstByTagType(tagList, AQH_MSGDATA_VALUE_TAGS_UNITS); valueUnits=tag?GWEN_Tag16_GetTagDataAsNewString(tag, NULL):NULL; - tag=GWEN_Tag16_List_FindFirstByTagType(tagList, AQH_MSGDATA_ADDVALUE_TAGS_TYPE); + tag=GWEN_Tag16_List_FindFirstByTagType(tagList, AQH_MSGDATA_VALUE_TAGS_TYPE); valueType=tag?GWEN_Tag16_GetTagDataAsUint32(tag, 0):0; } diff --git a/apps/aqhome-data/c_getlastdatapoint.c b/apps/aqhome-data/c_getlastdatapoint.c index 8771b76..fc44a1b 100644 --- a/apps/aqhome-data/c_getlastdatapoint.c +++ b/apps/aqhome-data/c_getlastdatapoint.c @@ -14,9 +14,11 @@ #include "./c_getlastdatapoint.h" #include "./aqhome_data_p.h" #include "aqhome/ipc/data/ipc_data.h" -#include "aqhome/ipc/data/msg_data_datapoints.h" +#include "aqhome/ipc/data/msg_data_value.h" +#include "aqhome/ipc/data/msg_data_singledata.h" #include "aqhome/ipc/endpoint_ipc.h" #include "aqhome/ipc/msg_ipc_result.h" +#include "aqhome/ipc/msg_ipc_tag16.h" #include #include @@ -46,69 +48,60 @@ void AqHomeData_HandleGetLastDataPoint(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *recvdMsg) { GWEN_MSG *outMsg; - int resultCode=0; + int resultCode=AQH_MSG_IPC_SUCCESS; if (AQH_IpcEndpoint_GetPermissions(ep) & AQH_IPCENDPOINT_PERMS_READDATA) { - if (AQH_DataPointsDataIpcMsg_IsValid(recvdMsg)) { - const char *valueName; + GWEN_TAG16_LIST *tagList; + const AQH_VALUE *value; + char *valueName=NULL; - valueName=AQH_DataPointsDataIpcMsg_GetValueName(recvdMsg); - if (valueName) { - const AQH_VALUE *value; + tagList=AQH_Tag16IpcMsg_ParseTags(recvdMsg, 0); + if (tagList) { + const GWEN_TAG16 *tag; - value=AQH_Storage_GetValueByNameForSystem(aqh->storage, valueName); - if (value) { - uint64_t valueId; - uint64_t timestamp=0; - union {double f; uint64_t i;} u; - int rv; + tag=GWEN_Tag16_List_FindFirstByTagType(tagList, AQH_MSGDATA_VALUE_TAGS_NAME); + valueName=tag?GWEN_Tag16_GetTagDataAsNewString(tag, NULL):NULL; + } - valueId=AQH_Value_GetId(value); - rv=AQH_Storage_GetLastDataPoint(aqh->storage, valueId, ×tamp, &(u.f)); - if (rv<0) { - switch(rv) { - case GWEN_ERROR_INVALID: resultCode=AQH_MSG_IPC_ERROR_INVALID; break; - case GWEN_ERROR_NO_DATA: resultCode=AQH_MSG_IPC_ERROR_NODATA; break; - default: resultCode=AQH_MSG_IPC_ERROR_GENERIC; break; - } - } - else { - uint64_t array[2]; + value=AQH_Storage_GetValueByNameForSystem(aqh->storage, valueName); + if (value) { + uint64_t timestamp=0; + double data=0.0; + int rv; - array[0]=timestamp; - array[1]=u.i; - outMsg=AQH_DataPointsDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_GETLASTDATA_RSP, AQH_MSGDATA_DATAPOINTS_FLAGS_LASTMSG, - valueId, - AQH_Value_GetNameForSystem(value), - AQH_Value_GetValueUnits(value), - array, 1); - GWEN_MsgEndpoint_AddSendMessage(ep, outMsg); - return; - } - } - else { - DBG_INFO(NULL, "Value \"%s\" not found", valueName); - resultCode=AQH_MSG_IPC_ERROR_NOTFOUND; - } + rv=AQH_Storage_GetLastDataPoint(aqh->storage, AQH_Value_GetId(value), ×tamp, &data); + if (rv<0) { + switch(rv) { + case GWEN_ERROR_INVALID: resultCode=AQH_MSG_IPC_ERROR_INVALID; break; + case GWEN_ERROR_NO_DATA: resultCode=AQH_MSG_IPC_ERROR_NODATA; break; + default: resultCode=AQH_MSG_IPC_ERROR_GENERIC; break; + } } else { - DBG_INFO(NULL, "No value name in request"); - resultCode=AQH_MSG_IPC_ERROR_INVALID; + outMsg=AQH_SingleDataDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_GETLASTDATA_RSP, + AQH_Value_GetNameForSystem(value), + AQH_Value_GetValueUnits(value), + AQH_Value_GetValueType(value), + timestamp, data); + GWEN_MsgEndpoint_AddSendMessage(ep, outMsg); + free(valueName); + return; } } else { - DBG_INFO(NULL, "Invalid request message"); - resultCode=AQH_MSG_IPC_ERROR_INVALID; + DBG_INFO(NULL, "Value \"%s\" not found", valueName); + resultCode=AQH_MSG_IPC_ERROR_NOTFOUND; } + free(valueName); } else { DBG_ERROR(AQH_LOGDOMAIN, "No permissions to read data"); resultCode=AQH_MSG_IPC_ERROR_PERMS; } + outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT, resultCode); GWEN_MsgEndpoint_AddSendMessage(ep, outMsg); } - diff --git a/apps/aqhome-data/c_updatedata.c b/apps/aqhome-data/c_updatedata.c index d681829..77c718c 100644 --- a/apps/aqhome-data/c_updatedata.c +++ b/apps/aqhome-data/c_updatedata.c @@ -15,9 +15,10 @@ #include "./aqhome_data_p.h" #include "./loop.h" #include "aqhome/ipc/data/ipc_data.h" -#include "aqhome/ipc/data/msg_data_datapoints.h" +#include "aqhome/ipc/data/msg_data_multidata.h" #include "aqhome/ipc/endpoint_ipc.h" #include "aqhome/ipc/msg_ipc_result.h" +#include "aqhome/ipc/msg_ipc_tag16.h" #include @@ -36,7 +37,7 @@ * ------------------------------------------------------------------------------------------------ */ -static int _readDataPoints(AQHOME_DATA *aqh, const AQH_VALUE *v, const uint64_t *dataPoints, uint32_t numValues); +static int _storeDataPoints(AQHOME_DATA *aqh, const AQH_VALUE *v, const uint64_t *dataPoints, int numValues); static void _sendDataChangedMsgToAllClients(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *epSrc, const AQH_VALUE *v, const uint64_t *dataPoints, uint32_t numValues); @@ -51,63 +52,58 @@ void AqHomeData_HandleUpdateData(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const { GWEN_MSG *outMsg; int resultCode=AQH_MSG_IPC_SUCCESS; + GWEN_TAG16_LIST *tagList; + char *valueName=NULL; + char *valueUnits=NULL; + int valueType; + const uint64_t *dataPoints=NULL; + unsigned int numberOfPoints=0; - if (AQH_IpcEndpoint_GetPermissions(ep) & AQH_IPCENDPOINT_PERMS_ADDDATA) { - if (AQH_DataPointsDataIpcMsg_IsValid(recvdMsg)) { - uint32_t numValues; - - numValues=AQH_DataPointsDataIpcMsg_GetNumValues(recvdMsg); - if (numValues) { - const char *s; - - s=AQH_DataPointsDataIpcMsg_GetValueName(recvdMsg); - if (s && *s) { - AQH_VALUE *v; - - v=AqHomeData_GetOrCreateValueForDriver(aqh, ep, s, AQH_DataPointsDataIpcMsg_GetUnits(recvdMsg), 0); - if (v==NULL) { - resultCode=AQH_MSG_IPC_ERROR_PERMS; - } - else { - const uint64_t *dataPoints; - - dataPoints=AQH_DataPointsDataIpcMsg_GetDataPoints(recvdMsg); - if (dataPoints) - resultCode=_readDataPoints(aqh, v, dataPoints, numValues); - else { - DBG_INFO(NULL, "No datapoints"); - resultCode=AQH_MSG_IPC_ERROR_BADDATA; - } - if (resultCode==AQH_MSG_IPC_SUCCESS) - _sendDataChangedMsgToAllClients(aqh, ep, v, dataPoints, numValues); - } - } - else { - DBG_INFO(NULL, "Value without name "); - resultCode=AQH_MSG_IPC_ERROR_INVALID; - } - } - else { - DBG_INFO(NULL, "No datapoints"); - resultCode=AQH_MSG_IPC_ERROR_BADDATA; - } + tagList=AQH_Tag16IpcMsg_ParseTags(recvdMsg, 0); + if (tagList) { + const GWEN_TAG16 *tag; + + tag=GWEN_Tag16_List_FindFirstByTagType(tagList, AQH_MSGDATA_MULTIDATA_TAGS_NAME); + valueName=tag?GWEN_Tag16_GetTagDataAsNewString(tag, NULL):NULL; + + tag=GWEN_Tag16_List_FindFirstByTagType(tagList, AQH_MSGDATA_MULTIDATA_TAGS_UNITS); + valueUnits=tag?GWEN_Tag16_GetTagDataAsNewString(tag, NULL):NULL; + + tag=GWEN_Tag16_List_FindFirstByTagType(tagList, AQH_MSGDATA_MULTIDATA_TAGS_TYPE); + valueType=tag?GWEN_Tag16_GetTagDataAsUint32(tag, 0):0; + + tag=GWEN_Tag16_List_FindFirstByTagType(tagList, AQH_MSGDATA_MULTIDATA_TAGS_DATA); + dataPoints=(const uint64_t*)GWEN_Tag16_GetTagData(tag); + numberOfPoints=(tag?GWEN_Tag16_GetTagLength(tag):0)/(2*sizeof(uint64_t)); + } + + if (numberOfPoints>0) { + AQH_VALUE *value; + + value=AqHomeData_GetOrCreateValueForDriver(aqh, ep, valueName, valueUnits, valueType); + if (value) { + resultCode=_storeDataPoints(aqh, value, dataPoints, numberOfPoints); + if (resultCode==AQH_MSG_IPC_SUCCESS) + _sendDataChangedMsgToAllClients(aqh, ep, value, dataPoints, numberOfPoints); } else { - DBG_INFO(NULL, "Invalid message received"); - resultCode=AQH_MSG_IPC_ERROR_BADDATA; + DBG_INFO(NULL, "No permissions to add datapoint for value \"%s\"", valueName); + resultCode=AQH_MSG_IPC_ERROR_PERMS; } } else { - DBG_ERROR(AQH_LOGDOMAIN, "No permissions to add data"); - resultCode=AQH_MSG_IPC_ERROR_PERMS; + DBG_INFO(NULL, "No datapoints"); + resultCode=AQH_MSG_IPC_ERROR_INVALID; } + free(valueName); outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT, resultCode); GWEN_MsgEndpoint_AddSendMessage(ep, outMsg); } -int _readDataPoints(AQHOME_DATA *aqh, const AQH_VALUE *v, const uint64_t *dataPoints, uint32_t numValues) + +int _storeDataPoints(AQHOME_DATA *aqh, const AQH_VALUE *v, const uint64_t *dataPoints, int numValues) { uint32_t i; @@ -145,13 +141,12 @@ void _sendDataChangedMsgToAllClients(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *epSrc, GWEN_MSG *msg; DBG_INFO(AQH_LOGDOMAIN, "Sending update msg to endpoint %s", GWEN_MsgEndpoint_GetName(ep)); - msg=AQH_DataPointsDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_DATACHANGED, - 0, /* flags */ - AQH_Value_GetId(v), - AQH_Value_GetNameForSystem(v), - AQH_Value_GetValueUnits(v), - dataPoints, numValues); - GWEN_MsgEndpoint_AddSendMessage(ep, msg); + msg=AQH_MultiDataDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_DATACHANGED, + AQH_Value_GetNameForSystem(v), + AQH_Value_GetValueUnits(v), + AQH_Value_GetValueType(v), + dataPoints, numValues); + GWEN_MsgEndpoint_AddSendMessage(ep, msg); } else { DBG_INFO(AQH_LOGDOMAIN, "Endpoint %s doesn't want updates", GWEN_MsgEndpoint_GetName(ep)); diff --git a/apps/aqhome-nodes/0BUILD b/apps/aqhome-nodes/0BUILD new file mode 100644 index 0000000..d714c0c --- /dev/null +++ b/apps/aqhome-nodes/0BUILD @@ -0,0 +1,83 @@ + + + + + + + + $(gwenhywfar_cflags) + -I$(topsrcdir) + -I$(topbuilddir) + + + + --include=$(builddir) + --include=$(srcdir) + + + $(visibility_cflags) + + + + + + + + + + + + + + + + + + aqhomed.h + aqhomed_p.h + init.h + fini.h + loop.h + loop_tty.h + loop_tty_ipc.h + loop_tty_broker.h + loop_ipc.h + db.h + tty_log.h + + + + $(local/typefiles) + main.c + aqhomed.c + init.c + fini.c + loop.c + loop_tty.c + loop_tty_ipc.c + loop_tty_broker.c + loop_ipc.c + db.c + tty_log.c + + + + aqhome + + + + $(gwenhywfar_libs) + + + + + + + + + + + + + + diff --git a/apps/aqhome-nodes/aqhomed.c b/apps/aqhome-nodes/aqhomed.c new file mode 100644 index 0000000..0c3b5c4 --- /dev/null +++ b/apps/aqhome-nodes/aqhomed.c @@ -0,0 +1,159 @@ +/**************************************************************************** + * 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 "./aqhomed_p.h" +#include "./tty_log.h" + +#include "aqhome/msg/endpoint_tty.h" +#include "aqhome/ipc/endpoint_ipc.h" + +#include +#include + + + +/* ------------------------------------------------------------------------------------------------ + * defines + * ------------------------------------------------------------------------------------------------ + */ + +#define I18N(msg) msg +#define I18S(msg) msg + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + + + + +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ + +AQHOMED *AqHomed_new(void) +{ + AQHOMED *aqh; + + GWEN_NEW_OBJECT(AQHOMED, aqh); + aqh->rootEndpoint=GWEN_MsgEndpoint_new("root", 0); + aqh->nodeDb=AQH_NodeDb_new(); + + return aqh; +} + + + +void AqHomed_free(AQHOMED *aqh) +{ + if (aqh) { + GWEN_MsgEndpoint_free(aqh->rootEndpoint); + aqh->rootEndpoint=NULL; + aqh->ttyEndpoint=NULL; + aqh->ipcdEndpoint=NULL; + aqh->brokerEndpoint=NULL; + GWEN_DB_Group_free(aqh->dbArgs); + AQH_NodeDb_free(aqh->nodeDb); + aqh->dbArgs=NULL; + free(aqh->logFile); + free(aqh->pidFile); + free(aqh->dbFile); + + GWEN_FREE_OBJECT(aqh); + } +} + + + +GWEN_MSG_ENDPOINT *AqHomed_GetTtyEndpoint(const AQHOMED *aqh) +{ + return aqh?aqh->ttyEndpoint:NULL; +} + + + +GWEN_MSG_ENDPOINT *AqHomed_GetIpcdEndpoint(const AQHOMED *aqh) +{ + return aqh?aqh->ipcdEndpoint:NULL; +} + + + +GWEN_MSG_ENDPOINT *AqHomed_GetBrokerEndpoint(const AQHOMED *aqh) +{ + return aqh?aqh->brokerEndpoint:NULL; +} + + + +GWEN_DB_NODE *AqHomed_GetDbArgs(const AQHOMED *aqh) +{ + return aqh?aqh->dbArgs:NULL; +} + + + +const char *AqHomed_GetLogFile(const AQHOMED *aqh) +{ + return aqh?aqh->logFile:NULL; +} + + + +void AqHomed_SetLogFile(AQHOMED *aqh, const char *s) +{ + if (aqh) { + free(aqh->logFile); + aqh->logFile=s?strdup(s):NULL; + } +} + + + +const char *AqHomed_GetPidFile(const AQHOMED *aqh) +{ + return aqh?aqh->pidFile:NULL; +} + + + +void AqHomed_SetPidFile(AQHOMED *aqh, const char *s) +{ + if (aqh) { + free(aqh->pidFile); + aqh->pidFile=s?strdup(s):NULL; + } +} + + + +const char *AqHomed_GetDbFile(const AQHOMED *aqh) +{ + return aqh?aqh->dbFile:NULL; +} + + + +void AqHomed_SetDbFile(AQHOMED *aqh, const char *s) +{ + if (aqh) { + free(aqh->dbFile); + aqh->dbFile=s?strdup(s):NULL; + } +} + + + diff --git a/apps/aqhome-nodes/aqhomed.h b/apps/aqhome-nodes/aqhomed.h new file mode 100644 index 0000000..0d45834 --- /dev/null +++ b/apps/aqhome-nodes/aqhomed.h @@ -0,0 +1,44 @@ +/**************************************************************************** + * 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 AQHOMED_H +#define AQHOMED_H + + +#include +#include + + +#define AQHOME_ENDPOINTGROUP_NODE 1 +#define AQHOME_ENDPOINTGROUP_IPC 2 +#define AQHOME_ENDPOINTGROUP_MQTT 4 + + +typedef struct AQHOMED AQHOMED; + +AQHOMED *AqHomed_new(void); +void AqHomed_free(AQHOMED *aqh); + +GWEN_MSG_ENDPOINT *AqHomed_GetTtyEndpoint(const AQHOMED *aqh); +GWEN_MSG_ENDPOINT *AqHomed_GetIpcdEndpoint(const AQHOMED *aqh); +GWEN_MSG_ENDPOINT *AqHomed_GetBrokerEndpoint(const AQHOMED *aqh); + +GWEN_DB_NODE *AqHomed_GetDbArgs(const AQHOMED *aqh); + +const char *AqHomed_GetLogFile(const AQHOMED *aqh); +void AqHomed_SetLogFile(AQHOMED *aqh, const char *s); + +const char *AqHomed_GetPidFile(const AQHOMED *aqh); +void AqHomed_SetPidFile(AQHOMED *aqh, const char *s); + +const char *AqHomed_GetDbFile(const AQHOMED *aqh); +void AqHomed_SetDbFile(AQHOMED *aqh, const char *s); + +#endif + + diff --git a/apps/aqhome-nodes/aqhomed_p.h b/apps/aqhome-nodes/aqhomed_p.h new file mode 100644 index 0000000..8e7c9d3 --- /dev/null +++ b/apps/aqhome-nodes/aqhomed_p.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 AQHOMED_P_H +#define AQHOMED_P_H + + +#include "./aqhomed.h" + +#include "aqhome/nodes/nodedb.h" + + +/* default values */ +#define AQHOMED_DEFAULT_NODEADDR 240 +#define AQHOMED_DEFAULT_PIDFILE "/var/run/aqhomed-node.pid" +#define AQHOMED_DEFAULT_DEVICE "/dev/ttyUSB0" +#define AQHOMED_DEFAULT_IPC_PORT 45454 +#define AQHOMED_DEFAULT_BROKER_PORT 1899 +#define AQHOMED_DEFAULT_BROKER_CLIENTID "nodes" + + + +struct AQHOMED { + GWEN_MSG_ENDPOINT *rootEndpoint; + + GWEN_MSG_ENDPOINT *ttyEndpoint; + GWEN_MSG_ENDPOINT *ipcdEndpoint; + + GWEN_MSG_ENDPOINT *brokerEndpoint; + + AQH_NODE_DB *nodeDb; + + GWEN_DB_NODE *dbArgs; + + char *dbFile; + char *logFile; + char *pidFile; + + int nodeAddress; +}; + +#endif + diff --git a/apps/aqhome-nodes/db.c b/apps/aqhome-nodes/db.c new file mode 100644 index 0000000..7635d01 --- /dev/null +++ b/apps/aqhome-nodes/db.c @@ -0,0 +1,278 @@ +/**************************************************************************** + * 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 "./db.h" +#include "./aqhomed_p.h" + +#include "aqhome/msg/msg_node.h" +#include "aqhome/msg/msg_sendstats.h" +#include "aqhome/msg/msg_recvstats.h" +#include "aqhome/msg/msg_value2.h" +#include "aqhome/msg/msg_needaddr.h" +#include "aqhome/msg/msg_claimaddr.h" +#include "aqhome/msg/msg_haveaddr.h" +#include "aqhome/msg/msg_device.h" +#include "aqhome/msg/msg_flashready.h" + + +#include +#include +#include +#include +#include + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static void _handleMsgValue2(AQHOMED *aqh, const GWEN_MSG *msg); +static void _handleMsgNeedAddress(AQHOMED *aqh, const GWEN_MSG *msg); +static void _handleMsgClaimAddress(AQHOMED *aqh, const GWEN_MSG *msg); +static void _handleMsgHaveAddress(AQHOMED *aqh, const GWEN_MSG *msg); +static void _handleMsgComSendStat(AQHOMED *aqh, const GWEN_MSG *msg); +static void _handleMsgComRecvStat(AQHOMED *aqh, const GWEN_MSG *msg); +static void _handleMsgDevice(AQHOMED *aqh, const GWEN_MSG *msg); +static void _handleMsgFlashReady(AQHOMED *aqh, const GWEN_MSG *msg); + +static AQH_NODE_INFO *_getOrCreateNodeAndUpdateUidAddr(AQHOMED *aqh, const GWEN_MSG *msg, uint32_t uid); +static void _updateTimestampLastChange(AQH_NODE_INFO *ni); + + + + +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ + +void AqHomed_NodeMsgToDb(AQHOMED *aqh, const GWEN_MSG *msg) +{ + int msgIsValid; + uint8_t msgType; + + DBG_INFO(AQH_LOGDOMAIN, + " - msg %d (%s) from %d to %d", + AQH_NodeMsg_GetMsgType(msg), + AQH_NodeMsg_MsgTypeToChar(AQH_NodeMsg_GetMsgType(msg)), + AQH_NodeMsg_GetSourceAddress(msg), + AQH_NodeMsg_GetDestAddress(msg)); + + msgIsValid=(AQH_NodeMsg_IsChecksumValid(msg) && AQH_NodeMsg_IsMsgComplete(msg)); + msgType=AQH_NodeMsg_GetMsgType(msg); + + if (msgIsValid) { + switch(msgType) { + case AQH_MSG_TYPE_COMSENDSTATS: _handleMsgComSendStat(aqh, msg); break; + case AQH_MSG_TYPE_COMRECVSTATS: _handleMsgComRecvStat(aqh, msg); break; + case AQH_MSG_TYPE_VALUE2: _handleMsgValue2(aqh, msg); break; + case AQH_MSG_TYPE_NEED_ADDRESS: _handleMsgNeedAddress(aqh, msg); break; + case AQH_MSG_TYPE_CLAIM_ADDRESS: _handleMsgClaimAddress(aqh, msg); break; + case AQH_MSG_TYPE_HAVE_ADDRESS: _handleMsgHaveAddress(aqh, msg); break; + case AQH_MSG_TYPE_DEVICE: _handleMsgDevice(aqh, msg); break; + case AQH_MSG_TYPE_FLASH_READY: _handleMsgFlashReady(aqh, msg); break; + default: break; + } + } +} + + + +void _handleMsgValue2(AQHOMED *aqh, const GWEN_MSG *msg) +{ + AQH_NODE_INFO *ni; + uint32_t uid; + + uid=AQH_Value2Msg_GetUid(msg); + ni=_getOrCreateNodeAndUpdateUidAddr(aqh, msg, uid); + if (ni==NULL) { + DBG_INFO(AQH_LOGDOMAIN, "Error handling message"); + } +} + + + +void _handleMsgNeedAddress(AQHOMED *aqh, const GWEN_MSG *msg) +{ + AQH_NODE_INFO *ni; + uint32_t uid; + + uid=AQH_NeedAddrMsg_GetUid(msg); + ni=_getOrCreateNodeAndUpdateUidAddr(aqh, msg, uid); + if (ni==NULL) { + DBG_INFO(AQH_LOGDOMAIN, "Error handling message"); + } +} + + + +void _handleMsgClaimAddress(AQHOMED *aqh, const GWEN_MSG *msg) +{ + AQH_NODE_INFO *ni; + uint32_t uid; + + uid=AQH_ClaimAddrMsg_GetUid(msg); + ni=_getOrCreateNodeAndUpdateUidAddr(aqh, msg, uid); + if (ni==NULL) { + DBG_INFO(AQH_LOGDOMAIN, "Error handling message"); + } +} + + + +void _handleMsgHaveAddress(AQHOMED *aqh, const GWEN_MSG *msg) +{ + AQH_NODE_INFO *ni; + uint32_t uid; + + uid=AQH_HaveAddrMsg_GetUid(msg); + ni=_getOrCreateNodeAndUpdateUidAddr(aqh, msg, uid); + if (ni==NULL) { + DBG_INFO(AQH_LOGDOMAIN, "Error handling message"); + } +} + + + +void _handleMsgComSendStat(AQHOMED *aqh, const GWEN_MSG *msg) +{ + AQH_NODE_INFO *ni; + uint32_t uid; + + uid=AQH_SendStatsMsg_GetUid(msg); + ni=_getOrCreateNodeAndUpdateUidAddr(aqh, msg, uid); + if (ni==NULL) { + DBG_INFO(AQH_LOGDOMAIN, "Error handling message"); + } + AQH_NodeInfo_SetStatsPacketsOut(ni, AQH_SendStatsMsg_GetPacketsOut(msg)); + AQH_NodeInfo_SetStatsCollisions(ni, AQH_SendStatsMsg_GetCollisions(msg)); + AQH_NodeInfo_SetStatsBusy(ni, AQH_SendStatsMsg_GetBusyErrors(msg)); + AQH_NodeDb_SetModified(aqh->nodeDb); + _updateTimestampLastChange(ni); +} + + + +void _handleMsgComRecvStat(AQHOMED *aqh, const GWEN_MSG *msg) +{ + AQH_NODE_INFO *ni; + uint32_t uid; + + uid=AQH_RecvStatsMsg_GetUid(msg); + ni=_getOrCreateNodeAndUpdateUidAddr(aqh, msg, uid); + if (ni==NULL) { + DBG_INFO(AQH_LOGDOMAIN, "Error handling message"); + } + AQH_NodeInfo_SetStatsPacketsIn(ni, AQH_RecvStatsMsg_GetPacketsIn(msg)); + AQH_NodeInfo_SetStatsCrcErrors(ni, AQH_RecvStatsMsg_GetCrcErrors(msg)); + AQH_NodeInfo_SetStatsIoErrors(ni, AQH_RecvStatsMsg_GetIoErrors(msg)); + AQH_NodeDb_SetModified(aqh->nodeDb); + _updateTimestampLastChange(ni); +} + + + +void _handleMsgDevice(AQHOMED *aqh, const GWEN_MSG *msg) +{ + AQH_NODE_INFO *ni; + uint32_t uid; + + uid=AQH_DeviceMsg_GetUid(msg); + ni=_getOrCreateNodeAndUpdateUidAddr(aqh, msg, uid); + if (ni) { + AQH_NodeInfo_SetFirmwareType(ni, AQH_DeviceMsg_GetFirmwareType(msg)); + AQH_NodeInfo_SetFirmwareVersion(ni, (AQH_DeviceMsg_GetFirmwareHigh(msg)<<8) | AQH_DeviceMsg_GetFirmwareLow(msg)); + AQH_NodeInfo_SetModules(ni, AQH_DeviceMsg_GetModuleMask(msg)); + _updateTimestampLastChange(ni); + AQH_NodeDb_SetModified(aqh->nodeDb); + } + else { + DBG_INFO(AQH_LOGDOMAIN, "Error handling message"); + } +} + + + +void _handleMsgFlashReady(AQHOMED *aqh, const GWEN_MSG *msg) +{ + AQH_NODE_INFO *ni; + uint32_t uid; + + uid=AQH_FlashReadyMsg_GetUid(msg); + ni=_getOrCreateNodeAndUpdateUidAddr(aqh, msg, uid); + if (ni) { + AQH_NodeInfo_SetFirmwareType(ni, AQH_FlashReadyMsg_GetFirmwareType(msg)); + AQH_NodeInfo_SetFirmwareVersion(ni, AQH_FlashReadyMsg_GetFirmwareVersion(msg)); + _updateTimestampLastChange(ni); + AQH_NodeDb_SetModified(aqh->nodeDb); + } + else { + DBG_INFO(AQH_LOGDOMAIN, "Error handling message"); + } +} + + + +AQH_NODE_INFO *_getOrCreateNodeAndUpdateUidAddr(AQHOMED *aqh, const GWEN_MSG *msg, uint32_t uid) +{ + uint8_t busAddr; + AQH_NODE_INFO *ni; + + busAddr=AQH_NodeMsg_GetSourceAddress(msg); + ni=AQH_NodeDb_GetNodeInfoByUid(aqh->nodeDb, uid); + if (ni) { + uint8_t storedBusAddr; + + storedBusAddr=AQH_NodeInfo_GetBusAddress(ni); + if (busAddr!=0 && storedBusAddr!=busAddr) { + DBG_INFO(AQH_LOGDOMAIN, "Changed busaddr for %08x from %02x to %02x", uid, storedBusAddr, busAddr); + AQH_NodeInfo_SetBusAddress(ni, busAddr); + _updateTimestampLastChange(ni); + AQH_NodeDb_SetModified(aqh->nodeDb); + } + } + else { + int rv; + + ni=AQH_NodeInfo_new(); + AQH_NodeInfo_SetBusAddress(ni, busAddr); + AQH_NodeInfo_SetUid(ni, uid); + _updateTimestampLastChange(ni); + rv=AQH_NodeDb_AddNodeInfo(aqh->nodeDb, ni); + if (rv<0) { + DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv); + AQH_NodeInfo_free(ni); + return NULL; + } + else { + DBG_INFO(AQH_LOGDOMAIN, "Added node %08x (%02x)", uid, busAddr); + } + } + return ni; +} + + + +void _updateTimestampLastChange(AQH_NODE_INFO *ni) +{ + GWEN_TIMESTAMP *t; + + t=GWEN_Timestamp_NowInLocalTime(); + AQH_NodeInfo_SetTimestampLastChange(ni, t); + GWEN_Timestamp_free(t); +} + + + diff --git a/apps/aqhome-nodes/db.h b/apps/aqhome-nodes/db.h new file mode 100644 index 0000000..cdd5f01 --- /dev/null +++ b/apps/aqhome-nodes/db.h @@ -0,0 +1,23 @@ +/**************************************************************************** + * 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 AQHOMED_DB_H +#define AQHOMED_DB_H + + +#include "./aqhomed.h" + + + +void AqHomed_NodeMsgToDb(AQHOMED *aqh, const GWEN_MSG *msg); + + + +#endif + + diff --git a/apps/aqhome-nodes/fini.c b/apps/aqhome-nodes/fini.c new file mode 100644 index 0000000..f066186 --- /dev/null +++ b/apps/aqhome-nodes/fini.c @@ -0,0 +1,86 @@ +/**************************************************************************** + * 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 "./fini.h" +#include "./aqhomed_p.h" + +#include +#include +#include +#include + + +#include + + + +/* ------------------------------------------------------------------------------------------------ + * defines + * ------------------------------------------------------------------------------------------------ + */ + +#define I18N(msg) msg +#define I18S(msg) msg + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static void _disconnectTree(GWEN_MSG_ENDPOINT *ep); + + + +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ + +void AqHomed_Fini(AQHOMED *aqh) +{ + if (aqh) { + if (aqh->rootEndpoint) { + _disconnectTree(aqh->rootEndpoint); + GWEN_MsgEndpoint_Disconnect(aqh->rootEndpoint); + } + GWEN_MsgEndpoint_free(aqh->rootEndpoint); + aqh->rootEndpoint=NULL; + aqh->ttyEndpoint=NULL; + aqh->ipcdEndpoint=NULL; + aqh->brokerEndpoint=NULL; + + if (aqh->pidFile) + remove(aqh->pidFile); + } +} + + + +void _disconnectTree(GWEN_MSG_ENDPOINT *ep) +{ + GWEN_MSG_ENDPOINT *epChild; + + epChild=GWEN_MsgEndpoint_Tree2_GetFirstChild(ep); + while(epChild) { + _disconnectTree(epChild); + epChild=GWEN_MsgEndpoint_Tree2_GetNext(epChild); + } /* while */ + + GWEN_MsgEndpoint_Disconnect(ep); +} + + + + diff --git a/apps/aqhome-nodes/fini.h b/apps/aqhome-nodes/fini.h new file mode 100644 index 0000000..4e41d91 --- /dev/null +++ b/apps/aqhome-nodes/fini.h @@ -0,0 +1,23 @@ +/**************************************************************************** + * 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 AQHOMED_FINI_H +#define AQHOMED_FINI_H + + +#include "./aqhomed.h" + + + +void AqHomed_Fini(AQHOMED *aqh); + + + +#endif + + diff --git a/apps/aqhome-nodes/init.c b/apps/aqhome-nodes/init.c new file mode 100644 index 0000000..da7d57b --- /dev/null +++ b/apps/aqhome-nodes/init.c @@ -0,0 +1,472 @@ +/**************************************************************************** + * 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 "./init.h" +#include "./aqhomed_p.h" +#include "./tty_log.h" + +#include "aqhome/msg/endpoint_tty.h" +#include "aqhome/ipc/endpoint_ipc.h" +#include "aqhome/ipc/endpoint_ipcclient.h" + +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_TYPES_H +# include +#endif + +#ifdef HAVE_SYS_STAT_H +# include +#endif + +#include +#include +#include +#include +#include +#include + + + +/* ------------------------------------------------------------------------------------------------ + * defines + * ------------------------------------------------------------------------------------------------ + */ + +#define I18N(msg) msg +#define I18S(msg) msg + + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static int _setupTty(AQHOMED *aqh, GWEN_DB_NODE *dbArgs); +static void _setupIpcd(AQHOMED *aqh, GWEN_DB_NODE *dbArgs); +static void _setupBroker(AQHOMED *aqh, GWEN_DB_NODE *dbArgs); +static GWEN_MSG_ENDPOINT *_acceptIpcFn(GWEN_MSG_ENDPOINT *ep, GWEN_SOCKET *sk, const GWEN_INETADDRESS *addr, void *data); +static void _setupLog(AQHOMED *aqh, GWEN_DB_NODE *dbArgs); +static void _setupDb(AQHOMED *aqh, GWEN_DB_NODE *dbArgs); + +static int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs); +static int _createPidFile(const char *pidFilename); + + + +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ + +int AqHomed_Init(AQHOMED *aqh, int argc, char **argv) +{ + GWEN_DB_NODE *dbArgs; + int rv; + const char *s; + + dbArgs=GWEN_DB_Group_new("args"); + rv=_readArgs(argc, argv, dbArgs); + if (rv<0) { + DBG_ERROR(NULL, "Error reading args (%d)", rv); + return rv; + } + aqh->dbArgs=dbArgs; + + s=GWEN_DB_GetCharValue(dbArgs, "pidfile", 0, AQHOMED_DEFAULT_PIDFILE); + if (s && *s) { + AqHomed_SetPidFile(aqh, s); + rv=_createPidFile(s); + if (rv<0) { + DBG_ERROR(NULL, "Error creating PID file (%d)", rv); + return rv; + } + } + + aqh->nodeAddress=GWEN_DB_GetIntValue(dbArgs, "nodeAddress", 0, AQHOMED_DEFAULT_NODEADDR); + + _setupDb(aqh, dbArgs); + + rv=_setupTty(aqh, dbArgs); + if (rv<0) { + DBG_ERROR(NULL, "Error setting up TTY endpoint (%d)", rv); + return rv; + } + + _setupIpcd(aqh, dbArgs); + _setupBroker(aqh, dbArgs); + _setupLog(aqh, dbArgs); + + return 0; +} + + + +int _setupTty(AQHOMED *aqh, GWEN_DB_NODE *dbArgs) +{ + const char *devicePath; + + devicePath=GWEN_DB_GetCharValue(dbArgs, "device", 0, AQHOMED_DEFAULT_DEVICE); + if (devicePath && *devicePath) { + GWEN_MSG_ENDPOINT *epTty; + + epTty=AQH_TtyEndpoint_new(devicePath, AQHOME_ENDPOINTGROUP_NODE); + if (epTty==NULL) { + DBG_ERROR(NULL, "Error creating endpoint TTY"); + return GWEN_ERROR_GENERIC; + } + GWEN_MsgEndpoint_Tree2_AddChild(aqh->rootEndpoint, epTty); + aqh->ttyEndpoint=epTty; + } + else { + DBG_ERROR(NULL, "Missing device path"); + return GWEN_ERROR_GENERIC; + } + + return 0; +} + + + +void _setupIpcd(AQHOMED *aqh, GWEN_DB_NODE *dbArgs) +{ + const char *tcpAddress; + int tcpPort; + + tcpAddress=GWEN_DB_GetCharValue(dbArgs, "tcpAddress", 0, NULL); + tcpPort=GWEN_DB_GetIntValue(dbArgs, "tcpPort", 0, AQHOMED_DEFAULT_IPC_PORT); + + if (tcpAddress && *tcpAddress && tcpPort) { + GWEN_MSG_ENDPOINT *ep; + + ep=GWEN_TcpdEndpoint_new(tcpAddress, tcpPort, NULL, AQHOME_ENDPOINTGROUP_IPC); + GWEN_TcpdEndpoint_SetAcceptFn(ep, _acceptIpcFn, aqh); + + GWEN_MsgEndpoint_Tree2_AddChild(aqh->rootEndpoint, ep); + aqh->ipcdEndpoint=ep; + } +} + + + +void _setupBroker(AQHOMED *aqh, GWEN_DB_NODE *dbArgs) +{ + const char *brokerAddress; + int brokerPort; + const char *brokerClientId; + + brokerAddress=GWEN_DB_GetCharValue(dbArgs, "brokerAddress", 0, NULL); + brokerPort=GWEN_DB_GetIntValue(dbArgs, "brokerPort", 0, AQHOMED_DEFAULT_BROKER_PORT); + brokerClientId=GWEN_DB_GetCharValue(dbArgs, "brokerClientId", 0, AQHOMED_DEFAULT_BROKER_CLIENTID); + + if (brokerAddress && *brokerAddress && brokerPort) { + GWEN_MSG_ENDPOINT *ep; + GWEN_MSG_ENDPOINT *ipcBaseEndpoint; + int rv; + + ep=AQH_ClientIpcEndpoint_new("brokerIpcClient", 0); + ipcBaseEndpoint=AQH_IpcEndpoint_CreateIpcTcpClient(brokerAddress, brokerPort, "brokerPhysEndpoint", 0); + AQH_IpcEndpoint_SetServiceName(ipcBaseEndpoint, brokerClientId); + GWEN_MsgEndpoint_Tree2_AddChild(ep, ipcBaseEndpoint); + + GWEN_MsgEndpoint_Tree2_AddChild(aqh->rootEndpoint, ep); + aqh->brokerEndpoint=ep; + + rv=GWEN_MultilayerEndpoint_StartConnect(ep); + if (rv<0 && rv!=GWEN_ERROR_IN_PROGRESS) { + DBG_ERROR(NULL, "Error connecting to broker server %s:%d (%d), will retry later", brokerAddress, brokerPort, rv); + } + } +} + + + +GWEN_MSG_ENDPOINT *_acceptIpcFn(GWEN_MSG_ENDPOINT *ep, + GWEN_SOCKET *sk, + const GWEN_INETADDRESS *addr, + GWEN_UNUSED void *data) +{ +/* AQHOMED *aqh; + * + * aqh=(AQHOMED*) data; + */ + DBG_INFO(NULL, "Incoming IPC connection"); + return AQH_IpcEndpoint_CreateIpcTcpServiceForSocket(sk, NULL, AQHOME_ENDPOINTGROUP_IPC); +} + + + +void _setupLog(AQHOMED *aqh, GWEN_DB_NODE *dbArgs) +{ + const char *logFile; + + logFile=GWEN_DB_GetCharValue(dbArgs, "logfile", 0, NULL); + if (logFile && *logFile) + AqHomed_SetLogFile(aqh, logFile); +} + + + +void _setupDb(AQHOMED *aqh, GWEN_DB_NODE *dbArgs) +{ + const char *s; + + s=GWEN_DB_GetCharValue(dbArgs, "dbfile", 0, NULL); + if (s && *s) { + GWEN_DB_NODE *dbNodeDb; + int rv; + + AqHomed_SetDbFile(aqh, s); + + dbNodeDb=GWEN_DB_Group_new("dbNodes"); + rv=GWEN_DB_ReadFile(dbNodeDb, s, GWEN_DB_FLAGS_DEFAULT); + if (rv==0) { + AQH_NodeDb_fromDb(aqh->nodeDb, dbNodeDb); + } + GWEN_DB_Group_free(dbNodeDb); + } +} + + + +int _createPidFile(const char *pidFilename) +{ + FILE *f; + int pidfd; + + if (remove(pidFilename)==0) { + DBG_ERROR(0, "Old PID file existed, removed. (Unclean shutdown?)"); + } + +#ifdef HAVE_SYS_STAT_H + pidfd = open(pidFilename, O_EXCL|O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); + if (pidfd < 0) { + DBG_ERROR(NULL, "Could not create PID file \"%s\" (%s), aborting.", pidFilename, strerror(errno)); + return GWEN_ERROR_IO; + } + + f = fdopen(pidfd, "w"); +#else /* HAVE_STAT_H */ + f=fopen(pidFilename,"w+"); +#endif /* HAVE_STAT_H */ + + /* write pid */ +#ifdef HAVE_GETPID + fprintf(f,"%d\n",getpid()); +#else + fprintf(f,"-1\n"); +#endif + if (fclose(f)) { + DBG_ERROR(0, "Could not close PID file \"%s\" (%s), aborting.", pidFilename, strerror(errno)); + return GWEN_ERROR_IO; + } + return 0; +} + + + +int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs) +{ + int rv; + const GWEN_ARGS args[]= { + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Char, /* type */ + "cfgdir", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "D", /* short option */ + "cfgdir", /* long option */ + I18S("Specify the configuration folder"), + I18S("Specify the configuration folder") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Char, /* type */ + "charset", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + 0, /* short option */ + "charset", /* long option */ + I18S("Specify the output character set"), /* short description */ + I18S("Specify the output character set") /* long description */ + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Char, /* type */ + "device", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "d", /* short option */ + "device", /* long option */ + I18S("Specify the device to communicate with (e.g. /dev/ttyUSB0)"), + I18S("Specify the device to communicate with (e.g. /dev/ttyUSB0)") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Int, /* type */ + "nodeAddress", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "n", /* short option */ + "node", /* long option */ + I18S("Specify the node address for the AqHome node adaptor (default 240)"), + I18S("Specify the node address for the AqHome node adaptor (default 240)") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Char, /* type */ + "logFile", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "l", /* short option */ + "logfile", /* long option */ + I18S("Specify a logfile to log received messages to"), + I18S("Specify a logfile to log received messages to") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Char, /* type */ + "tcpAddress", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "t", /* short option */ + "tcpaddress", /* long option */ + I18S("Specify the TCP address to listen on (disabled if missing)"), + I18S("Specify the TCP address to listen on (disabled if missing)") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Int, /* type */ + "tcpPort", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "P", /* short option */ + "tcpport", /* long option */ + I18S("Specify the TCP port to listen on (default: 45454)"), + I18S("Specify the TCP port to listen on (default: 45454)") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Char, /* type */ + "brokerAddress", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "ba", /* short option */ + "brokeraddress", /* long option */ + I18S("Specify the address of the broker server to connect to (disabled if missing)"), + I18S("Specify the address of the broker server to connect to (disabled if missing)") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Int, /* type */ + "brokerPort", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "bp", /* short option */ + "brokerport", /* long option */ + I18S("Specify the port of the broker server (default: 1899)"), + I18S("Specify the port of the broker server (default: 1899)") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Char, /* type */ + "brokerClientId", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + NULL, /* short option */ + "brokerclientid", /* long option */ + I18S("Specify client id for the broker server (default: \"nodes\")"), + I18S("Specify client id for the broker server (default: \"nodes\")") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Char, /* type */ + "dbfile", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "db", /* short option */ + "dbfile", /* long option */ + I18S("Specify DB file to read/write node database"), + I18S("Specify DB file to read/write node database") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Char, /* type */ + "pidfile", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "p", /* short option */ + "pidfile", /* long option */ + I18S("Specify the PID file"), + I18S("Specify the PID file") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Int, /* type */ + "timeout", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "T", /* short option */ + "timeout", /* long option */ + I18S("Specify timeout in second (default: no timeout)"), + I18S("Specify timeout in second (default: no timeout)") + }, + { + GWEN_ARGS_FLAGS_HELP | GWEN_ARGS_FLAGS_LAST, /* flags */ + GWEN_ArgsType_Int, /* type */ + "help", /* name */ + 0, /* minnum */ + 0, /* maxnum */ + "h", /* short option */ + "help", + I18S("Show this help screen."), + I18S("Show this help screen.") + } + }; + + rv=GWEN_Args_Check(argc, argv, 1, 0, args, dbArgs); + if (rv==GWEN_ARGS_RESULT_ERROR) { + fprintf(stderr, "ERROR: Could not parse arguments main\n"); + return GWEN_ERROR_INVALID; + } + else if (rv==GWEN_ARGS_RESULT_HELP) { + GWEN_BUFFER *ubuf; + + ubuf=GWEN_Buffer_new(0, 1024, 0, 1); + GWEN_Buffer_AppendArgs(ubuf, + I18N("This is version %s.\nUsage: %s [OPTIONS]\n\nOptions:\n"), + AQHOME_VERSION_STRING, + argv[0]); + if (GWEN_Args_Usage(args, ubuf, GWEN_ArgsOutType_Txt)) { + fprintf(stderr, "ERROR: Could not create help string\n"); + return 1; + } + GWEN_Buffer_AppendString(ubuf, "\n"); + + fprintf(stdout, "%s\n", GWEN_Buffer_GetStart(ubuf)); + GWEN_Buffer_free(ubuf); + return GWEN_ERROR_CLOSE; + } + return 0; +} + + + + diff --git a/apps/aqhome-nodes/init.h b/apps/aqhome-nodes/init.h new file mode 100644 index 0000000..8935383 --- /dev/null +++ b/apps/aqhome-nodes/init.h @@ -0,0 +1,23 @@ +/**************************************************************************** + * 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 AQHOMED_INIT_H +#define AQHOMED_INIT_H + + +#include "./aqhomed.h" + + + +int AqHomed_Init(AQHOMED *aqh, int argc, char **argv); + + + +#endif + + diff --git a/apps/aqhome-nodes/ipc.h b/apps/aqhome-nodes/ipc.h new file mode 100644 index 0000000..091934b --- /dev/null +++ b/apps/aqhome-nodes/ipc.h @@ -0,0 +1,23 @@ +/**************************************************************************** + * 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 AQHOMED_LOOP_IPC_H +#define AQHOMED_LOOP_IPC_H + + +#include "./aqhomed.h" + + + +void AqHomed_ForwardTtyMsgToIpcClients(AQHOMED *aqh, const GWEN_MSG *msg); + + + +#endif + + diff --git a/apps/aqhome-nodes/loop.c b/apps/aqhome-nodes/loop.c new file mode 100644 index 0000000..010aa18 --- /dev/null +++ b/apps/aqhome-nodes/loop.c @@ -0,0 +1,79 @@ +/**************************************************************************** + * 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 "./loop.h" +#include "./loop_tty.h" +#include "./loop_ipc.h" +#include "./aqhomed_p.h" +#include "./tty_log.h" +#include "./db.h" + +#include "aqhome/msg/endpoint_tty.h" +#include "aqhome/msg/msg_node.h" +#include "aqhome/msg/msg_value2.h" +#include "aqhome/ipc/endpoint_ipc.h" +#include "aqhome/ipc/nodes/msg_ipc_forward.h" +#include "aqhome/ipc/nodes/msg_ipc_value.h" + +#include +#include +#include +#include + + + +/* ------------------------------------------------------------------------------------------------ + * defines + * ------------------------------------------------------------------------------------------------ + */ + +#define I18N(msg) msg +#define I18S(msg) msg + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + + + + +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ + +void AqHomed_Loop(AQHOMED *aqh, int timeoutInMsecs) +{ + if (aqh) { + GWEN_MsgEndpoint_ChildrenIoLoop(aqh->rootEndpoint, timeoutInMsecs); + AqHomed_ReadAndHandleTtyMessages(aqh); + AqHomed_ReadAndHandleIpcMessages(aqh); + + if (AQH_NodeDb_IsModified(aqh->nodeDb)) { + if (aqh->dbFile) { + GWEN_DB_NODE *dbNodeDb; + + dbNodeDb=GWEN_DB_Group_new("nodeDb"); + AQH_NodeDb_toDb(aqh->nodeDb, dbNodeDb); + GWEN_DB_WriteFile(dbNodeDb, aqh->dbFile, GWEN_DB_FLAGS_DEFAULT); + GWEN_DB_Group_free(dbNodeDb); + } + } + } +} + + + diff --git a/apps/aqhome-nodes/loop.h b/apps/aqhome-nodes/loop.h new file mode 100644 index 0000000..c715173 --- /dev/null +++ b/apps/aqhome-nodes/loop.h @@ -0,0 +1,23 @@ +/**************************************************************************** + * 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 AQHOMED_LOOP_H +#define AQHOMED_LOOP_H + + +#include "./aqhomed.h" + + + +void AqHomed_Loop(AQHOMED *aqh, int timeoutInMsecs); + + + +#endif + + diff --git a/apps/aqhome-nodes/loop_ipc.c b/apps/aqhome-nodes/loop_ipc.c new file mode 100644 index 0000000..cab159a --- /dev/null +++ b/apps/aqhome-nodes/loop_ipc.c @@ -0,0 +1,187 @@ +/**************************************************************************** + * 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 "./loop_ipc.h" +#include "./aqhomed_p.h" +#include "./tty_log.h" +#include "./db.h" + +#include "aqhome/msg/endpoint_tty.h" +#include "aqhome/msg/msg_node.h" +#include "aqhome/msg/msg_value2.h" +#include "aqhome/msg/msg_ping.h" +#include "aqhome/ipc/endpoint_ipc.h" +#include "aqhome/ipc/nodes/ipc_nodes.h" +#include "aqhome/ipc/nodes/msg_ipc_forward.h" +#include "aqhome/ipc/nodes/msg_ipc_value.h" +#include "aqhome/ipc/nodes/msg_ipc_ping.h" +#include "aqhome/ipc/nodes/msg_ipc_setaccmsggrps.h" +#include "aqhome/ipc/nodes/msg_ipc_getdevices_rsp.h" +#include "aqhome/ipc/msg_ipc_result.h" + +#include +#include +#include +#include + + + +/* ------------------------------------------------------------------------------------------------ + * defines + * ------------------------------------------------------------------------------------------------ + */ + +#define I18N(msg) msg +#define I18S(msg) msg + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static void _handleIpcEndpoint(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep); +static void _handleIpcMsg(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg); +void _handleIpcMsgPing(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg); +void _handleIpcMsgSetAccMsgGrps(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg); +void _handleIpcMsgForward(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg); +void _handleIpcMsgGetDevicesReq(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg); + + + +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ + + +void AqHomed_ReadAndHandleIpcMessages(AQHOMED *aqh) +{ + if (aqh->ipcdEndpoint) { + GWEN_MSG_ENDPOINT *ep; + + ep=GWEN_MsgEndpoint_Tree2_GetFirstChild(aqh->ipcdEndpoint); + while(ep) { + _handleIpcEndpoint(aqh, ep); + ep=GWEN_MsgEndpoint_Tree2_GetNext(ep); + } + } +} + + + +void _handleIpcEndpoint(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep) +{ + GWEN_MSG *msg; + + while( (msg=GWEN_MsgEndpoint_TakeFirstReceivedMessage(ep)) ) { + _handleIpcMsg(aqh, ep, msg); + GWEN_Msg_free(msg); + } +} + + + +void _handleIpcMsg(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg) +{ + uint16_t code; + + /* exec IPC message */ + code=GWEN_IpcMsg_GetCode(msg); + DBG_ERROR(AQH_LOGDOMAIN, "Received IPC packet"); + switch(code) { + case AQH_MSGTYPE_IPC_NODES_PING: _handleIpcMsgPing(aqh, ep, msg); break; + case AQH_MSGTYPE_IPC_NODES_SETACCMSGGRPS: _handleIpcMsgSetAccMsgGrps(aqh, ep, msg); break; + case AQH_MSGTYPE_IPC_NODES_FORWARD: _handleIpcMsgForward(aqh, ep, msg); break; + case AQH_MSGTYPE_IPC_NODES_GETDEVICES_REQ: _handleIpcMsgGetDevicesReq(aqh, ep, msg); break; + default: break; + } +} + + + +void _handleIpcMsgPing(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg) +{ + if (aqh->ttyEndpoint && GWEN_MsgEndpoint_GetState(aqh->ttyEndpoint)==GWEN_MSG_ENDPOINT_STATE_CONNECTED) { + GWEN_MSG *msgOut; + + DBG_ERROR(AQH_LOGDOMAIN, "Received IPC PING message"); + msgOut=AQH_PingMsg_new(aqh->nodeAddress, AQH_PingIpcMsg_GetDestAddr(msg), AQH_MSG_TYPE_PING); + GWEN_MsgEndpoint_AddSendMessage(aqh->ttyEndpoint, msgOut); + } +} + + + +void _handleIpcMsgSetAccMsgGrps(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg) +{ + uint32_t groups; + + DBG_ERROR(AQH_LOGDOMAIN, "Received IPC SET_ACCEPTED_MSG_GROUPS message"); + groups=AQH_SetAcceptedMsgGroupsIpcMsg_GetMsgGroups(msg); + AQH_IpcEndpoint_SetAcceptedMsgGroups(ep, groups); + // TODO: send response? +} + + + +void _handleIpcMsgForward(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg) +{ + if (aqh->ttyEndpoint && GWEN_MsgEndpoint_GetState(aqh->ttyEndpoint)==GWEN_MSG_ENDPOINT_STATE_CONNECTED) { + GWEN_MSG *msgOut; + + DBG_ERROR(AQH_LOGDOMAIN, "Received IPC FORWARD message"); + msgOut=AQH_ForwardIpcMsg_GetCopyOfNodeMsg(msg); + if (msgOut) + GWEN_MsgEndpoint_AddSendMessage(aqh->ttyEndpoint, msgOut); + } +} + + + +void _handleIpcMsgGetDevicesReq(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg) +{ + AQH_NODE_INFO_LIST *nodeInfoList; + + DBG_ERROR(AQH_LOGDOMAIN, "Received IPC GetDevicesRequest message"); + nodeInfoList=AQH_NodeDb_GetAllNodeInfos(aqh->nodeDb); + if (nodeInfoList && AQH_NodeInfo_List_GetCount(nodeInfoList)) { + const AQH_NODE_INFO *ni; + + ni=AQH_NodeInfo_List_First(nodeInfoList); + while(ni) { + const AQH_NODE_INFO *niNext; + GWEN_MSG *msgOut; + + niNext=AQH_NodeInfo_List_Next(ni); + DBG_INFO(AQH_LOGDOMAIN, "Sending response for node %02x (%08x)", AQH_NodeInfo_GetBusAddress(ni), AQH_NodeInfo_GetUid(ni)); + msgOut=AQH_GetDevicesResponseIpcMsg_new(AQH_MSGTYPE_IPC_NODES_GETDEVICES_RSP, niNext?0:AQH_MSGIPC_GETDEVICES_RSP_FLAGS_LAST, ni); + GWEN_MsgEndpoint_AddSendMessage(ep, msgOut); + ni=niNext; + } + } + else { + GWEN_MSG *msgOut; + + DBG_INFO(AQH_LOGDOMAIN, "No nodes"); + msgOut=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_NODES_RESULT, AQH_MSG_IPC_ERROR_NODATA); + GWEN_MsgEndpoint_AddSendMessage(ep, msgOut); + } +} + + + + + + diff --git a/apps/aqhome-nodes/loop_ipc.h b/apps/aqhome-nodes/loop_ipc.h new file mode 100644 index 0000000..fab747e --- /dev/null +++ b/apps/aqhome-nodes/loop_ipc.h @@ -0,0 +1,23 @@ +/**************************************************************************** + * 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 AQHOMED_LOOP_IPC_H +#define AQHOMED_LOOP_IPC_H + + +#include "./aqhomed.h" + + + +void AqHomed_ReadAndHandleIpcMessages(AQHOMED *aqh); + + + +#endif + + diff --git a/apps/aqhome-nodes/loop_tty.c b/apps/aqhome-nodes/loop_tty.c new file mode 100644 index 0000000..2897091 --- /dev/null +++ b/apps/aqhome-nodes/loop_tty.c @@ -0,0 +1,85 @@ +/**************************************************************************** + * 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 "./loop_tty.h" +#include "./loop_tty_ipc.h" +#include "./loop_tty_broker.h" +#include "./aqhomed_p.h" +#include "./tty_log.h" +#include "./db.h" + +#include "aqhome/msg/endpoint_tty.h" +#include "aqhome/msg/msg_node.h" +#include "aqhome/msg/msg_value2.h" +#include "aqhome/ipc/endpoint_ipc.h" +#include "aqhome/ipc/nodes/msg_ipc_forward.h" +#include "aqhome/ipc/nodes/msg_ipc_value.h" + +#include +#include +#include +#include + + + +/* ------------------------------------------------------------------------------------------------ + * defines + * ------------------------------------------------------------------------------------------------ + */ + +#define I18N(msg) msg +#define I18S(msg) msg + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static void _handleTtyMsg(AQHOMED *aqh, const GWEN_MSG *msg); + + + +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ + + +void AqHomed_ReadAndHandleTtyMessages(AQHOMED *aqh) +{ + GWEN_MSG *msg; + + while( (msg=GWEN_MsgEndpoint_TakeFirstReceivedMessage(aqh->ttyEndpoint)) ) { + _handleTtyMsg(aqh, msg); + GWEN_Msg_free(msg); + } +} + + + +void _handleTtyMsg(AQHOMED *aqh, const GWEN_MSG *msg) +{ + if (aqh->logFile) + AqHomed_LogTtyMsg(aqh, msg); + if (aqh->nodeDb) + AqHomed_NodeMsgToDb(aqh, msg); + if (aqh->ipcdEndpoint) + AqHomed_ForwardTtyMsgToIpcClients(aqh, msg); + if (aqh->brokerEndpoint) + AqHomed_ForwardTtyMsgToBroker(aqh, msg); +} + + + diff --git a/apps/aqhome-nodes/loop_tty.h b/apps/aqhome-nodes/loop_tty.h new file mode 100644 index 0000000..f5aac57 --- /dev/null +++ b/apps/aqhome-nodes/loop_tty.h @@ -0,0 +1,23 @@ +/**************************************************************************** + * 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 AQHOMED_LOOP_TTY_H +#define AQHOMED_LOOP_TTY_H + + +#include "./aqhomed.h" + + + +void AqHomed_ReadAndHandleTtyMessages(AQHOMED *aqh); + + + +#endif + + diff --git a/apps/aqhome-nodes/loop_tty_broker.c b/apps/aqhome-nodes/loop_tty_broker.c new file mode 100644 index 0000000..bb96635 --- /dev/null +++ b/apps/aqhome-nodes/loop_tty_broker.c @@ -0,0 +1,190 @@ +/**************************************************************************** + * 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 "./loop_tty_broker.h" +#include "./aqhomed_p.h" +#include "./tty_log.h" +#include "./db.h" + +#include "aqhome/msg/endpoint_tty.h" +#include "aqhome/msg/msg_node.h" +#include "aqhome/msg/msg_value2.h" +#include "aqhome/msg/msg_sendstats.h" +#include "aqhome/msg/msg_recvstats.h" +#include "aqhome/ipc/endpoint_ipc.h" +#include "aqhome/ipc/data/msg_data_multidata.h" +#include "aqhome/ipc/data/ipc_data.h" + +#include +#include +#include +#include + + + +/* ------------------------------------------------------------------------------------------------ + * defines + * ------------------------------------------------------------------------------------------------ + */ + +#define I18N(msg) msg +#define I18S(msg) msg + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static void _processValue2Message(AQHOMED *aqh, const GWEN_MSG *nodeMsg); +static void _processSendStatsMessage(AQHOMED *aqh, const GWEN_MSG *nodeMsg); +static void _processRecvStatsMessage(AQHOMED *aqh, const GWEN_MSG *nodeMsg); +static void _publishInt(AQHOMED *aqh, uint32_t uid, int valueId, const char *valueUnits, const char *valuePath, int v); +static void _publishDouble(AQHOMED *aqh, uint32_t uid, int valueId, const char *valueUnits, const char *valuePath, double v); + + + +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ + + + +void AqHomed_ForwardTtyMsgToBroker(AQHOMED *aqh, const GWEN_MSG *nodeMsg) +{ + if (GWEN_MsgEndpoint_GetState(aqh->brokerEndpoint)==GWEN_MSG_ENDPOINT_STATE_CONNECTED) { + DBG_DEBUG(AQH_LOGDOMAIN, "Processing output message"); + switch(AQH_NodeMsg_GetMsgType(nodeMsg)) { + case AQH_MSG_TYPE_VALUE2: + _processValue2Message(aqh, nodeMsg); + break; + case AQH_MSG_TYPE_COMSENDSTATS: + _processSendStatsMessage(aqh, nodeMsg); + break; + case AQH_MSG_TYPE_COMRECVSTATS: + _processRecvStatsMessage(aqh, nodeMsg); + break; + default: + break; + } + } +} + + + +void _processValue2Message(AQHOMED *aqh, const GWEN_MSG *nodeMsg) +{ + _publishDouble(aqh, + AQH_Value2Msg_GetUid(nodeMsg), + AQH_Value2Msg_GetValueId(nodeMsg), + AQH_Value2Msg_GetValueTypeUnits(nodeMsg), + AQH_Value2Msg_GetValueTypeName(nodeMsg), + AQH_Value2Msg_GetValue(nodeMsg)); +} + + + +void _processSendStatsMessage(AQHOMED *aqh, const GWEN_MSG *nodeMsg) +{ + uint16_t packetsOutInt; + + packetsOutInt=AQH_SendStatsMsg_GetPacketsOut(nodeMsg); + if (packetsOutInt) { + double packetsOut; + double collisions; + double busy; + double collisionsPercentage=0.0; + double busyPercentage=0.0; + + packetsOut=(double) packetsOutInt; + collisions=(double)AQH_SendStatsMsg_GetCollisions(nodeMsg); + busy=(double)AQH_SendStatsMsg_GetBusyErrors(nodeMsg); + + collisionsPercentage=collisions*100.0/packetsOut; + busyPercentage=busy*100.0/packetsOut; + + _publishInt(aqh, AQH_SendStatsMsg_GetUid(nodeMsg), 0, NULL, "net/packetsOut", packetsOutInt); + _publishInt(aqh, AQH_SendStatsMsg_GetUid(nodeMsg), 0, NULL, "net/collisions", (int) AQH_SendStatsMsg_GetCollisions(nodeMsg)); + _publishDouble(aqh, AQH_SendStatsMsg_GetUid(nodeMsg), 0, "%", "net/collisionsPercent", collisionsPercentage); + _publishDouble(aqh, AQH_SendStatsMsg_GetUid(nodeMsg), 0, "%", "net/busyPercent", busyPercentage); + } +} + + + +void _processRecvStatsMessage(AQHOMED *aqh, const GWEN_MSG *nodeMsg) +{ + uint16_t packetsInInt; + + packetsInInt=AQH_RecvStatsMsg_GetPacketsIn(nodeMsg); + if (packetsInInt) { + double packetsIn; + double crcErrors; + double ioErrors; + double crcErrorsPercentage=0.0; + double ioErrorsPercentage=0.0; + + packetsIn=(double) packetsInInt; + crcErrors=(double)AQH_RecvStatsMsg_GetCrcErrors(nodeMsg); + ioErrors=(double)AQH_RecvStatsMsg_GetIoErrors(nodeMsg); + + crcErrorsPercentage=crcErrors*100.0/packetsIn; + ioErrorsPercentage=ioErrors*100.0/packetsIn; + + _publishInt(aqh, AQH_RecvStatsMsg_GetUid(nodeMsg), 0, NULL, "net/packetsIn", packetsInInt); + _publishInt(aqh, AQH_RecvStatsMsg_GetUid(nodeMsg), 0, NULL, "net/crcerrors", (int) AQH_RecvStatsMsg_GetCrcErrors(nodeMsg)); + _publishInt(aqh, AQH_RecvStatsMsg_GetUid(nodeMsg), 0, NULL, "net/ioerrors", (int) AQH_RecvStatsMsg_GetIoErrors(nodeMsg)); + _publishDouble(aqh, AQH_RecvStatsMsg_GetUid(nodeMsg), 0, "%", "net/crcerrorsPercent", crcErrorsPercentage); + _publishDouble(aqh, AQH_RecvStatsMsg_GetUid(nodeMsg), 0, "%", "net/ioerrorsPercent", ioErrorsPercentage); + } +} + + + +void _publishInt(AQHOMED *aqh, uint32_t uid, int valueId, const char *valueUnits, const char *valuePath, int v) +{ + _publishDouble(aqh, uid, valueId, valueUnits, valuePath, (double) v); +} + + + +void _publishDouble(AQHOMED *aqh, uint32_t uid, int valueId, const char *valueUnits, const char *valuePath, double v) +{ + GWEN_BUFFER *bufTopic; + GWEN_MSG *pubMsg; + union {double f; uint64_t i;} u; + uint64_t arrayToSend[2]; + + u.f=v; + arrayToSend[0]=(uint64_t) time(NULL); + arrayToSend[1]=u.i; + + bufTopic=GWEN_Buffer_new(0, 64, 0, 1); + if (valueId>0) + GWEN_Buffer_AppendArgs(bufTopic, "%08x/%d/%s", uid, valueId, valuePath); + else + GWEN_Buffer_AppendArgs(bufTopic, "%08x/%s", uid, valuePath); + + pubMsg=AQH_MultiDataDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_UPDATEDATA, GWEN_Buffer_GetStart(bufTopic), valueUnits, 0, arrayToSend, 1); + if (pubMsg) { + DBG_INFO(AQH_LOGDOMAIN, "BROKER PUBLISH %s: %f", GWEN_Buffer_GetStart(bufTopic), v); + GWEN_MsgEndpoint_AddSendMessage(aqh->brokerEndpoint, pubMsg); + } + GWEN_Buffer_free(bufTopic); +} + + + + diff --git a/apps/aqhome-nodes/loop_tty_broker.h b/apps/aqhome-nodes/loop_tty_broker.h new file mode 100644 index 0000000..ff08923 --- /dev/null +++ b/apps/aqhome-nodes/loop_tty_broker.h @@ -0,0 +1,23 @@ +/**************************************************************************** + * 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 AQHOMED_LOOP_TTY_BROKER_H +#define AQHOMED_LOOP_TTY_BROKER_H + + +#include "./aqhomed.h" + + + +void AqHomed_ForwardTtyMsgToBroker(AQHOMED *aqh, const GWEN_MSG *nodeMsg); + + + +#endif + + diff --git a/apps/aqhome-nodes/loop_tty_ipc.c b/apps/aqhome-nodes/loop_tty_ipc.c new file mode 100644 index 0000000..27afb01 --- /dev/null +++ b/apps/aqhome-nodes/loop_tty_ipc.c @@ -0,0 +1,117 @@ +/**************************************************************************** + * 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 "./loop_tty_ipc.h" +#include "./aqhomed_p.h" +#include "./tty_log.h" +#include "./db.h" + +#include "aqhome/msg/endpoint_tty.h" +#include "aqhome/msg/msg_node.h" +#include "aqhome/msg/msg_value2.h" +#include "aqhome/ipc/endpoint_ipc.h" +#include "aqhome/ipc/nodes/msg_ipc_forward.h" +#include "aqhome/ipc/nodes/msg_ipc_value.h" +#include "aqhome/mqtt/endpoint_mqttc.h" + +#include +#include +#include +#include + + + +/* ------------------------------------------------------------------------------------------------ + * defines + * ------------------------------------------------------------------------------------------------ + */ + +#define I18N(msg) msg +#define I18S(msg) msg + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static void _forwardValue2MsgToIpc(GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *nodeMsg); +static void _forwardAnyMsgToIpc(GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *nodeMsg); + + + +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ + +void AqHomed_ForwardTtyMsgToIpcClients(AQHOMED *aqh, const GWEN_MSG *msg) +{ + uint32_t msgGroup; + + msgGroup=AQH_NodeMsg_GetMsgGroup(AQH_NodeMsg_GetMsgType(msg)); + if (msgGroup) { + GWEN_MSG_ENDPOINT *ep; + + ep=GWEN_MsgEndpoint_Tree2_GetFirstChild(aqh->ipcdEndpoint); + while(ep) { + if (msgGroup & AQH_IpcEndpoint_GetAcceptedMsgGroups(ep)) { + DBG_INFO(NULL, "Endpoint accepts msg group %d", msgGroup); + switch(AQH_NodeMsg_GetMsgType(msg)) { + case AQH_MSG_TYPE_VALUE2: + _forwardValue2MsgToIpc(ep, msg); + break; + default: + _forwardAnyMsgToIpc(ep, msg); + break; + } + + } + ep=GWEN_MsgEndpoint_Tree2_GetNext(ep); + } + } + else { + DBG_ERROR(NULL, "Message type %d not in any message group, ignoring message", AQH_NodeMsg_GetMsgType(msg)); + } +} + + + +void _forwardValue2MsgToIpc(GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *nodeMsg) +{ + GWEN_MSG *ipcMsg; + + ipcMsg=AQH_ValueIpcMsg_new(AQH_MSGTYPE_IPC_NODES_VALUE, + AQH_Value2Msg_GetUid(nodeMsg), + AQH_Value2Msg_GetValueId(nodeMsg), + AQH_Value2Msg_GetValueType(nodeMsg), + AQH_Value2Msg_GetValueNom(nodeMsg), + AQH_Value2Msg_GetValueDenom(nodeMsg)); + GWEN_MsgEndpoint_AddSendMessage(ep, ipcMsg); +} + + + +void _forwardAnyMsgToIpc(GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *nodeMsg) +{ + GWEN_MSG *ipcMsg; + + ipcMsg=AQH_ForwardIpcMsg_new(AQH_MSGTYPE_IPC_NODES_FORWARD, GWEN_Msg_GetConstBuffer(nodeMsg), GWEN_Msg_GetBytesInBuffer(nodeMsg)); + GWEN_MsgEndpoint_AddSendMessage(ep, ipcMsg); +} + + + + + diff --git a/apps/aqhome-nodes/loop_tty_ipc.h b/apps/aqhome-nodes/loop_tty_ipc.h new file mode 100644 index 0000000..39e4c0e --- /dev/null +++ b/apps/aqhome-nodes/loop_tty_ipc.h @@ -0,0 +1,23 @@ +/**************************************************************************** + * 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 AQHOMED_LOOP_TTY_IPC_H +#define AQHOMED_LOOP_TTY_IPC_H + + +#include "./aqhomed.h" + + + +void AqHomed_ForwardTtyMsgToIpcClients(AQHOMED *aqh, const GWEN_MSG *msg); + + + +#endif + + diff --git a/apps/aqhome-nodes/loop_tty_mqtt.c b/apps/aqhome-nodes/loop_tty_mqtt.c new file mode 100644 index 0000000..a3bf995 --- /dev/null +++ b/apps/aqhome-nodes/loop_tty_mqtt.c @@ -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 +#endif + + +#include "./loop_tty_mqtt.h" +#include "./aqhomed_p.h" +#include "./tty_log.h" +#include "./tty_write.h" +#include "./db.h" + +#include "aqhome/msg/endpoint_tty.h" +#include "aqhome/msg/msg_node.h" +#include "aqhome/msg/msg_value2.h" +#include "aqhome/msg/msg_sendstats.h" +#include "aqhome/msg/msg_recvstats.h" +#include "aqhome/ipc/endpoint_ipc.h" +#include "aqhome/ipc/nodes/msg_ipc_forward.h" +#include "aqhome/ipc/nodes/msg_ipc_value.h" +#include "aqhome/mqtt/endpoint_mqttc.h" +#include "aqhome/mqtt/msg_mqtt_publish.h" + +#include +#include +#include +#include + + + +/* ------------------------------------------------------------------------------------------------ + * defines + * ------------------------------------------------------------------------------------------------ + */ + +#define I18N(msg) msg +#define I18S(msg) msg + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static void _processValue2Message(AQHOMED *aqh, const GWEN_MSG *nodeMsg); +static void _processSendStatsMessage(AQHOMED *aqh, const GWEN_MSG *nodeMsg); +static void _processRecvStatsMessage(AQHOMED *aqh, const GWEN_MSG *nodeMsg); +static void _publishDouble(AQHOMED *aqh, uint32_t uid, int valueId, const char *valuePath, double v); +static void _publishInt(AQHOMED *aqh, uint32_t uid, int valueId, const char *valuePath, int v); +static void _publishString(AQHOMED *aqh, uint32_t uid, int valueId, const char *valuePath, const char *v); + + + + +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ + + + +void AqHomed_ForwardTtyMsgToMqttServer(AQHOMED *aqh, const GWEN_MSG *nodeMsg) +{ + if (GWEN_MsgEndpoint_GetState(aqh->mqttEndpoint)==GWEN_MSG_ENDPOINT_STATE_CONNECTED) { + DBG_DEBUG(AQH_LOGDOMAIN, "Processing output message"); + switch(AQH_NodeMsg_GetMsgType(nodeMsg)) { + case AQH_MSG_TYPE_VALUE2: + _processValue2Message(aqh, nodeMsg); + break; + case AQH_MSG_TYPE_COMSENDSTATS: + _processSendStatsMessage(aqh, nodeMsg); + break; + case AQH_MSG_TYPE_COMRECVSTATS: + _processRecvStatsMessage(aqh, nodeMsg); + break; + default: + break; + } + } +} + + + +void _processValue2Message(AQHOMED *aqh, const GWEN_MSG *nodeMsg) +{ + if (AQH_Value2Msg_GetValueType(nodeMsg)==AQH_MSG_VALUE2_TYPE_DOOR) + _publishString(aqh, + AQH_Value2Msg_GetUid(nodeMsg), + AQH_Value2Msg_GetValueId(nodeMsg), + AQH_Value2Msg_GetValueTypeName(nodeMsg), + AQH_Value2Msg_GetValueAsWindowStateString(nodeMsg)); + else + _publishDouble(aqh, + AQH_Value2Msg_GetUid(nodeMsg), + AQH_Value2Msg_GetValueId(nodeMsg), + AQH_Value2Msg_GetValueTypeName(nodeMsg), + AQH_Value2Msg_GetValue(nodeMsg)); +} + + + +void _processSendStatsMessage(AQHOMED *aqh, const GWEN_MSG *nodeMsg) +{ + uint16_t packetsOutInt; + + packetsOutInt=AQH_SendStatsMsg_GetPacketsOut(nodeMsg); + if (packetsOutInt) { + double packetsOut; + double collisions; + double busy; + double collisionsPercentage=0.0; + double busyPercentage=0.0; + + packetsOut=(double) packetsOutInt; + collisions=(double)AQH_SendStatsMsg_GetCollisions(nodeMsg); + busy=(double)AQH_SendStatsMsg_GetBusyErrors(nodeMsg); + + collisionsPercentage=collisions*100.0/packetsOut; + busyPercentage=busy*100.0/packetsOut; + + _publishInt(aqh, AQH_SendStatsMsg_GetUid(nodeMsg), 0, "net/packetsOut", packetsOutInt); + _publishInt(aqh, AQH_SendStatsMsg_GetUid(nodeMsg), 0, "net/collisions", (int) AQH_SendStatsMsg_GetCollisions(nodeMsg)); + _publishDouble(aqh, AQH_SendStatsMsg_GetUid(nodeMsg), 0, "net/collisionsPercent", collisionsPercentage); + _publishDouble(aqh, AQH_SendStatsMsg_GetUid(nodeMsg), 0, "net/busyPercent", busyPercentage); + } +} + + + +void _processRecvStatsMessage(AQHOMED *aqh, const GWEN_MSG *nodeMsg) +{ + uint16_t packetsInInt; + + packetsInInt=AQH_RecvStatsMsg_GetPacketsIn(nodeMsg); + if (packetsInInt) { + double packetsIn; + double crcErrors; + double ioErrors; + double crcErrorsPercentage=0.0; + double ioErrorsPercentage=0.0; + + packetsIn=(double) packetsInInt; + crcErrors=(double)AQH_RecvStatsMsg_GetCrcErrors(nodeMsg); + ioErrors=(double)AQH_RecvStatsMsg_GetIoErrors(nodeMsg); + + crcErrorsPercentage=crcErrors*100.0/packetsIn; + ioErrorsPercentage=ioErrors*100.0/packetsIn; + + _publishInt(aqh, AQH_RecvStatsMsg_GetUid(nodeMsg), 0, "net/packetsIn", packetsInInt); + _publishInt(aqh, AQH_RecvStatsMsg_GetUid(nodeMsg), 0, "net/crcerrors", (int) AQH_RecvStatsMsg_GetCrcErrors(nodeMsg)); + _publishInt(aqh, AQH_RecvStatsMsg_GetUid(nodeMsg), 0, "net/ioerrors", (int) AQH_RecvStatsMsg_GetIoErrors(nodeMsg)); + _publishDouble(aqh, AQH_RecvStatsMsg_GetUid(nodeMsg), 0, "net/crcerrorsPercent", crcErrorsPercentage); + _publishDouble(aqh, AQH_RecvStatsMsg_GetUid(nodeMsg), 0, "net/ioerrorsPercent", ioErrorsPercentage); + } +} + + + +void _publishDouble(AQHOMED *aqh, uint32_t uid, int valueId, const char *valuePath, double v) +{ + char numBuf[16]; + + snprintf(numBuf, sizeof(numBuf)-1, "%f", v); + numBuf[sizeof(numBuf)-1]=0; + _publishString(aqh, uid, valueId, valuePath, numBuf); +} + + + +void _publishInt(AQHOMED *aqh, uint32_t uid, int valueId, const char *valuePath, int v) +{ + char numBuf[16]; + + snprintf(numBuf, sizeof(numBuf)-1, "%d", v); + numBuf[sizeof(numBuf)-1]=0; + _publishString(aqh, uid, valueId, valuePath, numBuf); +} + + + +void _publishString(AQHOMED *aqh, uint32_t uid, int valueId, const char *valuePath, const char *v) +{ + GWEN_BUFFER *bufTopic; + GWEN_MSG *pubMsg; + + bufTopic=GWEN_Buffer_new(0, 64, 0, 1); + if (valueId>0) + GWEN_Buffer_AppendArgs(bufTopic, "%s/%08x/%d/%s", + aqh->mqttTopicPrefix, + uid, + valueId, + valuePath); + else + GWEN_Buffer_AppendArgs(bufTopic, "%s/%08x/%s", + aqh->mqttTopicPrefix, + uid, + valuePath); + + pubMsg=AQH_PublishMqttMsg_new(0, 0, GWEN_Buffer_GetStart(bufTopic), (const uint8_t*) v, strlen(v)); + if (pubMsg) { + DBG_INFO(AQH_LOGDOMAIN, "MQTT PUBLISH %s: %s", GWEN_Buffer_GetStart(bufTopic), v); + GWEN_MsgEndpoint_AddSendMessage(aqh->mqttEndpoint, pubMsg); + } + GWEN_Buffer_free(bufTopic); +} + + diff --git a/apps/aqhome-nodes/loop_tty_mqtt.h b/apps/aqhome-nodes/loop_tty_mqtt.h new file mode 100644 index 0000000..ab62bd2 --- /dev/null +++ b/apps/aqhome-nodes/loop_tty_mqtt.h @@ -0,0 +1,23 @@ +/**************************************************************************** + * 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 AQHOMED_LOOP_TTY_MQTT_H +#define AQHOMED_LOOP_TTY_MQTT_H + + +#include "./aqhomed.h" + + + +void AqHomed_ForwardTtyMsgToMqttServer(AQHOMED *aqh, const GWEN_MSG *msg); + + + +#endif + + diff --git a/apps/aqhome-nodes/main.c b/apps/aqhome-nodes/main.c new file mode 100644 index 0000000..87c1050 --- /dev/null +++ b/apps/aqhome-nodes/main.c @@ -0,0 +1,191 @@ +/**************************************************************************** + * 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 +#include + +#include "./aqhomed.h" +#include "./init.h" +#include "./fini.h" +#include "./loop.h" + +#include +#include +#include +#include + +#ifdef HAVE_SIGNAL_H +# include +#endif + + + +/* ------------------------------------------------------------------------------------------------ + * defines + * ------------------------------------------------------------------------------------------------ + */ + +#define I18N(msg) msg +#define I18S(msg) msg + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +#ifdef HAVE_SIGNAL_H +static int _setSignalHandlers(void); +static int _setupSigAction(struct sigaction *sa, int sig); +static void _signalHandler(int s); +#endif + + + +/* ------------------------------------------------------------------------------------------------ + * static vars + * ------------------------------------------------------------------------------------------------ + */ + +#ifdef HAVE_SIGNAL_H +static struct sigaction saINT,saTERM, saHUP, saTSTP, saCONT; +#endif + +static int stopService=0; + + + +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ + +int main(int argc, char **argv) +{ + int rv; + AQHOMED *aqh; + GWEN_GUI *gui; + + rv=GWEN_Init(); + if (rv) { + fprintf(stderr, "ERROR: Unable to init Gwen.\n"); + return 2; + } + + GWEN_Logger_Open(0, "aqhomed", 0, GWEN_LoggerType_Console, GWEN_LoggerFacility_User); + //GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Warning); + GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Info); + + rv=_setSignalHandlers(); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + return rv; + } + + rv=AQH_Init(); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + return 2; + } + + gui=GWEN_Gui_CGui_new(); + GWEN_Gui_SetGui(gui); + + aqh=AqHomed_new(); + rv=AqHomed_Init(aqh, argc, argv); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + return 2; + } + + while(!stopService) { + DBG_DEBUG(NULL, "Next loop"); + AqHomed_Loop(aqh, 2000); + } + + AqHomed_Fini(aqh); + AqHomed_free(aqh); + + GWEN_Gui_SetGui(NULL); + GWEN_Gui_free(gui); + + return 0; +} + + + +int _setSignalHandlers(void) +{ +#ifdef HAVE_SIGNAL_H + int rv; + + rv=_setupSigAction(&saINT, SIGINT); + if (rv) + return rv; + + rv=_setupSigAction(&saTERM, SIGTERM); + if (rv) + return rv; + + rv=_setupSigAction(&saHUP, SIGHUP); + if (rv) + return rv; + +# ifdef SIGTSTP + rv=_setupSigAction(&saTSTP, SIGTSTP); + if (rv) + return rv; +# endif + +# ifdef SIGCONT + rv=_setupSigAction(&saCONT, SIGCONT); + if (rv) + return rv; +# endif +#endif + return 0; +} + + + +int _setupSigAction(struct sigaction *sa, int sig) +{ + sa->sa_handler=_signalHandler; + sigemptyset(&sa->sa_mask); + sa->sa_flags=0; + if (sigaction(sig, sa, 0)) { + DBG_ERROR(NULL, "Could not setup signal handler for signal %d", sig); + return GWEN_ERROR_IO; + } + + return 0; +} + + + +void _signalHandler(int s) +{ + switch(s) { + case SIGINT: + case SIGTERM: + case SIGHUP: + DBG_WARN(0, "Received signal %d, stopping service in next loop.",s); + stopService=1; + break; + default: + DBG_WARN(0, "Unknown signal %d",s); + break; + } +} + + diff --git a/apps/aqhome-nodes/tty_log.c b/apps/aqhome-nodes/tty_log.c new file mode 100644 index 0000000..0ac05aa --- /dev/null +++ b/apps/aqhome-nodes/tty_log.c @@ -0,0 +1,131 @@ +/**************************************************************************** + * 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 "./tty_log.h" +#include "./aqhomed_p.h" + +#include "aqhome/msg/msg_value.h" +#include "aqhome/msg/msg_value2.h" +#include "aqhome/msg/msg_sendstats.h" +#include "aqhome/msg/msg_recvstats.h" +#include "aqhome/msg/msg_memstats.h" +#include "aqhome/msg/msg_sysstats.h" +#include "aqhome/msg/msg_ping.h" +#include "aqhome/msg/msg_pong.h" +#include "aqhome/msg/msg_needaddr.h" +#include "aqhome/msg/msg_claimaddr.h" +#include "aqhome/msg/msg_haveaddr.h" +#include "aqhome/msg/msg_denyaddr.h" +#include "aqhome/msg/msg_device.h" +#include "aqhome/msg/msg_flashready.h" +#include "aqhome/msg/msg_flashstart.h" +#include "aqhome/msg/msg_flashresponse.h" +#include "aqhome/msg/msg_flashend.h" +#include "aqhome/msg/msg_flashdata.h" +#include "aqhome/msg/msg_reboot.h" + +#include +#include +#include +#include +#include + +#include + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static void _writeToLogFile(const char *filename, const char *txt); + + + +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ + +void AqHomed_LogTtyMsg(AQHOMED *aqh, const GWEN_MSG *msg) +{ + if (aqh && aqh->logFile) { + 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); + GWEN_Time_free(ti); + ti=NULL; + + msgIsValid=(AQH_NodeMsg_IsChecksumValid(msg) && AQH_NodeMsg_IsMsgComplete(msg)); + msgType=AQH_NodeMsg_GetMsgType(msg); + + if (msgIsValid) { + switch(msgType) { + case AQH_MSG_TYPE_PING: AQH_PingMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_PONG: AQH_PongMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_COMSENDSTATS: AQH_SendStatsMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_COMRECVSTATS: AQH_RecvStatsMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_TWIBUSMEMBER: AQH_NodeMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_DEBUG: AQH_NodeMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_VALUE: AQH_ValueMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_VALUE2: AQH_Value2Msg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_NEED_ADDRESS: AQH_NeedAddrMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_CLAIM_ADDRESS: AQH_ClaimAddrMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_HAVE_ADDRESS: AQH_HaveAddrMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_DENY_ADDRESS: AQH_DenyAddrMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_DEVICE: AQH_DeviceMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_MEMSTATS: AQH_MemStatsMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_SYSSTATS: AQH_SysStatsMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_FLASH_READY: AQH_FlashReadyMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_FLASH_START: AQH_FlashStartMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_FLASH_RSP: AQH_FlashResponseMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_FLASH_END: AQH_FlashEndMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_FLASH_DATA: AQH_FlashDataMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_REBOOT_REQ: AQH_RebootRequestMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_REBOOT_RSP: AQH_RebootResponseMsg_DumpToBuffer(msg, dbuf, "received"); break; + default: AQH_NodeMsg_DumpToBuffer(msg, dbuf, "received"); break; + } + } + else { + AQH_NodeMsg_DumpToBuffer(msg, dbuf, "(invalid) received"); + } + _writeToLogFile(aqh->logFile, GWEN_Buffer_GetStart(dbuf)); + GWEN_Buffer_free(dbuf); + } +} + + + +void _writeToLogFile(const char *filename, const char *txt) +{ + if (txt && *txt) { + FILE *f; + + f=fopen(filename, "a+"); + if (f) { + if (1!=fwrite(txt, strlen(txt), 1, f)) { + DBG_ERROR(AQH_LOGDOMAIN, "Error logging."); + } + fclose(f); + } + } +} + + + diff --git a/apps/aqhome-nodes/tty_log.h b/apps/aqhome-nodes/tty_log.h new file mode 100644 index 0000000..29add37 --- /dev/null +++ b/apps/aqhome-nodes/tty_log.h @@ -0,0 +1,23 @@ +/**************************************************************************** + * 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 AQHOMED_TTY_LOG_H +#define AQHOMED_TTY_LOG_H + + +#include "./aqhomed.h" + + + +void AqHomed_LogTtyMsg(AQHOMED *aqh, const GWEN_MSG *msg); + + + +#endif + + diff --git a/apps/aqhome-tool/data/adddata.c b/apps/aqhome-tool/data/adddata.c index c78445a..c171099 100644 --- a/apps/aqhome-tool/data/adddata.c +++ b/apps/aqhome-tool/data/adddata.c @@ -15,7 +15,7 @@ #include "aqhome/msg/msg_node.h" #include "aqhome/ipc/msg_ipc_result.h" -#include "aqhome/ipc/data/msg_data_datapoints.h" +#include "aqhome/ipc/data/msg_data_multidata.h" #include "aqhome/ipc/data/ipc_data.h" #include @@ -296,7 +296,7 @@ void _sendCommand(GWEN_MSG_ENDPOINT *epTcp, const char *valueName, const char *v arrayToSend[0]=timestampToSend; arrayToSend[1]=u.i; - msgOut=AQH_DataPointsDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_UPDATEDATA, 0, 0, valueName, valueUnits, arrayToSend, 1); + msgOut=AQH_MultiDataDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_UPDATEDATA, valueName, valueUnits, 0, arrayToSend, 1); GWEN_MsgEndpoint_AddSendMessage(epTcp, msgOut); } diff --git a/apps/aqhome-tool/data/getlastdatapoint.c b/apps/aqhome-tool/data/getlastdatapoint.c index 7b974c4..0abbef2 100644 --- a/apps/aqhome-tool/data/getlastdatapoint.c +++ b/apps/aqhome-tool/data/getlastdatapoint.c @@ -15,8 +15,10 @@ #include "aqhome/msg/msg_node.h" #include "aqhome/ipc/msg_ipc_result.h" -#include "aqhome/ipc/data/msg_data_datapoints.h" +#include "aqhome/ipc/data/msg_data_value.h" +#include "aqhome/ipc/data/msg_data_singledata.h" #include "aqhome/ipc/data/ipc_data.h" +#include "aqhome/ipc/msg_ipc_tag16.h" #include #include @@ -31,11 +33,22 @@ #define I18N(msg) GWEN_I18N_Translate(PACKAGE, msg) +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + static int _doGetLastDataPoint(GWEN_DB_NODE *dbArgs); static void _sendCommand(GWEN_MSG_ENDPOINT *epTcp, const char *valueName); +static int _awaitAndHandleResponse(GWEN_MSG_ENDPOINT *epTcp, int timeoutInSeconds); +static int _handleDataResponse(const GWEN_MSG *msg); +/* ------------------------------------------------------------------------------------------------ + * code + * ------------------------------------------------------------------------------------------------ + */ int AQH_Tool_GetLastDataPoint(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv) { @@ -163,8 +176,8 @@ int _doGetLastDataPoint(GWEN_DB_NODE *dbArgs) { GWEN_MSG_ENDPOINT *epTcp; int timeoutInSeconds; - GWEN_MSG *msg; const char *valueName; + int rv; timeoutInSeconds=GWEN_DB_GetIntValue(dbArgs, "timeout", 0, 5); valueName=GWEN_DB_GetCharValue(dbArgs, "valueName", 0, NULL); @@ -179,46 +192,12 @@ int _doGetLastDataPoint(GWEN_DB_NODE *dbArgs) _sendCommand(epTcp, valueName); - for (;;) { - uint16_t code; - - msg=Utils_WaitForSpecificIpcMessage(epTcp, AQH_MSGTYPE_IPC_DATA_GETLASTDATA_RSP, timeoutInSeconds); - if (msg==NULL) { - DBG_ERROR(NULL, "No response received"); - return 2; - } - code=GWEN_IpcMsg_GetCode(msg); - if (code==AQH_MSGTYPE_IPC_DATA_GETLASTDATA_RSP) { - if (AQH_DataPointsDataIpcMsg_IsValid(msg)) { - Utils_PrintDataPoints(AQH_DataPointsDataIpcMsg_GetDataPoints(msg), - AQH_DataPointsDataIpcMsg_GetNumValues(msg), - AQH_DataPointsDataIpcMsg_GetUnits(msg)); - if (AQH_DataPointsDataIpcMsg_GetFlags(msg) & AQH_MSGDATA_DATAPOINTS_FLAGS_LASTMSG) { - DBG_INFO(NULL, "Last message received"); - break; - } - } - else { - DBG_ERROR(NULL, "Invalid message received"); - GWEN_MsgEndpoint_free(epTcp); - return 3; - } - } - else if (code==AQH_MSGTYPE_IPC_DATA_RESULT) { - uint32_t resultCode; - - resultCode=AQH_ResultIpcMsg_GetResultCode(msg); - fprintf(stderr, "ERROR: %d\n", resultCode); - GWEN_MsgEndpoint_free(epTcp); - return 3; - } - else { - DBG_INFO(NULL, "Unexpected message \"%d\"", code); - GWEN_MsgEndpoint_free(epTcp); - return 3; - } - } /* for */ - + rv=_awaitAndHandleResponse(epTcp, timeoutInSeconds); + if (rv!=0) { + DBG_INFO(NULL, "here (%d)", rv); + GWEN_MsgEndpoint_free(epTcp); + return rv; + } GWEN_MsgEndpoint_free(epTcp); return 0; } @@ -229,26 +208,82 @@ void _sendCommand(GWEN_MSG_ENDPOINT *epTcp, const char *valueName) { GWEN_MSG *msgOut; - msgOut=AQH_DataPointsDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_GETLASTDATA_REQ, 0, 0, valueName, NULL, NULL, 0); + msgOut=AQH_ValueDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_GETLASTDATA_REQ, valueName, NULL, 0); GWEN_MsgEndpoint_AddSendMessage(epTcp, msgOut); } -uint64_t _getTimeStampFromString(const char *s) +int _awaitAndHandleResponse(GWEN_MSG_ENDPOINT *epTcp, int timeoutInSeconds) { - if (s && *s) { - unsigned long int x; + GWEN_MSG *msg; + uint16_t code; - if (1!=sscanf("%lu", s, &x)) { - DBG_ERROR(NULL, "ERROR: Invalid timestamp"); - return (uint64_t) (-1); + msg=Utils_WaitForSpecificIpcMessage(epTcp, AQH_MSGTYPE_IPC_DATA_GETLASTDATA_RSP, timeoutInSeconds); + if (msg) { + code=GWEN_IpcMsg_GetCode(msg); + if (code==AQH_MSGTYPE_IPC_DATA_GETLASTDATA_RSP) { + int rv; + + rv=_handleDataResponse(msg); + GWEN_Msg_free(msg); + return rv; + } + else if (code==AQH_MSGTYPE_IPC_DATA_RESULT) { + uint32_t resultCode; + + resultCode=AQH_ResultIpcMsg_GetResultCode(msg); + fprintf(stderr, "ERROR: %d\n", resultCode); + GWEN_Msg_free(msg); + return 3; + } + else { + DBG_INFO(NULL, "Unexpected message \"%d\"", code); + GWEN_Msg_free(msg); + return 3; } - return (uint64_t) x; } - return 0; + else { + DBG_ERROR(NULL, "No response received"); + return 2; + } +} + + + +int _handleDataResponse(const GWEN_MSG *msg) +{ + GWEN_TAG16_LIST *tagList; + + tagList=AQH_Tag16IpcMsg_ParseTags(msg, 0); + if (tagList) { + const GWEN_TAG16 *tag; + char *valueUnits; + uint64_t timestamp; + union {double f; uint64_t i;} u; + + tag=GWEN_Tag16_List_FindFirstByTagType(tagList, AQH_MSGDATA_SINGLEDATA_TAGS_UNITS); + valueUnits=tag?GWEN_Tag16_GetTagDataAsNewString(tag, NULL):NULL; + + tag=GWEN_Tag16_List_FindFirstByTagType(tagList, AQH_MSGDATA_SINGLEDATA_TAGS_TIME); + timestamp=tag?GWEN_Tag16_GetTagDataAsUint64(tag, 0):0; + + tag=GWEN_Tag16_List_FindFirstByTagType(tagList, AQH_MSGDATA_SINGLEDATA_TAGS_DATA); + u.i=tag?GWEN_Tag16_GetTagDataAsUint64(tag, 0):0; + + Utils_PrintSingleDataPoint(timestamp, u.f, valueUnits); + + free(valueUnits); + return 0; + } + else { + DBG_ERROR(NULL, "Invalid message received"); + return 3; + } } + + diff --git a/apps/aqhome-tool/utils.c b/apps/aqhome-tool/utils.c index 53605a7..2d230a0 100644 --- a/apps/aqhome-tool/utils.c +++ b/apps/aqhome-tool/utils.c @@ -243,14 +243,18 @@ void Utils_PrintDataPoints(const uint64_t *dataPoints, uint32_t numValues, const timestamp=*(dataPoints++); u.i=*(dataPoints++); - fprintf(stdout, "%lu\t%lf\t%s\n", - (unsigned long int) timestamp, - u.f, - valueUnits?valueUnits:""); + Utils_PrintSingleDataPoint(timestamp, u.f, valueUnits); } } +void Utils_PrintSingleDataPoint(uint64_t timestamp, double data, const char *valueUnits) +{ + fprintf(stdout, "%lu\t%lf\t%s\n", (unsigned long int) timestamp, data, valueUnits?valueUnits:""); +} + + + diff --git a/apps/aqhome-tool/utils.h b/apps/aqhome-tool/utils.h index 2fb3b8d..6e677fd 100644 --- a/apps/aqhome-tool/utils.h +++ b/apps/aqhome-tool/utils.h @@ -28,6 +28,7 @@ int Utils_SendAcceptedMsgGroups(GWEN_MSG_ENDPOINT *epTcp, uint32_t groups); GWEN_MSG_ENDPOINT *Utils_OpenConnection(GWEN_DB_NODE *dbArgs, uint32_t flags, int timeoutInSeconds); void Utils_PrintDataPoints(const uint64_t *dataPoints, uint32_t numValues, const char *valueUnits); +void Utils_PrintSingleDataPoint(uint64_t timestamp, double data, const char *valueUnits); #endif diff --git a/aqhome/ipc/0BUILD b/aqhome/ipc/0BUILD index d4f24a6..b742089 100644 --- a/aqhome/ipc/0BUILD +++ b/aqhome/ipc/0BUILD @@ -46,6 +46,7 @@ endpoint_ipc.h + endpoint_ipcclient.h msg_ipc_result.h msg_ipc_qwords.h msg_ipc_tag16.h @@ -61,6 +62,7 @@ $(local/typefiles) endpoint_ipc.c + endpoint_ipcclient.c msg_ipc_result.c msg_ipc_qwords.c msg_ipc_tag16.c diff --git a/aqhome/ipc/data/0BUILD b/aqhome/ipc/data/0BUILD index 10f885a..240f832 100644 --- a/aqhome/ipc/data/0BUILD +++ b/aqhome/ipc/data/0BUILD @@ -49,7 +49,7 @@ msg_data_values.h msg_data_datapoints.h msg_data_connect.h - msg_data_addvalue.h + msg_data_value.h msg_data_singledata.h msg_data_multidata.h msg_data_getdata.h @@ -67,7 +67,7 @@ msg_data_values.c msg_data_datapoints.c msg_data_connect.c - msg_data_addvalue.c + msg_data_value.c msg_data_singledata.c msg_data_multidata.c msg_data_getdata.c diff --git a/aqhome/ipc/data/ipc_data.h b/aqhome/ipc/data/ipc_data.h index 0f2fd45..1c924d9 100644 --- a/aqhome/ipc/data/ipc_data.h +++ b/aqhome/ipc/data/ipc_data.h @@ -23,18 +23,18 @@ #define AQH_MSGTYPE_IPC_DATA_CONNECT_REQ 0x010 /* serviceName, userName, password */ -#define AQH_MSGTYPE_IPC_DATA_UPDATEDATA 0x100 /* AQH_DataPointsDataIpcMsg */ /* TODO Multi */ -#define AQH_MSGTYPE_IPC_DATA_DATACHANGED 0x200 /* AQH_DataPointsDataIpcMsg */ /* TODO */ +#define AQH_MSGTYPE_IPC_DATA_UPDATEDATA 0x100 /* AQH_MultiDataDataIpcMsg */ +#define AQH_MSGTYPE_IPC_DATA_DATACHANGED 0x200 /* AQH_MultiDataDataIpcMsg */ -#define AQH_MSGTYPE_IPC_DATA_SETDATA 0x300 /* AQH_SingleDataDataIpcMsg */ /* Single */ +#define AQH_MSGTYPE_IPC_DATA_SETDATA 0x300 /* AQH_SingleDataDataIpcMsg */ #define AQH_MSGTYPE_IPC_DATA_ADDVALUE 0x400 /* AQH_AddValueDataIpcMsg */ #define AQH_MSGTYPE_IPC_DATA_GETDATA_REQ 0x500 /* AQH_GetDataDataIpcMsg */ #define AQH_MSGTYPE_IPC_DATA_GETDATA_RSP 0x600 /* AQH_DataPointsDataIpcMsg */ /* TODO */ -#define AQH_MSGTYPE_IPC_DATA_GETLASTDATA_REQ 0x700 /* AQH_DataPointsDataIpcMsg (0 datapoints) */ -#define AQH_MSGTYPE_IPC_DATA_GETLASTDATA_RSP 0x800 /* AQH_DataPointsDataIpcMsg */ +#define AQH_MSGTYPE_IPC_DATA_GETLASTDATA_REQ 0x700 /* AQH_ValueDataIpcMsg */ +#define AQH_MSGTYPE_IPC_DATA_GETLASTDATA_RSP 0x800 /* AQH_SingleDataDataIpcMsg */ #define AQH_MSGTYPE_IPC_DATA_GETVALUES_REQ 0x900 /* GWEN_IpcMsg */ #define AQH_MSGTYPE_IPC_DATA_GETVALUES_RSP 0xa00 /* AQH_ValuesDataIpcMsg */ /* TODO */ diff --git a/aqhome/ipc/data/msg_data_addvalue.h b/aqhome/ipc/data/msg_data_addvalue.h deleted file mode 100644 index 9adb02c..0000000 --- a/aqhome/ipc/data/msg_data_addvalue.h +++ /dev/null @@ -1,46 +0,0 @@ -/**************************************************************************** - * 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_IPC_DATA_ADDVALUE_H -#define AQH_MSG_IPC_DATA_ADDVALUE_H - - -#include - -#include - -#include - - -/** - * This message is used in request AQH_MSGTYPE_IPC_DATA_ADDVALUE_REQ. - */ - -#define AQH_MSGDATA_ADDVALUE_TAGS_NAME 0x0001 -#define AQH_MSGDATA_ADDVALUE_TAGS_UNITS 0x0002 -#define AQH_MSGDATA_ADDVALUE_TAGS_TYPE 0x0003 - - - -AQHOME_API GWEN_MSG *AQH_AddValueDataIpcMsg_new(uint16_t code, - const char *valueName, - const char *valueUnits, - int valueType); - -AQHOME_API void AQH_AddValueDataIpcMsg_DumpToBuffer(const GWEN_MSG *msg, GWEN_BUFFER *dbuf, const char *sText); - - - - - - - -#endif - - - diff --git a/aqhome/ipc/data/msg_data_addvalue.c b/aqhome/ipc/data/msg_data_value.c similarity index 69% rename from aqhome/ipc/data/msg_data_addvalue.c rename to aqhome/ipc/data/msg_data_value.c index c3d0fa1..5c4fbd0 100644 --- a/aqhome/ipc/data/msg_data_addvalue.c +++ b/aqhome/ipc/data/msg_data_value.c @@ -10,7 +10,7 @@ # include #endif -#include +#include #include #include @@ -22,25 +22,25 @@ -#define AQH_MSGDATA_ADDVALUE_MINSIZE GWEN_MSGIPC_OFFS_PAYLOAD +#define AQH_MSGDATA_VALUE_MINSIZE GWEN_MSGIPC_OFFS_PAYLOAD -GWEN_MSG *AQH_AddValueDataIpcMsg_new(uint16_t code, - const char *valueName, - const char *valueUnits, - int valueType) +GWEN_MSG *AQH_ValueDataIpcMsg_new(uint16_t code, + const char *valueName, + const char *valueUnits, + int valueType) { GWEN_MSG *msg; GWEN_BUFFER *buf; buf=GWEN_Buffer_new(0, 256, 0, 1); if (valueName && *valueName) - GWEN_Tag16_WriteStringTagToBuffer(AQH_MSGDATA_ADDVALUE_TAGS_NAME, valueName, buf); + GWEN_Tag16_WriteStringTagToBuffer(AQH_MSGDATA_VALUE_TAGS_NAME, valueName, buf); if (valueUnits && *valueUnits) - GWEN_Tag16_WriteStringTagToBuffer(AQH_MSGDATA_ADDVALUE_TAGS_UNITS, valueUnits, buf); - GWEN_Tag16_WriteUint32TagToBuffer(AQH_MSGDATA_ADDVALUE_TAGS_TYPE, valueType, buf); + GWEN_Tag16_WriteStringTagToBuffer(AQH_MSGDATA_VALUE_TAGS_UNITS, valueUnits, buf); + GWEN_Tag16_WriteUint32TagToBuffer(AQH_MSGDATA_VALUE_TAGS_TYPE, valueType, buf); msg=AQH_Tag16IpcMsg_new(AQH_IPC_PROTOCOL_DATA_ID, AQH_IPC_PROTOCOL_DATA_VERSION, code, GWEN_Buffer_GetUsedBytes(buf), (const uint8_t*) GWEN_Buffer_GetStart(buf)); @@ -51,9 +51,9 @@ GWEN_MSG *AQH_AddValueDataIpcMsg_new(uint16_t code, -void AQH_AddValueDataIpcMsg_DumpToBuffer(const GWEN_MSG *msg, GWEN_BUFFER *dbuf, const char *sText) +void AQH_ValueDataIpcMsg_DumpToBuffer(const GWEN_MSG *msg, GWEN_BUFFER *dbuf, const char *sText) { - if (GWEN_Msg_GetBytesInBuffer(msg)>=AQH_MSGDATA_ADDVALUE_MINSIZE) { + if (GWEN_Msg_GetBytesInBuffer(msg)>=AQH_MSGDATA_VALUE_MINSIZE) { GWEN_TAG16_LIST *tagList; char *valueName=NULL; char *valueUnits=NULL; @@ -63,18 +63,18 @@ void AQH_AddValueDataIpcMsg_DumpToBuffer(const GWEN_MSG *msg, GWEN_BUFFER *dbuf, if (tagList) { const GWEN_TAG16 *tag; - tag=GWEN_Tag16_List_FindFirstByTagType(tagList, AQH_MSGDATA_ADDVALUE_TAGS_NAME); + tag=GWEN_Tag16_List_FindFirstByTagType(tagList, AQH_MSGDATA_VALUE_TAGS_NAME); valueName=tag?GWEN_Tag16_GetTagDataAsNewString(tag, NULL):NULL; - tag=GWEN_Tag16_List_FindFirstByTagType(tagList, AQH_MSGDATA_ADDVALUE_TAGS_UNITS); + tag=GWEN_Tag16_List_FindFirstByTagType(tagList, AQH_MSGDATA_VALUE_TAGS_UNITS); valueUnits=tag?GWEN_Tag16_GetTagDataAsNewString(tag, NULL):NULL; - tag=GWEN_Tag16_List_FindFirstByTagType(tagList, AQH_MSGDATA_ADDVALUE_TAGS_TYPE); + tag=GWEN_Tag16_List_FindFirstByTagType(tagList, AQH_MSGDATA_VALUE_TAGS_TYPE); valueType=tag?GWEN_Tag16_GetTagDataAsUint32(tag, 0):0; } GWEN_Buffer_AppendArgs(dbuf, - "ADDVALUE (code=%d, proto=%d, proto version=%d, name=%s, units=%s, type=%d)\n", + "VALUE (code=%d, proto=%d, proto version=%d, name=%s, units=%s, type=%d)\n", GWEN_IpcMsg_GetCode(msg), GWEN_IpcMsg_GetProtoId(msg), GWEN_IpcMsg_GetProtoVersion(msg), diff --git a/aqhome/ipc/data/msg_data_value.h b/aqhome/ipc/data/msg_data_value.h new file mode 100644 index 0000000..92c2c08 --- /dev/null +++ b/aqhome/ipc/data/msg_data_value.h @@ -0,0 +1,46 @@ +/**************************************************************************** + * 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_IPC_DATA_VALUE_H +#define AQH_MSG_IPC_DATA_VALUE_H + + +#include + +#include + +#include + + +/** + * This message is used in request AQH_MSGTYPE_IPC_DATA_ADDVALUE_REQ. + */ + +#define AQH_MSGDATA_VALUE_TAGS_NAME 0x0001 +#define AQH_MSGDATA_VALUE_TAGS_UNITS 0x0002 +#define AQH_MSGDATA_VALUE_TAGS_TYPE 0x0003 + + + +AQHOME_API GWEN_MSG *AQH_ValueDataIpcMsg_new(uint16_t code, + const char *valueName, + const char *valueUnits, + int valueType); + +AQHOME_API void AQH_ValueDataIpcMsg_DumpToBuffer(const GWEN_MSG *msg, GWEN_BUFFER *dbuf, const char *sText); + + + + + + + +#endif + + + diff --git a/aqhome/ipc/endpoint_ipc.c b/aqhome/ipc/endpoint_ipc.c index db547eb..ed210c6 100644 --- a/aqhome/ipc/endpoint_ipc.c +++ b/aqhome/ipc/endpoint_ipc.c @@ -58,6 +58,7 @@ void _freeData(void *bp, void *p) free(xep->serviceName); free(xep->userName); + free(xep->password); GWEN_FREE_OBJECT(xep); } @@ -177,6 +178,35 @@ void AQH_IpcEndpoint_SetUserName(GWEN_MSG_ENDPOINT *ep, const char *s) +const char *AQH_IpcEndpoint_GetPassword(const GWEN_MSG_ENDPOINT *ep) +{ + if (ep) { + AQH_ENDPOINT_IPC *xep; + + xep=GWEN_INHERIT_GETDATA(GWEN_MSG_ENDPOINT, AQH_ENDPOINT_IPC, ep); + if (xep) + return xep->password; + } + return NULL; +} + + + +void AQH_IpcEndpoint_SetPassword(GWEN_MSG_ENDPOINT *ep, const char *s) +{ + if (ep) { + AQH_ENDPOINT_IPC *xep; + + xep=GWEN_INHERIT_GETDATA(GWEN_MSG_ENDPOINT, AQH_ENDPOINT_IPC, ep); + if (xep) { + free(xep->password); + xep->password=s?strdup(s):NULL; + } + } +} + + + uint32_t AQH_IpcEndpoint_GetPermissions(const GWEN_MSG_ENDPOINT *ep) { if (ep) { diff --git a/aqhome/ipc/endpoint_ipc.h b/aqhome/ipc/endpoint_ipc.h index 4d0266a..4da5625 100644 --- a/aqhome/ipc/endpoint_ipc.h +++ b/aqhome/ipc/endpoint_ipc.h @@ -44,6 +44,9 @@ AQHOME_API void AQH_IpcEndpoint_SetServiceName(GWEN_MSG_ENDPOINT *ep, const char AQHOME_API const char *AQH_IpcEndpoint_GetUserName(const GWEN_MSG_ENDPOINT *ep); AQHOME_API void AQH_IpcEndpoint_SetUserName(GWEN_MSG_ENDPOINT *ep, const char *s); +AQHOME_API const char *AQH_IpcEndpoint_GetPassword(const GWEN_MSG_ENDPOINT *ep); +AQHOME_API void AQH_IpcEndpoint_SetPassword(GWEN_MSG_ENDPOINT *ep, const char *s); + AQHOME_API uint32_t AQH_IpcEndpoint_GetPermissions(const GWEN_MSG_ENDPOINT *ep); AQHOME_API void AQH_IpcEndpoint_SetPermissions(GWEN_MSG_ENDPOINT *ep, uint32_t i); diff --git a/aqhome/ipc/endpoint_ipc_p.h b/aqhome/ipc/endpoint_ipc_p.h index 4d6d740..0b61bb8 100644 --- a/aqhome/ipc/endpoint_ipc_p.h +++ b/aqhome/ipc/endpoint_ipc_p.h @@ -22,6 +22,7 @@ struct AQH_ENDPOINT_IPC { uint32_t acceptedMsgGroups; char *serviceName; char *userName; + char *password; uint32_t permissions; }; diff --git a/aqhome/ipc/endpoint_ipcclient.c b/aqhome/ipc/endpoint_ipcclient.c new file mode 100644 index 0000000..eef73a9 --- /dev/null +++ b/aqhome/ipc/endpoint_ipcclient.c @@ -0,0 +1,135 @@ +/**************************************************************************** + * 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/ipc/endpoint_ipcclient.h" +#include "aqhome/ipc/data/ipc_data.h" +#include "aqhome/ipc/endpoint_ipc.h" +#include "aqhome/ipc/data/msg_data_connect.h" +#include "aqhome/ipc/msg_ipc_result.h" + +#include +#include +#include +#include + + +#define AQH_MSG_ENDPOINT_IPCCLIENT_NAME "ipc-client" + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static int _startConnect(GWEN_MSG_ENDPOINT *ep, GWEN_MSG_ENDPOINT *epChild); +static void _checkSockets(GWEN_MSG_ENDPOINT *ep, + GWEN_MSG_ENDPOINT *epChild, + GWEN_SOCKETSET *readSet, + GWEN_SOCKETSET *writeSet, + GWEN_SOCKETSET *xSet); + + + +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ + +GWEN_MSG_ENDPOINT *AQH_ClientIpcEndpoint_new(const char *name, int groupId) +{ + GWEN_MSG_ENDPOINT *ep; + + ep=GWEN_MultilayerEndpoint_new(name?name:AQH_MSG_ENDPOINT_IPCCLIENT_NAME, groupId); + GWEN_MultilayerEndpoint_SetStartConnectFn(ep, _startConnect); + GWEN_MultilayerEndpoint_SetCheckSocketsFn(ep, _checkSockets); + + return ep; +} + + + +int _startConnect(GWEN_MSG_ENDPOINT *ep, GWEN_MSG_ENDPOINT *epChild) +{ + if (epChild) { + int rv; + GWEN_MSG *msg; + uint32_t flagsForConnectMsg; + + flagsForConnectMsg=(GWEN_MsgEndpoint_GetFlags(ep) & AQH_ENDPOINT_IPCCLIENT_FLAGS_WANTUPDATES)?AQH_IPCENDPOINT_FLAGS_WANTUPDATES:0; + + rv=GWEN_TcpcEndpoint_StartConnect(epChild); + if (rv<0 && rv!=GWEN_ERROR_IN_PROGRESS) { + DBG_INFO(AQH_LOGDOMAIN, "Error starting to connect child layer (%d)", rv); + return rv; + } + msg=AQH_ConnectDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_CONNECT_REQ, + AQH_IpcEndpoint_GetServiceName(epChild), + AQH_IpcEndpoint_GetUserName(epChild), + AQH_IpcEndpoint_GetPassword(epChild), + flagsForConnectMsg); + GWEN_MsgEndpoint_AddSendMessage(epChild, msg); + GWEN_MsgEndpoint_SetState(ep, GWEN_MSG_ENDPOINT_STATE_CONNECTING); + return rv; /* result from GWEN_TcpcEndpoint_StartConnect() above */ + } + return GWEN_ERROR_GENERIC; +} + + + +void _checkSockets(GWEN_MSG_ENDPOINT *ep, + GWEN_MSG_ENDPOINT *epChild, + GWEN_SOCKETSET *readSet, + GWEN_SOCKETSET *writeSet, + GWEN_SOCKETSET *xSet) +{ + GWEN_MSG *msg; + + GWEN_MsgEndpoint_CheckSockets(epChild, readSet, writeSet, xSet); /* let base layer work */ + + msg=GWEN_MsgEndpoint_GetFirstReceivedMessage(epChild); + while(msg) { + GWEN_MSG *msgNext; + uint16_t code; + + msgNext=GWEN_Msg_List_Next(msg); + code=GWEN_IpcMsg_GetCode(msg); + if (code==AQH_MSGTYPE_IPC_DATA_RESULT) { + uint32_t resultCode; + + GWEN_Msg_List_Del(msg); /* remove from list */ + resultCode=AQH_ResultIpcMsg_GetResultCode(msg); + if (resultCode==AQH_MSG_IPC_SUCCESS) { + DBG_INFO(AQH_LOGDOMAIN, "Positive CONNECT response, connected"); + GWEN_MsgEndpoint_SetState(ep, GWEN_MSG_ENDPOINT_STATE_CONNECTED); + } + else { + DBG_ERROR(AQH_LOGDOMAIN, "Negative CONNECT response (%d)", code); + GWEN_MsgEndpoint_Disconnect(epChild); + GWEN_MsgEndpoint_Disconnect(ep); + } + GWEN_Msg_free(msg); + break; + } + else { + DBG_ERROR(AQH_LOGDOMAIN, "Ignoring response (%u)", code); + GWEN_Msg_free(msg); + } + msg=msgNext; + } /* while */ +} + + + + + + diff --git a/aqhome/ipc/endpoint_ipcclient.h b/aqhome/ipc/endpoint_ipcclient.h new file mode 100644 index 0000000..0ed01f0 --- /dev/null +++ b/aqhome/ipc/endpoint_ipcclient.h @@ -0,0 +1,46 @@ +/**************************************************************************** + * 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_ENDPOINT_IPCCLIENT_H +#define AQH_ENDPOINT_IPCCLIENT_H + + +#include + +#include + + +#define AQH_ENDPOINT_IPCCLIENT_FLAGS_WANTUPDATES 0x0001 + + +/** + * This class expects to later have a child endpoint derived in any form from GWEN_TcpcEndpoint and from + * AQH_IpcEndpoint. It allows for automatic connect/reconnect including automatic exchange of AQH_ConnectDataIpcMsg + * messages thereby combining physical and logical connection to a server in one class. + * + * Use this class like this: + * + * GWEN_MSG_ENDPOINT *clientEndpoint; + * GWEN_MSG_ENDPOINT *ipcBaseEndpoint; + * + * clientEndpoint=AQH_ClientIpcEndpoint_new("testClient", 0); + * ipcBaseEndpoint=AQH_IpcEndpoint_CreateIpcTcpClient("127.0.0.1", 1234, "ipcBaseClient", 0); + * AQH_IpcEndpoint_SetServiceName(ipcBaseEndpoint, "testclient"); + * AQH_IpcEndpoint_SetUserName(ipcBaseEndpoint, "testUser"); + * ... + * GWEN_MsgEndpoint_Tree2_AddChild(clientEndpoint, ipcBaseEndpoint); + * + * + */ + +AQHOME_API GWEN_MSG_ENDPOINT *AQH_ClientIpcEndpoint_new(const char *name, int groupId); + + + +#endif + diff --git a/aqhome/mqtt/endpoint_mqttc.c b/aqhome/mqtt/endpoint_mqttc.c index 868e80c..cf33ac6 100644 --- a/aqhome/mqtt/endpoint_mqttc.c +++ b/aqhome/mqtt/endpoint_mqttc.c @@ -156,6 +156,17 @@ uint16_t AQH_MqttClientEndpoint_GetNextPacketId(const GWEN_MSG_ENDPOINT *ep) +void _moveMessagesBetweenLists(GWEN_MSG_LIST *srcList, GWEN_MSG_LIST *dstList) +{ + GWEN_MSG *msg; + + while( (msg=GWEN_Msg_List_First(srcList)) ) { + GWEN_Msg_List_Del(msg); + GWEN_Msg_List_Add(msg, dstList); + } +} + + void _addSockets(GWEN_MSG_ENDPOINT *ep, GWEN_SOCKETSET *readSet, GWEN_SOCKETSET *writeSet, GWEN_SOCKETSET *xSet) { @@ -270,6 +281,19 @@ void _addSocketsWhenConnected(GWEN_MSG_ENDPOINT *ep, GWEN_MSG_ENDPOINT *epChild, +void _checkSocketsWhenConnected(GWEN_MSG_ENDPOINT *ep, GWEN_MSG_ENDPOINT *epChild, + GWEN_SOCKETSET *readSet, GWEN_SOCKETSET *writeSet, GWEN_SOCKETSET *xSet) +{ + _moveMessagesBetweenLists(GWEN_MsgEndpoint_GetSendMessageList(ep), GWEN_MsgEndpoint_GetSendMessageList(epChild)); + GWEN_MsgEndpoint_CheckSockets(epChild, readSet, writeSet, xSet); + _moveMessagesBetweenLists(GWEN_MsgEndpoint_GetReceivedMessageList(epChild), GWEN_MsgEndpoint_GetReceivedMessageList(ep)); +} + + + + + + void _checkSocketsWhenConnecting(GWEN_MSG_ENDPOINT *ep, GWEN_MSG_ENDPOINT *epChild, GWEN_SOCKETSET *readSet, GWEN_SOCKETSET *writeSet, GWEN_SOCKETSET *xSet) { @@ -310,16 +334,6 @@ void _checkSocketsWhenConnecting(GWEN_MSG_ENDPOINT *ep, GWEN_MSG_ENDPOINT *epChi -void _checkSocketsWhenConnected(GWEN_MSG_ENDPOINT *ep, GWEN_MSG_ENDPOINT *epChild, - GWEN_SOCKETSET *readSet, GWEN_SOCKETSET *writeSet, GWEN_SOCKETSET *xSet) -{ - _moveMessagesBetweenLists(GWEN_MsgEndpoint_GetSendMessageList(ep), GWEN_MsgEndpoint_GetSendMessageList(epChild)); - GWEN_MsgEndpoint_CheckSockets(epChild, readSet, writeSet, xSet); - _moveMessagesBetweenLists(GWEN_MsgEndpoint_GetReceivedMessageList(epChild), GWEN_MsgEndpoint_GetReceivedMessageList(ep)); -} - - - int _startConnect(GWEN_MSG_ENDPOINT *ep) { GWEN_MSG_ENDPOINT *epChild; @@ -347,18 +361,3 @@ int _startConnect(GWEN_MSG_ENDPOINT *ep) -void _moveMessagesBetweenLists(GWEN_MSG_LIST *srcList, GWEN_MSG_LIST *dstList) -{ - GWEN_MSG *msg; - - while( (msg=GWEN_Msg_List_First(srcList)) ) { - GWEN_Msg_List_Del(msg); - GWEN_Msg_List_Add(msg, dstList); - } -} - - - - - - diff --git a/aqhome/msg/msg_value2.c b/aqhome/msg/msg_value2.c index c8e8c10..7d33415 100644 --- a/aqhome/msg/msg_value2.c +++ b/aqhome/msg/msg_value2.c @@ -94,6 +94,22 @@ const char *AQH_Value2Msg_GetValueAsWindowStateString(const GWEN_MSG *msg) +const char *AQH_Value2Msg_GetValueTypeUnits(const GWEN_MSG *msg) +{ + uint8_t t; + + t=AQH_Value2Msg_GetValueType(msg); + switch(t) { + case AQH_MSG_VALUE2_TYPE_TEMP: return "Celsius"; + case AQH_MSG_VALUE2_TYPE_HUMIDITY: return "%"; + case AQH_MSG_VALUE2_TYPE_DOOR: return NULL; + default: break; + } + return NULL; +} + + + double AQH_Value2Msg_GetValue(const GWEN_MSG *msg) { if ((AQH_NodeMsg_GetMsgType(msg)==AQH_MSG_TYPE_VALUE2) && diff --git a/aqhome/msg/msg_value2.h b/aqhome/msg/msg_value2.h index e2eed77..1077f48 100644 --- a/aqhome/msg/msg_value2.h +++ b/aqhome/msg/msg_value2.h @@ -34,6 +34,7 @@ AQHOME_API double AQH_Value2Msg_GetValue(const GWEN_MSG *msg); AQHOME_API const char *AQH_Value2Msg_GetValueAsWindowStateString(const GWEN_MSG *msg); AQHOME_API const char *AQH_Value2Msg_GetValueTypeName(const GWEN_MSG *msg); +AQHOME_API const char *AQH_Value2Msg_GetValueTypeUnits(const GWEN_MSG *msg); AQHOME_API void AQH_Value2Msg_DumpToBuffer(const GWEN_MSG *msg, GWEN_BUFFER *dbuf, const char *sText); diff --git a/avr/modules/stats/main.asm b/avr/modules/stats/main.asm index 503aa9a..26a4390 100644 --- a/avr/modules/stats/main.asm +++ b/avr/modules/stats/main.asm @@ -11,12 +11,12 @@ ; *************************************************************************** ; defines -.equ STATS_POS_MAX = 4 -.equ STATS_POS_SEND = 4 -.equ STATS_POS_RECV = 3 -.equ STATS_POS_SYS = 2 -.equ STATS_POS_MEM = 1 - +.equ STATS_POS_MAX = 5 +.equ STATS_POS_DEVICE = 5 +.equ STATS_POS_SEND = 4 +.equ STATS_POS_RECV = 3 +.equ STATS_POS_SYS = 2 +.equ STATS_POS_MEM = 1 ; *************************************************************************** @@ -57,7 +57,7 @@ Stats_Run: cli ldi xl, LOW(com2SendBuffer) ldi xh, HIGH(com2SendBuffer) - ldi r16, 0xff + ldi r16, 0xff ; broadcast lds r17, statsRemaining tst r17 @@ -83,6 +83,11 @@ Stats_Run_l3: rcall CPRO_WriteComSendStats rjmp Stats_Run_SendPacket Stats_Run_l4: + cpi r17, STATS_POS_DEVICE + brne Stats_Run_l5 + rcall CPRO_WriteDevice + rjmp Stats_Run_SendPacket +Stats_Run_l5: ; add more stats here rjmp Stats_Run_done Stats_Run_SendPacket: