More work on aqhome-react.

This commit is contained in:
Martin Preuss
2024-03-09 01:23:06 +01:00
parent 605d78a2b7
commit a3efa18a61
28 changed files with 1661 additions and 61 deletions

View File

@@ -39,16 +39,24 @@
<headers dist="true" > <headers dist="true" >
aqhome_react.h aqhome_react.h
aqhome_react_p.h aqhome_react_p.h
init.h
fini.h
loop.h
</headers> </headers>
<sources> <sources>
$(local/typefiles) $(local/typefiles)
aqhome_react.c
init.c
fini.c
loop.c
main.c main.c
</sources> </sources>
<useTargets> <useTargets>
aqhome aqhome
aqhreact_types aqhreact_types
aqhreact_units
</useTargets> </useTargets>
<libraries> <libraries>
@@ -57,6 +65,7 @@
<subdirs> <subdirs>
types types
units
</subdirs> </subdirs>

View File

@@ -0,0 +1,86 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2024 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_react_p.h"
#include <gwenhywfar/misc.h>
#include <gwenhywfar/debug.h>
AQHOME_REACT *AqHomeReact_new()
{
AQHOME_REACT *aqh;
GWEN_NEW_OBJECT(AQHOME_REACT, aqh);
return aqh;
}
void AqHomeReact_free(AQHOME_REACT *aqh)
{
if (aqh) {
GWEN_MsgEndpoint_free(aqh->brokerEndpoint);
GWEN_DB_Group_free(aqh->dbArgs);
free(aqh->pidFile);
GWEN_FREE_OBJECT(aqh);
}
}
GWEN_MSG_ENDPOINT *AqHomeReact_GetBrokerEndpoint(const AQHOME_REACT *aqh)
{
return aqh?(aqh->brokerEndpoint):NULL;
}
GWEN_DB_NODE *AqHomeReact_GetDbArgs(const AQHOME_REACT *aqh)
{
return aqh?(aqh->dbArgs):NULL;
}
const char *AqHomeReact_GetPidFile(const AQHOME_REACT *aqh)
{
return aqh?aqh->pidFile:NULL;
}
void AqHomeReact_SetPidFile(AQHOME_REACT *aqh, const char *s)
{
if (aqh) {
free(aqh->pidFile);
aqh->pidFile=s?strdup(s):NULL;
}
}
int AqHomeReact_GetTimeout(const AQHOME_REACT *aqh)
{
return aqh?aqh->timeout:0;
}

View File

@@ -1,6 +1,6 @@
/**************************************************************************** /****************************************************************************
* This file is part of the project AqHome. * This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved. * AqHome (c) by 2024 Martin Preuss, all rights reserved.
* *
* The license for this file can be found in the file COPYING which you * The license for this file can be found in the file COPYING which you
* should have received along with this file. * should have received along with this file.
@@ -13,24 +13,22 @@
#include <gwenhywfar/endpoint.h> #include <gwenhywfar/endpoint.h>
#define AQHOME_REACT_DEFAULT_PIDFILE "/var/run/aqhome-react.pid" typedef struct AQHOME_REACT AQHOME_REACT;
#define AQHOME_REACT_DEFAULT_DATADIR "/var/lib/aqhome-react"
#define AQHOME_REACT_DEFAULT_BROKER_PORT 1899
#define AQHOME_REACT_DEFAULT_BROKER_CLIENTID "react"
AQHOME_REACT *AqHomeReact_new();
void AqHomeReact_free(AQHOME_REACT *aqh);
GWEN_MSG_ENDPOINT *AqHomeReact_GetBrokerEndpoint(const AQHOME_REACT *aqh);
GWEN_DB_NODE *AqHomeReact_GetDbArgs(const AQHOME_REACT *aqh);
const char *AqHomeReact_GetPidFile(const AQHOME_REACT *aqh);
void AqHomeReact_SetPidFile(AQHOME_REACT *aqh, const char *s);
int AqHomeReact_GetTimeout(const AQHOME_REACT *aqh);
struct AQHOME_REACT {
GWEN_MSG_ENDPOINT *rootEndpoint;
GWEN_MSG_ENDPOINT *brokerEndpoint; /* do not free (is part of tree pointed to by rootEndpoint) */
GWEN_DB_NODE *dbArgs;
char *pidFile;
int timeout; /* timeout for run e.g. inside valgrind */
};
#endif #endif

View File

@@ -23,15 +23,12 @@
struct AQHOME_REACT { struct AQHOME_REACT {
GWEN_MSG_ENDPOINT *rootEndpoint; GWEN_MSG_ENDPOINT *brokerEndpoint;
GWEN_MSG_ENDPOINT *brokerEndpoint; /* do not free (is part of tree pointed to by rootEndpoint) */
GWEN_DB_NODE *dbArgs; GWEN_DB_NODE *dbArgs;
char *pidFile; char *pidFile;
int timeout; /* timeout for run e.g. inside valgrind */ int timeout; /* timeout for run e.g. inside valgrind */
AQH_STORAGE *storage;
}; };

61
apps/aqhome-react/fini.c Normal file
View File

@@ -0,0 +1,61 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2024 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 "aqhome-react/aqhome_react_p.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint.h>
#include <unistd.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
int AqHomeReact_Fini(AQHOME_REACT *aqh)
{
GWEN_MsgEndpoint_Disconnect(aqh->brokerEndpoint);
GWEN_MsgEndpoint_free(aqh->brokerEndpoint);
aqh->brokerEndpoint=NULL;
if (aqh->pidFile)
remove(aqh->pidFile);
return 0;
}

21
apps/aqhome-react/fini.h Normal file
View File

@@ -0,0 +1,21 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2024 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 AQHOMEREACT_FINI_H
#define AQHOMEREACT_FINI_H
#include "./aqhome_react.h"
int AqHomeReact_Fini(AQHOME_REACT *aqh);
#endif

312
apps/aqhome-react/init.c Normal file
View File

@@ -0,0 +1,312 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2024 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 "./aqhome_react_p.h"
#include "aqhome/aqhome.h"
#include "aqhome/ipc/endpoint_ipc.h"
#include "aqhome/ipc/endpoint_ipcclient.h"
#include "aqhome/mqtt/endpoint_mqttc.h"
#include <gwenhywfar/endpoint_multilayer.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/debug.h>
#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 _createPidFile(const char *pidFilename);
static int _setupBroker(AQHOME_REACT *aqh, GWEN_DB_NODE *dbArgs);
static int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
int AqHomeReact_Init(AQHOME_REACT *aqh, int argc, char **argv)
{
int rv;
GWEN_DB_NODE *dbArgs;
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_MergeConfigFileIntoConfig(dbArgs, "ConfigFile");
aqh->dbArgs=dbArgs;
aqh->timeout=GWEN_DB_GetIntValue(dbArgs, "timeout", 0, 0);
s=GWEN_DB_GetCharValue(dbArgs, "pidfile", 0, AQHOME_REACT_DEFAULT_PIDFILE);
if (s && *s) {
AqHomeReact_SetPidFile(aqh, s);
rv=_createPidFile(s);
if (rv<0) {
DBG_ERROR(NULL, "Error creating PID file (%d)", rv);
return rv;
}
}
/* TODO: setup react units */
rv=_setupBroker(aqh, dbArgs);
if (rv<0) {
DBG_ERROR(NULL, "Error setting up connection to broker (%d)", rv);
return rv;
}
return 0;
}
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 _setupBroker(AQHOME_REACT *aqh, GWEN_DB_NODE *dbArgs)
{
const char *brokerAddress;
int brokerPort;
const char *brokerClientId;
brokerAddress=GWEN_DB_GetCharValue(dbArgs, "brokerAddress", 0, NULL);
if (!(brokerAddress && *brokerAddress))
brokerAddress=GWEN_DB_GetCharValue(dbArgs, "ConfigFile/brokerAddress", 0, "127.0.0.1");
brokerPort=GWEN_DB_GetIntValue(dbArgs, "brokerPort", 0, -1);
if (brokerPort<0)
brokerPort=GWEN_DB_GetIntValue(dbArgs, "ConfigFile/brokerPort", 0, AQHOME_REACT_DEFAULT_BROKER_PORT);
brokerClientId=GWEN_DB_GetCharValue(dbArgs, "brokerClientId", 0, AQHOME_REACT_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);
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);
return rv;
}
}
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 */
"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 */
"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_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"devicefile", /* name */
0, /* minnum */
1, /* maxnum */
"d", /* short option */
"devicefile", /* long option */
I18S("Specify the device file"),
I18S("Specify the device file")
},
{
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;
}

