75 Commits

Author SHA1 Message Date
Martin Preuss
439e787d37 added values to device description file for t03. 2025-07-06 14:40:14 +02:00
Martin Preuss
d242d63c2e disable irqs when releasing buffer. 2025-07-06 14:39:48 +02:00
Martin Preuss
86982d0000 reuse code. 2025-07-06 14:39:16 +02:00
Martin Preuss
f549ef5d27 added debug output. 2025-07-06 14:39:02 +02:00
Martin Preuss
fe2eaafb7b add devices r04 and r05 to flash script. 2025-07-06 14:38:43 +02:00
Martin Preuss
caf149fe8b minor changes to unify modules. 2025-07-06 14:38:21 +02:00
Martin Preuss
c540135705 fixed a bug. 2025-07-06 14:37:10 +02:00
Martin Preuss
734c237666 sort counters to simplify stats app. 2025-07-06 14:36:50 +02:00
Martin Preuss
85d445ec61 t03: use comonuart0 from uart_hw2 2025-07-06 14:35:52 +02:00
Martin Preuss
b059f4a56e added node r05. 2025-07-06 14:35:22 +02:00
Martin Preuss
b56ab22117 more work on test firmware for r04 2025-07-06 14:34:55 +02:00
Martin Preuss
5bda393b10 added valueids for stats from 2nd network device. 2025-07-06 12:24:46 +02:00
Martin Preuss
4ad508eca6 n27: removed driver for SGP30 (is now used externally in n26). 2025-07-06 12:23:49 +02:00
Martin Preuss
7f856dacf6 use uart_hw2 now. 2025-07-06 12:22:50 +02:00
Martin Preuss
b6ba56a564 added code to read calibration data. 2025-07-06 12:22:22 +02:00
Martin Preuss
f930b846c2 uart_hw2: basically works, but skips messages. 2025-07-06 12:21:41 +02:00
Martin Preuss
fc5394a5c9 avr: added comonuart0
works fine so far.
2025-07-03 22:12:40 +02:00
Martin Preuss
725ff96425 added test firmware for r04. 2025-07-03 22:11:27 +02:00
Martin Preuss
bfd0cd77a9 comonuart1: fixed bit names, disable IRQ when starting to write. 2025-07-03 00:16:29 +02:00
Martin Preuss
548a7634b7 comonuart1: undid some of the latest changes. 2025-07-02 00:10:46 +02:00
Martin Preuss
3e4637e174 comonuart1: try to solve timing/irq problem. 2025-07-02 00:08:01 +02:00
Martin Preuss
20b7c3f50d avr: new uart_hw2 module comonuart1 works now. 2025-07-01 00:52:44 +02:00
Martin Preuss
9206341032 started working on improved UART_HW module. 2025-06-30 21:29:05 +02:00
Martin Preuss
6383d18e0e avr: added comonuart1. 2025-06-29 22:32:43 +02:00
Martin Preuss
cfc7dc6320 avr: added r04. 2025-06-29 22:31:51 +02:00
Martin Preuss
72acef3aaf Increased max message size. 2025-06-26 00:31:11 +02:00
Martin Preuss
850975a85b avr: fixed a bug (was not calling sysOnEveryDay) 2025-06-26 00:18:33 +02:00
Martin Preuss
68ee246216 aqhome-tool: added some commands
- getFirstData
- getLastData
- getPeriodData
2025-06-26 00:18:05 +02:00
Martin Preuss
2ba802bb06 More work on dataclient library. 2025-06-26 00:16:52 +02:00
Martin Preuss
688129cf08 added n27 to flash script. 2025-06-25 00:09:41 +02:00
Martin Preuss
81721ab7eb avr: added device n27. 2025-06-25 00:05:47 +02:00
Martin Preuss
bf50871208 n25: use pin PA5 to select led strip driver to use
does nothing for now but will later allow to select between SK6812 and SPI.
2025-06-25 00:05:19 +02:00
Martin Preuss
cbf88e05fe added "mode" argument to "getdata" command. 2025-06-25 00:03:58 +02:00
Martin Preuss
a808450fa2 add dataclient sublib to be used by multiple tools. 2025-06-25 00:03:09 +02:00
Martin Preuss
033b7cd4db getvalues: allow for filtering value list on server. 2025-06-25 00:02:32 +02:00
Martin Preuss
cd6a918533 s_getvalues: allow for filtering output list. 2025-06-25 00:01:52 +02:00
Martin Preuss
63ebcbadc9 added msg "getValues" 2025-06-25 00:01:12 +02:00
Martin Preuss
b2802a37aa added AQH_Storage_GetFirstNDataPoints() 2025-06-25 00:00:39 +02:00
Martin Preuss
1e95b317bf incremented firmware version. 2025-06-23 19:28:35 +02:00
Martin Preuss
78fec171f9 sgp30: measure every second, increases accuracy. 2025-06-23 19:28:20 +02:00
Martin Preuss
8bfaabcf27 read 10bit brightness (instead of 8 bit). 2025-06-23 19:27:53 +02:00
Martin Preuss
2b08847cf7 added n26. 2025-06-23 19:21:58 +02:00
Martin Preuss
9ea722607f avr: added brightness sensor 2025-06-23 19:21:49 +02:00
Martin Preuss
409155f0d0 increment version. 2025-06-17 00:14:14 +02:00
Martin Preuss
026a943648 avr: adde stats messages to device definitions. 2025-06-17 00:13:52 +02:00
Martin Preuss
aeb6df5685 avr: reduce number of messages send.
- sensor report interval 60->120s
- stats report interval 11-31 mins
2025-06-17 00:13:33 +02:00
Martin Preuss
06886e0094 aqhome-cgi: more work 2025-06-16 23:31:53 +02:00
Martin Preuss
b498a445b2 added missing files, n26, increased firmware version. 2025-06-16 23:31:38 +02:00
Martin Preuss
876e9ac7b9 avr: added n14 back in. 2025-06-16 23:29:56 +02:00
Martin Preuss
a89b875872 avr: added NET_Interface_ResetStats and call it daily. 2025-06-16 23:29:18 +02:00
Martin Preuss
0ce70e48b1 avr: added type "light" 2025-06-16 23:27:37 +02:00
Martin Preuss
bf583a1aa5 avr: incremented version. 2025-06-15 17:47:45 +02:00
Martin Preuss
1533f82ec4 n21: send value of door sensor every minute
this will allow us to determine the best value for a adc limit to detect
open/closed windows and doors.
2025-06-15 17:47:34 +02:00
Martin Preuss
8a43bc252f tcrt1000: decreased limit from 170 to 100 2025-06-15 17:46:06 +02:00
Martin Preuss
ffcc5c0d9f some minor work on gui/win modules. 2025-06-12 23:30:36 +02:00
Martin Preuss
c51043d72a more work on aqhome-cgi. 2025-06-12 23:30:08 +02:00
Martin Preuss
2cb534df85 more work on GUI module. 2025-06-05 22:48:22 +02:00
Martin Preuss
4f30623f2d increased stacksize. 2025-06-05 22:47:54 +02:00
Martin Preuss
b9ac7c65fa include CCS811 in reportsensors app. 2025-06-05 22:46:55 +02:00
Martin Preuss
cef487fb3a re-enabled node n19. adapted n20. 2025-06-05 22:45:52 +02:00
Martin Preuss
284539fd52 re-enabled CCS811 module, adapted to latest changes. 2025-06-05 22:44:27 +02:00
Martin Preuss
08a1313ba5 More work on layout code. 2025-06-04 23:56:42 +02:00
Martin Preuss
7349014bd6 Make coordinates 16 bit again. 2025-06-04 23:56:29 +02:00
Martin Preuss
12cfe2ff4b Fixed a bug.
Need to make room for stack.
2025-06-04 23:56:04 +02:00
Martin Preuss
ae1892f196 share code. 2025-06-03 00:00:14 +02:00
Martin Preuss
dbad237826 fixed a typo. 2025-06-02 23:41:38 +02:00
Martin Preuss
56e222a97e split WID_SIGNAL_GETMINSIZE into two signals. 2025-06-02 23:38:08 +02:00
Martin Preuss
888792a201 more work on gui code. 2025-06-02 23:29:50 +02:00
Martin Preuss
41867ed01a added missing files. 2025-06-02 23:29:06 +02:00
Martin Preuss
b82e0d02df avr: more general approach to fonts. 2025-06-02 21:13:44 +02:00
Martin Preuss
cd1fce313e avr: added some unit tests for LIST and TREE. 2025-06-02 21:13:01 +02:00
Martin Preuss
5153bd2f69 removed signal "CREATED".
unsure when this would be called:
- when the basic object is called?
- when the last derived object is called?
better remove it to avoid complications...
2025-06-02 01:04:49 +02:00
Martin Preuss
d4ad6844e3 ili9341: save X 2025-06-02 01:03:23 +02:00
Martin Preuss
4f610c68a2 added more fonts and corresponding code. disabled test code in ili9341 module. 2025-06-02 01:03:03 +02:00
Martin Preuss
3582659018 added more bigcall/bigjmp as we go along with larger code. 2025-06-02 01:02:06 +02:00
205 changed files with 14964 additions and 1852 deletions

5
0BUILD
View File

@@ -2,7 +2,7 @@
<gwbuild>
<project name="aqhome" version="0.0.10" so_current="0" so_age="0" so_revision="10" write_config_h="TRUE">
<project name="aqhome" version="0.0.11" so_current="0" so_age="0" so_revision="11" write_config_h="TRUE">
<setVar name="package">$(project_name)</setVar>
<setVar name="version">
$(project_vmajor).$(project_vminor).$(project_vpatchlevel)
@@ -51,6 +51,8 @@
<setVar name="pkgincludedir">$(includedir)/aqhome/$(package)</setVar>
<setVar name="pkgdatadir">$(datadir)/$(package)</setVar>
<setVar name="httpdatadir">/var/www</setVar>
<option id="enable_testcode" type="string">
<default>TRUE</default>
<choices>TRUE FALSE</choices>
@@ -126,6 +128,7 @@
</option>
<checkheaders>
signal.h
sys/stat.h

View File

@@ -3,7 +3,7 @@
<gwbuild>
<target type="Program" name="aqhome-cgi" install="$(sbindir)" >
<target type="Program" name="aqhome-cgi" install="$(libdir)/cgi-bin" >
<includes type="c" >
$(gwenhywfar_cflags)
@@ -55,6 +55,7 @@
<libraries>
$(gwenhywfar_libs)
-lm
$(aqcgi_libs)
</libraries>
<subdirs>
@@ -117,6 +118,7 @@
<useTargets>
aqhome
aqhcgi_service
aqhcgi_modules
</useTargets>
<libraries>
@@ -127,6 +129,7 @@
<subdirs>
service
modules
</subdirs>

23
apps/aqhome-cgi/README Normal file
View File

@@ -0,0 +1,23 @@
Modules:
- login
- signup
- main
- devices
- list
- show?name="nodes/12345678"
- add
- edit
- delete
- values
- rooms
- users
- list
- show?alias="admin"
- add
- edit
- delete
- dashboards

View File

@@ -1,11 +1,181 @@
#include "./service_file.h"
#include "aqhome-cgi/modules/mroot.h"
#include "aqhome/aqhome.h"
#include <aqcgi/cgi.h>
#include <aqcgi/request.h>
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/nogui.h>
#include <gwenhywfar/logger.h>
#include <gwenhywfar/text.h>
#include <gwenhywfar/debug.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#define AQHOME_CGI_LOGFILE "/var/www/aqhome-cgi/log/aqhome-cgi.log"
#define AQHOME_CGI_DEFAULT_STATIC_FILES "0-build/services/static"
#define AQHOME_CGI_DEFAULT_RUNTIME_FILES "0-build/services/runtime"
void _handleRequest(AQCGI_REQUEST *rq, const char *sPathStaticFiles, const char *sPathRuntimeFiles);
int _handlePath(AQH_SERVICE *sv, AQCGI_REQUEST *rq, const char *sPathStaticFiles);
AQH_MODULE *_loadModule(AQH_SERVICE *sv, AQCGI_REQUEST *rq, AQH_MODULE *mParent, const char *sModuleName);
static void logStart(void);
int main(int argc, char **argv)
{
GWEN_GUI *gui;
AQCGI_REQUEST *rq;
GWEN_Init();
gui=GWEN_NoGui_new();
GWEN_Gui_SetGui(gui);
logStart();
GWEN_Logger_Open(GWEN_LOGDOMAIN, "gwenhywfar", AQHOME_CGI_LOGFILE, GWEN_LoggerType_File, GWEN_LoggerFacility_Daemon);
GWEN_Logger_Open(AQH_LOGDOMAIN, "aqhome", AQHOME_CGI_LOGFILE, GWEN_LoggerType_File, GWEN_LoggerFacility_Daemon);
GWEN_Logger_Open(AQCGI_LOGDOMAIN, "aqcgi", AQHOME_CGI_LOGFILE, GWEN_LoggerType_File, GWEN_LoggerFacility_Daemon);
GWEN_Logger_Open(NULL, "aqhome-cgi", AQHOME_CGI_LOGFILE, GWEN_LoggerType_File, GWEN_LoggerFacility_Daemon);
GWEN_Logger_SetLevel(GWEN_LOGDOMAIN, GWEN_LoggerLevel_Debug);
GWEN_Logger_SetLevel(AQCGI_LOGDOMAIN, GWEN_LoggerLevel_Debug);
GWEN_Logger_SetLevel(NULL, GWEN_LoggerLevel_Debug);
DBG_ERROR(NULL, "Init CGI");
AQCGI_Init();
GWEN_Logger_Close(GWEN_LOGDOMAIN);
GWEN_Logger_Open(GWEN_LOGDOMAIN, "gwenhywfar", AQHOME_CGI_LOGFILE, GWEN_LoggerType_File, GWEN_LoggerFacility_Daemon);
GWEN_Logger_SetLevel(GWEN_LOGDOMAIN, GWEN_LoggerLevel_Debug);
GWEN_Logger_SetLevel(AQCGI_LOGDOMAIN, GWEN_LoggerLevel_Debug);
GWEN_Logger_SetLevel(NULL, GWEN_LoggerLevel_Debug);
rq=AQCGI_ReadRequest();
if (rq) {
const char *sPathStaticFiles;
const char *sPathRuntimeFiles;
sPathStaticFiles=getenv("AQHOME_STATIC_FILES");
if (!(sPathStaticFiles && *sPathStaticFiles))
sPathStaticFiles=AQHOME_CGI_DEFAULT_STATIC_FILES;
sPathRuntimeFiles=getenv("AQHOME_RUNTIME_FILES");
if (!(sPathRuntimeFiles && *sPathRuntimeFiles))
sPathRuntimeFiles=AQHOME_CGI_DEFAULT_RUNTIME_FILES;
_handleRequest(rq, sPathStaticFiles, sPathRuntimeFiles);
}
else {
fprintf(stdout, "Content-type: text/plain\n\n");
fprintf(stdout, "Error: No Request!\n");
return 0;
}
AQCGI_Fini();
return 0;
}
void _handleRequest(AQCGI_REQUEST *rq, const char *sPathStaticFiles, const char *sPathRuntimeFiles)
{
AQH_SERVICE *sv;
int rv;
sv=AQH_ServiceFiles_new(sPathRuntimeFiles);
rv=_handlePath(sv, rq, sPathStaticFiles);
if (rv<0) {
}
AQH_Service_free(sv);
}
int _handlePath(AQH_SERVICE *sv, AQCGI_REQUEST *rq, const char *sPathStaticFiles)
{
AQH_MODULE *mRoot;
AQH_MODULE *mParent;
const GWEN_STRINGLIST *sl;
mRoot=AQH_ModRoot_new(sv, sPathStaticFiles);
mParent=mRoot;
sl=AQCGI_Request_GetStringlistPath(rq);
if (sl) {
GWEN_STRINGLISTENTRY *se;
se=GWEN_StringList_FirstEntry(sl);
while(se) {
GWEN_STRINGLISTENTRY *seNext;
const char *s;
seNext=GWEN_StringListEntry_Next(se);
s=GWEN_StringListEntry_Data(se);
if (s && *s) {
if (seNext) {
AQH_MODULE *m;
DBG_ERROR(NULL, "Entry: %s (%s)", s, seNext?"not last":"last");
m=AQH_ModService_LoadSubModule(mParent, rq, s);
if (m==NULL) {
AQH_Module_free(mRoot);
AQCGI_SendResponseWithStatus(rq, 404, "Not found");
return GWEN_ERROR_GENERIC;
}
mParent=m;
}
else {
int rv;
/* last, let module handle remaining part */
rv=AQH_ModService_HandleRequest(mParent, rq, s);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
AQH_Module_free(mRoot);
return rv;
}
break;
}
}
se=seNext;
}
AQH_Module_free(mRoot);
return 0;
}
else {
AQH_Module_free(mRoot);
return GWEN_ERROR_GENERIC;
}
}
void logStart()
{
FILE *f;
f=fopen(AQHOME_CGI_LOGFILE, "a+");
if (f!=NULL) {
fprintf(f, "Started.\n");
fclose(f);
}
}

View File

@@ -0,0 +1,84 @@
<?xml?>
<gwbuild>
<target type="ConvenienceLibrary" name="aqhcgi_modules" >
<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>
<define name="BUILDING_AQHOME" />
<setVar name="local/cflags">$(visibility_cflags)</setVar>
<setVar name="tm2flags-INACTIVE" >
--api=AQHOME_API
</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="false" install="$(pkgincludedir)/service" >
$(local/built_headers_pub)
</headers>
<headers dist="true" install="$(pkgincludedir)/service" >
mservice.h
mroot.h
</headers>
<headers dist="true" >
mservice_p.h
mroot_p.h
</headers>
<sources>
$(local/typefiles)
mservice.c
mroot.c
</sources>
<extradist>
</extradist>
<useTargets>
</useTargets>
<subdirs>
static
</subdirs>
</target>
</gwbuild>

View File

@@ -0,0 +1,246 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2025 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 "./mroot_p.h"
#include "aqhome-cgi/service/module.h"
#include <gwenhywfar/debug.h>
#include <gwenhywfar/timestamp.h>
/* ------------------------------------------------------------------------------------------------
* defs and enums
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* global vars
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static AQH_MODULE *_loadSubModule(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sModuleName);
static int _handleRequest(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sLastPathElem);
static int _handleRqLogin(AQH_MODULE *m, AQCGI_REQUEST *rq);
static int _handleRqLoginPost(AQH_MODULE *m, AQCGI_REQUEST *rq);
static AQH_USER *_getAndCheckUser(AQH_MODULE *m, AQCGI_REQUEST *rq);
/* ------------------------------------------------------------------------------------------------
* code
* ------------------------------------------------------------------------------------------------
*/
AQH_MODULE *AQH_ModRoot_new(AQH_SERVICE *sv, const char *baseFolder)
{
AQH_MODULE *m;
m=AQH_ModService_new(sv, baseFolder);
AQH_ModService_SetHandleRequestFn(m, _handleRequest);
AQH_ModService_SetLoadSubModuleFn(m, _loadSubModule);
return m;
}
AQH_MODULE *_loadSubModule(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sModuleName)
{
return NULL;
}
int _handleRequest(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sLastPathElem)
{
if (strcasecmp(sLastPathElem, "login")==0)
return _handleRqLogin(m, rq);
else if (strcasecmp(sLastPathElem, "signup")==0) {
AQCGI_SendResponseWithStatus(rq, 501, "Not Implemented");
return GWEN_ERROR_NOT_IMPLEMENTED;
}
else if (strcasecmp(sLastPathElem, "confirm")==0) {
AQCGI_SendResponseWithStatus(rq, 501, "Not Implemented");
return GWEN_ERROR_NOT_IMPLEMENTED;
}
else {
AQCGI_SendResponseWithStatus(rq, 404, "Not Found");
return GWEN_ERROR_NOT_IMPLEMENTED;
}
}
int _handleRqLogin(AQH_MODULE *m, AQCGI_REQUEST *rq)
{
int rv;
if (AQCGI_Request_GetRequestMethod(rq)==AQCGI_REQUEST_METHOD_GET)
rv=AQH_ModService_RespondWithFile(m, rq, "en", "login.html");
else if (AQCGI_Request_GetRequestMethod(rq)==AQCGI_REQUEST_METHOD_POST)
rv=_handleRqLoginPost(m, rq);
else {
DBG_ERROR(NULL, "Invalid request method %d", AQCGI_Request_GetRequestMethod(rq));
AQCGI_SendResponseWithStatus(rq, 405, "Method No Allowed");
return GWEN_ERROR_INVALID;
}
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return rv;
}
return 0;
}
int _handleRqLoginPost(AQH_MODULE *m, AQCGI_REQUEST *rq)
{
AQH_SERVICE *sv;
AQH_USER *user;
AQH_SESSION *session;
GWEN_BUFFER *dbuf;
GWEN_TIMESTAMP *ts;
int rv;
DBG_ERROR(NULL, "Handling request");
sv=AQH_ModService_GetService(m);
user=_getAndCheckUser(m, rq);
if (user==NULL) {
DBG_INFO(NULL, "here");
return GWEN_ERROR_GENERIC;
}
ts=GWEN_Timestamp_NowInLocalTime();
AQH_User_SetTimestampLastLogin(user, ts);
DBG_ERROR(NULL, "Saving user");
rv=AQH_Service_SaveUser(sv, user);
if (rv<0) {
DBG_ERROR(NULL, "Error saving user \"%s\"", AQH_User_GetAlias(user));
AQCGI_SendResponseWithStatus(rq, 500, "Internal Error");
AQH_User_free(user);
return rv;
}
/* generate session */
DBG_ERROR(NULL, "Generating session");
dbuf=GWEN_Buffer_new(0, 64, 0, 1);
AQCGI_GenerateSessionId(dbuf);
session=AQH_Session_new();
AQH_Session_SetTimestampCreation(session, ts);
AQH_Session_SetTimestampLastAccess(session, ts);
AQH_Session_SetUid(session, GWEN_Buffer_GetStart(dbuf));
GWEN_Buffer_free(dbuf);
AQH_Session_SetUserAlias(session, AQH_User_GetAlias(user));
rv=AQH_Service_AddSession(sv, session);
if (rv<0) {
DBG_ERROR(NULL, "Error adding session for user \"%s\"", AQH_User_GetAlias(user));
AQCGI_SendResponseWithStatus(rq, 500, "Internal Error");
AQH_Session_free(session);
AQH_User_free(user);
return GWEN_ERROR_INTERNAL;
}
/* add Set-Cookie header */
dbuf=GWEN_Buffer_new(0, 256, 0, 1);
GWEN_Buffer_AppendArgs(dbuf, "Set-Cookie: session=%s; max-age=3600", AQH_Session_GetUid(session));
AQCGI_Request_AddResponseHeaderData(rq, GWEN_Buffer_GetStart(dbuf));
/* finish */
AQCGI_SendResponseWithStatus(rq, 200, "Ok");
AQH_Session_free(session);
AQH_User_free(user);
return 0;
}
AQH_USER *_getAndCheckUser(AQH_MODULE *m, AQCGI_REQUEST *rq)
{
GWEN_DB_NODE *dbPost;
dbPost=AQCGI_Request_GetDbPostBody(rq);
if (dbPost) {
AQH_SERVICE *sv;
const char *sUserName;
const char *sPasswd;
AQH_USER *user;
const char *hashedPaswd;
GWEN_BUFFER *buf;
sv=AQH_ModService_GetService(m);
sUserName=GWEN_DB_GetCharValue(dbPost, "userid", 0, NULL);
sPasswd=GWEN_DB_GetCharValue(dbPost, "password", 0, NULL);
if (!(sUserName && *sUserName && sPasswd && *sPasswd)) {
DBG_ERROR(NULL, "Either user name or password missing");
AQCGI_SendResponseWithStatus(rq, 400, "Bad Request");
return NULL;
}
DBG_ERROR(NULL, "Loading user \"%s\" (%p)", sUserName, sv);
user=AQH_Service_LoadUser(sv, sUserName);
if (user==NULL) {
DBG_ERROR(NULL, "User \"%s\" not found", sUserName);
AQCGI_SendResponseWithStatus(rq, 403, "Forbidden");
return NULL;
}
DBG_ERROR(NULL, "Loaded user \"%s\"", sUserName);
if (AQH_User_GetState(user)!=AQH_UserState_Active) {
DBG_ERROR(NULL, "User \"%s\" not active", sUserName);
AQCGI_SendResponseWithStatus(rq, 403, "Forbidden");
AQH_User_free(user);
return NULL;
}
hashedPaswd=AQH_User_GetHashedPassword(user);
if (!(hashedPaswd && *hashedPaswd)) {
DBG_ERROR(NULL, "User \"%s\" has no hashed password", sUserName);
AQCGI_SendResponseWithStatus(rq, 403, "Forbidden");
AQH_User_free(user);
return NULL;
}
buf=GWEN_Buffer_new(0, 256, 0, 1);
AQCGI_HashMd256ToBuffer(sPasswd, buf);
DBG_ERROR(NULL, "Hashed password: [%s]", GWEN_Buffer_GetStart(buf));
if (strcasecmp(GWEN_Buffer_GetStart(buf), hashedPaswd)!=0) {
DBG_ERROR(NULL, "Bad password for user \"%s\"", sUserName);
AQCGI_SendResponseWithStatus(rq, 403, "Forbidden");
GWEN_Buffer_free(buf);
AQH_User_free(user);
return NULL;
}
GWEN_Buffer_free(buf);
DBG_ERROR(NULL, "User \"%s\" accepted", sUserName);
return user;
}
else {
DBG_ERROR(NULL, "No POST data");
AQCGI_SendResponseWithStatus(rq, 400, "Bad Request");
return NULL;
}
}

View File

@@ -0,0 +1,27 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2025 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_CGI_MROOT_H
#define AQHOME_CGI_MROOT_H
#include <aqhome-cgi/modules/mservice.h>
#include <aqcgi/request.h>
#include <gwenhywfar/buffer.h>
AQH_MODULE *AQH_ModRoot_new(AQH_SERVICE *sv, const char *baseFolder);
AQH_MODULE *AQH_ModRoot_LoadSubModule(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sModuleName);
int AQH_ModRoot_HandleRequest(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sLastPathElem);
#endif

View File

@@ -0,0 +1,18 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2025 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_CGI_MROOT_P_H
#define AQHOME_CGI_MROOT_P_H
#include "aqhome-cgi/modules/mroot.h"
#endif

View File

