Started working on aqhome-nodes which will replace aqhomed.

This commit is contained in:
Martin Preuss
2023-09-13 23:31:02 +02:00
parent 161b979e84
commit 9b7d043682
49 changed files with 3143 additions and 258 deletions

View File

@@ -7,6 +7,7 @@
aqhome-tool aqhome-tool
aqhome-mqttlog aqhome-mqttlog
aqhome-data aqhome-data
aqhome-nodes
</subdirs> </subdirs>
</gwbuild> </gwbuild>

View File

@@ -17,7 +17,7 @@
#include "aqhome/ipc/data/ipc_data.h" #include "aqhome/ipc/data/ipc_data.h"
#include "aqhome/ipc/endpoint_ipc.h" #include "aqhome/ipc/endpoint_ipc.h"
#include "aqhome/ipc/msg_ipc_result.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 "aqhome/ipc/msg_ipc_tag16.h"
#include <gwenhywfar/debug.h> #include <gwenhywfar/debug.h>
@@ -59,13 +59,13 @@ void AqHomeData_HandleAddValue(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GW
if (tagList) { if (tagList) {
const GWEN_TAG16 *tag; 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; 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; 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; valueType=tag?GWEN_Tag16_GetTagDataAsUint32(tag, 0):0;
} }

View File

@@ -14,9 +14,11 @@
#include "./c_getlastdatapoint.h" #include "./c_getlastdatapoint.h"
#include "./aqhome_data_p.h" #include "./aqhome_data_p.h"
#include "aqhome/ipc/data/ipc_data.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/endpoint_ipc.h"
#include "aqhome/ipc/msg_ipc_result.h" #include "aqhome/ipc/msg_ipc_result.h"
#include "aqhome/ipc/msg_ipc_tag16.h"
#include <gwenhywfar/debug.h> #include <gwenhywfar/debug.h>
#include <gwenhywfar/text.h> #include <gwenhywfar/text.h>
@@ -46,69 +48,60 @@
void AqHomeData_HandleGetLastDataPoint(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *recvdMsg) void AqHomeData_HandleGetLastDataPoint(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *recvdMsg)
{ {
GWEN_MSG *outMsg; GWEN_MSG *outMsg;
int resultCode=0; int resultCode=AQH_MSG_IPC_SUCCESS;
if (AQH_IpcEndpoint_GetPermissions(ep) & AQH_IPCENDPOINT_PERMS_READDATA) { if (AQH_IpcEndpoint_GetPermissions(ep) & AQH_IPCENDPOINT_PERMS_READDATA) {
if (AQH_DataPointsDataIpcMsg_IsValid(recvdMsg)) { GWEN_TAG16_LIST *tagList;
const char *valueName; const AQH_VALUE *value;
char *valueName=NULL;
valueName=AQH_DataPointsDataIpcMsg_GetValueName(recvdMsg); tagList=AQH_Tag16IpcMsg_ParseTags(recvdMsg, 0);
if (valueName) { if (tagList) {
const AQH_VALUE *value; const GWEN_TAG16 *tag;
value=AQH_Storage_GetValueByNameForSystem(aqh->storage, valueName); tag=GWEN_Tag16_List_FindFirstByTagType(tagList, AQH_MSGDATA_VALUE_TAGS_NAME);
if (value) { valueName=tag?GWEN_Tag16_GetTagDataAsNewString(tag, NULL):NULL;
uint64_t valueId; }
uint64_t timestamp=0;
union {double f; uint64_t i;} u;
int rv;
valueId=AQH_Value_GetId(value); value=AQH_Storage_GetValueByNameForSystem(aqh->storage, valueName);
rv=AQH_Storage_GetLastDataPoint(aqh->storage, valueId, &timestamp, &(u.f)); if (value) {
if (rv<0) { uint64_t timestamp=0;
switch(rv) { double data=0.0;
case GWEN_ERROR_INVALID: resultCode=AQH_MSG_IPC_ERROR_INVALID; break; int rv;
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];
array[0]=timestamp; rv=AQH_Storage_GetLastDataPoint(aqh->storage, AQH_Value_GetId(value), &timestamp, &data);
array[1]=u.i; if (rv<0) {
outMsg=AQH_DataPointsDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_GETLASTDATA_RSP, AQH_MSGDATA_DATAPOINTS_FLAGS_LASTMSG, switch(rv) {
valueId, case GWEN_ERROR_INVALID: resultCode=AQH_MSG_IPC_ERROR_INVALID; break;
AQH_Value_GetNameForSystem(value), case GWEN_ERROR_NO_DATA: resultCode=AQH_MSG_IPC_ERROR_NODATA; break;
AQH_Value_GetValueUnits(value), default: resultCode=AQH_MSG_IPC_ERROR_GENERIC; break;
array, 1); }
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
return;
}
}
else {
DBG_INFO(NULL, "Value \"%s\" not found", valueName);
resultCode=AQH_MSG_IPC_ERROR_NOTFOUND;
}
} }
else { else {
DBG_INFO(NULL, "No value name in request"); outMsg=AQH_SingleDataDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_GETLASTDATA_RSP,
resultCode=AQH_MSG_IPC_ERROR_INVALID; AQH_Value_GetNameForSystem(value),
AQH_Value_GetValueUnits(value),
AQH_Value_GetValueType(value),
timestamp, data);
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
free(valueName);
return;
} }
} }
else { else {
DBG_INFO(NULL, "Invalid request message"); DBG_INFO(NULL, "Value \"%s\" not found", valueName);
resultCode=AQH_MSG_IPC_ERROR_INVALID; resultCode=AQH_MSG_IPC_ERROR_NOTFOUND;
} }
free(valueName);
} }
else { else {
DBG_ERROR(AQH_LOGDOMAIN, "No permissions to read data"); DBG_ERROR(AQH_LOGDOMAIN, "No permissions to read data");
resultCode=AQH_MSG_IPC_ERROR_PERMS; resultCode=AQH_MSG_IPC_ERROR_PERMS;
} }
outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT, resultCode); outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT, resultCode);
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg); GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
} }