21
apps/aqhome-react/init.h Normal file
View File

@@ -0,0 +1,21 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2024 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 AQHOMEREACT_INIT_H
#define AQHOMEREACT_INIT_H
#include "./aqhome_react.h"
int AqHomeReact_Init(AQHOME_REACT *aqh, int argc, char **argv);
#endif

103
apps/aqhome-react/loop.c Normal file
View File

@@ -0,0 +1,103 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2024 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 "./aqhome_react_p.h"
#include "aqhome/ipc/data/ipc_data.h"
#include "aqhome/ipc/data/msg_data_multidata.h"
#include "aqhome/ipc/msg_ipc_tag16.h"
#include <gwenhywfar/debug.h>
#include <time.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _handleDataResponse(GWEN_MSG *msg);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomeReact_Loop(AQHOME_REACT *aqh, int timeoutInMilliSecs)
{
GWEN_MSG *msg;
GWEN_MsgEndpoint_IoLoop(aqh->brokerEndpoint, timeoutInMilliSecs);
msg=GWEN_MsgEndpoint_TakeFirstReceivedMessage(aqh->brokerEndpoint);
if (msg) {
uint16_t code;
code=GWEN_IpcMsg_GetCode(msg);
if (code==AQH_MSGTYPE_IPC_DATA_DATACHANGED) {
DBG_INFO(NULL, "Received expected IPC message");
_handleDataResponse(msg);
}
else if (code==AQH_MSGTYPE_IPC_DATA_RESULT) {
DBG_INFO(NULL, "Received IPC result message, ignoring");
}
else {
DBG_INFO(NULL, "Received unexpected message %d (%x)", code, code);
}
GWEN_Msg_free(msg);
}
}
void _handleDataResponse(GWEN_MSG *msg)
{
AQH_VALUE *value;
const GWEN_TAG16 *tag;
unsigned int numberOfPoints;
const uint64_t *dataPoints;
AQH_MultiDataDataIpcMsg_Parse(msg, 0);
value=AQH_MultiDataDataIpcMsg_ReadValue(msg);
tag=AQH_Tag16IpcMsg_FindFirstTagByType(msg, AQH_MSGDATA_MULTIDATA_TAGS_DATA);
numberOfPoints=(tag?GWEN_Tag16_GetTagLength(tag):0)/(2*sizeof(uint64_t));
dataPoints=tag?((const uint64_t*) GWEN_Tag16_GetTagData(tag)):NULL;
if (numberOfPoints>0 && dataPoints) {
uint32_t i;
for(i=0; i<numberOfPoints; i++) {
uint64_t timestamp;
union {double f; uint64_t i;} u;
timestamp=*(dataPoints++);
u.i=*(dataPoints++);
// Utils_PrintFormattedSingleDataPoint(value, timestamp, u.f, tmpl);
}
}
AQH_Value_free(value);
}

21
apps/aqhome-react/loop.h Normal file
View File

@@ -0,0 +1,21 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2024 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 AQHOMEREACT_LOOP_H
#define AQHOMEREACT_LOOP_H
#include "./aqhome_react.h"
void AqHomeReact_Loop(AQHOME_REACT *aqh, int timeoutInMilliSecs);
#endif

View File

@@ -1,9 +1,249 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2024 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 "./fini.h"
#include "./loop.h"
#include "aqhome/aqhome.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/logger.h>
#include <gwenhywfar/db.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/cgui.h>
#include <gwenhywfar/text.h>
#ifdef HAVE_SIGNAL_H
# include <signal.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
#define FULL_DEBUG
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _serve(AQHOME_REACT *aqh);
#ifdef HAVE_SIGNAL_H
static int _setSignalHandlers(void);
static int _setupSigAction(struct sigaction *sa, int sig);
static void _signalHandler(int s);
static struct sigaction saINT,saTERM, saHUP, saTSTP, saCONT;
#endif
/* ------------------------------------------------------------------------------------------------
* static vars
* ------------------------------------------------------------------------------------------------
*/
static int stopService=0;
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
AQHOME_REACT *aqh;
GWEN_DB_NODE *dbArgs;
int rv;
GWEN_GUI *gui;
const char *s;
rv=GWEN_Init();
if (rv) {
fprintf(stderr, "ERROR: Unable to init Gwen.\n");
return 2;
}
GWEN_Logger_Open(0, "aqhome-react", 0, GWEN_LoggerType_Console, GWEN_LoggerFacility_User);
GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Warning);
//GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Info);
rv=AQH_Init();
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return 2;
}
aqh=AqHomeReact_new();
rv=AqHomeReact_Init(aqh, argc, argv);
if (rv<0) {
if (rv==GWEN_ERROR_CLOSE)
return 1;
DBG_INFO(NULL, "here (%d)", rv);
return 2;
}
dbArgs=AqHomeReact_GetDbArgs(aqh);
gui=GWEN_Gui_CGui_new();
s=GWEN_DB_GetCharValue(dbArgs, "charset", 0, NULL);
if (s && *s)
GWEN_Gui_SetCharSet(gui, s);
GWEN_Gui_SetGui(gui);
_serve(aqh);
AqHomeReact_Fini(aqh);
AqHomeReact_free(aqh);
GWEN_Gui_SetGui(NULL);
GWEN_Gui_free(gui);
return 0;
} }
void _serve(AQHOME_REACT *aqh)
{
int rv;
int timeout;
time_t startTime;
time_t lastTimerTime;
GWEN_DB_NODE *dbArgs;
startTime=time(NULL);
lastTimerTime=startTime;
dbArgs=AqHomeReact_GetDbArgs(aqh);
rv=_setSignalHandlers();
if (rv<0) {
DBG_ERROR(NULL, "Error setting signal handlers (%d)", rv);
return;
}
timeout=GWEN_DB_GetIntValue(dbArgs, "timeout", 0, 0);
while(!stopService) {
time_t now;
DBG_DEBUG(NULL, "Next loop");
AqHomeReact_Loop(aqh, 500);
now=time(NULL);
if (now!=lastTimerTime) {
lastTimerTime=now;
/* TODO: fire timer */
}
if (timeout) {
if ((now-startTime)>timeout) {
DBG_ERROR(NULL, "Timeout, stopping service");
break;
}
}
} /* while */
}
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;
}
}

View File

@@ -12,6 +12,7 @@
#include "./inputslot_p.h" #include "./inputslot_p.h"
#include "aqhome-react/types/unit.h"
#include <gwenhywfar/list.h> #include <gwenhywfar/list.h>
#include <gwenhywfar/debug.h> #include <gwenhywfar/debug.h>
@@ -27,6 +28,8 @@ AQHREACT_INPUT_SLOT *AQHREACT_InputSlot_new()
GWEN_NEW_OBJECT(AQHREACT_INPUT_SLOT, inSlot); GWEN_NEW_OBJECT(AQHREACT_INPUT_SLOT, inSlot);
GWEN_LIST_INIT(AQHREACT_INPUT_SLOT, inSlot); GWEN_LIST_INIT(AQHREACT_INPUT_SLOT, inSlot);
inSlot->idForUnit=-1;
return inSlot; return inSlot;
} }
@@ -54,7 +57,7 @@ AQHREACT_INPUT_SLOT *AQHREACT_InputSlot_dup(const AQHREACT_INPUT_SLOT *origSlot)
AQHREACT_InputSlot_SetName(inSlot, origSlot->name); AQHREACT_InputSlot_SetName(inSlot, origSlot->name);
AQHREACT_InputSlot_SetDescription(inSlot, origSlot->description); AQHREACT_InputSlot_SetDescription(inSlot, origSlot->description);
inSlot->idForUnit=origSlot->idForUnit; inSlot->idForUnit=origSlot->idForUnit;
inSlot->flags=origSlot->flags; inSlot->flags=origSlot->flags & ~AQHREACT_UNIT_FLAGS_MULTI; /* don't copy MULTI flag */
inSlot->acceptedDataType=origSlot->acceptedDataType; inSlot->acceptedDataType=origSlot->acceptedDataType;
/* don't copy current dataObject */ /* don't copy current dataObject */
return inSlot; return inSlot;

View File

@@ -25,7 +25,7 @@ AQHREACT_LINK *AQHREACT_Link_new()
GWEN_NEW_OBJECT(AQHREACT_LINK, lnk); GWEN_NEW_OBJECT(AQHREACT_LINK, lnk);
GWEN_LIST_INIT(AQHREACT_LINK, lnk); GWEN_LIST_INIT(AQHREACT_LINK, lnk);
lnk->targetInputSlotIdx=-1; lnk->targetInputSlotIdForUnit=-1;
return lnk; return lnk;
} }
@@ -60,17 +60,17 @@ void AQHREACT_Link_SetTargetUnitId(AQHREACT_LINK *lnk, const char *s)
int AQHREACT_Link_GetTargetInputSlotIdx(const AQHREACT_LINK *lnk) int AQHREACT_Link_GetTargetInputSlotIdForUnit(const AQHREACT_LINK *lnk)
{ {
return lnk?lnk->targetInputSlotIdx:-1; return lnk?lnk->targetInputSlotIdForUnit:-1;
} }
void AQHREACT_Link_SetTargetInputSlotIdx(AQHREACT_LINK *lnk, int i) void AQHREACT_Link_SetTargetInputSlotIdForUnit(AQHREACT_LINK *lnk, int i)
{ {
if (lnk) if (lnk)
lnk->targetInputSlotIdx=i;; lnk->targetInputSlotIdForUnit=i;
} }

View File

@@ -27,8 +27,8 @@ void AQHREACT_Link_free(AQHREACT_LINK *lnk);
const char *AQHREACT_Link_GetTargetUnitId(const AQHREACT_LINK *lnk); const char *AQHREACT_Link_GetTargetUnitId(const AQHREACT_LINK *lnk);
void AQHREACT_Link_SetTargetUnitId(AQHREACT_LINK *lnk, const char *s); void AQHREACT_Link_SetTargetUnitId(AQHREACT_LINK *lnk, const char *s);
int AQHREACT_Link_GetTargetInputSlotIdx(const AQHREACT_LINK *lnk); int AQHREACT_Link_GetTargetInputSlotIdForUnit(const AQHREACT_LINK *lnk);
void AQHREACT_Link_SetTargetInputSlotIdx(AQHREACT_LINK *lnk, int i); void AQHREACT_Link_SetTargetInputSlotIdForUnit(AQHREACT_LINK *lnk, int i);
AQHREACT_UNIT *AQHREACT_Link_GetTargetUnit(const AQHREACT_LINK *lnk); AQHREACT_UNIT *AQHREACT_Link_GetTargetUnit(const AQHREACT_LINK *lnk);
void AQHREACT_Link_SetTargetUnit(AQHREACT_LINK *lnk, AQHREACT_UNIT *unit); void AQHREACT_Link_SetTargetUnit(AQHREACT_LINK *lnk, AQHREACT_UNIT *unit);

View File

@@ -17,7 +17,7 @@ struct AQHREACT_LINK {
GWEN_LIST_ELEMENT(AQHREACT_LINK) GWEN_LIST_ELEMENT(AQHREACT_LINK)
char *targetUnitId; char *targetUnitId;
int targetInputSlotIdx; int targetInputSlotIdForUnit;
AQHREACT_UNIT *targetUnit; AQHREACT_UNIT *targetUnit;
}; };

View File