@@ -0,0 +1,291 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2025 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 "./mservice_p.h"
#include "aqhome-cgi/service/module.h"
#include <gwenhywfar/debug.h>
/* ------------------------------------------------------------------------------------------------
* defs and enums
* ------------------------------------------------------------------------------------------------
*/
#define AQH_MOD_SERVICE_HEADERFILE "header.html"
#define AQH_MOD_SERVICE_FOOTERFILE "footer.html"
/* ------------------------------------------------------------------------------------------------
* global vars
* ------------------------------------------------------------------------------------------------
*/
GWEN_INHERIT(AQH_MODULE, AQH_MOD_SERVICE)
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void GWENHYWFAR_CB _freeData(void *bp, void *p);
/* ------------------------------------------------------------------------------------------------
* code
* ------------------------------------------------------------------------------------------------
*/
AQH_MODULE *AQH_ModService_new(AQH_SERVICE *sv, const char *baseFolder)
{
AQH_MODULE *m;
AQH_MOD_SERVICE *xm;
m=AQH_Module_new();
GWEN_NEW_OBJECT(AQH_MOD_SERVICE, xm);
GWEN_INHERIT_SETDATA(AQH_MODULE, AQH_MOD_SERVICE, m, xm, _freeData);
xm->service=sv;
xm->baseFolder=(baseFolder && *baseFolder)?strdup(baseFolder):NULL;
return m;
}
void _freeData(GWEN_UNUSED void *bp, void *p)
{
AQH_MOD_SERVICE *xm;
xm=(AQH_MOD_SERVICE*) p;
free(xm->baseFolder);
GWEN_FREE_OBJECT(xm);
}
AQH_SERVICE *AQH_ModService_GetService(const AQH_MODULE *m)
{
if (m) {
AQH_MOD_SERVICE *xm;
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
if (xm) {
return xm->service;
}
}
return NULL;
}
const char *AQH_ModService_GetBaseFolder(const AQH_MODULE *m)
{
if (m) {
AQH_MOD_SERVICE *xm;
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
if (xm) {
return xm->baseFolder;
}
}
return NULL;
}
void AQH_ModService_SetHandleRequestFn(AQH_MODULE *m, AQH_MODSERVICE_HANDLEREQUEST_FN fn)
{
if (m) {
AQH_MOD_SERVICE *xm;
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
if (xm) {
xm->handleRequestFn=fn;
}
}
}
void AQH_ModService_SetLoadSubModuleFn(AQH_MODULE *m, AQH_MODSERVICE_LOADSUBMODULE_FN fn)
{
if (m) {
AQH_MOD_SERVICE *xm;
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
if (xm) {
xm->loadSubModuleFn=fn;
}
}
}
int AQH_ModService_AddHeader(AQH_MODULE *m, const char *lang, GWEN_BUFFER *dbuf)
{
if (m && dbuf) {
AQH_MODULE *mParent;
mParent=AQH_Module_Tree2_GetParent(m);
if (mParent) {
int rv;
rv=AQH_ModService_AddHeader(mParent, lang, dbuf);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return rv;
}
}
return AQH_ModService_ReadStaticFile(m, lang, AQH_MOD_SERVICE_HEADERFILE, dbuf);
}
DBG_ERROR(NULL, "Argument missing");
return GWEN_ERROR_INVALID;
}
int AQH_ModService_AddFooter(AQH_MODULE *m, const char *lang, GWEN_BUFFER *dbuf)
{
if (m && dbuf) {
AQH_MODULE *mParent;
int rv;
rv=AQH_ModService_ReadStaticFile(m, lang, AQH_MOD_SERVICE_FOOTERFILE, dbuf);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return rv;
}
mParent=AQH_Module_Tree2_GetParent(m);
if (mParent) {
int rv;
rv=AQH_ModService_AddFooter(mParent, lang, dbuf);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return rv;
}
}
return 0;
}
else {
DBG_ERROR(NULL, "Argument missing");
return GWEN_ERROR_INVALID;
}
}
int AQH_ModService_RespondWithFile(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *lang, const char *sFilename)
{
GWEN_BUFFER *buf;
int rv;
buf=GWEN_Buffer_new(0, 256, 0, 1);
rv=AQH_ModService_AddHeader(m, lang, buf);
if (rv<0) {
AQCGI_SendResponseWithStatus(rq, 500, "Internal error");
GWEN_Buffer_free(buf);
return GWEN_ERROR_INTERNAL;
}
rv=AQH_ModService_ReadStaticFile(m, lang, sFilename, buf);
if (rv<0) {
AQCGI_SendResponseWithStatus(rq, 500, "Internal error");
GWEN_Buffer_free(buf);
return GWEN_ERROR_INTERNAL;
}
rv=AQH_ModService_AddFooter(m, lang, buf);
if (rv<0) {
AQCGI_SendResponseWithStatus(rq, 500, "Internal error");
GWEN_Buffer_free(buf);
return GWEN_ERROR_INTERNAL;
}
AQCGI_Request_SetBufferResponseBody(rq, buf);
AQCGI_Request_AddResponseHeaderData(rq, "Content-type: text/html");
AQCGI_SendResponseWithStatus(rq, 200, "Ok");
return 0;
}
int AQH_ModService_HandleRequest(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sLastPathElem)
{
if (m) {
AQH_MOD_SERVICE *xm;
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
if (xm && xm->handleRequestFn)
return xm->handleRequestFn(m, rq, sLastPathElem);
}
return GWEN_ERROR_NOT_IMPLEMENTED;
}
AQH_MODULE *AQH_ModService_LoadSubModule(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sModuleName)
{
if (m) {
AQH_MOD_SERVICE *xm;
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
if (xm && xm->loadSubModuleFn)
return xm->loadSubModuleFn(m, rq, sModuleName);
}
return NULL;
}
int AQH_ModService_ReadStaticFile(AQH_MODULE *m, const char *lang, const char *filename, GWEN_BUFFER *dbuf)
{
if (m && filename && dbuf) {
AQH_MOD_SERVICE *xm;
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
if (xm) {
GWEN_BUFFER *fbuf;
int rv;
fbuf=GWEN_Buffer_new(0, 256, 0, 1);
GWEN_Buffer_AppendString(fbuf, xm->baseFolder);
GWEN_Buffer_AppendString(fbuf, GWEN_DIR_SEPARATOR_S);
GWEN_Buffer_AppendString(fbuf, (lang && *lang)?lang:"en");
GWEN_Buffer_AppendString(fbuf, GWEN_DIR_SEPARATOR_S);
GWEN_Buffer_AppendString(fbuf, filename);
DBG_ERROR(NULL, "Reading file \"%s\"", GWEN_Buffer_GetStart(fbuf));
rv=GWEN_SyncIo_Helper_ReadFile(GWEN_Buffer_GetStart(fbuf), dbuf);
if (rv<0) {
DBG_ERROR(NULL, "Read(%s): %d", GWEN_Buffer_GetStart(fbuf), rv);
GWEN_Buffer_free(fbuf);
return rv;
}
GWEN_Buffer_free(fbuf);
return 0;
}
}
DBG_ERROR(NULL, "Any arg is missing (or is not a AQH_MOD_SERVICE object)");
return GWEN_ERROR_INTERNAL;
}

View File

@@ -0,0 +1,46 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2025 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_CGI_MSERVICE_H
#define AQHOME_CGI_MSERVICE_H
#include <aqhome-cgi/service/module.h>
#include <aqhome-cgi/service/service.h>
#include <aqcgi/request.h>
#include <gwenhywfar/buffer.h>
typedef int (*AQH_MODSERVICE_HANDLEREQUEST_FN)(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sLastPathElem);
typedef AQH_MODULE* (*AQH_MODSERVICE_LOADSUBMODULE_FN)(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sModuleName);
AQH_MODULE *AQH_ModService_new(AQH_SERVICE *sv, const char *baseFolder);
AQH_SERVICE *AQH_ModService_GetService(const AQH_MODULE *m);
const char *AQH_ModService_GetBaseFolder(const AQH_MODULE *m);
int AQH_ModService_AddHeader(AQH_MODULE *m, const char *lang, GWEN_BUFFER *dbuf);
int AQH_ModService_AddFooter(AQH_MODULE *m, const char *lang, GWEN_BUFFER *dbuf);
AQH_MODULE *AQH_ModService_LoadSubModule(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sModuleName);
int AQH_ModService_HandleRequest(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sLastPathElem);
int AQH_ModService_RespondWithFile(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *lang, const char *sFilename);
int AQH_ModService_ReadStaticFile(AQH_MODULE *m, const char *lang, const char *filename, GWEN_BUFFER *dbuf);
void AQH_ModService_SetHandleRequestFn(AQH_MODULE *m, AQH_MODSERVICE_HANDLEREQUEST_FN fn);
void AQH_ModService_SetLoadSubModuleFn(AQH_MODULE *m, AQH_MODSERVICE_LOADSUBMODULE_FN fn);
#endif

View File

@@ -0,0 +1,27 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2025 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_CGI_MSERVICE_P_H
#define AQHOME_CGI_MSERVICE_P_H
#include "aqhome-cgi/modules/mservice.h"
typedef struct AQH_MOD_SERVICE AQH_MOD_SERVICE;
struct AQH_MOD_SERVICE {
AQH_SERVICE *service;
char *baseFolder;
AQH_MODSERVICE_HANDLEREQUEST_FN handleRequestFn;
AQH_MODSERVICE_LOADSUBMODULE_FN loadSubModuleFn;
};
#endif

View File

@@ -0,0 +1,7 @@
<?xml?>
<gwbuild>
<subdirs>
en
</subdirs>
</gwbuild>

View File

@@ -0,0 +1,13 @@
<?xml?>
<gwbuild>
<data dist="true" install="$(httpdatadir)/aqhome-cgi/static/en">
header.html
footer.html
login.html
</data>
</gwbuild>

View File

@@ -0,0 +1,4 @@
</body>
</html>

View File

@@ -0,0 +1,17 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<!-- copyright (c) 2025 by martin@libchipcard.de -->
<meta name="generator" content="FTE 1.1" />
<meta name="revised" content="martin,2025-06-12" />
<meta name="keywords" content="" />
<meta name="description" content="" />
<meta name="author" content="martin" />
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
<title>AqHome</title>
</head>
<body>

View File

@@ -0,0 +1,25 @@
<div class="main">
<h1>AqHome</h1>
<h3>Enter your login credentials</h3>
<form action="login" method="post">
<label for="userid">Username:</label>
<input type="text" id="userid" name="userid" placeholder="Enter your Username" required>
<label for="password">Password:</label>
<input type="password" id="password" name="password" placeholder="Enter your Password" required>
<div class="wrap">
<button type="submit">Submit</button>
</div>
</form>
<p>Not registered?
<a href="signup" style="text-decoration: none;">
Create an account
</a>
</p>
</div>
</body>
</html>

View File

@@ -54,6 +54,10 @@
<descr>Waiting for approval by admin</descr>
</item>
<item name="active">
<descr>User active</descr>
</item>
</enum>
</enums>

View File