View File

@@ -15,9 +15,10 @@
#include "./aqhome_data_p.h" #include "./aqhome_data_p.h"
#include "./loop.h" #include "./loop.h"
#include "aqhome/ipc/data/ipc_data.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/endpoint_ipc.h"
#include "aqhome/ipc/msg_ipc_result.h" #include "aqhome/ipc/msg_ipc_result.h"
#include "aqhome/ipc/msg_ipc_tag16.h"
#include <gwenhywfar/debug.h> #include <gwenhywfar/debug.h>
@@ -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, static void _sendDataChangedMsgToAllClients(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *epSrc, const AQH_VALUE *v,
const uint64_t *dataPoints, uint32_t numValues); 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; GWEN_MSG *outMsg;
int resultCode=AQH_MSG_IPC_SUCCESS; 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) { tagList=AQH_Tag16IpcMsg_ParseTags(recvdMsg, 0);
if (AQH_DataPointsDataIpcMsg_IsValid(recvdMsg)) { if (tagList) {
uint32_t numValues; const GWEN_TAG16 *tag;
numValues=AQH_DataPointsDataIpcMsg_GetNumValues(recvdMsg); tag=GWEN_Tag16_List_FindFirstByTagType(tagList, AQH_MSGDATA_MULTIDATA_TAGS_NAME);
if (numValues) { valueName=tag?GWEN_Tag16_GetTagDataAsNewString(tag, NULL):NULL;
const char *s;
tag=GWEN_Tag16_List_FindFirstByTagType(tagList, AQH_MSGDATA_MULTIDATA_TAGS_UNITS);
s=AQH_DataPointsDataIpcMsg_GetValueName(recvdMsg); valueUnits=tag?GWEN_Tag16_GetTagDataAsNewString(tag, NULL):NULL;
if (s && *s) {
AQH_VALUE *v; tag=GWEN_Tag16_List_FindFirstByTagType(tagList, AQH_MSGDATA_MULTIDATA_TAGS_TYPE);
valueType=tag?GWEN_Tag16_GetTagDataAsUint32(tag, 0):0;
v=AqHomeData_GetOrCreateValueForDriver(aqh, ep, s, AQH_DataPointsDataIpcMsg_GetUnits(recvdMsg), 0);
if (v==NULL) { tag=GWEN_Tag16_List_FindFirstByTagType(tagList, AQH_MSGDATA_MULTIDATA_TAGS_DATA);
resultCode=AQH_MSG_IPC_ERROR_PERMS; dataPoints=(const uint64_t*)GWEN_Tag16_GetTagData(tag);
} numberOfPoints=(tag?GWEN_Tag16_GetTagLength(tag):0)/(2*sizeof(uint64_t));
else { }
const uint64_t *dataPoints;
if (numberOfPoints>0) {
dataPoints=AQH_DataPointsDataIpcMsg_GetDataPoints(recvdMsg); AQH_VALUE *value;
if (dataPoints)
resultCode=_readDataPoints(aqh, v, dataPoints, numValues); value=AqHomeData_GetOrCreateValueForDriver(aqh, ep, valueName, valueUnits, valueType);
else { if (value) {
DBG_INFO(NULL, "No datapoints"); resultCode=_storeDataPoints(aqh, value, dataPoints, numberOfPoints);
resultCode=AQH_MSG_IPC_ERROR_BADDATA; if (resultCode==AQH_MSG_IPC_SUCCESS)
} _sendDataChangedMsgToAllClients(aqh, ep, value, dataPoints, numberOfPoints);
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;
}
} }
else { else {
DBG_INFO(NULL, "Invalid message received"); DBG_INFO(NULL, "No permissions to add datapoint for value \"%s\"", valueName);
resultCode=AQH_MSG_IPC_ERROR_BADDATA; resultCode=AQH_MSG_IPC_ERROR_PERMS;
} }
} }
else { else {
DBG_ERROR(AQH_LOGDOMAIN, "No permissions to add data"); DBG_INFO(NULL, "No datapoints");
resultCode=AQH_MSG_IPC_ERROR_PERMS; resultCode=AQH_MSG_IPC_ERROR_INVALID;
} }
free(valueName);
outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT, resultCode); outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT, resultCode);
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg); 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; uint32_t i;
@@ -145,13 +141,12 @@ void _sendDataChangedMsgToAllClients(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *epSrc,
GWEN_MSG *msg; GWEN_MSG *msg;
DBG_INFO(AQH_LOGDOMAIN, "Sending update msg to endpoint %s", GWEN_MsgEndpoint_GetName(ep)); DBG_INFO(AQH_LOGDOMAIN, "Sending update msg to endpoint %s", GWEN_MsgEndpoint_GetName(ep));
msg=AQH_DataPointsDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_DATACHANGED, msg=AQH_MultiDataDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_DATACHANGED,
0, /* flags */ AQH_Value_GetNameForSystem(v),
AQH_Value_GetId(v), AQH_Value_GetValueUnits(v),
AQH_Value_GetNameForSystem(v), AQH_Value_GetValueType(v),
AQH_Value_GetValueUnits(v), dataPoints, numValues);
dataPoints, numValues); GWEN_MsgEndpoint_AddSendMessage(ep, msg);
GWEN_MsgEndpoint_AddSendMessage(ep, msg);
} }
else { else {
DBG_INFO(AQH_LOGDOMAIN, "Endpoint %s doesn't want updates", GWEN_MsgEndpoint_GetName(ep)); DBG_INFO(AQH_LOGDOMAIN, "Endpoint %s doesn't want updates", GWEN_MsgEndpoint_GetName(ep));

83
apps/aqhome-nodes/0BUILD Normal file
View File

@@ -0,0 +1,83 @@
<?xml?>
<gwbuild>
<target type="Program" name="aqhome-nodes" install="$(sbindir)" >
<includes type="c" >
$(gwenhywfar_cflags)
-I$(topsrcdir)
-I$(topbuilddir)
</includes>
<includes type="tm2" >
--include=$(builddir)
--include=$(srcdir)
</includes>
<setVar name="local/cflags">$(visibility_cflags)</setVar>
<setVar name="tm2flags" >
</setVar>
<setVar name="local/typefiles" >
</setVar>
<setVar name="local/built_sources" >
</setVar>
<setVar name="local/built_headers_pub">
</setVar>
<setVar name="local/built_headers_priv" >
</setVar>
<headers dist="true" >
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
</headers>
<sources>
$(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
</sources>
<useTargets>
aqhome
</useTargets>
<libraries>
$(gwenhywfar_libs)
</libraries>
<subdirs>
</subdirs>
<extradist>
</extradist>
</target>
</gwbuild>

159
apps/aqhome-nodes/aqhomed.c Normal file
View File

@@ -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 <config.h>
#endif
#include "./aqhomed_p.h"
#include "./tty_log.h"
#include "aqhome/msg/endpoint_tty.h"
#include "aqhome/ipc/endpoint_ipc.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/debug.h>
/* ------------------------------------------------------------------------------------------------
* 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;
}
}

View File

@@ -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 <gwenhywfar/endpoint.h>
#include <gwenhywfar/db.h>
#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

View File

@@ -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

278
apps/aqhome-nodes/db.c Normal file
View File

@@ -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 <config.h>
#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 <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint_tcpd.h>
#include <gwenhywfar/timestamp.h>
/* ------------------------------------------------------------------------------------------------
* 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);
}

23
apps/aqhome-nodes/db.h Normal file
View File

@@ -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

86
apps/aqhome-nodes/fini.c Normal file
View File

@@ -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 <config.h>
#endif
#include "./fini.h"
#include "./aqhomed_p.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint_tcpd.h>
#include <unistd.h>
/* ------------------------------------------------------------------------------------------------
* 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);
}

23
apps/aqhome-nodes/fini.h Normal file
View File

@@ -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

472
apps/aqhome-nodes/init.c Normal file
View File

@@ -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 <config.h>
#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 <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint_tcpd.h>
#include <gwenhywfar/endpoint_multilayer.h>
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <time.h>
/* ------------------------------------------------------------------------------------------------
* 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;
}

23
apps/aqhome-nodes/init.h Normal file
View File

@@ -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

23
apps/aqhome-nodes/ipc.h Normal file
View File

@@ -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

79
apps/aqhome-nodes/loop.c Normal file
View File

@@ -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 <config.h>
#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 <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint_tcpd.h>
/* ------------------------------------------------------------------------------------------------
* 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);
}
}
}
}

23
apps/aqhome-nodes/loop.h Normal file
View File

@@ -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

View File

@@ -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 <config.h>
#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 <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint_tcpd.h>
/* ------------------------------------------------------------------------------------------------
* 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);
}
}

View File

@@ -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

View File

@@ -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 <config.h>
#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 <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint_tcpd.h>
/* ------------------------------------------------------------------------------------------------
* 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);
}

View File

@@ -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

View File

@@ -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 <config.h>
#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 <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint_tcpd.h>
/* ------------------------------------------------------------------------------------------------
* 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);
}

View File

@@ -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

View File

@@ -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 <config.h>
#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 <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint_tcpd.h>
/* ------------------------------------------------------------------------------------------------
* 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);
}

View File

@@ -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

View File

@@ -0,0 +1,215 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./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 <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint_tcpd.h>
/* ------------------------------------------------------------------------------------------------
* 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);
}

View File

@@ -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

191
apps/aqhome-nodes/main.c Normal file
View File

@@ -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 <config.h>
#endif
#include <aqhome/api.h>
#include <aqhome/aqhome.h>
#include "./aqhomed.h"
#include "./init.h"
#include "./fini.h"
#include "./loop.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/logger.h>
#include <gwenhywfar/cgui.h>
#include <gwenhywfar/debug.h>
#ifdef HAVE_SIGNAL_H
# include <signal.h>
#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;
}
}

131
apps/aqhome-nodes/tty_log.c Normal file
View File

@@ -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 <config.h>
#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 <gwenhywfar/list.h>
#include <gwenhywfar/inherit.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/gwentime.h>
#include <gwenhywfar/text.h>
#include <stdio.h>
/* ------------------------------------------------------------------------------------------------
* 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);
}
}
}

View File

@@ -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

View File

@@ -15,7 +15,7 @@
#include "aqhome/msg/msg_node.h" #include "aqhome/msg/msg_node.h"
#include "aqhome/ipc/msg_ipc_result.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 "aqhome/ipc/data/ipc_data.h"
#include <gwenhywfar/args.h> #include <gwenhywfar/args.h>
@@ -296,7 +296,7 @@ void _sendCommand(GWEN_MSG_ENDPOINT *epTcp, const char *valueName, const char *v
arrayToSend[0]=timestampToSend; arrayToSend[0]=timestampToSend;
arrayToSend[1]=u.i; 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); GWEN_MsgEndpoint_AddSendMessage(epTcp, msgOut);
} }

View File

@@ -15,8 +15,10 @@
#include "aqhome/msg/msg_node.h" #include "aqhome/msg/msg_node.h"
#include "aqhome/ipc/msg_ipc_result.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/data/ipc_data.h"
#include "aqhome/ipc/msg_ipc_tag16.h"
#include <gwenhywfar/args.h> #include <gwenhywfar/args.h>
#include <gwenhywfar/i18n.h> #include <gwenhywfar/i18n.h>
@@ -31,11 +33,22 @@
#define I18N(msg) GWEN_I18N_Translate(PACKAGE, msg) #define I18N(msg) GWEN_I18N_Translate(PACKAGE, msg)
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static int _doGetLastDataPoint(GWEN_DB_NODE *dbArgs); static int _doGetLastDataPoint(GWEN_DB_NODE *dbArgs);
static void _sendCommand(GWEN_MSG_ENDPOINT *epTcp, const char *valueName); 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) 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; GWEN_MSG_ENDPOINT *epTcp;
int timeoutInSeconds; int timeoutInSeconds;
GWEN_MSG *msg;
const char *valueName; const char *valueName;
int rv;
timeoutInSeconds=GWEN_DB_GetIntValue(dbArgs, "timeout", 0, 5); timeoutInSeconds=GWEN_DB_GetIntValue(dbArgs, "timeout", 0, 5);
valueName=GWEN_DB_GetCharValue(dbArgs, "valueName", 0, NULL); valueName=GWEN_DB_GetCharValue(dbArgs, "valueName", 0, NULL);
@@ -179,46 +192,12 @@ int _doGetLastDataPoint(GWEN_DB_NODE *dbArgs)
_sendCommand(epTcp, valueName); _sendCommand(epTcp, valueName);
for (;;) { rv=_awaitAndHandleResponse(epTcp, timeoutInSeconds);
uint16_t code; if (rv!=0) {
DBG_INFO(NULL, "here (%d)", rv);
msg=Utils_WaitForSpecificIpcMessage(epTcp, AQH_MSGTYPE_IPC_DATA_GETLASTDATA_RSP, timeoutInSeconds); GWEN_MsgEndpoint_free(epTcp);
if (msg==NULL) { return rv;
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 */
GWEN_MsgEndpoint_free(epTcp); GWEN_MsgEndpoint_free(epTcp);
return 0; return 0;
} }
@@ -229,26 +208,82 @@ void _sendCommand(GWEN_MSG_ENDPOINT *epTcp, const char *valueName)
{ {
GWEN_MSG *msgOut; 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); GWEN_MsgEndpoint_AddSendMessage(epTcp, msgOut);
} }
uint64_t _getTimeStampFromString(const char *s) int _awaitAndHandleResponse(GWEN_MSG_ENDPOINT *epTcp, int timeoutInSeconds)
{ {
if (s && *s) { GWEN_MSG *msg;
unsigned long int x; uint16_t code;
if (1!=sscanf("%lu", s, &x)) { msg=Utils_WaitForSpecificIpcMessage(epTcp, AQH_MSGTYPE_IPC_DATA_GETLASTDATA_RSP, timeoutInSeconds);
DBG_ERROR(NULL, "ERROR: Invalid timestamp"); if (msg) {
return (uint64_t) (-1); 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;
}
} }

View File

@@ -243,14 +243,18 @@ void Utils_PrintDataPoints(const uint64_t *dataPoints, uint32_t numValues, const
timestamp=*(dataPoints++); timestamp=*(dataPoints++);
u.i=*(dataPoints++); u.i=*(dataPoints++);
fprintf(stdout, "%lu\t%lf\t%s\n", Utils_PrintSingleDataPoint(timestamp, u.f, valueUnits);
(unsigned long int) timestamp,
u.f,
valueUnits?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:"");
}

View File

@@ -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); 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_PrintDataPoints(const uint64_t *dataPoints, uint32_t numValues, const char *valueUnits);
void Utils_PrintSingleDataPoint(uint64_t timestamp, double data, const char *valueUnits);
#endif #endif

View File

@@ -46,6 +46,7 @@
<headers dist="true" install="$(pkgincludedir)/ipc" > <headers dist="true" install="$(pkgincludedir)/ipc" >
endpoint_ipc.h endpoint_ipc.h
endpoint_ipcclient.h
msg_ipc_result.h msg_ipc_result.h
msg_ipc_qwords.h msg_ipc_qwords.h
msg_ipc_tag16.h msg_ipc_tag16.h
@@ -61,6 +62,7 @@
$(local/typefiles) $(local/typefiles)
endpoint_ipc.c endpoint_ipc.c
endpoint_ipcclient.c
msg_ipc_result.c msg_ipc_result.c
msg_ipc_qwords.c msg_ipc_qwords.c
msg_ipc_tag16.c msg_ipc_tag16.c

View File

@@ -49,7 +49,7 @@
msg_data_values.h msg_data_values.h
msg_data_datapoints.h msg_data_datapoints.h
msg_data_connect.h msg_data_connect.h
msg_data_addvalue.h msg_data_value.h
msg_data_singledata.h msg_data_singledata.h
msg_data_multidata.h msg_data_multidata.h
msg_data_getdata.h msg_data_getdata.h
@@ -67,7 +67,7 @@
msg_data_values.c msg_data_values.c
msg_data_datapoints.c msg_data_datapoints.c
msg_data_connect.c msg_data_connect.c
msg_data_addvalue.c msg_data_value.c
msg_data_singledata.c msg_data_singledata.c
msg_data_multidata.c msg_data_multidata.c
msg_data_getdata.c msg_data_getdata.c

View File

@@ -23,18 +23,18 @@
#define AQH_MSGTYPE_IPC_DATA_CONNECT_REQ 0x010 /* serviceName, userName, password */ #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_UPDATEDATA 0x100 /* AQH_MultiDataDataIpcMsg */
#define AQH_MSGTYPE_IPC_DATA_DATACHANGED 0x200 /* AQH_DataPointsDataIpcMsg */ /* TODO */ #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_ADDVALUE 0x400 /* AQH_AddValueDataIpcMsg */
#define AQH_MSGTYPE_IPC_DATA_GETDATA_REQ 0x500 /* AQH_GetDataDataIpcMsg */ #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_GETDATA_RSP 0x600 /* AQH_DataPointsDataIpcMsg */ /* TODO */
#define AQH_MSGTYPE_IPC_DATA_GETLASTDATA_REQ 0x700 /* AQH_DataPointsDataIpcMsg (0 datapoints) */ #define AQH_MSGTYPE_IPC_DATA_GETLASTDATA_REQ 0x700 /* AQH_ValueDataIpcMsg */
#define AQH_MSGTYPE_IPC_DATA_GETLASTDATA_RSP 0x800 /* AQH_DataPointsDataIpcMsg */ #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_REQ 0x900 /* GWEN_IpcMsg */
#define AQH_MSGTYPE_IPC_DATA_GETVALUES_RSP 0xa00 /* AQH_ValuesDataIpcMsg */ /* TODO */ #define AQH_MSGTYPE_IPC_DATA_GETVALUES_RSP 0xa00 /* AQH_ValuesDataIpcMsg */ /* TODO */

View File

@@ -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 <aqhome/api.h>
#include <aqhome/data/value.h>
#include <gwenhywfar/msg_ipc.h>
/**
* 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

View File

@@ -10,7 +10,7 @@
# include <config.h> # include <config.h>
#endif #endif
#include <aqhome/ipc/data/msg_data_addvalue.h> #include <aqhome/ipc/data/msg_data_value.h>
#include <aqhome/ipc/data/ipc_data.h> #include <aqhome/ipc/data/ipc_data.h>
#include <aqhome/ipc/msg_ipc_tag16.h> #include <aqhome/ipc/msg_ipc_tag16.h>
@@ -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, GWEN_MSG *AQH_ValueDataIpcMsg_new(uint16_t code,
const char *valueName, const char *valueName,
const char *valueUnits, const char *valueUnits,
int valueType) int valueType)
{ {
GWEN_MSG *msg; GWEN_MSG *msg;
GWEN_BUFFER *buf; GWEN_BUFFER *buf;
buf=GWEN_Buffer_new(0, 256, 0, 1); buf=GWEN_Buffer_new(0, 256, 0, 1);
if (valueName && *valueName) 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) if (valueUnits && *valueUnits)
GWEN_Tag16_WriteStringTagToBuffer(AQH_MSGDATA_ADDVALUE_TAGS_UNITS, valueUnits, buf); GWEN_Tag16_WriteStringTagToBuffer(AQH_MSGDATA_VALUE_TAGS_UNITS, valueUnits, buf);
GWEN_Tag16_WriteUint32TagToBuffer(AQH_MSGDATA_ADDVALUE_TAGS_TYPE, valueType, 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, 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)); 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; GWEN_TAG16_LIST *tagList;
char *valueName=NULL; char *valueName=NULL;
char *valueUnits=NULL; char *valueUnits=NULL;
@@ -63,18 +63,18 @@ void AQH_AddValueDataIpcMsg_DumpToBuffer(const GWEN_MSG *msg, GWEN_BUFFER *dbuf,
if (tagList) { if (tagList) {
const GWEN_TAG16 *tag; 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; 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; 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; valueType=tag?GWEN_Tag16_GetTagDataAsUint32(tag, 0):0;
} }
GWEN_Buffer_AppendArgs(dbuf, 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_GetCode(msg),
GWEN_IpcMsg_GetProtoId(msg), GWEN_IpcMsg_GetProtoId(msg),
GWEN_IpcMsg_GetProtoVersion(msg), GWEN_IpcMsg_GetProtoVersion(msg),

View File

@@ -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 <aqhome/api.h>
#include <aqhome/data/value.h>
#include <gwenhywfar/msg_ipc.h>
/**
* 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

View File

@@ -58,6 +58,7 @@ void _freeData(void *bp, void *p)
free(xep->serviceName); free(xep->serviceName);
free(xep->userName); free(xep->userName);
free(xep->password);
GWEN_FREE_OBJECT(xep); 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) uint32_t AQH_IpcEndpoint_GetPermissions(const GWEN_MSG_ENDPOINT *ep)
{ {
if (ep) { if (ep) {

View File

@@ -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 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 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 uint32_t AQH_IpcEndpoint_GetPermissions(const GWEN_MSG_ENDPOINT *ep);
AQHOME_API void AQH_IpcEndpoint_SetPermissions(GWEN_MSG_ENDPOINT *ep, uint32_t i); AQHOME_API void AQH_IpcEndpoint_SetPermissions(GWEN_MSG_ENDPOINT *ep, uint32_t i);

View File

@@ -22,6 +22,7 @@ struct AQH_ENDPOINT_IPC {
uint32_t acceptedMsgGroups; uint32_t acceptedMsgGroups;
char *serviceName; char *serviceName;
char *userName; char *userName;
char *password;
uint32_t permissions; uint32_t permissions;
}; };

View File

@@ -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 <config.h>
#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 <gwenhywfar/endpoint_ipc.h>
#include <gwenhywfar/endpoint_tcpc.h>
#include <gwenhywfar/endpoint_multilayer.h>
#include <gwenhywfar/debug.h>
#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 */
}

