aqhome-nodes: send heartbeat message to interface every 2mins.
e02 now expects this message. If for at least 10mins no such msg is received the USB interface is reset.
This commit is contained in:
@@ -36,6 +36,7 @@
|
||||
|
||||
#define CONNCLEAN_INTERVAL_IN_SECS 2
|
||||
#define CONNCHECK_INTERVAL_IN_SECS 10
|
||||
#define HEARTBEAT_INTERVAL_IN_SECS 120 /* every 2mins */
|
||||
|
||||
|
||||
|
||||
@@ -133,11 +134,13 @@ void _runService(AQH_OBJECT *aqh, AQH_EVENT_LOOP *eventLoop)
|
||||
int timeout;
|
||||
time_t timeLastConnectionCleanup;
|
||||
time_t timeLastConnCheck;
|
||||
time_t timeLastHeartbeat;
|
||||
|
||||
timeout=AQH_NodeServer_GetTimeout(aqh);
|
||||
timeStart=time(NULL);
|
||||
timeLastConnectionCleanup=time(NULL);
|
||||
timeLastConnCheck=time(NULL);
|
||||
timeLastConnectionCleanup=timeStart;
|
||||
timeLastConnCheck=timeStart;
|
||||
timeLastHeartbeat=timeStart;
|
||||
|
||||
while(!stopService) {
|
||||
time_t now;
|
||||
@@ -162,6 +165,13 @@ void _runService(AQH_OBJECT *aqh, AQH_EVENT_LOOP *eventLoop)
|
||||
timeLastConnCheck=now;
|
||||
}
|
||||
|
||||
if (_diffInSeconds(now, timeLastHeartbeat)>HEARTBEAT_INTERVAL_IN_SECS) {
|
||||
DBG_INFO(NULL, "Sending heartbeat message");
|
||||
AQH_NodeServer_SendHeartbeat(aqh);
|
||||
timeLastHeartbeat=now;
|
||||
}
|
||||
|
||||
|
||||
if (timeout && (_diffInSeconds(now, timeStart)>timeout)) {
|
||||
DBG_INFO(NULL, "Timeout");
|
||||
break;
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include <aqhome/msg/node/m_recvstats.h>
|
||||
#include <aqhome/msg/node/m_sendstats.h>
|
||||
#include <aqhome/msg/node/m_memstats.h>
|
||||
#include <aqhome/msg/node/m_heartbeat.h>
|
||||
#include <aqhome/data/value.h>
|
||||
|
||||
#include <gwenhywfar/args.h>
|
||||
@@ -811,6 +812,25 @@ void AQH_NodeServer_HandleTtyMsgs(AQH_OBJECT *o)
|
||||
|
||||
|
||||
|
||||
void AQH_NodeServer_SendHeartbeat(AQH_OBJECT *o)
|
||||
{
|
||||
AQH_NODE_SERVER *xo;
|
||||
|
||||
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_NODE_SERVER, o);
|
||||
if (xo && xo->ttyEndpoint) {
|
||||
AQH_MESSAGE *nodeMsg;
|
||||
time_t t;
|
||||
|
||||
t=time(0);
|
||||
nodeMsg=AQH_HeartbeatMessage_new(0xf0, 0x00, AQH_MSG_TYPE_HEARTBEAT, (uint32_t) t);
|
||||
AQH_Endpoint_AddMsgOut(xo->ttyEndpoint, nodeMsg);
|
||||
AQH_NodeServer_WriteTtyMsgToLogFile(o, nodeMsg, "sending");
|
||||
DBG_ERROR(NULL, "Forwarding node message %d to node", AQH_NodeMessage_GetMsgType(nodeMsg));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleMsgFromTty(AQH_OBJECT *o, AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg)
|
||||
{
|
||||
uint8_t code;
|
||||
|
||||
@@ -57,6 +57,7 @@ void AQH_NodeServer_HandleClientMsgs(AQH_OBJECT *o);
|
||||
void AQH_NodeServer_HandleBrokerMsgs(AQH_OBJECT *o);
|
||||
void AQH_NodeServer_CheckBrokerConnection(AQH_OBJECT *o);
|
||||
void AQH_NodeServer_CheckTtyConnection(AQH_OBJECT *o);
|
||||
void AQH_NodeServer_SendHeartbeat(AQH_OBJECT *o);
|
||||
|
||||
|
||||
/* getters and setters */
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "aqhome/msg/msg_sysstats.h"
|
||||
#include "aqhome/msg/msg_ping.h"
|
||||
#include "aqhome/msg/msg_pong.h"
|
||||
#include "aqhome/msg/m_heartbeat.h"
|
||||
#include "aqhome/msg/msg_needaddr.h"
|
||||
#include "aqhome/msg/msg_claimaddr.h"
|
||||
#include "aqhome/msg/msg_haveaddr.h"
|
||||
@@ -80,6 +81,7 @@ void AqHomed_LogTtyMsg(AQHOMED *aqh, const GWEN_MSG *msg)
|
||||
switch(msgType) {
|
||||
case AQH_MSG_TYPE_PING: AQH_PingMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_PONG: AQH_PongMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_HEARTBEAT: AQH_HeartbeatMessage_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_COMSENDSTATS: AQH_SendStatsMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_COMRECVSTATS: AQH_RecvStatsMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_TWIBUSMEMBER: AQH_NodeMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
m_flashresponse.h
|
||||
m_range.h
|
||||
m_time.h
|
||||
m_heartbeat.h
|
||||
</headers>
|
||||
|
||||
|
||||
@@ -93,6 +94,7 @@
|
||||
m_flashresponse.c
|
||||
m_range.c
|
||||
m_time.c
|
||||
m_heartbeat.c
|
||||
</sources>
|
||||
|
||||
|
||||
|
||||
55
aqhome/msg/node/m_heartbeat.c
Normal file
55
aqhome/msg/node/m_heartbeat.c
Normal file
@@ -0,0 +1,55 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2026 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_heartbeat.h"
|
||||
#include "aqhome/msg/node/m_node.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/endianfns.h>
|
||||
|
||||
|
||||
|
||||
#define AQH_MSG_OFFS_HEARTBEAT_TIMESTAMP 0 /* 4 bytes */
|
||||
|
||||
|
||||
|
||||
AQH_MESSAGE *AQH_HeartbeatMessage_new(uint8_t destAddr, uint8_t srcAddr, uint8_t code, uint32_t timestamp)
|
||||
{
|
||||
uint32_t payload;
|
||||
|
||||
payload=GWEN_ENDIAN_HTOLE32(timestamp);
|
||||
return AQH_NodeMessage_new(destAddr, srcAddr, code, sizeof(payload), (const uint8_t*)&payload);
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint32_t AQH_HeartbeatMessage_GetTimestamp(const AQH_MESSAGE *msg)
|
||||
{
|
||||
return AQH_Message_ReadUint32At(msg, AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_HEARTBEAT_TIMESTAMP, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_HeartbeatMessage_DumpToBuffer(const AQH_MESSAGE *msg, GWEN_BUFFER *dbuf, const char *sText)
|
||||
{
|
||||
GWEN_Buffer_AppendArgs(dbuf,
|
||||
"0x%02x->0x%02x: HEARTBEAT(%s) %s (uid=0x%08x)\n",
|
||||
AQH_NodeMessage_GetSourceAddress(msg),
|
||||
AQH_NodeMessage_GetDestAddress(msg),
|
||||
AQH_NodeMessage_MsgTypeToChar(AQH_NodeMessage_GetMsgType(msg)),
|
||||
sText,
|
||||
(unsigned int) AQH_HeartbeatMessage_GetTimestamp(msg));
|
||||
}
|
||||
|
||||
|
||||
28
aqhome/msg/node/m_heartbeat.h
Normal file
28
aqhome/msg/node/m_heartbeat.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2026 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_HEARTBEAT_H
|
||||
#define AQH_M_HEARTBEAT_H
|
||||
|
||||
|
||||
#include <aqhome/api.h>
|
||||
#include <aqhome/ipc2/message.h>
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
AQHOME_API AQH_MESSAGE *AQH_HeartbeatMessage_new(uint8_t destAddr, uint8_t srcAddr, uint8_t code, uint32_t timestamp);
|
||||
AQHOME_API uint32_t AQH_HeartbeatMessage_GetTimestamp(const AQH_MESSAGE *msg);
|
||||
|
||||
AQHOME_API void AQH_HeartbeatMessage_DumpToBuffer(const AQH_MESSAGE *msg, GWEN_BUFFER *dbuf, const char *sText);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "aqhome/msg/node/m_needaddr.h"
|
||||
#include "aqhome/msg/node/m_ping.h"
|
||||
#include "aqhome/msg/node/m_pong.h"
|
||||
#include "aqhome/msg/node/m_heartbeat.h"
|
||||
#include "aqhome/msg/node/m_reboot.h"
|
||||
#include "aqhome/msg/node/m_value.h"
|
||||
#include "aqhome/msg/node/m_flashstart.h"
|
||||
@@ -29,6 +30,7 @@
|
||||
#include "aqhome/msg/node/m_flashready.h"
|
||||
#include "aqhome/msg/node/m_flashresponse.h"
|
||||
#include "aqhome/msg/node/m_range.h"
|
||||
#include "aqhome/msg/node/m_time.h"
|
||||
|
||||
#include <gwenhywfar/text.h>
|
||||
|
||||
@@ -202,6 +204,7 @@ const char *AQH_NodeMessage_MsgTypeToChar(uint8_t i)
|
||||
switch(i) {
|
||||
case AQH_MSG_TYPE_PING: return "Ping";
|
||||
case AQH_MSG_TYPE_PONG: return "Pong";
|
||||
case AQH_MSG_TYPE_HEARTBEAT: return "Heartbeat";
|
||||
case AQH_MSG_TYPE_COMSENDSTATS: return "SendStats";
|
||||
case AQH_MSG_TYPE_COMRECVSTATS: return "RecvStats";
|
||||
case AQH_MSG_TYPE_TWIBUSMEMBER: return "TwiBusMember";
|
||||
@@ -245,6 +248,7 @@ void AQH_NodeMessage_DumpSpecificToBuffer(const AQH_MESSAGE *msg, GWEN_BUFFER *d
|
||||
switch(AQH_NodeMessage_GetMsgType(msg)) {
|
||||
case AQH_MSG_TYPE_PING: AQH_PingMessage_DumpToBuffer(msg, dbuf, sText); break;
|
||||
case AQH_MSG_TYPE_PONG: AQH_PongMessage_DumpToBuffer(msg, dbuf, sText); break;
|
||||
case AQH_MSG_TYPE_HEARTBEAT: AQH_HeartbeatMessage_DumpToBuffer(msg, dbuf, sText); break;
|
||||
case AQH_MSG_TYPE_COMSENDSTATS: AQH_SendStatsMessage_DumpToBuffer(msg, dbuf, sText); break;
|
||||
case AQH_MSG_TYPE_COMRECVSTATS: AQH_RecvStatsMessage_DumpToBuffer(msg, dbuf, sText); break;
|
||||
case AQH_MSG_TYPE_NEED_ADDRESS: AQH_AddrMessage_DumpToBuffer(msg, dbuf, sText); break;
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#define AQH_MSG_TYPE_PING 10
|
||||
#define AQH_MSG_TYPE_PONG 11
|
||||
#define AQH_MSG_TYPE_HEARTBEAT 12
|
||||
#define AQH_MSG_TYPE_COMSENDSTATS 22
|
||||
#define AQH_MSG_TYPE_COMRECVSTATS 23
|
||||
#define AQH_MSG_TYPE_TWIBUSMEMBER 30
|
||||
|
||||
@@ -108,3 +108,13 @@
|
||||
.equ USART0_DATAREG = UDR0
|
||||
.equ USART1_DATAREG = UDR1
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; MCP2221
|
||||
|
||||
.equ MCP2221_RESET_DDR = DDRB
|
||||
.equ MCP2221_RESET_PORT = PORTB
|
||||
.equ MCP2221_RESET_PINNUM = PORTB0
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -72,30 +72,12 @@
|
||||
#define APP_ROUTER_NO_ADDR_MGR
|
||||
|
||||
#define MODULES_CLOCK
|
||||
;#define MODULES_COM
|
||||
;#define MODULES_COM_WITH_ADDR_PROTO
|
||||
;#define MODULES_LED
|
||||
#define MODULES_LED_SIMPLE
|
||||
;#define MODULES_LED_SIGNAL
|
||||
;#define MODULES_LED_ACTIVITY
|
||||
;#define MODULES_TWI_MASTER
|
||||
;#define MODULES_LCD
|
||||
;#define LCD_MINIMAL_FONT
|
||||
;#define MODULES_SI7021
|
||||
;#define MODULES_STATS
|
||||
;#define MODULES_CNY70
|
||||
;#define MODULES_REED
|
||||
;#define MODULES_OWI_MASTER
|
||||
;#define MODULES_DS18B20
|
||||
;#define MODULES_MOTION
|
||||
#define MODULES_NETWORK
|
||||
#define MODULES_COM2W
|
||||
;#define MODULES_COMONUART0
|
||||
;#define MODULES_TTYONUART1
|
||||
#define MODULES_UARTFD0
|
||||
|
||||
#define APPS_STATS
|
||||
;#define APPS_NETWORK
|
||||
;#define APPS_ROUTER
|
||||
#define APPS_FORWARDER
|
||||
|
||||
|
||||
@@ -106,14 +88,17 @@
|
||||
|
||||
|
||||
|
||||
.equ HEARTBEAT_MAXTIME_IN_MINS = 10 ; 10 minutes
|
||||
|
||||
.equ LEDMCPRESET_ONTIME = 2
|
||||
.equ LEDMCPRESET_OFFTIME = 2
|
||||
.equ LEDMCPRESET_REPEATS = 50 ; 50*0.4=20s
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; defines for values
|
||||
|
||||
.equ VALUE_ID_DS18B20_TEMP = 0x06
|
||||
|
||||
.equ VALUE_ID_LEDSIMPLE_TIMING = 0x88
|
||||
;.equ VALUE_ID_ROUTER_SETRANGE = 0x89
|
||||
; none
|
||||
|
||||
|
||||
|
||||
@@ -187,6 +172,30 @@ onSystemStart:
|
||||
ldi r16, 0xf0
|
||||
sts netInterfaceData+NET_IFACE_OFFS_ADDRESS, r16
|
||||
sts netInterfaceData2+NET_IFACE_OFFS_ADDRESS, r16
|
||||
|
||||
ldi r16, HEARTBEAT_MAXTIME_IN_MINS
|
||||
sts heartbeatTimer, r16
|
||||
|
||||
rcall resetMcp2221
|
||||
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
onEveryMinute:
|
||||
lds r16, heartbeatTimer
|
||||
tst r16
|
||||
breq onEverySecond_ret
|
||||
dec r16
|
||||
sts heartbeatTimer, r16
|
||||
brne onEverySecond_ret
|
||||
|
||||
rcall resetMcp2221
|
||||
|
||||
ldi r16, HEARTBEAT_MAXTIME_IN_MINS
|
||||
sts heartbeatTimer, r16
|
||||
onEverySecond_ret:
|
||||
ret
|
||||
; @end
|
||||
|
||||
@@ -194,7 +203,6 @@ onSystemStart:
|
||||
|
||||
onEvery100ms:
|
||||
onEverySecond:
|
||||
onEveryMinute:
|
||||
onEveryHour:
|
||||
onEveryDay:
|
||||
ret
|
||||
@@ -218,12 +226,48 @@ onEveryLoop:
|
||||
; Called on every message received
|
||||
|
||||
onMessageReceived:
|
||||
adiw xh:xl, NETMSG_OFFS_CMD
|
||||
ld r16, X
|
||||
sbiw xh:xl, NETMSG_OFFS_CMD
|
||||
cpi r16, NETMSG_CMD_HEARTBEAT
|
||||
brne onMessageReceived_ret
|
||||
ldi r16, HEARTBEAT_MAXTIME_IN_MINS
|
||||
sts heartbeatTimer, r16
|
||||
onMessageReceived_ret:
|
||||
clc
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; @routine resetMcp2221
|
||||
;
|
||||
; Reset MCP2221 by pulling /RST low for 10us.
|
||||
|
||||
resetMcp2221:
|
||||
push r15
|
||||
inr r15, SREG
|
||||
cli
|
||||
sbi MCP2221_RESET_DDR, MCP2221_RESET_PINNUM ; out
|
||||
cbi MCP2221_RESET_PORT, MCP2221_RESET_PINNUM ; set RST low
|
||||
Utils_WaitNanoSecs 10000, 0, r22 ; minimum is 2us, use 10us to be safe
|
||||
sbi MCP2221_RESET_PORT, MCP2221_RESET_PINNUM ; set RST high
|
||||
outr SREG, r15
|
||||
pop r15
|
||||
|
||||
#ifdef MODULES_LED_SIMPLE
|
||||
ldi r18, LEDMCPRESET_ONTIME
|
||||
ldi r19, LEDMCPRESET_OFFTIME
|
||||
ldi r20, LEDMCPRESET_REPEATS
|
||||
bigcall LedSimple_SetTiming
|
||||
#endif
|
||||
|
||||
ret
|
||||
; @end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -249,3 +293,16 @@ deviceCodeEnd:
|
||||
.warning "Code reaches into boot loader!"
|
||||
.endif
|
||||
|
||||
|
||||
|
||||
|
||||
; ***************************************************************************
|
||||
; data segment
|
||||
|
||||
.dseg
|
||||
|
||||
heartbeatTimer: .byte 1
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
.equ NETMSG_CMD_PING = 10
|
||||
.equ NETMSG_CMD_PONG = 11
|
||||
.equ NETMSG_CMD_HEARTBEAT = 12
|
||||
.equ NETMSG_CMD_SENDSTATS = 22
|
||||
.equ NETMSG_CMD_RECVSTATS = 23
|
||||
.equ NETMSG_CMD_TWIBUSMEMBER = 30
|
||||
|
||||
Reference in New Issue
Block a user