Merge branch 'mp-2025_07-improvr_uart_hw2'
This commit is contained in:
5
0BUILD
5
0BUILD
@@ -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.14" so_current="0" so_age="0" so_revision="14" 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
|
||||
|
||||
@@ -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
23
apps/aqhome-cgi/README
Normal 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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
84
apps/aqhome-cgi/modules/0BUILD
Normal file
84
apps/aqhome-cgi/modules/0BUILD
Normal 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>
|
||||
246
apps/aqhome-cgi/modules/mroot.c
Normal file
246
apps/aqhome-cgi/modules/mroot.c
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
27
apps/aqhome-cgi/modules/mroot.h
Normal file
27
apps/aqhome-cgi/modules/mroot.h
Normal 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
|
||||
|
||||
18
apps/aqhome-cgi/modules/mroot_p.h
Normal file
18
apps/aqhome-cgi/modules/mroot_p.h
Normal 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
|
||||
|
||||
291
apps/aqhome-cgi/modules/mservice.c
Normal file
291
apps/aqhome-cgi/modules/mservice.c
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
46
apps/aqhome-cgi/modules/mservice.h
Normal file
46
apps/aqhome-cgi/modules/mservice.h
Normal 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
|
||||
|
||||
27
apps/aqhome-cgi/modules/mservice_p.h
Normal file
27
apps/aqhome-cgi/modules/mservice_p.h
Normal 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
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
<?xml?>
|
||||
|
||||
<gwbuild>
|
||||
|
||||
<subdirs>
|
||||
uart
|
||||
ccs811
|
||||
en
|
||||
</subdirs>
|
||||
|
||||
</gwbuild>
|
||||
|
||||
13
apps/aqhome-cgi/modules/static/en/0BUILD
Normal file
13
apps/aqhome-cgi/modules/static/en/0BUILD
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml?>
|
||||
|
||||
<gwbuild>
|
||||
|
||||
<data dist="true" install="$(httpdatadir)/aqhome-cgi/static/en">
|
||||
header.html
|
||||
footer.html
|
||||
login.html
|
||||
</data>
|
||||
|
||||
|
||||
</gwbuild>
|
||||
|
||||
4
apps/aqhome-cgi/modules/static/en/footer.html
Normal file
4
apps/aqhome-cgi/modules/static/en/footer.html
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
17
apps/aqhome-cgi/modules/static/en/header.html
Normal file
17
apps/aqhome-cgi/modules/static/en/header.html
Normal 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>
|
||||
|
||||
25
apps/aqhome-cgi/modules/static/en/login.html
Normal file
25
apps/aqhome-cgi/modules/static/en/login.html
Normal 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>
|
||||
@@ -54,6 +54,10 @@
|
||||
<descr>Waiting for approval by admin</descr>
|
||||
</item>
|
||||
|
||||
<item name="active">
|
||||
<descr>User active</descr>
|
||||
</item>
|
||||
|
||||
</enum>
|
||||
|
||||
</enums>
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "aqhome-cgi/service/service.h"
|
||||
|
||||
|
||||
AQH_SERVICE *AQH_ServiceFiles_new(const char *baseFolder);
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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), ×tamp, &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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ void AQH_NodeServer_HandleGetNodes(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESS
|
||||
AQH_Endpoint_GetNextMessageId(ep), AQH_IpcMessage_GetMsgId(msg),
|
||||
niNext?0:AQH_MSGNODE_GETDEVICES_RSP_FLAGS_LASTMSG, ni);
|
||||
AQH_Endpoint_AddMsgOut(ep, outMsg);
|
||||
DBG_ERROR(NULL, "Messages in clients out queue: %d", AQH_Message_List_GetCount(AQH_Endpoint_GetMsgOutList(ep)));
|
||||
DBG_DEBUG(NULL, "Messages in clients out queue: %d", AQH_Message_List_GetCount(AQH_Endpoint_GetMsgOutList(ep)));
|
||||
ni=niNext;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include <aqhome/msg/node/m_value.h>
|
||||
#include <aqhome/msg/node/m_recvstats.h>
|
||||
#include <aqhome/msg/node/m_sendstats.h>
|
||||
#include <aqhome/msg/node/m_memstats.h>
|
||||
#include <aqhome/data/value.h>
|
||||
|
||||
#include <gwenhywfar/args.h>
|
||||
@@ -122,7 +123,9 @@ static void _forwardTtyMsgToBroker(AQH_OBJECT *o, AQH_NODE_SERVER *xo, const AQH
|
||||
static void _forwardValueMessageToBroker(AQH_OBJECT *o, AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg);
|
||||
static void _forwardDataFromSendStatsMsgToBroker(AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg);
|
||||
static void _forwardDataFromRecvStatsMsgToBroker(AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg);
|
||||
static void _forwardDataFromMemStatsMsgToBroker(AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg);
|
||||
static void _forwardTtyMsgToClients(AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg);
|
||||
static void _publishIntWithIdx(AQH_NODE_SERVER *xo, uint32_t uid, const char *vPath, int idx, int vModality, const char *vUnits, int v);
|
||||
static void _publishInt(AQH_NODE_SERVER *xo, uint32_t uid, const char *vPath, int vModality, const char *vUnits, int v);
|
||||
static void _publishDouble(AQH_NODE_SERVER *xo, uint32_t uid, const char *vPath, int vModality, const char *vUnits, double v);
|
||||
static void _setDeviceName(AQH_VALUE *value, uint32_t uid);
|
||||
@@ -827,9 +830,11 @@ void _forwardTtyMsgToBroker(AQH_OBJECT *o, AQH_NODE_SERVER *xo, const AQH_MESSAG
|
||||
|
||||
code=AQH_NodeMessage_GetMsgType(msg);
|
||||
switch(code) {
|
||||
case AQH_MSG_TYPE_VALUE_REPORT: _forwardValueMessageToBroker(o, xo, msg); break;
|
||||
case AQH_MSG_TYPE_VALUE_REPORT: _forwardValueMessageToBroker(o, xo, msg); break;
|
||||
case AQH_MSG_TYPE_COMSENDSTATS: _forwardDataFromSendStatsMsgToBroker(xo, msg); break;
|
||||
case AQH_MSG_TYPE_COMRECVSTATS: _forwardDataFromRecvStatsMsgToBroker(xo, msg); break;
|
||||
case AQH_MSG_TYPE_MEMSTATS: _forwardDataFromMemStatsMsgToBroker(xo, msg); break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
@@ -898,24 +903,21 @@ void _forwardDataFromSendStatsMsgToBroker(AQH_NODE_SERVER *xo, const AQH_MESSAGE
|
||||
packetsOutInt=AQH_SendStatsMessage_GetPacketsOut(msg);
|
||||
if (packetsOutInt) {
|
||||
uint32_t uid;
|
||||
double packetsOut;
|
||||
double collisions;
|
||||
double busy;
|
||||
double collisionsPercentage=0.0;
|
||||
double busyPercentage=0.0;
|
||||
int devNum;
|
||||
|
||||
uid=AQH_SendStatsMessage_GetUid(msg);
|
||||
packetsOut=/*(double)*/ packetsOutInt;
|
||||
collisions=/*(double)*/ AQH_SendStatsMessage_GetCollisions(msg);
|
||||
busy=/*(double)*/ AQH_SendStatsMessage_GetBusyErrors(msg);
|
||||
devNum=AQH_SendStatsMessage_GetInterface(msg);
|
||||
|
||||
collisionsPercentage=collisions*100.0/packetsOut;
|
||||
busyPercentage=busy*100.0/packetsOut;
|
||||
|
||||
_publishInt( xo, uid, "net/packetsOut", 0, NULL, packetsOutInt);
|
||||
_publishInt( xo, uid, "net/collisions", 0, NULL, (int) AQH_SendStatsMessage_GetCollisions(msg));
|
||||
_publishDouble(xo, uid, "net/collisionsPercent", 0, "%", collisionsPercentage);
|
||||
_publishDouble(xo, uid, "net/busyPercent", 0, "%", busyPercentage);
|
||||
if (devNum==0) {
|
||||
_publishInt(xo, uid, "net/packetsOut", 0, NULL, packetsOutInt);
|
||||
_publishInt(xo, uid, "net/collisions", 0, NULL, (int) AQH_SendStatsMessage_GetCollisions(msg));
|
||||
_publishInt(xo, uid, "net/busy", 0, NULL, (int) AQH_SendStatsMessage_GetBusyErrors(msg));
|
||||
}
|
||||
else {
|
||||
_publishIntWithIdx(xo, uid, "net/packetsOut", devNum, 0, NULL, packetsOutInt);
|
||||
_publishIntWithIdx(xo, uid, "net/collisions", devNum, 0, NULL, (int) AQH_SendStatsMessage_GetCollisions(msg));
|
||||
_publishIntWithIdx(xo, uid, "net/busy", devNum, 0, NULL, (int) AQH_SendStatsMessage_GetBusyErrors(msg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -928,30 +930,56 @@ void _forwardDataFromRecvStatsMsgToBroker(AQH_NODE_SERVER *xo, const AQH_MESSAGE
|
||||
packetsInInt=AQH_RecvStatsMessage_GetPacketsIn(msg);
|
||||
if (packetsInInt) {
|
||||
uint32_t uid;
|
||||
double packetsIn;
|
||||
double crcErrors;
|
||||
double ioErrors;
|
||||
double crcErrorsPercentage=0.0;
|
||||
double ioErrorsPercentage=0.0;
|
||||
int devNum;
|
||||
|
||||
uid=AQH_SendStatsMessage_GetUid(msg);
|
||||
packetsIn=/*(double)*/ packetsInInt;
|
||||
crcErrors=/*(double)*/AQH_RecvStatsMessage_GetCrcErrors(msg);
|
||||
ioErrors=/*(double)*/AQH_RecvStatsMessage_GetIoErrors(msg);
|
||||
uid=AQH_RecvStatsMessage_GetUid(msg);
|
||||
devNum=AQH_RecvStatsMessage_GetInterface(msg);
|
||||
|
||||
crcErrorsPercentage=crcErrors*100.0/packetsIn;
|
||||
ioErrorsPercentage=ioErrors*100.0/packetsIn;
|
||||
|
||||
_publishInt( xo, uid, "net/packetsIn", 0, NULL, packetsInInt);
|
||||
_publishInt( xo, uid, "net/crcerrors", 0, NULL, (int) AQH_RecvStatsMessage_GetCrcErrors(msg));
|
||||
_publishInt( xo, uid, "net/ioerrors", 0, NULL, (int) AQH_RecvStatsMessage_GetIoErrors(msg));
|
||||
_publishDouble(xo, uid, "net/crcerrorsPercent", 0, "%", crcErrorsPercentage);
|
||||
_publishDouble(xo, uid, "net/ioerrorsPercent", 0, "%", ioErrorsPercentage);
|
||||
if (devNum==0) {
|
||||
_publishInt(xo, uid, "net/packetsIn", 0, NULL, packetsInInt);
|
||||
_publishInt(xo, uid, "net/crcErrors", 0, NULL, (int) AQH_RecvStatsMessage_GetCrcErrors(msg));
|
||||
_publishInt(xo, uid, "net/ioErrors", 0, NULL, (int) AQH_RecvStatsMessage_GetIoErrors(msg));
|
||||
_publishInt(xo, uid, "net/nobufferErrors", 0, NULL, (int) AQH_RecvStatsMessage_GetNoBufferErrors(msg));
|
||||
_publishInt(xo, uid, "net/msgSizeErrors", 0, NULL, (int) AQH_RecvStatsMessage_GetMsgSizeErrors(msg));
|
||||
_publishInt(xo, uid, "net/missed", 0, NULL, (int) AQH_RecvStatsMessage_GetMissed(msg));
|
||||
}
|
||||
else {
|
||||
_publishIntWithIdx(xo, uid, "net/packetsIn", devNum, 0, NULL, packetsInInt);
|
||||
_publishIntWithIdx(xo, uid, "net/crcErrors", devNum, 0, NULL, (int) AQH_RecvStatsMessage_GetCrcErrors(msg));
|
||||
_publishIntWithIdx(xo, uid, "net/ioErrors", devNum, 0, NULL, (int) AQH_RecvStatsMessage_GetIoErrors(msg));
|
||||
_publishIntWithIdx(xo, uid, "net/nobufferErrors", devNum, 0, NULL, (int) AQH_RecvStatsMessage_GetNoBufferErrors(msg));
|
||||
_publishIntWithIdx(xo, uid, "net/msgSizeErrors", devNum, 0, NULL, (int) AQH_RecvStatsMessage_GetMsgSizeErrors(msg));
|
||||
_publishIntWithIdx(xo, uid, "net/missed", devNum, 0, NULL, (int) AQH_RecvStatsMessage_GetMissed(msg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _forwardDataFromMemStatsMsgToBroker(AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg)
|
||||
{
|
||||
uint32_t uid;
|
||||
|
||||
uid=AQH_MemStatsMessage_GetUid(msg);
|
||||
|
||||
_publishInt( xo, uid, "mem/buffersUsed", 0, NULL, AQH_MemStatsMessage_GetBuffersUsed(msg));
|
||||
_publishInt( xo, uid, "mem/maxBuffersUsed", 0, NULL, AQH_MemStatsMessage_GetMaxBuffersUsed(msg));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _publishIntWithIdx(AQH_NODE_SERVER *xo, uint32_t uid, const char *vPath, int idx, int vModality, const char *vUnits, int v)
|
||||
{
|
||||
GWEN_BUFFER *tbuf;
|
||||
|
||||
tbuf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
GWEN_Buffer_AppendArgs(tbuf, "%s%d", vPath, idx);
|
||||
_publishInt(xo, uid, GWEN_Buffer_GetStart(tbuf), vModality, vUnits, v);
|
||||
GWEN_Buffer_free(tbuf);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _publishInt(AQH_NODE_SERVER *xo, uint32_t uid, const char *vPath, int vModality, const char *vUnits, int v)
|
||||
{
|
||||
_publishDouble(xo, uid, vPath, vModality, vUnits, /*(double)*/ v);
|
||||
|
||||
@@ -37,9 +37,13 @@
|
||||
getdevices.h
|
||||
adddata.h
|
||||
getdatapoints.h
|
||||
getfirstdata.h
|
||||
getlastdata.h
|
||||
getperioddata.h
|
||||
setdata.h
|
||||
moddevice.h
|
||||
watch.h
|
||||
devicestate.h
|
||||
</headers>
|
||||
|
||||
<sources>
|
||||
@@ -49,9 +53,13 @@
|
||||
getdevices.c
|
||||
adddata.c
|
||||
getdatapoints.c
|
||||
getfirstdata.c
|
||||
getlastdata.c
|
||||
getperioddata.c
|
||||
setdata.c
|
||||
moddevice.c
|
||||
watch.c
|
||||
devicestate.c
|
||||
</sources>
|
||||
|
||||
<useTargets>
|
||||
|
||||
265
apps/aqhome-tool/data/devicestate.c
Normal file
265
apps/aqhome-tool/data/devicestate.c
Normal file
@@ -0,0 +1,265 @@
|
||||
/****************************************************************************
|
||||
* 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 "./devicestate.h"
|
||||
#include "../utils.h"
|
||||
|
||||
#include "aqhome/aqhome.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 <gwenhywfar/timestamp.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);
|
||||
static void _handleDevice(AQH_DATACLIENT *dc, const AQH_DEVICE *device);
|
||||
static void _handleValue(AQH_DATACLIENT *dc, const AQH_VALUE *value);
|
||||
static void _printDataPoints(const uint64_t *dataPoints, uint32_t numValues);
|
||||
static void _printSingleDataPoint(uint64_t timestamp, double data);
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* code
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int AQH_Tool_DeviceState(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, "device", 1, 1, "d", "device", I18S("device name"), NULL},
|
||||
{ A_ARG, A_CHAR, "valueName", 0, 1, "N", "valuename", I18S("Value name for device(e.g. LIGHT)"), NULL},
|
||||
{ A_ARG, A_INT, "numOfDatapoints", 0, 1, "n", NULL, I18S("Get up to n datapoints"), 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 *deviceName;
|
||||
AQH_DEVICE_LIST *deviceList;
|
||||
AQH_DEVICE *device;
|
||||
|
||||
dbLocalArgs=AQH_DataClient_GetDbLocalArgs(dc);
|
||||
deviceName=GWEN_DB_GetCharValue(dbLocalArgs, "device", 0, "*");
|
||||
|
||||
deviceList=AQH_DataClient_GetDevices(dc);
|
||||
if (deviceList==NULL) {
|
||||
DBG_ERROR(NULL, "Error getting devices");
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
device=AQH_Device_List_First(deviceList);
|
||||
while(device) {
|
||||
const char *s;
|
||||
|
||||
s=AQH_Device_GetNameForSystem(device);
|
||||
if (s && *s && -1!=GWEN_Text_ComparePattern(s, deviceName, 0)) {
|
||||
_handleDevice(dc, device);
|
||||
}
|
||||
|
||||
device=AQH_Device_List_Next(device);
|
||||
}
|
||||
|
||||
AQH_Device_List_free(deviceList);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleDevice(AQH_DATACLIENT *dc, const AQH_DEVICE *device)
|
||||
{
|
||||
AQH_VALUE_LIST *valueList;
|
||||
const char *devName;
|
||||
const char *roomName;
|
||||
const char *location;
|
||||
const char *descr;
|
||||
|
||||
devName=AQH_Device_GetNameForSystem(device);
|
||||
roomName=AQH_Device_GetRoomName(device);
|
||||
location=AQH_Device_GetLocation(device);
|
||||
descr=AQH_Device_GetDescription(device);
|
||||
|
||||
fprintf(stdout, "%s (room: %s, loc: %s, descr: %s)\n",
|
||||
devName,
|
||||
roomName?roomName:"--",
|
||||
location?location:"--",
|
||||
descr?descr:"--");
|
||||
valueList=AQH_DataClient_GetValues(dc, devName, 0);
|
||||
if (valueList) {
|
||||
const AQH_VALUE *value;
|
||||
|
||||
value=AQH_Value_List_First(valueList);
|
||||
while(value) {
|
||||
if (AQH_Value_GetValueType(value)==AQH_ValueType_Sensor)
|
||||
_handleValue(dc, value);
|
||||
value=AQH_Value_List_Next(value);
|
||||
}
|
||||
}
|
||||
|
||||
AQH_Value_List_free(valueList);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleValue(AQH_DATACLIENT *dc, const AQH_VALUE *value)
|
||||
{
|
||||
GWEN_DB_NODE *dbLocalArgs;
|
||||
const char *wantedValueName;
|
||||
const char *valueName;
|
||||
int numDataPoints;
|
||||
|
||||
dbLocalArgs=AQH_DataClient_GetDbLocalArgs(dc);
|
||||
numDataPoints=GWEN_DB_GetIntValue(dbLocalArgs, "numOfDatapoints", 0, 5);
|
||||
wantedValueName=GWEN_DB_GetCharValue(dbLocalArgs, "valueName", 0, "*");
|
||||
|
||||
valueName=AQH_Value_GetName(value);
|
||||
if (valueName &&
|
||||
-1==GWEN_Text_ComparePattern(valueName, "stats_*", 0) &&
|
||||
-1!=GWEN_Text_ComparePattern(valueName, wantedValueName, 0)) {
|
||||
const char *valueNameForSystem;
|
||||
uint64_t *dataPoints;
|
||||
uint64_t recvdNum;
|
||||
|
||||
valueNameForSystem=AQH_Value_GetNameForSystem(value);
|
||||
fprintf(stdout, " %s: ", valueName?valueName:"<empty>");
|
||||
|
||||
dataPoints=malloc(numDataPoints*sizeof(uint64_t)*2);
|
||||
|
||||
recvdNum=AQH_DataClient_GetLastData(dc, valueNameForSystem, dataPoints, numDataPoints);
|
||||
if (recvdNum>0)
|
||||
_printDataPoints(dataPoints, recvdNum);
|
||||
|
||||
free(dataPoints);
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _printDataPoints(const uint64_t *dataPoints, uint32_t numValues)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for(i=0; i<numValues; i++) {
|
||||
uint64_t timestamp;
|
||||
union {double f; uint64_t i;} u;
|
||||
|
||||
if (i)
|
||||
fprintf(stdout, " | ");
|
||||
timestamp=*(dataPoints++);
|
||||
u.i=*(dataPoints++);
|
||||
|
||||
_printSingleDataPoint(timestamp, u.f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _printSingleDataPoint(uint64_t timestamp, double data)
|
||||
{
|
||||
GWEN_TIMESTAMP *ts;
|
||||
|
||||
ts=GWEN_Timestamp_fromLocalTime((time_t) timestamp);
|
||||
if (ts)
|
||||
fprintf(stdout, "%lf (%04d/%02d/%02d-%02d:%02d:%02d)",
|
||||
data,
|
||||
GWEN_Timestamp_GetYear(ts),
|
||||
GWEN_Timestamp_GetMonth(ts),
|
||||
GWEN_Timestamp_GetDay(ts),
|
||||
GWEN_Timestamp_GetHour(ts),
|
||||
GWEN_Timestamp_GetMinute(ts),
|
||||
GWEN_Timestamp_GetSecond(ts));
|
||||
else
|
||||
fprintf(stdout, "%lf", data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
21
apps/aqhome-tool/data/devicestate.h
Normal file
21
apps/aqhome-tool/data/devicestate.h
Normal 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_DEVICESTATE_H
|
||||
#define AQHOME_TOOL_DEVICESTATE_H
|
||||
|
||||
|
||||
#include <gwenhywfar/db.h>
|
||||
|
||||
|
||||
|
||||
int AQH_Tool_DeviceState(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
153
apps/aqhome-tool/data/getfirstdata.c
Normal file
153
apps/aqhome-tool/data/getfirstdata.c
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
21
apps/aqhome-tool/data/getfirstdata.h
Normal file
21
apps/aqhome-tool/data/getfirstdata.h
Normal 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
|
||||
|
||||
153
apps/aqhome-tool/data/getlastdata.c
Normal file
153
apps/aqhome-tool/data/getlastdata.c
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
21
apps/aqhome-tool/data/getlastdata.h
Normal file
21
apps/aqhome-tool/data/getlastdata.h
Normal 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
|
||||
|
||||
167
apps/aqhome-tool/data/getperioddata.c
Normal file
167
apps/aqhome-tool/data/getperioddata.c
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
21
apps/aqhome-tool/data/getperioddata.h
Normal file
21
apps/aqhome-tool/data/getperioddata.h
Normal 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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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,9 +17,13 @@
|
||||
#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"
|
||||
#include "./data/devicestate.h"
|
||||
|
||||
#include <aqhome/api.h>
|
||||
#include <aqhome/aqhome.h>
|
||||
@@ -92,9 +96,13 @@ 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")),
|
||||
GWEN_FE_DAH("devicestate", AQH_Tool_DeviceState, I18N("Show state of devices")),
|
||||
GWEN_FE_END(),
|
||||
};
|
||||
const GWEN_FUNCS *func;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
14
aqhome-cgi.sh
Normal 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 "$@"
|
||||
@@ -69,6 +69,7 @@
|
||||
hexfile
|
||||
data
|
||||
events2
|
||||
dataclient
|
||||
</subdirs>
|
||||
|
||||
|
||||
@@ -79,6 +80,7 @@
|
||||
aqhhexfile
|
||||
aqhdata
|
||||
aqhevents2
|
||||
aqhdataclient
|
||||
</useTargets>
|
||||
|
||||
<libraries>
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
@@ -45,7 +45,8 @@ enum {
|
||||
AQH_ValueModality_Motion,
|
||||
AQH_ValueModality_Co2,
|
||||
AQH_ValueModality_TVOC,
|
||||
AQH_ValueModality_Stats
|
||||
AQH_ValueModality_Stats,
|
||||
AQH_ValueModality_Light
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
|
||||
#define AQH_STORAGE_DATAPOINTS_STEPS 128
|
||||
|
||||
#define AQH_STORAGE_MAXOPENFILES 128
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
@@ -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;
|
||||
@@ -601,6 +650,16 @@ AQH_DATAFILE *_getDataFileByValueId(AQH_STORAGE *sto, uint64_t valueId)
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error opening/creating datafile for valueId \"%lu\"", (unsigned long int) valueId);
|
||||
return NULL;
|
||||
}
|
||||
if (AQH_DataFile_List_GetCount(sto->dataFileList)>=AQH_STORAGE_MAXOPENFILES) {
|
||||
AQH_DATAFILE *dfLast;
|
||||
|
||||
dfLast=AQH_DataFile_List_Last(sto->dataFileList);
|
||||
if (dfLast) {
|
||||
AQH_DataFile_Close(dfLast);
|
||||
AQH_DataFile_List_Del(dfLast);
|
||||
AQH_DataFile_free(dfLast);
|
||||
}
|
||||
}
|
||||
DBG_DEBUG(AQH_LOGDOMAIN, "Adding datafile for valueId \"%lu\" to list", (unsigned long int) valueId);
|
||||
AQH_DataFile_List_Add(df, sto->dataFileList);
|
||||
}
|
||||
@@ -612,8 +671,17 @@ AQH_DATAFILE *_getDataFileByValueId(AQH_STORAGE *sto, uint64_t valueId)
|
||||
|
||||
AQH_DATAFILE *_findDataFileByValueId(const AQH_STORAGE *sto, uint64_t valueId)
|
||||
{
|
||||
if (sto && sto->dataFileList)
|
||||
return AQH_DataFile_List_GetByValueId(sto->dataFileList, valueId);
|
||||
if (sto && sto->dataFileList) {
|
||||
AQH_DATAFILE *df;
|
||||
|
||||
df=AQH_DataFile_List_GetByValueId(sto->dataFileList, valueId);
|
||||
if (df) {
|
||||
/* move to front of list */
|
||||
AQH_DataFile_List_Del(df);
|
||||
AQH_DataFile_List_Insert(df, sto->dataFileList);
|
||||
return df;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
|
||||
@@ -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
81
aqhome/dataclient/0BUILD
Normal 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
555
aqhome/dataclient/client.c
Normal 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_INFO(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, 1899);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
57
aqhome/dataclient/client.h
Normal file
57
aqhome/dataclient/client.h
Normal 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
|
||||
32
aqhome/dataclient/client_p.h
Normal file
32
aqhome/dataclient/client_p.h
Normal 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
|
||||
@@ -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 {
|
||||
|
||||
@@ -79,7 +79,7 @@ AQH_MESSAGE *AQH_IpcEndpoint_WaitForResponseMsg(AQH_OBJECT *ipcEndpoint, uint32_
|
||||
uint16_t code;
|
||||
|
||||
code=AQH_IpcMessage_GetCode(msg);
|
||||
DBG_ERROR(NULL, "Received unexpected message %d (%x), ignoring", code, code);
|
||||
DBG_DEBUG(NULL, "Received unexpected message %d (%x), ignoring", code, code);
|
||||
AQH_Message_free(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -176,17 +176,17 @@ int _handleSocketReady(AQH_OBJECT *o)
|
||||
{
|
||||
AQH_TCPD_OBJECT *xo;
|
||||
|
||||
DBG_INFO(NULL, "Socket ready");
|
||||
DBG_DEBUG(NULL, "Socket ready");
|
||||
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_TCPD_OBJECT, o);
|
||||
if (xo) {
|
||||
int clientSk;
|
||||
|
||||
clientSk=_acceptConnection(xo->fdSocket);
|
||||
if (clientSk<0) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "here (%d)", clientSk);
|
||||
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", clientSk);
|
||||
}
|
||||
else {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "New connection");
|
||||
DBG_NOTICE(AQH_LOGDOMAIN, "New connection");
|
||||
if (0==AQH_Object_EmitSignal(o, AQH_TCPD_OBJECT_SIGNAL_NEWCONN, clientSk, NULL)) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "New connection not handled");
|
||||
close(clientSk);
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
81
aqhome/msg/ipc/data/m_ipcd_getvalues.c
Normal file
81
aqhome/msg/ipc/data/m_ipcd_getvalues.c
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
36
aqhome/msg/ipc/data/m_ipcd_getvalues.h
Normal file
36
aqhome/msg/ipc/data/m_ipcd_getvalues.h
Normal 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
|
||||
@@ -62,6 +62,7 @@
|
||||
m_flashend.h
|
||||
m_flashready.h
|
||||
m_flashresponse.h
|
||||
m_range.h
|
||||
</headers>
|
||||
|
||||
|
||||
@@ -89,6 +90,7 @@
|
||||
m_flashend.c
|
||||
m_flashready.c
|
||||
m_flashresponse.c
|
||||
m_range.c
|
||||
</sources>
|
||||
|
||||
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
|
||||
|
||||
|
||||
#define AQH_MSG_OFFS_MEMSTATS_SECONDS 0 /* 4 bytes */
|
||||
#define AQH_MSG_OFFS_MEMSTATS_UID 4 /* 4 bytes */
|
||||
#define AQH_MSG_OFFS_MEMSTATS_UID 0 /* 4 bytes */
|
||||
#define AQH_MSG_OFFS_MEMSTATS_SECONDS 4 /* 4 bytes */
|
||||
#define AQH_MSG_OFFS_MEMSTATS_STACKUSAGE 8 /* 2 bytes */
|
||||
#define AQH_MSG_OFFS_MEMSTATS_BUFFERSUSED 10 /* 1 byte */
|
||||
#define AQH_MSG_OFFS_MEMSTATS_MAXBUFFERSUSED 11 /* 1 byte */
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "aqhome/msg/node/m_flashend.h"
|
||||
#include "aqhome/msg/node/m_flashready.h"
|
||||
#include "aqhome/msg/node/m_flashresponse.h"
|
||||
#include "aqhome/msg/node/m_range.h"
|
||||
|
||||
#include <gwenhywfar/text.h>
|
||||
|
||||
@@ -212,6 +213,7 @@ const char *AQH_NodeMessage_MsgTypeToChar(uint8_t i)
|
||||
case AQH_MSG_TYPE_CLAIM_ADDRESS: return "ClaimAddress";
|
||||
case AQH_MSG_TYPE_DENY_ADDRESS: return "DenyAddress";
|
||||
case AQH_MSG_TYPE_ADDRESS_RANGE: return "Range";
|
||||
case AQH_MSG_TYPE_REENUM: return "Reenum";
|
||||
|
||||
case AQH_MSG_TYPE_FLASH_START: return "FlashStart";
|
||||
case AQH_MSG_TYPE_FLASH_END: return "FlashEnd";
|
||||
@@ -246,6 +248,8 @@ void AQH_NodeMessage_DumpSpecificToBuffer(const AQH_MESSAGE *msg, GWEN_BUFFER *d
|
||||
case AQH_MSG_TYPE_HAVE_ADDRESS: AQH_AddrMessage_DumpToBuffer(msg, dbuf, sText); break;
|
||||
case AQH_MSG_TYPE_CLAIM_ADDRESS: AQH_AddrMessage_DumpToBuffer(msg, dbuf, sText); break;
|
||||
case AQH_MSG_TYPE_DENY_ADDRESS: AQH_AddrMessage_DumpToBuffer(msg, dbuf, sText); break;
|
||||
case AQH_MSG_TYPE_ADDRESS_RANGE: AQH_RangeMessage_DumpToBuffer(msg, dbuf, sText); break;
|
||||
case AQH_MSG_TYPE_REENUM: AQH_RangeMessage_DumpToBuffer(msg, dbuf, sText); break;
|
||||
|
||||
case AQH_MSG_TYPE_FLASH_START: AQH_FlashStartMessage_DumpToBuffer(msg, dbuf, sText); break;
|
||||
case AQH_MSG_TYPE_FLASH_END: AQH_FlashEndMessage_DumpToBuffer(msg, dbuf, sText); break;
|
||||
@@ -266,7 +270,6 @@ void AQH_NodeMessage_DumpSpecificToBuffer(const AQH_MESSAGE *msg, GWEN_BUFFER *d
|
||||
|
||||
case AQH_MSG_TYPE_DEBUG:
|
||||
case AQH_MSG_TYPE_TWIBUSMEMBER:
|
||||
case AQH_MSG_TYPE_ADDRESS_RANGE:
|
||||
default: AQH_NodeMessage_DumpToBuffer(msg, dbuf, sText); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
|
||||
#define AQH_MSG_TYPE_PING 10
|
||||
#define AQH_MSG_TYPE_PONG 11
|
||||
#define AQH_MSG_TYPE_COMSENDSTATS 20
|
||||
#define AQH_MSG_TYPE_COMRECVSTATS 21
|
||||
#define AQH_MSG_TYPE_COMSENDSTATS 22
|
||||
#define AQH_MSG_TYPE_COMRECVSTATS 23
|
||||
#define AQH_MSG_TYPE_TWIBUSMEMBER 30
|
||||
#define AQH_MSG_TYPE_DEBUG 40
|
||||
#define AQH_MSG_TYPE_VALUE 50 /* deprecated */
|
||||
@@ -40,6 +40,7 @@
|
||||
#define AQH_MSG_TYPE_CLAIM_ADDRESS 62
|
||||
#define AQH_MSG_TYPE_DENY_ADDRESS 63
|
||||
#define AQH_MSG_TYPE_ADDRESS_RANGE 64
|
||||
#define AQH_MSG_TYPE_REENUM 65
|
||||
|
||||
#define AQH_MSG_TYPE_FLASH_START 70
|
||||
#define AQH_MSG_TYPE_FLASH_END 71
|
||||
|
||||
61
aqhome/msg/node/m_range.c
Normal file
61
aqhome/msg/node/m_range.c
Normal file
@@ -0,0 +1,61 @@
|
||||
/****************************************************************************
|
||||
* 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/node/m_range.h"
|
||||
#include "aqhome/msg/node/m_node.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
#define AQH_MSG_OFFS_RANGE_UID 0 /* 4 bytes */
|
||||
#define AQH_MSG_OFFS_RANGE_BEGIN 4 /* 1 bytes */
|
||||
#define AQH_MSG_OFFS_RANGE_END 5 /* 1 bytes */
|
||||
|
||||
|
||||
|
||||
uint32_t AQH_RangeMessage_GetUid(const AQH_MESSAGE *msg)
|
||||
{
|
||||
return AQH_Message_ReadUint32At(msg, AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_RANGE_UID, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint8_t AQH_RangeMessage_GetRangeBegin(const AQH_MESSAGE *msg)
|
||||
{
|
||||
return AQH_Message_ReadUint8At(msg, AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_RANGE_BEGIN, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint8_t AQH_RangeMessage_GetRangeEnd(const AQH_MESSAGE *msg)
|
||||
{
|
||||
return AQH_Message_ReadUint8At(msg, AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_RANGE_END, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_RangeMessage_DumpToBuffer(const AQH_MESSAGE *msg, GWEN_BUFFER *dbuf, const char *sText)
|
||||
{
|
||||
GWEN_Buffer_AppendArgs(dbuf,
|
||||
"0x%02x->0x%02x: RANGE(%s) %s (uid=0x%08x, begin=0x%x, end=0x%x)\n",
|
||||
AQH_NodeMessage_GetSourceAddress(msg),
|
||||
AQH_NodeMessage_GetDestAddress(msg),
|
||||
AQH_NodeMessage_MsgTypeToChar(AQH_NodeMessage_GetMsgType(msg)),
|
||||
sText,
|
||||
(unsigned int) AQH_RangeMessage_GetUid(msg),
|
||||
AQH_RangeMessage_GetRangeBegin(msg),
|
||||
AQH_RangeMessage_GetRangeEnd(msg));
|
||||
}
|
||||
|
||||
|
||||
30
aqhome/msg/node/m_range.h
Normal file
30
aqhome/msg/node/m_range.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/****************************************************************************
|
||||
* 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_RANGE_H
|
||||
#define AQH_M_RANGE_H
|
||||
|
||||
|
||||
#include <aqhome/api.h>
|
||||
#include <aqhome/ipc2/message.h>
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
/* This message is used for message types ClaimAddr, DenyAddr, HaveAddr */
|
||||
|
||||
AQHOME_API uint32_t AQH_RangeMessage_GetUid(const AQH_MESSAGE *msg);
|
||||
AQHOME_API uint8_t AQH_RangeMessage_GetAddr(const AQH_MESSAGE *msg);
|
||||
AQHOME_API uint8_t AQH_RangeMessage_GetRangeBegin(const AQH_MESSAGE *msg);
|
||||
AQHOME_API uint8_t AQH_RangeMessage_GetRangeEnd(const AQH_MESSAGE *msg);
|
||||
|
||||
AQHOME_API void AQH_RangeMessage_DumpToBuffer(const AQH_MESSAGE *msg, GWEN_BUFFER *dbuf, const char *sText);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -18,13 +18,21 @@
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
#define AQH_MSG_OFFS_RECVSTATS_UID 0 /* 4 bytes */
|
||||
#define AQH_MSG_OFFS_RECVSTATS_PACKETSIN 4 /* 2 bytes */
|
||||
#define AQH_MSG_OFFS_RECVSTATS_CRCERRORS 6 /* 2 bytes */
|
||||
#define AQH_MSG_OFFS_RECVSTATS_IOERRORS 8 /* 2 bytes */
|
||||
#define AQH_MSG_OFFS_RECVSTATS_NOBUFFER 10 /* 2 bytes */
|
||||
#define AQH_MSG_OFFS_RECVSTATS_HANDLED 12 /* 2 bytes */
|
||||
#define AQH_MSG_OFFS_RECVSTATS_MISSED 14 /* 2 bytes */
|
||||
#define AQH_MSG_OFFS_RECVSTATS_UID 0 /* 4 bytes */
|
||||
#define AQH_MSG_OFFS_RECVSTATS_IFACE 4 /* 1 byte */
|
||||
#define AQH_MSG_OFFS_RECVSTATS_PACKETSIN 5 /* 2 bytes */
|
||||
#define AQH_MSG_OFFS_RECVSTATS_CRCERRORS 7 /* 2 bytes */
|
||||
#define AQH_MSG_OFFS_RECVSTATS_IOERRORS 9 /* 2 bytes */
|
||||
#define AQH_MSG_OFFS_RECVSTATS_NOBUFFER 11 /* 2 bytes */
|
||||
#define AQH_MSG_OFFS_RECVSTATS_MSGSIZEERRORS 13 /* 2 bytes */
|
||||
#define AQH_MSG_OFFS_RECVSTATS_MISSED 15 /* 2 bytes */
|
||||
|
||||
|
||||
|
||||
uint8_t AQH_RecvStatsMessage_GetInterface(const AQH_MESSAGE *msg)
|
||||
{
|
||||
return AQH_Message_ReadUint8At(msg, AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_RECVSTATS_IFACE, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -63,9 +71,9 @@ uint16_t AQH_RecvStatsMessage_GetNoBufferErrors(const AQH_MESSAGE *msg)
|
||||
|
||||
|
||||
|
||||
uint16_t AQH_RecvStatsMessage_GetHandled(const AQH_MESSAGE *msg)
|
||||
uint16_t AQH_RecvStatsMessage_GetMsgSizeErrors(const AQH_MESSAGE *msg)
|
||||
{
|
||||
return AQH_Message_ReadUint16At(msg, AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_RECVSTATS_HANDLED, 0);
|
||||
return AQH_Message_ReadUint16At(msg, AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_RECVSTATS_MSGSIZEERRORS, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -80,17 +88,18 @@ uint16_t AQH_RecvStatsMessage_GetMissed(const AQH_MESSAGE *msg)
|
||||
void AQH_RecvStatsMessage_DumpToBuffer(const AQH_MESSAGE *msg, GWEN_BUFFER *dbuf, const char *sText)
|
||||
{
|
||||
GWEN_Buffer_AppendArgs(dbuf,
|
||||
"0x%02x->0x%02x: RECVSTATS %s "
|
||||
"(uid=0x%08x, in=%d, crc errs=%d, io errs=%d, nobuf errs=%d, handled=%d, missed=%d)\n",
|
||||
"0x%02x->0x%02x: RECVSTATS %s"
|
||||
"(uid=0x%08x, dev=%d, in=%d, eCrc=%d, eIo=%d, eNobuf=%d, eMsgSize=%d, eMissed=%d)\n",
|
||||
AQH_NodeMessage_GetSourceAddress(msg),
|
||||
AQH_NodeMessage_GetDestAddress(msg),
|
||||
sText,
|
||||
(unsigned int) AQH_RecvStatsMessage_GetUid(msg),
|
||||
AQH_RecvStatsMessage_GetInterface(msg),
|
||||
AQH_RecvStatsMessage_GetPacketsIn(msg),
|
||||
AQH_RecvStatsMessage_GetCrcErrors(msg),
|
||||
AQH_RecvStatsMessage_GetIoErrors(msg),
|
||||
AQH_RecvStatsMessage_GetNoBufferErrors(msg),
|
||||
AQH_RecvStatsMessage_GetHandled(msg),
|
||||
AQH_RecvStatsMessage_GetMsgSizeErrors(msg),
|
||||
AQH_RecvStatsMessage_GetMissed(msg));
|
||||
}
|
||||
|
||||
|
||||
@@ -17,12 +17,13 @@
|
||||
|
||||
|
||||
|
||||
AQHOME_API uint8_t AQH_RecvStatsMessage_GetInterface(const AQH_MESSAGE *msg);
|
||||
AQHOME_API uint32_t AQH_RecvStatsMessage_GetUid(const AQH_MESSAGE *msg);
|
||||
AQHOME_API uint16_t AQH_RecvStatsMessage_GetPacketsIn(const AQH_MESSAGE *msg);
|
||||
AQHOME_API uint16_t AQH_RecvStatsMessage_GetCrcErrors(const AQH_MESSAGE *msg);
|
||||
AQHOME_API uint16_t AQH_RecvStatsMessage_GetIoErrors(const AQH_MESSAGE *msg);
|
||||
AQHOME_API uint16_t AQH_RecvStatsMessage_GetNoBufferErrors(const AQH_MESSAGE *msg);
|
||||
AQHOME_API uint16_t AQH_RecvStatsMessage_GetHandled(const AQH_MESSAGE *msg);
|
||||
AQHOME_API uint16_t AQH_RecvStatsMessage_GetMsgSizeErrors(const AQH_MESSAGE *msg);
|
||||
AQHOME_API uint16_t AQH_RecvStatsMessage_GetMissed(const AQH_MESSAGE *msg);
|
||||
|
||||
AQHOME_API void AQH_RecvStatsMessage_DumpToBuffer(const AQH_MESSAGE *msg, GWEN_BUFFER *dbuf, const char *sText);
|
||||
|
||||
@@ -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.
|
||||
@@ -19,9 +19,17 @@
|
||||
|
||||
|
||||
#define AQH_MSG_OFFS_SENDSTATS_UID 0 /* 4 bytes */
|
||||
#define AQH_MSG_OFFS_SENDSTATS_PACKETSOUT 4 /* 2 bytes */
|
||||
#define AQH_MSG_OFFS_SENDSTATS_COLLISIONS 6 /* 2 bytes */
|
||||
#define AQH_MSG_OFFS_SENDSTATS_BUSY 8 /* 2 bytes */
|
||||
#define AQH_MSG_OFFS_SENDSTATS_IFACE 4 /* 1 byte */
|
||||
#define AQH_MSG_OFFS_SENDSTATS_PACKETSOUT 5 /* 2 bytes */
|
||||
#define AQH_MSG_OFFS_SENDSTATS_COLLISIONS 7 /* 2 bytes */
|
||||
#define AQH_MSG_OFFS_SENDSTATS_BUSY 9 /* 2 bytes */
|
||||
|
||||
|
||||
|
||||
uint8_t AQH_SendStatsMessage_GetInterface(const AQH_MESSAGE *msg)
|
||||
{
|
||||
return AQH_Message_ReadUint8At(msg, AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_SENDSTATS_IFACE, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -57,11 +65,12 @@ void AQH_SendStatsMessage_DumpToBuffer(const AQH_MESSAGE *msg, GWEN_BUFFER *dbuf
|
||||
{
|
||||
if (msg)
|
||||
GWEN_Buffer_AppendArgs(dbuf,
|
||||
"0x%02x->0x%02x: SENDSTATS %s (uid=0x%08x, out=%d, collisions=%d, busy line=%d)\n",
|
||||
"0x%02x->0x%02x: SENDSTATS %s (uid=0x%08x, dev=%d, out=%d, collisions=%d, busy line=%d)\n",
|
||||
AQH_NodeMessage_GetSourceAddress(msg),
|
||||
AQH_NodeMessage_GetDestAddress(msg),
|
||||
sText,
|
||||
(unsigned int) AQH_SendStatsMessage_GetUid(msg),
|
||||
AQH_SendStatsMessage_GetInterface(msg),
|
||||
AQH_SendStatsMessage_GetPacketsOut(msg),
|
||||
AQH_SendStatsMessage_GetCollisions(msg),
|
||||
AQH_SendStatsMessage_GetBusyErrors(msg));
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
|
||||
|
||||
AQHOME_API uint8_t AQH_SendStatsMessage_GetInterface(const AQH_MESSAGE *msg);
|
||||
AQHOME_API uint32_t AQH_SendStatsMessage_GetUid(const AQH_MESSAGE *msg);
|
||||
AQHOME_API uint16_t AQH_SendStatsMessage_GetPacketsOut(const AQH_MESSAGE *msg);
|
||||
AQHOME_API uint16_t AQH_SendStatsMessage_GetCollisions(const AQH_MESSAGE *msg);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
network
|
||||
reportsensors
|
||||
stats
|
||||
router
|
||||
hub
|
||||
forwarder
|
||||
</subdirs>
|
||||
|
||||
<extradist>
|
||||
|
||||
@@ -3,15 +3,13 @@
|
||||
<gwbuild>
|
||||
|
||||
<subdirs>
|
||||
boot
|
||||
main
|
||||
</subdirs>
|
||||
|
||||
<extradist>
|
||||
defs.asm
|
||||
README
|
||||
main.asm
|
||||
</extradist>
|
||||
|
||||
|
||||
</gwbuild>
|
||||
|
||||
|
||||
359
avr/apps/forwarder/main.asm
Normal file
359
avr/apps/forwarder/main.asm
Normal file
@@ -0,0 +1,359 @@
|
||||
; ***************************************************************************
|
||||
; 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. *
|
||||
; ***************************************************************************
|
||||
|
||||
|
||||
|
||||
; ***************************************************************************
|
||||
; defines
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; network interfaces
|
||||
|
||||
.equ NETDEV0_IFACENUM = 1
|
||||
.equ NETDEV1_IFACENUM = 2
|
||||
|
||||
|
||||
|
||||
; ***************************************************************************
|
||||
; data
|
||||
|
||||
.dseg
|
||||
|
||||
; nothing so far
|
||||
|
||||
|
||||
|
||||
; ***************************************************************************
|
||||
; code
|
||||
|
||||
.cseg
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine AppForwarder_Init @global
|
||||
|
||||
AppForwarder_Init:
|
||||
; set interface number for NETDEV0
|
||||
ldi r16, NETDEV0_IFACENUM
|
||||
sts netInterfaceData+NET_IFACE_OFFS_IFACENUM, r16
|
||||
; set interface number for NETDEV1
|
||||
ldi r16, NETDEV1_IFACENUM
|
||||
sts netInterfaceData2+NET_IFACE_OFFS_IFACENUM, r16
|
||||
sec
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine AppForwarder_EveryDay @global
|
||||
;
|
||||
; @clobbers R16, R17, X
|
||||
|
||||
AppForwarder_EveryDay:
|
||||
ldi yl, LOW(netInterfaceData)
|
||||
ldi yh, HIGH(netInterfaceData)
|
||||
bigcall NET_Interface_ResetStats ; (R16, R17, X)
|
||||
|
||||
ldi yl, LOW(netInterfaceData2)
|
||||
ldi yh, HIGH(netInterfaceData2)
|
||||
bigcall NET_Interface_ResetStats ; (R16, R17, X)
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine AppForwarder_Run @global
|
||||
;
|
||||
; Read messages from either interface and forward to the other one.
|
||||
|
||||
AppForwarder_Run:
|
||||
rjmp appForwarderCheckRecvdMsg
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appForwarderCheckRecvdMsg
|
||||
;
|
||||
; Read messages from either interface and forward to the other one.
|
||||
; @return CFLAG set if something done, cleared otherwise
|
||||
; @clobbers any
|
||||
|
||||
appForwarderCheckRecvdMsg:
|
||||
rcall NET_PeekNextIncomingMsgNum ; check read queue (bufNum->r16)
|
||||
brcc appForwarderCheckRecvdMsg_ret ; no msg, jmp
|
||||
rcall NET_Buffer_Locate ; (R17)
|
||||
push r16
|
||||
ld r16, X ; read buffer header
|
||||
andi r16, 0x0f ; keep interface number (in low nibble)
|
||||
rcall appForwarderGetDeviceByIfaceNum ; Y=src interface (R17)
|
||||
pop r16
|
||||
brcc appForwarderCheckRecvdMsg_ret ; interface not found
|
||||
adiw xh:xl, 1 ; point to message begin
|
||||
|
||||
push r16
|
||||
rcall appForwarderHandleMsgAnyDev ; check for message we should handle (ping etc)
|
||||
pop r16
|
||||
|
||||
; let system handle incoming messages
|
||||
push r16
|
||||
rcall appForwarderLetSysHandleMsg
|
||||
pop r16
|
||||
|
||||
; forward to other interface
|
||||
ldd r17, Y+NET_IFACE_OFFS_IFACENUM
|
||||
rcall appForwarderSendToOtherDev
|
||||
brcc appForwarderCheckRecvdMsg_ret ; could not add, jmp
|
||||
rcall NET_GetNextIncomingMsgNum ; take off the queue
|
||||
sec
|
||||
appForwarderCheckRecvdMsg_ret:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appForwarderHandleMsgAnyDev @global
|
||||
;
|
||||
; @param Y pointer to source interface for the message
|
||||
; @param X pointer to received message
|
||||
; @return CFLAG set if msg handled, cleared otherwise
|
||||
; @clobbers any, !X
|
||||
|
||||
appForwarderHandleMsgAnyDev:
|
||||
push xl
|
||||
push xh
|
||||
rcall appForwarderHandleMsgAnyDev_savedX
|
||||
pop xh
|
||||
pop xl
|
||||
rjmp appForwarderHandleMsgAnyDev_end
|
||||
appForwarderHandleMsgAnyDev_savedX:
|
||||
adiw xh:xl, NETMSG_OFFS_CMD ; maybe move ping/reboot handling to all/main.asm?
|
||||
ld r16, X
|
||||
sbiw xh:xl, NETMSG_OFFS_CMD
|
||||
cpi r16, NETMSG_CMD_REBOOT_REQUEST
|
||||
breq appForwarderHandleMsgAnyDev_handleRebootMsg
|
||||
cpi r16, NETMSG_CMD_PING
|
||||
breq appForwarderHandleMsgAnyDev_handlePingMsg
|
||||
cpi r16, NETMSG_CMD_CLAIM_ADDRESS
|
||||
breq appForwarderHandleMsgAnyDev_handleClaimAddr
|
||||
rjmp appForwarderHandleMsgAnyDev_clcRet
|
||||
appForwarderHandleMsgAnyDev_handleRebootMsg:
|
||||
rcall appForwarderHandleRebootRequest
|
||||
ret
|
||||
appForwarderHandleMsgAnyDev_handlePingMsg:
|
||||
rcall appForwarderHandlePingRequest
|
||||
clc
|
||||
ret
|
||||
appForwarderHandleMsgAnyDev_handleClaimAddr:
|
||||
rcall appForwarderHandleClaimAddrRequest
|
||||
clc
|
||||
ret
|
||||
appForwarderHandleMsgAnyDev_clcRet:
|
||||
clc
|
||||
appForwarderHandleMsgAnyDev_end:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appForwarderHandleClaimAddrRequest
|
||||
;
|
||||
; @param X pointer to received message
|
||||
; @param Y pointer to source interface for the message
|
||||
; @clobbers
|
||||
|
||||
appForwarderHandleClaimAddrRequest:
|
||||
rcall NETMSG_Address_Read ; R18=cmd, R19=addr(R18, R19)
|
||||
lds r16, netInterfaceData+NET_IFACE_OFFS_ADDRESS
|
||||
cp r19, r16
|
||||
brne appForwarderHandleClaimAddrRequest_ret
|
||||
ldi r18, NETMSG_CMD_DENY_ADDRESS ; deny addr
|
||||
rcall appForwarderSendAddrMsg ; (R16, R17, R18, R19, R20, R21, X, Y)
|
||||
appForwarderHandleClaimAddrRequest_ret:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appForwarderSendAddrMsg
|
||||
;
|
||||
; @param R18 command
|
||||
; @param R19 address to send
|
||||
; @param Y pointer to interface to send to
|
||||
; @clobbers R16 (R17, R18, R19, R20, R21, X, Y)
|
||||
|
||||
appForwarderSendAddrMsg:
|
||||
bigcall NET_Buffer_Alloc ; (R16, R17, X)
|
||||
brcc appForwarderSendAddrMsg_end
|
||||
push r16
|
||||
adiw xh:xl, 1
|
||||
bigcall NETMSG_Address_Write ; (R16, R17, R18, R19, R20, R21)
|
||||
sbiw xh:xl, 1
|
||||
pop r16
|
||||
bigcall NET_Interface_AddOrReleaseOutMsg ; (R16, R17, R18, X)
|
||||
appForwarderSendAddrMsg_end:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appForwarderHandleRebootRequest
|
||||
;
|
||||
; Doesn't return if reboot msg is valid.
|
||||
;
|
||||
; @param X pointer to received message
|
||||
|
||||
appForwarderHandleRebootRequest:
|
||||
rcall NETMSG_RebootRequestRead
|
||||
brcc appForwarderHandleRebootRequest_end
|
||||
; reboot
|
||||
cli
|
||||
bigjmp BOOTLOADER_ADDR
|
||||
appForwarderHandleRebootRequest_end:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appForwarderHandlePingRequest
|
||||
;
|
||||
; @param X pointer to received message
|
||||
; @param Y pointer to source interface for the message
|
||||
|
||||
appForwarderHandlePingRequest:
|
||||
ld r17, X
|
||||
lds r16, (netInterfaceData+NET_IFACE_OFFS_ADDRESS)
|
||||
cp r16, r17
|
||||
breq appForwarderHandlePingRequest_forMe
|
||||
cpi r17, 0xff
|
||||
breq appForwarderHandlePingRequest_forMe
|
||||
clc
|
||||
rjmp appForwarderHandlePingRequest_end
|
||||
appForwarderHandlePingRequest_forMe:
|
||||
adiw xh:xl, NETMSG_OFFS_SRCADDR
|
||||
ld r17, X
|
||||
sbiw xh:xl, NETMSG_OFFS_SRCADDR
|
||||
push r17
|
||||
bigcall NET_Buffer_Alloc ; (R16, R17, X)
|
||||
pop r17
|
||||
brcc appForwarderHandlePingRequest_end ; jmp on error
|
||||
push r16 ; buffer num
|
||||
mov r16, r17 ; DEST addr
|
||||
adiw xh:xl, 1
|
||||
bigcall NETMSG_Pong_Write ; (R16, R17, R18, R19, R20, X)
|
||||
sbiw xh:xl, 1
|
||||
pop r16 ; buffer num
|
||||
bigcall NET_Interface_AddOrReleaseOutMsg ; (R16, R17, R18, X)
|
||||
appForwarderHandlePingRequest_end:
|
||||
ret
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appForwarderLetSysHandleMsg
|
||||
;
|
||||
; @param X pointer to msg to handle (point behind the buffer header!)
|
||||
; @param Y pointer to source interface for the message
|
||||
; @clobbers any, !X
|
||||
|
||||
appForwarderLetSysHandleMsg:
|
||||
ld r16, X
|
||||
cpi r16, 0xff
|
||||
breq appForwarderLetSysHandleMsg_forMe
|
||||
lds r17, netInterfaceData+NET_IFACE_OFFS_ADDRESS
|
||||
cp r16, r17
|
||||
brne appForwarderLetSysHandleMsg_end
|
||||
appForwarderLetSysHandleMsg_forMe:
|
||||
push xl
|
||||
push xh
|
||||
rcall onMessageReceived
|
||||
pop xh
|
||||
pop xl
|
||||
push xl
|
||||
push xh
|
||||
rcall mainModulesOnPacketReceived
|
||||
pop xh
|
||||
pop xl
|
||||
push xl
|
||||
push xh
|
||||
rcall mainAppsOnPacketReceived
|
||||
pop xh
|
||||
pop xl
|
||||
appForwarderLetSysHandleMsg_end:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appForwarderSendToOtherDev
|
||||
; @param r16 buffer num
|
||||
; @param r17 src interface num
|
||||
|
||||
appForwarderSendToOtherDev:
|
||||
ldi yl, LOW(netInterfaceData)
|
||||
ldi yh, HIGH(netInterfaceData)
|
||||
ldd r18, Y+NET_IFACE_OFFS_IFACENUM
|
||||
andi r18, 0x0f
|
||||
cp r18, r17
|
||||
breq appForwarderSendToAllDevsBut_check2
|
||||
bigcall NET_Interface_AddOutgoingMsgNum ; (R17, R18, X)
|
||||
rjmp appForwarderSendToOtherDev_ret
|
||||
appForwarderSendToAllDevsBut_check2:
|
||||
ldi yl, LOW(netInterfaceData2)
|
||||
ldi yh, HIGH(netInterfaceData2)
|
||||
ldd r18, Y+NET_IFACE_OFFS_IFACENUM
|
||||
andi r18, 0x0f
|
||||
cp r18, r17
|
||||
breq appForwarderSendToOtherDev_ret
|
||||
bigcall NET_Interface_AddOutgoingMsgNum ; (R17, R18, X)
|
||||
appForwarderSendToOtherDev_ret:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appForwarderGetDeviceByIfaceNum
|
||||
;
|
||||
; @param r16 interface number
|
||||
; @return CFLAG set if interface found (cleared otherwise)
|
||||
; @return Y pointer to interface with given number
|
||||
; @clobbers r17
|
||||
|
||||
appForwarderGetDeviceByIfaceNum:
|
||||
ldi yl, LOW(netInterfaceData)
|
||||
ldi yh, HIGH(netInterfaceData)
|
||||
ldd r17, Y+NET_IFACE_OFFS_IFACENUM
|
||||
cp r16, r17
|
||||
breq appForwarderGetDeviceByIfaceNum_secRet
|
||||
ldi yl, LOW(netInterfaceData2)
|
||||
ldi yh, HIGH(netInterfaceData2)
|
||||
ldd r17, Y+NET_IFACE_OFFS_IFACENUM
|
||||
cp r16, r17
|
||||
breq appForwarderGetDeviceByIfaceNum_secRet
|
||||
clc
|
||||
rjmp appForwarderGetDeviceByIfaceNum_ret
|
||||
appForwarderGetDeviceByIfaceNum_secRet:
|
||||
sec
|
||||
appForwarderGetDeviceByIfaceNum_ret:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
|
||||
15
avr/apps/hub/0BUILD
Normal file
15
avr/apps/hub/0BUILD
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml?>
|
||||
|
||||
<gwbuild>
|
||||
|
||||
<subdirs>
|
||||
</subdirs>
|
||||
|
||||
<extradist>
|
||||
main.asm
|
||||
</extradist>
|
||||
|
||||
|
||||
</gwbuild>
|
||||
|
||||
|
||||
715
avr/apps/hub/main.asm
Normal file
715
avr/apps/hub/main.asm
Normal file
@@ -0,0 +1,715 @@
|
||||
; ***************************************************************************
|
||||
; 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. *
|
||||
; ***************************************************************************
|
||||
|
||||
|
||||
|
||||
; ***************************************************************************
|
||||
; defines
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; network interfaces
|
||||
|
||||
|
||||
|
||||
|
||||
; ***************************************************************************
|
||||
; data
|
||||
|
||||
.dseg
|
||||
|
||||
appHubDataBegin:
|
||||
appHubRangeBegin: .byte 1
|
||||
appHubRangeEnd: .byte 1
|
||||
appHubDataEnd:
|
||||
|
||||
|
||||
|
||||
|
||||
; ***************************************************************************
|
||||
; code
|
||||
|
||||
.cseg
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine AppHub_Init @global
|
||||
|
||||
AppHub_Init:
|
||||
ldi xh, HIGH(appHubDataBegin)
|
||||
ldi xl, LOW(appHubDataBegin)
|
||||
clr r16
|
||||
ldi r17, (appHubDataEnd-appHubDataBegin)
|
||||
rcall Utils_FillSram
|
||||
|
||||
; set device address and interface number in all interfaces
|
||||
ldi r16, 0xf0 ; hub address
|
||||
ldi r17, 1 ; first interface number
|
||||
rcall appHubAllSetAddrIfaceNumAndRange ; (R17, R19, R20, Y)
|
||||
|
||||
; TODO: read ranges from EEPROM
|
||||
; TODO: send range msg to all interfaces
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine AppHub_Run @global
|
||||
;
|
||||
; Read messages from any interface, handle them and probably forward to the other
|
||||
; interfaces.
|
||||
; @return CFLAG set if something done, cleared otherwise
|
||||
; @clobbers all
|
||||
|
||||
AppHub_Run:
|
||||
rjmp appHubCheckRecvdMsg
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appHubGetDeviceByIfaceNum
|
||||
;
|
||||
; @param r16 interface number
|
||||
; @clobbers r17, r19, r20, Y
|
||||
|
||||
appHubGetDeviceByIfaceNum:
|
||||
ldi r19, COM_PORTS
|
||||
ldi yl, LOW(com2w0_iface) ; first interface
|
||||
ldi yh, HIGH(com2w0_iface)
|
||||
appHubGetDeviceByIfaceNum_loop:
|
||||
ldd r17, Y+NET_IFACE_OFFS_IFACENUM
|
||||
cp r16, r17
|
||||
sec ; mark "found"
|
||||
breq appHubGetDeviceByIfaceNum_ret
|
||||
ldi r20, COM2W_IFACE_SIZE
|
||||
add yl, r20
|
||||
adc yh, r20
|
||||
sub yh, r20
|
||||
dec r19
|
||||
brne appHubGetDeviceByIfaceNum_loop
|
||||
clc ; mark "not found"
|
||||
appHubGetDeviceByIfaceNum_ret:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appHubAllSetAddrIfaceNumAndRange
|
||||
;
|
||||
; @clobbers R17, R18, R19, R20, Y
|
||||
|
||||
appHubAllSetAddrIfaceNumAndRange:
|
||||
ldi r19, COM_PORTS
|
||||
ldi yl, LOW(com2w0_iface) ; first interface
|
||||
ldi yh, HIGH(com2w0_iface)
|
||||
ldi r18, 0x10
|
||||
appHubAllSetAddrIfaceNumAndRange_loop:
|
||||
; set address
|
||||
std Y+NET_IFACE_OFFS_ADDRESS, r16
|
||||
; set interface number
|
||||
std Y+NET_IFACE_OFFS_IFACENUM, r17
|
||||
inc r17
|
||||
; set default range (step of 16)
|
||||
std Y+NET_IFACE_OFFS_RANGE_BEGIN, r18
|
||||
subi r18, -15
|
||||
std Y+NET_IFACE_OFFS_RANGE_END, r18
|
||||
inc r18
|
||||
; next interface
|
||||
ldi r20, COM2W_IFACE_SIZE
|
||||
add yl, r20
|
||||
adc yh, r20
|
||||
sub yh, r20
|
||||
dec r19
|
||||
brne appHubAllSetAddrIfaceNumAndRange_loop
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appHubSendRangeMsg
|
||||
;
|
||||
; @param R18 msg code
|
||||
; @param Y pointer to interface data
|
||||
; @return CFLAG set if message enqueued, cleared on error
|
||||
; @clobbers (R16, R17, R18, R19, R20, R21, R24, R25, X)
|
||||
|
||||
appHubSendRangeMsg:
|
||||
bigcall NET_Buffer_Alloc ; (R16, R17, X)
|
||||
brcc appHubSendRangeMsg_end
|
||||
push r16
|
||||
ldd r20, Y+NET_IFACE_OFFS_RANGE_BEGIN
|
||||
ldd r21, Y+NET_IFACE_OFFS_RANGE_END
|
||||
adiw xh:xl, 1
|
||||
bigcall NETMSG_Range_Write ; (R16, R17, R18, R19, R20, R21)
|
||||
sbiw xh:xl, 1
|
||||
pop r16
|
||||
rcall appHubSendMsg ; (R16, R17, R18, R24, R25, X)
|
||||
appHubSendRangeMsg_end:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appHubSendDenyAddrR19
|
||||
;
|
||||
; @param R19 address to send
|
||||
; @clobbers R16, R17, R18, R19, R20, R21, X, Y
|
||||
|
||||
appHubSendDenyAddrR19:
|
||||
ldi r18, NETMSG_CMD_DENY_ADDRESS ; deny addr
|
||||
rjmp appHubSendAddrMsg ; (R16, R17, R18, R19, R20, R21, X, Y)
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appHubSendAddrMsg
|
||||
;
|
||||
; @param R18 command
|
||||
; @param R19 address to send
|
||||
; @clobbers R16 (R17, R18, R19, R20, R21, X, Y)
|
||||
|
||||
appHubSendAddrMsg:
|
||||
bigcall NET_Buffer_Alloc ; (R16, R17, X)
|
||||
brcc appHubSendAddrMsg_end
|
||||
push r16
|
||||
adiw xh:xl, 1
|
||||
bigcall NETMSG_Address_Write ; (R16, R17, R18, R19, R20, R21)
|
||||
sbiw xh:xl, 1
|
||||
pop r16
|
||||
rcall appHubSendMsg ; (R16, R17, R18, R24, R25, X)
|
||||
appHubSendAddrMsg_end:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appHubSendValueResponse
|
||||
;
|
||||
; @param R17 value id
|
||||
; @param R19:R18 value
|
||||
; @param R21:R20 denom (e.g. 100, meaning value must be divided by 100)
|
||||
; @param R23 command
|
||||
; @param R25:R24 ref msg id
|
||||
; @return CFLAG on success, cleared on error
|
||||
; @clobbers r22 (r16, r17, r18, r19, r20, r21, r23, r24, r25, X)
|
||||
|
||||
appHubSendValueResponse:
|
||||
push r17
|
||||
rcall NET_Buffer_Alloc ; (R16, R17, X)
|
||||
pop r17
|
||||
brcc appHubSendValueResponse_end ; jmp on error
|
||||
push r16 ; buffer num
|
||||
ldi r16, 0xff ; DEST addr
|
||||
clr r22 ; value type
|
||||
adiw xh:xl, 1
|
||||
rcall NETMSG_ValueWriteResponse ; (R16, R17, R18, R19, R20, R21, R23, R24, R25)
|
||||
sbiw xh:xl, 1
|
||||
pop r16 ; buffer num
|
||||
rcall NET_Interface_AddOrReleaseOutMsg ; (R16, R17, R18, X)
|
||||
appHubSendValueResponse_end:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appHubSendMsg
|
||||
;
|
||||
; @param R16 num of allocated buffer
|
||||
; @param Y pointer to interface data
|
||||
; @param X msg to send (points to start of allocated buffer, e.g. buffer header)
|
||||
; @return CFLAG set if message enqueued, cleared on error
|
||||
; @clobbers R16 (R17, R18, R24, R25, X)
|
||||
|
||||
appHubSendMsg:
|
||||
bigcall NET_Interface_AddOutgoingMsgNum ; (R17, R18, X)
|
||||
brcs appHubSendMsg_end
|
||||
bigcall NET_Buffer_ReleaseByNum ; (R16, X)
|
||||
ldi r16, NET_IFACE_OFFS_ERR_NOBUF_LOW
|
||||
rcall NET_Interface_IncCounter16 ; (R24, R25)
|
||||
clc
|
||||
appHubSendMsg_end:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appHubAllResetStats
|
||||
;
|
||||
; @clobbers r19, r20, Y (r16, r17, X)
|
||||
|
||||
appHubAllResetStats:
|
||||
ldi r19, COM_PORTS
|
||||
ldi yl, LOW(com2w0_iface) ; first interface
|
||||
ldi yh, HIGH(com2w0_iface)
|
||||
appHubAllResetStats_loop:
|
||||
bigcall NET_Interface_ResetStats ; (R16, R17, X)
|
||||
|
||||
ldi r20, COM2W_IFACE_SIZE
|
||||
add yl, r20
|
||||
adc yh, r20
|
||||
sub yh, r20
|
||||
dec r19
|
||||
brne appHubAllResetStats_loop
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine AppHub_EveryDay @global
|
||||
;
|
||||
; @clobbers R16, R17, X
|
||||
|
||||
AppHub_EveryDay:
|
||||
rcall appHubAllResetStats
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appHubSendMsgToAllOthers
|
||||
;
|
||||
; @param R16 buffer number
|
||||
; @param X buffer pointer
|
||||
; @clobbers r17, r19, r20, r24, r25 (r16, r18, X)
|
||||
|
||||
appHubSendMsgToAllOthers:
|
||||
ld r24, X
|
||||
andi r24, 0x0f ; get sender interface num
|
||||
ldi r19, COM_PORTS ; number of ports
|
||||
ldi yl, LOW(com2w0_iface) ; first interface
|
||||
ldi yh, HIGH(com2w0_iface)
|
||||
appHubSendMsgToAllOthers_loop:
|
||||
ldd r25, Y+NET_IFACE_OFFS_IFACENUM
|
||||
cp r24, r25 ; same interface?
|
||||
breq appHubSendMsgToAllOthers_next
|
||||
; current iface is not source, send and inc ref counter
|
||||
bigcall NET_Interface_AddOutgoingMsgNum ; (R17, R18, X)
|
||||
brcs appHubSendMsgToAllOthers_added
|
||||
; inc error counter
|
||||
push r24
|
||||
mov r17, r16 ; save r16
|
||||
ldi r16, NET_IFACE_OFFS_ERR_NOBUF_LOW
|
||||
bigcall NET_Interface_IncCounter16 ; (R24, R25)
|
||||
mov r16, r17 ; restore r16
|
||||
pop r24
|
||||
rjmp appHubSendMsgToAllOthers_next
|
||||
appHubSendMsgToAllOthers_added:
|
||||
mov r17, r16 ; save r16
|
||||
bigcall NET_Buffer_IncRef ; (r16)
|
||||
mov r16, r17 ; restore r16
|
||||
appHubSendMsgToAllOthers_next:
|
||||
ldi r20, COM2W_IFACE_SIZE
|
||||
add yl, r20
|
||||
adc yh, r20
|
||||
sub yh, r20
|
||||
dec r19
|
||||
brne appHubSendMsgToAllOthers_loop
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appHubHandleMsgLocally
|
||||
;
|
||||
; @param X pointer to received buffer (points to header byte)
|
||||
; @param Y pointer to IFACE data from which msg was received
|
||||
; @clobbers all, !X
|
||||
|
||||
appHubHandleMsgLocally:
|
||||
push xl
|
||||
push xh
|
||||
rcall appHubHandleMsgLocally_savedX
|
||||
pop xh
|
||||
pop xl
|
||||
rjmp appHubHandleMsgLocally_ret
|
||||
appHubHandleMsgLocally_savedX:
|
||||
; get message type
|
||||
adiw xh:xl, NETMSG_OFFS_CMD+1 ; account for header byte
|
||||
ld r16, X
|
||||
sbiw xh:xl, NETMSG_OFFS_CMD+1
|
||||
cpi r16, NETMSG_CMD_PING
|
||||
breq appHubHandleMsgLocally_handlePingMsg
|
||||
cpi r16, NETMSG_CMD_REBOOT_REQUEST
|
||||
breq appHubHandleMsgLocally_handleRebootMsg
|
||||
cpi r16, NETMSG_CMD_VALUE_SET
|
||||
breq appHubHandleMsgLocally_handleSetValue
|
||||
rjmp appHubHandleMsgLocally_ret
|
||||
appHubHandleMsgLocally_handlePingMsg:
|
||||
rjmp appHubHandlePingMsg
|
||||
appHubHandleMsgLocally_handleRebootMsg:
|
||||
rjmp appHubHandleRebootMsg
|
||||
appHubHandleMsgLocally_handleSetValue:
|
||||
rjmp appHubHandleSetValueMsg
|
||||
appHubHandleMsgLocally_ret:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appHubHandlePingMsg
|
||||
;
|
||||
; @param X pointer to received message
|
||||
; @clobbers any, !X, !Y
|
||||
|
||||
appHubHandlePingMsg:
|
||||
adiw xh:xl, NETMSG_OFFS_DESTADDR+1
|
||||
ld r17, X
|
||||
sbiw xh:xl, NETMSG_OFFS_DESTADDR+1
|
||||
ldd r16, Y+NET_IFACE_OFFS_ADDRESS
|
||||
cp r16, r17
|
||||
breq appHubHandlePingMsg_forMe
|
||||
cpi r17, 0xff
|
||||
breq appHubHandlePingMsg_forMe
|
||||
clc
|
||||
rjmp appHubHandlePingMsg_end
|
||||
appHubHandlePingMsg_forMe:
|
||||
adiw xh:xl, NETMSG_OFFS_SRCADDR+1
|
||||
ld r17, X
|
||||
sbiw xh:xl, NETMSG_OFFS_SRCADDR+1
|
||||
push r17
|
||||
bigcall NET_Buffer_Alloc ; (R16, R17, X)
|
||||
pop r17
|
||||
brcc appHubHandlePingMsg_end ; jmp on error
|
||||
push r16 ; buffer num
|
||||
mov r16, r17 ; DEST addr
|
||||
adiw xh:xl, 1
|
||||
bigcall NETMSG_Pong_Write ; (R16, R17, R18, R19, R20, X)
|
||||
sbiw xh:xl, 1
|
||||
pop r16 ; buffer num
|
||||
bigcall NET_Interface_AddOrReleaseOutMsg ; (R16, R17, R18, X)
|
||||
appHubHandlePingMsg_end:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appHubHandleRebootMsg
|
||||
;
|
||||
; Doesn't return if reboot msg is valid.
|
||||
;
|
||||
; @param X pointer to received message
|
||||
|
||||
appHubHandleRebootMsg:
|
||||
rcall NETMSG_RebootRequestRead
|
||||
brcc appHubHandleRebootMsg_end
|
||||
; reboot
|
||||
cli
|
||||
bigjmp BOOTLOADER_ADDR
|
||||
appHubHandleRebootMsg_end:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appHubHandleSetValueMsg
|
||||
;
|
||||
; @param X pointer to received message
|
||||
; @param Y pointer to IFACE data from which msg was received
|
||||
; @clobbers all, !Y
|
||||
|
||||
appHubHandleSetValueMsg:
|
||||
adiw xh:xl, NETMSG_OFFS_DESTADDR+1
|
||||
ld r17, X
|
||||
sbiw xh:xl, NETMSG_OFFS_DESTADDR+1
|
||||
ldd r16, Y+NET_IFACE_OFFS_ADDRESS
|
||||
cp r16, r17
|
||||
breq appHubHandleSetValueMsg_forMe
|
||||
cpi r17, 0xff
|
||||
breq appHubHandleSetValueMsg_forMe
|
||||
rjmp appHubHandleSetValueMsg_ret
|
||||
appHubHandleSetValueMsg_forMe:
|
||||
rcall NETMSG_ValueRead ; (none)
|
||||
cpi r17, VALUE_ID_HUB_SETRANGE1
|
||||
brcs appHubHandleSetValueMsg_ret
|
||||
cpi r17, VALUE_ID_HUB_SETRANGE8+1
|
||||
brcc appHubHandleSetValueMsg_ret
|
||||
appHubHandleSetValueMsg_setRange:
|
||||
push yl
|
||||
push yh
|
||||
subi r17, (VALUE_ID_HUB_SETRANGE1-1)
|
||||
push r18
|
||||
push r19
|
||||
; send ACK back the same interface the request came from
|
||||
push r17 ; interface number
|
||||
ldi r23, NETMSG_CMD_VALUE_SET_ACK
|
||||
rcall appHubSendValueResponse ; r22 (r16, r17, r18, r19, r20, r21, r23, r24, r25, X)
|
||||
pop r16 ; pop interface number to r16 (from r17)
|
||||
rcall appHubGetDeviceByIfaceNum ; Y=interface to modify (r17, r19, r20)
|
||||
pop r19
|
||||
pop r18
|
||||
; modify interface
|
||||
std Y+NET_IFACE_OFFS_RANGE_BEGIN, r18
|
||||
std Y+NET_IFACE_OFFS_RANGE_END, r19
|
||||
; TODO: store new config
|
||||
|
||||
; let subnodes of modified interface re-eunumerate
|
||||
ldi r18, NETMSG_CMD_REENUM
|
||||
rcall appHubSendRangeMsg ; (R16, R17, R18, R19, R20, R21, X)
|
||||
pop yh
|
||||
pop yl
|
||||
|
||||
appHubHandleSetValueMsg_ret:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appHubHandleRoutingMsg
|
||||
;
|
||||
; @param X pointer to received buffer (points to header byte)
|
||||
; @param Y pointer to IFACE data from which msg was received
|
||||
; @clobbers all, !X
|
||||
|
||||
appHubHandleRoutingMsg:
|
||||
push xl
|
||||
push xh
|
||||
rcall appHubHandleRoutingMsg_savedX
|
||||
pop xh
|
||||
pop xl
|
||||
rjmp appHubHandleRoutingMsg_ret
|
||||
appHubHandleRoutingMsg_savedX:
|
||||
; get message type
|
||||
adiw xh:xl, NETMSG_OFFS_CMD+1 ; account for header byte
|
||||
ld r16, X
|
||||
sbiw xh:xl, NETMSG_OFFS_CMD+1
|
||||
cpi r16, NETMSG_CMD_NEED_ADDRESS
|
||||
breq appHubHandleRoutingMsg_handleNeedAddress
|
||||
cpi r16, NETMSG_CMD_CLAIM_ADDRESS
|
||||
breq appHubHandleRoutingMsg_handleClaimAddress
|
||||
clc
|
||||
rjmp appHubHandleRoutingMsg_ret
|
||||
appHubHandleRoutingMsg_handleNeedAddress:
|
||||
rcall appHubHandleNeedAddressMsg
|
||||
rjmp appHubHandleRoutingMsg_secRet
|
||||
appHubHandleRoutingMsg_handleClaimAddress:
|
||||
rcall appHubHandleClaimAddressMsg
|
||||
appHubHandleRoutingMsg_secRet:
|
||||
sec
|
||||
appHubHandleRoutingMsg_ret:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appHubHandleNeedAddressMsg
|
||||
;
|
||||
; @param X pointer to received message
|
||||
; @param Y pointer to IFACE data from which msg was received
|
||||
; @clobbers all, !Y
|
||||
|
||||
appHubHandleNeedAddressMsg:
|
||||
ldi r18, NETMSG_CMD_ADDRESS_RANGE
|
||||
rcall appHubSendRangeMsg ; (R16, R17, R18, R19, R20, R21, X)
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appHubHandleClaimAddressMsg
|
||||
;
|
||||
; @param X pointer to received message
|
||||
; @param Y pointer to IFACE data from which msg was received
|
||||
; @clobbers all, !Y
|
||||
|
||||
appHubHandleClaimAddressMsg:
|
||||
rcall NETMSG_Address_Read ; R18=cmd, R19=addr(R18, R19)
|
||||
rcall appHubIsR19InRange
|
||||
brcs appHubHandleClaimAddressMsg_end
|
||||
; is not in subnet range, deny
|
||||
rcall appHubSendDenyAddrR19 ; (R16, R17, R18, R19, R20, R21, X)
|
||||
appHubHandleClaimAddressMsg_end:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appHubIsR19InRange
|
||||
;
|
||||
; @param R19 address to check against range
|
||||
; @param Y pointer to IFACE data
|
||||
; @clobbers R16
|
||||
|
||||
appHubIsR19InRange:
|
||||
ldd r16, Y+NET_IFACE_OFFS_RANGE_BEGIN
|
||||
cp r19, r16
|
||||
brcs appHubIsR19InRangeClcRet
|
||||
ldd r16, Y+NET_IFACE_OFFS_RANGE_END
|
||||
cp r16, r19
|
||||
brcs appHubIsR19InRangeClcRet
|
||||
sec
|
||||
rjmp appHubIsR19InRange_end
|
||||
appHubIsR19InRangeClcRet:
|
||||
clc
|
||||
appHubIsR19InRange_end:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appHubCheckRecvdMsg
|
||||
;
|
||||
; Read messages from any interface and forward to the other ones.
|
||||
;
|
||||
; @return CFLAG set if something done, cleared otherwise
|
||||
|
||||
appHubCheckRecvdMsg:
|
||||
rcall NET_PeekNextIncomingMsgNum ; check read queue (R16=bufNum)
|
||||
brcc appHubCheckRecvdMsg_end ; no msg, jmp
|
||||
rcall NET_Buffer_Locate ; (R17)
|
||||
rcall appHubHandleRecvdMsg ; (all, !X)
|
||||
rcall NET_GetNextIncomingMsgNum ; take off the queue
|
||||
rcall NET_Buffer_ReleaseByNum ; (R16, X)
|
||||
sec ; we had a message, so something was done
|
||||
appHubCheckRecvdMsg_end:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appHubHandleRecvdMsg
|
||||
;
|
||||
; @param R16 buffer number
|
||||
; @param X pointer to received message
|
||||
; @clobbers all, !X
|
||||
|
||||
appHubHandleRecvdMsg:
|
||||
mov r18, r16
|
||||
ld r16, X
|
||||
andi r16, 0x0f
|
||||
rcall appHubGetDeviceByIfaceNum ; Y=source iface (r17, r19, r20)
|
||||
brcc appHubHandleRecvdMsg_ret
|
||||
; filter out routing msgs
|
||||
push yl
|
||||
push yh
|
||||
push r18
|
||||
rcall appHubHandleRoutingMsg ; (all, !X)
|
||||
pop r18
|
||||
pop yh
|
||||
pop yl
|
||||
brcs appHubHandleRecvdMsg_ret
|
||||
; check for PING, SETVALUE etc
|
||||
push r18
|
||||
push yl
|
||||
push yh
|
||||
rcall appHubHandleMsgLocally ; (all, !X)
|
||||
pop yh
|
||||
pop yl
|
||||
; let other apps and modules handle message
|
||||
push xl
|
||||
push xh
|
||||
bigcall mainHandleMessages
|
||||
pop xh
|
||||
pop xl
|
||||
pop r18
|
||||
; forward message to all other interfaces
|
||||
mov r16, r18 ; buffer number
|
||||
push xl
|
||||
push xh
|
||||
rcall appHubSendMsgToAllOthers ; (r17, r19, r20, r24, r25 (r16, r18, X)
|
||||
pop xh
|
||||
pop xl
|
||||
appHubHandleRecvdMsg_ret:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appHubWriteConfToEeprom
|
||||
;
|
||||
; @clobbers R16, X (R17)
|
||||
|
||||
appHubWriteConfToEeprom:
|
||||
; write range begin
|
||||
ldi xl, LOW(EEPROM_OFFS_ROUTER_RANGE_BEGIN)
|
||||
ldi xh, HIGH(EEPROM_OFFS_ROUTER_RANGE_BEGIN)
|
||||
lds r16, appHubRangeBegin
|
||||
rcall Eeprom_WriteByteIfChanged ; (R17)
|
||||
brcc appHubWriteConfToEeprom_end
|
||||
|
||||
; write range end
|
||||
ldi xl, LOW(EEPROM_OFFS_ROUTER_RANGE_END)
|
||||
ldi xh, HIGH(EEPROM_OFFS_ROUTER_RANGE_END)
|
||||
lds r16, appHubRangeEnd
|
||||
rcall Eeprom_WriteByteIfChanged ; (R17)
|
||||
appHubWriteConfToEeprom_end:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
#if 0
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appHubReadConfFromEeprom
|
||||
;
|
||||
; @clobbers R16, X (R17)
|
||||
|
||||
appHubReadConfFromEeprom:
|
||||
; read range begin
|
||||
ldi xl, LOW(EEPROM_OFFS_ROUTER_RANGE_BEGIN)
|
||||
ldi xh, HIGH(EEPROM_OFFS_ROUTER_RANGE_BEGIN)
|
||||
rcall Eeprom_ReadByte
|
||||
brcc appHubReadConfFromEeprom_end
|
||||
cpi r16, 0xff
|
||||
breq appHubReadConfFromEeprom_okay ; not set, jmp
|
||||
cpi r16, 2 ; range should at least start at 2 to assign 1 to router
|
||||
brcs appHubReadConfFromEeprom_okay
|
||||
sts appHubRangeBegin, r16
|
||||
dec r16
|
||||
sts netInterfaceData+NET_IFACE_OFFS_ADDRESS, r16 ; use addr rangeBegin-1 for router itself
|
||||
sts netInterfaceData2+NET_IFACE_OFFS_ADDRESS, r16 ; use same address for both interfaces to save on addresses
|
||||
|
||||
; read range end
|
||||
ldi xl, LOW(EEPROM_OFFS_ROUTER_RANGE_END)
|
||||
ldi xh, HIGH(EEPROM_OFFS_ROUTER_RANGE_END)
|
||||
rcall Eeprom_ReadByte
|
||||
brcc appHubReadConfFromEeprom_end
|
||||
cpi r16, 0xff
|
||||
breq appHubReadConfFromEeprom_okay
|
||||
sts appHubRangeEnd, r16
|
||||
appHubReadConfFromEeprom_okay:
|
||||
sec
|
||||
appHubReadConfFromEeprom_end:
|
||||
ret
|
||||
; @end
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -100,12 +100,30 @@ AppNetwork_Every100ms_jump:
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine AppNetwork_EveryDay @global
|
||||
;
|
||||
; @clobbers R16, R17, X
|
||||
|
||||
AppNetwork_EveryDay:
|
||||
bigjmp NET_Interface_ResetStats ; (R16, R17, X)
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine AppNetwork_HandleMsg @global
|
||||
;
|
||||
; @param X pointer to received message
|
||||
|
||||
AppNetwork_HandleMsg:
|
||||
push xl
|
||||
push xh
|
||||
rcall AppNetwork_HandleMsg_savedX
|
||||
pop xh
|
||||
pop xl
|
||||
rjmp AppNetwork_HandleMsg_end
|
||||
AppNetwork_HandleMsg_savedX:
|
||||
adiw xh:xl, NETMSG_OFFS_CMD
|
||||
ld r16, X
|
||||
sbiw xh:xl, NETMSG_OFFS_CMD
|
||||
@@ -113,18 +131,25 @@ AppNetwork_HandleMsg:
|
||||
breq AppNetwork_HandleMsg_handleRebootMsg
|
||||
cpi r16, NETMSG_CMD_PING
|
||||
breq AppNetwork_HandleMsg_handlePingMsg
|
||||
cpi r16, NETMSG_CMD_REENUM
|
||||
breq AppNetwork_HandleMsg_handleReenumMsg
|
||||
cpi r16, NETMSG_CMD_NEED_ADDRESS
|
||||
brcs AppNetwork_HandleMsg_clcRet ; lower than "HAVE_NEED"
|
||||
cpi r16, NETMSG_CMD_ADDRESS_RANGE
|
||||
breq AppNetwork_HandleMsg_handleRangeMsg
|
||||
brcc AppNetwork_HandleMsg_clcRet ; higher or equal to "ADDR_RANGE"
|
||||
rjmp AppNetwork_HandleMsg_handleAddrMsg
|
||||
AppNetwork_HandleMsg_handleReenumMsg:
|
||||
rjmp appNetworkHandleReeunumRequest
|
||||
AppNetwork_HandleMsg_handleRangeMsg:
|
||||
; TODO
|
||||
bigcall NETMSG_Range_Read
|
||||
std Y+NET_IFACE_OFFS_RANGE_BEGIN, r20
|
||||
std Y+NET_IFACE_OFFS_RANGE_END, r21
|
||||
std Y+NET_IFACE_OFFS_ADDRESS, r20
|
||||
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)
|
||||
@@ -134,21 +159,13 @@ AppNetwork_HandleMsg_handleAddrMsg:
|
||||
sub zh, r16
|
||||
ijmp
|
||||
AppNetwork_HandleMsg_handleRebootMsg:
|
||||
push xl
|
||||
push xh
|
||||
rcall appNetworkHandleRebootRequest
|
||||
pop xh
|
||||
pop xl
|
||||
rcall appNetworkHandleRebootRequest
|
||||
ret
|
||||
AppNetwork_HandleMsg_handlePingMsg:
|
||||
push xl
|
||||
push xh
|
||||
rcall appNetworkHandlePingRequest
|
||||
pop xh
|
||||
pop xl
|
||||
ret
|
||||
rjmp appNetworkHandlePingRequest
|
||||
AppNetwork_HandleMsg_clcRet:
|
||||
clc
|
||||
AppNetwork_HandleMsg_end:
|
||||
ret
|
||||
; @end
|
||||
|
||||
@@ -161,7 +178,7 @@ AppNetwork_HandleMsg_clcRet:
|
||||
|
||||
appNetworkHandleRebootRequest:
|
||||
rcall NETMSG_RebootRequestRead
|
||||
brcc appNetworkHandleRebootRequest_end
|
||||
brcc appNetworkHandleRebootRequest_end ; uid doesn't match
|
||||
; reboot
|
||||
cli
|
||||
bigjmp BOOTLOADER_ADDR
|
||||
@@ -172,26 +189,56 @@ appNetworkHandleRebootRequest_end:
|
||||
|
||||
|
||||
appNetworkHandlePingRequest:
|
||||
ld r17, X
|
||||
lds r16, (netInterfaceData+NET_IFACE_OFFS_ADDRESS)
|
||||
cp r16, r17
|
||||
breq appNetworkHandlePingRequest_forMe
|
||||
cpi r17, 0xff
|
||||
breq appNetworkHandlePingRequest_forMe
|
||||
clc
|
||||
rjmp appNetworkHandlePingRequest_end
|
||||
appNetworkHandlePingRequest_forMe:
|
||||
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
|
||||
|
||||
|
||||
|
||||
appNetworkHandleReeunumRequest:
|
||||
push xl
|
||||
push xh
|
||||
rcall Utils_ReadUid ; r21:r20:r19:r18=uid (r16, X)
|
||||
pop xh
|
||||
pop xl
|
||||
rcall NETMSG_Range_Read ; r20=range begin, r21=range end (none)
|
||||
ldi r16, APP_NETWORK_STATE_INITIALWAIT
|
||||
std Y+NET_IFACE_OFFS_STATUS, r16
|
||||
cpi r18, 20
|
||||
brcc appNetworkHandleReeunumRequest_setWait
|
||||
subi r18, -20 ; minimum 2s
|
||||
appNetworkHandleReeunumRequest_setWait:
|
||||
std Y+NET_IFACE_OFFS_STATETIMER, r18 ; use lowest byte of uid as wat time
|
||||
std Y+NET_IFACE_OFFS_RANGE_BEGIN, r20
|
||||
std Y+NET_IFACE_OFFS_RANGE_END, r21
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
appNetworkTimerTable:
|
||||
rjmp appNetworkHandleStateInitialWait
|
||||
rjmp appNetworkHandleStateNeedAddress
|
||||
@@ -238,20 +285,11 @@ appNetworkHandleStateHaveAddress2:
|
||||
std Y+NET_IFACE_OFFS_STATUS, r16
|
||||
ldi r16, APP_NETWORK_TIMER_100MS
|
||||
std Y+NET_IFACE_OFFS_STATETIMER, r16
|
||||
ldd r16, Y+NET_IFACE_OFFS_RANGE_BEGIN ; set interface address
|
||||
ldd r17, Y+NET_IFACE_OFFS_ADDRESS
|
||||
cp r16, r17
|
||||
breq appNetworkHandleStateHaveAddress2_end
|
||||
; store new address in IFACE and in EEPROM
|
||||
std Y+NET_IFACE_OFFS_ADDRESS, r16
|
||||
push r15
|
||||
in r15, SREG
|
||||
cli
|
||||
ldi xl, LOW(EEPROM_OFFS_COMADDR)
|
||||
ldi xh, HIGH(EEPROM_OFFS_COMADDR)
|
||||
bigcall Utils_WriteEepromIncr ; write address to EEPROM
|
||||
out SREG, r15
|
||||
pop r15
|
||||
ldd r16, Y+NET_IFACE_OFFS_ADDRESS
|
||||
ldi xl, LOW(EEPROM_OFFS_COMADDR)
|
||||
ldi xh, HIGH(EEPROM_OFFS_COMADDR)
|
||||
bigcall Eeprom_WriteByteIfChanged ; write address to EEPROM (R17)
|
||||
appNetworkHandleStateHaveAddress2_end:
|
||||
ret
|
||||
|
||||
@@ -269,7 +307,7 @@ appNetworkHandleStateUp:
|
||||
; @clobbers R16, R19 (R17, R18, R20, R21, X)
|
||||
|
||||
appNetworkSendMsgNextState:
|
||||
ldd r19, Y+NET_IFACE_OFFS_RANGE_BEGIN
|
||||
ldd r19, Y+NET_IFACE_OFFS_ADDRESS
|
||||
rcall appNetworkSendAddrMsg ; (R16, R17, R18, R19, R20, R21, X)
|
||||
brcc appNetworkSendMsgNextState_retry
|
||||
ldd r16, Y+NET_IFACE_OFFS_STATUS
|
||||
@@ -334,9 +372,9 @@ appNetworkHandleMsgClaimAddr:
|
||||
cp r19, r16
|
||||
brne appNetworkHandleMsgClaimAddr_end ; not our address
|
||||
ldd r16, Y+NET_IFACE_OFFS_STATUS
|
||||
cpi r16, APP_NETWORK_STATE_UP ; up?
|
||||
brne appNetworkHandleMsgClaimAddr_end ; nope, ignore
|
||||
; network is up, someone claimed our address, deny it
|
||||
cpi r16, APP_NETWORK_STATE_CLAIMADDRESS1
|
||||
brcs appNetworkHandleMsgClaimAddr_end ; nope, ignore
|
||||
; network is somewhat up, someone claimed our address, deny it
|
||||
ldi r18, NETMSG_CMD_DENY_ADDRESS ; deny our addr
|
||||
ldd r19, Y+NET_IFACE_OFFS_ADDRESS
|
||||
rjmp appNetworkSendAddrMsg
|
||||
@@ -358,12 +396,12 @@ appNetworkHandleMsgDenyAddr:
|
||||
cpi r16, APP_NETWORK_STATE_UP
|
||||
breq appNetworkHandleMsgDenyAddr_end ; ignore (our network stack is up)
|
||||
; still setting up address, check whether the last one is denied now
|
||||
ldd r16, Y+NET_IFACE_OFFS_RANGE_BEGIN
|
||||
ldd r16, Y+NET_IFACE_OFFS_ADDRESS
|
||||
cp r19, r16 ; our claimed address?
|
||||
brne appNetworkHandleMsgDenyAddr_end ; nope, jump
|
||||
; try next address (if any left)
|
||||
ldd r17, Y+NET_IFACE_OFFS_RANGE_END
|
||||
inc r16 ; RANGE_BEGIN+1
|
||||
inc r16 ; next address
|
||||
cp r17, r16 ; smaller than or equal to RANGE_END?
|
||||
brcc appNetworkHandleMsgDenyAddr_claimNext
|
||||
; out of addresses, start completely new after some waiting time
|
||||
@@ -373,7 +411,7 @@ appNetworkHandleMsgDenyAddr:
|
||||
rjmp appNetworkHandleMsgDenyAddr_end
|
||||
appNetworkHandleMsgDenyAddr_claimNext:
|
||||
; send CLAIM_ADDR for next address (new state: APP_NETWORK_STATE_NEEDADDRESS+1)
|
||||
std Y+NET_IFACE_OFFS_RANGE_BEGIN, r16
|
||||
std Y+NET_IFACE_OFFS_ADDRESS, r16
|
||||
ldi r16, APP_NETWORK_STATE_NEEDADDRESS
|
||||
std Y+NET_IFACE_OFFS_STATUS, r16
|
||||
ldi r18, NETMSG_CMD_CLAIM_ADDRESS
|
||||
@@ -393,16 +431,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
|
||||
@@ -424,6 +462,7 @@ appNetworkResetState:
|
||||
std Y+NET_IFACE_OFFS_STATETIMER, r16
|
||||
ldi r16, APP_NETWORK_ADDRESS_RANGE_BEGIN
|
||||
std Y+NET_IFACE_OFFS_RANGE_BEGIN, r16
|
||||
std Y+NET_IFACE_OFFS_ADDRESS, r16
|
||||
rcall appNetworkGetAddressFromEeprom ; R16=addr (R15, X)
|
||||
tst r16
|
||||
breq appNetworkResetState_setRangeEnd
|
||||
|
||||
@@ -18,14 +18,20 @@
|
||||
; @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)
|
||||
push yl
|
||||
push yh
|
||||
ldi yl, LOW(netInterfaceData)
|
||||
ldi yh, HIGH(netInterfaceData)
|
||||
bigcall NET_Interface_AddOrReleaseOutMsg ; (R16, R17, R18, X)
|
||||
pop yh
|
||||
pop yl
|
||||
AppNetwork_SendTxdStats_end:
|
||||
ret
|
||||
; @end
|
||||
@@ -35,18 +41,24 @@ AppNetwork_SendTxdStats_end:
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine AppNetwork_SendRxdStats
|
||||
|
||||
; @param Y network interface to work with
|
||||
; @param Y network interface whose stats to send
|
||||
; @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)
|
||||
push yl
|
||||
push yh
|
||||
ldi yl, LOW(netInterfaceData)
|
||||
ldi yh, HIGH(netInterfaceData)
|
||||
bigcall NET_Interface_AddOrReleaseOutMsg ; (R16, R17, R18, X)
|
||||
pop yh
|
||||
pop yl
|
||||
AppNetwork_SendRxdStats_end:
|
||||
ret
|
||||
; @end
|
||||
@@ -54,20 +66,25 @@ AppNetwork_SendRxdStats_end:
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine AppNetwork_SendRxdStats
|
||||
; @routine AppNetwork_SendMemStats
|
||||
|
||||
; @param Y network interface to work with
|
||||
; @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)
|
||||
push yl
|
||||
push yh
|
||||
ldi yl, LOW(netInterfaceData)
|
||||
ldi yh, HIGH(netInterfaceData)
|
||||
bigcall NET_Interface_AddOrReleaseOutMsg ; (R16, R17, R18, X)
|
||||
pop yh
|
||||
pop yl
|
||||
AppNetwork_SendMemStats_end:
|
||||
ret
|
||||
; @end
|
||||
@@ -81,14 +98,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
|
||||
|
||||
@@ -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
|
||||
|
||||
15
avr/apps/router/0BUILD
Normal file
15
avr/apps/router/0BUILD
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml?>
|
||||
|
||||
<gwbuild>
|
||||
|
||||
<subdirs>
|
||||
</subdirs>
|
||||
|
||||
<extradist>
|
||||
main.asm
|
||||
</extradist>
|
||||
|
||||
|
||||
</gwbuild>
|
||||
|
||||
|
||||
579
avr/apps/router/main.asm
Normal file
579
avr/apps/router/main.asm
Normal file
@@ -0,0 +1,579 @@
|
||||
; ***************************************************************************
|
||||
; 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. *
|
||||
; ***************************************************************************
|
||||
|
||||
|
||||
|
||||
; ***************************************************************************
|
||||
; defines
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; network interfaces
|
||||
|
||||
.equ NETDEV0_IFACENUM = 1
|
||||
.equ NETDEV1_IFACENUM = 2
|
||||
|
||||
|
||||
|
||||
; ***************************************************************************
|
||||
; data
|
||||
|
||||
.dseg
|
||||
|
||||
appRouterDataBegin:
|
||||
appRouterRangeBegin: .byte 1
|
||||
appRouterRangeEnd: .byte 1
|
||||
appRouterDataEnd:
|
||||
|
||||
|
||||
|
||||
|
||||
; ***************************************************************************
|
||||
; code
|
||||
|
||||
.cseg
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine AppRouter_Init @global
|
||||
|
||||
AppRouter_Init:
|
||||
ldi xh, HIGH(appRouterDataBegin)
|
||||
ldi xl, LOW(appRouterDataBegin)
|
||||
clr r16
|
||||
ldi r17, (appRouterDataEnd-appRouterDataBegin)
|
||||
rcall Utils_FillSram
|
||||
|
||||
#ifndef APP_ROUTER_NO_ADDR_MGR
|
||||
ldi r16, 0xe0 ; default range from 0xe0-0xef (will be changed later)
|
||||
sts netInterfaceData+NET_IFACE_OFFS_ADDRESS, r16 ; use first address for router itself
|
||||
sts netInterfaceData2+NET_IFACE_OFFS_ADDRESS, r16 ; use same address for both interfaces to save on addresses
|
||||
inc r16
|
||||
sts appRouterRangeBegin, r16 ; range from router+1
|
||||
ldi r16, 0xef
|
||||
sts appRouterRangeEnd, r16
|
||||
|
||||
rcall appRouterReadConfFromEeprom ; try to read config from EEPROM
|
||||
#endif
|
||||
|
||||
; set interface number for NETDEV0
|
||||
ldi r16, NETDEV0_IFACENUM
|
||||
sts netInterfaceData+NET_IFACE_OFFS_IFACENUM, r16
|
||||
; set interface number for NETDEV1
|
||||
ldi r16, NETDEV1_IFACENUM
|
||||
sts netInterfaceData2+NET_IFACE_OFFS_IFACENUM, r16
|
||||
|
||||
#ifndef APP_ROUTER_NO_ADDR_MGR
|
||||
ldi r18, NETMSG_CMD_ADDRESS_RANGE
|
||||
rcall appRouterSendRangeMsgToDev1
|
||||
#endif
|
||||
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine AppRouter_EveryDay @global
|
||||
;
|
||||
; @clobbers R16, R17, X
|
||||
|
||||
AppRouter_EveryDay:
|
||||
ldi yl, LOW(netInterfaceData)
|
||||
ldi yh, HIGH(netInterfaceData)
|
||||
bigcall NET_Interface_ResetStats ; (R16, R17, X)
|
||||
|
||||
ldi yl, LOW(netInterfaceData2)
|
||||
ldi yh, HIGH(netInterfaceData2)
|
||||
bigcall NET_Interface_ResetStats ; (R16, R17, X)
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine AppRouter_Run @global
|
||||
;
|
||||
; Read messages from either interface and forward to the other one.
|
||||
|
||||
AppRouter_Run:
|
||||
rjmp appRouterCheckRecvdMsg
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appRouterHandleMsgAnyDev @global
|
||||
;
|
||||
; @param X pointer to received message
|
||||
; @return CFLAG set if msg handled, cleared otherwise
|
||||
; @clobbers any, !X
|
||||
|
||||
appRouterHandleMsgAnyDev:
|
||||
push xl
|
||||
push xh
|
||||
rcall appRouterHandleMsgAnyDev_savedX
|
||||
pop xh
|
||||
pop xl
|
||||
rjmp appRouterHandleMsgAnyDev_end
|
||||
appRouterHandleMsgAnyDev_savedX:
|
||||
adiw xh:xl, NETMSG_OFFS_CMD ; maybe move ping/reboot handling to all/main.asm?
|
||||
ld r16, X
|
||||
sbiw xh:xl, NETMSG_OFFS_CMD
|
||||
cpi r16, NETMSG_CMD_REBOOT_REQUEST
|
||||
breq appRouterHandleMsgAnyDev_handleRebootMsg
|
||||
cpi r16, NETMSG_CMD_PING
|
||||
breq appRouterHandleMsgAnyDev_handlePingMsg
|
||||
cpi r16, NETMSG_CMD_VALUE_SET
|
||||
breq appRouterHandleMsgAnyDev_handleSetValue
|
||||
rjmp appRouterHandleMsgAnyDev_clcRet
|
||||
appRouterHandleMsgAnyDev_handleRebootMsg:
|
||||
rcall appRouterHandleRebootRequest
|
||||
ret
|
||||
appRouterHandleMsgAnyDev_handlePingMsg:
|
||||
rcall appRouterHandlePingRequest
|
||||
clc
|
||||
ret
|
||||
appRouterHandleMsgAnyDev_handleSetValue:
|
||||
rcall NETMSG_ValueRead ; (none)
|
||||
cpi r17, VALUE_ID_ROUTER_SETRANGE
|
||||
breq appRouterHandleMsgAnyDev_handleSetRange
|
||||
rjmp appRouterHandleMsgAnyDev_clcRet
|
||||
appRouterHandleMsgAnyDev_handleSetRange:
|
||||
#ifndef APP_ROUTER_NO_ADDR_MGR
|
||||
sts netInterfaceData+NET_IFACE_OFFS_ADDRESS, r18 ; use first address for router itself
|
||||
sts netInterfaceData2+NET_IFACE_OFFS_ADDRESS, r18 ; use same address for both interfaces to save on addresses
|
||||
inc r18 ; start range after router
|
||||
sts appRouterRangeBegin, r18
|
||||
sts appRouterRangeEnd, r19
|
||||
; send ACK
|
||||
ldi r23, NETMSG_CMD_VALUE_SET_ACK
|
||||
rcall Main_SendValueResponse ; (clobbers all, including Y)
|
||||
; let subnodes re-eunumerate
|
||||
ldi r18, NETMSG_CMD_REENUM
|
||||
rcall appRouterSendRangeMsgToDev1 ; (R16, R17, R18, R19, R20, R21, X, Y)
|
||||
rcall appRouterWriteConfToEeprom ; (r16, r17, X)
|
||||
#endif
|
||||
sec
|
||||
ret
|
||||
appRouterHandleMsgAnyDev_clcRet:
|
||||
clc
|
||||
appRouterHandleMsgAnyDev_end:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appRouterHandleDev1Msg @global
|
||||
;
|
||||
; Handle messages from controlled subnet.
|
||||
;
|
||||
; @param X pointer to received message
|
||||
; @return CFLAG set if msg handled, cleared otherwise
|
||||
; @clobbers any, !X
|
||||
|
||||
appRouterHandleDev1Msg:
|
||||
#ifndef APP_ROUTER_NO_ADDR_MGR
|
||||
push xl
|
||||
push xh
|
||||
rcall appRouterHandleDev1Msg_savedX
|
||||
pop xh
|
||||
pop xl
|
||||
rjmp appRouterHandleDev1Msg_end
|
||||
appRouterHandleDev1Msg_savedX:
|
||||
adiw xh:xl, NETMSG_OFFS_CMD
|
||||
ld r16, X
|
||||
sbiw xh:xl, NETMSG_OFFS_CMD
|
||||
cpi r16, NETMSG_CMD_NEED_ADDRESS
|
||||
breq appRouterHandleDev1Msg_handleNeedAddr
|
||||
cpi r16, NETMSG_CMD_CLAIM_ADDRESS
|
||||
breq appRouterHandleDev1Msg_handleClaimAddr
|
||||
; add more here
|
||||
ldi r16, 0
|
||||
rjmp appRouterHandleDev1Msg_clcRet
|
||||
appRouterHandleDev1Msg_handleNeedAddr:
|
||||
ldi r18, NETMSG_CMD_ADDRESS_RANGE
|
||||
rcall appRouterSendRangeMsgToDev1 ; (R16, R17, R18, R19, R20, R21, X, Y)
|
||||
sec
|
||||
rjmp appRouterHandleDev1Msg_end
|
||||
appRouterHandleDev1Msg_handleClaimAddr:
|
||||
rcall NETMSG_Address_Read ; R18=cmd, R19=addr(R18, R19)
|
||||
rcall appRouterIsR19InRange
|
||||
brcs appRouterHandleDev1Msg_end
|
||||
; is not in subnet range, deny
|
||||
rcall appRouterSendDenyAddrR19ToDev1 ; (R16, R17, R18, R19, R20, R21, X, Y)
|
||||
sec
|
||||
rjmp appRouterHandleDev1Msg_end
|
||||
#endif
|
||||
appRouterHandleDev1Msg_clcRet:
|
||||
clc
|
||||
appRouterHandleDev1Msg_end:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appRouterIsR19InRange
|
||||
;
|
||||
; @param R19 address to check against range
|
||||
; @clobbers R16
|
||||
|
||||
appRouterIsR19InRange:
|
||||
lds r16, appRouterRangeBegin
|
||||
cp r19, r16
|
||||
brcs appRouterIsR19InRangeClcRet
|
||||
lds r16, appRouterRangeEnd
|
||||
cp r16, r19
|
||||
brcs appRouterIsR19InRangeClcRet
|
||||
sec
|
||||
rjmp appRouterIsR19InRange_end
|
||||
appRouterIsR19InRangeClcRet:
|
||||
clc
|
||||
appRouterIsR19InRange_end:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appRouterSendDenyAddrR19ToDev1
|
||||
;
|
||||
; @param R19 address to send
|
||||
; @clobbers R16, R17, R18, R19, R20, R21, X, Y
|
||||
|
||||
appRouterSendDenyAddrR19ToDev1:
|
||||
ldi r18, NETMSG_CMD_DENY_ADDRESS ; deny addr
|
||||
rjmp appRouterSendAddrMsgToDev1 ; (R16, R17, R18, R19, R20, R21, X, Y)
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appRouterSendAddrMsgToDev1
|
||||
;
|
||||
; @param R18 command
|
||||
; @param R19 address to send
|
||||
; @clobbers R16 (R17, R18, R19, R20, R21, X, Y)
|
||||
|
||||
appRouterSendAddrMsgToDev1:
|
||||
bigcall NET_Buffer_Alloc ; (R16, R17, X)
|
||||
brcc appRouterSendAddrMsgToDev1_end
|
||||
push r16
|
||||
adiw xh:xl, 1
|
||||
bigcall NETMSG_Address_Write ; (R16, R17, R18, R19, R20, R21)
|
||||
sbiw xh:xl, 1
|
||||
pop r16
|
||||
rcall appRouterSendMsgToDev1 ; (R16, R17, R18, R24, R25, X, Y)
|
||||
appRouterSendAddrMsgToDev1_end:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appRouterSendRangeMsgToDev1
|
||||
;
|
||||
; @param R18 msg code
|
||||
; @return CFLAG set if message enqueued, cleared on error
|
||||
; @clobbers (R16, R17, R18, R19, R20, R21, R24, R25, X, Y)
|
||||
|
||||
appRouterSendRangeMsgToDev1:
|
||||
bigcall NET_Buffer_Alloc ; (R16, R17, X)
|
||||
brcc appRouterSendRangeMsgToDev1_end
|
||||
push r16
|
||||
lds r20, appRouterRangeBegin
|
||||
lds r21, appRouterRangeEnd
|
||||
adiw xh:xl, 1
|
||||
bigcall NETMSG_Range_Write ; (R16, R17, R18, R19, R20, R21)
|
||||
sbiw xh:xl, 1
|
||||
pop r16
|
||||
rcall appRouterSendMsgToDev1 ; (R16, R17, R18, R24, R25, X, Y)
|
||||
appRouterSendRangeMsgToDev1_end:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appRouterSendMsgToDev1
|
||||
;
|
||||
; @param R16 num of allocated buffer
|
||||
; @param X msg to send (points to start of allocated buffer, e.g. buffer header)
|
||||
; @return CFLAG set if message enqueued, cleared on error
|
||||
; @clobbers Y (R16, R17, R18, R24, R25, X)
|
||||
|
||||
appRouterSendMsgToDev1:
|
||||
ldi yl, LOW(netInterfaceData2)
|
||||
ldi yh, HIGH(netInterfaceData2)
|
||||
bigcall NET_Interface_AddOutgoingMsgNum ; (R17, R18, X)
|
||||
brcs appRouterSendMsgToDev1_end
|
||||
bigcall NET_Buffer_ReleaseByNum ; (R16, X)
|
||||
ldi r16, NET_IFACE_OFFS_ERR_NOBUF_LOW
|
||||
rcall NET_Interface_IncCounter16 ; (R24, R25)
|
||||
clc
|
||||
appRouterSendMsgToDev1_end:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appRouterHandleRebootRequest
|
||||
;
|
||||
; Doesn't return if reboot msg is valid.
|
||||
;
|
||||
; @param X pointer to received message
|
||||
|
||||
appRouterHandleRebootRequest:
|
||||
rcall NETMSG_RebootRequestRead
|
||||
brcc appRouterHandleRebootRequest_end
|
||||
; reboot
|
||||
cli
|
||||
bigjmp BOOTLOADER_ADDR
|
||||
appRouterHandleRebootRequest_end:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appRouterHandlePingRequest
|
||||
;
|
||||
; @param X pointer to received message
|
||||
|
||||
appRouterHandlePingRequest:
|
||||
ld r17, X
|
||||
lds r16, (netInterfaceData+NET_IFACE_OFFS_ADDRESS)
|
||||
cp r16, r17
|
||||
breq appRouterHandlePingRequest_forMe
|
||||
cpi r17, 0xff
|
||||
breq appRouterHandlePingRequest_forMe
|
||||
clc
|
||||
rjmp appRouterHandlePingRequest_end
|
||||
appRouterHandlePingRequest_forMe:
|
||||
adiw xh:xl, NETMSG_OFFS_SRCADDR
|
||||
ld r17, X
|
||||
sbiw xh:xl, NETMSG_OFFS_SRCADDR
|
||||
push r17
|
||||
bigcall NET_Buffer_Alloc ; (R16, R17, X)
|
||||
pop r17
|
||||
brcc appRouterHandlePingRequest_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)
|
||||
bigcall NETMSG_Pong_Write ; (R16, R17, R18, R19, R20, X)
|
||||
sbiw xh:xl, 1
|
||||
pop r16 ; buffer num
|
||||
bigcall NET_Interface_AddOrReleaseOutMsg ; (R16, R17, R18, X)
|
||||
appRouterHandlePingRequest_end:
|
||||
ret
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appRouterCheckRecvdMsg
|
||||
;
|
||||
; Read messages from either interface and forward to the other one.
|
||||
;
|
||||
; @return CFLAG set if something done, cleared otherwise
|
||||
|
||||
appRouterCheckRecvdMsg:
|
||||
rcall NET_PeekNextIncomingMsgNum ; check read queue (bufNum->r16)
|
||||
brcc appRouterCheckRecvdMsg_end ; no msg, jmp
|
||||
rcall NET_Buffer_Locate ; (R17)
|
||||
rcall appRouterHandleRouterMsgWithHdr ; filter out router msgs
|
||||
brcs appRouterCheckRecvdMsg_removeMsg ; handled by router code, don't forward
|
||||
; let system handle incoming messages
|
||||
adiw xh:xl, 1
|
||||
rcall appRouterLetSysHandleMsg
|
||||
sbiw xh:xl, 1
|
||||
|
||||
; forward to other interface
|
||||
ld r17, X
|
||||
andi r17, (1<<NET_IFACE_BUFFER_IFACENUM1_BIT) | (1<<NET_IFACE_BUFFER_IFACENUM0_BIT)
|
||||
rcall appRouterReverseInterfaceNum ; (R16, R17)
|
||||
rcall appRouterAddMsgToInterface
|
||||
brcc appRouterCheckRecvdMsg_end ; could not add, jmp
|
||||
rcall NET_GetNextIncomingMsgNum ; take off the queue
|
||||
sec
|
||||
ret
|
||||
appRouterCheckRecvdMsg_removeMsg:
|
||||
rcall NET_GetNextIncomingMsgNum ; take off the queue
|
||||
rcall NET_Buffer_ReleaseByNum ; (R16, X)
|
||||
sec
|
||||
appRouterCheckRecvdMsg_end:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appRouterHandleRouterMsgWithHdr
|
||||
;
|
||||
; @param X pointer to msg
|
||||
; @return CFLAG set if msg handled, cleared otherwise
|
||||
|
||||
appRouterHandleRouterMsgWithHdr:
|
||||
ld r17, X
|
||||
adiw xh:xl, 1
|
||||
andi r17, (1<<NET_IFACE_BUFFER_IFACENUM1_BIT) | (1<<NET_IFACE_BUFFER_IFACENUM0_BIT)
|
||||
cpi r17, NETDEV1_IFACENUM
|
||||
brne appRouterHandleRouterMsgWithHdr_any
|
||||
#ifndef APP_ROUTER_NO_ADDR_MGR
|
||||
rcall appRouterHandleDev1Msg ; handle messages from controlled subnet
|
||||
brcs appRouterHandleRouterMsgWithHdr_msgHandled
|
||||
#endif
|
||||
appRouterHandleRouterMsgWithHdr_any:
|
||||
rcall appRouterHandleMsgAnyDev ; handle any msg
|
||||
brcs appRouterHandleRouterMsgWithHdr_msgHandled
|
||||
sbiw xh:xl, 1 ; CFLAG cleared
|
||||
rjmp appRouterHandleRouterMsgWithHdr_end
|
||||
appRouterHandleRouterMsgWithHdr_msgHandled:
|
||||
sbiw xh:xl, 1
|
||||
sec
|
||||
appRouterHandleRouterMsgWithHdr_end:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appRouterLetSysHandleMsg
|
||||
;
|
||||
; @param X pointer to msg to handle (point behind the buffer header!)
|
||||
; @clobbers any, !X
|
||||
|
||||
appRouterLetSysHandleMsg:
|
||||
ld r16, X
|
||||
cpi r16, 0xff
|
||||
breq appRouterLetSysHandleMsg_forMe
|
||||
lds r17, netInterfaceData+NET_IFACE_OFFS_ADDRESS
|
||||
cp r16, r17
|
||||
brne appRouterLetSysHandleMsg_end
|
||||
appRouterLetSysHandleMsg_forMe:
|
||||
push xl
|
||||
push xh
|
||||
rcall onMessageReceived
|
||||
pop xh
|
||||
pop xl
|
||||
push xl
|
||||
push xh
|
||||
rcall mainModulesOnPacketReceived
|
||||
pop xh
|
||||
pop xl
|
||||
push xl
|
||||
push xh
|
||||
rcall mainAppsOnPacketReceived
|
||||
pop xh
|
||||
pop xl
|
||||
appRouterLetSysHandleMsg_end:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appRouterReverseInterfaceNum
|
||||
;
|
||||
; @param r17 buffer num
|
||||
; @return r17 reversed interface number
|
||||
; @clobbers r16, r17
|
||||
|
||||
appRouterReverseInterfaceNum:
|
||||
ldi r16, (1<<NET_IFACE_BUFFER_IFACENUM1_BIT) | (1<<NET_IFACE_BUFFER_IFACENUM0_BIT)
|
||||
eor r17, r16
|
||||
and r17, r16
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appRouterAddMsgToInterface
|
||||
; @param r16 buffer num
|
||||
; @param r17 interface num
|
||||
|
||||
appRouterAddMsgToInterface:
|
||||
cpi r17, NETDEV0_IFACENUM
|
||||
brne appRouterAddMsgToInterface_notNetDev0
|
||||
ldi yl, LOW(netInterfaceData)
|
||||
ldi yh, HIGH(netInterfaceData)
|
||||
rjmp NET_Interface_AddOutgoingMsgNum ; try to add msg to interface
|
||||
appRouterAddMsgToInterface_notNetDev0:
|
||||
ldi yl, LOW(netInterfaceData2)
|
||||
ldi yh, HIGH(netInterfaceData2)
|
||||
rjmp NET_Interface_AddOutgoingMsgNum ; try to add msg to interface
|
||||
appRouterAddMsgToInterface_end:
|
||||
clc
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appRouterWriteConfToEeprom
|
||||
;
|
||||
; @clobbers R16, X (R17)
|
||||
|
||||
appRouterWriteConfToEeprom:
|
||||
; write range begin
|
||||
ldi xl, LOW(EEPROM_OFFS_ROUTER_RANGE_BEGIN)
|
||||
ldi xh, HIGH(EEPROM_OFFS_ROUTER_RANGE_BEGIN)
|
||||
lds r16, appRouterRangeBegin
|
||||
rcall Eeprom_WriteByteIfChanged ; (R17)
|
||||
brcc appRouterWriteConfToEeprom_end
|
||||
|
||||
; write range end
|
||||
ldi xl, LOW(EEPROM_OFFS_ROUTER_RANGE_END)
|
||||
ldi xh, HIGH(EEPROM_OFFS_ROUTER_RANGE_END)
|
||||
lds r16, appRouterRangeEnd
|
||||
rcall Eeprom_WriteByteIfChanged ; (R17)
|
||||
appRouterWriteConfToEeprom_end:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine appRouterReadConfFromEeprom
|
||||
;
|
||||
; @clobbers R16, X (R17)
|
||||
|
||||
appRouterReadConfFromEeprom:
|
||||
; read range begin
|
||||
ldi xl, LOW(EEPROM_OFFS_ROUTER_RANGE_BEGIN)
|
||||
ldi xh, HIGH(EEPROM_OFFS_ROUTER_RANGE_BEGIN)
|
||||
rcall Eeprom_ReadByte
|
||||
brcc appRouterReadConfFromEeprom_end
|
||||
cpi r16, 0xff
|
||||
breq appRouterReadConfFromEeprom_okay ; not set, jmp
|
||||
cpi r16, 2 ; range should at least start at 2 to assign 1 to router
|
||||
brcs appRouterReadConfFromEeprom_okay
|
||||
sts appRouterRangeBegin, r16
|
||||
dec r16
|
||||
sts netInterfaceData+NET_IFACE_OFFS_ADDRESS, r16 ; use addr rangeBegin-1 for router itself
|
||||
sts netInterfaceData2+NET_IFACE_OFFS_ADDRESS, r16 ; use same address for both interfaces to save on addresses
|
||||
|
||||
; read range end
|
||||
ldi xl, LOW(EEPROM_OFFS_ROUTER_RANGE_END)
|
||||
ldi xh, HIGH(EEPROM_OFFS_ROUTER_RANGE_END)
|
||||
rcall Eeprom_ReadByte
|
||||
brcc appRouterReadConfFromEeprom_end
|
||||
cpi r16, 0xff
|
||||
breq appRouterReadConfFromEeprom_okay
|
||||
sts appRouterRangeEnd, r16
|
||||
appRouterReadConfFromEeprom_okay:
|
||||
sec
|
||||
appRouterReadConfFromEeprom_end:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
; ***************************************************************************
|
||||
; defines
|
||||
|
||||
.equ APP_STATS_INTERVAL_MINS = 11
|
||||
.equ APP_STATS_INTERVAL_MINS = 30
|
||||
|
||||
|
||||
|
||||
@@ -62,10 +62,6 @@ AppStats_OnEveryMinute:
|
||||
ret
|
||||
|
||||
AppStats_OnEveryMinute_noIrq:
|
||||
; ldi yl, LOW(netInterfaceData)
|
||||
; ldi yh, HIGH(netInterfaceData)
|
||||
; rcall AppNetwork_SendRxdStats ; debug
|
||||
|
||||
lds r16, appStatsTimer
|
||||
inc r16
|
||||
cpi r16, APP_STATS_INTERVAL_MINS
|
||||
@@ -73,97 +69,68 @@ AppStats_OnEveryMinute_noIrq:
|
||||
clr r16
|
||||
AppStats_OnEveryMinute_store:
|
||||
sts appStatsTimer, r16
|
||||
|
||||
mov r17, r16
|
||||
andi r17, 3
|
||||
brne AppStats_OnEveryMinute_sendStats
|
||||
; send device announcement
|
||||
push yl
|
||||
push yh
|
||||
ldi yl, LOW(netInterfaceData)
|
||||
ldi yh, HIGH(netInterfaceData)
|
||||
rcall AppNetwork_SendDevice
|
||||
#ifdef APP_STATS_NETDEV2
|
||||
ldi yl, LOW(netInterfaceData2)
|
||||
ldi yh, HIGH(netInterfaceData2)
|
||||
rcall AppNetwork_SendDevice
|
||||
#endif
|
||||
pop yh
|
||||
pop yl
|
||||
AppStats_OnEveryMinute_sendStats:
|
||||
cpi r16, 2
|
||||
breq AppStats_OnEveryMinute_sendMemStats
|
||||
|
||||
cpi r16, 3
|
||||
breq AppStats_OnEveryMinute_sendRecvStats1
|
||||
|
||||
cpi r16, 5
|
||||
breq AppStats_OnEveryMinute_sendSendStats1
|
||||
|
||||
#ifdef APP_STATS_NETDEV2
|
||||
cpi r16, 6
|
||||
breq AppStats_OnEveryMinute_sendRecvStats2
|
||||
|
||||
cpi r16, 7
|
||||
breq AppStats_OnEveryMinute_sendSendStats2
|
||||
#endif
|
||||
; add more here
|
||||
ret
|
||||
AppStats_OnEveryMinute_sendMemStats:
|
||||
rjmp AppNetwork_SendMemStats
|
||||
|
||||
AppStats_OnEveryMinute_sendRecvStats1:
|
||||
ldi yl, LOW(netInterfaceData)
|
||||
ldi yh, 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
|
||||
cpi r16, 5
|
||||
breq AppStats_OnEveryMinute_sendIoErrs
|
||||
cpi r16, 6
|
||||
breq AppStats_OnEveryMinute_sendNoBufErrs
|
||||
cpi r16, 7
|
||||
breq AppStats_OnEveryMinute_sendCollisionErrs
|
||||
cpi r16, 8
|
||||
breq AppStats_OnEveryMinute_sendBusyErrs
|
||||
#ifdef MODULES_HEAP
|
||||
cpi r16, 9
|
||||
breq AppStats_OnEveryMinute_sendHeapUsed
|
||||
cpi r16, 10
|
||||
breq AppStats_OnEveryMinute_sendHeapfree
|
||||
#endif
|
||||
rjmp AppNetwork_SendRxdStats
|
||||
|
||||
AppStats_OnEveryMinute_sendDevice:
|
||||
rjmp AppNetwork_SendDevice
|
||||
AppStats_OnEveryMinute_sendSendStats1:
|
||||
ldi yl, LOW(netInterfaceData)
|
||||
ldi yh, HIGH(netInterfaceData)
|
||||
rjmp AppNetwork_SendTxdStats
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
#ifdef MODULES_HEAP
|
||||
AppStats_OnEveryMinute_sendHeapUsed:
|
||||
ldi r17, AQHOME_VALUEID_STATS_HEAP_USED
|
||||
lds r18, heapUsed
|
||||
lds r19, heapUsed+1
|
||||
rjmp appStatsSend16BitValue
|
||||
AppStats_OnEveryMinute_sendHeapfree:
|
||||
ldi r17, AQHOME_VALUEID_STATS_HEAP_FREE
|
||||
lds r18, heapFree
|
||||
lds r19, heapFree+1
|
||||
rjmp appStatsSend16BitValue
|
||||
#ifdef APP_STATS_NETDEV2
|
||||
AppStats_OnEveryMinute_sendRecvStats2:
|
||||
ldi yl, LOW(netInterfaceData2)
|
||||
ldi yh, HIGH(netInterfaceData2)
|
||||
rjmp AppNetwork_SendRxdStats
|
||||
|
||||
AppStats_OnEveryMinute_sendSendStats2:
|
||||
ldi yl, LOW(netInterfaceData2)
|
||||
ldi yh, HIGH(netInterfaceData2)
|
||||
rjmp AppNetwork_SendTxdStats
|
||||
#endif
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine AppStats_OnEveryMinute @global
|
||||
;
|
||||
; @param R17 value id
|
||||
; @param R19:R18 value
|
||||
|
||||
appStatsSend16BitValue:
|
||||
ldi r20, 1
|
||||
clr r21
|
||||
ldi r22, AQHOME_VALUETYPE_STATS
|
||||
bigjmp Main_SendValueReport
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -27,7 +27,11 @@
|
||||
wait_50us.asm
|
||||
watchdog.asm
|
||||
list.asm
|
||||
list_t.asm
|
||||
tree.asm
|
||||
tree_t.asm
|
||||
eeprom-r.asm
|
||||
eeprom-w.asm
|
||||
</extradist>
|
||||
|
||||
</gwbuild>
|
||||
|
||||
80
avr/common/eeprom-r.asm
Normal file
80
avr/common/eeprom-r.asm
Normal file
@@ -0,0 +1,80 @@
|
||||
; ***************************************************************************
|
||||
; 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_EEPROM_R_H
|
||||
#define AQH_AVR_COMMON_EEPROM_R_H
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine Eeprom_ReadByte
|
||||
;
|
||||
; Read a byte from EEPROM (see example in ATtiny24/44/84 manual p.19).
|
||||
;
|
||||
; @param X EEPROM Address to read from
|
||||
; @return CFLAG set if address okay, cleared if out of range
|
||||
; @return R16 byte read
|
||||
; @return X EEPROM Address incremented
|
||||
; @clobbers none
|
||||
|
||||
Eeprom_ReadByte:
|
||||
rcall Eeprom_CheckAddr
|
||||
brcs Eeprom_ReadByte_addrOk
|
||||
ret
|
||||
Eeprom_ReadByte_addrOk:
|
||||
; call routine with IRQs disabled
|
||||
push r15
|
||||
inr r15, SREG
|
||||
cli
|
||||
rcall Eeprom_ReadByte_noirq
|
||||
outr SREG, r15
|
||||
pop r15
|
||||
sec
|
||||
ret
|
||||
Eeprom_ReadByte_noirq:
|
||||
; wait until EEPROM ready
|
||||
Eeprom_ReadByte_waitLoop:
|
||||
.ifdef EEPE
|
||||
sbic EECR, EEPE ; wait for previous write to complete (if any)
|
||||
.else
|
||||
sbic EECR, EEWE ; wait for previous write to complete (if any)
|
||||
.endif
|
||||
rjmp Eeprom_ReadByte_waitLoop
|
||||
; read from EEPROM
|
||||
out EEARH, xh ; set EEPROM address
|
||||
out EEARL, xl
|
||||
sbi EECR, EERE ; start EEPROM read by writing EERE
|
||||
in r16, EEDR ; read data from data register
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine Eeprom_CheckAddr
|
||||
;
|
||||
;
|
||||
; @param X EEPROM Address to validate
|
||||
; @return CFLAG set if address okay, cleared if out of range
|
||||
; @clobbers r16
|
||||
|
||||
Eeprom_CheckAddr:
|
||||
mov r16, xl
|
||||
subi r16, LOW(EEPROMEND)
|
||||
mov r16, xh
|
||||
sbci r16, HIGH(EEPROMEND)
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
|
||||
#endif ; AQH_AVR_COMMON_EEPROM_R_H
|
||||
|
||||
|
||||
100
avr/common/eeprom-w.asm
Normal file
100
avr/common/eeprom-w.asm
Normal file
@@ -0,0 +1,100 @@
|
||||
; ***************************************************************************
|
||||
; 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_EEPROM_W_H
|
||||
#define AQH_AVR_COMMON_EEPROM_W_H
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; Utils_WriteEepromIncr
|
||||
;
|
||||
; Write a byte to EEPROM (see example in ATtiny24/44/84 manual p.18).
|
||||
;
|
||||
; @param R16 byte to write
|
||||
; @param X EEPROM Address to write to
|
||||
; @return CFLAG set if data written, cleared on error
|
||||
; @clobbers R17
|
||||
|
||||
Eeprom_WriteByte:
|
||||
mov r17, r16
|
||||
rcall Eeprom_CheckAddr ; (r16)
|
||||
mov r16, r17
|
||||
brcs Eeprom_WriteByte_addrOk
|
||||
ret
|
||||
Eeprom_WriteByte_addrOk:
|
||||
; call routine with IRQs disabled
|
||||
push r15
|
||||
inr r15, SREG
|
||||
cli
|
||||
rcall Eeprom_WriteByte_noirq
|
||||
outr SREG, r15
|
||||
pop r15
|
||||
sec
|
||||
ret
|
||||
Eeprom_WriteByte_noirq:
|
||||
; wait for EEPROM to be ready
|
||||
Eeprom_WriteByte_waitLoop:
|
||||
.ifdef EEPE
|
||||
sbic EECR, EEPE ; wait for previous write to complete (if any)
|
||||
.else
|
||||
sbic EECR, EEWE ; wait for previous write to complete (if any)
|
||||
.endif
|
||||
rjmp Eeprom_WriteByte_waitLoop
|
||||
; write data
|
||||
.ifdef EEPM1
|
||||
ldi r17, (0<<EEPM1) | (0<<EEPM0) ; set programming mode
|
||||
.endif
|
||||
out EECR, r17
|
||||
out EEARH, xh ; set EEPROM address
|
||||
out EEARL, xl
|
||||
out EEDR, r16 ; write data to data register
|
||||
.ifdef EEMPE
|
||||
sbi EECR, EEMPE ; write logical one to EEMPE
|
||||
.else
|
||||
sbi EECR, EEMWE ; write logical one to EEMWE
|
||||
.endif
|
||||
.ifdef EEPE
|
||||
sbi EECR, EEPE ; start EEPROM write by setting EEPE
|
||||
.else
|
||||
sbi EECR, EEWE ; start EEPROM write by setting EEWE
|
||||
.endif
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine Eeprom_WriteByteIfChanged @global
|
||||
;
|
||||
; Only write EEPROM byte if changed from current value (save on write cycles)
|
||||
;
|
||||
; @param r16 byte to write
|
||||
; @param X eeprom address to write to
|
||||
; @clobbers r17
|
||||
|
||||
Eeprom_WriteByteIfChanged:
|
||||
mov r17, r16
|
||||
rcall Eeprom_ReadByte
|
||||
brcc Eeprom_WriteByteIfChanged_end
|
||||
cp r16, r17
|
||||
sec
|
||||
breq Eeprom_WriteByteIfChanged_end
|
||||
mov r16, r17
|
||||
rcall Eeprom_WriteByte ; (R17)
|
||||
Eeprom_WriteByteIfChanged_end:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif ; AQH_AVR_COMMON_EEPROM_W_H
|
||||
|
||||
|
||||
135
avr/common/eeprom_tlv.asm
Normal file
135
avr/common/eeprom_tlv.asm
Normal file
@@ -0,0 +1,135 @@
|
||||
; ***************************************************************************
|
||||
; 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_EEPROM_TLV_H
|
||||
#define AQH_AVR_COMMON_EEPROM_TLV_H
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine EepromTlv_AddTlv @global
|
||||
;
|
||||
; @param r16 type (must not be 0xff!)
|
||||
; @param r17 length
|
||||
; @return CFLAG set if free bytes found, cleared on error
|
||||
; @return X EEPROM address of data for TLV (behind TLV header)
|
||||
; @clobbers R16, R20, R21, X (R18)
|
||||
|
||||
EepromTlv_AddTlv:
|
||||
mov r20, r16
|
||||
mov r21, r17
|
||||
ldi r16, 0xff
|
||||
rcall EepromTlv_FindFirst ; (R18)
|
||||
brcc EepromTlv_AddTlv_end
|
||||
cpi r17, 0xff
|
||||
brne EepromTlv_AddTlv_clcEnd
|
||||
add xl, r21 ; wanted size
|
||||
adc xh, r21
|
||||
sub xh, r21
|
||||
rcall Eeprom_CheckAddr ; check end address
|
||||
brcc EepromTlv_AddTlv_end
|
||||
sub xl, r21
|
||||
sbc xh, r21
|
||||
add xh, r21
|
||||
sbiw xh:xl, 2
|
||||
mov r16, r20 ; type
|
||||
rcall Eeprom_WriteByte
|
||||
adiw xh:xl, 1
|
||||
mov r16, r21 ; length
|
||||
rcall Eeprom_WriteByte
|
||||
adiw xh:xl, 1
|
||||
sec
|
||||
rjmp EepromTlv_AddTlv_end
|
||||
EepromTlv_AddTlv_clcEnd:
|
||||
clc
|
||||
EepromTlv_AddTlv_end:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine EepromTlv_FindFirst @global
|
||||
;
|
||||
; Find first matching TLV
|
||||
;
|
||||
; @param r16 TLV type to find
|
||||
; @return CFLAG set if TLV found, cleared otherwise
|
||||
; @return r16 type
|
||||
; @return r17 length
|
||||
; @return X points to begin of TLV data
|
||||
; @clobbers r18
|
||||
|
||||
EepromTlv_FindFirst:
|
||||
ldi xl, LOW(EEPROM_OFFS_TLV)
|
||||
ldi xh, HIGH(EEPROM_OFFS_TLV)
|
||||
rjmp EepromTlv_Find
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine EepromTlv_Find @global
|
||||
;
|
||||
; @param r16 TLV type to find
|
||||
; @param X EEPROM address to start search
|
||||
; @return CFLAG set if TLV found, cleared otherwise
|
||||
; @return r16 type
|
||||
; @return r17 length
|
||||
; @return X points to begin of TLV data
|
||||
; @clobbers r18
|
||||
|
||||
EepromTlv_Find:
|
||||
mov r18, r16
|
||||
EepromTlv_Find_loop:
|
||||
rcall EepromTlv_ReadHeader
|
||||
brcc EepromTlv_Find_notFound
|
||||
cpi r16, r18 ; the one we wanted?
|
||||
breq EepromTlv_Find_found
|
||||
add xl, r17 ; skip TLV data
|
||||
adc xh, r17
|
||||
sub xh, r17
|
||||
rjmp EepromTlv_Find_loop
|
||||
EepromTlv_Find_notFound:
|
||||
clc
|
||||
rjmp EepromTlv_Find_end
|
||||
EepromTlv_Find_found:
|
||||
sec
|
||||
EepromTlv_Find_end:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine EepromTlv_ReadHeader
|
||||
;
|
||||
; @param X EEPROM address
|
||||
; @return CFLAG set if address okay, cleared if out of range
|
||||
; @return r16 type
|
||||
; @return r17 length (only data length, can be 0)
|
||||
; @return X EEPROM address behind TLV header
|
||||
; @clobbers none
|
||||
|
||||
EepromTlv_ReadHeader:
|
||||
rcall Eeprom_ReadByteIncr ; read type
|
||||
brcc EepromTlv_ReadHeader
|
||||
adiw xh:xl, 1
|
||||
push r16
|
||||
rcall Eeprom_ReadByteIncr ; read length
|
||||
mov r17, r16
|
||||
pop r16
|
||||
brcc EepromTlv_ReadHeader
|
||||
adiw xh:xl, 1
|
||||
sec
|
||||
EepromTlv_ReadHeader:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
@@ -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
240
avr/common/list_t.asm
Normal 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
|
||||
@@ -52,7 +52,7 @@ l_loop:
|
||||
brcs l_loop
|
||||
rjmp l_end ; use cleared CFLAG
|
||||
l_foundfree:
|
||||
ldi r16, 0x80 ; mark as used
|
||||
ldi r16, 0x10 ; mark as used
|
||||
st X, r16
|
||||
mov r16, r17
|
||||
sec ; set CFLAG, return bufnum in r16, pointre in X
|
||||
|
||||
@@ -120,7 +120,7 @@ RingBufferY_Reset:
|
||||
;
|
||||
; @return CFLAG on success, cleared on error
|
||||
; @return r16 byte read
|
||||
; @param Y pointer to start of interface data
|
||||
; @param Y base address of ringbuffer struct
|
||||
; @clobbers R17, R18, X
|
||||
|
||||
RingBufferY_ReadByteGuarded:
|
||||
|
||||
@@ -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
381
avr/common/tree_t.asm
Normal 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
|
||||
|
||||
|
||||
|
||||
@@ -7,29 +7,6 @@
|
||||
; * Please see toplevel file COPYING of that project for license details. *
|
||||
; ***************************************************************************
|
||||
|
||||
#if 0
|
||||
; M_IO_READ DEST, SRC
|
||||
.macro M_IO_READ
|
||||
.if @1 < 64
|
||||
in @0, @1
|
||||
.else
|
||||
lds @0, @1
|
||||
.endif
|
||||
.endmacro
|
||||
|
||||
|
||||
|
||||
; M_IO_WRITE DEST, SRC
|
||||
.macro M_IO_WRITE
|
||||
.if @0 < 64
|
||||
out @0, @1
|
||||
.else
|
||||
sts @0, @1
|
||||
.endif
|
||||
.endmacro
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
; inr DEST, SRC
|
||||
.macro inr
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
; @clobbers r22
|
||||
|
||||
Utils_WaitFor50MicroSecs:
|
||||
Utils_WaitNanoSecs 50000, 7, r22 ; wait for 50us (minus RCALL and RET)
|
||||
Utils_WaitNanoSecs 25000, 0, r22 ; wait for 25us
|
||||
Utils_WaitNanoSecs 25000, 7, r22 ; wait for 25us (minus RCALL and RET)
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
@@ -26,14 +26,19 @@
|
||||
all
|
||||
c01
|
||||
c02
|
||||
n14
|
||||
n16
|
||||
n20
|
||||
n21
|
||||
n22
|
||||
n23
|
||||
n24
|
||||
n25
|
||||
n26
|
||||
n27
|
||||
n28
|
||||
r05
|
||||
r06
|
||||
s03
|
||||
t03
|
||||
t04
|
||||
</subdirs>
|
||||
|
||||
</gwbuild>
|
||||
|
||||
@@ -29,6 +29,18 @@ initApps:
|
||||
bigcall AppNetwork_Init
|
||||
#endif
|
||||
|
||||
#ifdef APPS_ROUTER
|
||||
bigcall AppRouter_Init
|
||||
#endif
|
||||
|
||||
#ifdef APPS_HUB
|
||||
bigcall AppHub_Init
|
||||
#endif
|
||||
|
||||
#ifdef APPS_FORWARDER
|
||||
bigcall AppForwarder_Init
|
||||
#endif
|
||||
|
||||
#ifdef APPS_MOTION
|
||||
bigcall AppMotion_Init
|
||||
#endif
|
||||
@@ -62,9 +74,37 @@ initApps:
|
||||
;
|
||||
|
||||
runApps:
|
||||
clr r16
|
||||
#ifdef APPS_ROUTER
|
||||
push r16
|
||||
bigcall AppRouter_Run
|
||||
pop r16
|
||||
sbci r16, 0 ; decrease r16 only if CFLAG set
|
||||
#endif
|
||||
|
||||
#ifdef APPS_HUB
|
||||
push r16
|
||||
bigcall AppHub_Run
|
||||
pop r16
|
||||
sbci r16, 0 ; decrease r16 only if CFLAG set
|
||||
#endif
|
||||
|
||||
#ifdef APPS_FORWARDER
|
||||
push r16
|
||||
bigcall AppForwarder_Run
|
||||
pop r16
|
||||
sbci r16, 0 ; decrease r16 only if CFLAG set
|
||||
#endif
|
||||
|
||||
; add more modules here
|
||||
|
||||
tst r16
|
||||
clc
|
||||
breq runApps_end
|
||||
sec
|
||||
runApps_end:
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
@@ -46,6 +57,12 @@
|
||||
|
||||
|
||||
|
||||
.equ TLV_OFFS_LEN = 0
|
||||
.equ TLV_OFFS_TYPE = 1
|
||||
.equ TLV_OFFS_VALUE = 2
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; EEPROM positions
|
||||
|
||||
@@ -65,5 +82,18 @@
|
||||
.equ EEPROM_OFFS_MAL_CONF_SRC2_VALUEID = 19 ; 1 byte
|
||||
.equ EEPROM_OFFS_MAL_CONF_RGBWVALUE = 20 ; 4 bytes
|
||||
|
||||
; next is 24
|
||||
.equ EEPROM_OFFS_ROUTER_RANGE_BEGIN = 24 ; 1 byte
|
||||
.equ EEPROM_OFFS_ROUTER_RANGE_END = 25 ; 1 byte
|
||||
; next is 26
|
||||
|
||||
|
||||
.equ EEPROM_OFFS_TLV = 32 ; begin TLV area here
|
||||
|
||||
|
||||
|
||||
|
||||
.equ EEPROM_TLV_ROUTER_RANGE = 0x10 ; 2 bytes (range begin, range end)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -103,13 +103,11 @@ systemSetupTimer0: ; setup timer for IRQ every 100ms
|
||||
ldi r16, 1
|
||||
sts baseTimerModuleReloadValue, r16
|
||||
sts baseTimerModuleTickCounter, r16
|
||||
.endif
|
||||
|
||||
;
|
||||
; Settings for clock 8Mhz
|
||||
; use timer0 with OCR0=78 (irq every 9.984 millisecs), baseTimerModuleReloadValue 10
|
||||
;
|
||||
.if clock == 8000000
|
||||
.elif clock == 8000000
|
||||
; CMP interrupt about every 10ms
|
||||
ldi r16, 78-1
|
||||
outr OCR0A, r16
|
||||
@@ -117,6 +115,24 @@ systemSetupTimer0: ; setup timer for IRQ every 100ms
|
||||
ldi r16, 10
|
||||
sts baseTimerModuleReloadValue, r16
|
||||
sts baseTimerModuleTickCounter, r16
|
||||
.elif clock == 10000000
|
||||
; CMP-A interrupt about every 10ms
|
||||
ldi r16, 98-1 ; (10,000,000/1024)/10 = 97.65625
|
||||
outr OCR0A, r16
|
||||
|
||||
ldi r16, 10
|
||||
sts baseTimerModuleReloadValue, r16
|
||||
sts baseTimerModuleTickCounter, r16
|
||||
.elif clock == 20000000
|
||||
; CMP-A interrupt about every 5ms
|
||||
ldi r16, 98-1
|
||||
outr OCR0A, r16
|
||||
|
||||
ldi r16, 20
|
||||
sts baseTimerModuleReloadValue, r16
|
||||
sts baseTimerModuleTickCounter, r16
|
||||
.else
|
||||
.error "Unhandled clock frequency"
|
||||
.endif
|
||||
|
||||
ldi r16, (1<<OCF0A) ; clear pending interrupts
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -68,23 +68,88 @@
|
||||
|
||||
|
||||
#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
|
||||
|
||||
|
||||
|
||||
#ifdef MODULES_COM2W
|
||||
.include "modules/com2w/defs.asm"
|
||||
.include "modules/com2w/com2w.asm"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef MODULES_COM2W0
|
||||
.include "modules/com2w/defs.asm"
|
||||
.include "modules/com2w/common.asm"
|
||||
.include "modules/com2w/com2w0.asm"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef MODULES_COM2W1
|
||||
.include "modules/com2w/defs.asm"
|
||||
.include "modules/com2w/common.asm"
|
||||
.include "modules/com2w/com2w1.asm"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef MODULES_COM2WN
|
||||
.include "modules/com2w/defs.asm"
|
||||
.include "modules/com2w/com2wn_init.asm"
|
||||
.include "modules/com2w/com2wn_io.asm"
|
||||
.include "modules/com2w/com2wn_irq.asm"
|
||||
.include "modules/com2w/com2wn_recv.asm"
|
||||
.include "modules/com2w/com2wn_run.asm"
|
||||
.include "modules/com2w/com2wn_send.asm"
|
||||
.include "modules/com2w/com2wn_wait.asm"
|
||||
.include "modules/com2w/com2wn_data.asm"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef MODULES_UARTFD0
|
||||
.include "modules/uart_fd/defs.asm"
|
||||
.include "modules/uart_fd/macros.asm"
|
||||
.include "modules/uart_fd/uartfd0.asm"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef MODULES_UARTFD1
|
||||
.include "modules/uart_fd/defs.asm"
|
||||
.include "modules/uart_fd/macros.asm"
|
||||
.include "modules/uart_fd/uartfd1.asm"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef MODULES_CLOCK
|
||||
.include "modules/clock/main.asm"
|
||||
#endif
|
||||
@@ -96,6 +161,16 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef MODULES_LED_SIGNAL
|
||||
.include "modules/led_signal/main.asm"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef MODULES_LED_ACTIVITY
|
||||
.include "modules/led_activity/main.asm"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef MODULES_TWI_MASTER
|
||||
.include "modules/twimaster/main.asm"
|
||||
#endif
|
||||
@@ -144,6 +219,9 @@
|
||||
|
||||
#ifdef MODULES_CCS811
|
||||
.include "modules/ccs811/main.asm"
|
||||
#ifdef MODULES_NETWORK
|
||||
.include "modules/ccs811/send.asm"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef MODULES_TCRT1000
|
||||
@@ -157,6 +235,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 +247,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 +274,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"
|
||||
@@ -198,6 +303,44 @@
|
||||
.include "modules/network/msg/reboot-d.asm"
|
||||
.include "modules/network/msg/reboot-r.asm"
|
||||
.include "modules/network/msg/pong-w.asm"
|
||||
.include "modules/network/msg/range-d.asm"
|
||||
.include "modules/network/msg/range-r.asm"
|
||||
.include "common/eeprom-r.asm"
|
||||
.include "common/eeprom-w.asm"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef APPS_ROUTER
|
||||
.include "apps/router/main.asm"
|
||||
.include "modules/network/msg/reboot-d.asm"
|
||||
.include "modules/network/msg/reboot-r.asm"
|
||||
.include "modules/network/msg/pong-w.asm"
|
||||
.include "modules/network/msg/range-d.asm"
|
||||
.include "modules/network/msg/range-r.asm"
|
||||
.include "modules/network/msg/range-w.asm"
|
||||
.include "common/eeprom-r.asm"
|
||||
.include "common/eeprom-w.asm"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef APPS_HUB
|
||||
.include "apps/hub/main.asm"
|
||||
.include "modules/network/msg/reboot-d.asm"
|
||||
.include "modules/network/msg/reboot-r.asm"
|
||||
.include "modules/network/msg/pong-w.asm"
|
||||
.include "modules/network/msg/range-d.asm"
|
||||
.include "modules/network/msg/range-r.asm"
|
||||
.include "modules/network/msg/range-w.asm"
|
||||
.include "common/eeprom-r.asm"
|
||||
.include "common/eeprom-w.asm"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef APPS_FORWARDER
|
||||
.include "apps/forwarder/main.asm"
|
||||
.include "modules/network/msg/reboot-r.asm"
|
||||
.include "modules/network/msg/reboot-d.asm"
|
||||
.include "modules/network/msg/pong-w.asm"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -55,11 +55,35 @@ main:
|
||||
|
||||
main_loop:
|
||||
bigcall systemSleep ; system-dependant
|
||||
bigcall runModules
|
||||
bigcall runApps
|
||||
|
||||
bigcall onEveryLoop ; call into main app
|
||||
|
||||
; run loop as long as some run function returns with CFLAG set
|
||||
clr r17
|
||||
main_runLoop:
|
||||
push r17
|
||||
clr r16
|
||||
push r16
|
||||
bigcall runModules
|
||||
pop r16
|
||||
sbci r16, 0
|
||||
|
||||
push r16
|
||||
bigcall runApps
|
||||
pop r16
|
||||
sbci r16, 0
|
||||
|
||||
push r16
|
||||
bigcall onEveryLoop ; call into main app
|
||||
pop r16
|
||||
pop r17
|
||||
|
||||
tst r16
|
||||
breq main_endRunLoop
|
||||
inc r17
|
||||
cpi r17, 10
|
||||
brcc main_endRunLoop
|
||||
brne main_runLoop
|
||||
main_endRunLoop:
|
||||
|
||||
#ifdef MODULES_NETWORK
|
||||
#ifndef MAIN_WITHOUT_MSG_HANDLING
|
||||
rcall mainHandleMessages
|
||||
@@ -91,6 +115,16 @@ onSystemTimerTick:
|
||||
bigcall LedSimple_Every100ms
|
||||
#endif
|
||||
|
||||
#ifdef MODULES_LED_SIGNAL
|
||||
bigcall LedSignal_Every100ms
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef MODULES_LED_ACTIVITY
|
||||
bigcall LedActivity_Every100ms
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef MODULES_UART_BITBANG
|
||||
bigcall UART_BitBang_Every100ms
|
||||
#endif
|
||||
@@ -103,14 +137,47 @@ onSystemTimerTick:
|
||||
bigcall TtyOnUart1_Periodically
|
||||
#endif
|
||||
|
||||
#ifdef MODULES_UARTFD0
|
||||
bigcall UARTFD0_Every100ms
|
||||
#endif
|
||||
|
||||
#ifdef MODULES_UARTFD1
|
||||
bigcall UARTFD1_Every100ms
|
||||
#endif
|
||||
|
||||
#ifdef MODULES_COMONUART0
|
||||
bigcall ComOnUart0_Periodically
|
||||
#endif
|
||||
|
||||
#ifdef MODULES_COMONUART1
|
||||
bigcall ComOnUart1_Periodically
|
||||
#endif
|
||||
|
||||
#ifdef MODULES_COM2W
|
||||
bigcall COM2W_Every100ms
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef MODULES_COM2W0
|
||||
bigcall COM2W0_Periodically
|
||||
#endif
|
||||
|
||||
#ifdef MODULES_COM2W1
|
||||
bigcall COM2W1_Periodically
|
||||
#endif
|
||||
|
||||
#ifdef MODULES_COM2WN
|
||||
bigcall COM2WN_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 +212,11 @@ sysOnEverySecond:
|
||||
#ifdef APPS_REPORTSENSORS
|
||||
bigcall AppReportSensors_OnEverySecond
|
||||
#endif
|
||||
|
||||
#ifdef MODULES_SGP30
|
||||
bigcall SGP30_EverySecond
|
||||
#endif
|
||||
|
||||
bigjmp onEverySecond
|
||||
; @end
|
||||
|
||||
@@ -154,6 +226,10 @@ sysOnEveryMinute:
|
||||
bigcall AppStats_OnEveryMinute
|
||||
#endif
|
||||
|
||||
#ifdef MODULES_CCS811
|
||||
bigcall CCS811_OnEveryMinute
|
||||
#endif
|
||||
|
||||
bigjmp onEveryMinute
|
||||
; @end
|
||||
|
||||
@@ -164,6 +240,20 @@ sysOnEveryHour:
|
||||
|
||||
|
||||
sysOnEveryDay:
|
||||
#ifdef APPS_NETWORK
|
||||
ldi yl, LOW(netInterfaceData)
|
||||
ldi yh, HIGH(netInterfaceData)
|
||||
bigcall AppNetwork_EveryDay
|
||||
#endif
|
||||
|
||||
#ifdef APPS_ROUTER
|
||||
bigcall AppRouter_EveryDay
|
||||
#endif
|
||||
|
||||
#ifdef APPS_FORWARDER
|
||||
bigcall AppForwarder_EveryDay
|
||||
#endif
|
||||
|
||||
bigjmp onEveryDay
|
||||
; @end
|
||||
|
||||
|
||||
@@ -51,7 +51,19 @@ initModules:
|
||||
#ifdef MODULES_LED_SIMPLE
|
||||
bigcall LedSimple_Init
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef MODULES_LED_SIGNAL
|
||||
bigcall LedSignal_Init
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef MODULES_LED_ACTIVITY
|
||||
bigcall LedActivity_Init
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef MODULES_COM
|
||||
bigcall Com2_Init ; init COM module
|
||||
bigcall CPRO_Init ; init COM protocol module
|
||||
@@ -73,10 +85,39 @@ initModules:
|
||||
bigcall TtyOnUart1_Init
|
||||
#endif
|
||||
|
||||
#ifdef MODULES_UARTFD0
|
||||
bigcall UARTFD0_Init
|
||||
#endif
|
||||
|
||||
#ifdef MODULES_UARTFD1
|
||||
bigcall UARTFD1_Init
|
||||
#endif
|
||||
|
||||
#ifdef MODULES_COMONUART0
|
||||
bigcall ComOnUart0_Init
|
||||
#endif
|
||||
|
||||
#ifdef MODULES_COMONUART1
|
||||
bigcall ComOnUart1_Init
|
||||
#endif
|
||||
|
||||
#ifdef MODULES_COM2W
|
||||
bigcall COM2W_Init
|
||||
#endif
|
||||
|
||||
#ifdef MODULES_COM2W0
|
||||
bigcall COM2W0_Init
|
||||
#endif
|
||||
|
||||
#ifdef MODULES_COM2W1
|
||||
bigcall COM2W1_Init
|
||||
#endif
|
||||
|
||||
#ifdef MODULES_COM2WN
|
||||
bigcall COM2WN_Init
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef MODULES_MOTION
|
||||
bigcall Motion_Init
|
||||
#endif
|
||||
@@ -148,6 +189,10 @@ initModules:
|
||||
bigcall ILI9341_Init
|
||||
#endif
|
||||
|
||||
#ifdef MODULES_BRIGHTNESS
|
||||
bigcall Brightness_Init
|
||||
#endif
|
||||
|
||||
|
||||
; done
|
||||
ret
|
||||
@@ -160,61 +205,92 @@ initModules:
|
||||
;
|
||||
; Call run functions of the used modules. Add your routine calls here.
|
||||
;
|
||||
; IN:
|
||||
; - nothing
|
||||
; OUT:
|
||||
; - nothing
|
||||
; USED: depending on called routines
|
||||
; @return CFLAG set: at least one RUN routine returned CFLAG set
|
||||
; @clobbers all
|
||||
|
||||
runModules:
|
||||
bigcall BaseTimer_Run
|
||||
clr r16
|
||||
|
||||
#ifdef MODULES_COM
|
||||
; COM module (call until carry flag cleared but at most 10 times to not starve other modules)
|
||||
ldi r16, 10
|
||||
runModules_Com:
|
||||
push r16
|
||||
bigcall Com2_Run
|
||||
pop r16
|
||||
brcc runModules_ComEnd
|
||||
dec r16
|
||||
brne runModules_Com
|
||||
runModules_ComEnd:
|
||||
push r16
|
||||
bigcall BaseTimer_Run
|
||||
pop r16
|
||||
sbci r16, 0
|
||||
|
||||
#ifdef MODULES_TTYONUART1
|
||||
push r16
|
||||
bigcall TtyOnUart1_Run
|
||||
pop r16
|
||||
#endif
|
||||
|
||||
#ifdef MODULES_TTYONUART1
|
||||
bigcall TtyOnUart1_Run
|
||||
|
||||
#ifdef MODULES_UARTFD0
|
||||
push r16
|
||||
bigcall UARTFD0_Run
|
||||
pop r16
|
||||
sbci r16, 0
|
||||
#endif
|
||||
|
||||
#ifdef MODULES_UARTFD1
|
||||
push r16
|
||||
bigcall UARTFD1_Run
|
||||
pop r16
|
||||
sbci r16, 0
|
||||
#endif
|
||||
|
||||
#ifdef MODULES_COMONUART0
|
||||
bigcall ComOnUart0_Run
|
||||
push r16
|
||||
bigcall ComOnUart0_Run
|
||||
pop r16
|
||||
sbci r16, 0
|
||||
#endif
|
||||
|
||||
#ifdef MODULES_STATS
|
||||
bigcall Stats_Run
|
||||
#endif
|
||||
|
||||
#ifdef MODULES_REED
|
||||
bigcall REED_Run
|
||||
#endif
|
||||
|
||||
#ifdef MODULES_CNY70
|
||||
bigcall CNY70_Run
|
||||
#endif
|
||||
|
||||
#ifdef MODULES_MOTION_LIGHT
|
||||
; rcall MotionLight_Run
|
||||
#ifdef MODULES_COMONUART1
|
||||
push r16
|
||||
bigcall ComOnUart1_Run
|
||||
pop r16
|
||||
sbci r16, 0
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef MODULES_TCRT1000
|
||||
; rcall TCRT1K_Run
|
||||
#ifdef MODULES_COM2W
|
||||
push r16
|
||||
bigcall COM2W_Run
|
||||
pop r16
|
||||
sbci r16, 0
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef MODULES_COM2W0
|
||||
push r16
|
||||
bigcall COM2W0_Run
|
||||
pop r16
|
||||
sbci r16, 0
|
||||
#endif
|
||||
|
||||
#ifdef MODULES_COM2W1
|
||||
push r16
|
||||
bigcall COM2W1_Run
|
||||
pop r16
|
||||
sbci r16, 0
|
||||
#endif
|
||||
|
||||
#ifdef MODULES_COM2WN
|
||||
push r16
|
||||
bigcall COM2WN_Run
|
||||
pop r16
|
||||
sbci r16, 0
|
||||
#endif
|
||||
|
||||
; add more modules here
|
||||
|
||||
; check for repeat request
|
||||
tst r16
|
||||
clc
|
||||
breq runModules_end
|
||||
sec
|
||||
runModules_end:
|
||||
ret
|
||||
|
||||
|
||||
; @end
|
||||
|
||||
|
||||
mainModulesOnPacketReceived:
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
; @param R19:R18 value
|
||||
; @param R21:R20 denom (e.g. 100, meaning value must be divided by 100)
|
||||
; @param R22 value type
|
||||
; @return CFLAG on success, cleared on error
|
||||
|
||||
Main_SendValueReport:
|
||||
push r17
|
||||
@@ -52,6 +53,7 @@ Main_SendValueReport_end:
|
||||
; @param R21:R20 denom (e.g. 100, meaning value must be divided by 100)
|
||||
; @param R23 command
|
||||
; @param R25:R24 ref msg id
|
||||
; @return CFLAG on success, cleared on error
|
||||
|
||||
Main_SendValueResponse:
|
||||
push r17
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user