@@ -70,6 +70,8 @@ static int _addGroupLocked(AQH_SERVICE *sv, const char *groupName, const char *s
static int _deleteGroup(AQH_SERVICE *sv, const char *groupName, const char *subGroupName);
static GWEN_STRINGLIST *_listGroup(AQH_SERVICE *sv, const char *groupName);
//static void _logGroup(const char *groupName, const char *subGroupName, GWEN_DB_NODE *db);
/* ------------------------------------------------------------------------------------------------
@@ -169,6 +171,9 @@ int _saveUser(AQH_SERVICE *sv, AQH_USER *user)
GWEN_DB_Group_free(db);
return rv;
}
//_logGroup(AQH_SERVICE_FILE_GROUP_USERS, s, db);
rv=_saveGroupLocked(sv, AQH_SERVICE_FILE_GROUP_USERS, s, db);
if (rv<0) {
DBG_ERROR(NULL, "here (%d)", rv);
@@ -414,6 +419,7 @@ GWEN_STRINGLIST *_listSessions(AQH_SERVICE *sv)
GWEN_DB_NODE *_loadGroupLocked(AQH_SERVICE *sv, const char *groupName, const char *subGroupName)
{
DBG_ERROR(NULL, "Lock and load group %s/%s", groupName, subGroupName);
if (sv && groupName && subGroupName) {
AQH_SERVICE_FILE *xs;
@@ -422,17 +428,20 @@ GWEN_DB_NODE *_loadGroupLocked(AQH_SERVICE *sv, const char *groupName, const cha
GWEN_DB_NODE *db=NULL;
int rv;
DBG_ERROR(NULL, "Locking group %s/%s", groupName, subGroupName);
rv=GWEN_ConfigMgr_LockGroup(xs->configMgr, groupName, subGroupName);
if (rv<0) {
DBG_ERROR(NULL, "Error locking group \"%s/%s\": %d", groupName, subGroupName, rv);
return NULL;
}
DBG_ERROR(NULL, "Loading group %s/%s", groupName, subGroupName);
rv=GWEN_ConfigMgr_GetGroup(xs->configMgr, groupName, subGroupName, &db);
if (rv<0) {
DBG_ERROR(NULL, "Error reading group \"%s/%s\": %d", groupName, subGroupName, rv);
GWEN_ConfigMgr_UnlockGroup(xs->configMgr, groupName, subGroupName);
return NULL;
}
DBG_ERROR(NULL, "Unlocking group %s/%s", groupName, subGroupName);
rv=GWEN_ConfigMgr_UnlockGroup(xs->configMgr, groupName, subGroupName);
if (rv<0) {
DBG_ERROR(NULL, "Error unlocking group \"%s/%s\": %d", groupName, subGroupName, rv);
@@ -442,6 +451,9 @@ GWEN_DB_NODE *_loadGroupLocked(AQH_SERVICE *sv, const char *groupName, const cha
return db;
}
}
else {
DBG_ERROR(NULL, "Missing argument");
}
return NULL;
}
@@ -454,25 +466,26 @@ int _saveGroupLocked(AQH_SERVICE *sv, const char *groupName, const char *subGrou
xs=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_SERVICE_FILE, sv);
if (xs) {
GWEN_DB_NODE *db=NULL;
int rv;
DBG_ERROR(NULL, "Locking group %s/%s", groupName, subGroupName);
rv=GWEN_ConfigMgr_LockGroup(xs->configMgr, groupName, subGroupName);
if (rv<0) {
DBG_ERROR(NULL, "Error locking group \"%s/%s\": %d", groupName, subGroupName, rv);
return rv;
}
DBG_ERROR(NULL, "Writing group %s/%s", groupName, subGroupName);
rv=GWEN_ConfigMgr_SetGroup(xs->configMgr, groupName, subGroupName, db);
if (rv<0) {
DBG_ERROR(NULL, "Error writing group \"%s/%s\": %d", groupName, subGroupName, rv);
return rv;
}
DBG_ERROR(NULL, "Unlocking group %s/%s", groupName, subGroupName);
rv=GWEN_ConfigMgr_UnlockGroup(xs->configMgr, groupName, subGroupName);
if (rv<0) {
DBG_ERROR(NULL, "Error unlocking group \"%s/%s\": %d", groupName, subGroupName, rv);
GWEN_DB_Group_free(db);
return rv;
}
@@ -491,7 +504,6 @@ int _addGroupLocked(AQH_SERVICE *sv, const char *groupName, const char *subGroup
xs=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_SERVICE_FILE, sv);
if (xs) {
GWEN_DB_NODE *db=NULL;
int rv;
rv=GWEN_ConfigMgr_HasGroup(xs->configMgr, groupName, subGroupName);
@@ -515,7 +527,6 @@ int _addGroupLocked(AQH_SERVICE *sv, const char *groupName, const char *subGroup
rv=GWEN_ConfigMgr_UnlockGroup(xs->configMgr, groupName, subGroupName);
if (rv<0) {
DBG_ERROR(NULL, "Error unlocking group \"%s/%s\": %d", groupName, subGroupName, rv);
GWEN_DB_Group_free(db);
return rv;
}
@@ -577,3 +588,24 @@ GWEN_STRINGLIST *_listGroup(AQH_SERVICE *sv, const char *groupName)
}
#if 0
void _logGroup(const char *groupName, const char *subGroupName, GWEN_DB_NODE *db)
{
if (db) {
GWEN_BUFFER *dbuf;
dbuf=GWEN_Buffer_new(0, 256, 0, 1);
GWEN_DB_WriteToBuffer(db, dbuf, GWEN_DB_FLAGS_DEFAULT);
DBG_ERROR(NULL, "Group %s/%s:\n%s", groupName?groupName:"<empty>", subGroupName?subGroupName:"<empty>",
GWEN_Buffer_GetStart(dbuf));
GWEN_Buffer_free(dbuf);
}
else {
DBG_ERROR(NULL, "Group %s/%s empty", groupName?groupName:"<empty>", subGroupName?subGroupName:"<empty>");
}
}
#endif

View File

@@ -13,6 +13,7 @@
#include "aqhome-cgi/service/service.h"
AQH_SERVICE *AQH_ServiceFiles_new(const char *baseFolder);

View File

@@ -1,6 +1,6 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
* AqHome (c) by 2025 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.
@@ -33,8 +33,8 @@
* ------------------------------------------------------------------------------------------------
*/
#define AQHOMEDATA_HANDLEGETDATAPOINTS_MAXTABLEENTRIES 2048
#define AQHOMEDATA_HANDLEGETDATAPOINTS_MAXDATAPOINTS 1024
#define AQHOMEDATA_HANDLEGETDATAPOINTS_MAXTABLEENTRIES 1024
#define AQHOMEDATA_HANDLEGETDATAPOINTS_MAXDATAPOINTS 512
/* ------------------------------------------------------------------------------------------------
@@ -44,13 +44,15 @@
static int _getAndSendDataPoints(AQH_STORAGE *storage, AQH_OBJECT *ep,
const AQH_VALUE *value,
int mode,
uint64_t tsBegin, uint64_t tsEnd, uint64_t num, uint32_t refMsgId);
static int _getAndSendDataPointsNoNum(AQH_STORAGE *storage, AQH_OBJECT *ep, const AQH_VALUE *value, uint64_t tsBegin, uint64_t tsEnd,
static int _getAndSendDataPointsPeriod(AQH_STORAGE *storage, AQH_OBJECT *ep, const AQH_VALUE *value,
uint64_t tsBegin, uint64_t tsEnd, uint64_t num,
uint32_t refMsgId);
static int _getAndSendDataPointsWithNum(AQH_STORAGE *storage, AQH_OBJECT *ep, const AQH_VALUE *value, uint64_t num, uint32_t refMsgId);
static int _getAndSendDataPointsFirst(AQH_STORAGE *storage, AQH_OBJECT *ep, const AQH_VALUE *value, uint64_t num, uint32_t refMsgId);
static int _getAndSendDataPointsLast(AQH_STORAGE *storage, AQH_OBJECT *ep, const AQH_VALUE *value, uint64_t num, uint32_t refMsgId);
static void _sendDataPointsResponse(AQH_OBJECT *ep, const AQH_VALUE *value, const uint64_t *tablePtr,
uint32_t refMsgId);
static void _getAndSendLastDatapoint(AQH_STORAGE *storage, AQH_OBJECT *ep, const AQH_VALUE *value, uint32_t refMsgId);
@@ -79,16 +81,18 @@ void AqHomeDataServer_HandleGetDataPoints(AQH_OBJECT *o, AQH_OBJECT *ep, const A
uint64_t tsBegin;
uint64_t tsEnd;
uint64_t numRequested;
int mode;
tsBegin=AQH_Tag16_GetTagDataAsUint64(tagList, AQH_MSGDATA_GETDATA_TAGS_BEGIN, 0);
tsEnd=AQH_Tag16_GetTagDataAsUint64(tagList, AQH_MSGDATA_GETDATA_TAGS_END, 0);
numRequested=AQH_Tag16_GetTagDataAsUint64(tagList, AQH_MSGDATA_GETDATA_TAGS_NUM, 0);
mode=AQH_Tag16_GetTagDataAsUint64(tagList, AQH_MSGDATA_GETDATA_TAGS_MODE, AQH_MSGDATA_GETDATA_MODE_FIRST);
value=AQH_Storage_GetValueByNameForSystem(xo->storage, valueName);
if (value) {
int resultCode;
resultCode=_getAndSendDataPoints(xo->storage, ep, value, tsBegin, tsEnd, numRequested, refMsgId);
resultCode=_getAndSendDataPoints(xo->storage, ep, value, mode, tsBegin, tsEnd, numRequested, refMsgId);
AqHomeDataServer_SendResponseResultToEndpoint(ep, refMsgId, resultCode);
}
else {
@@ -114,30 +118,31 @@ void AqHomeDataServer_HandleGetDataPoints(AQH_OBJECT *o, AQH_OBJECT *ep, const A
int _getAndSendDataPoints(AQH_STORAGE *storage, AQH_OBJECT *ep,
const AQH_VALUE *value,
int mode,
uint64_t tsBegin, uint64_t tsEnd, uint64_t num,
uint32_t refMsgId)
{
if (num==0)
return _getAndSendDataPointsNoNum(storage, ep, value, tsBegin, tsEnd, refMsgId);
else if (num==1) {
_getAndSendLastDatapoint(storage, ep, value, refMsgId);
return AQH_MSGDATA_RESULT_SUCCESS;
switch(mode) {
case AQH_MSGDATA_GETDATA_MODE_FIRST: return _getAndSendDataPointsFirst(storage, ep, value, num, refMsgId);
case AQH_MSGDATA_GETDATA_MODE_PERIOD: return _getAndSendDataPointsPeriod(storage, ep, value, tsBegin, tsEnd, num, refMsgId);
default:
case AQH_MSGDATA_GETDATA_MODE_LAST: return _getAndSendDataPointsLast(storage, ep, value, num, refMsgId);
}
else
return _getAndSendDataPointsWithNum(storage, ep, value, num, refMsgId);
}
int _getAndSendDataPointsNoNum(AQH_STORAGE *storage, AQH_OBJECT *ep,
const AQH_VALUE *value, uint64_t tsBegin, uint64_t tsEnd,
uint32_t refMsgId)
int _getAndSendDataPointsPeriod(AQH_STORAGE *storage, AQH_OBJECT *ep,
const AQH_VALUE *value, uint64_t tsBegin, uint64_t tsEnd, uint64_t num,
uint32_t refMsgId)
{
uint64_t valueId;
uint64_t *tablePtr;
valueId=AQH_Value_GetId(value);
tablePtr=AQH_Storage_GetDataPoints(storage, valueId, tsBegin, tsEnd, AQHOMEDATA_HANDLEGETDATAPOINTS_MAXTABLEENTRIES);
if (num==0 || num>AQHOMEDATA_HANDLEGETDATAPOINTS_MAXTABLEENTRIES)
num=AQHOMEDATA_HANDLEGETDATAPOINTS_MAXTABLEENTRIES;
tablePtr=AQH_Storage_GetDataPoints(storage, valueId, tsBegin, tsEnd, num);
if (tablePtr) {
_sendDataPointsResponse(ep, value, tablePtr, refMsgId);
free(tablePtr);
@@ -151,9 +156,9 @@ int _getAndSendDataPointsNoNum(AQH_STORAGE *storage, AQH_OBJECT *ep,
int _getAndSendDataPointsWithNum(AQH_STORAGE *storage, AQH_OBJECT *ep,
const AQH_VALUE *value, uint64_t num,
uint32_t refMsgId)
int _getAndSendDataPointsLast(AQH_STORAGE *storage, AQH_OBJECT *ep,
const AQH_VALUE *value, uint64_t num,
uint32_t refMsgId)
{
uint64_t valueId;
uint64_t *tablePtr;
@@ -175,6 +180,30 @@ int _getAndSendDataPointsWithNum(AQH_STORAGE *storage, AQH_OBJECT *ep,
int _getAndSendDataPointsFirst(AQH_STORAGE *storage, AQH_OBJECT *ep,
const AQH_VALUE *value, uint64_t num,
uint32_t refMsgId)
{
uint64_t valueId;
uint64_t *tablePtr;
if (num>AQHOMEDATA_HANDLEGETDATAPOINTS_MAXDATAPOINTS)
num=AQHOMEDATA_HANDLEGETDATAPOINTS_MAXDATAPOINTS;
valueId=AQH_Value_GetId(value);
tablePtr=AQH_Storage_GetFirstNDataPoints(storage, valueId, num);
if (tablePtr) {
_sendDataPointsResponse(ep, value, tablePtr, refMsgId);
free(tablePtr);
return AQH_MSGDATA_RESULT_SUCCESS;
}
else {
DBG_INFO(NULL, "No matching datapoints for value \"%s\"", AQH_Value_GetNameForSystem(value));
return AQH_MSGDATA_RESULT_ERROR_NODATA;
}
}
void _sendDataPointsResponse(AQH_OBJECT *ep,
const AQH_VALUE *value, const uint64_t *tablePtr,
uint32_t refMsgId)
@@ -193,36 +222,3 @@ void _sendDataPointsResponse(AQH_OBJECT *ep,
void _getAndSendLastDatapoint(AQH_STORAGE *storage, AQH_OBJECT *ep,
const AQH_VALUE *value, uint32_t refMsgId)
{
int rv;
uint64_t timestamp=0;
double data=0.0;
rv=AQH_Storage_GetLastDataPoint(storage, AQH_Value_GetId(value), &timestamp, &data);
if (rv<0) {
int resultCode;
switch(rv) {
case GWEN_ERROR_INVALID: resultCode=AQH_MSGDATA_RESULT_ERROR_INVALID; break;
case GWEN_ERROR_NO_DATA: resultCode=AQH_MSGDATA_RESULT_ERROR_NODATA; break;
default: resultCode=AQH_MSGDATA_RESULT_ERROR_GENERIC; break;
}
AqHomeDataServer_SendResponseResultToEndpoint(ep, refMsgId, resultCode);
}
else {
AQH_MESSAGE *outMsg;
outMsg=AQH_IpcdMessageMultiData_newForOne(AQH_MSGTYPE_IPC_DATA_GETDATA_RSP,
AQH_Endpoint_GetNextMessageId(ep), refMsgId,
value, timestamp, data);
AQH_Endpoint_AddMsgOut(ep, outMsg);
}
}

View File

@@ -13,13 +13,16 @@
#include "./s_getvalues.h"
#include "./server_p.h"
#include "aqhome/aqhome.h"
#include "aqhome/ipc2/endpoint.h"
#include "aqhome/msg/ipc/m_ipc.h"
#include "aqhome/msg/ipc/data/m_ipcd.h"
#include "aqhome/msg/ipc/data/m_ipcd_getvalues.h"
#include "aqhome/msg/ipc/data/m_ipcd_values.h"
#include "aqhome/msg/ipc/m_ipc_result.h"
#include "aqhome/msg/ipc/m_ipc_tag16.h"
#include <gwenhywfar/text.h>
#include <gwenhywfar/debug.h>
@@ -38,7 +41,10 @@
* ------------------------------------------------------------------------------------------------
*/
static void _sendValueList(AQH_OBJECT *ep, const AQH_VALUE_LIST *vl, uint32_t flags, uint32_t refMsgId);
static AQH_VALUE_LIST *_getMatchingValueList(AQHOME_SERVER *xo, const GWEN_TAG16_LIST *tagList);
static void _sendValueList(AQH_OBJECT *ep, const AQH_VALUE_LIST *vl, uint32_t refMsgId);
static void _sendValueListMsg(AQH_OBJECT *ep, const AQH_VALUE_LIST *vl, uint32_t flags, uint32_t refMsgId);
static int _valueMatches(const AQH_VALUE *v, const char *deviceName, int modality);
@@ -47,64 +53,100 @@ static void _sendValueList(AQH_OBJECT *ep, const AQH_VALUE_LIST *vl, uint32_t fl
* ------------------------------------------------------------------------------------------------
*/
void AqHomeDataServer_HandleGetValues(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg, GWEN_UNUSED const GWEN_TAG16_LIST *tagList)
void AqHomeDataServer_HandleGetValues(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList)
{
AQHOME_SERVER *xo;
xo=AqHomeDataServer_GetServerData(o);
if (xo) {
const AQH_VALUE_LIST *origValueList;
AQH_VALUE_LIST *valueList;
uint32_t refMsgId;
refMsgId=AQH_IpcMessage_GetMsgId(msg);
DBG_INFO(NULL, "HandleGetValues");
origValueList=AQH_Storage_GetValueList(xo->storage);
if (origValueList) {
DBG_INFO(NULL, "Have a list of %d values", AQH_Value_List_GetCount(origValueList));
if (AQH_Value_List_GetCount(origValueList)<AQHOMEDATA_VALUESPERMSG) {
DBG_INFO(NULL, "Sending all entries in one message");
_sendValueList(ep, origValueList, AQH_MSGDATA_VALUES_FLAGS_LASTMSG, refMsgId);
}
else {
AQH_VALUE_LIST *tmpValueList;
const AQH_VALUE *v;
DBG_INFO(NULL, "Sending entries in multiple messages");
tmpValueList=AQH_Value_List_new();
v=AQH_Value_List_First(origValueList);
while(v) {
const AQH_VALUE *next;
AQH_VALUE *copyOfValue;
next=AQH_Value_List_Next(v);
copyOfValue=AQH_Value_dup(v);
AQH_Value_List_Add(copyOfValue, tmpValueList);
if (AQH_Value_List_GetCount(tmpValueList)>=AQHOMEDATA_VALUESPERMSG) {
DBG_INFO(NULL, "Sending %d values", AQH_Value_List_GetCount(tmpValueList));
_sendValueList(ep, tmpValueList, next?0:AQH_MSGDATA_VALUES_FLAGS_LASTMSG, refMsgId);
AQH_Value_List_Clear(tmpValueList);
}
v=next;
}
if (AQH_Value_List_GetCount(tmpValueList)) {
DBG_INFO(NULL, "Sending %d values", AQH_Value_List_GetCount(tmpValueList));
_sendValueList(ep, tmpValueList, AQH_MSGDATA_VALUES_FLAGS_LASTMSG, refMsgId); /* send remaining */
}
AQH_Value_List_free(tmpValueList);
}
valueList=_getMatchingValueList(xo, tagList);
if (valueList) {
_sendValueList(ep, valueList, refMsgId);
AQH_Value_List_free(valueList);
}
else {
/* empty list */
_sendValueList(ep, NULL, AQH_MSGDATA_VALUES_FLAGS_LASTMSG, refMsgId);
_sendValueListMsg(ep, NULL, AQH_MSGDATA_VALUES_FLAGS_LASTMSG, refMsgId);
}
}
}
void _sendValueList(AQH_OBJECT *ep, const AQH_VALUE_LIST *vl, uint32_t flags, uint32_t refMsgId)
AQH_VALUE_LIST *_getMatchingValueList(AQHOME_SERVER *xo, const GWEN_TAG16_LIST *tagList)
{
const AQH_VALUE_LIST *origValueList;
AQH_VALUE_LIST *tmpValueList=NULL;
char *deviceName;
int modality;
deviceName=tagList?AQH_Tag16_GetTagDataAsNewString(tagList, AQH_MSGDATA_GETVALUES_TAGS_DEVICENAME, NULL):NULL;
modality=tagList?AQH_Tag16_GetTagDataAsUint64(tagList, AQH_MSGDATA_GETVALUES_TAGS_MODALITY, 0):0;
origValueList=AQH_Storage_GetValueList(xo->storage);
if (origValueList) {
const AQH_VALUE *v;
tmpValueList=AQH_Value_List_new();
v=AQH_Value_List_First(origValueList);
while(v) {
if (_valueMatches(v, deviceName, modality)) {
AQH_VALUE *copyOfValue;
copyOfValue=AQH_Value_dup(v);
AQH_Value_List_Add(copyOfValue, tmpValueList);
}
v=AQH_Value_List_Next(v);
}
if (AQH_Value_List_GetCount(tmpValueList)<1) {
AQH_Value_List_free(tmpValueList);
tmpValueList=NULL;
}
}
free(deviceName);
return tmpValueList;
}
void _sendValueList(AQH_OBJECT *ep, const AQH_VALUE_LIST *vl, uint32_t refMsgId)
{
AQH_VALUE_LIST *tmpValueList;
const AQH_VALUE *v;
tmpValueList=AQH_Value_List_new();
v=AQH_Value_List_First(vl);
while(v) {
const AQH_VALUE *next;
AQH_VALUE *copyOfValue;
next=AQH_Value_List_Next(v);
copyOfValue=AQH_Value_dup(v);
AQH_Value_List_Add(copyOfValue, tmpValueList);
if (AQH_Value_List_GetCount(tmpValueList)>=AQHOMEDATA_VALUESPERMSG) {
DBG_INFO(NULL, "Sending %d values", AQH_Value_List_GetCount(tmpValueList));
_sendValueListMsg(ep, tmpValueList, next?0:AQH_MSGDATA_VALUES_FLAGS_LASTMSG, refMsgId);
AQH_Value_List_Clear(tmpValueList);
}
v=next;
}
if (AQH_Value_List_GetCount(tmpValueList)) {
DBG_INFO(NULL, "Sending %d values", AQH_Value_List_GetCount(tmpValueList));
_sendValueListMsg(ep, tmpValueList, AQH_MSGDATA_VALUES_FLAGS_LASTMSG, refMsgId); /* send remaining */
}
AQH_Value_List_free(tmpValueList);
}
void _sendValueListMsg(AQH_OBJECT *ep, const AQH_VALUE_LIST *vl, uint32_t flags, uint32_t refMsgId)
{
AQH_MESSAGE *msg;
@@ -115,3 +157,27 @@ void _sendValueList(AQH_OBJECT *ep, const AQH_VALUE_LIST *vl, uint32_t flags, ui
int _valueMatches(const AQH_VALUE *v, const char *deviceName, int modality)
{
if (modality!=AQH_ValueModality_Unknown) {
int valModality;
valModality=AQH_Value_GetModality(v);
if (valModality!=modality)
return 0;
}
if (deviceName && *deviceName) {
const char *s;
s=AQH_Value_GetDeviceNameForSystem(v);
if (s && *s && GWEN_Text_ComparePattern(s, deviceName, 0)==-1)
return 0;
}
return 1;
}

View File

@@ -37,6 +37,9 @@
getdevices.h
adddata.h
getdatapoints.h
getfirstdata.h
getlastdata.h
getperioddata.h
setdata.h
moddevice.h
watch.h
@@ -49,6 +52,9 @@
getdevices.c
adddata.c
getdatapoints.c
getfirstdata.c
getlastdata.c
getperioddata.c
setdata.c
moddevice.c
watch.c

View File

@@ -10,7 +10,7 @@
# include <config.h>
#endif
#include "./getvalues.h"
#include "./getdatapoints.h"
#include "../client.h"
#include "../utils.h"
@@ -52,7 +52,6 @@
static AQH_MESSAGE *_createRequestMessage(AQH_OBJECT *o, uint32_t msgId);
static int _handleResponseMessage(AQH_OBJECT *o, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList, int first);
static void _handleDataResponse(const GWEN_TAG16_LIST *tagList, int printMean, int printDiff);
static uint64_t _getTimeStampFromString(const char *s);
@@ -110,18 +109,23 @@ AQH_MESSAGE *_createRequestMessage(GWEN_UNUSED AQH_OBJECT *o, uint32_t msgId)
dbArgs=AQH_ToolClient_GetDbLocalArgs(o);
valueName=GWEN_DB_GetCharValue(dbArgs, "valueName", 0, NULL);
num=GWEN_DB_GetIntValue(dbArgs, "numOfLastDatapoints", 0, 0);
tsBegin=_getTimeStampFromString(GWEN_DB_GetCharValue(dbArgs, "tsBegin", 0, NULL));
tsBegin=Utils_GetTimeStampFromString(GWEN_DB_GetCharValue(dbArgs, "tsBegin", 0, NULL));
if (tsBegin==(uint64_t) (-1)) {
DBG_ERROR(NULL, "Bad begin timestamp");
return NULL;
}
tsEnd=_getTimeStampFromString(GWEN_DB_GetCharValue(dbArgs, "tsEnd", 0, NULL));
tsEnd=Utils_GetTimeStampFromString(GWEN_DB_GetCharValue(dbArgs, "tsEnd", 0, NULL));
if (tsEnd==(uint64_t) (-1)) {
DBG_ERROR(NULL, "Bad end timestamp");
return NULL;
}
return AQH_IpcdMessageGetData_new(AQH_MSGTYPE_IPC_DATA_GETDATA_REQ, msgId, 0, valueName, tsBegin, tsEnd, num);
// TODO: use "mode" correctly
return AQH_IpcdMessageGetData_new(AQH_MSGTYPE_IPC_DATA_GETDATA_REQ,
msgId, 0,
AQH_MSGDATA_GETDATA_MODE_LAST,
valueName,
tsBegin, tsEnd, num);
}
@@ -178,45 +182,3 @@ void _handleDataResponse(const GWEN_TAG16_LIST *tagList, int printMean, int prin
uint64_t _getTimeStampFromString(const char *s)
{
if (s && *s) {
if (*s=='-') {
uint64_t x=0;
uint64_t now=time(NULL);
s++;
while(*s && isdigit(*s)) {
unsigned int i;
i=*(s++)-'0';
x*=10;
x+=i;
}
if (*s) {
switch(*s) {
case 0:
case 'm': x*=60; break;
case 'h': x*=(60*60); break;
case 'd': x*=(60*60*24); break;
default: break;
}
}
return (now-x);
}
else {
unsigned long int x;
if (1!=sscanf(s, "%lu", &x)) {
DBG_ERROR(NULL, "ERROR: Invalid timestamp");
return (uint64_t) (-1);
}
return (uint64_t) x;
}
}
return 0;
}

View File

@@ -0,0 +1,153 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2025 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 "./getfirstdata.h"
#include "../utils.h"
#include "aqhome/dataclient/client.h"
#include "aqhome/msg/ipc/m_ipc.h"
#include "aqhome/msg/ipc/m_ipc_result.h"
#include "aqhome/msg/ipc/data/m_ipcd.h"
#include "aqhome/msg/ipc/data/m_ipcd_getdata.h"
#include "aqhome/msg/ipc/data/m_ipcd_multidata.h"
#include "aqhome/dataclient/client.h"
#include <gwenhywfar/args.h>
#include <gwenhywfar/i18n.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/text.h>
#include <ctype.h>
/* ------------------------------------------------------------------------------------------------
* defs
* ------------------------------------------------------------------------------------------------
*/
#define I18S(msg) msg
#define I18N(msg) GWEN_I18N_Translate(PACKAGE, msg)
#define A_ARG GWEN_ARGS_FLAGS_HAS_ARGUMENT
#define A_END (GWEN_ARGS_FLAGS_HELP | GWEN_ARGS_FLAGS_LAST)
#define A_CHAR GWEN_ArgsType_Char
#define A_INT GWEN_ArgsType_Int
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static int _runCommand(AQH_DATACLIENT *dc);
/* ------------------------------------------------------------------------------------------------
* code
* ------------------------------------------------------------------------------------------------
*/
int AQH_Tool_GetFirstData(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv)
{
AQH_EVENT_LOOP *eventLoop;
AQH_DATACLIENT *dc;
int rv;
const GWEN_ARGS args[]= {
/* flags type name min max s long short_descr, long_descr */
{ A_ARG, A_CHAR, "brokerAddress", 0, 1, "t", "tcpaddress", I18S("TCP address to connect to [127.0.0.1]"), NULL},
{ A_ARG, A_INT, "brokerPort", 0, 1, "P", "tcpport", I18S("Specify the TCP port to listen on"), NULL},
{ A_ARG, A_INT, "timeout", 0, 1, "T", NULL, I18S("Specify timeout in seconds for response"), NULL},
{ A_ARG, A_CHAR, "brokerClientId", 0, 1, "c", "clientid", I18S("Specify CLIENTID"), NULL},
{ A_ARG, A_CHAR, "userId", 0, 1, "u", "userid", I18S("Specify user id"), NULL},
{ A_ARG, A_CHAR, "password", 0, 1, "p", "password", I18S("Specify service password"), NULL},
{ A_ARG, A_CHAR, "valueName", 1, 1, "N", "valuename", I18S("Value name (e.g. server/temp/system)"), NULL},
{ A_ARG, A_INT, "numOfDatapoints", 0, 1, "n", NULL, I18S("Get up to n datapoints"), NULL},
{ 0, A_INT, "printMean", 0, 1, "M", "mean", I18S("Print mean value of data received"), NULL},
{ 0, A_INT, "printDiff", 0, 1, "D", "diff", I18S("Print diff last-first value"), NULL},
{ A_END, A_INT, "help", 0, 0, "h", "help", I18S("Show this help screen"), NULL}
};
eventLoop=AQH_EventLoop_new();
dc=AQH_DataClient_new(eventLoop, AQH_IPC_PROTOCOL_DATA_ID, AQH_IPC_PROTOCOL_DATA_VERSION);
rv=AQH_DataClient_ReadLocalArgs(dc, dbGlobalArgs, args, argc, argv);
if (rv<0) {
DBG_ERROR(NULL, "here (%d)", rv);
AQH_DataClient_free(dc);
AQH_EventLoop_free(eventLoop);
return 2;
}
rv=AQH_DataClient_ConnectWithArgs(dc, 0);
if (rv<0) {
DBG_ERROR(NULL, "Error connecting (%d)", rv);
AQH_DataClient_free(dc);
AQH_EventLoop_free(eventLoop);
return 2;
}
rv=_runCommand(dc);
if (rv<0) {
DBG_ERROR(NULL, "Error running (%d)", rv);
AQH_DataClient_free(dc);
AQH_EventLoop_free(eventLoop);
return 2;
}
AQH_DataClient_free(dc);
AQH_EventLoop_free(eventLoop);
return 0;
}
int _runCommand(AQH_DATACLIENT *dc)
{
GWEN_DB_NODE *dbLocalArgs;
const char *valueName;
uint64_t num;
int printMean;
int printDiff;
dbLocalArgs=AQH_DataClient_GetDbLocalArgs(dc);
valueName=GWEN_DB_GetCharValue(dbLocalArgs, "valueName", 0, NULL);
num=GWEN_DB_GetIntValue(dbLocalArgs, "numOfDatapoints", 0, 1);
printMean=GWEN_DB_GetIntValue(dbLocalArgs, "printMean", 0, 0);
printDiff=GWEN_DB_GetIntValue(dbLocalArgs, "printDiff", 0, 0);
if (num>0) {
uint64_t *dataPoints;
uint64_t recvdNum;
dataPoints=malloc(num*sizeof(uint64_t)*2);
recvdNum=AQH_DataClient_GetFirstData(dc, valueName, dataPoints, num);
if (recvdNum>0) {
if (printMean)
Utils_PrintMeanData(dataPoints, recvdNum, NULL);
else if (printDiff)
Utils_PrintDiffData(dataPoints, recvdNum, NULL);
else
Utils_PrintDataPoints(dataPoints, recvdNum, NULL);
}
free(dataPoints);
}
return 0;
}

View File

@@ -0,0 +1,21 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2025 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_TOOL_GETFIRSTDATA_H
#define AQHOME_TOOL_GETFIRSTDATA_H
#include <gwenhywfar/db.h>
int AQH_Tool_GetFirstData(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv);
#endif

View File

@@ -0,0 +1,153 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2025 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 "./getlastdata.h"
#include "../utils.h"
#include "aqhome/dataclient/client.h"
#include "aqhome/msg/ipc/m_ipc.h"
#include "aqhome/msg/ipc/m_ipc_result.h"
#include "aqhome/msg/ipc/data/m_ipcd.h"
#include "aqhome/msg/ipc/data/m_ipcd_getdata.h"
#include "aqhome/msg/ipc/data/m_ipcd_multidata.h"
#include "aqhome/dataclient/client.h"
#include <gwenhywfar/args.h>
#include <gwenhywfar/i18n.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/text.h>
#include <ctype.h>
/* ------------------------------------------------------------------------------------------------
* defs
* ------------------------------------------------------------------------------------------------
*/
#define I18S(msg) msg
#define I18N(msg) GWEN_I18N_Translate(PACKAGE, msg)
#define A_ARG GWEN_ARGS_FLAGS_HAS_ARGUMENT
#define A_END (GWEN_ARGS_FLAGS_HELP | GWEN_ARGS_FLAGS_LAST)
#define A_CHAR GWEN_ArgsType_Char
#define A_INT GWEN_ArgsType_Int
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static int _runCommand(AQH_DATACLIENT *dc);
/* ------------------------------------------------------------------------------------------------
* code
* ------------------------------------------------------------------------------------------------
*/
int AQH_Tool_GetLastData(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv)
{
AQH_EVENT_LOOP *eventLoop;
AQH_DATACLIENT *dc;
int rv;
const GWEN_ARGS args[]= {
/* flags type name min max s long short_descr, long_descr */
{ A_ARG, A_CHAR, "brokerAddress", 0, 1, "t", "tcpaddress", I18S("TCP address to connect to [127.0.0.1]"), NULL},
{ A_ARG, A_INT, "brokerPort", 0, 1, "P", "tcpport", I18S("Specify the TCP port to listen on"), NULL},
{ A_ARG, A_INT, "timeout", 0, 1, "T", NULL, I18S("Specify timeout in seconds for response"), NULL},
{ A_ARG, A_CHAR, "brokerClientId", 0, 1, "c", "clientid", I18S("Specify CLIENTID"), NULL},
{ A_ARG, A_CHAR, "userId", 0, 1, "u", "userid", I18S("Specify user id"), NULL},
{ A_ARG, A_CHAR, "password", 0, 1, "p", "password", I18S("Specify service password"), NULL},
{ A_ARG, A_CHAR, "valueName", 1, 1, "N", "valuename", I18S("Value name (e.g. server/temp/system)"), NULL},
{ A_ARG, A_INT, "numOfDatapoints", 0, 1, "n", NULL, I18S("Get up to n datapoints"), NULL},
{ 0, A_INT, "printMean", 0, 1, "M", "mean", I18S("Print mean value of data received"), NULL},
{ 0, A_INT, "printDiff", 0, 1, "D", "diff", I18S("Print diff last-first value"), NULL},
{ A_END, A_INT, "help", 0, 0, "h", "help", I18S("Show this help screen"), NULL}
};
eventLoop=AQH_EventLoop_new();
dc=AQH_DataClient_new(eventLoop, AQH_IPC_PROTOCOL_DATA_ID, AQH_IPC_PROTOCOL_DATA_VERSION);
rv=AQH_DataClient_ReadLocalArgs(dc, dbGlobalArgs, args, argc, argv);
if (rv<0) {
DBG_ERROR(NULL, "here (%d)", rv);
AQH_DataClient_free(dc);
AQH_EventLoop_free(eventLoop);
return 2;
}
rv=AQH_DataClient_ConnectWithArgs(dc, 0);
if (rv<0) {
DBG_ERROR(NULL, "Error connecting (%d)", rv);
AQH_DataClient_free(dc);
AQH_EventLoop_free(eventLoop);
return 2;
}
rv=_runCommand(dc);
if (rv<0) {
DBG_ERROR(NULL, "Error running (%d)", rv);
AQH_DataClient_free(dc);
AQH_EventLoop_free(eventLoop);
return 2;
}
AQH_DataClient_free(dc);
AQH_EventLoop_free(eventLoop);
return 0;
}
int _runCommand(AQH_DATACLIENT *dc)
{
GWEN_DB_NODE *dbLocalArgs;
const char *valueName;
uint64_t num;
int printMean;
int printDiff;
dbLocalArgs=AQH_DataClient_GetDbLocalArgs(dc);
valueName=GWEN_DB_GetCharValue(dbLocalArgs, "valueName", 0, NULL);
num=GWEN_DB_GetIntValue(dbLocalArgs, "numOfDatapoints", 0, 1);
printMean=GWEN_DB_GetIntValue(dbLocalArgs, "printMean", 0, 0);
printDiff=GWEN_DB_GetIntValue(dbLocalArgs, "printDiff", 0, 0);
if (num>0) {
uint64_t *dataPoints;
uint64_t recvdNum;
dataPoints=malloc(num*sizeof(uint64_t)*2);
recvdNum=AQH_DataClient_GetLastData(dc, valueName, dataPoints, num);
if (recvdNum>0) {
if (printMean)
Utils_PrintMeanData(dataPoints, recvdNum, NULL);
else if (printDiff)
Utils_PrintDiffData(dataPoints, recvdNum, NULL);
else
Utils_PrintDataPoints(dataPoints, recvdNum, NULL);
}
free(dataPoints);
}
return 0;
}

View File

@@ -0,0 +1,21 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2025 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_TOOL_GETLASTDATA_H
#define AQHOME_TOOL_GETLASTDATA_H
#include <gwenhywfar/db.h>
int AQH_Tool_GetLastData(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv);
#endif

View File

@@ -0,0 +1,167 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2025 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 "./getperioddata.h"
#include "../utils.h"
#include "aqhome/dataclient/client.h"
#include "aqhome/msg/ipc/m_ipc.h"
#include "aqhome/msg/ipc/m_ipc_result.h"
#include "aqhome/msg/ipc/data/m_ipcd.h"
#include "aqhome/msg/ipc/data/m_ipcd_getdata.h"
#include "aqhome/msg/ipc/data/m_ipcd_multidata.h"
#include "aqhome/dataclient/client.h"
#include <gwenhywfar/args.h>
#include <gwenhywfar/i18n.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/text.h>
#include <ctype.h>
/* ------------------------------------------------------------------------------------------------
* defs
* ------------------------------------------------------------------------------------------------
*/
#define I18S(msg) msg
#define I18N(msg) GWEN_I18N_Translate(PACKAGE, msg)
#define A_ARG GWEN_ARGS_FLAGS_HAS_ARGUMENT
#define A_END (GWEN_ARGS_FLAGS_HELP | GWEN_ARGS_FLAGS_LAST)
#define A_CHAR GWEN_ArgsType_Char
#define A_INT GWEN_ArgsType_Int
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static int _runCommand(AQH_DATACLIENT *dc);
/* ------------------------------------------------------------------------------------------------
* code
* ------------------------------------------------------------------------------------------------
*/
int AQH_Tool_GetPeriodData(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv)
{
AQH_EVENT_LOOP *eventLoop;
AQH_DATACLIENT *dc;
int rv;
const GWEN_ARGS args[]= {
/* flags type name min max s long short_descr, long_descr */
{ A_ARG, A_CHAR, "brokerAddress", 0, 1, "t", "tcpaddress", I18S("TCP address to connect to [127.0.0.1]"), NULL},
{ A_ARG, A_INT, "brokerPort", 0, 1, "P", "tcpport", I18S("Specify the TCP port to listen on"), NULL},
{ A_ARG, A_INT, "timeout", 0, 1, "T", NULL, I18S("Specify timeout in seconds for response"), NULL},
{ A_ARG, A_CHAR, "brokerClientId", 0, 1, "c", "clientid", I18S("Specify CLIENTID"), NULL},
{ A_ARG, A_CHAR, "userId", 0, 1, "u", "userid", I18S("Specify user id"), NULL},
{ A_ARG, A_CHAR, "password", 0, 1, "p", "password", I18S("Specify service password"), NULL},
{ A_ARG, A_CHAR, "valueName", 1, 1, "N", "valuename", I18S("Value name (e.g. server/temp/system)"), NULL},
{ A_ARG, A_INT, "numOfDatapoints", 0, 1, "n", NULL, I18S("Get up to n datapoints"), NULL},
{ A_ARG, A_CHAR, "tsBegin", 0, 1, "tb", "tsbegin", I18S("Timestamp range begin"), NULL},
{ A_ARG, A_CHAR, "tsEnd", 0, 1, "te", "tsend", I18S("Timestamp range end"), NULL},
{ 0, A_INT, "printMean", 0, 1, "M", "mean", I18S("Print mean value of data received"), NULL},
{ 0, A_INT, "printDiff", 0, 1, "D", "diff", I18S("Print diff last-first value"), NULL},
{ A_END, A_INT, "help", 0, 0, "h", "help", I18S("Show this help screen"), NULL}
};
eventLoop=AQH_EventLoop_new();
dc=AQH_DataClient_new(eventLoop, AQH_IPC_PROTOCOL_DATA_ID, AQH_IPC_PROTOCOL_DATA_VERSION);
rv=AQH_DataClient_ReadLocalArgs(dc, dbGlobalArgs, args, argc, argv);
if (rv<0) {
DBG_ERROR(NULL, "here (%d)", rv);
AQH_DataClient_free(dc);
AQH_EventLoop_free(eventLoop);
return 2;
}
rv=AQH_DataClient_ConnectWithArgs(dc, 0);
if (rv<0) {
DBG_ERROR(NULL, "Error connecting (%d)", rv);
AQH_DataClient_free(dc);
AQH_EventLoop_free(eventLoop);
return 2;
}
rv=_runCommand(dc);
if (rv<0) {
DBG_ERROR(NULL, "Error running (%d)", rv);
AQH_DataClient_free(dc);
AQH_EventLoop_free(eventLoop);
return 2;
}
AQH_DataClient_free(dc);
AQH_EventLoop_free(eventLoop);
return 0;
}
int _runCommand(AQH_DATACLIENT *dc)
{
GWEN_DB_NODE *dbLocalArgs;
const char *valueName;
uint64_t num;
uint64_t tsBegin;
uint64_t tsEnd;
int printMean;
int printDiff;
dbLocalArgs=AQH_DataClient_GetDbLocalArgs(dc);
valueName=GWEN_DB_GetCharValue(dbLocalArgs, "valueName", 0, NULL);
num=GWEN_DB_GetIntValue(dbLocalArgs, "numOfDatapoints", 0, 1);
tsBegin=Utils_GetTimeStampFromString(GWEN_DB_GetCharValue(dbLocalArgs, "tsBegin", 0, NULL));
if (tsBegin==(uint64_t) (-1)) {
DBG_ERROR(NULL, "Bad begin timestamp");
return 1;
}
tsEnd=Utils_GetTimeStampFromString(GWEN_DB_GetCharValue(dbLocalArgs, "tsEnd", 0, NULL));
if (tsEnd==(uint64_t) (-1)) {
DBG_ERROR(NULL, "Bad end timestamp");
return 1;
}
printMean=GWEN_DB_GetIntValue(dbLocalArgs, "printMean", 0, 0);
printDiff=GWEN_DB_GetIntValue(dbLocalArgs, "printDiff", 0, 0);
if (num>0) {
uint64_t *dataPoints;
uint64_t recvdNum;
dataPoints=malloc(num*sizeof(uint64_t)*2);
recvdNum=AQH_DataClient_GetPeriodData(dc, valueName, dataPoints, num, tsBegin, tsEnd);
if (recvdNum>0) {
if (printMean)
Utils_PrintMeanData(dataPoints, recvdNum, NULL);
else if (printDiff)
Utils_PrintDiffData(dataPoints, recvdNum, NULL);
else
Utils_PrintDataPoints(dataPoints, recvdNum, NULL);
}
free(dataPoints);
}
return 0;
}

View File

@@ -0,0 +1,21 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2025 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_TOOL_GETPERIODDATA_H
#define AQHOME_TOOL_GETPERIODDATA_H
#include <gwenhywfar/db.h>
int AQH_Tool_GetPeriodData(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv);
#endif

View File

@@ -14,10 +14,12 @@
#include "../client.h"
#include "../utils.h"
#include "aqhome/aqhome.h"
#include "aqhome/msg/ipc/m_ipc.h"
#include "aqhome/msg/ipc/m_ipc_result.h"
#include "aqhome/msg/ipc/data/m_ipcd.h"
#include "aqhome/msg/ipc/data/m_ipcd_values.h"
#include "aqhome/msg/ipc/data/m_ipcd_getvalues.h"
#include <gwenhywfar/args.h>
#include <gwenhywfar/i18n.h>
@@ -67,6 +69,8 @@ int AQH_Tool_GetValues(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv)
{ A_ARG, A_INT, "timeout", 0, 1, "T", NULL, I18S("Specify timeout in seconds for response"), NULL},
{ A_ARG, A_CHAR, "brokerClientId", 0, 1, "c", "clientid", I18S("Specify CLIENTID"), NULL},
{ A_ARG, A_CHAR, "userId", 0, 1, "u", "userid", I18S("Specify user id"), NULL},
{ A_ARG, A_CHAR, "device", 0, 1, "d", "device", I18S("device name to match"), NULL},
{ A_ARG, A_CHAR, "modality", 0, 1, "m", NULL, I18S("Modality to match"), NULL},
{ A_ARG, A_CHAR, "password", 0, 1, "p", "password", I18S("Specify service password"), NULL},
{ 0, A_INT, "printHeader", 0, 1, "H", "printheader", I18S("Print header if given"), NULL},
{ A_END, A_INT, "help", 0, 0, "h", "help", I18S("Show this help screen"), NULL}
@@ -90,11 +94,23 @@ int AQH_Tool_GetValues(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv)
AQH_MESSAGE *_createRequestMessage(GWEN_UNUSED AQH_OBJECT *o, uint32_t msgId)
{
return AQH_IpcMessage_new(AQH_IPC_PROTOCOL_DATA_ID,
AQH_IPC_PROTOCOL_DATA_VERSION,
AQH_MSGTYPE_IPC_DATA_GETVALUES_REQ,
msgId, 0,
0, NULL);
GWEN_DB_NODE *dbArgs;
const char *deviceName;
const char *s;
int modality;
dbArgs=AQH_ToolClient_GetDbLocalArgs(o);
deviceName=GWEN_DB_GetCharValue(dbArgs, "device", 0, NULL);
s=GWEN_DB_GetCharValue(dbArgs, "modality", 0, NULL);
if (s && *s) {
modality=AQH_ValueModality_fromString(s);
if (modality==AQH_ValueModality_Unknown) {
}
}
else
modality=AQH_ValueModality_Unknown;
return AQH_IpcdMessageGetValues_new(AQH_MSGTYPE_IPC_DATA_GETVALUES_REQ, msgId, 0, deviceName, modality);
}

View File

@@ -1,6 +1,6 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
* AqHome (c) by 2025 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.
@@ -17,6 +17,9 @@
#include "./data/getdevices.h"
#include "./data/adddata.h"
#include "./data/getdatapoints.h"
#include "./data/getfirstdata.h"
#include "./data/getlastdata.h"
#include "./data/getperioddata.h"
#include "./data/setdata.h"
#include "./data/moddevice.h"
#include "./data/watch.h"
@@ -92,6 +95,9 @@ int main(int argc, char **argv)
GWEN_FE_DAH("adddata", AQH_Tool_AddDataPoint, I18N("Send a datapoint to the data server")),
GWEN_FE_DAH("addjsondata", AQH_Tool_AddDataPoint, I18N("(same as adddata)")),
GWEN_FE_DAH("getdata", AQH_Tool_GetDataPoints, I18N("Request list of datapoints for a value on the data server")),
GWEN_FE_DAH("getfirstdata", AQH_Tool_GetFirstData, I18N("Request first datapoints for a value on the data server")),
GWEN_FE_DAH("getlastdata", AQH_Tool_GetLastData, I18N("Request last datapoints for a value on the data server")),
GWEN_FE_DAH("getperioddata", AQH_Tool_GetPeriodData, I18N("Request datapoints from a date range for a value on the data server")),
GWEN_FE_DAH("setdata", AQH_Tool_SetData, I18N("Set data for a value on the data server (e.g. a switch or thermostat)")),
GWEN_FE_DAH("moddevice", AQH_Tool_ModDevice, I18N("Modify a device on the data server")),
GWEN_FE_DAH("watch", AQH_Tool_Watch, I18N("Watch and print changes of values on the data server")),

View File

@@ -19,6 +19,7 @@
#include "aqhome/msg/ipc/nodes/m_ipcn_setaccmsggrps.h"
#include "aqhome/ipc2/tcp_object.h"
#include "aqhome/ipc2/ipc_client.h"
#include "aqhome/dataclient/client.h"
#include <gwenhywfar/debug.h>
@@ -27,6 +28,7 @@
#include <time.h>
#include <unistd.h>
#include <ctype.h>
#define UTILS_IPC_ENDPOINT_DEFAULT_MSGSIZE 4096
@@ -361,4 +363,47 @@ void Utils_PrintValue(const AQH_VALUE *value, int printHeader)
uint64_t Utils_GetTimeStampFromString(const char *s)
{
if (s && *s) {
if (*s=='-') {
uint64_t x=0;
uint64_t now=time(NULL);
s++;
while(*s && isdigit(*s)) {
unsigned int i;
i=*(s++)-'0';
x*=10;
x+=i;
}
if (*s) {
switch(*s) {
case 0:
case 'm': x*=60; break;
case 'h': x*=(60*60); break;
case 'd': x*=(60*60*24); break;
default: break;
}
}
return (now-x);
}
else {
unsigned long int x;
if (1!=sscanf(s, "%lu", &x)) {
DBG_ERROR(NULL, "ERROR: Invalid timestamp");
return (uint64_t) (-1);
}
return (uint64_t) x;
}
}
return 0;
}

View File

@@ -41,6 +41,8 @@ void Utils_PrintValue(const AQH_VALUE *value, int printHeader);
AQH_DEVICE *Utils_DeviceFromArgs(GWEN_DB_NODE *dbArgs);
uint64_t Utils_GetTimeStampFromString(const char *s);
#endif

14
aqhome-cgi.sh Normal file
View File

@@ -0,0 +1,14 @@
#!/bin/bash
# AQHOME_LOGLEVEL=info LD_LIBRARY_PATH="../../aqhome/:$LD_LIBRARY_PATH" ./aqhomed -l aqhome.log -db aqhome.db -ma 127.0.0.1
# export AQHOME_LOGLEVEL=info
export LD_LIBRARY_PATH="0-build/aqhome/:$LD_LIBRARY_PATH"
# aqhomed -l /var/log/aqhome.log -db /var/cache/aqhome/nodes.db -ma 192.168.117.192 -mp 1883 -t 127.0.0.1 -W /var/cache/aqhome
# 0-build/apps/aqhomed/aqhomed -l aqhome.log -db aqhome.db -ma 192.168.117.192 -mp 1883 -t 127.0.0.1 -p aqhomed.pid
# 0-build/apps/aqhomed/aqhomed -l aqhome.log -db aqhome.db -p aqhomed.pid -W /tmp/aqhome/aqhomed -ma 192.168.117.192 -mp 1883 -t 127.0.0.1 --mqttclientid=AQHOMEMQTTLOGTEST1
0-build/apps/aqhome-cgi/aqhome-cgi
#0-build/apps/aqhome-nodes/aqhome-nodes -l aqhome-nodes.log -db aqhome-nodes.db -p aqhome-nodes.pid -t 127.0.0.1 -ba 127.0.0.1 "$@"

View File

@@ -69,6 +69,7 @@
hexfile
data
events2
dataclient
</subdirs>
@@ -79,6 +80,7 @@
aqhhexfile
aqhdata
aqhevents2
aqhdataclient
</useTargets>
<libraries>

View File

@@ -267,6 +267,8 @@ int AQH_ValueModality_fromString(const char *s)
return AQH_ValueModality_TVOC;
else if (strcasecmp(s, "stats")==0)
return AQH_ValueModality_Stats;
else if (strcasecmp(s, "light")==0)
return AQH_ValueModality_Light;
}
return AQH_ValueModality_Unknown;
}
@@ -285,6 +287,7 @@ const char *AQH_ValueModality_toString(int i)
case AQH_ValueModality_Co2: return "co2";
case AQH_ValueModality_TVOC: return "tvoc";
case AQH_ValueModality_Stats: return "stats";
case AQH_ValueModality_Light: return "light";
case AQH_ValueModality_Unknown:
default: return "unknown";
}

View File

@@ -45,7 +45,8 @@ enum {
AQH_ValueModality_Motion,
AQH_ValueModality_Co2,
AQH_ValueModality_TVOC,
AQH_ValueModality_Stats
AQH_ValueModality_Stats,
AQH_ValueModality_Light
};

View File

@@ -305,6 +305,17 @@ AQH_STORAGE_GETLASTDATAPOINT_FN AQH_Storage_SetGetLastDatapointFn(AQH_STORAGE *s
AQH_STORAGE_GETFIRSTNDATAPOINTS_FN AQH_Storage_SetGetFirstNDatapointsFn(AQH_STORAGE *sto, AQH_STORAGE_GETFIRSTNDATAPOINTS_FN fn)
{
AQH_STORAGE_GETFIRSTNDATAPOINTS_FN oldFn;
oldFn=sto->getFirstNDatapointsFn;
sto->getFirstNDatapointsFn=fn;
return oldFn;
}
AQH_STORAGE_GETLASTNDATAPOINTS_FN AQH_Storage_SetGetLastNDatapointsFn(AQH_STORAGE *sto, AQH_STORAGE_GETLASTNDATAPOINTS_FN fn)
{
AQH_STORAGE_GETLASTNDATAPOINTS_FN oldFn;
@@ -383,8 +394,8 @@ int AQH_Storage_AddDatapoint(AQH_STORAGE *sto, uint64_t valueId, uint64_t timest
}
uint64_t *AQH_Storage_GetDataPoints(AQH_STORAGE *sto, uint64_t valueId, uint64_t fromTime, uint64_t toTime, uint64_t maxArrayLen)
uint64_t *AQH_Storage_GetDataPoints(AQH_STORAGE *sto, uint64_t valueId, uint64_t fromTime, uint64_t toTime,
uint64_t maxDataPointsRequested)
{
AQH_DATAFILE *df;
uint64_t numEntries;
@@ -399,13 +410,9 @@ uint64_t *AQH_Storage_GetDataPoints(AQH_STORAGE *sto, uint64_t valueId, uint64_t
return NULL;
}
numEntries=AQH_DataFile_GetNumberOfEntries(df);
if (fromTime==0 && toTime==0)
arrayLen=(numEntries*2)+1;
else
arrayLen=(AQH_STORAGE_DATAPOINTS_STEPS*2)+1;
if (arrayLen>maxArrayLen+1)
arrayLen=maxArrayLen+1;
if (maxDataPointsRequested>numEntries)
maxDataPointsRequested=numEntries;
arrayLen=(maxDataPointsRequested*2)+1;
arrayPtr=(uint64_t*) malloc(arrayLen*sizeof(uint64_t));
if (arrayPtr==NULL) {
DBG_ERROR(AQH_LOGDOMAIN, "Not enough memory for %lu entries", (unsigned long int) arrayLen);
@@ -427,30 +434,11 @@ uint64_t *AQH_Storage_GetDataPoints(AQH_STORAGE *sto, uint64_t valueId, uint64_t
}
if ((fromTime==0 || ts>=fromTime) && (toTime==0 || ts<=toTime)) {
if ((arrayPos+1)>maxArrayLen) {
if ((arrayPos+1)>arrayLen) {
DBG_INFO(AQH_LOGDOMAIN, "Limit for number of returned entries reached");
break;
}
if (arrayPos+1>=arrayLen) {
uint64_t newArrayLen;
void *p;
newArrayLen=arrayLen+(AQH_STORAGE_DATAPOINTS_STEPS*2);
if (newArrayLen>maxArrayLen+1)
newArrayLen=maxArrayLen+1;
if (newArrayLen==arrayLen) {
DBG_INFO(AQH_LOGDOMAIN, "Limit for number of returned entries reached");
break;
}
p=realloc((void*) arrayPtr, newArrayLen*sizeof(uint64_t));
if (p==NULL) {
DBG_ERROR(AQH_LOGDOMAIN, "Not enough memory for %lu entries", (unsigned long int) arrayLen+AQH_STORAGE_DATAPOINTS_STEPS);
free(arrayPtr);
return NULL;
}
arrayPtr=(uint64_t*) p;
arrayLen=newArrayLen;
}
arrayPtr[arrayPos++]=ts;
arrayPtr[arrayPos++]=u.i;
}
@@ -468,6 +456,67 @@ uint64_t *AQH_Storage_GetDataPoints(AQH_STORAGE *sto, uint64_t valueId, uint64_t
uint64_t *AQH_Storage_GetFirstNDataPoints(AQH_STORAGE *sto, uint64_t valueId, uint64_t maxDataPointsRequested)
{
AQH_DATAFILE *df;
uint64_t numEntries;
uint64_t numOfDataEntries;
uint64_t arrayLen;
uint64_t arrayPos;
uint64_t *arrayPtr;
uint64_t firstRecord;
uint64_t i;
df=_getDataFileByValueId(sto, valueId);
if (df==NULL) {
DBG_ERROR(AQH_LOGDOMAIN, "No file for value id %lu", (unsigned long int) valueId);
return NULL;
}
numEntries=AQH_DataFile_GetNumberOfEntries(df);
numOfDataEntries=numEntries-1; /* first entry is reserved, don't count it here */
if (numOfDataEntries<1) {
DBG_INFO(AQH_LOGDOMAIN, "No data records for value id %lu", (unsigned long int) valueId);
return NULL;
}
firstRecord=1;
if (numOfDataEntries>maxDataPointsRequested) /* more entries in file than requested */
arrayLen=(maxDataPointsRequested*2)+1; /* +1 because the first array entry contains the number of entries */
else
arrayLen=(numOfDataEntries*2)+1;
arrayPtr=(uint64_t*) malloc(arrayLen*sizeof(uint64_t));
if (arrayPtr==NULL) {
DBG_ERROR(AQH_LOGDOMAIN, "Not enough memory for %lu entries", (unsigned long int) arrayLen);
return NULL;
}
arrayPos=1;
for (i=firstRecord; i<numEntries; i++) {
union {double f; uint64_t i;} u;
uint64_t ts;
int rv;
rv=AQH_DataFile_ReadRecord(df, i, &ts, &(u.f));
if (rv<0) {
DBG_ERROR(AQH_LOGDOMAIN, "here (%d)", rv);
free(arrayPtr);
return NULL;
}
if ((arrayPos+1)>=arrayLen) {
DBG_INFO(AQH_LOGDOMAIN, "Requested number of entries reached");
break;
}
arrayPtr[arrayPos++]=ts;
arrayPtr[arrayPos++]=u.i;
} /* for */
arrayPtr[0]=arrayPos-1;
return arrayPtr;
}
uint64_t *AQH_Storage_GetLastNDataPoints(AQH_STORAGE *sto, uint64_t valueId, uint64_t maxDataPointsRequested)
{
AQH_DATAFILE *df;

View File

@@ -53,6 +53,8 @@ typedef uint64_t *(*AQH_STORAGE_GETDATAPOINTS_FN)(AQH_STORAGE *sto, uint64_t val
uint64_t maxArrayLen);
typedef int (*AQH_STORAGE_GETFIRSTDATAPOINT_FN)(AQH_STORAGE *sto, uint64_t valueId, uint64_t *pTimestamp, double *pValue);
typedef int (*AQH_STORAGE_GETLASTDATAPOINT_FN)(AQH_STORAGE *sto, uint64_t valueId, uint64_t *pTimestamp, double *pValue);
typedef uint64_t *(*AQH_STORAGE_GETFIRSTNDATAPOINTS_FN)(AQH_STORAGE *sto, uint64_t valueId, uint64_t maxDataPointsRequested);
typedef uint64_t *(*AQH_STORAGE_GETLASTNDATAPOINTS_FN)(AQH_STORAGE *sto, uint64_t valueId, uint64_t maxDataPointsRequested);
@@ -96,6 +98,8 @@ AQHOME_API uint64_t *AQH_Storage_GetDataPoints(AQH_STORAGE *sto, uint64_t valueI
uint64_t maxArrayLen);
AQHOME_API int AQH_Storage_GetFirstDataPoint(AQH_STORAGE *sto, uint64_t valueId, uint64_t *pTimestamp, double *pValue);
AQHOME_API int AQH_Storage_GetLastDataPoint(AQH_STORAGE *sto, uint64_t valueId, uint64_t *pTimestamp, double *pValue);
AQHOME_API uint64_t *AQH_Storage_GetFirstNDataPoints(AQH_STORAGE *sto, uint64_t valueId, uint64_t maxDataPointsRequested);
AQHOME_API uint64_t *AQH_Storage_GetLastNDataPoints(AQH_STORAGE *sto, uint64_t valueId, uint64_t maxDataPointsRequested);
@@ -105,6 +109,8 @@ AQHOME_API AQH_STORAGE_ADDDATAPOINT_FN AQH_Storage_SetAddDatapointFn(AQH_STORAGE
AQHOME_API AQH_STORAGE_GETDATAPOINTS_FN AQH_Storage_SetGetDatapointsFn(AQH_STORAGE *sto, AQH_STORAGE_GETDATAPOINTS_FN fn);
AQHOME_API AQH_STORAGE_GETFIRSTDATAPOINT_FN AQH_Storage_SetGetFirstDatapointFn(AQH_STORAGE *sto, AQH_STORAGE_GETFIRSTDATAPOINT_FN fn);
AQHOME_API AQH_STORAGE_GETLASTDATAPOINT_FN AQH_Storage_SetGetLastDatapointFn(AQH_STORAGE *sto, AQH_STORAGE_GETLASTDATAPOINT_FN fn);
AQHOME_API AQH_STORAGE_GETFIRSTNDATAPOINTS_FN AQH_Storage_SetGetFirstNDatapointsFn(AQH_STORAGE *sto, AQH_STORAGE_GETFIRSTNDATAPOINTS_FN fn);
AQHOME_API AQH_STORAGE_GETLASTNDATAPOINTS_FN AQH_Storage_SetGetLastNDatapointsFn(AQH_STORAGE *sto, AQH_STORAGE_GETLASTNDATAPOINTS_FN fn);

View File

@@ -47,6 +47,7 @@ struct AQH_STORAGE {
AQH_STORAGE_GETFIRSTDATAPOINT_FN getFirstDatapointFn;
AQH_STORAGE_GETLASTDATAPOINT_FN getLastDatapointFn;
AQH_STORAGE_GETLASTNDATAPOINTS_FN getLastNDatapointsFn;
AQH_STORAGE_GETFIRSTNDATAPOINTS_FN getFirstNDatapointsFn;
};

81
aqhome/dataclient/0BUILD Normal file
View File

@@ -0,0 +1,81 @@
<?xml?>
<gwbuild>
<target type="ConvenienceLibrary" name="aqhdataclient" >
<includes type="c" >
$(gwenhywfar_cflags)
$(aqdatabase_cflags)
-I$(topsrcdir)
-I$(topbuilddir)
</includes>
<includes type="tm2" >
--include=$(builddir)
--include=$(srcdir)
--include=$(aqdatabase_AQDATABASE_TYPEMAKERDIR)/c
</includes>
<define name="BUILDING_AQHOME" />
<setVar name="local/cflags">$(visibility_cflags)</setVar>
<setVar name="tm2flags" >
--api=AQHOME_API
</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="false" install="$(pkgincludedir)/dataclient" >
$(local/built_headers_pub)
</headers>
<headers dist="true" install="$(pkgincludedir)/dataclient" >
client.h
</headers>
<headers dist="true" >
client_p.h
</headers>
<sources>
$(local/typefiles)
client.c
</sources>
<extradist>
</extradist>
<useTargets>
</useTargets>
<subdirs>
</subdirs>
</target>
</gwbuild>

555
aqhome/dataclient/client.c Normal file
View File

@@ -0,0 +1,555 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2025 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 "./client_p.h"
#include "aqhome/aqhome.h"
#include "aqhome/msg/ipc/m_ipc.h"
#include "aqhome/msg/ipc/m_ipc_tag16.h"
#include "aqhome/msg/ipc/m_ipc_result.h"
#include "aqhome/msg/ipc/data/m_ipcd.h"
#include "aqhome/msg/ipc/nodes/m_ipcn.h"
#include "aqhome/msg/ipc/m_ipc_connect.h"
#include "aqhome/msg/ipc/data/m_ipcd_devices.h"
#include "aqhome/msg/ipc/data/m_ipcd_values.h"
#include "aqhome/msg/ipc/data/m_ipcd_getvalues.h"
#include "aqhome/msg/ipc/data/m_ipcd_getdata.h"
#include "aqhome/msg/ipc/data/m_ipcd_multidata.h"
#include "aqhome/msg/ipc/data/m_ipcd_setdata.h"
#include "aqhome/ipc2/tcp_object.h"
#include "aqhome/ipc2/ipc_client.h"
#include <aqhome/ipc2/ipc_endpoint.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/timestamp.h>
#include <gwenhywfar/db.h>
#include <gwenhywfar/i18n.h>
#include <gwenhywfar/text.h>
#define AQH_DATA_CLIENT_DEFAULT_CMD_TIMEOUT 5
static int _connectEndpoint(AQH_DATACLIENT *dc, const char *addr, int port, uint32_t flags);
static int _exchangeConnectMsgs(AQH_DATACLIENT *dc, const char *userId, const char *passwd, const char *clientId, uint32_t flags);
static uint64_t _getFirstOrLastData(AQH_DATACLIENT *dc, const char *valueName, uint64_t *dataPtr, uint64_t maxNum, int mode);
static uint64_t _handleDataResponses(AQH_DATACLIENT *dc, uint64_t *dataPtr, uint64_t maxNum, uint32_t msgId);
static int _handleResult(AQH_DATACLIENT *dc, uint32_t msgId);
AQH_DATACLIENT *AQH_DataClient_new(AQH_EVENT_LOOP *eventLoop, uint8_t protoId, uint8_t protoVer)
{
AQH_DATACLIENT *dc;
GWEN_NEW_OBJECT(AQH_DATACLIENT, dc);
dc->eventLoop=eventLoop;
dc->protoId=protoId;
dc->protoVer=protoVer;
dc->timeoutInSeconds=AQH_DATA_CLIENT_DEFAULT_CMD_TIMEOUT;
return dc;
}
void AQH_DataClient_free(AQH_DATACLIENT *dc)
{
if (dc) {
AQH_Object_free(dc->ipcEndpoint);
GWEN_FREE_OBJECT(dc);
}
}
int AQH_DataClient_ReadLocalArgs(AQH_DATACLIENT *dc,
GWEN_DB_NODE *dbGlobalArgs, const GWEN_ARGS *args,
int argc, char **argv)
{
if (dc) {
int rv;
GWEN_DB_Group_free(dc->dbLocalArgs);
dc->dbLocalArgs=GWEN_DB_GetGroup(dbGlobalArgs, GWEN_DB_FLAGS_DEFAULT, "local");
rv=GWEN_Args_Check(argc, argv, 1, GWEN_ARGS_MODE_ALLOW_FREEPARAM, args, dc->dbLocalArgs);
if (rv==GWEN_ARGS_RESULT_ERROR) {
fprintf(stderr, "ERROR: Could not parse arguments\n");
return 1;
}
else if (rv==GWEN_ARGS_RESULT_HELP) {
GWEN_BUFFER *ubuf;
ubuf=GWEN_Buffer_new(0, 1024, 0, 1);
if (GWEN_Args_Usage(args, ubuf, GWEN_ArgsOutType_Txt)) {
fprintf(stderr, "ERROR: Could not create help string\n");
return 1;
}
fprintf(stderr, "%s\n", GWEN_Buffer_GetStart(ubuf));
GWEN_Buffer_free(ubuf);
return 1;
}
dc->timeoutInSeconds=GWEN_DB_GetIntValue(dc->dbLocalArgs, "timeout", 0, 5);
AQH_MergeConfigFileIntoConfig(dc->dbLocalArgs, "ConfigFile");
return 0;
}
return GWEN_ERROR_INVALID;
}
GWEN_DB_NODE *AQH_DataClient_GetDbLocalArgs(const AQH_DATACLIENT *dc)
{
return dc?dc->dbLocalArgs:NULL;
}
int AQH_DataClient_Connect(AQH_DATACLIENT *dc,
const char *addr, int port,
const char *userId, const char *passwd,
const char *clientId,
uint32_t flags)
{
if (dc) {
int rv;
AQH_Object_free(dc->ipcEndpoint);
dc->ipcEndpoint=NULL;
rv=_connectEndpoint(dc, addr, port, 0 /* connection flags */);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return rv;
}
rv=_exchangeConnectMsgs(dc, userId, passwd, clientId, flags);
if (rv<0) {
AQH_Object_free(dc->ipcEndpoint);
dc->ipcEndpoint=NULL;
DBG_INFO(NULL, "here (%d)", rv);
return rv;
}
return 0;
}
return GWEN_ERROR_INVALID;
}
int AQH_DataClient_Disconnect(AQH_DATACLIENT *dc)
{
if (dc) {
AQH_Object_free(dc->ipcEndpoint);
dc->ipcEndpoint=NULL;
return 0;
}
return GWEN_ERROR_INVALID;
}
void AQH_DataClient_SetTimeout(AQH_DATACLIENT *dc, int i)
{
if (dc) {
dc->timeoutInSeconds=i;
}
}
AQH_DEVICE_LIST *AQH_DataClient_GetDevices(AQH_DATACLIENT *dc)
{
if (dc) {
AQH_MESSAGE *msgOut;
AQH_MESSAGE *msgIn;
uint32_t msgId;
AQH_DEVICE_LIST *fullDeviceList;
fullDeviceList=AQH_Device_List_new();
msgId=++(dc->lastMsgId);
msgOut=AQH_IpcMessage_new(dc->protoId, dc->protoVer, AQH_MSGTYPE_IPC_DATA_GETDEVICES_REQ, msgId, 0, 0, NULL);
AQH_Endpoint_AddMsgOut(dc->ipcEndpoint, msgOut);
while( (msgIn=AQH_IpcEndpoint_WaitForResponseMsg(dc->ipcEndpoint, msgId, dc->timeoutInSeconds)) ) {
GWEN_TAG16_LIST *tagList;
tagList=AQH_IpcMessageTag16_ParsePayload(msgIn, 0);
if (tagList) {
uint16_t code;
code=AQH_IpcMessage_GetCode(msgIn);
if (code==AQH_MSGTYPE_IPC_DATA_GETDEVICES_RSP) {
AQH_DEVICE_LIST *deviceList;
deviceList=AQH_IpcdMessageDevices_ReadDeviceList(tagList);
if (deviceList) {
AQH_Device_List_AddList(fullDeviceList, deviceList);
AQH_Device_List_free(deviceList);
}
if (AQH_IpcdMessageDevices_GetFlags(tagList) & AQH_MSGDATA_DEVICES_FLAGS_LASTMSG) {
GWEN_Tag16_List_free(tagList);
AQH_Message_free(msgIn);
break;
}
}
else if (code==AQH_MSGTYPE_IPC_DATA_RESULT) {
DBG_ERROR(NULL, "Server Error: %d", AQH_IpcMessageResult_GetResult(tagList));
GWEN_Tag16_List_free(tagList);
AQH_Message_free(msgIn);
AQH_Device_List_free(fullDeviceList);
return NULL;
}
else {
DBG_INFO(NULL, "Ignoring message \"%d\"", code);
}
GWEN_Tag16_List_free(tagList);
}
AQH_Message_free(msgIn);
} /* while */
if (AQH_Device_List_GetCount(fullDeviceList)>0)
return fullDeviceList;
AQH_Device_List_free(fullDeviceList);
}
return NULL;
}
AQH_VALUE_LIST *AQH_DataClient_GetValues(AQH_DATACLIENT *dc, const char *deviceName, int modality)
{
if (dc) {
AQH_MESSAGE *msgOut;
AQH_MESSAGE *msgIn;
uint32_t msgId;
AQH_VALUE_LIST *fullValueList;
fullValueList=AQH_Value_List_new();
msgId=++(dc->lastMsgId);
msgOut=AQH_IpcdMessageGetValues_new(AQH_MSGTYPE_IPC_DATA_GETVALUES_REQ, msgId, 0, deviceName, modality);
AQH_Endpoint_AddMsgOut(dc->ipcEndpoint, msgOut);
while( (msgIn=AQH_IpcEndpoint_WaitForResponseMsg(dc->ipcEndpoint, msgId, dc->timeoutInSeconds)) ) {
GWEN_TAG16_LIST *tagList;
tagList=AQH_IpcMessageTag16_ParsePayload(msgIn, 0);
if (tagList) {
uint16_t code;
code=AQH_IpcMessage_GetCode(msgIn);
if (code==AQH_MSGTYPE_IPC_DATA_GETVALUES_RSP) {
AQH_VALUE_LIST *valueList;
valueList=AQH_IpcdMessageValues_ReadValueList(tagList);
if (valueList) {
AQH_Value_List_AddList(fullValueList, valueList);
AQH_Value_List_free(valueList);
}
if (AQH_IpcdMessageValues_GetFlags(tagList) & AQH_MSGDATA_VALUES_FLAGS_LASTMSG) {
GWEN_Tag16_List_free(tagList);
AQH_Message_free(msgIn);
break;
}
}
else if (code==AQH_MSGTYPE_IPC_DATA_RESULT) {
DBG_ERROR(NULL, "Server Error: %d", AQH_IpcMessageResult_GetResult(tagList));
GWEN_Tag16_List_free(tagList);
AQH_Message_free(msgIn);
AQH_Value_List_free(fullValueList);
return NULL;
}
else {
DBG_INFO(NULL, "Ignoring message \"%d\"", code);
}
GWEN_Tag16_List_free(tagList);
}
AQH_Message_free(msgIn);
} /* while */
if (AQH_Value_List_GetCount(fullValueList)>0)
return fullValueList;
AQH_Value_List_free(fullValueList);
}
return NULL;
}
uint64_t AQH_DataClient_GetFirstData(AQH_DATACLIENT *dc, const char *valueName, uint64_t *dataPtr, uint64_t maxNum)
{
return _getFirstOrLastData(dc, valueName, dataPtr, maxNum, AQH_MSGDATA_GETDATA_MODE_FIRST);
}
uint64_t AQH_DataClient_GetLastData(AQH_DATACLIENT *dc, const char *valueName, uint64_t *dataPtr, uint64_t maxNum)
{
return _getFirstOrLastData(dc, valueName, dataPtr, maxNum, AQH_MSGDATA_GETDATA_MODE_LAST);
}
uint64_t AQH_DataClient_GetPeriodData(AQH_DATACLIENT *dc, const char *valueName,
uint64_t *dataPtr, uint64_t maxNum,
uint64_t tsBegin, uint64_t tsEnd)
{
if (dc) {
AQH_MESSAGE *msgOut;
uint32_t msgId;
msgId=++(dc->lastMsgId);
msgOut=AQH_IpcdMessageGetData_new(AQH_MSGTYPE_IPC_DATA_GETDATA_REQ,
msgId, 0,
AQH_MSGDATA_GETDATA_MODE_PERIOD,
valueName, tsBegin, tsEnd, maxNum);
AQH_Endpoint_AddMsgOut(dc->ipcEndpoint, msgOut);
return _handleDataResponses(dc, dataPtr, maxNum, msgId);
}
return 0;
}
int AQH_DataClient_SetData(AQH_DATACLIENT *dc, const AQH_VALUE *v, const char *data)
{
if (dc) {
AQH_MESSAGE *msgOut;
uint32_t msgId;
msgId=++(dc->lastMsgId);
msgOut=AQH_IpcdMessageSetData_new(AQH_MSGTYPE_IPC_DATA_SETDATA, msgId, 0, v, data);
AQH_Endpoint_AddMsgOut(dc->ipcEndpoint, msgOut);
return _handleResult(dc, msgId);
}
return GWEN_ERROR_INVALID;
}
int AQH_DataClient_UpdateData(AQH_DATACLIENT *dc, const AQH_VALUE *v, uint64_t timeStamp, double dataPoint)
{
if (dc) {
AQH_MESSAGE *msgOut;
uint32_t msgId;
msgId=++(dc->lastMsgId);
msgOut=AQH_IpcdMessageMultiData_newForOne(AQH_MSGTYPE_IPC_DATA_UPDATEDATA, msgId, 0, v, timeStamp, dataPoint);
AQH_Endpoint_AddMsgOut(dc->ipcEndpoint, msgOut);
return _handleResult(dc, msgId);
}
return GWEN_ERROR_INVALID;
}
int _connectEndpoint(AQH_DATACLIENT *dc, const char *addr, int port, uint32_t flags)
{
if (dc) {
AQH_OBJECT *ep;
int fd;
fd=AQH_TcpObject_CreateConnectedSocket(addr, port);
if (fd<0) {
DBG_ERROR(NULL, "Error connecting to broker server %s:%d", addr, port);
return GWEN_ERROR_IO;
}
ep=AQH_IpcClientObject_new(dc->eventLoop, fd);
assert(ep);
AQH_Endpoint_AddFlags(ep, flags);
dc->ipcEndpoint=ep;
return 0;
}
return GWEN_ERROR_INVALID;
}
int _exchangeConnectMsgs(AQH_DATACLIENT *dc, const char *userId, const char *passwd, const char *clientId, uint32_t flags)
{
AQH_MESSAGE *msgOut;
uint32_t msgId;
DBG_INFO(NULL, "Sending connect message for proto=%d.%d", dc->protoId, dc->protoVer);
msgId=AQH_Endpoint_GetNextMessageId(dc->ipcEndpoint);
msgOut=AQH_IpcMessageConnect_new(dc->protoId, dc->protoVer,
AQH_MSGTYPE_IPC_CONNECT_REQ,
msgId, 0,
clientId, userId, passwd, flags);
AQH_Endpoint_AddMsgOut(dc->ipcEndpoint, msgOut);
return AQH_IpcEndpoint_WaitForResultMsg(dc->ipcEndpoint,
dc->protoId, dc->protoVer, AQH_MSGTYPE_IPC_RESULT,
msgId, dc->timeoutInSeconds);
}
uint64_t _getFirstOrLastData(AQH_DATACLIENT *dc, const char *valueName, uint64_t *dataPtr, uint64_t maxNum, int mode)
{
if (dc) {
AQH_MESSAGE *msgOut;
uint32_t msgId;
msgId=++(dc->lastMsgId);
msgOut=AQH_IpcdMessageGetData_new(AQH_MSGTYPE_IPC_DATA_GETDATA_REQ,
msgId, 0,
mode,
valueName, 0, 0, maxNum);
AQH_Endpoint_AddMsgOut(dc->ipcEndpoint, msgOut);
return _handleDataResponses(dc, dataPtr, maxNum, msgId);
}
return 0;
}
uint64_t _handleDataResponses(AQH_DATACLIENT *dc, uint64_t *dataPtr, uint64_t maxNum, uint32_t msgId)
{
AQH_MESSAGE *msgIn;
uint64_t fullNumberOfPoints=0;
while( (msgIn=AQH_IpcEndpoint_WaitForResponseMsg(dc->ipcEndpoint, msgId, dc->timeoutInSeconds)) ) {
GWEN_TAG16_LIST *tagList;
tagList=AQH_IpcMessageTag16_ParsePayload(msgIn, 0);
if (tagList) {
uint16_t code;
code=AQH_IpcMessage_GetCode(msgIn);
if (code==AQH_MSGTYPE_IPC_DATA_GETDATA_RSP) {
const uint64_t *recvDataPtr;
uint64_t recvNumberOfPoints;
AQH_IpcdMessageMultiData_ReadDatapoints(tagList, &recvDataPtr, &recvNumberOfPoints);
if (recvNumberOfPoints) {
uint64_t i;
for (i=0; i<recvNumberOfPoints; i++) {
if (fullNumberOfPoints<maxNum) {
dataPtr[fullNumberOfPoints*2]=recvDataPtr[i*2];
dataPtr[(fullNumberOfPoints*2)+1]=recvDataPtr[(i*2)+1];
fullNumberOfPoints++;
}
else {
DBG_ERROR(NULL, "Too many bytes received");
break;
}
}
}
GWEN_Tag16_List_free(tagList);
AQH_Message_free(msgIn);
break;
}
else if (code==AQH_MSGTYPE_IPC_DATA_RESULT) {
DBG_ERROR(NULL, "Server Error: %d", AQH_IpcMessageResult_GetResult(tagList));
GWEN_Tag16_List_free(tagList);
AQH_Message_free(msgIn);
return 0;
}
else {
DBG_INFO(NULL, "Ignoring message \"%d\"", code);
}
GWEN_Tag16_List_free(tagList);
}
AQH_Message_free(msgIn);
} /* while */
return fullNumberOfPoints;
}
int _handleResult(AQH_DATACLIENT *dc, uint32_t msgId)
{
AQH_MESSAGE *msgIn;
while( (msgIn=AQH_IpcEndpoint_WaitForResponseMsg(dc->ipcEndpoint, msgId, dc->timeoutInSeconds)) ) {
GWEN_TAG16_LIST *tagList;
tagList=AQH_IpcMessageTag16_ParsePayload(msgIn, 0);
if (tagList) {
uint16_t code;
code=AQH_IpcMessage_GetCode(msgIn);
if (code==AQH_MSGTYPE_IPC_DATA_RESULT) {
int result;
result=AQH_IpcMessageResult_GetResult(tagList);
DBG_INFO(NULL, "Server result: %d", result);
GWEN_Tag16_List_free(tagList);
AQH_Message_free(msgIn);
if (result!=AQH_MSGDATA_RESULT_SUCCESS) {
DBG_INFO(NULL, "here (%d)", result);
return GWEN_ERROR_GENERIC;
}
return 0;
}
else {
DBG_INFO(NULL, "Ignoring message \"%d\"", code);
}
GWEN_Tag16_List_free(tagList);
}
AQH_Message_free(msgIn);
} /* while */
return GWEN_ERROR_TIMEOUT;
}
int AQH_DataClient_ConnectWithArgs(AQH_DATACLIENT *dc, uint32_t flags)
{
const char *brokerAddress;
int brokerPort;
const char *userId;
const char *passwd;
const char *clientId;
int rv;
brokerAddress=GWEN_DB_GetCharValue(dc->dbLocalArgs, "brokerAddress", 0, NULL);
if (!(brokerAddress && *brokerAddress))
brokerAddress=GWEN_DB_GetCharValue(dc->dbLocalArgs, "ConfigFile/brokerAddress", 0, "127.0.0.1");
brokerPort=GWEN_DB_GetIntValue(dc->dbLocalArgs, "brokerPort", 0, -1);
if (brokerPort<0)
brokerPort=GWEN_DB_GetIntValue(dc->dbLocalArgs, "ConfigFile/brokerPort", 0, 45456);
userId=GWEN_DB_GetCharValue(dc->dbLocalArgs, "userId", 0, NULL);
passwd=GWEN_DB_GetCharValue(dc->dbLocalArgs, "password", 0, NULL);
clientId=GWEN_DB_GetCharValue(dc->dbLocalArgs, "brokerClientId", 0, NULL);
rv=AQH_DataClient_Connect(dc, brokerAddress, brokerPort, userId, passwd, clientId, flags);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return rv;
}
return 0;
}

View File

@@ -0,0 +1,57 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2025 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_DATA_CLIENT_H
#define AQHOME_DATA_CLIENT_H
#include <aqhome/api.h>
#include <aqhome/events2/object.h>
#include <aqhome/data/value.h>
#include <aqhome/data/device.h>
#include <gwenhywfar/args.h>
typedef struct AQH_DATACLIENT AQH_DATACLIENT;
AQHOME_API AQH_DATACLIENT *AQH_DataClient_new(AQH_EVENT_LOOP *eventLoop, uint8_t protoId, uint8_t protoVer);
AQHOME_API void AQH_DataClient_free(AQH_DATACLIENT *dc);
AQHOME_API void AQH_DataClient_SetTimeout(AQH_DATACLIENT *dc, int i);
AQHOME_API int AQH_DataClient_Connect(AQH_DATACLIENT *dc,
const char *addr, int port,
const char *userId, const char *passwd,
const char *clientId,
uint32_t flags);
AQHOME_API int AQH_DataClient_Disconnect(AQH_DATACLIENT *dc);
AQHOME_API AQH_DEVICE_LIST *AQH_DataClient_GetDevices(AQH_DATACLIENT *dc);
AQHOME_API AQH_VALUE_LIST *AQH_DataClient_GetValues(AQH_DATACLIENT *dc, const char *deviceName, int modality);
AQHOME_API uint64_t AQH_DataClient_GetFirstData(AQH_DATACLIENT *dc, const char *valueName, uint64_t *dataPtr, uint64_t maxNum);
AQHOME_API uint64_t AQH_DataClient_GetLastData(AQH_DATACLIENT *dc, const char *valueName, uint64_t *dataPtr, uint64_t maxNum);
AQHOME_API uint64_t AQH_DataClient_GetPeriodData(AQH_DATACLIENT *dc, const char *valueName,
uint64_t *dataPtr, uint64_t maxNum,
uint64_t tsBegin, uint64_t tsEnd);
AQHOME_API int AQH_DataClient_SetData(AQH_DATACLIENT *dc, const AQH_VALUE *v, const char *data);
AQHOME_API int AQH_DataClient_UpdateData(AQH_DATACLIENT *dc, const AQH_VALUE *v, uint64_t timeStamp, double dataPoint);
AQHOME_API int AQH_DataClient_ReadLocalArgs(AQH_DATACLIENT *dc,
GWEN_DB_NODE *dbGlobalArgs, const GWEN_ARGS *argDescrs,
int argc, char **argv);
AQHOME_API int AQH_DataClient_ConnectWithArgs(AQH_DATACLIENT *dc, uint32_t flags);
AQHOME_API GWEN_DB_NODE *AQH_DataClient_GetDbLocalArgs(const AQH_DATACLIENT *dc);
#endif

View File

@@ -0,0 +1,32 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2025 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_DATA_CLIENT_P_H
#define AQHOME_DATA_CLIENT_P_H
#include "aqhome/dataclient/client.h"
struct AQH_DATACLIENT {
AQH_EVENT_LOOP *eventLoop;
AQH_OBJECT *ipcEndpoint;
int timeoutInSeconds;
uint8_t protoId;
uint8_t protoVer;
uint32_t lastMsgId;
GWEN_DB_NODE *dbLocalArgs;
};
#endif

View File

@@ -14,6 +14,7 @@
#include <gwenhywfar/inherit.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/text.h>
//#include <sys/socket.h>
#include <errno.h>
@@ -170,6 +171,7 @@ int AQH_FdObject_Read(AQH_OBJECT *o, uint8_t *ptrBuffer, uint32_t lenBuffer)
else if (rv>0) {
/* data received */
DBG_DEBUG(AQH_LOGDOMAIN, "Received %d bytes", (int) rv);
// GWEN_Text_LogString((const char*) ptrBuffer, rv, NULL, GWEN_LoggerLevel_Error);
return (int) rv;
}
else {

View File

@@ -24,7 +24,7 @@
#define AQH_MSG_READER_HEADER_SIZE 4
#define AQH_MSG_READER_MINMSGSIZE 12
#define AQH_MSG_READER_MAXMSGSIZE 10240
#define AQH_MSG_READER_MAXMSGSIZE 20480

View File

@@ -51,6 +51,7 @@
m_ipcd_values.h
m_ipcd_getdata.h
m_ipcd_setdata.h
m_ipcd_getvalues.h
</headers>
@@ -67,6 +68,7 @@
m_ipcd_values.c
m_ipcd_getdata.c
m_ipcd_setdata.c
m_ipcd_getvalues.c
</sources>

View File

@@ -28,6 +28,8 @@
* ------------------------------------------------------------------------------------------------
*/
static const char *_modeToChar(int mode);
/* ------------------------------------------------------------------------------------------------
@@ -37,6 +39,7 @@
AQH_MESSAGE *AQH_IpcdMessageGetData_new(uint16_t code,
uint32_t msgId, uint32_t refMsgId,
int mode,
const char *valueName, uint64_t tsBegin, uint64_t tsEnd, uint64_t num)
{
AQH_MESSAGE *msg;
@@ -49,6 +52,7 @@ AQH_MESSAGE *AQH_IpcdMessageGetData_new(uint16_t code,
GWEN_Tag16_WriteUint64TagToBuffer(AQH_MSGDATA_GETDATA_TAGS_BEGIN, tsBegin, buf);
GWEN_Tag16_WriteUint64TagToBuffer(AQH_MSGDATA_GETDATA_TAGS_END, tsEnd, buf);
GWEN_Tag16_WriteUint64TagToBuffer(AQH_MSGDATA_GETDATA_TAGS_NUM, num, buf);
GWEN_Tag16_WriteUint64TagToBuffer(AQH_MSGDATA_GETDATA_TAGS_MODE, mode, buf);
msg=AQH_IpcMessage_new(AQH_IPC_PROTOCOL_DATA_ID, AQH_IPC_PROTOCOL_DATA_VERSION, code, msgId, refMsgId,
GWEN_Buffer_GetUsedBytes(buf), (const uint8_t*) GWEN_Buffer_GetStart(buf));
@@ -64,19 +68,22 @@ void AQH_IpcdMessageGetData_DumpToBuffer(const AQH_MESSAGE *msg, const GWEN_TAG1
char *valueName;
uint64_t tsBegin;
uint64_t tsEnd;
uint64_t mode;
valueName=tagList?AQH_Tag16_GetTagDataAsNewString(tagList, AQH_MSGDATA_GETDATA_TAGS_NAME, NULL):NULL;
tsBegin=tagList?AQH_Tag16_GetTagDataAsUint64(tagList, AQH_MSGDATA_GETDATA_TAGS_BEGIN, 0):0;
tsEnd=tagList?AQH_Tag16_GetTagDataAsUint64(tagList, AQH_MSGDATA_GETDATA_TAGS_END, 0):0;
mode=tagList?AQH_Tag16_GetTagDataAsUint64(tagList, AQH_MSGDATA_GETDATA_TAGS_MODE, 0):0;
GWEN_Buffer_AppendArgs(dbuf,
"GETDATA(%s) %s (code=%d, proto=%d, proto version=%d, name=%s, tsBegin=%lu, tsEnd=%lu)\n",
"GETDATA(%s) %s (code=%d, proto=%d, proto version=%d, name=%s, mode=%s, tsBegin=%lu, tsEnd=%lu)\n",
AQH_IpcdMessage_MsgTypeToChar(AQH_IpcMessage_GetCode(msg)),
sText?sText:"",
AQH_IpcMessage_GetCode(msg),
AQH_IpcMessage_GetProtoId(msg),
AQH_IpcMessage_GetProtoVersion(msg),
valueName?valueName:"<empty>",
valueName?valueName:"<empty>",
_modeToChar(mode),
(unsigned long int) tsBegin,
(unsigned long int) tsEnd);
free(valueName);
@@ -85,3 +92,15 @@ void AQH_IpcdMessageGetData_DumpToBuffer(const AQH_MESSAGE *msg, const GWEN_TAG1
const char *_modeToChar(int mode)
{
switch(mode) {
case AQH_MSGDATA_GETDATA_MODE_FIRST: return "first";
case AQH_MSGDATA_GETDATA_MODE_LAST: return "last";
case AQH_MSGDATA_GETDATA_MODE_PERIOD: return "period";
default: return "unknown";
}
}

View File

@@ -24,10 +24,20 @@
#define AQH_MSGDATA_GETDATA_TAGS_BEGIN 0x0020
#define AQH_MSGDATA_GETDATA_TAGS_END 0x0021
#define AQH_MSGDATA_GETDATA_TAGS_NUM 0x0022
#define AQH_MSGDATA_GETDATA_TAGS_MODE 0x0023
enum {
AQH_MSGDATA_GETDATA_MODE_FIRST=0,
AQH_MSGDATA_GETDATA_MODE_LAST,
AQH_MSGDATA_GETDATA_MODE_PERIOD
};
AQHOME_API AQH_MESSAGE *AQH_IpcdMessageGetData_new(uint16_t code,
uint32_t msgId, uint32_t refMsgId,
int mode,
const char *valueName, uint64_t tsBegin, uint64_t tsEnd, uint64_t num);
AQHOME_API void AQH_IpcdMessageGetData_DumpToBuffer(const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList,

View File

@@ -0,0 +1,81 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2025 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/msg/ipc/data/m_ipcd_getvalues.h"
#include "aqhome/msg/ipc/m_ipc_tag16.h"
#include "aqhome/msg/ipc/data/m_ipcd.h"
#include "aqhome/msg/ipc/m_ipc.h"
#include <gwenhywfar/text.h>
#include <gwenhywfar/tag16.h>
#include <gwenhywfar/buffer.h>
#include <gwenhywfar/debug.h>
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* implementation
* ------------------------------------------------------------------------------------------------
*/
AQH_MESSAGE *AQH_IpcdMessageGetValues_new(uint16_t code, uint32_t msgId, uint32_t refMsgId,
const char *deviceName, int modality)
{
AQH_MESSAGE *msg;
GWEN_BUFFER *buf;
buf=GWEN_Buffer_new(0, 256, 0, 1);
if (deviceName && *deviceName)
GWEN_Tag16_WriteStringTagToBuffer(AQH_MSGDATA_GETVALUES_TAGS_DEVICENAME, deviceName, buf);
GWEN_Tag16_WriteUint64TagToBuffer(AQH_MSGDATA_GETVALUES_TAGS_MODALITY, modality, buf);
msg=AQH_IpcMessage_new(AQH_IPC_PROTOCOL_DATA_ID, AQH_IPC_PROTOCOL_DATA_VERSION, code, msgId, refMsgId,
GWEN_Buffer_GetUsedBytes(buf), (const uint8_t*) GWEN_Buffer_GetStart(buf));
GWEN_Buffer_free(buf);
return msg;
}
void AQH_IpcdMessageGetValues_DumpToBuffer(const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList,
GWEN_BUFFER *dbuf, const char *sText)
{
char *deviceName;
uint64_t modality;
deviceName=tagList?AQH_Tag16_GetTagDataAsNewString(tagList, AQH_MSGDATA_GETVALUES_TAGS_DEVICENAME, NULL):NULL;
modality=tagList?AQH_Tag16_GetTagDataAsUint64(tagList, AQH_MSGDATA_GETVALUES_TAGS_MODALITY, 0):0;
GWEN_Buffer_AppendArgs(dbuf,
"GETVALUES(%s) %s (code=%d, proto=%d, proto version=%d, device=%s, modality=%s)\n",
AQH_IpcdMessage_MsgTypeToChar(AQH_IpcMessage_GetCode(msg)),
sText?sText:"",
AQH_IpcMessage_GetCode(msg),
AQH_IpcMessage_GetProtoId(msg),
AQH_IpcMessage_GetProtoVersion(msg),
deviceName?deviceName:"<empty>",
AQH_ValueModality_toString(modality));
free(deviceName);
}

View File

@@ -0,0 +1,36 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQH_M_IPCD_GETVALUES_H
#define AQH_M_IPCD_GETVALUES_H
#include <aqhome/api.h>
#include <aqhome/ipc2/message.h>
#include <aqhome/data/value.h>
#include <gwenhywfar/tag16.h>
#include <gwenhywfar/buffer.h>
#define AQH_MSGDATA_GETVALUES_TAGS_DEVICENAME 0x0001
#define AQH_MSGDATA_GETVALUES_TAGS_MODALITY 0x0002
AQHOME_API AQH_MESSAGE *AQH_IpcdMessageGetValues_new(uint16_t code, uint32_t msgId, uint32_t refMsgId,
const char *deviceName, int modality);
AQHOME_API void AQH_IpcdMessageGetValues_DumpToBuffer(const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList,
GWEN_BUFFER *dbuf, const char *sText);
#endif

View File

@@ -12,6 +12,7 @@
#include "aqhome/aqhome.h"
#include "aqhome/msg/node/m_value.h"
#include "aqhome/msg/node/m_node.h"
@@ -102,19 +103,7 @@ uint16_t AQH_ValueMessage_GetValueDenom(const AQH_MESSAGE *msg)
const char *AQH_ValueMessage_GetValueTypeName(const AQH_MESSAGE *msg)
{
uint8_t t;
t=AQH_ValueMessage_GetValueType(msg);
switch(t) {
case AQH_MSG_VALUE_TYPE_TEMP: return "temperature";
case AQH_MSG_VALUE_TYPE_HUMIDITY: return "humidity";
case AQH_MSG_VALUE_TYPE_DOOR: return "door_window";
case AQH_MSG_VALUE_TYPE_MOTION: return "motion";
case AQH_MSG_VALUE_TYPE_CO2: return "CO2";
case AQH_MSG_VALUE_TYPE_TVOC: return "TVOC";
default: break;
}
return "unknown";
return AQH_ValueModality_toString(AQH_ValueMessage_GetValueType(msg));
}

View File

@@ -100,6 +100,17 @@ AppNetwork_Every100ms_jump:
; ---------------------------------------------------------------------------
; @routine AppNetwork_Every100ms @global
;
; @clobbers R16, R17, X
AppNetwork_EveryDay:
bigjmp NET_Interface_ResetStats ; (R16, R17, X)
; @end
; ---------------------------------------------------------------------------
; @routine AppNetwork_HandleMsg @global
;
@@ -124,7 +135,7 @@ AppNetwork_HandleMsg_handleRangeMsg:
rjmp AppNetwork_HandleMsg_clcRet
AppNetwork_HandleMsg_handleAddrMsg:
rcall NETMSG_Address_Read ; R18=cmd, R19=addr(R18, R19)
bigcall NETMSG_Address_Read ; R18=cmd, R19=addr(R18, R19)
mov r16, r18
subi r16, NETMSG_CMD_NEED_ADDRESS
ldi zl, LOW(appNetworkMsgTable)
@@ -175,18 +186,18 @@ appNetworkHandlePingRequest:
adiw xh:xl, NETMSG_OFFS_SRCADDR
ld r17, X
push r17
rcall NET_Buffer_Alloc ; (R16, R17, X)
bigcall NET_Buffer_Alloc ; (R16, R17, X)
pop r17
brcc appNetworkHandlePingRequest_end ; jmp on error
push r16 ; buffer num
mov r16, r17 ; DEST addr
brcc appNetworkHandlePingRequest_end ; jmp on error
push r16 ; buffer num
mov r16, r17 ; DEST addr
adiw xh:xl, 1
ldi yl, LOW(netInterfaceData)
ldi yh, HIGH(netInterfaceData)
rcall NETMSG_Pong_Write ; (R16, R17, R18, R19, R20, X)
bigcall NETMSG_Pong_Write ; (R16, R17, R18, R19, R20, X)
sbiw xh:xl, 1
pop r16 ; buffer num
rcall NET_Interface_AddOrReleaseOutMsg ; (R16, R17, R18, X)
pop r16 ; buffer num
bigcall NET_Interface_AddOrReleaseOutMsg ; (R16, R17, R18, X)
appNetworkHandlePingRequest_end:
ret
@@ -393,16 +404,16 @@ appNetworkHandleMsgDenyAddr_end:
; @clobbers R16 (R17, R18, R19, R20, R21, X)
appNetworkSendAddrMsg:
rcall NET_Buffer_Alloc ; (R16, R17, X)
bigcall NET_Buffer_Alloc ; (R16, R17, X)
brcc appNetworkSendAddrMsg_end
adiw xh:xl, 1
push r16
rcall NETMSG_Address_Write ; (R16, R17, R18, R19, R20, R21)
bigcall NETMSG_Address_Write ; (R16, R17, R18, R19, R20, R21)
pop r16
sbiw xh:xl, 1
rcall NET_Interface_AddOutgoingMsgNum ; (R17, R18, X)
bigcall NET_Interface_AddOutgoingMsgNum ; (R17, R18, X)
brcs appNetworkSendAddrMsg_end
rcall NET_Buffer_ReleaseByNum ; (R16, X)
bigcall NET_Buffer_ReleaseByNum ; (R16, X)
clc
appNetworkSendAddrMsg_end:
ret

View File

@@ -18,14 +18,14 @@
; @clobbers R16, X (R17, R18, R19, R20, R21, Z)
AppNetwork_SendTxdStats:
rcall NET_Buffer_Alloc ; (R16, R17, X)
bigcall NET_Buffer_Alloc ; (R16, R17, X)
brcc AppNetwork_SendTxdStats_end
push r16
adiw xh:xl, 1
rcall NETMSG_SendStats_Write ; (R16, R17, R18, R19, R20, R21, Z)
bigcall NETMSG_SendStats_Write ; (R16, R17, R18, R19, R20, R21, Z)
sbiw xh:xl, 1
pop r16
rcall NET_Interface_AddOrReleaseOutMsg ; (R16, R17, R18, X)
bigcall NET_Interface_AddOrReleaseOutMsg ; (R16, R17, R18, X)
AppNetwork_SendTxdStats_end:
ret
; @end
@@ -39,14 +39,14 @@ AppNetwork_SendTxdStats_end:
; @clobbers R16, X (R17, R18, R19, R20, R21, Z)
AppNetwork_SendRxdStats:
rcall NET_Buffer_Alloc ; (R16, R17, X)
bigcall NET_Buffer_Alloc ; (R16, R17, X)
brcc AppNetwork_SendRxdStats_end
push r16
adiw xh:xl, 1
rcall NETMSG_RecvStats_Write ; (R16, R17, R18, R19, R20, R21, Z)
bigcall NETMSG_RecvStats_Write ; (R16, R17, R18, R19, R20, R21, Z)
sbiw xh:xl, 1
pop r16
rcall NET_Interface_AddOrReleaseOutMsg ; (R16, R17, R18, X)
bigcall NET_Interface_AddOrReleaseOutMsg ; (R16, R17, R18, X)
AppNetwork_SendRxdStats_end:
ret
; @end
@@ -60,14 +60,14 @@ AppNetwork_SendRxdStats_end:
; @clobbers R16, X (R17, R18, R19, R20, R21, Z)
AppNetwork_SendMemStats:
rcall NET_Buffer_Alloc ; (R16, R17, X)
bigcall NET_Buffer_Alloc ; (R16, R17, X)
brcc AppNetwork_SendMemStats_end
push r16
adiw xh:xl, 1
rcall NETMSG_MemStats_Write ; (R16, R17, R18, R19, R20, R21)
bigcall NETMSG_MemStats_Write ; (R16, R17, R18, R19, R20, R21)
sbiw xh:xl, 1
pop r16
rcall NET_Interface_AddOrReleaseOutMsg ; (R16, R17, R18, X)
bigcall NET_Interface_AddOrReleaseOutMsg ; (R16, R17, R18, X)
AppNetwork_SendMemStats_end:
ret
; @end
@@ -81,14 +81,14 @@ AppNetwork_SendMemStats_end:
; @clobbers R16, X (R17, R18, R19, R20, R21, Z)
AppNetwork_SendDevice:
rcall NET_Buffer_Alloc ; (R16, R17, X)
bigcall NET_Buffer_Alloc ; (R16, R17, X)
brcc AppNetwork_SendDevice_end
push r16
adiw xh:xl, 1
rcall NETMSG_Device_Write ; (R16, R17, R18, R19, R20, R21, Z)
bigcall NETMSG_Device_Write ; (R16, R17, R18, R19, R20, R21, Z)
sbiw xh:xl, 1
pop r16
rcall NET_Interface_AddOrReleaseOutMsg ; (R16, R17, R18, X)
bigcall NET_Interface_AddOrReleaseOutMsg ; (R16, R17, R18, X)
AppNetwork_SendDevice_end:
ret
; @end

View File

@@ -11,7 +11,7 @@
; ***************************************************************************
; defines
.equ APP_REPORT_SENSORS_INTERVAL_SECS = 60
.equ APP_REPORT_SENSORS_INTERVAL_SECS = 120
@@ -78,35 +78,45 @@ AppReportSensors_OnEverySecond_store:
#ifdef MODULES_SI7021
cpi r16, 1
breq AppReportSensors_OnEverySecond_measureValue1
cpi r16, 19
cpi r16, 11
breq AppReportSensors_OnEverySecond_measureValue2
cpi r16, 39
cpi r16, 16
breq AppReportSensors_OnEverySecond_sendValue1
cpi r16, 49
cpi r16, 21
breq AppReportSensors_OnEverySecond_sendValue2
#endif
#ifdef MODULES_SGP40
cpi r16, 27
cpi r16, 32
breq AppReportSensors_OnEverySecond_measureValue4
cpi r16, 55
cpi r16, 42
breq AppReportSensors_OnEverySecond_sendValue4
#endif
#ifdef MODULES_SGP30
cpi r16, 29
breq AppReportSensors_OnEverySecond_measureValue5
cpi r16, 57
cpi r16, 53
breq AppReportSensors_OnEverySecond_sendValue5
cpi r16, 59
cpi r16, 63
breq AppReportSensors_OnEverySecond_sendValue6
#endif
#ifdef MODULES_DS18B20
cpi r16, 9
cpi r16, 84
breq AppReportSensors_OnEverySecond_sendValue3
#endif
#ifdef MODULES_CCS811
cpi r16, 94
breq AppReportSensors_OnEverySecond_sendCCS811_TVOC
cpi r16, 104
breq AppReportSensors_OnEverySecond_sendCCS811_CO2
#endif
#ifdef MODULES_BRIGHTNESS
cpi r16, 97
breq AppReportSensors_OnEverySecond_sendBrightness
#endif
ret
#ifdef MODULES_SI7021
@@ -133,13 +143,23 @@ AppReportSensors_OnEverySecond_sendValue3:
#endif
#ifdef MODULES_SGP30
AppReportSensors_OnEverySecond_measureValue5:
rjmp SGP30_Measure
AppReportSensors_OnEverySecond_sendValue5:
rjmp SGP30_SendTVOC
ret
AppReportSensors_OnEverySecond_sendValue6:
rjmp SGP30_SendCO2
AppReportSensors_OnEverySecond_sendValue5:
rjmp SGP30_SendTVOC
ret
AppReportSensors_OnEverySecond_sendValue6:
rjmp SGP30_SendCO2
#endif
#ifdef MODULES_CCS811
AppReportSensors_OnEverySecond_sendCCS811_TVOC:
rjmp CCS811_SendTVOC
AppReportSensors_OnEverySecond_sendCCS811_CO2:
rjmp CCS811_SendCO2
#endif
#ifdef MODULES_BRIGHTNESS
AppReportSensors_OnEverySecond_sendBrightness:
rjmp Brightness_Send
#endif
; @end

View File

@@ -11,7 +11,7 @@
; ***************************************************************************
; defines
.equ APP_STATS_INTERVAL_MINS = 11
.equ APP_STATS_INTERVAL_MINS = 31
@@ -75,67 +75,94 @@ AppStats_OnEveryMinute_store:
sts appStatsTimer, r16
ldi yl, LOW(netInterfaceData)
ldi yh, HIGH(netInterfaceData)
ldi r17, AQHOME_VALUEID_STATS_PACKETS_IN
ldi xl, LOW(netInterfaceData)
ldi xh, HIGH(netInterfaceData)
cpi r16, 1
breq AppStats_OnEveryMinute_sendDevice
cpi r16, 2
breq AppStats_OnEveryMinute_sendPacketsIn
cpi r16, 3
breq AppStats_OnEveryMinute_sendPacketsOut
cpi r16, 4
breq AppStats_OnEveryMinute_sendContentErrs
breq AppStats_OnEveryMinute_sendPacketsIn
cpi r16, 5
breq AppStats_OnEveryMinute_sendIoErrs
breq AppStats_OnEveryMinute_sendPacketsOut
cpi r16, 6
breq AppStats_OnEveryMinute_sendNoBufErrs
breq AppStats_OnEveryMinute_sendDevice
cpi r16, 7
breq AppStats_OnEveryMinute_sendCollisionErrs
cpi r16, 8
breq AppStats_OnEveryMinute_sendBusyErrs
#ifdef MODULES_HEAP
breq AppStats_OnEveryMinute_sendContentErrs
cpi r16, 9
breq AppStats_OnEveryMinute_sendHeapUsed
breq AppStats_OnEveryMinute_sendIoErrs
cpi r16, 10
breq AppStats_OnEveryMinute_sendDevice
cpi r16, 11
breq AppStats_OnEveryMinute_sendNoBufErrs
cpi r16, 13
breq AppStats_OnEveryMinute_sendCollisionErrs
cpi r16, 14
breq AppStats_OnEveryMinute_sendDevice
cpi r16, 15
breq AppStats_OnEveryMinute_sendBusyErrs
#ifdef APP_STATS_NETDEV2
ldi r17, AQHOME_VALUEID_STATS_PACKETS_IN2
ldi xl, LOW(netInterfaceData2)
ldi xh, HIGH(netInterfaceData2)
cpi r16, 16
breq AppStats_OnEveryMinute_sendPacketsIn
cpi r16, 17
breq AppStats_OnEveryMinute_sendPacketsOut
cpi r16, 18
breq AppStats_OnEveryMinute_sendDevice
cpi r16, 19
breq AppStats_OnEveryMinute_sendContentErrs
cpi r16, 20
breq AppStats_OnEveryMinute_sendIoErrs
cpi r16, 21
breq AppStats_OnEveryMinute_sendDevice
cpi r16, 22
breq AppStats_OnEveryMinute_sendNoBufErrs
cpi r16, 23
breq AppStats_OnEveryMinute_sendDevice
cpi r16, 24
breq AppStats_OnEveryMinute_sendCollisionErrs
cpi r16, 25
breq AppStats_OnEveryMinute_sendBusyErrs
#endif
#ifdef MODULES_HEAP
cpi r16, 26
breq AppStats_OnEveryMinute_sendHeapUsed
cpi r16, 27
breq AppStats_OnEveryMinute_sendHeapfree
#endif
cpi r16, 28
breq AppStats_OnEveryMinute_sendDevice
ret
AppStats_OnEveryMinute_sendDevice:
rjmp AppNetwork_SendDevice
AppStats_OnEveryMinute_sendPacketsIn:
ldi r17, AQHOME_VALUEID_STATS_PACKETS_IN
ldd r18, Y+NET_IFACE_OFFS_PACKETSIN_LOW
ldd r19, Y+NET_IFACE_OFFS_PACKETSIN_HIGH
rjmp appStatsSend16BitValue
ldi r16, 0
rjmp appStatsSendDeviceStat
AppStats_OnEveryMinute_sendPacketsOut:
ldi r17, AQHOME_VALUEID_STATS_PACKETS_OUT
ldd r18, Y+NET_IFACE_OFFS_PACKETSOUT_LOW
ldd r19, Y+NET_IFACE_OFFS_PACKETSOUT_HIGH
rjmp appStatsSend16BitValue
ldi r16, 1
rjmp appStatsSendDeviceStat
AppStats_OnEveryMinute_sendContentErrs:
ldi r17, AQHOME_VALUEID_STATS_ERRS_CONTENT
ldd r18, Y+NET_IFACE_OFFS_ERR_CONTENT_LOW
ldd r19, Y+NET_IFACE_OFFS_ERR_CONTENT_HIGH
rjmp appStatsSend16BitValue
ldi r16, 2
rjmp appStatsSendDeviceStat
AppStats_OnEveryMinute_sendIoErrs:
ldi r17, AQHOME_VALUEID_STATS_ERRS_IO
ldd r18, Y+NET_IFACE_OFFS_ERR_IO_LOW
ldd r19, Y+NET_IFACE_OFFS_ERR_IO_HIGH
rjmp appStatsSend16BitValue
ldi r16, 3
rjmp appStatsSendDeviceStat
AppStats_OnEveryMinute_sendNoBufErrs:
ldi r17, AQHOME_VALUEID_STATS_ERRS_NOBUF
ldd r18, Y+NET_IFACE_OFFS_ERR_NOBUF_LOW
ldd r19, Y+NET_IFACE_OFFS_ERR_NOBUF_HIGH
rjmp appStatsSend16BitValue
ldi r16, 4
rjmp appStatsSendDeviceStat
AppStats_OnEveryMinute_sendCollisionErrs:
ldi r17, AQHOME_VALUEID_STATS_ERRS_COLLISIONS
ldd r18, Y+NET_IFACE_OFFS_ERR_COLLISIONS_LOW
ldd r19, Y+NET_IFACE_OFFS_ERR_COLLISIONS_HIGH
rjmp appStatsSend16BitValue
ldi r16, 5
rjmp appStatsSendDeviceStat
AppStats_OnEveryMinute_sendBusyErrs:
ldi r17, AQHOME_VALUEID_STATS_ERRS_BUSY
ldd r18, Y+NET_IFACE_OFFS_ERR_BUSY_LOW
ldd r19, Y+NET_IFACE_OFFS_ERR_BUSY_HIGH
rjmp appStatsSend16BitValue
ldi r16, 6
rjmp appStatsSendDeviceStat
#ifdef MODULES_HEAP
AppStats_OnEveryMinute_sendHeapUsed:
ldi r17, AQHOME_VALUEID_STATS_HEAP_USED
@@ -152,6 +179,30 @@ AppStats_OnEveryMinute_sendHeapfree:
; ---------------------------------------------------------------------------
; @routine AppStats_OnEveryMinute @global
;
; @param r16 index into device table (e.g. 0 for NET_IFACE_OFFS_PACKETSIN_LOW)
; @param r17 offset to first value id (e.g. AQHOME_VALUEID_STATS_PACKETS_IN for device 0,
; AQHOME_VALUEID_STATS_PACKETS_IN2 for device 1)
; @param Y pointer to device to send data to
; @param X pointer to device to inspect
appStatsSendDeviceStat:
add r17, r16
lsl r16
adiw xh:xl, NET_IFACE_OFFS_PACKETSIN_LOW
add xl, r16
adc xh, r16
sub xh, r16
ld r18, X+
ld r19, X
rjmp appStatsSend16BitValue
; @end
; ---------------------------------------------------------------------------
; @routine AppStats_OnEveryMinute @global
;

View File

@@ -27,7 +27,9 @@
wait_50us.asm
watchdog.asm
list.asm
list_t.asm
tree.asm
tree_t.asm
</extradist>
</gwbuild>

View File

@@ -54,11 +54,26 @@ List_InitObject:
; ---------------------------------------------------------------------------
; @routine List_FiniObject @global
;
; @param Y pointer to object
; @clobbers r16
List_FiniObject:
clr r16 ; set this->NEXT to NULL
std Y+LIST_OFFS_NEXT_LO, r16
std Y+LIST_OFFS_NEXT_HI, r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine List_GetNextObject @global
; @param Y pointer to object
; @return X pointer to parent object
; @return X pointer to successor object
; @clobbers none
List_GetNextObject:
@@ -101,13 +116,13 @@ List_GetPredecessorFor:
cp r16, yl
brne List_GetPredecessorFor_next
cp r17, yh
breq List_GetLastObject_haveIt
breq List_GetPredecessorFor_haveIt
List_GetPredecessorFor_next:
mov xl, r16
mov xh, r17
rjmp List_GetPredecessorFor
List_GetPredecessorFor_haveIt:
sbiw xh:xl, 1
sbiw xh:xl, 2
List_GetPredecessorFor_ret:
ret
; @end
@@ -127,8 +142,14 @@ List_AddObject:
rcall List_GetLastObject ; (r16, r17, X, Y)
pop yh
pop yl
st X+, yl ; WID_OFFS_WNEXT_LO
st X+, yh ; WID_OFFS_WNEXT_HI
mov r16, xl
or r16, xh
clc
breq List_AddObject_ret
st X+, yl ; LIST_OFFS_NEXT_LO
st X+, yh ; LIST_OFFS_NEXT_HI
sec
List_AddObject_ret:
ret
; @end
@@ -163,4 +184,68 @@ List_UnlinkObject_ret:
; ---------------------------------------------------------------------------
; @routine List_UnlinkAllObjects
; @param Y pointer to first object in a list
; @clobbers r16, r17, r18, Y
List_UnlinkAllObjects:
clr r18
List_UnlinkAllObjects_loop:
ldd r16, Y+LIST_OFFS_NEXT_LO
ldd r17, Y+LIST_OFFS_NEXT_HI
std Y+LIST_OFFS_NEXT_LO, r18
std Y+LIST_OFFS_NEXT_HI, r18
mov yl, r16
mov yh, r17
or r16, r17
brne List_UnlinkAllObjects_loop
ret
; @end
; ---------------------------------------------------------------------------
; @routine List_ForEveryObject
;
; Calls the given function for every object until it
; returns with a set carry flag or until the full list
; is handled.
; Registers that can be used by the given function are all
; except R16, R18 and R19 (those are used by this routine).
;
; @param Y pointer to first object in a list
; @param Z routine to call for every object
; @clobbers r16, r17, r18, r19, X, Y (r24, r25)
List_ForEveryObject:
List_ForEveryObject_loop:
ldd r18, Y+LIST_OFFS_NEXT_LO ; next
ldd r19, Y+LIST_OFFS_NEXT_HI ; next
clr r16
std Y+LIST_OFFS_NEXT_LO, r16
std Y+LIST_OFFS_NEXT_HI, r16
push r18 ; next
push r19 ; next
rcall List_ForEveryObject_callZ
pop r19 ; next
pop r18 ; next
brcs List_ForEveryObject_ret
mov yl, r18
mov yh, r19
or r18, r19
brne List_ForEveryObject_loop
List_ForEveryObject_ret:
ret
List_ForEveryObject_callZ:
ijmp
; @end
#endif ; AQH_AVR_COMMON_LIST_H

240
avr/common/list_t.asm Normal file
View File

@@ -0,0 +1,240 @@
; ***************************************************************************
; copyright : (C) 2025 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
#ifndef AQH_AVR_COMMON_LIST_T_H
#define AQH_AVR_COMMON_LIST_T_H
.equ LIST_TEST_OBJECT_OFFS_LIST = 0
.equ LIST_TEST_OBJECT_OFFS_VALUE1 = LIST_SIZE
.equ LIST_TEST_OBJECT_OFFS_VALUE2 = LIST_SIZE+1
.equ LIST_TEST_OBJECT_SIZE = LIST_SIZE+2
.dseg
listTest_list: .byte 2
listTest_object1: .byte LIST_TEST_OBJECT_SIZE
listTest_object2: .byte LIST_TEST_OBJECT_SIZE
listTest_object3: .byte LIST_TEST_OBJECT_SIZE
.cseg
; ---------------------------------------------------------------------------
; @routine listTest_Object_Init
; @param Y pointer to object to init
; @param r18 value 1
; @param r19 value 2
listTest_Object_Init:
bigcall List_InitObject ; (R16)
std Y+LIST_TEST_OBJECT_OFFS_VALUE1, r18
std Y+LIST_TEST_OBJECT_OFFS_VALUE2, r19
ret
; @end
listTest1:
ldi yl, LOW(listTest_object1)
ldi yh, HIGH(listTest_object1)
ldi r18, 1
ldi r19, 2
rcall listTest_Object_Init
sts listTest_list, yl
sts listTest_list+1, yh
mov xl, yl ; X=listTest_object1
mov xh, yh
ldi yl, LOW(listTest_object2)
ldi yh, HIGH(listTest_object2)
ldi r18, 3
ldi r19, 4
rcall listTest_Object_Init
; X=object 1, Y=object 2
bigcall List_AddObject ; (r16, r17, x)
lds yl, listTest_list
lds yh, listTest_list+1
ldd r16, Y+LIST_TEST_OBJECT_OFFS_VALUE1
cpi r16, 1
ldi r16, 1
brne listTest1_error
ldd r16, Y+LIST_TEST_OBJECT_OFFS_VALUE2
cpi r16, 2
ldi r16, 2
brne listTest1_error
bigcall List_GetNextObject
ldi r16, 3
cpi xl, LOW(listTest_object2)
brne listTest1_error
cpi xh, HIGH(listTest_object2)
brne listTest1_error
mov yl, xl
mov yh, xh
ldd r16, Y+LIST_TEST_OBJECT_OFFS_VALUE1
cpi r16, 3
ldi r16, 4
brne listTest1_error
ldd r16, Y+LIST_TEST_OBJECT_OFFS_VALUE2
cpi r16, 4
ldi r16, 5
brne listTest1_error
bigcall List_GetNextObject
mov r16, xh
or r16, xl
ldi r16, 6
brne listTest1_error
sec
ret
listTest1_error:
clc
ret
; @end
listTest2:
lds xl, listTest_list
lds xh, listTest_list+1
ldi yl, LOW(listTest_object3)
ldi yh, HIGH(listTest_object3)
ldi r18, 5
ldi r19, 6
rcall listTest_Object_Init
; X=object 1, Y=object 2
bigcall List_AddObject ; (r16, r17, x)
mov xl, yl
mov xh, yh
bigcall List_GetLastObject
ldi r16, 1
cpi xl, LOW(listTest_object3)
brne listTest2_error
cpi xh, HIGH(listTest_object3)
brne listTest2_error
mov yl, xl
mov yh, xh
ldd r16, Y+LIST_TEST_OBJECT_OFFS_VALUE1
cpi r16, 5
ldi r16, 2
brne listTest2_error
ldd r16, Y+LIST_TEST_OBJECT_OFFS_VALUE2
cpi r16, 6
ldi r16, 3
brne listTest2_error
sec
ret
listTest2_error:
clc
ret
; @end
listTest3:
lds xl, listTest_list
lds xh, listTest_list+1
ldi yl, LOW(listTest_object2)
ldi yh, HIGH(listTest_object2)
bigcall List_UnlinkObject
lds yl, listTest_list
lds yh, listTest_list+1
ldd r16, Y+LIST_TEST_OBJECT_OFFS_VALUE1
cpi r16, 1
ldi r16, 1
brne listTest3_error
ldd r16, Y+LIST_TEST_OBJECT_OFFS_VALUE2
cpi r16, 2
ldi r16, 2
brne listTest3_error
bigcall List_GetNextObject
ldi r16, 3
cpi xl, LOW(listTest_object3)
brne listTest3_error
cpi xh, HIGH(listTest_object3)
brne listTest3_error
mov yl, xl
mov yh, xh
ldd r16, Y+LIST_TEST_OBJECT_OFFS_VALUE1
cpi r16, 5
ldi r16, 4
brne listTest3_error
ldd r16, Y+LIST_TEST_OBJECT_OFFS_VALUE2
cpi r16, 6
ldi r16, 5
brne listTest3_error
bigcall List_GetNextObject
mov r16, xh
or r16, xl
ldi r16, 6
brne listTest3_error
sec
ret
listTest3_error:
clc
ret
; @end
listTest4:
lds xl, listTest_list
lds xh, listTest_list+1
ldi yl, LOW(listTest_object3)
ldi yh, HIGH(listTest_object3)
bigcall List_UnlinkObject
lds yl, listTest_list
lds yh, listTest_list+1
ldd r16, Y+LIST_TEST_OBJECT_OFFS_VALUE1
cpi r16, 1
ldi r16, 1
brne listTest4_error
ldd r16, Y+LIST_TEST_OBJECT_OFFS_VALUE2
cpi r16, 2
ldi r16, 2
brne listTest4_error
bigcall List_GetNextObject
mov r16, xh
or r16, xl
ldi r16, 6
brne listTest4_error
sec
ret
listTest4_error:
clc
ret
; @end
#endif

View File

@@ -17,10 +17,10 @@
; defs
.equ TREE_OFFS_LIST = 0
.equ TREE_OFFS_WPARENT_LO = TREE_OFFS_LIST+LIST_SIZE
.equ TREE_OFFS_WPARENT_HI = TREE_OFFS_LIST+LIST_SIZE+1
.equ TREE_OFFS_WCHILD_LO = TREE_OFFS_LIST+LIST_SIZE+2
.equ TREE_OFFS_WCHILD_HI = TREE_OFFS_LIST+LIST_SIZE+3
.equ TREE_OFFS_PARENT_LO = TREE_OFFS_LIST+LIST_SIZE
.equ TREE_OFFS_PARENT_HI = TREE_OFFS_LIST+LIST_SIZE+1
.equ TREE_OFFS_CHILD_LO = TREE_OFFS_LIST+LIST_SIZE+2
.equ TREE_OFFS_CHILD_HI = TREE_OFFS_LIST+LIST_SIZE+3
.equ TREE_SIZE = TREE_OFFS_LIST+LIST_SIZE+4
@@ -42,10 +42,10 @@
Tree_InitObject:
rcall List_InitObject ; (R16)
clr r16 ; clear this->TREE data
std Y+TREE_OFFS_LIST+TREE_OFFS_WPARENT_LO, r16
std Y+TREE_OFFS_LIST+TREE_OFFS_WPARENT_HI, r16
std Y+TREE_OFFS_LIST+TREE_OFFS_WCHILD_LO, r16
std Y+TREE_OFFS_LIST+TREE_OFFS_WCHILD_HI, r16
std Y+TREE_OFFS_LIST+TREE_OFFS_PARENT_LO, r16
std Y+TREE_OFFS_LIST+TREE_OFFS_PARENT_HI, r16
std Y+TREE_OFFS_LIST+TREE_OFFS_CHILD_LO, r16
std Y+TREE_OFFS_LIST+TREE_OFFS_CHILD_HI, r16
ret
; @end
@@ -59,8 +59,8 @@ Tree_InitObject:
; @clobbers none
Tree_GetParentObject:
ldd xl, Y+TREE_OFFS_WPARENT_LO
ldd xh, Y+TREE_OFFS_WPARENT_HI
ldd xl, Y+TREE_OFFS_PARENT_LO
ldd xh, Y+TREE_OFFS_PARENT_HI
ret
; @end
@@ -74,13 +74,46 @@ Tree_GetParentObject:
; @clobbers none
Tree_GetFirstChildObject:
ldd xl, Y+TREE_OFFS_WCHILD_LO
ldd xh, Y+TREE_OFFS_WCHILD_HI
ldd xl, Y+TREE_OFFS_CHILD_LO
ldd xh, Y+TREE_OFFS_CHILD_HI
ret
; @end
; ---------------------------------------------------------------------------
; @routine Tree_GetLastChildObject @global
; @param Y pointer to object
; @return X pointer to last child object
; @clobbers none
Tree_GetLastChildObject:
ldd xl, Y+TREE_OFFS_CHILD_LO
ldd xh, Y+TREE_OFFS_CHILD_HI
mov r16, xl
or r16, xh
breq Tree_GetLastChildObject_ret
rcall List_GetLastObject
Tree_GetLastChildObject_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine Tree_GetNextSibling @global
; @param Y pointer to object
; @return X pointer to successor object
; @clobbers none
Tree_GetNextSibling:
rjmp List_GetNextObject
; @end
; ---------------------------------------------------------------------------
; @routine Tree_GetObjectBelow @global
@@ -101,7 +134,7 @@ treeGetObjectBelow:
mov r16, xl
or r16, xh
brne treeGetObjectBelow_ret ; got one
rcall List_GetNextObject
rcall Tree_GetNextSibling
mov r16, xl
or r16, xh
brne treeGetObjectBelow_ret ; got one
@@ -122,27 +155,27 @@ treeGetObjectBelow_ret:
; ---------------------------------------------------------------------------
; @routine Tree_AddChildObject @global
; @param X pointer to parent to add to
; @param Y pointer to object to add
; @param X pointer to parent to add to
; @clobbers r16, r17, r18, x
Tree_AddChildObject:
std Y+TREE_OFFS_WPARENT_LO, xl ; immediately store parent pointer
std Y+TREE_OFFS_WPARENT_HI, xh
adiw xh:xl, TREE_OFFS_WCHILD_LO
std Y+TREE_OFFS_PARENT_LO, xl ; immediately store parent pointer
std Y+TREE_OFFS_PARENT_HI, xh
adiw xh:xl, TREE_OFFS_CHILD_LO ; read pointer to first child
ld r16, X+
ld r17, X
mov r18, r16
or r18, r17
brne Tree_AddChildObject_addToChildList
st X, yh ; no child, set THIS as first
st X, yh ; no child, set THIS as first
st -X, yl
sbiw xh:xl, WID_OFFS_TREE+TREE_OFFS_WCHILD_LO
sbiw xh:xl, TREE_OFFS_CHILD_LO
ret
Tree_AddChildObject_addToChildList:
mov xl, r16
mov xl, r16 ; X=first child
mov xh, r17
rjmp List_AddObject
rjmp List_AddObject ; add Y as new object
; @end
@@ -154,17 +187,17 @@ Tree_AddChildObject_addToChildList:
; @clobbers r16, r17, x
Tree_UnlinkObject:
ldd xl, Y+TREE_OFFS_WPARENT_LO
ldd xh, Y+TREE_OFFS_WPARENT_HI
ldd xl, Y+TREE_OFFS_PARENT_LO
ldd xh, Y+TREE_OFFS_PARENT_HI
mov r16, xl
or r16, xh
breq Tree_UnlinkObject_ret ; not part of a tree
adiw xh:xl, TREE_OFFS_WCHILD_LO ; get parent's first child to R17:R16
adiw xh:xl, TREE_OFFS_CHILD_LO ; get parent's first child to R17:R16
ld r16, X+
ld r17, X
cp r16, yl ; same as THIS?
brne Tree_UnlinkObject_inList ; nope, need to check childList
cp r17, yh
cp r17, yh ; same as THIS?
brne Tree_UnlinkObject_inList ; nope, need to check childList
ldd r16, Y+TREE_OFFS_LIST+LIST_OFFS_NEXT_HI ; is first child, set this->NEXT as new first child
st X, r16
@@ -177,8 +210,8 @@ Tree_UnlinkObject_inList:
rcall List_UnlinkObject ; (R16, R17, X)
Tree_UnlinkObject_clrParentAndSibling:
clr r16 ; clear this->PARENT
std Y+TREE_OFFS_LIST+TREE_OFFS_WPARENT_LO, r16
std Y+TREE_OFFS_LIST+TREE_OFFS_WPARENT_HI, r16
std Y+TREE_OFFS_PARENT_LO, r16
std Y+TREE_OFFS_PARENT_HI, r16
std Y+LIST_OFFS_NEXT_LO, r16
std Y+LIST_OFFS_NEXT_HI, r16 ; clear this->NEXT
Tree_UnlinkObject_ret:
@@ -188,5 +221,6 @@ Tree_UnlinkObject_ret:
#endif ; AQH_AVR_COMMON_TREE_H

381
avr/common/tree_t.asm Normal file
View File

@@ -0,0 +1,381 @@
; ***************************************************************************
; copyright : (C) 2025 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
.equ TREE_TEST_OBJECT_OFFS_LIST = 0
.equ TREE_TEST_OBJECT_OFFS_VALUE1 = TREE_SIZE
.equ TREE_TEST_OBJECT_OFFS_VALUE2 = TREE_SIZE+1
.equ TREE_TEST_OBJECT_SIZE = TREE_SIZE+2
.dseg
testTree_root: .byte TREE_TEST_OBJECT_SIZE
testTree_child1: .byte TREE_TEST_OBJECT_SIZE
testTree_child2: .byte TREE_TEST_OBJECT_SIZE
testTree_child3: .byte TREE_TEST_OBJECT_SIZE
.cseg
; ---------------------------------------------------------------------------
; @routine treeTest_Object_Init
; @param Y pointer to object to init
; @param r18 value 1
; @param r19 value 2
treeTest_Object_Init:
bigcall Tree_InitObject ; (R16)
std Y+TREE_TEST_OBJECT_OFFS_VALUE1, r18
std Y+TREE_TEST_OBJECT_OFFS_VALUE2, r19
ret
; @end
treeTest1:
ldi yl, LOW(testTree_root)
ldi yh, HIGH(testTree_root)
ldi r18, 1
ldi r19, 2
rcall treeTest_Object_Init
mov xl, yl
mov xh, yh
rcall treeTestCreateAndAddChild1
ldi r16, 1 ; error code
brcc treeTest1_error
rcall treeTestCreateAndAddChild2
ldi r16, 2 ; error code
brcc treeTest1_error
rcall treeTestCreateAndAddChild3
ldi r16, 3 ; error code
brcc treeTest1_error
ldi yl, LOW(testTree_root)
ldi yh, HIGH(testTree_root)
bigcall Tree_GetFirstChildObject
ldi r16, 4 ; error code
cpi xl, LOW(testTree_child1)
brne treeTest1_error
cpi xh, HIGH(testTree_child1)
brne treeTest1_error
mov yl, xl
mov yh, xh
ldd r16, Y+TREE_TEST_OBJECT_OFFS_VALUE1
cpi r16, 3
ldi r16, 5 ; error code
brne treeTest1_error
ldd r16, Y+TREE_TEST_OBJECT_OFFS_VALUE2
cpi r16, 4
ldi r16, 6 ; error code
brne treeTest1_error
rcall treeTestNextSiblingIs2
ldi r16, 7 ; error code
brcc treeTest1_error
rcall treeTestNextSiblingIs3
ldi r16, 8 ; error code
brcc treeTest1_error
rcall treeTestNextSiblingIsNull
ldi r16, 9 ; error code
brcc treeTest1_error
sec
ret
treeTest1_error:
clc
ret
; @end
treeTest2:
ldi yl, LOW(testTree_child2)
ldi yh, HIGH(testTree_child2)
bigcall Tree_UnlinkObject
rcall treeTestCheckParentNull
ldi r16, 1 ; error code
brcc treeTest2_error
bigcall Tree_GetNextSibling
mov r16, xl
or r16, xh
ldi r16, 2 ; error code
brne treeTest2_error
ldi yl, LOW(testTree_root)
ldi yh, HIGH(testTree_root)
bigcall Tree_GetFirstChildObject
ldi r16, 3 ; error code
cpi xl, LOW(testTree_child1)
brne treeTest2_error
cpi xh, HIGH(testTree_child1)
brne treeTest2_error
mov yl, xl
mov yh, xh
rcall treeTestNextSiblingIs3
ldi r16, 4 ; error code
brcc treeTest2_error
sec
ret
treeTest2_error:
clc
ret
; @end
treeTest3:
ldi yl, LOW(testTree_child1)
ldi yh, HIGH(testTree_child1)
bigcall Tree_UnlinkObject
rcall treeTestCheckParentNull
ldi r16, 1 ; error code
brcc treeTest3_error
bigcall Tree_GetNextSibling
mov r16, xl
or r16, xh
ldi r16, 2 ; error code
brne treeTest3_error
ldi yl, LOW(testTree_root)
ldi yh, HIGH(testTree_root)
bigcall Tree_GetFirstChildObject
ldi r16, 3 ; error code
cpi xl, LOW(testTree_child3)
brne treeTest3_error
cpi xh, HIGH(testTree_child3)
brne treeTest3_error
mov yl, xl
mov yh, xh
rcall treeTestNextSiblingIsNull
ldi r16, 4 ; error code
brcc treeTest3_error
sec
ret
treeTest3_error:
clc
ret
; @end
treeTest4:
ldi yl, LOW(testTree_child1)
ldi yh, HIGH(testTree_child1)
ldi xl, LOW(testTree_root)
ldi xh, HIGH(testTree_root)
bigcall Tree_AddChildObject
rcall treeTestCheckParentRoot
ldi r16, 1 ; error code
brcc treeTest4_error
ldi yl, LOW(testTree_root)
ldi yh, HIGH(testTree_root)
bigcall Tree_GetFirstChildObject
ldi r16, 2 ; error code
cpi xl, LOW(testTree_child3)
brne treeTest4_error
cpi xh, HIGH(testTree_child3)
brne treeTest4_error
mov yl, xl
mov yh, xh
rcall treeTestNextSiblingIs1
ldi r16, 3 ; error code
brcc treeTest4_error
rcall treeTestNextSiblingIsNull
ldi r16, 4 ; error code
brcc treeTest4_error
sec
ret
treeTest4_error:
clc
ret
; @end
treeTestCreateAndAddChild1:
ldi yl, LOW(testTree_child1)
ldi yh, HIGH(testTree_child1)
ldi r18, 3
ldi r19, 4
rcall treeTest_Object_Init
ldi xl, LOW(testTree_root)
ldi xh, HIGH(testTree_root)
bigcall Tree_AddChildObject
rcall treeTestCheckParentRoot
brcc treeTestCreateAndAddChild1_error
sec
ret
treeTestCreateAndAddChild1_error:
clc
ret
treeTestCreateAndAddChild2:
ldi yl, LOW(testTree_child2)
ldi yh, HIGH(testTree_child2)
ldi r18, 5
ldi r19, 6
rcall treeTest_Object_Init
ldi xl, LOW(testTree_root)
ldi xh, HIGH(testTree_root)
bigcall Tree_AddChildObject
rcall treeTestCheckParentRoot
brcc treeTestCreateAndAddChild2_error
sec
ret
treeTestCreateAndAddChild2_error:
clc
ret
treeTestCreateAndAddChild3:
ldi yl, LOW(testTree_child3)
ldi yh, HIGH(testTree_child3)
ldi r18, 7
ldi r19, 8
rcall treeTest_Object_Init
ldi xl, LOW(testTree_root)
ldi xh, HIGH(testTree_root)
bigcall Tree_AddChildObject
rcall treeTestCheckParentRoot
brcc treeTestCreateAndAddChild3_error
sec
ret
treeTestCreateAndAddChild3_error:
clc
ret
treeTestCheckParentNull:
bigcall Tree_GetParentObject
mov r16, xl
or r16, xh
brne treeTestCheckParentNull_error
sec
ret
treeTestCheckParentNull_error:
clc
ret
treeTestCheckParentRoot:
bigcall Tree_GetParentObject
cpi xl, LOW(testTree_root)
brne treeTestCheckParentRoot_error
cpi xh, HIGH(testTree_root)
brne treeTestCheckParentRoot_error
sec
ret
treeTestCheckParentRoot_error:
clc
ret
treeTestNextSiblingIs1:
bigcall Tree_GetNextSibling
cpi xl, LOW(testTree_child1)
brne treeTestNextSiblingIs1_error
cpi xh, HIGH(testTree_child1)
brne treeTestNextSiblingIs1_error
mov yl, xl
mov yh, xh
sec
ret
treeTestNextSiblingIs1_error:
clc
ret
treeTestNextSiblingIs2:
bigcall Tree_GetNextSibling
cpi xl, LOW(testTree_child2)
brne treeTestNextSiblingIs2_error
cpi xh, HIGH(testTree_child2)
brne treeTestNextSiblingIs2_error
mov yl, xl
mov yh, xh
sec
ret
treeTestNextSiblingIs2_error:
clc
ret
treeTestNextSiblingIs3:
bigcall Tree_GetNextSibling
cpi xl, LOW(testTree_child3)
brne treeTestNextSiblingIs3_error
cpi xh, HIGH(testTree_child3)
brne treeTestNextSiblingIs3_error
mov yl, xl
mov yh, xh
sec
ret
treeTestNextSiblingIs3_error:
clc
ret
treeTestNextSiblingIsNull:
bigcall Tree_GetNextSibling
mov r16, xl
or r16, xh
brne treeTestNextSiblingIsNull_error
sec
ret
treeTestNextSiblingIsNull_error:
clc
ret

View File

@@ -26,13 +26,19 @@
all
c01
c02
n14
n16
n19
n20
n21
n22
n23
n24
n25
n26
n27
r04
r05
t03
</subdirs>

View File

@@ -20,6 +20,7 @@
.equ AQHOME_VALUETYPE_CO2 = 7
.equ AQHOME_VALUETYPE_TVOC = 8
.equ AQHOME_VALUETYPE_STATS = 9
.equ AQHOME_VALUETYPE_LIGHT = 10
; Value Ids
@@ -31,11 +32,21 @@
.equ AQHOME_VALUEID_STATS_ERRS_NOBUF = 0xe4
.equ AQHOME_VALUEID_STATS_ERRS_COLLISIONS = 0xe5
.equ AQHOME_VALUEID_STATS_ERRS_BUSY = 0xe6
.equ AQHOME_VALUEID_STATS_HEAP_USED = 0xe7
.equ AQHOME_VALUEID_STATS_HEAP_FREE = 0xe8
.equ AQHOME_VALUEID_STATS_ERRS_MSGSIZE = 0xe7
.equ AQHOME_VALUEID_STATS_ERRS_MISSED = 0xe8
.equ AQHOME_VALUEID_STATS_PACKETS_IN2 = 0xe9
.equ AQHOME_VALUEID_STATS_PACKETS_OUT2 = 0xea
.equ AQHOME_VALUEID_STATS_ERRS_CONTENT2 = 0xeb
.equ AQHOME_VALUEID_STATS_ERRS_IO2 = 0xec
.equ AQHOME_VALUEID_STATS_ERRS_NOBUF2 = 0xed
.equ AQHOME_VALUEID_STATS_ERRS_COLLISIONS2 = 0xee
.equ AQHOME_VALUEID_STATS_ERRS_BUSY2 = 0xef
.equ AQHOME_VALUEID_STATS_ERRS_MSGSIZE2 = 0xf0
.equ AQHOME_VALUEID_STATS_ERRS_MISSED2 = 0xf1
.equ AQHOME_VALUEID_STATS_HEAP_USED = 0xf2
.equ AQHOME_VALUEID_STATS_HEAP_FREE = 0xf3
; ---------------------------------------------------------------------------

View File

@@ -19,14 +19,14 @@
systemInitHardware:
; set all ports as inputs and enable internal pull-up resistors
ldi r16, 0xff
; ldi r16, 0xff
clr r17
out DDRA, r17 ; all input
sts PUEA, r16 ; enable pull-up on all
outr DDRA, r17 ; all input
outr PUEA, r17 ; disable pull-up on all
out DDRB, r17 ; all input
sts PUEB, r16 ; enable pull-up on all
outr DDRB, r17 ; all input
outr PUEB, r17 ; disable pull-up on all
ret
; @end
@@ -50,6 +50,22 @@ systemSetSpeed:
clr r16 ; SUT=0, CLKPS=0
sts CCP, r17
sts CLKPR, r16
#if 0
; read and set calibration data
push r15
inr r15, SREG
cli
ldi zl, 0
ldi zh, 1
ldi r16, (1<<RSIG) | (1<<SPMEN)
outr SPMCSR, r16
lpm r17, Z
outr OSCCAL0, r17
outr SREG, r15
pop r15
#endif
.endif
ret
@@ -118,16 +134,16 @@ systemSetupTimer0: ; setup timer for IRQ every 100ms
ldi r16, (1<<OCF0A) ; clear pending interrupts
.ifdef TIFR0
out TIFR0, r16
outr TIFR0, r16
.else
out TIFR, r16
outr TIFR, r16
.endif
ldi r16, (1<<OCIE0A) ; Timer/Counter0 Output Compare Match A Interrupt Enable
.ifdef TIMSK0
out TIMSK0, r16
outr TIMSK0, r16
.else
out TIMSK, r16
outr TIMSK, r16
.endif
sec
ret

View File

@@ -68,20 +68,31 @@
#ifdef MODULES_COMONUART0
.include "modules/uart_hw/defs.asm"
.include "modules/uart_hw/lowlevel.asm"
.include "modules/uart_hw/m_lowlevel_uart.asm"
.include "modules/uart_hw/comonuart0.asm"
;.include "modules/uart_hw/defs.asm"
;.include "modules/uart_hw/lowlevel.asm"
;.include "modules/uart_hw/m_lowlevel_uart.asm"
;.include "modules/uart_hw/comonuart0.asm"
.include "modules/uart_hw2/defs.asm"
.include "modules/uart_hw2/comonuart0.asm"
#endif
#ifdef MODULES_COMONUART1
;.include "modules/uart_hw/defs.asm"
;.include "modules/uart_hw/lowlevel.asm"
;.include "modules/uart_hw/m_lowlevel_uart.asm"
;.include "modules/uart_hw/comonuart1.asm"
.include "modules/uart_hw2/defs.asm"
.include "modules/uart_hw2/comonuart1.asm"
#endif
#ifdef MODULES_TTYONUART1
#ifndef MODULES_COMONUART0
.include "modules/uart_hw/defs.asm"
.include "modules/uart_hw/lowlevel.asm"
.include "modules/uart_hw/m_lowlevel_uart.asm"
#endif
.include "modules/uart_hw/ttyonuart1.asm"
;.include "modules/uart_hw2/defs.asm"
;.include "modules/uart_hw2/ttyonuart1.asm"
#endif
@@ -144,6 +155,9 @@
#ifdef MODULES_CCS811
.include "modules/ccs811/main.asm"
#ifdef MODULES_NETWORK
.include "modules/ccs811/send.asm"
#endif
#endif
#ifdef MODULES_TCRT1000
@@ -157,6 +171,10 @@
#endif
#endif
#ifdef MODULES_LCD
.include "modules/lcd/main.asm"
#endif
#ifdef MODULES_ILI9341
.include "modules/lcd2/ili9341/defs.asm"
.include "modules/lcd2/ili9341/main.asm"
@@ -165,6 +183,21 @@
.include "modules/lcd2/ili9341/text.asm"
#endif
#ifdef MODULES_FONT
.include "modules/lcd2/font/defs.asm"
.include "modules/lcd2/font/main.asm"
#endif
#ifdef MODULES_WIN
.include "common/list.asm"
.include "common/tree.asm"
.include "modules/lcd2/win/defs.asm"
.include "modules/lcd2/win/object.asm"
.include "modules/lcd2/win/widget.asm"
.include "modules/lcd2/win/gui.asm"
#endif
#ifdef MODULES_FONT_8X8
.include "modules/lcd2/font/defs.asm"
.include "modules/lcd2/font/font8x8.asm"
@@ -177,6 +210,14 @@
#endif
#ifdef MODULES_BRIGHTNESS
.include "modules/brightness/main.asm"
#ifdef MODULES_NETWORK
.include "modules/brightness/send.asm"
#endif
#endif
#ifdef APPS_MOTION
.include "modules/f_keepup/main.asm"
.include "modules/valsched/main.asm"

View File

@@ -107,10 +107,17 @@ onSystemTimerTick:
bigcall ComOnUart0_Periodically
#endif
#ifdef MODULES_COMONUART1
bigcall ComOnUart1_Periodically
#endif
#ifdef MODULES_TCRT1000
bigcall TCRT1K_Every100ms
#endif
#ifdef MODULES_BRIGHTNESS
bigcall Brightness_Every100ms
#endif
#ifdef APPS_NETWORK
ldi yl, LOW(netInterfaceData)
@@ -145,6 +152,11 @@ sysOnEverySecond:
#ifdef APPS_REPORTSENSORS
bigcall AppReportSensors_OnEverySecond
#endif
#ifdef MODULES_SGP30
bigcall SGP30_EverySecond
#endif
bigjmp onEverySecond
; @end
@@ -154,6 +166,10 @@ sysOnEveryMinute:
bigcall AppStats_OnEveryMinute
#endif
#ifdef MODULES_CCS811
bigcall CCS811_OnEveryMinute
#endif
bigjmp onEveryMinute
; @end
@@ -164,6 +180,12 @@ sysOnEveryHour:
sysOnEveryDay:
#ifdef APPS_NETWORK
ldi yl, LOW(netInterfaceData)
ldi yh, HIGH(netInterfaceData)
bigcall AppNetwork_EveryDay
#endif
bigjmp onEveryDay
; @end

View File

@@ -77,6 +77,10 @@ initModules:
bigcall ComOnUart0_Init
#endif
#ifdef MODULES_COMONUART1
bigcall ComOnUart1_Init
#endif
#ifdef MODULES_MOTION
bigcall Motion_Init
#endif
@@ -148,6 +152,10 @@ initModules:
bigcall ILI9341_Init
#endif
#ifdef MODULES_BRIGHTNESS
bigcall Brightness_Init
#endif
; done
ret
@@ -190,6 +198,10 @@ runModules_ComEnd:
bigcall ComOnUart0_Run
#endif
#ifdef MODULES_COMONUART1
bigcall ComOnUart1_Run
#endif
#ifdef MODULES_STATS
bigcall Stats_Run
#endif
@@ -211,6 +223,7 @@ runModules_ComEnd:
; rcall TCRT1K_Run
#endif
; add more modules here
ret

View File

@@ -21,6 +21,7 @@
.include "./data.asm"
.include "devices/all/defs.asm"
.include "common/calls.asm"
.include "common/utils_wait.asm"
.include "common/utils_io.asm"

View File

@@ -33,20 +33,13 @@
; ---------------------------------------------------------------------------
; generic
.equ STACK_SIZE = 256
.equ NET_BUFFERS_NUM = 8
.equ NET_BUFFERS_SIZE = 32
; ---------------------------------------------------------------------------
; heap
.equ HEAP_START = SRAM_START+0x200
.equ HEAP_SIZE = SRAM_SIZE-HEAP_START
; ---------------------------------------------------------------------------
; firmware settings including list of modules used
@@ -61,9 +54,8 @@
#define MODULES_UART_BITBANG
#define MODULES_SPI_HW
#define MODULES_ILI9341
;#define MODULES_FONT_8X8
#define MODULES_FONT_6X8
;#define MODULES_UART_BITBANG
#define MODULES_FONT
#define MODULES_WIN
;#define MODULES_TWI_MASTER
;#define MODULES_LCD
;#define LCD_MINIMAL_FONT
@@ -175,6 +167,7 @@ irqNotSet:
; @routine onSystemStart
onSystemStart:
bigcall test
ret
; @end
@@ -226,8 +219,18 @@ onEveryLoop:
.include "devices/all/hw_m644p.asm"
.include "devices/all/includes.asm"
.include "common/debug.asm"
;.include "common/debug.asm"
;.include "modules/lcd2/font/font2.asm"
;.include "modules/lcd2/font/font3.asm"
;.include "modules/lcd2/font/font16x26.asm"
;.include "modules/lcd2/font/font4.asm"
;.include "modules/lcd2/font/font12x16.asm"
.include "modules/lcd2/font/font5.asm"
.include "modules/lcd2/font/font12x20.asm"
;.include "common/list_t.asm"
.include "common/tree_t.asm"
.include "common/divide.asm"
; ---------------------------------------------------------------------------
@@ -238,3 +241,210 @@ onEveryLoop:
; @param %0 X
; @param %1 Y
; @param %2 W
; @param %3 H
.macro M_FILL_RECT
ldi r16, LOW(@0) ; X0
mov r4, r16
ldi r16, HIGH(@0)
mov r5, r16
ldi r16, LOW(@1) ; Y0
mov r6, r16
ldi r16, HIGH(@1)
mov r7, r16
ldi r16, LOW(@2) ; W
mov r8, r16
ldi r16, HIGH(@2)
mov r9, r16
ldi r16, LOW(@3) ; H
mov r10, r16
ldi r16, HIGH(@3)
mov r11, r16
bigcall ILI9341_FillRect
.endmacro
test:
; set foreground (r3:r2)
; 0bRRRRRGGGGGGBBBBB
ldi r16, 0b11111111
mov r3, r16
ldi r16, 0b11111111 ; white
mov r2, r16
M_FILL_RECT 0, 0, 319, 239
; set foreground (r3:r2)
ldi r16, 0b00000000
mov r3, r16
ldi r16, 0b00011111 ; blue
mov r2, r16
M_FILL_RECT 0, 0, 319, 32
; set background (r1:r0)
mov r0, r2
mov r1, r3
; set foreground (r3:r2)
ldi r16, 0b11111111
mov r3, r16
ldi r16, 0b11111111 ; white
mov r2, r16
; set Xpos
ldi r16, LOW(10)
mov r4, r16
ldi r16, HIGH(10)
mov r5, r16
; setYpos
ldi r16, LOW(3)
mov r6, r16
ldi r16, HIGH(3)
mov r7, r16
; set font
; ldi zl, LOW(font3_16x26*2)
; ldi zh, HIGH(font3_16x26*2)
ldi zl, LOW(font5_12x20*2)
ldi zh, HIGH(font5_12x20*2)
; set buffer
ldi xl, LOW(glyphBuffer)
ldi xh, HIGH(glyphBuffer)
; write characters
ldi r16, 'A'
bigcall ili9341_WriteCharacterX1At
ldi r16, 'Q'
bigcall ili9341_WriteCharacterX1At
ldi r16, 'H'
bigcall ili9341_WriteCharacterX1At
ldi r16, 'O'
bigcall ili9341_WriteCharacterX1At
ldi r16, 'M'
bigcall ili9341_WriteCharacterX1At
ldi r16, 'E'
bigcall ili9341_WriteCharacterX1At
#if 0
push xl
push xh
rcall listTest1
pop xh
pop xl
brcc test_error
ldi r16, '!'
bigcall ili9341_WriteCharacterX1At
push xl
push xh
rcall listTest2
pop xh
pop xl
brcc test_error
ldi r16, '!'
bigcall ili9341_WriteCharacterX1At
push xl
push xh
rcall listTest3
pop xh
pop xl
brcc test_error
ldi r16, '!'
bigcall ili9341_WriteCharacterX1At
push xl
push xh
rcall listTest4
pop xh
pop xl
brcc test_error
ldi r16, '!'
bigcall ili9341_WriteCharacterX1At
#endif
#if 1
push xl
push xh
rcall treeTest1
pop xh
pop xl
brcc test_error
ldi r16, '!'
bigcall ili9341_WriteCharacterX1At
push xl
push xh
rcall treeTest2
pop xh
pop xl
brcc test_error
ldi r16, '!'
bigcall ili9341_WriteCharacterX1At
push xl
push xh
rcall treeTest3
pop xh
pop xl
brcc test_error
ldi r16, '!'
bigcall ili9341_WriteCharacterX1At
push xl
push xh
rcall treeTest4
pop xh
pop xl
brcc test_error
ldi r16, '!'
bigcall ili9341_WriteCharacterX1At
#endif
ret
test_error:
ldi r17, '0'
add r16, r17
bigcall ili9341_WriteCharacterX1At
ret
helloWorld: .db "Hello World", 0
.dseg
glyphBuffer: .byte 1024
heapStart:
.equ HEAP_START = heapStart
.equ HEAP_SIZE = (SRAM_SIZE-STACK_SIZE)-HEAP_START

View File

@@ -2,51 +2,21 @@
<gwbuild>
<target type="AvrHexFile" name="n14_main" >
<includes type="avrasm" >
-I $(builddir)
-I $(srcdir)
-I $(topsrcdir)/avr
-I $(topbuilddir)/avr
</includes>
<sources type="avrasm" >
n14_main.asm
</sources>
</target>
<target type="AvrHexFile" name="n14_boot" >
<includes type="avrasm" >
-I $(builddir)
-I $(srcdir)
-I $(topsrcdir)/avr
-I $(topbuilddir)/avr
</includes>
<sources type="avrasm" >
n14_boot.asm
</sources>
</target>
<subdirs>
boot
main
</subdirs>
<data dist="true" install="$(datadir)/aqhome/devices/nodes">
aqua_n14.xml
</data>
<extradist>
n14_defs.asm
defs.asm
README
</extradist>
</gwbuild>

14
avr/devices/n14/README Normal file
View File

@@ -0,0 +1,14 @@
N14
===
- Role: LED strip controller
- MCU: AtTiny85
- Connection: RJ45
- UART: uart_bitbang2
- Periphery:
- LED strip connection (SK6812)
- OWI interface
- DS18B20 temperature sensor
- Modules:
- MA_LIGHT: motion activated light

View File

@@ -14,6 +14,16 @@
<value name="MALONTIME" id="0x85" type="actor" dataType="uint16" />
<value name="MALSOURCE1" id="0x86" type="actor" dataType="uint16" />
<value name="MALSOURCE2" id="0x87" type="actor" dataType="uint16" />
<value name="stats_packets_in" id="0xe0" type="sensor" dataType="uint16" denom="1" />
<value name="stats_packets_out" id="0xe1" type="sensor" dataType="uint16" denom="1" />
<value name="stats_content_errors" id="0xe2" type="sensor" dataType="uint16" denom="1" />
<value name="stats_io_errors" id="0xe3" type="sensor" dataType="uint16" denom="1" />
<value name="stats_nobuf_errors" id="0xe4" type="sensor" dataType="uint16" denom="1" />
<value name="stats_collision_errors" id="0xe5" type="sensor" dataType="uint16" denom="1" />
<value name="stats_busy_errors" id="0xe6" type="sensor" dataType="uint16" denom="1" />
<value name="LEDTIMING" id="0x88" type="actor" dataType="uint16" />
</values>
</device>

View File

@@ -0,0 +1,32 @@
<?xml?>
<gwbuild>
<target type="AvrHexFile" name="n14_boot" >
<includes type="avrasm" >
-I $(builddir)
-I $(srcdir)
-I $(topsrcdir)/avr
-I $(topbuilddir)/avr
</includes>
<sources type="avrasm" >
boot.asm
</sources>
</target>
<subdirs>
</subdirs>
<extradist>
</extradist>
</gwbuild>

View File

@@ -14,30 +14,19 @@
.include "include/tn85def.inc" ; Define device ATtiny85
.list
.include "n14_defs.asm"
.include "defs_all.asm"
#define COM_ACCEPT_ALL_DEST
; ***************************************************************************
; defines
; ---------------------------------------------------------------------------
; generic
.include "version.asm"
.include "../defs.asm"
.include "devices/all/defs.asm"
.include "common/calls.asm"
.include "common/utils_wait.asm"
.include "modules/com2/defs.asm"
.include "modules/comproto/defs.asm"
; ---------------------------------------------------------------------------
; firmware settings
.equ FIRMWARE_VERSION_MAJOR = 0
.equ FIRMWARE_VERSION_MINOR = 0
.equ FIRMWARE_VERSION_PATCHLEVEL = 1
; ***************************************************************************
; defines
; ---------------------------------------------------------------------------
@@ -95,8 +84,7 @@ firmwareStart: rjmp main ; will be overwritten when flashing
main:
rjmp bootLoader ; this routine is in modules/flash/proto.asm
rjmp bootLoader ; this routine is in modules/bootloader/main.asm
@@ -112,6 +100,7 @@ main:
.include "modules/flash/io.asm"
.include "modules/flash/io_attn.asm"
.include "modules/flash/io_bitbang.asm"
.include "modules/flash/flashxp.asm"
.include "modules/flash/flash1p.asm"
.include "modules/flash/flashprocess.asm"
.include "modules/flash/wait.asm"
@@ -138,72 +127,3 @@ systemSetSpeed:
ret
DEBUG1:
ldi r19, 50
ldi r20, 1
ldi r21, 9
rcall blinkLed
rjmp DEBUG1
DEBUG2:
ldi r19, 50
ldi r20, 1
ldi r21, 1
rcall blinkLed
rjmp DEBUG2
; @param r19 loop count
; @param r20 on time
; @param r21 off time
; @clobbers (R16, R18, R22, R24, R25)
blinkLed:
cbi LED_SIMPLE_PORT, LED_SIMPLE_PINNUM ; on
mov r22, r20
rcall waitForMultiple100ms ; (R252
sbi LED_SIMPLE_PORT, LED_SIMPLE_PINNUM ; off
mov r22, r21
rcall waitForMultiple100ms ; (R22)
dec r19
brne blinkLed
ret
; @param r22 number of 100ms periods to wait
waitForMultiple100ms:
waitForMultiple100ms_loop:
push r22
rcall waitFor100ms
pop r22
dec r22
brne waitForMultiple100ms_loop
ret
waitFor100ms:
ldi r22, 10
waitFor100ms_loop:
push r22
rcall waitFor10ms
pop r22
dec r22
brne waitFor100ms_loop
ret
waitFor10ms:
ldi r22, 100
waitFor10ms_loop:
push r22
rcall Utils_WaitFor100MicroSecs
pop r22
dec r22
brne waitFor10ms_loop
ret

View File

@@ -1,5 +1,5 @@
; ***************************************************************************
; copyright : (C) 2024 by Martin Preuss
; copyright : (C) 2025 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
@@ -39,6 +39,7 @@
.equ LED_SIMPLE_OFFTIME = 30
.equ LED_SIMPLE_DDR = DDRB
.equ LED_SIMPLE_PORT = PORTB
.equ LED_SIMPLE_PORTIN = PINB
.equ LED_SIMPLE_PINNUM = PORTB4

View File

@@ -0,0 +1,33 @@
<?xml?>
<gwbuild>
<target type="AvrHexFile" name="n14_firmware" >
<includes type="avrasm" >
-I $(builddir)
-I $(srcdir)
-I $(topsrcdir)/avr
-I $(topbuilddir)/avr
</includes>
<sources type="avrasm" >
main.asm
</sources>
</target>
<subdirs>
</subdirs>
<extradist>
</extradist>
</gwbuild>

View File

@@ -0,0 +1,208 @@
; ***************************************************************************
; copyright : (C) 2024 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
; ***************************************************************************
; Source file for LED controller node on AtTiny 85
;
; This is for the full system (i.e. not the boot loader).
; ***************************************************************************
.equ clock=8000000 ; Define the clock frequency
.nolist
.include "include/tn85def.inc" ; Define device ATtiny85
.list
.include "version.asm"
.include "../defs.asm"
;.include "./data.asm"
.include "devices/all/defs.asm"
.include "common/calls.asm"
.include "common/utils_wait.asm"
; ***************************************************************************
; defines
; ---------------------------------------------------------------------------
; generic
.equ NET_BUFFERS_NUM = 6
.equ NET_BUFFERS_SIZE = 32
; ---------------------------------------------------------------------------
; firmware settings including list of modules used
#define MODULES_CLOCK
#define MODULES_LED_SIMPLE
#define MODULES_NETWORK
#define MODULES_UART_BITBANG
#define MODULES_OWI_MASTER
#define MODULES_DS18B20
#define MODULES_SK6812
;#define MODULES_MOTION_LIGHT
#define APPS_NETWORK
#define APPS_REPORTSENSORS
#define APPS_STATS
#define APPS_MA_LIGHT
; ---------------------------------------------------------------------------
; defines for modules
;.equ VALUE_ID_SI7021_TEMP = 0x01
;.equ VALUE_ID_SI7021_HUM = 0x02
;.equ VALUE_ID_ADC = 0x03
;.equ VALUE_ID_REED1 = 0x04
;.equ VALUE_ID_REED2 = 0x05
.equ VALUE_ID_DS18B20_TEMP = 0x06
;.equ VALUE_ID_REED_CONF = 0x81
.equ VALUE_ID_LED_NUMLEDS = 0x82
.equ VALUE_ID_LED_RGBW_VALUE = 0x83
.equ VALUE_ID_MAL_RGBW_VALUE = 0x84
.equ VALUE_ID_MAL_ONTIME = 0x85
.equ VALUE_ID_MAL_SOURCE1 = 0x86
.equ VALUE_ID_MAL_SOURCE2 = 0x87
.equ VALUE_ID_LEDSIMPLE_TIMING = 0x88
; ***************************************************************************
; code segment
.cseg
.org 000000
; ---------------------------------------------------------------------------
; Reset and interrupt vectors
rjmp BOOTLOADER_ADDR ; Reset vector ; use this for flashed system
reti ; EXT_INT0
rjmp UART_BitBang_PcintIsr ; PCI0
reti ; OC1A
reti ; OVF1
reti ; OVF0
reti ; ERDY
reti ; ACI
reti ; ADCC
reti ; OC1B
rjmp baseTimerIrqOC0A ; OC0A
reti ; OC0B
reti ; WATCHDOG
reti ; USI_STR
reti ; USI_OVF
devInfoBlock: ; 12 bytes
devInfoManufacturer: .db 'A', 'Q', 'U', 'A'
devInfoId: .db DEVICEINFO_ID, 0
devInfoVersion: .db DEVICEINFO_VERSION, DEVICEINFO_REVISION ; version, revision
firmwareVersion: .db FIRMWARE_VARIANT_LEDSTRIPS, FIRMWARE_VERSION_MAJOR
.db FIRMWARE_VERSION_MINOR, FIRMWARE_VERSION_PATCHLEVEL
; ---------------------------------------------------------------------------
; @routine firmwareStart @global
firmwareStart:
rjmp main
; @end
; ---------------------------------------------------------------------------
; @routine onSystemStart
onSystemStart:
ret
; @end
; ---------------------------------------------------------------------------
; @routine onMessageReceived
;
; Called on every message received
onMessageReceived:
clc
ret
; @end
; ---------------------------------------------------------------------------
; @routine onEvery100ms
;
; Called every 100ms. Add your routine calls here. No arguments, no results.
onEvery100ms:
onEveryMinute:
onEveryHour:
onEveryDay:
ret
; @end
onEverySecond:
ret
; debug
ldi r19, 0x00 ; G
ldi r18, 0xff ; R
ldi r20, 0x55 ; B
ldi r21, 0xaa ; W
rcall SK6812_SetAllColor ; r23 (r16, r17)
ret
; ---------------------------------------------------------------------------
; @routine onEveryLoop
;
; Called on every loop (i.e. after awakening from sleep).
;
onEveryLoop:
ret
; @end
; ***************************************************************************
; includes
.include "devices/all/hw_tn85.asm"
.include "devices/all/includes.asm"
.include "common/debug.asm"
; ---------------------------------------------------------------------------
; defines for network interface
.equ netInterfaceData = uart_bitbang_iface

View File

@@ -1,333 +0,0 @@
; ***************************************************************************
; copyright : (C) 2024 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
; ***************************************************************************
; Source file for LED controller node on AtTiny 85
;
; This is for the full system (i.e. not the boot loader).
; ***************************************************************************
.equ clock=8000000 ; Define the clock frequency
.nolist
.include "include/tn85def.inc" ; Define device ATtiny85
.list
.include "n14_defs.asm"
.include "defs_all.asm"
.include "common/utils_wait.asm" ; wait macro
; ***************************************************************************
; defines
; ---------------------------------------------------------------------------
; firmware settings including list of modules used
.equ FIRMWARE_VERSION_MAJOR = 0
.equ FIRMWARE_VERSION_MINOR = 0
.equ FIRMWARE_VERSION_PATCHLEVEL = 1
#define MODULES_TIMER
#define MODULES_COM
#define MODULES_COM_WITH_ADDR_PROTO
#define MODULES_LED_SIMPLE
#define MODULES_STATS
#define MODULES_OWI_MASTER
#define MODULES_DS18B20
#define MODULES_SK6812
#define MODULES_MOTION_LIGHT
; #define COM_ACCEPT_ALL_DEST
; ---------------------------------------------------------------------------
; defines for modules
;.equ VALUE_ID_SI7021_TEMP = 0x01
;.equ VALUE_ID_SI7021_HUM = 0x02
;.equ VALUE_ID_ADC = 0x03
;.equ VALUE_ID_REED1 = 0x04
;.equ VALUE_ID_REED2 = 0x05
.equ VALUE_ID_DS18B20_TEMP = 0x06
;.equ VALUE_ID_REED_CONF = 0x81
.equ VALUE_ID_LED_NUMLEDS = 0x82
.equ VALUE_ID_LED_RGBW_VALUE = 0x83
.equ VALUE_ID_MAL_RGBW_VALUE = 0x84
.equ VALUE_ID_MAL_ONTIME = 0x85
.equ VALUE_ID_MAL_SOURCE1 = 0x86
.equ VALUE_ID_MAL_SOURCE2 = 0x87
; ***************************************************************************
; code segment
.cseg
.org 000000
; ---------------------------------------------------------------------------
; Reset and interrupt vectors
rjmp BOOTLOADER_ADDR ; Reset vector ; use this for flashed system
reti ; EXT_INT0
rjmp uartBitbangIsrPcint0 ; PCI0
reti ; OC1A
reti ; OVF1
reti ; OVF0
reti ; ERDY
reti ; ACI
reti ; ADCC
reti ; OC1B
rjmp baseTimerIrqOC0A ; OC0A
reti ; OC0B
reti ; WATCHDOG
reti ; USI_STR
reti ; USI_OVF
devInfoBlock: ; 12 bytes
devInfoManufacturer: .db 'A', 'Q', 'U', 'A'
devInfoId: .db DEVICEINFO_ID, 0
devInfoVersion: .db DEVICEINFO_VERSION, DEVICEINFO_REVISION ; version, revision
firmwareVersion: .db FIRMWARE_VARIANT_LEDSTRIPS, FIRMWARE_VERSION_MAJOR
.db FIRMWARE_VERSION_MINOR, FIRMWARE_VERSION_PATCHLEVEL
firmwareStart: rjmp main
; ***************************************************************************
; includes
.include "common/utils.asm"
.include "common/utils_wait_fixed.asm"
.include "common/utils_copy_from_flash.asm"
.include "common/utils_copy_sdram.asm"
.include "common/crc8.asm"
.include "modules/basetimer/main.asm"
#ifdef MODULES_TIMER
.include "modules/timer/main.asm"
#endif
#ifdef MODULES_LED_SIMPLE
.include "modules/led_simple/main.asm"
#endif
#ifdef MODULES_COM
.include "modules/com2/defs.asm"
.include "modules/com2/main.asm"
.include "modules/com2/buffer.asm"
#ifdef MODULES_STATS
.include "modules/comproto/msg_recvstats.asm"
.include "modules/comproto/msg_sendstats.asm"
.include "modules/comproto/msg_sysstats.asm"
.include "modules/comproto/msg_memstats.asm"
#endif
.include "modules/comproto/msg_pong.asm"
.include "modules/comproto/msg_value.asm"
.include "modules/comproto/msg_device.asm"
.include "modules/comproto/msg_reboot.asm"
.include "modules/uart_bitbang/defs.asm"
.include "modules/uart_bitbang/main.asm"
.include "modules/uart_bitbang/bytelevel.asm"
.include "modules/uart_bitbang/packetlevel.asm"
#ifdef MODULES_COM_WITH_ADDR_PROTO
.include "modules/comproto/defs.asm"
.include "modules/comproto/main.asm"
.include "modules/comproto/addr.asm"
#endif
#endif
#ifdef MODULES_STATS
.include "modules/stats/main.asm"
#endif
#ifdef MODULES_OWI_MASTER
.include "modules/owimaster/main.asm"
#endif
#ifdef MODULES_DS18B20
.include "modules/ds18b20/main.asm"
#endif
#ifdef MODULES_SK6812
.include "modules/sk6812/main.asm"
#endif
#ifdef MODULES_MOTION_LIGHT
.include "modules/ma_light/main.asm"
#endif
; ***************************************************************************
; data in SRAM
.dseg
#ifdef MODULES_DS18B20
sramDs18b20Timer: .byte 2
sramSendDs18b20TempTimer: .byte 2
#endif
; ***************************************************************************
; data in FLASH
.cseg
; ---------------------------------------------------------------------------
; timer list
timerList:
; SRAM variable/counter routine flags secs (0=don't start or restart)
#ifdef MODULES_COM_WITH_ADDR_PROTO
.dw cproAddresModeTimer, CPRO_Address_OnTimer, 0, 0 ; (no restart)
#endif
#ifdef MODULES_STATS
.dw statsSendTimer, Stats_Timer, TIMER_FLAGS_IF_ADDR, 9000 ; every 15m
#endif
#ifdef MODULES_DS18B20
.dw sramDs18b20Timer, Ds18b20_OnTimer, 0, 300 ; every 30s
.dw sramSendDs18b20TempTimer, sendDs18b20Temp, TIMER_FLAGS_IF_ADDR, 600 ; every 60s
#endif
.dw 0 ; end of list
.include "main_all.asm"
; ---------------------------------------------------------------------------
; Called early on system startup. No arguments, no results.
systemSetSpeed:
.if clock == 1000000
ldi r16, (1<<CLKPCE)
ldi r17, (1<<CLKPS1) | (1<<CLKPS0)
out CLKPR, r16
out CLKPR, r17
.endif
.if clock == 8000000
ldi r16, (1<<CLKPCE)
ldi r17, 0
out CLKPR, r16
out CLKPR, r17
.endif
ret
; ---------------------------------------------------------------------------
; Called just before rebooting to bootloader. No arguments, no results.
systemSetBootSpeed:
ldi r16, (1<<CLKPCE)
ldi r17, (1<<CLKPS1) | (1<<CLKPS0)
out CLKPR, r16
out CLKPR, r17
ret
; ---------------------------------------------------------------------------
; Called on first time run, i.e. on system start. No arguments, no results.
onSystemStart:
ret
#ifdef MODULES_DS18B20
sendDs18b20Temp:
rcall Ds18b20_SendTemp
brcs sendDs18b20Temp_okay
; set timer to 1s to retry later
ldi xl, LOW(sramSendDs18b20TempTimer)
ldi xh, HIGH(sramSendDs18b20TempTimer)
rjmp Timer_SetValueTo1s
sendDs18b20Temp_okay:
ret
#endif
; ---------------------------------------------------------------------------
; Called every 100ms. Add your routine calls here. No arguments, no results.
onEvery100ms:
#ifdef MODULES_LED_SIMPLE
rcall LedSimple_Every100ms
#endif
#ifdef MODULES_REED
rcall REED_Every100ms
#endif
#ifdef MODULES_MOTION_LIGHT
rcall MotionLight_Every100ms
#endif
ret
; ---------------------------------------------------------------------------
; @routine onPacketReceived:
;
; Called after a packet was received via COM module. Add your routine calls here.
;
; The packet will be released in any case after return from this call.
;
; @return CFLAG set if message handled, cleared otherwise
; @param X pointer to received buffer
; @clobbers all
onPacketReceived:
; get msg code
adiw xh:xl, COM2_MSG_OFFS_CMD
ld r16, x
sbiw xh:xl, COM2_MSG_OFFS_CMD
#ifdef MODULES_MOTION_LIGHT
rcall MotionLight_OnPacketReceived
brcs onPacketReceived_end
#endif
#ifdef MODULES_SK6812
rcall SK6812_OnPacketReceived
brcs onPacketReceived_end
#endif
#ifdef MODULES_REED
rcall REED_OnPacketReceived
brcs onPacketReceived_end
#endif
#ifdef MODULES_COM
rcall CPRO_OnPacketReceived
brcs onPacketReceived_end
#endif
clc
onPacketReceived_end:
ret
; @end

View File

@@ -2,51 +2,16 @@
<gwbuild>
<target type="AvrHexFile" name="firmware" >
<includes type="avrasm" >
-I $(builddir)
-I $(srcdir)
-I $(topsrcdir)/avr
-I $(topbuilddir)/avr
</includes>
<sources type="avrasm" >
main.asm
</sources>
</target>
<target type="AvrHexFile" name="boot" >
<includes type="avrasm" >
-I $(builddir)
-I $(srcdir)
-I $(topsrcdir)/avr
-I $(topbuilddir)/avr
</includes>
<sources type="avrasm" >
boot.asm
</sources>
</target>
<subdirs>
boot
main
</subdirs>
<extradist>
defs.asm
README
</extradist>
</gwbuild>

13
avr/devices/n19/README Normal file
View File

@@ -0,0 +1,13 @@
N19
===
- Role: Air quality and climate sensors
- MCU: AtTiny84
- Connection: RJ45
- Periphery:
- PIR sensor (AMN31112)
- TWI interface
- SI7021 temperature and humidity sensor
- CCS811 air quality sensor

View File

@@ -0,0 +1,32 @@
<?xml?>
<gwbuild>
<target type="AvrHexFile" name="n19_boot" >
<includes type="avrasm" >
-I $(builddir)
-I $(srcdir)
-I $(topsrcdir)/avr
-I $(topbuilddir)/avr
</includes>
<sources type="avrasm" >
boot.asm
</sources>
</target>
<subdirs>
</subdirs>
<extradist>
</extradist>
</gwbuild>

View File

@@ -14,8 +14,10 @@
.include "include/tn85def.inc" ; Define device ATtiny85
.list
.include "./defs.asm"
.include "defs_all.asm"
.include "../defs.asm"
.include "devices/all/defs.asm"
.include "common/calls.asm"
.include "common/utils_wait.asm"
@@ -25,10 +27,6 @@
; ---------------------------------------------------------------------------
; generic
.include "common/utils_wait.asm"
.include "modules/com2/defs.asm"
.include "modules/comproto/defs.asm"
; ---------------------------------------------------------------------------
; firmware settings

View File

@@ -40,6 +40,7 @@
.equ LED_SIMPLE_OFFTIME = 50
.equ LED_SIMPLE_DDR = DDRB
.equ LED_SIMPLE_PORT = PORTB
.equ LED_SIMPLE_PORTIN = PINB
.equ LED_SIMPLE_PINNUM = PORTB3

View File

@@ -1,379 +0,0 @@
; ***************************************************************************
; copyright : (C) 2024 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
; ***************************************************************************
; Source file for LED controller node on AtTiny 85
;
; This is for the full system (i.e. not the boot loader).
; ***************************************************************************
.equ clock=1000000 ; Define the clock frequency
.nolist
.include "include/tn85def.inc" ; Define device ATtiny85
.list
.include "./defs.asm"
.include "defs_all.asm"
.include "common/utils_wait.asm" ; wait macro
; ***************************************************************************
; defines
; ---------------------------------------------------------------------------
; firmware settings including list of modules used
.equ FIRMWARE_VERSION_MAJOR = 0
.equ FIRMWARE_VERSION_MINOR = 0
.equ FIRMWARE_VERSION_PATCHLEVEL = 1
#define MODULES_TIMER
#define MODULES_COM
#define MODULES_COM_WITH_ADDR_PROTO
#define MODULES_LED_SIMPLE
#define MODULES_TWI_MASTER
#define MODULES_SI7021
#define MODULES_STATS
; #define MODULES_OWI_MASTER
; #define MODULES_DS18B20
; #define MODULES_SK6812
; #define MODULES_MOTION_LIGHT
; #define COM_ACCEPT_ALL_DEST
#define MODULES_CCS811
; ---------------------------------------------------------------------------
; defines for modules
.equ VALUE_ID_SI7021_TEMP = 0x01
.equ VALUE_ID_SI7021_HUM = 0x02
.equ VALUE_ID_CO2 = 0x07
.equ VALUE_ID_TVOC = 0x08
.equ VALUE_ID_DEBUG = 0x7f
; ***************************************************************************
; code segment
.cseg
.org 000000
; ---------------------------------------------------------------------------
; Reset and interrupt vectors
rjmp BOOTLOADER_ADDR ; Reset vector ; use this for flashed system
reti ; EXT_INT0
rjmp uartBitbangIsrPcint0 ; PCI0
reti ; OC1A
reti ; OVF1
reti ; OVF0
reti ; ERDY
reti ; ACI
reti ; ADCC
reti ; OC1B
rjmp baseTimerIrqOC0A ; OC0A
reti ; OC0B
reti ; WATCHDOG
reti ; USI_STR
reti ; USI_OVF
devInfoBlock: ; 12 bytes
devInfoManufacturer: .db 'A', 'Q', 'U', 'A'
devInfoId: .db DEVICEINFO_ID, 0
devInfoVersion: .db DEVICEINFO_VERSION, DEVICEINFO_REVISION ; version, revision
firmwareVersion: .db FIRMWARE_VARIANT_MAIN, FIRMWARE_VERSION_MAJOR
.db FIRMWARE_VERSION_MINOR, FIRMWARE_VERSION_PATCHLEVEL
firmwareStart: rjmp main
; ***************************************************************************
; includes
.include "common/utils.asm"
.include "common/utils_wait_fixed.asm"
.include "common/utils_copy_from_flash.asm"
.include "common/utils_copy_sdram.asm"
.include "common/crc8.asm"
.include "modules/basetimer/main.asm"
#ifdef MODULES_TIMER
.include "modules/timer/main.asm"
#endif
#ifdef MODULES_LED_SIMPLE
.include "modules/led_simple/main.asm"
#endif
#ifdef MODULES_COM
.include "modules/com2/defs.asm"
.include "modules/com2/main.asm"
.include "modules/com2/buffer.asm"
#ifdef MODULES_STATS
.include "modules/comproto/msg_recvstats.asm"
.include "modules/comproto/msg_sendstats.asm"
.include "modules/comproto/msg_sysstats.asm"
.include "modules/comproto/msg_memstats.asm"
#endif
.include "modules/comproto/msg_pong.asm"
.include "modules/comproto/msg_value.asm"
.include "modules/comproto/msg_device.asm"
.include "modules/comproto/msg_reboot.asm"
.include "modules/uart_bitbang/defs.asm"
.include "modules/uart_bitbang/main.asm"
.include "modules/uart_bitbang/bytelevel.asm"
.include "modules/uart_bitbang/packetlevel.asm"
#ifdef MODULES_COM_WITH_ADDR_PROTO
.include "modules/comproto/defs.asm"
.include "modules/comproto/main.asm"
.include "modules/comproto/addr.asm"
#endif
#endif
#ifdef MODULES_STATS
.include "modules/stats/main.asm"
#endif
#ifdef MODULES_TWI_MASTER
.include "modules/twimaster/main.asm"
#endif
#ifdef MODULES_OWI_MASTER
.include "modules/owimaster/main.asm"
#endif
#ifdef MODULES_SI7021
.include "modules/si7021/main.asm"
#endif
#ifdef MODULES_DS18B20
.include "modules/ds18b20/main.asm"
#endif
#ifdef MODULES_SK6812
.include "modules/sk6812/main.asm"
#endif
#ifdef MODULES_MOTION_LIGHT
.include "modules/ma_light/main.asm"
#endif
#ifdef MODULES_CCS811
.include "modules/ccs811/main.asm"
#endif
; ***************************************************************************
; data in SRAM
.dseg
#ifdef MODULES_SI7021
sramTimerSI7021Measure: .byte 2
sramTimerSI7021SendTemp: .byte 2
sramTimerSI7021SendHumidity: .byte 2
#endif
#ifdef MODULES_DS18B20
sramDs18b20Timer: .byte 2
sramSendDs18b20TempTimer: .byte 2
#endif
#ifdef MODULES_CCS811
sramCcs811Timer: .byte 2
#endif
; ***************************************************************************
; data in FLASH
.cseg
; ---------------------------------------------------------------------------
; timer list
timerList:
; SRAM variable/counter routine flags secs (0=don't start or restart)
#ifdef MODULES_COM_WITH_ADDR_PROTO
.dw cproAddresModeTimer, CPRO_Address_OnTimer, 0, 0 ; (no restart)
#endif
#ifdef MODULES_STATS
.dw statsSendTimer, Stats_Timer, TIMER_FLAGS_IF_ADDR, 9000 ; every 15m
#endif
#ifdef MODULES_DS18B20
.dw sramDs18b20Timer, Ds18b20_OnTimer, 0, 300 ; every 30s
.dw sramSendDs18b20TempTimer, sendDs18b20Temp, TIMER_FLAGS_IF_ADDR, 600 ; every 60s
#endif
#ifdef MODULES_SI7021
.dw sramTimerSI7021Measure, SI7021_OnTimer, 0, 300 ; every 30s
.dw sramTimerSI7021SendTemp, sendSI7021Temp, TIMER_FLAGS_IF_ADDR, 600 ; every 60s
.dw sramTimerSI7021SendHumidity, sendSI7021Humidity, TIMER_FLAGS_IF_ADDR, 600 ; every 60s
#endif
#ifdef MODULES_CCS811
.dw sramCcs811Timer, CCS811_OnTimer, 0, 10 ; every 1s
#endif
.dw 0 ; end of list
.include "main_all.asm"
; ---------------------------------------------------------------------------
; Called early on system startup. No arguments, no results.
systemSetSpeed:
.if clock == 1000000
ldi r16, (1<<CLKPCE)
ldi r17, (1<<CLKPS1) | (1<<CLKPS0)
out CLKPR, r16
out CLKPR, r17
.endif
.if clock == 8000000
ldi r16, (1<<CLKPCE)
ldi r17, 0
out CLKPR, r16
out CLKPR, r17
.endif
ret
; ---------------------------------------------------------------------------
; Called just before rebooting to bootloader. No arguments, no results.
systemSetBootSpeed:
ldi r16, (1<<CLKPCE)
ldi r17, (1<<CLKPS1) | (1<<CLKPS0)
out CLKPR, r16
out CLKPR, r17
ret
; ---------------------------------------------------------------------------
; Called on first time run, i.e. on system start. No arguments, no results.
onSystemStart:
ret
#ifdef MODULES_DS18B20
sendDs18b20Temp:
rcall Ds18b20_SendTemp
brcs sendDs18b20Temp_okay
; set timer to 1s to retry later
ldi xl, LOW(sramSendDs18b20TempTimer)
ldi xh, HIGH(sramSendDs18b20TempTimer)
rjmp Timer_SetValueTo1s
sendDs18b20Temp_okay:
ret
#endif
; ---------------------------------------------------------------------------
; Called every 100ms. Add your routine calls here. No arguments, no results.
onEvery100ms:
#ifdef MODULES_LED_SIMPLE
rcall LedSimple_Every100ms
#endif
#ifdef MODULES_REED
rcall REED_Every100ms
#endif
#ifdef MODULES_MOTION_LIGHT
rcall MotionLight_Every100ms
#endif
ret
; ---------------------------------------------------------------------------
; @routine onPacketReceived:
;
; Called after a packet was received via COM module. Add your routine calls here.
;
; The packet will be released in any case after return from this call.
;
; @return CFLAG set if message handled, cleared otherwise
; @param X pointer to received buffer
; @clobbers all
onPacketReceived:
; get msg code
adiw xh:xl, COM2_MSG_OFFS_CMD
ld r16, x
sbiw xh:xl, COM2_MSG_OFFS_CMD
#ifdef MODULES_MOTION_LIGHT
rcall MotionLight_OnPacketReceived
brcs onPacketReceived_end
#endif
#ifdef MODULES_SK6812
rcall SK6812_OnPacketReceived
brcs onPacketReceived_end
#endif
#ifdef MODULES_REED
rcall REED_OnPacketReceived
brcs onPacketReceived_end
#endif
#ifdef MODULES_COM
rcall CPRO_OnPacketReceived
brcs onPacketReceived_end
#endif
clc
onPacketReceived_end:
ret
; @end
#ifdef MODULES_SI7021
sendSI7021Humidity:
rcall SI7021_SendHumidity
brcs sendSI7021Humidity_okay
; set timer to 1s to retry later
ldi xl, LOW(sramTimerSI7021SendHumidity)
ldi xh, HIGH(sramTimerSI7021SendHumidity)
rjmp Timer_SetValueTo1s
sendSI7021Humidity_okay:
ret
sendSI7021Temp:
rcall SI7021_SendTemp
brcs sendSI7021Temp_okay
; set timer to 1s to retry later
ldi xl, LOW(sramTimerSI7021SendTemp)
ldi xh, HIGH(sramTimerSI7021SendTemp)
rjmp Timer_SetValueTo1s
sendSI7021Temp_okay:
ret
#endif

View File

@@ -0,0 +1,33 @@
<?xml?>
<gwbuild>
<target type="AvrHexFile" name="n19_firmware" >
<includes type="avrasm" >
-I $(builddir)
-I $(srcdir)
-I $(topsrcdir)/avr
-I $(topbuilddir)/avr
</includes>
<sources type="avrasm" >
main.asm
</sources>
</target>
<subdirs>
</subdirs>
<extradist>
</extradist>
</gwbuild>

View File

@@ -0,0 +1,176 @@
; ***************************************************************************
; copyright : (C) 2025 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
; ***************************************************************************
; Source file for LED controller node on AtTiny 85
;
; This is for the full system (i.e. not the boot loader).
; ***************************************************************************
.equ clock=1000000 ; Define the clock frequency
.nolist
.include "include/tn85def.inc" ; Define device ATtiny85
.list
.include "../defs.asm"
.include "devices/all/defs.asm"
.include "common/calls.asm"
.include "common/utils_wait.asm" ; wait macro
; ***************************************************************************
; defines
.equ NET_BUFFERS_NUM = 6
.equ NET_BUFFERS_SIZE = 32
; ---------------------------------------------------------------------------
; firmware settings including list of modules used
.equ FIRMWARE_VERSION_MAJOR = 0
.equ FIRMWARE_VERSION_MINOR = 0
.equ FIRMWARE_VERSION_PATCHLEVEL = 1
#define MODULES_CLOCK
#define MODULES_LED_SIMPLE
#define MODULES_NETWORK
#define MODULES_UART_BITBANG
#define MODULES_TWI_MASTER
#define MODULES_SI7021
#define MODULES_CCS811
#define APPS_NETWORK
#define APPS_REPORTSENSORS
#define APPS_STATS
; ---------------------------------------------------------------------------
; defines for modules
.equ VALUE_ID_SI7021_TEMP = 0x01
.equ VALUE_ID_SI7021_HUM = 0x02
.equ VALUE_ID_CO2 = 0x07
.equ VALUE_ID_TVOC = 0x08
.equ VALUE_ID_DEBUG = 0x7f
.equ VALUE_ID_LEDSIMPLE_TIMING = 0x88
; ***************************************************************************
; code segment
.cseg
.org 000000
; ---------------------------------------------------------------------------
; Reset and interrupt vectors
rjmp BOOTLOADER_ADDR ; Reset vector ; use this for flashed system
reti ; EXT_INT0
rjmp UART_BitBang_PcintIsr ; PCI0
reti ; OC1A
reti ; OVF1
reti ; OVF0
reti ; ERDY
reti ; ACI
reti ; ADCC
reti ; OC1B
rjmp baseTimerIrqOC0A ; OC0A
reti ; OC0B
reti ; WATCHDOG
reti ; USI_STR
reti ; USI_OVF
devInfoBlock: ; 12 bytes
devInfoManufacturer: .db 'A', 'Q', 'U', 'A'
devInfoId: .db DEVICEINFO_ID, 0
devInfoVersion: .db DEVICEINFO_VERSION, DEVICEINFO_REVISION ; version, revision
firmwareVersion: .db FIRMWARE_VARIANT_MAIN, FIRMWARE_VERSION_MAJOR
.db FIRMWARE_VERSION_MINOR, FIRMWARE_VERSION_PATCHLEVEL
firmwareStart:
rjmp main
; ---------------------------------------------------------------------------
; @routine onSystemStart
onSystemStart:
ret
; @end
; ---------------------------------------------------------------------------
; @routine onMessageReceived
;
; Called on every message received
onMessageReceived:
clc
ret
; @end
; ---------------------------------------------------------------------------
; @routine onEvery100ms
;
; Called every 100ms. Add your routine calls here. No arguments, no results.
onEvery100ms:
onEverySecond:
onEveryMinute:
onEveryHour:
onEveryDay:
ret
; @end
; ---------------------------------------------------------------------------
; @routine onEveryLoop
;
; Called on every loop (i.e. after awakening from sleep).
;
onEveryLoop:
ret
; @end
; ***************************************************************************
; includes
.include "devices/all/hw_tn85.asm"
.include "devices/all/includes.asm"
; ---------------------------------------------------------------------------
; defines for network interface
.equ netInterfaceData = uart_bitbang_iface

View File

@@ -2,44 +2,9 @@
<gwbuild>
<target type="AvrHexFile" name="n20_firmware" >
<includes type="avrasm" >
-I $(builddir)
-I $(srcdir)
-I $(topsrcdir)/avr
-I $(topbuilddir)/avr
</includes>
<sources type="avrasm" >
main.asm
</sources>
</target>
<target type="AvrHexFile" name="n20_boot" >
<includes type="avrasm" >
-I $(builddir)
-I $(srcdir)
-I $(topsrcdir)/avr
-I $(topbuilddir)/avr
</includes>
<sources type="avrasm" >
boot.asm
</sources>
</target>
<subdirs>
boot
main
</subdirs>
<extradist>
@@ -50,4 +15,3 @@
</gwbuild>

View File

@@ -0,0 +1,32 @@
<?xml?>
<gwbuild>
<target type="AvrHexFile" name="n20_boot" >
<includes type="avrasm" >
-I $(builddir)
-I $(srcdir)
-I $(topsrcdir)/avr
-I $(topbuilddir)/avr
</includes>
<sources type="avrasm" >
boot.asm
</sources>
</target>
<subdirs>
</subdirs>
<extradist>
</extradist>
</gwbuild>

View File

@@ -13,7 +13,7 @@
.list
.include "version.asm"
.include "./defs.asm"
.include "../defs.asm"
.include "devices/all/defs.asm"
.include "common/calls.asm"

View File

@@ -0,0 +1,33 @@
<?xml?>
<gwbuild>
<target type="AvrHexFile" name="n20_firmware" >
<includes type="avrasm" >
-I $(builddir)
-I $(srcdir)
-I $(topsrcdir)/avr
-I $(topbuilddir)/avr
</includes>
<sources type="avrasm" >
main.asm
</sources>
</target>
<subdirs>
</subdirs>
<extradist>
</extradist>
</gwbuild>

View File

@@ -31,7 +31,7 @@
.list
.include "version.asm"
.include "./defs.asm"
.include "../defs.asm"
.include "devices/all/defs.asm"
.include "common/calls.asm"
@@ -67,7 +67,7 @@
;#define MODULES_DS18B20
;#define MODULES_MOTION
;#define MODULES_TCRT1000
;#define MODULES_CCS811
#define MODULES_CCS811
#define APPS_NETWORK
;#define APPS_MOTION

View File

@@ -11,7 +11,11 @@
defs.asm
README
</extradist>
<data dist="true" install="$(datadir)/aqhome/devices/nodes">
aqua_n21.xml
</data>
</gwbuild>

View File

@@ -7,6 +7,7 @@
<values>
<value name="SI7021_TEMP" id="0x01" type="sensor" dataType="rational" modality="temperature" units="C" denom="100" />
<value name="SI7021_HUM" id="0x02" type="sensor" dataType="rational" modality="humidity" units="%" denom="1" />
<value name="ADC" id="0x03" type="sensor" dataType="uint16" denom="1" />
<value name="MOTION" id="0x07" type="sensor" dataType="rational" modality="motion" denom="1" />
<value name="DOOR" id="0x08" type="sensor" dataType="rational" modality="door" denom="1" />
@@ -18,10 +19,6 @@
<value name="stats_collision_errors" id="0xe5" type="sensor" dataType="uint16" denom="1" />
<value name="stats_busy_errors" id="0xe6" type="sensor" dataType="uint16" denom="1" />
<value name="stats_heap_used" id="0xe7" type="sensor" dataType="uint16" denom="1" />
<value name="stats_heap_free" id="0xe8" type="sensor" dataType="uint16" denom="1" />
<value name="stats_noram_errors" id="0xe9" type="sensor" dataType="uint16" denom="1" />
<value name="LEDTIMING" id="0x88" type="actor" dataType="uint16" />
</values>

View File

@@ -173,7 +173,6 @@ onMessageReceived:
onEvery100ms:
onEverySecond:
onEveryMinute:
onEveryHour:
onEveryDay:
ret
@@ -181,6 +180,14 @@ onEveryDay:
onEveryMinute:
lds r16, tcrt1kLastValue
ldi r17, VALUE_ID_ADC
ldi r22, AQHOME_VALUETYPE_UNKNOWN ; VALUE TYPE
rjmp Main_Send8BitValueReport
; ---------------------------------------------------------------------------
; @routine onEveryLoop
;

View File

@@ -5,6 +5,8 @@ N22
- Role: LED strip controller
- MCU: AtTiny85
- Connection: RJ45
- Predecessor: N16
- UART: uart_bitbang2
- Periphery:
- LED strip connection (SK6812)
- OWI interface

View File

@@ -5,6 +5,7 @@ N23
- Role: Air quality and climate sensors
- MCU: AtTiny84
- Connection: RJ45
- Predecessor: N19
- Periphery:
- PIR sensor (AMN31112)
- TWI interface

View File

@@ -20,10 +20,6 @@
<value name="stats_collision_errors" id="0xe5" type="sensor" dataType="uint16" denom="1" />
<value name="stats_busy_errors" id="0xe6" type="sensor" dataType="uint16" denom="1" />
<value name="stats_heap_used" id="0xe7" type="sensor" dataType="uint16" denom="1" />
<value name="stats_heap_free" id="0xe8" type="sensor" dataType="uint16" denom="1" />
<value name="stats_noram_errors" id="0xe9" type="sensor" dataType="uint16" denom="1" />
<value name="LEDTIMING" id="0x88" type="actor" dataType="uint16" />
</values>

View File

@@ -5,6 +5,7 @@ N24
- Role: Air quality and climate sensors
- MCU: AtTiny84
- Connection: RJ45
- Predecessor: N23, N19
- Periphery:
- PIR sensor (AMN31112)
- TWI interface

View File

@@ -11,6 +11,7 @@
<value name="SGP40_VALUE" id="0x08" type="sensor" dataType="rational" modality="tvoc" denom="1" />
<value name="SGP30_TVOC" id="0x09" type="sensor" dataType="rational" modality="tvoc" denom="1" />
<value name="SGP30_CO2" id="0x0a" type="sensor" dataType="rational" modality="co2" denom="1" />
<value name="LIGHT" id="0x0b" type="sensor" dataType="rational" modality="light" denom="1" />
<value name="stats_packets_in" id="0xe0" type="sensor" dataType="uint16" denom="1" />
<value name="stats_packets_out" id="0xe1" type="sensor" dataType="uint16" denom="1" />
@@ -20,10 +21,6 @@
<value name="stats_collision_errors" id="0xe5" type="sensor" dataType="uint16" denom="1" />
<value name="stats_busy_errors" id="0xe6" type="sensor" dataType="uint16" denom="1" />
<value name="stats_heap_used" id="0xe7" type="sensor" dataType="uint16" denom="1" />
<value name="stats_heap_free" id="0xe8" type="sensor" dataType="uint16" denom="1" />
<value name="stats_noram_errors" id="0xe9" type="sensor" dataType="uint16" denom="1" />
<value name="LEDTIMING" id="0x88" type="actor" dataType="uint16" />
</values>

View File

@@ -13,7 +13,7 @@
; AtTiny84
; --------
; VCC 1 14 GND
; AUX-PB0 PB0 2 13 PA0 AUX-PA0
; AUX-PB0 PB0 2 13 PA0 LUM
; PIR PB1 3 12 PA1 COM-DATA
; /RESET PB3 4 11 PA2 AUX-PA2
; PB2 5 10 PA3 LED
@@ -146,3 +146,14 @@
; ---------------------------------------------------------------------------
; Brightness
.equ BRIGHTNESS_ADC_PORT = PORTA ; adc0
.equ BRIGHTNESS_ADC_DDR = DDRA
.equ BRIGHTNESS_ADC_PIN = PORTA0
.equ BRIGHTNESS_ADC_MUX = 0

Some files were not shown because too many files have changed in this diff Show More