View File

@@ -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 <aqhome/api.h>
#include <gwenhywfar/endpoint.h>
#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:
* <code>
* 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);
* </code>
*
*/
AQHOME_API GWEN_MSG_ENDPOINT *AQH_ClientIpcEndpoint_new(const char *name, int groupId);
#endif

View File

@@ -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) 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, void _checkSocketsWhenConnecting(GWEN_MSG_ENDPOINT *ep, GWEN_MSG_ENDPOINT *epChild,
GWEN_SOCKETSET *readSet, GWEN_SOCKETSET *writeSet, GWEN_SOCKETSET *xSet) 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) int _startConnect(GWEN_MSG_ENDPOINT *ep)
{ {
GWEN_MSG_ENDPOINT *epChild; 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);
}
}

View File

@@ -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) double AQH_Value2Msg_GetValue(const GWEN_MSG *msg)
{ {
if ((AQH_NodeMsg_GetMsgType(msg)==AQH_MSG_TYPE_VALUE2) && if ((AQH_NodeMsg_GetMsgType(msg)==AQH_MSG_TYPE_VALUE2) &&

View File

@@ -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_GetValueAsWindowStateString(const GWEN_MSG *msg);
AQHOME_API const char *AQH_Value2Msg_GetValueTypeName(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); AQHOME_API void AQH_Value2Msg_DumpToBuffer(const GWEN_MSG *msg, GWEN_BUFFER *dbuf, const char *sText);

View File

@@ -11,12 +11,12 @@
; *************************************************************************** ; ***************************************************************************
; defines ; defines
.equ STATS_POS_MAX = 4 .equ STATS_POS_MAX = 5
.equ STATS_POS_SEND = 4 .equ STATS_POS_DEVICE = 5
.equ STATS_POS_RECV = 3 .equ STATS_POS_SEND = 4
.equ STATS_POS_SYS = 2 .equ STATS_POS_RECV = 3
.equ STATS_POS_MEM = 1 .equ STATS_POS_SYS = 2
.equ STATS_POS_MEM = 1
; *************************************************************************** ; ***************************************************************************
@@ -57,7 +57,7 @@ Stats_Run:
cli cli
ldi xl, LOW(com2SendBuffer) ldi xl, LOW(com2SendBuffer)
ldi xh, HIGH(com2SendBuffer) ldi xh, HIGH(com2SendBuffer)
ldi r16, 0xff ldi r16, 0xff ; broadcast
lds r17, statsRemaining lds r17, statsRemaining
tst r17 tst r17
@@ -83,6 +83,11 @@ Stats_Run_l3:
rcall CPRO_WriteComSendStats rcall CPRO_WriteComSendStats
rjmp Stats_Run_SendPacket rjmp Stats_Run_SendPacket
Stats_Run_l4: 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 ; add more stats here
rjmp Stats_Run_done rjmp Stats_Run_done
Stats_Run_SendPacket: Stats_Run_SendPacket: