More work on aqhome-react.
This commit is contained in:
@@ -39,16 +39,24 @@
|
||||
<headers dist="true" >
|
||||
aqhome_react.h
|
||||
aqhome_react_p.h
|
||||
init.h
|
||||
fini.h
|
||||
loop.h
|
||||
</headers>
|
||||
|
||||
<sources>
|
||||
$(local/typefiles)
|
||||
aqhome_react.c
|
||||
init.c
|
||||
fini.c
|
||||
loop.c
|
||||
main.c
|
||||
</sources>
|
||||
|
||||
<useTargets>
|
||||
aqhome
|
||||
aqhreact_types
|
||||
aqhreact_units
|
||||
</useTargets>
|
||||
|
||||
<libraries>
|
||||
@@ -57,6 +65,7 @@
|
||||
|
||||
<subdirs>
|
||||
types
|
||||
units
|
||||
</subdirs>
|
||||
|
||||
|
||||
|
||||
86
apps/aqhome-react/aqhome_react.c
Normal file
86
apps/aqhome-react/aqhome_react.c
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
* 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
|
||||
* should have received along with this file.
|
||||
@@ -13,24 +13,22 @@
|
||||
#include <gwenhywfar/endpoint.h>
|
||||
|
||||
|
||||
#define AQHOME_REACT_DEFAULT_PIDFILE "/var/run/aqhome-react.pid"
|
||||
#define AQHOME_REACT_DEFAULT_DATADIR "/var/lib/aqhome-react"
|
||||
|
||||
#define AQHOME_REACT_DEFAULT_BROKER_PORT 1899
|
||||
#define AQHOME_REACT_DEFAULT_BROKER_CLIENTID "react"
|
||||
typedef struct AQHOME_REACT AQHOME_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
|
||||
|
||||
@@ -23,15 +23,12 @@
|
||||
|
||||
|
||||
struct AQHOME_REACT {
|
||||
GWEN_MSG_ENDPOINT *rootEndpoint;
|
||||
GWEN_MSG_ENDPOINT *brokerEndpoint; /* do not free (is part of tree pointed to by rootEndpoint) */
|
||||
GWEN_MSG_ENDPOINT *brokerEndpoint;
|
||||
|
||||
GWEN_DB_NODE *dbArgs;
|
||||
char *pidFile;
|
||||
int timeout; /* timeout for run e.g. inside valgrind */
|
||||
|
||||
AQH_STORAGE *storage;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
61
apps/aqhome-react/fini.c
Normal file
61
apps/aqhome-react/fini.c
Normal 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
21
apps/aqhome-react/fini.h
Normal 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
312
apps/aqhome-react/init.c
Normal 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
21
apps/aqhome-react/init.h
Normal 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
103
apps/aqhome-react/loop.c
Normal 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
21
apps/aqhome-react/loop.h
Normal 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
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
|
||||
#include "./inputslot_p.h"
|
||||
#include "aqhome-react/types/unit.h"
|
||||
|
||||
#include <gwenhywfar/list.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
@@ -27,6 +28,8 @@ AQHREACT_INPUT_SLOT *AQHREACT_InputSlot_new()
|
||||
|
||||
GWEN_NEW_OBJECT(AQHREACT_INPUT_SLOT, inSlot);
|
||||
GWEN_LIST_INIT(AQHREACT_INPUT_SLOT, inSlot);
|
||||
inSlot->idForUnit=-1;
|
||||
|
||||
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_SetDescription(inSlot, origSlot->description);
|
||||
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;
|
||||
/* don't copy current dataObject */
|
||||
return inSlot;
|
||||
|
||||
@@ -25,7 +25,7 @@ AQHREACT_LINK *AQHREACT_Link_new()
|
||||
|
||||
GWEN_NEW_OBJECT(AQHREACT_LINK, lnk);
|
||||
GWEN_LIST_INIT(AQHREACT_LINK, lnk);
|
||||
lnk->targetInputSlotIdx=-1;
|
||||
lnk->targetInputSlotIdForUnit=-1;
|
||||
|
||||
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)
|
||||
lnk->targetInputSlotIdx=i;;
|
||||
lnk->targetInputSlotIdForUnit=i;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -27,8 +27,8 @@ void AQHREACT_Link_free(AQHREACT_LINK *lnk);
|
||||
const char *AQHREACT_Link_GetTargetUnitId(const AQHREACT_LINK *lnk);
|
||||
void AQHREACT_Link_SetTargetUnitId(AQHREACT_LINK *lnk, const char *s);
|
||||
|
||||
int AQHREACT_Link_GetTargetInputSlotIdx(const AQHREACT_LINK *lnk);
|
||||
void AQHREACT_Link_SetTargetInputSlotIdx(AQHREACT_LINK *lnk, int i);
|
||||
int AQHREACT_Link_GetTargetInputSlotIdForUnit(const AQHREACT_LINK *lnk);
|
||||
void AQHREACT_Link_SetTargetInputSlotIdForUnit(AQHREACT_LINK *lnk, int i);
|
||||
|
||||
AQHREACT_UNIT *AQHREACT_Link_GetTargetUnit(const AQHREACT_LINK *lnk);
|
||||
void AQHREACT_Link_SetTargetUnit(AQHREACT_LINK *lnk, AQHREACT_UNIT *unit);
|
||||
|
||||
@@ -17,7 +17,7 @@ struct AQHREACT_LINK {
|
||||
GWEN_LIST_ELEMENT(AQHREACT_LINK)
|
||||
|
||||
char *targetUnitId;
|
||||
int targetInputSlotIdx;
|
||||
int targetInputSlotIdForUnit;
|
||||
|
||||
AQHREACT_UNIT *targetUnit;
|
||||
};
|
||||
|
||||
@@ -28,6 +28,7 @@ AQHREACT_OUTPUT_SLOT *AQHREACT_OutputSlot_new()
|
||||
GWEN_NEW_OBJECT(AQHREACT_OUTPUT_SLOT, outSlot);
|
||||
GWEN_LIST_INIT(AQHREACT_OUTPUT_SLOT, outSlot);
|
||||
outSlot->linkList=AQHREACT_Link_List_new();
|
||||
outSlot->id=-1;
|
||||
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)
|
||||
{
|
||||
return outSlot?outSlot->name:NULL;
|
||||
|
||||
@@ -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);
|
||||
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);
|
||||
void AQHREACT_OutputSlot_SetFlags(AQHREACT_OUTPUT_SLOT *outSlot, uint32_t f);
|
||||
void AQHREACT_OutputSlot_AddFlags(AQHREACT_OUTPUT_SLOT *outSlot, uint32_t f);
|
||||
|
||||
@@ -16,8 +16,10 @@
|
||||
struct AQHREACT_OUTPUT_SLOT {
|
||||
GWEN_LIST_ELEMENT(AQHREACT_OUTPUT_SLOT)
|
||||
|
||||
int id;
|
||||
char *name;
|
||||
char *description;
|
||||
int idForUnit;
|
||||
uint32_t flags;
|
||||
int emittedDataType;
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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) {
|
||||
AQHREACT_OUTPUT_SLOT *slot;
|
||||
|
||||
slot=AQHREACT_Unit_GetOutputSlotAt(unit, slotIndex);
|
||||
slot=AQHREACT_Unit_GetOutputSlotByIdForUnit(unit, slotIdForUnit);
|
||||
if (slot) {
|
||||
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);
|
||||
while(lnk) {
|
||||
AQHREACT_UNIT *targetUnit;
|
||||
int idx;
|
||||
int targetSlotIdForUnit;
|
||||
|
||||
targetUnit=AQHREACT_Link_GetTargetUnit(lnk);
|
||||
idx=AQHREACT_Link_GetTargetInputSlotIdx(lnk);
|
||||
if (targetUnit && idx>=0)
|
||||
AQHREACT_Unit_InputData(targetUnit, idx, dataObject);
|
||||
targetSlotIdForUnit=AQHREACT_Link_GetTargetInputSlotIdForUnit(lnk);
|
||||
if (targetUnit && targetSlotIdForUnit>=0)
|
||||
AQHREACT_Unit_InputData(targetUnit, targetSlotIdForUnit, dataObject);
|
||||
lnk=AQHREACT_Link_List_Next(lnk);
|
||||
} /* while */
|
||||
} /* 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->inputDataFn)
|
||||
(unit->inputDataFn)(unit, slotIndex, dataObject);
|
||||
(unit->inputDataFn)(unit, slotIdForUnit, dataObject);
|
||||
else {
|
||||
AQHREACT_Unit_ClearChangeFlagsInUnitAndInputSlots(unit);
|
||||
}
|
||||
@@ -261,16 +408,8 @@ int AQHREACT_Unit_Process(AQHREACT_UNIT *unit)
|
||||
if (unit) {
|
||||
if (unit->processFn)
|
||||
return (unit->processFn)(unit);
|
||||
else {
|
||||
AQHREACT_INPUT_SLOT *slot;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
else
|
||||
AQHREACT_Unit_ClearChangeFlagsInUnitAndInputSlots(unit);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
idx--;
|
||||
}
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
idx--;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ GWEN_INHERIT_FUNCTION_DEFS(AQHREACT_UNIT)
|
||||
#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);
|
||||
|
||||
|
||||
@@ -48,6 +48,9 @@ void AQHREACT_Unit_SetDescription(AQHREACT_UNIT *unit, const char *s);
|
||||
const char *AQHREACT_Unit_GetId(const AQHREACT_UNIT *unit);
|
||||
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);
|
||||
void AQHREACT_Unit_SetFlags(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);
|
||||
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);
|
||||
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);
|
||||
int AQHREACT_Unit_InputHasChanged(const AQHREACT_UNIT *unit);
|
||||
|
||||
|
||||
AQHREACT_PARAM_LIST *AQHREACT_Unit_GetParamList(const AQHREACT_UNIT *unit);
|
||||
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_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);
|
||||
|
||||
|
||||
@@ -23,6 +23,8 @@ struct AQHREACT_UNIT {
|
||||
|
||||
uint32_t flags;
|
||||
|
||||
int nextInputSlotId;
|
||||
|
||||
AQHREACT_INPUT_SLOT_LIST *inputSlotList;
|
||||
AQHREACT_OUTPUT_SLOT_LIST *outputSlotList;
|
||||
|
||||
|
||||
71
apps/aqhome-react/units/0BUILD
Normal file
71
apps/aqhome-react/units/0BUILD
Normal 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>
|
||||
|
||||
|
||||
136
apps/aqhome-react/units/u_or.c
Normal file
136
apps/aqhome-react/units/u_or.c
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
23
apps/aqhome-react/units/u_or.h
Normal file
23
apps/aqhome-react/units/u_or.h
Normal 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
|
||||
|
||||
|
||||
96
apps/aqhome-react/units/u_valuefilter.c
Normal file
96
apps/aqhome-react/units/u_valuefilter.c
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
26
apps/aqhome-react/units/u_valuefilter.h
Normal file
26
apps/aqhome-react/units/u_valuefilter.h
Normal 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
|
||||
|
||||
|
||||
81
apps/aqhome-react/units/u_varchanges.c
Normal file
81
apps/aqhome-react/units/u_varchanges.c
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
23
apps/aqhome-react/units/u_varchanges.h
Normal file
23
apps/aqhome-react/units/u_varchanges.h
Normal 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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user