aqhome-react: added program rules with test code.
This commit is contained in:
@@ -73,6 +73,11 @@ int AqHomeReact_Init(AQHOME_REACT *aqh, int argc, char **argv)
|
||||
DBG_ERROR(NULL, "Error reading args (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
s=GWEN_DB_GetCharValue(dbArgs, "params", 0, NULL);
|
||||
if (s && *s && strcasecmp(s, "modtest")==0)
|
||||
return rv;
|
||||
|
||||
AQH_MergeConfigFileIntoConfig(dbArgs, "ConfigFile");
|
||||
aqh->dbArgs=dbArgs;
|
||||
|
||||
@@ -340,7 +345,6 @@ int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs)
|
||||
I18S("Specify the device file"),
|
||||
I18S("Specify the device file")
|
||||
},
|
||||
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HELP | GWEN_ARGS_FLAGS_LAST, /* flags */
|
||||
GWEN_ArgsType_Int, /* type */
|
||||
@@ -354,7 +358,7 @@ int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs)
|
||||
}
|
||||
};
|
||||
|
||||
rv=GWEN_Args_Check(argc, argv, 1, 0, args, dbArgs);
|
||||
rv=GWEN_Args_Check(argc, argv, 1, GWEN_ARGS_MODE_ALLOW_FREEPARAM, args, dbArgs);
|
||||
if (rv==GWEN_ARGS_RESULT_ERROR) {
|
||||
fprintf(stderr, "ERROR: Could not parse arguments main\n");
|
||||
return GWEN_ERROR_INVALID;
|
||||
@@ -377,7 +381,7 @@ int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs)
|
||||
GWEN_Buffer_free(ubuf);
|
||||
return GWEN_ERROR_CLOSE;
|
||||
}
|
||||
return 0;
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "./loop.h"
|
||||
#include "./net_read.h"
|
||||
#include "aqhome-react/units/u_timer.h"
|
||||
#include "aqhome-react/types/prgrule-t.h"
|
||||
|
||||
#include "aqhome/aqhome.h"
|
||||
|
||||
@@ -25,6 +26,7 @@
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/cgui.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
#include <gwenhywfar/testframework.h>
|
||||
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
# include <signal.h>
|
||||
@@ -60,6 +62,7 @@
|
||||
*/
|
||||
|
||||
static void _serve(AQHOME_REACT *aqh);
|
||||
static int _testModules(int argc, char **argv);
|
||||
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
static int _setSignalHandlers(void);
|
||||
@@ -107,24 +110,32 @@ int main(int argc, char **argv)
|
||||
return 2;
|
||||
}
|
||||
|
||||
gui=GWEN_Gui_CGui_new();
|
||||
|
||||
aqh=AqHomeReact_new();
|
||||
rv=AqHomeReact_Init(aqh, argc, argv);
|
||||
dbArgs=AqHomeReact_GetDbArgs(aqh);
|
||||
DBG_ERROR(NULL, "RV=%d", rv);
|
||||
if (rv<0) {
|
||||
if (rv==GWEN_ERROR_CLOSE)
|
||||
return 1;
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return 2;
|
||||
}
|
||||
else if (rv>0) {
|
||||
argc-=rv;
|
||||
argv+=rv;
|
||||
rv=_testModules(argc, argv);
|
||||
}
|
||||
else {
|
||||
s=GWEN_DB_GetCharValue(dbArgs, "charset", 0, NULL);
|
||||
if (s && *s)
|
||||
GWEN_Gui_SetCharSet(gui, s);
|
||||
GWEN_Gui_SetGui(gui);
|
||||
|
||||
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);
|
||||
_serve(aqh);
|
||||
rv=0;
|
||||
}
|
||||
|
||||
AqHomeReact_Fini(aqh);
|
||||
AqHomeReact_free(aqh);
|
||||
@@ -132,7 +143,7 @@ int main(int argc, char **argv)
|
||||
GWEN_Gui_SetGui(NULL);
|
||||
GWEN_Gui_free(gui);
|
||||
|
||||
return 0;
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
@@ -273,4 +284,39 @@ void _signalHandler(int s)
|
||||
|
||||
|
||||
|
||||
int _testModules(int argc, char **argv)
|
||||
{
|
||||
GWEN_GUI *gui;
|
||||
GWEN_TEST_FRAMEWORK *tf;
|
||||
int rv;
|
||||
|
||||
gui=GWEN_Gui_CGui_new();
|
||||
GWEN_Gui_SetGui(gui);
|
||||
|
||||
tf=TestFramework_new();
|
||||
|
||||
rv=AQHREACT_PrgRule_AddTests(TestFramework_GetModulesRoot(tf));
|
||||
if (rv<0) {
|
||||
fprintf(stderr, "Adding module failed.\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
argc--;
|
||||
argv++;
|
||||
rv=TestFramework_Run(tf, argc, argv);
|
||||
if (rv) {
|
||||
fprintf(stderr, "SomeError in tests failed.\n");
|
||||
GWEN_Gui_SetGui(NULL);
|
||||
GWEN_Gui_free(gui);
|
||||
return 2;
|
||||
}
|
||||
TestFramework_free(tf);
|
||||
|
||||
GWEN_Gui_SetGui(NULL);
|
||||
GWEN_Gui_free(gui);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -47,6 +47,8 @@
|
||||
param_p.h
|
||||
unit.h
|
||||
unit_p.h
|
||||
prgrule.h
|
||||
prgrule_p.h
|
||||
</headers>
|
||||
|
||||
<sources>
|
||||
@@ -56,6 +58,7 @@
|
||||
link.c
|
||||
param.c
|
||||
unit.c
|
||||
prgrule.c
|
||||
</sources>
|
||||
|
||||
<useTargets>
|
||||
@@ -69,6 +72,8 @@
|
||||
|
||||
|
||||
<extradist>
|
||||
prgrule-t.h
|
||||
prgrule-t.c
|
||||
</extradist>
|
||||
|
||||
|
||||
|
||||
156
apps/aqhome-react/types/prgrule-t.c
Normal file
156
apps/aqhome-react/types/prgrule-t.c
Normal file
@@ -0,0 +1,156 @@
|
||||
/****************************************************************************
|
||||
* 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.
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
/* This file is included by "prgrule.c" */
|
||||
|
||||
|
||||
#include <gwenhywfar/testframework.h>
|
||||
#include "prgrule-t.h"
|
||||
|
||||
|
||||
#ifdef AQHOME_ENABLE_TESTCODE
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static int GWENHYWFAR_CB test1(GWEN_TEST_MODULE *mod);
|
||||
static int GWENHYWFAR_CB test2(GWEN_TEST_MODULE *mod);
|
||||
|
||||
static int testAgainstValues(const char *ruleText, const uint64_t *ptrExpectedFields, double expectedValue);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
int AQHREACT_PrgRule_AddTests(GWEN_TEST_MODULE *mod)
|
||||
{
|
||||
GWEN_TEST_MODULE *newMod;
|
||||
|
||||
newMod=GWEN_Test_Module_AddModule(mod, "AQHREACT_PrgRule", NULL);
|
||||
|
||||
GWEN_Test_Module_AddTest(newMod, "parse rules 1", test1, NULL);
|
||||
GWEN_Test_Module_AddTest(newMod, "parse rules 2", test2, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int test1(GWEN_UNUSED GWEN_TEST_MODULE *mod)
|
||||
{
|
||||
static char ruleText[]="* * * * * 10.0";
|
||||
uint64_t expectedFields[]={
|
||||
0b111111111111111111111111111111111111111111111111111111111111L, /* minute */
|
||||
0b111111111111111111111111L, /* hour */
|
||||
0b11111111111111111111111111111110L, /* day of month */
|
||||
0b1111111111110L, /* month */
|
||||
0b1111111L /* day of week (0=sunday) */
|
||||
};
|
||||
|
||||
return testAgainstValues(ruleText, expectedFields, 10.0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int test2(GWEN_UNUSED GWEN_TEST_MODULE *mod)
|
||||
{
|
||||
static char ruleText[]="/2 4-7 1-5,8,15,23-25 * 0,3,5 12.3";
|
||||
uint64_t expectedFields[]={
|
||||
0b010101010101010101010101010101010101010101010101010101010101L, /* minute */
|
||||
0b000000000000000011110000L, /* hour */
|
||||
0b00000011100000001000000100111110L, /* day of month */
|
||||
0b1111111111110L, /* month */
|
||||
0b0101001L /* day of week (0=sunday) */
|
||||
};
|
||||
|
||||
return testAgainstValues(ruleText, expectedFields, 12.3);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int testAgainstValues(const char *ruleText, const uint64_t *ptrExpectedFields, double expectedValue)
|
||||
{
|
||||
AQHREACT_PRGRULE_LIST *prgRuleList;
|
||||
AQHREACT_PRGRULE *prgRule;
|
||||
|
||||
prgRuleList=AQHREACT_PrgRule_ReadRules(ruleText);
|
||||
if (prgRuleList==NULL) {
|
||||
DBG_ERROR(NULL, "Error reading rules list");
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
prgRule=AQHREACT_PrgRule_List_First(prgRuleList);
|
||||
if (AQHREACT_PrgRule_List_Next(prgRule)) {
|
||||
DBG_ERROR(NULL, "More than one rule read when only one given");
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
if (prgRule->bitfieldMinute!=ptrExpectedFields[0]) {
|
||||
DBG_ERROR(NULL, "Unexpected value for MINUTE: %016lX [%016lX]", prgRule->bitfieldMinute, ptrExpectedFields[0]);
|
||||
AQHREACT_PrgRule_List_free(prgRuleList);
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
if (prgRule->bitfieldHour!=ptrExpectedFields[1]) {
|
||||
DBG_ERROR(NULL, "Unexpected value for HOUR: %016X [%016lX]", prgRule->bitfieldHour, ptrExpectedFields[1]);
|
||||
AQHREACT_PrgRule_List_free(prgRuleList);
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
if (prgRule->bitfieldDayOfMonth!=ptrExpectedFields[2]) {
|
||||
DBG_ERROR(NULL, "Unexpected value for DAYOFMONTH: %016X [%016lX]", prgRule->bitfieldDayOfMonth, ptrExpectedFields[2]);
|
||||
AQHREACT_PrgRule_List_free(prgRuleList);
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
if (prgRule->bitfieldMonth!=ptrExpectedFields[3]) {
|
||||
DBG_ERROR(NULL, "Unexpected value for MONTH: %016X [%016lX]", prgRule->bitfieldMonth, ptrExpectedFields[3]);
|
||||
AQHREACT_PrgRule_List_free(prgRuleList);
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
if (prgRule->bitfieldDayOfWeek!=ptrExpectedFields[4]) {
|
||||
DBG_ERROR(NULL, "Unexpected value for DAYOFWEEK: %08X [%016lX]", prgRule->bitfieldDayOfWeek, ptrExpectedFields[4]);
|
||||
AQHREACT_PrgRule_List_free(prgRuleList);
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
if (prgRule->value!=expectedValue) {
|
||||
DBG_ERROR(NULL, "Unexpected value : %f", prgRule->value);
|
||||
AQHREACT_PrgRule_List_free(prgRuleList);
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#else
|
||||
|
||||
int AQHREACT_PrgRule_AddTests(GWEN_TEST_MODULE *mod)
|
||||
{
|
||||
DBG_ERROR(GWEN_LOGDOMAIN, "AqHome was compiled without test code enabled.");
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
26
apps/aqhome-react/types/prgrule-t.h
Normal file
26
apps/aqhome-react/types/prgrule-t.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 AQHOME_REACT_PRGRULE_T_H
|
||||
#define AQHOME_REACT_PRGRULE_T_H
|
||||
|
||||
|
||||
|
||||
#include <gwenhywfar/gwenhywfarapi.h>
|
||||
#include <gwenhywfar/testframework.h>
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Internal tests for AQHREACT_PrgRule.
|
||||
*/
|
||||
int AQHREACT_PrgRule_AddTests(GWEN_TEST_MODULE *mod);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
418
apps/aqhome-react/types/prgrule.c
Normal file
418
apps/aqhome-react/types/prgrule.c
Normal file
@@ -0,0 +1,418 @@
|
||||
/****************************************************************************
|
||||
* 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 "./prgrule_p.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
GWEN_LIST_FUNCTIONS(AQHREACT_PRGRULE, AQHREACT_PrgRule)
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
const char *_readRule(AQHREACT_PRGRULE *prgRule, const char *s);
|
||||
|
||||
const char *_readField(const char *s, uint64_t *ptrBitField, int minValue, int maxValue);
|
||||
const char *_readRangeOpenBegin(const char *s, uint64_t *ptrBitField, int minValue, int maxValue);
|
||||
const char *_readInterval(const char *s, uint64_t *ptrBitField, int minValue, int maxValue);
|
||||
const char *_readValueAndProbablyRange(const char *s, uint64_t *ptrBitField, int minValue, int maxValue);
|
||||
const char *_readDouble(const char *s, double *ptrDouble);
|
||||
|
||||
int _valueOkay(int v, int minValue, int maxValue);
|
||||
int _rangeOkay(int startValue, int endValue, int minValue, int maxValue);
|
||||
void _setBitField(uint64_t *ptrBitField, int startValue, int endValue);
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
AQHREACT_PRGRULE *AQHREACT_PrgRule_new(void)
|
||||
{
|
||||
AQHREACT_PRGRULE *prgRule;
|
||||
|
||||
GWEN_NEW_OBJECT(AQHREACT_PRGRULE, prgRule);
|
||||
GWEN_LIST_INIT(AQHREACT_PRGRULE, prgRule);
|
||||
|
||||
return prgRule;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQHREACT_PrgRule_free(AQHREACT_PRGRULE *prgRule)
|
||||
{
|
||||
if (prgRule) {
|
||||
GWEN_LIST_FINI(AQHREACT_PRGRULE, prgRule);
|
||||
GWEN_FREE_OBJECT(prgRule);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AQHREACT_PrgRule_Matches(const AQHREACT_PRGRULE *prgRule, int min, int hour, int dayOfMonth, int month, int dayOfWeek)
|
||||
{
|
||||
if ((prgRule->bitfieldMonth & (1L<<month)) &&
|
||||
(prgRule->bitfieldDayOfMonth & (1L<<dayOfMonth)) &&
|
||||
(prgRule->bitfieldDayOfWeek & (1L<<dayOfWeek)) &&
|
||||
(prgRule->bitfieldHour & (1L<<hour)) &&
|
||||
(prgRule->bitfieldMinute & (1L<<min)))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHREACT_PRGRULE *AQHREACT_PrgRule_List_FindMatchingRule(AQHREACT_PRGRULE_LIST *prgRuleList,
|
||||
int min, int hour, int dayOfMonth, int month, int dayOfWeek)
|
||||
{
|
||||
AQHREACT_PRGRULE *prgRule;
|
||||
|
||||
prgRule=AQHREACT_PrgRule_List_First(prgRuleList);
|
||||
while(prgRule) {
|
||||
if (AQHREACT_PrgRule_Matches(prgRule, min, hour, dayOfMonth, month, dayOfWeek))
|
||||
return prgRule;
|
||||
prgRule=AQHREACT_PrgRule_List_Next(prgRule);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHREACT_PRGRULE_LIST *AQHREACT_PrgRule_ReadRules(const char *s)
|
||||
{
|
||||
AQHREACT_PRGRULE_LIST *prgRuleList;
|
||||
|
||||
prgRuleList=AQHREACT_PrgRule_List_new();
|
||||
|
||||
while(*s) {
|
||||
AQHREACT_PRGRULE *prgRule;
|
||||
const char *r;
|
||||
|
||||
prgRule=AQHREACT_PrgRule_new();
|
||||
r=_readRule(prgRule, s);
|
||||
if (r==NULL){
|
||||
DBG_INFO(NULL, "Error parsing \"%s\"", s);
|
||||
AQHREACT_PrgRule_free(prgRule);
|
||||
AQHREACT_PrgRule_List_free(prgRuleList);
|
||||
return NULL;
|
||||
}
|
||||
AQHREACT_PrgRule_List_Add(prgRule, prgRuleList);
|
||||
s=r;
|
||||
|
||||
while(*s && isspace(*s))
|
||||
s++;
|
||||
if (*s==';')
|
||||
s++;
|
||||
}
|
||||
|
||||
if (AQHREACT_PrgRule_List_GetCount(prgRuleList)<1) {
|
||||
AQHREACT_PrgRule_List_free(prgRuleList);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return prgRuleList;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *_readRule(AQHREACT_PRGRULE *prgRule, const char *s)
|
||||
{
|
||||
uint64_t v;
|
||||
const char *r;
|
||||
|
||||
v=0;
|
||||
r=_readField(s, &v, 0, 59);
|
||||
if (r==NULL) {
|
||||
DBG_ERROR(NULL, "Error reading MIN field at \"%s\"", s);
|
||||
return NULL;
|
||||
}
|
||||
prgRule->bitfieldMinute=v;
|
||||
|
||||
s=r;
|
||||
v=0;
|
||||
r=_readField(s, &v, 0, 23);
|
||||
if (r==NULL) {
|
||||
DBG_ERROR(NULL, "Error reading HOUR field at \"%s\"", s);
|
||||
return NULL;
|
||||
}
|
||||
prgRule->bitfieldHour=(uint32_t)(v & 0xffffffffl);
|
||||
|
||||
s=r;
|
||||
v=0;
|
||||
r=_readField(s, &v, 1, 31);
|
||||
if (r==NULL) {
|
||||
DBG_ERROR(NULL, "Error reading DAYOFMONTH field at \"%s\"", s);
|
||||
return NULL;
|
||||
}
|
||||
prgRule->bitfieldDayOfMonth=(uint32_t)(v & 0xffffffffl);
|
||||
|
||||
s=r;
|
||||
v=0;
|
||||
r=_readField(s, &v, 1, 12);
|
||||
if (r==NULL) {
|
||||
DBG_ERROR(NULL, "Error reading MONTH field at \"%s\"", s);
|
||||
return NULL;
|
||||
}
|
||||
prgRule->bitfieldMonth=(uint16_t)(v & 0xffffl);
|
||||
|
||||
s=r;
|
||||
v=0;
|
||||
r=_readField(s, &v, 0, 6);
|
||||
if (r==NULL) {
|
||||
DBG_ERROR(NULL, "Error reading DAYOFWEEK field at \"%s\"", s);
|
||||
return NULL;
|
||||
}
|
||||
prgRule->bitfieldDayOfWeek=(uint8_t)(v & 0xffl);
|
||||
|
||||
s=r;
|
||||
r=_readDouble(s, &(prgRule->value));
|
||||
if (r==NULL) {
|
||||
DBG_ERROR(NULL, "Error reading DOUBLE field at \"%s\"", s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *_readField(const char *s, uint64_t *ptrBitField, int minValue, int maxValue)
|
||||
{
|
||||
while(*s && isspace(*s))
|
||||
s++;
|
||||
|
||||
if (*s==0) {
|
||||
DBG_INFO(NULL, "Premature field end");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while(s && *s) {
|
||||
if (*s=='*') {
|
||||
_setBitField(ptrBitField, minValue, maxValue);
|
||||
s++;
|
||||
}
|
||||
else if (*s=='-') {
|
||||
s=_readRangeOpenBegin(++s, ptrBitField, minValue, maxValue);
|
||||
if (s==NULL) {
|
||||
DBG_INFO(NULL, "here");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else if (*s=='/') {
|
||||
s=_readInterval(++s, ptrBitField, minValue, maxValue);
|
||||
if (s==NULL) {
|
||||
DBG_INFO(NULL, "here");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else if (isdigit(*s)) {
|
||||
s=_readValueAndProbablyRange(s, ptrBitField, minValue, maxValue);
|
||||
if (s==NULL) {
|
||||
DBG_INFO(NULL, "here");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Unexpected character at \"%s\"", s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (isspace(*s)){
|
||||
/* field done */
|
||||
return s;
|
||||
}
|
||||
else if (*s==',') {
|
||||
s++;
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Unexpected character at \"%s\"", s);
|
||||
return NULL;
|
||||
}
|
||||
} /* while */
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *_readRangeOpenBegin(const char *s, uint64_t *ptrBitField, int minValue, int maxValue)
|
||||
{
|
||||
int v=0;
|
||||
|
||||
if (!isdigit(*s)) {
|
||||
DBG_ERROR(NULL, "Need at least start or end value for range");
|
||||
return NULL;
|
||||
}
|
||||
while(isdigit(*s)) {
|
||||
v*=10;
|
||||
v+=(*s)-'0';
|
||||
s++;
|
||||
}
|
||||
if (!_rangeOkay(minValue, v, minValue, maxValue)) {
|
||||
DBG_INFO(NULL, "here");
|
||||
return NULL;
|
||||
}
|
||||
_setBitField(ptrBitField, minValue, v);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *_readInterval(const char *s, uint64_t *ptrBitField, int minValue, int maxValue)
|
||||
{
|
||||
int v=0;
|
||||
int i;
|
||||
|
||||
while(isdigit(*s)) {
|
||||
v*=10;
|
||||
v+=(*s)-'0';
|
||||
s++;
|
||||
}
|
||||
if (v==0) {
|
||||
DBG_ERROR(NULL, "Bad value 0 for interval (/0)");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i=minValue; i<maxValue; i+=v) {
|
||||
_setBitField(ptrBitField, i, i);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *_readValueAndProbablyRange(const char *s, uint64_t *ptrBitField, int minValue, int maxValue)
|
||||
{
|
||||
int v=0;
|
||||
|
||||
while(isdigit(*s)) {
|
||||
v*=10;
|
||||
v+=(*s)-'0';
|
||||
s++;
|
||||
}
|
||||
if (!_valueOkay(v, minValue, maxValue)) {
|
||||
DBG_INFO(NULL, "here");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (*s=='-') {
|
||||
s=_readRangeOpenBegin(++s, ptrBitField, v, maxValue);
|
||||
if (s==NULL) {
|
||||
DBG_INFO(NULL, "here");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!_valueOkay(v, minValue, maxValue)) {
|
||||
DBG_INFO(NULL, "here");
|
||||
return NULL;
|
||||
}
|
||||
_setBitField(ptrBitField, v, v);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *_readDouble(const char *s, double *ptrDouble)
|
||||
{
|
||||
const char *sStart;
|
||||
int rv;
|
||||
|
||||
while(*s && isspace(*s))
|
||||
s++;
|
||||
sStart=s;
|
||||
while(*s && (isdigit(*s) || *s=='.'))
|
||||
s++;
|
||||
|
||||
rv=GWEN_Text_StringToDouble(sStart, ptrDouble);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error reading double: %d", rv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _valueOkay(int v, int minValue, int maxValue)
|
||||
{
|
||||
if (v<minValue) {
|
||||
DBG_ERROR(NULL, "Value below minimum value (%d < %d)", v, minValue);
|
||||
return 0;
|
||||
}
|
||||
if (v>maxValue) {
|
||||
DBG_ERROR(NULL, "Value above maxmum value (%d > %d)", v, maxValue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _rangeOkay(int startValue, int endValue, int minValue, int maxValue)
|
||||
{
|
||||
if (startValue>endValue) {
|
||||
DBG_ERROR(NULL, "Startvalue (%d) > endvalue (%d)", startValue, endValue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (startValue<minValue || startValue>maxValue) {
|
||||
DBG_ERROR(NULL, "Startvalue (%d) out of range (%d-%d)", startValue, minValue, maxValue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (endValue>maxValue) {
|
||||
DBG_ERROR(NULL, "Endvalue (%d) out of range (%d-%d)", endValue, minValue, maxValue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _setBitField(uint64_t *ptrBitField, int startValue, int endValue)
|
||||
{
|
||||
int i;
|
||||
uint64_t m;
|
||||
uint64_t v=0;
|
||||
|
||||
m=1l<<startValue;
|
||||
for (i=startValue; i<=endValue; i++) {
|
||||
v|=m;
|
||||
m<<=1;
|
||||
}
|
||||
*ptrBitField|=v;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#include "prgrule-t.c"
|
||||
|
||||
|
||||
|
||||
35
apps/aqhome-react/types/prgrule.h
Normal file
35
apps/aqhome-react/types/prgrule.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/****************************************************************************
|
||||
* 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 AQHOME_REACT_PRGRULE_H
|
||||
#define AQHOME_REACT_PRGRULE_H
|
||||
|
||||
|
||||
#include "aqhome-react/aqhome_react.h"
|
||||
|
||||
#include <gwenhywfar/gwentime.h>
|
||||
#include <gwenhywfar/list.h>
|
||||
|
||||
|
||||
typedef struct AQHREACT_PRGRULE AQHREACT_PRGRULE;
|
||||
GWEN_LIST_FUNCTION_DEFS(AQHREACT_PRGRULE, AQHREACT_PrgRule)
|
||||
|
||||
AQHREACT_PRGRULE *AQHREACT_PrgRule_new(void);
|
||||
void AQHREACT_PrgRule_free(AQHREACT_PRGRULE *prgRule);
|
||||
|
||||
int AQHREACT_PrgRule_Matches(const AQHREACT_PRGRULE *prgRule, int min, int hour, int dayOfMonth, int month, int dayOfWeek);
|
||||
|
||||
AQHREACT_PRGRULE *AQHREACT_PrgRule_List_FindMatchingRule(AQHREACT_PRGRULE_LIST *prgRuleList,
|
||||
int min, int hour, int dayOfMonth, int month, int dayOfWeek);
|
||||
|
||||
|
||||
AQHREACT_PRGRULE_LIST *AQHREACT_PrgRule_ReadRules(const char *s);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
30
apps/aqhome-react/types/prgrule_p.h
Normal file
30
apps/aqhome-react/types/prgrule_p.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/****************************************************************************
|
||||
* 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 AQHOME_REACT_PRGRULE_P_H
|
||||
#define AQHOME_REACT_PRGRULE_P_H
|
||||
|
||||
|
||||
#include "aqhome-react/types/prgrule.h"
|
||||
|
||||
|
||||
struct AQHREACT_PRGRULE {
|
||||
GWEN_LIST_ELEMENT(AQHREACT_PRGRULE)
|
||||
|
||||
uint64_t bitfieldMinute;
|
||||
uint32_t bitfieldDayOfMonth;
|
||||
uint32_t bitfieldHour;
|
||||
uint16_t bitfieldMonth;
|
||||
uint8_t bitfieldDayOfWeek;
|
||||
|
||||
double value;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user