@@ -28,6 +28,7 @@ AQHREACT_OUTPUT_SLOT *AQHREACT_OutputSlot_new()
GWEN_NEW_OBJECT(AQHREACT_OUTPUT_SLOT, outSlot); GWEN_NEW_OBJECT(AQHREACT_OUTPUT_SLOT, outSlot);
GWEN_LIST_INIT(AQHREACT_OUTPUT_SLOT, outSlot); GWEN_LIST_INIT(AQHREACT_OUTPUT_SLOT, outSlot);
outSlot->linkList=AQHREACT_Link_List_new(); outSlot->linkList=AQHREACT_Link_List_new();
outSlot->id=-1;
return outSlot; return outSlot;
} }
@@ -46,6 +47,21 @@ void AQHREACT_OutputSlot_free(AQHREACT_OUTPUT_SLOT *outSlot)
int AQHREACT_OutputSlot_GetIdForUnit(const AQHREACT_OUTPUT_SLOT *outSlot)
{
return outSlot?outSlot->id:-1;
}
void AQHREACT_OutputSlot_SetIdForUnit(AQHREACT_OUTPUT_SLOT *outSlot, int i)
{
if (outSlot)
outSlot->id=i;
}
const char *AQHREACT_OutputSlot_GetName(const AQHREACT_OUTPUT_SLOT *outSlot) const char *AQHREACT_OutputSlot_GetName(const AQHREACT_OUTPUT_SLOT *outSlot)
{ {
return outSlot?outSlot->name:NULL; return outSlot?outSlot->name:NULL;

View File

@@ -31,6 +31,9 @@ void AQHREACT_OutputSlot_SetName(AQHREACT_OUTPUT_SLOT *outSlot, const char *s);
const char *AQHREACT_OutputSlot_GetDescription(const AQHREACT_OUTPUT_SLOT *outSlot); const char *AQHREACT_OutputSlot_GetDescription(const AQHREACT_OUTPUT_SLOT *outSlot);
void AQHREACT_OutputSlot_SetDescription(AQHREACT_OUTPUT_SLOT *outSlot, const char *s); void AQHREACT_OutputSlot_SetDescription(AQHREACT_OUTPUT_SLOT *outSlot, const char *s);
int AQHREACT_OutputSlot_GetIdForUnit(const AQHREACT_OUTPUT_SLOT *outSlot);
void AQHREACT_OutputSlot_SetIdForUnit(AQHREACT_OUTPUT_SLOT *outSlot, int i);
uint32_t AQHREACT_OutputSlot_GetFlags(const AQHREACT_OUTPUT_SLOT *outSlot); uint32_t AQHREACT_OutputSlot_GetFlags(const AQHREACT_OUTPUT_SLOT *outSlot);
void AQHREACT_OutputSlot_SetFlags(AQHREACT_OUTPUT_SLOT *outSlot, uint32_t f); void AQHREACT_OutputSlot_SetFlags(AQHREACT_OUTPUT_SLOT *outSlot, uint32_t f);
void AQHREACT_OutputSlot_AddFlags(AQHREACT_OUTPUT_SLOT *outSlot, uint32_t f); void AQHREACT_OutputSlot_AddFlags(AQHREACT_OUTPUT_SLOT *outSlot, uint32_t f);

View File

@@ -16,8 +16,10 @@
struct AQHREACT_OUTPUT_SLOT { struct AQHREACT_OUTPUT_SLOT {
GWEN_LIST_ELEMENT(AQHREACT_OUTPUT_SLOT) GWEN_LIST_ELEMENT(AQHREACT_OUTPUT_SLOT)
int id;
char *name; char *name;
char *description; char *description;
int idForUnit;
uint32_t flags; uint32_t flags;
int emittedDataType; int emittedDataType;

View File

@@ -105,6 +105,21 @@ void AQHREACT_Unit_SetId(AQHREACT_UNIT *unit, const char *s)
int AQHREACT_Unit_GetNextInputSlotId(const AQHREACT_UNIT *unit)
{
return unit?unit->nextInputSlotId:-1;
}
void AQHREACT_Unit_SetNextInputSlotId(AQHREACT_UNIT *unit, int i)
{
if (unit)
unit->nextInputSlotId=i;
}
uint32_t AQHREACT_Unit_GetFlags(const AQHREACT_UNIT *unit) uint32_t AQHREACT_Unit_GetFlags(const AQHREACT_UNIT *unit)
{ {
return unit?unit->flags:0; return unit?unit->flags:0;
@@ -181,6 +196,108 @@ void AQHREACT_Unit_AddParam(AQHREACT_UNIT *unit, AQHREACT_PARAM *param)
AQHREACT_PARAM *AQHREACT_Unit_GetParamByName(const AQHREACT_UNIT *unit, const char *paramName)
{
if (unit && unit->paramList && paramName && *paramName) {
AQHREACT_PARAM *param;
param=AQHREACT_Param_List_First(unit->paramList);
while(param) {
const char *s;
s=AQHREACT_Param_GetName(param);
if (s && *s && strcasecmp(paramName, s)==0)
return param;
param=AQHREACT_Param_List_Next(param);
}
}
return NULL;
}
double AQHREACT_Unit_GetParamValueDouble(const AQHREACT_UNIT *unit, const char *paramName, double defVal)
{
AQHREACT_PARAM *param;
param=AQHREACT_Unit_GetParamByName(unit, paramName);
if (param) {
if (AQHREACT_Param_GetDataType(param)==AQHREACT_DATAOBJECTTYPE_DOUBLE) {
return AQHREACT_Param_GetDoubleValue(param);
}
else {
DBG_INFO(NULL, "Datatype for param \"%s/%s\" is not DOUBLE", (unit->name)?unit->name:"<unnamed>", paramName);
}
}
return defVal;
}
void AQHREACT_Unit_SetParamValueDouble(AQHREACT_UNIT *unit, const char *paramName, double val)
{
AQHREACT_PARAM *param;
param=AQHREACT_Unit_GetParamByName(unit, paramName);
if (param) {
if (AQHREACT_Param_GetDataType(param)==AQHREACT_DATAOBJECTTYPE_DOUBLE) {
AQHREACT_Param_SetDoubleValue(param, val);
}
else {
DBG_INFO(NULL, "Datatype for param \"%s/%s\" is not DOUBLE", (unit->name)?unit->name:"<unnamed>", paramName);
}
}
else {
DBG_INFO(NULL, "Param \"%s\" not found in unit %s", paramName, (unit->name)?unit->name:"<unnamed>");
}
}
const char *AQHREACT_Unit_GetParamValueString(const AQHREACT_UNIT *unit, const char *paramName, const char *defVal)
{
AQHREACT_PARAM *param;
param=AQHREACT_Unit_GetParamByName(unit, paramName);
if (param) {
if (AQHREACT_Param_GetDataType(param)==AQHREACT_DATAOBJECTTYPE_STRING) {
return AQHREACT_Param_GetStringValue(param);
}
else {
DBG_INFO(NULL, "Datatype for param \"%s/%s\" is not STRING", (unit->name)?unit->name:"<unnamed>", paramName);
}
}
else {
DBG_INFO(NULL, "Param \"%s\" not found in unit %s", paramName, (unit->name)?unit->name:"<unnamed>");
}
return defVal;
}
void AQHREACT_Unit_SetParamValueString(AQHREACT_UNIT *unit, const char *paramName, const char *val)
{
AQHREACT_PARAM *param;
param=AQHREACT_Unit_GetParamByName(unit, paramName);
if (param) {
if (AQHREACT_Param_GetDataType(param)==AQHREACT_DATAOBJECTTYPE_STRING) {
AQHREACT_Param_SetStringValue(param, val);
}
else {
DBG_INFO(NULL, "Datatype for param \"%s\" is not STRING", paramName);
}
}
else {
DBG_INFO(NULL, "Param \"%s\" not found in unit %s", paramName, (unit->name)?unit->name:"<unnamed>");
}
}
AQHREACT_UNIT_INPUTDATA_FN AQHREACT_Unit_SetInputDataFn(AQHREACT_UNIT *unit, AQHREACT_UNIT_INPUTDATA_FN f) AQHREACT_UNIT_INPUTDATA_FN AQHREACT_Unit_SetInputDataFn(AQHREACT_UNIT *unit, AQHREACT_UNIT_INPUTDATA_FN f)
{ {
if (unit) { if (unit) {
@@ -209,12 +326,12 @@ AQHREACT_UNIT_PROCESS_FN AQHREACT_Unit_SetProcessFn(AQHREACT_UNIT *unit, AQHREAC
void AQHREACT_Unit_OutputData(AQHREACT_UNIT *unit, int slotIndex, const AQHREACT_DATAOBJECT *dataObject) void AQHREACT_Unit_OutputData(AQHREACT_UNIT *unit, int slotIdForUnit, const AQHREACT_DATAOBJECT *dataObject)
{ {
if (unit && unit->outputSlotList) { if (unit && unit->outputSlotList) {
AQHREACT_OUTPUT_SLOT *slot; AQHREACT_OUTPUT_SLOT *slot;
slot=AQHREACT_Unit_GetOutputSlotAt(unit, slotIndex); slot=AQHREACT_Unit_GetOutputSlotByIdForUnit(unit, slotIdForUnit);
if (slot) { if (slot) {
AQHREACT_LINK_LIST *linkList; AQHREACT_LINK_LIST *linkList;
@@ -225,12 +342,12 @@ void AQHREACT_Unit_OutputData(AQHREACT_UNIT *unit, int slotIndex, const AQHREACT
lnk=AQHREACT_Link_List_First(linkList); lnk=AQHREACT_Link_List_First(linkList);
while(lnk) { while(lnk) {
AQHREACT_UNIT *targetUnit; AQHREACT_UNIT *targetUnit;
int idx; int targetSlotIdForUnit;
targetUnit=AQHREACT_Link_GetTargetUnit(lnk); targetUnit=AQHREACT_Link_GetTargetUnit(lnk);
idx=AQHREACT_Link_GetTargetInputSlotIdx(lnk); targetSlotIdForUnit=AQHREACT_Link_GetTargetInputSlotIdForUnit(lnk);
if (targetUnit && idx>=0) if (targetUnit && targetSlotIdForUnit>=0)
AQHREACT_Unit_InputData(targetUnit, idx, dataObject); AQHREACT_Unit_InputData(targetUnit, targetSlotIdForUnit, dataObject);
lnk=AQHREACT_Link_List_Next(lnk); lnk=AQHREACT_Link_List_Next(lnk);
} /* while */ } /* while */
} /* if linkList */ } /* if linkList */
@@ -240,11 +357,41 @@ void AQHREACT_Unit_OutputData(AQHREACT_UNIT *unit, int slotIndex, const AQHREACT
void AQHREACT_Unit_InputData(AQHREACT_UNIT *unit, int slotIndex, const AQHREACT_DATAOBJECT *dataObject) void AQHREACT_Unit_OutputDoubleData(AQHREACT_UNIT *unit, int slotIndex, double data)
{
if (unit && unit->outputSlotList) {
AQHREACT_DATAOBJECT *dataObject;
dataObject=AQHREACT_DataObject_new();
AQHREACT_DataObject_SetDataType(dataObject, AQHREACT_DATAOBJECTTYPE_DOUBLE);
AQHREACT_DataObject_SetDoubleData(dataObject, data);
AQHREACT_Unit_OutputData(unit, slotIndex, dataObject);
AQHREACT_DataObject_free(dataObject);
}
}
void AQHREACT_Unit_OutputStringData(AQHREACT_UNIT *unit, int slotIndex, const char *data)
{
if (unit && unit->outputSlotList) {
AQHREACT_DATAOBJECT *dataObject;
dataObject=AQHREACT_DataObject_new();
AQHREACT_DataObject_SetDataType(dataObject, AQHREACT_DATAOBJECTTYPE_STRING);
AQHREACT_DataObject_SetStringData(dataObject, data);
AQHREACT_Unit_OutputData(unit, slotIndex, dataObject);
AQHREACT_DataObject_free(dataObject);
}
}
void AQHREACT_Unit_InputData(AQHREACT_UNIT *unit, int slotIdForUnit, const AQHREACT_DATAOBJECT *dataObject)
{ {
if (unit) { if (unit) {
if (unit->inputDataFn) if (unit->inputDataFn)
(unit->inputDataFn)(unit, slotIndex, dataObject); (unit->inputDataFn)(unit, slotIdForUnit, dataObject);
else { else {
AQHREACT_Unit_ClearChangeFlagsInUnitAndInputSlots(unit); AQHREACT_Unit_ClearChangeFlagsInUnitAndInputSlots(unit);
} }
@@ -261,16 +408,8 @@ int AQHREACT_Unit_Process(AQHREACT_UNIT *unit)
if (unit) { if (unit) {
if (unit->processFn) if (unit->processFn)
return (unit->processFn)(unit); return (unit->processFn)(unit);
else { else
AQHREACT_INPUT_SLOT *slot; AQHREACT_Unit_ClearChangeFlagsInUnitAndInputSlots(unit);
unit->flags&=~AQHREACT_UNIT_FLAGS_CHANGED;
slot=AQHREACT_InputSlot_List_First(unit->inputSlotList);
while(slot) {
AQHREACT_InputSlot_SubFlags(slot, AQHREACT_UNIT_FLAGS_CHANGED);
slot=AQHREACT_InputSlot_List_Next(slot);
}
}
} }
return 0; return 0;
@@ -278,18 +417,17 @@ int AQHREACT_Unit_Process(AQHREACT_UNIT *unit)
AQHREACT_INPUT_SLOT *AQHREACT_Unit_GetInputSlotAt(AQHREACT_UNIT *unit, int idx) AQHREACT_INPUT_SLOT *AQHREACT_Unit_GetInputSlotByIdForUnit(const AQHREACT_UNIT *unit, int id)
{ {
if (unit && unit->inputSlotList && idx>=0) { if (unit && unit->inputSlotList && id>=0) {
AQHREACT_INPUT_SLOT *slot; AQHREACT_INPUT_SLOT *slot;
slot=AQHREACT_InputSlot_List_First(unit->inputSlotList); slot=AQHREACT_InputSlot_List_First(unit->inputSlotList);
while(slot && idx) { while(slot) {
if (AQHREACT_InputSlot_GetIdForUnit(slot)==id)
return slot;
slot=AQHREACT_InputSlot_List_Next(slot); slot=AQHREACT_InputSlot_List_Next(slot);
idx--;
} }
return slot;
} }
return NULL; return NULL;
@@ -297,15 +435,92 @@ AQHREACT_INPUT_SLOT *AQHREACT_Unit_GetInputSlotAt(AQHREACT_UNIT *unit, int idx)
AQHREACT_OUTPUT_SLOT *AQHREACT_Unit_GetOutputSlotAt(AQHREACT_UNIT *unit, int idx) AQHREACT_INPUT_SLOT *AQHREACT_Unit_GetInputSlotByName(const AQHREACT_UNIT *unit, const char *s)
{ {
if (unit && unit->outputSlotList && idx>=0) { if (unit && unit->inputSlotList && s && *s) {
AQHREACT_INPUT_SLOT *slot;
slot=AQHREACT_InputSlot_List_First(unit->inputSlotList);
while(slot) {
const char *slotName;
slotName=AQHREACT_InputSlot_GetName(slot);
if (slotName && *slotName && strcasecmp(slotName, s)==0)
return slot;
slot=AQHREACT_InputSlot_List_Next(slot);
}
}
return NULL;
}
AQHREACT_INPUT_SLOT *AQHREACT_Unit_GetOrCreateUnusedInputSlotByName(AQHREACT_UNIT *unit, const char *s)
{
if (unit && unit->inputSlotList && s && *s) {
AQHREACT_INPUT_SLOT *slot;
slot=AQHREACT_Unit_GetInputSlotByName(unit, s);
if (slot) {
uint32_t flags;
const char *slotName;
slotName=AQHREACT_InputSlot_GetName(slot);
flags=AQHREACT_InputSlot_GetFlags(slot);
if (!(flags & AQHREACT_UNIT_FLAGS_INUSE))
return slot;
if (flags & AQHREACT_UNIT_FLAGS_MULTI) { /* can we just duplicate existing? */
AQHREACT_INPUT_SLOT *newSlot;
newSlot=AQHREACT_InputSlot_dup(slot);
AQHREACT_InputSlot_SetIdForUnit(newSlot, (unit->nextInputSlotId)++);
AQHREACT_Unit_AddInputSlot(unit, newSlot);
return newSlot;
}
else {
DBG_INFO(NULL, "Slot \"%s\" found but in use, no multi flag", slotName);
}
}
}
return NULL;
}
AQHREACT_OUTPUT_SLOT *AQHREACT_Unit_GetOutputSlotByIdForUnit(const AQHREACT_UNIT *unit, int id)
{
if (unit && unit->outputSlotList && id>=0) {
AQHREACT_OUTPUT_SLOT *slot; AQHREACT_OUTPUT_SLOT *slot;
slot=AQHREACT_OutputSlot_List_First(unit->outputSlotList); slot=AQHREACT_OutputSlot_List_First(unit->outputSlotList);
while(slot && idx) { while(slot) {
if (AQHREACT_OutputSlot_GetIdForUnit(slot)==id)
return slot;
slot=AQHREACT_OutputSlot_List_Next(slot);
}
}
return NULL;
}
AQHREACT_OUTPUT_SLOT *AQHREACT_Unit_GetOutputSlotByName(const AQHREACT_UNIT *unit, const char *s)
{
if (unit && unit->outputSlotList && s && *s) {
AQHREACT_OUTPUT_SLOT *slot;
slot=AQHREACT_OutputSlot_List_First(unit->outputSlotList);
while(slot) {
const char *slotName;
slotName=AQHREACT_OutputSlot_GetName(slot);
if (slotName && *slotName && strcasecmp(slotName, s)==0)
return slot;
slot=AQHREACT_OutputSlot_List_Next(slot); slot=AQHREACT_OutputSlot_List_Next(slot);
idx--;
} }
return slot; return slot;
} }
@@ -331,5 +546,25 @@ void AQHREACT_Unit_ClearChangeFlagsInUnitAndInputSlots(AQHREACT_UNIT *unit)
int AQHREACT_Unit_InputHasChanged(const AQHREACT_UNIT *unit)
{
if (unit) {
AQHREACT_INPUT_SLOT *slot;
if (unit->flags & AQHREACT_UNIT_FLAGS_CHANGED)
return 1;
slot=AQHREACT_InputSlot_List_First(unit->inputSlotList);
while(slot) {
if (AQHREACT_InputSlot_GetFlags(slot) & AQHREACT_UNIT_FLAGS_CHANGED)
return 1;
slot=AQHREACT_InputSlot_List_Next(slot);
}
}
return 0;
}

View File

@@ -31,7 +31,7 @@ GWEN_INHERIT_FUNCTION_DEFS(AQHREACT_UNIT)
#include "aqhome-react/types/param.h" #include "aqhome-react/types/param.h"
typedef void (*AQHREACT_UNIT_INPUTDATA_FN)(AQHREACT_UNIT *unit, int slotIndex, const AQHREACT_DATAOBJECT *dataObject); typedef void (*AQHREACT_UNIT_INPUTDATA_FN)(AQHREACT_UNIT *unit, int slotIdForUnit, const AQHREACT_DATAOBJECT *dataObject);
typedef int (*AQHREACT_UNIT_PROCESS_FN)(AQHREACT_UNIT *unit); typedef int (*AQHREACT_UNIT_PROCESS_FN)(AQHREACT_UNIT *unit);
@@ -48,6 +48,9 @@ void AQHREACT_Unit_SetDescription(AQHREACT_UNIT *unit, const char *s);
const char *AQHREACT_Unit_GetId(const AQHREACT_UNIT *unit); const char *AQHREACT_Unit_GetId(const AQHREACT_UNIT *unit);
void AQHREACT_Unit_SetId(AQHREACT_UNIT *unit, const char *s); void AQHREACT_Unit_SetId(AQHREACT_UNIT *unit, const char *s);
int AQHREACT_Unit_GetNextInputSlotId(const AQHREACT_UNIT *unit);
void AQHREACT_Unit_SetNextInputSlotId(AQHREACT_UNIT *unit, int i);
uint32_t AQHREACT_Unit_GetFlags(const AQHREACT_UNIT *unit); uint32_t AQHREACT_Unit_GetFlags(const AQHREACT_UNIT *unit);
void AQHREACT_Unit_SetFlags(AQHREACT_UNIT *unit, uint32_t i); void AQHREACT_Unit_SetFlags(AQHREACT_UNIT *unit, uint32_t i);
void AQHREACT_Unit_AddFlags(AQHREACT_UNIT *unit, uint32_t i); void AQHREACT_Unit_AddFlags(AQHREACT_UNIT *unit, uint32_t i);
@@ -55,22 +58,33 @@ void AQHREACT_Unit_SubFlags(AQHREACT_UNIT *unit, uint32_t i);
AQHREACT_INPUT_SLOT_LIST *AQHREACT_Unit_GetInputSlots(const AQHREACT_UNIT *unit); AQHREACT_INPUT_SLOT_LIST *AQHREACT_Unit_GetInputSlots(const AQHREACT_UNIT *unit);
void AQHREACT_Unit_AddInputSlot(AQHREACT_UNIT *unit, AQHREACT_INPUT_SLOT *inSlot); void AQHREACT_Unit_AddInputSlot(AQHREACT_UNIT *unit, AQHREACT_INPUT_SLOT *inSlot);
AQHREACT_INPUT_SLOT *AQHREACT_Unit_GetInputSlotAt(AQHREACT_UNIT *unit, int idx); AQHREACT_INPUT_SLOT *AQHREACT_Unit_GetInputSlotByIdForUnit(const AQHREACT_UNIT *unit, int id);
AQHREACT_INPUT_SLOT *AQHREACT_Unit_GetInputSlotByName(const AQHREACT_UNIT *unit, const char *s);
AQHREACT_OUTPUT_SLOT_LIST *AQHREACT_Unit_GetOutputSlots(const AQHREACT_UNIT *unit); AQHREACT_OUTPUT_SLOT_LIST *AQHREACT_Unit_GetOutputSlots(const AQHREACT_UNIT *unit);
void AQHREACT_Unit_AddOutputSlot(AQHREACT_UNIT *unit, AQHREACT_OUTPUT_SLOT *outSlot); void AQHREACT_Unit_AddOutputSlot(AQHREACT_UNIT *unit, AQHREACT_OUTPUT_SLOT *outSlot);
AQHREACT_OUTPUT_SLOT *AQHREACT_Unit_GetOutputSlotAt(AQHREACT_UNIT *unit, int idx); AQHREACT_OUTPUT_SLOT *AQHREACT_Unit_GetOutputSlotByIdForUnit(const AQHREACT_UNIT *unit, int idx);
AQHREACT_OUTPUT_SLOT *AQHREACT_Unit_GetOutputSlotByName(const AQHREACT_UNIT *unit, const char *s);
void AQHREACT_Unit_ClearChangeFlagsInUnitAndInputSlots(AQHREACT_UNIT *unit); void AQHREACT_Unit_ClearChangeFlagsInUnitAndInputSlots(AQHREACT_UNIT *unit);
int AQHREACT_Unit_InputHasChanged(const AQHREACT_UNIT *unit);
AQHREACT_PARAM_LIST *AQHREACT_Unit_GetParamList(const AQHREACT_UNIT *unit); AQHREACT_PARAM_LIST *AQHREACT_Unit_GetParamList(const AQHREACT_UNIT *unit);
void AQHREACT_Unit_AddParam(AQHREACT_UNIT *unit, AQHREACT_PARAM *param); void AQHREACT_Unit_AddParam(AQHREACT_UNIT *unit, AQHREACT_PARAM *param);
AQHREACT_PARAM *AQHREACT_Unit_GetParamByName(const AQHREACT_UNIT *unit, const char *s);
double AQHREACT_Unit_GetParamValueDouble(const AQHREACT_UNIT *unit, const char *s, double defVal);
void AQHREACT_Unit_SetParamValueDouble(AQHREACT_UNIT *unit, const char *paramName, double val);
const char *AQHREACT_Unit_GetParamValueString(const AQHREACT_UNIT *unit, const char *paramName, const char *defVal);
void AQHREACT_Unit_SetParamValueString(AQHREACT_UNIT *unit, const char *paramName, const char *val);
void AQHREACT_Unit_OutputData(AQHREACT_UNIT *unit, int slotIndex, const AQHREACT_DATAOBJECT *dataObject); void AQHREACT_Unit_OutputData(AQHREACT_UNIT *unit, int slotIndex, const AQHREACT_DATAOBJECT *dataObject);
void AQHREACT_Unit_OutputDoubleData(AQHREACT_UNIT *unit, int slotIndex, double data);
void AQHREACT_Unit_OutputStringData(AQHREACT_UNIT *unit, int slotIndex, const char *data);
void AQHREACT_Unit_InputData(AQHREACT_UNIT *unit, int slotIndex, const AQHREACT_DATAOBJECT *dataObject);
void AQHREACT_Unit_InputData(AQHREACT_UNIT *unit, int slotIdForUnit, const AQHREACT_DATAOBJECT *dataObject);
int AQHREACT_Unit_Process(AQHREACT_UNIT *unit); int AQHREACT_Unit_Process(AQHREACT_UNIT *unit);

View File

@@ -23,6 +23,8 @@ struct AQHREACT_UNIT {
uint32_t flags; uint32_t flags;
int nextInputSlotId;
AQHREACT_INPUT_SLOT_LIST *inputSlotList; AQHREACT_INPUT_SLOT_LIST *inputSlotList;
AQHREACT_OUTPUT_SLOT_LIST *outputSlotList; AQHREACT_OUTPUT_SLOT_LIST *outputSlotList;

View File

@@ -0,0 +1,71 @@
<?xml?>
<gwbuild>
<target type="ConvenienceLibrary" name="aqhreact_units" >
<includes type="c" >
$(gwenhywfar_cflags)
-I$(topsrcdir)
-I$(topbuilddir)
-I$(topsrcdir)/apps
-I$(topbuilddir)/apps
-I$(builddir)
-I$(srcdir)
</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" >
u_or.h
u_varchanges.h
u_valuefilter.h
</headers>
<sources>
$(local/typefiles)
u_or.c
u_varchanges.c
u_valuefilter.c
</sources>
<useTargets>
</useTargets>
<libraries>
</libraries>
<subdirs>
</subdirs>
<extradist>
</extradist>
</target>
</gwbuild>

View File

@@ -0,0 +1,136 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2024 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 "./u_or.h"
#include <gwenhywfar/debug.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
#define AQHOMEREACT_UNIT_OR_INSLOT_INPUT 0
#define AQHOMEREACT_UNIT_OR_INSLOT_AUTOINPUT 100
#define AQHOMEREACT_UNIT_OR_OUTSLOT_RESULT 0
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static int _cbProcessFn(AQHREACT_UNIT *unit);
static int _sampleInputSlots(const AQHREACT_INPUT_SLOT_LIST *inputSlotList);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
AQHREACT_UNIT *AqHomeReact_UnitOr_new(AQHOME_REACT *aqh)
{
AQHREACT_UNIT *unit;
AQHREACT_OUTPUT_SLOT *outputSlot;
AQHREACT_INPUT_SLOT *inputSlot;
unit=AQHREACT_Unit_new();
AQHREACT_Unit_SetName(unit, "or");
AQHREACT_Unit_SetDescription(unit, "Logical OR inputs");
AQHREACT_Unit_SetProcessFn(unit, _cbProcessFn);
AQHREACT_Unit_SetNextInputSlotId(unit, AQHOMEREACT_UNIT_OR_INSLOT_AUTOINPUT); /* for auto-gen multi-slots */
outputSlot=AQHREACT_OutputSlot_new();
AQHREACT_OutputSlot_SetName(outputSlot, "output");
AQHREACT_OutputSlot_SetIdForUnit(outputSlot, AQHOMEREACT_UNIT_OR_OUTSLOT_RESULT);
AQHREACT_OutputSlot_SetEmittedDataType(outputSlot, AQHREACT_DATAOBJECTTYPE_DOUBLE);
AQHREACT_Unit_AddOutputSlot(unit, outputSlot);
inputSlot=AQHREACT_InputSlot_new();
AQHREACT_InputSlot_SetName(inputSlot, "input");
AQHREACT_InputSlot_SetIdForUnit(inputSlot, AQHOMEREACT_UNIT_OR_INSLOT_INPUT);
AQHREACT_InputSlot_SetAcceptedDataType(inputSlot, AQHREACT_DATAOBJECTTYPE_DOUBLE);
AQHREACT_InputSlot_AddFlags(inputSlot, AQHREACT_UNIT_FLAGS_MULTI);
AQHREACT_Unit_AddInputSlot(unit, inputSlot);
return unit;
}
int _cbProcessFn(AQHREACT_UNIT *unit)
{
if (unit && AQHREACT_Unit_InputHasChanged(unit)) {
AQHREACT_INPUT_SLOT_LIST *inputSlotList;
inputSlotList=AQHREACT_Unit_GetInputSlots(unit);
if (inputSlotList) {
int result;
result=_sampleInputSlots(inputSlotList);
AQHREACT_Unit_ClearChangeFlagsInUnitAndInputSlots(unit);
AQHREACT_Unit_OutputDoubleData(unit, AQHOMEREACT_UNIT_OR_OUTSLOT_RESULT, result?1.0:0.0);
}
}
return 0;
}
int _sampleInputSlots(const AQHREACT_INPUT_SLOT_LIST *inputSlotList)
{
const AQHREACT_INPUT_SLOT *inputSlot;
int result=0;
inputSlot=AQHREACT_InputSlot_List_First(inputSlotList);
while(inputSlot) {
const char *slotName;
const AQHREACT_DATAOBJECT *dataObject;
slotName=AQHREACT_InputSlot_GetName(inputSlot);
dataObject=AQHREACT_InputSlot_GetCurrentDataObject(inputSlot);
if (dataObject) {
if (AQHREACT_DataObject_GetDataType(dataObject)==AQHREACT_DATAOBJECTTYPE_DOUBLE) {
double d;
d=AQHREACT_DataObject_GetDoubleData(dataObject);
if (d>0.0)
result|=1;
}
else {
DBG_ERROR(NULL, "Data at input slot \"%s\" isn't DOUBLE, ignoring", slotName?slotName:"<unnamed>");
}
}
else {
DBG_ERROR(NULL, "Data at input slot \"%s\" has not current data, ignoring", slotName?slotName:"<unnamed>");
}
inputSlot=AQHREACT_InputSlot_List_Next(inputSlot);
}
return result;
}

View File

@@ -0,0 +1,23 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2024 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 AQHOMEREACT_U_OR_H
#define AQHOMEREACT_U_OR_H
#include "aqhome-react/aqhome_react.h"
#include "aqhome-react/types/unit.h"
AQHREACT_UNIT *AqHomeReact_UnitOr_new(AQHOME_REACT *aqh);
#endif

View File

@@ -0,0 +1,96 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2024 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 "./u_valuefilter.h"
#include <gwenhywfar/debug.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
#define AQHOMEREACT_UNIT_VALUEFILTER_INSLOT_VALUE 0
#define AQHOMEREACT_UNIT_VALUEFILTER_OUTSLOT_RESULT 0
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _cbInputData(AQHREACT_UNIT *unit, int slotIdForUnit, const AQHREACT_DATAOBJECT *dataObject);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
AQHREACT_UNIT *AqHomeReact_UnitValueFilter_new(AQHOME_REACT *aqh)
{
AQHREACT_UNIT *unit;
AQHREACT_OUTPUT_SLOT *outputSlot;
AQHREACT_INPUT_SLOT *inputSlot;
AQHREACT_PARAM *param;
unit=AQHREACT_Unit_new();
AQHREACT_Unit_SetName(unit, "valuefilter");
AQHREACT_Unit_SetDescription(unit, "Filter values received from unit VarChanges by value path");
AQHREACT_Unit_SetInputDataFn(unit, _cbInputData);
outputSlot=AQHREACT_OutputSlot_new();
AQHREACT_OutputSlot_SetName(outputSlot, "output");
AQHREACT_OutputSlot_SetIdForUnit(outputSlot, AQHOMEREACT_UNIT_VALUEFILTER_OUTSLOT_RESULT);
AQHREACT_OutputSlot_SetEmittedDataType(outputSlot, AQHREACT_DATAOBJECTTYPE_DOUBLE);
AQHREACT_Unit_AddOutputSlot(unit, outputSlot);
inputSlot=AQHREACT_InputSlot_new();
AQHREACT_InputSlot_SetName(inputSlot, "input");
AQHREACT_InputSlot_SetIdForUnit(inputSlot, AQHOMEREACT_UNIT_VALUEFILTER_INSLOT_VALUE);
AQHREACT_InputSlot_SetAcceptedDataType(inputSlot, AQHREACT_DATAOBJECTTYPE_DOUBLE);
AQHREACT_Unit_AddInputSlot(unit, inputSlot);
param=AQHREACT_Param_new();
AQHREACT_Param_SetName(param, AQHOMEREACT_UNIT_VALUEFILTER_PARAM_VALUENAME);
AQHREACT_Param_SetDataType(param, AQHREACT_DATAOBJECTTYPE_STRING);
AQHREACT_Unit_AddParam(unit, param);
return unit;
}
void _cbInputData(AQHREACT_UNIT *unit, int slotIdForUnit, const AQHREACT_DATAOBJECT *dataObject)
{
if (unit && dataObject && slotIdForUnit==AQHOMEREACT_UNIT_VALUEFILTER_INSLOT_VALUE) {
const char *sSystemValueId;
sSystemValueId=AQHREACT_DataObject_GetSystemValueId(dataObject);
if (sSystemValueId && *sSystemValueId) {
const char *sFilter;
sFilter=AQHREACT_Unit_GetParamValueString(unit, AQHOMEREACT_UNIT_VALUEFILTER_PARAM_VALUENAME, NULL);
if (sFilter && *sFilter && strcasecmp(sSystemValueId, sFilter)==0)
AQHREACT_Unit_OutputData(unit, AQHOMEREACT_UNIT_VALUEFILTER_OUTSLOT_RESULT, dataObject);
}
}
}

View File

@@ -0,0 +1,26 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2024 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 AQHOMEREACT_U_VALUEFILTER_H
#define AQHOMEREACT_U_VALUEFILTER_H
#include "aqhome-react/aqhome_react.h"
#include "aqhome-react/types/unit.h"
#define AQHOMEREACT_UNIT_VALUEFILTER_PARAM_VALUENAME "valueName"
AQHREACT_UNIT *AqHomeReact_UnitValueFilter_new(AQHOME_REACT *aqh);
#endif

View File

@@ -0,0 +1,81 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2024 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 "./u_varchanges.h"
#include <gwenhywfar/debug.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
#define AQHOMEREACT_UNIT_VARCHANGES_INSLOT_CHANGE 0
#define AQHOMEREACT_UNIT_VARCHANGES_OUTSLOT_RESULT 0
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _cbInputData(AQHREACT_UNIT *unit, int slotIdForUnit, const AQHREACT_DATAOBJECT *dataObject);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
AQHREACT_UNIT *AqHomeReact_UnitVarChanges_new(AQHOME_REACT *aqh)
{
AQHREACT_UNIT *unit;
AQHREACT_OUTPUT_SLOT *outputSlot;
AQHREACT_INPUT_SLOT *inputSlot;
unit=AQHREACT_Unit_new();
AQHREACT_Unit_SetName(unit, "varchanges");
AQHREACT_Unit_SetDescription(unit, "Propagates changes of values on the data server");
AQHREACT_Unit_SetInputDataFn(unit, _cbInputData);
outputSlot=AQHREACT_OutputSlot_new();
AQHREACT_OutputSlot_SetName(outputSlot, "output");
AQHREACT_OutputSlot_SetIdForUnit(outputSlot, AQHOMEREACT_UNIT_VARCHANGES_OUTSLOT_RESULT);
AQHREACT_OutputSlot_SetEmittedDataType(outputSlot, AQHREACT_DATAOBJECTTYPE_DOUBLE);
AQHREACT_Unit_AddOutputSlot(unit, outputSlot);
inputSlot=AQHREACT_InputSlot_new();
AQHREACT_InputSlot_SetName(inputSlot, "input");
AQHREACT_InputSlot_SetIdForUnit(inputSlot, AQHOMEREACT_UNIT_VARCHANGES_INSLOT_CHANGE);
AQHREACT_InputSlot_SetAcceptedDataType(inputSlot, AQHREACT_DATAOBJECTTYPE_DOUBLE);
AQHREACT_Unit_AddInputSlot(unit, inputSlot);
return unit;
}
void _cbInputData(AQHREACT_UNIT *unit, int slotIdForUnit, const AQHREACT_DATAOBJECT *dataObject)
{
if (unit && dataObject && slotIdForUnit==0)
AQHREACT_Unit_OutputData(unit, AQHOMEREACT_UNIT_VARCHANGES_OUTSLOT_RESULT, dataObject);
}

View File

@@ -0,0 +1,23 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2024 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 AQHOMEREACT_U_VARCHANGES_H
#define AQHOMEREACT_U_VARCHANGES_H
#include "aqhome-react/aqhome_react.h"
#include "aqhome-react/types/unit.h"
AQHREACT_UNIT *AqHomeReact_UnitVarChanges_new(AQHOME_REACT *aqh);
#endif