Skip to content

Commit e0e78a6

Browse files
committed
Add library status indication & improve error LED feedback (#462)
* Added MyIndication to provide status feedback from the library * Fix: Allow led blinking for hardware errors * Refactor LED blinking implementation to show blink patterns * Refactor LED blinking to show blink pattern
1 parent bc7e246 commit e0e78a6

File tree

11 files changed

+366
-76
lines changed

11 files changed

+366
-76
lines changed

libraries/MySensors/MySensor.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,8 @@
142142
#include "core/MyLeds.h"
143143
#endif
144144

145+
#include "core/MyIndication.cpp"
146+
145147

146148
// INCLUSION MODE
147149
#if defined(MY_INCLUSION_MODE_FEATURE)

libraries/MySensors/core/MyGatewayTransportEthernet.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ bool gatewayTransportSend(MyMessage &message)
151151
bool ret = true;
152152
char *_ethernetMsg = protocolFormat(message);
153153

154+
setIndication(INDICATION_GW_TX);
155+
154156
_w5100_spi_en(true);
155157
#if defined(MY_CONTROLLER_IP_ADDRESS)
156158
#if defined(MY_USE_UDP)
@@ -267,6 +269,7 @@ bool gatewayTransportAvailable()
267269

268270
if (packet_size) {
269271
//debug(PSTR("UDP packet available. Size:%d\n"), packet_size);
272+
setIndication(INDICATION_GW_RX);
270273
#if defined(MY_GATEWAY_ESP8266)
271274
_ethernetServer.read(inputString[0].string, MY_GATEWAY_MAX_RECEIVE_LENGTH);
272275
inputString[0].string[packet_size] = 0;
@@ -316,6 +319,7 @@ bool gatewayTransportAvailable()
316319
// Loop over clients connect and read available data
317320
for (uint8_t i = 0; i < ARRAY_SIZE(clients); i++) {
318321
if (_readFromClient(i)) {
322+
setIndication(INDICATION_GW_RX);
319323
_w5100_spi_en(false);
320324
return true;
321325
}
@@ -341,6 +345,7 @@ bool gatewayTransportAvailable()
341345
client.stop();
342346
} else {
343347
if (_readFromClient()) {
348+
setIndication(INDICATION_GW_RX);
344349
_w5100_spi_en(false);
345350
return true;
346351
}

libraries/MySensors/core/MyGatewayTransportMQTTClient.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ MyMessage _mqttMsg;
5959
bool gatewayTransportSend(MyMessage &message) {
6060
if (!_client.connected())
6161
return false;
62+
setIndication(INDICATION_GW_TX);
63+
6264
snprintf_P(_fmtBuffer, MY_GATEWAY_MAX_SEND_LENGTH, PSTR(MY_MQTT_PUBLISH_TOPIC_PREFIX "/%d/%d/%d/%d/%d"), message.sender, message.sensor, mGetCommand(message), mGetAck(message), message.type);
6365
debug(PSTR("Sending message on topic: %s\n"), _fmtBuffer);
6466
return _client.publish(_fmtBuffer, message.getString(_convBuffer));

libraries/MySensors/core/MyGatewayTransportSerial.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ MyMessage _serialMsg;
3131

3232

3333
bool gatewayTransportSend(MyMessage &message) {
34+
setIndication(INDICATION_GW_TX);
3435
MY_SERIALDEVICE.print(protocolFormat(message));
3536
// Serial print is always successful
3637
return true;
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/**
2+
* The MySensors Arduino library handles the wireless radio link and protocol
3+
* between your home built sensors/actuators and HA controller of choice.
4+
* The sensors forms a self healing radio network with optional repeaters. Each
5+
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
6+
* network topology allowing messages to be routed to nodes.
7+
*
8+
* Created by Henrik Ekblad <[email protected]>
9+
* Copyright (C) 2013-2016 Sensnology AB
10+
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
11+
*
12+
* Documentation: http://www.mysensors.org
13+
* Support Forum: http://forum.mysensors.org
14+
*
15+
* This program is free software; you can redistribute it and/or
16+
* modify it under the terms of the GNU General Public License
17+
* version 2 as published by the Free Software Foundation.
18+
*/
19+
20+
#include "MyIndication.h"
21+
#ifdef MY_LEDS_BLINKING_FEATURE
22+
#include "MyLeds.h"
23+
#endif
24+
25+
void setIndication( const indication_t ind )
26+
{
27+
#ifdef MY_LEDS_BLINKING_FEATURE
28+
if ((INDICATION_TX == ind) || (INDICATION_GW_TX == ind))
29+
{
30+
ledsBlinkTx(1);
31+
} else if ((INDICATION_RX == ind) || (INDICATION_GW_RX == ind))
32+
{
33+
ledsBlinkRx(1);
34+
} else if (ind > INDICATION_ERR_START)
35+
{
36+
// Number of blinks indicates which error occurred.
37+
ledsBlinkErr(ind-INDICATION_ERR_START);
38+
}
39+
#endif
40+
if (indication)
41+
indication(ind);
42+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/**
2+
* The MySensors Arduino library handles the wireless radio link and protocol
3+
* between your home built sensors/actuators and HA controller of choice.
4+
* The sensors forms a self healing radio network with optional repeaters. Each
5+
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
6+
* network topology allowing messages to be routed to nodes.
7+
*
8+
* Created by Henrik Ekblad <[email protected]>
9+
* Copyright (C) 2013-2016 Sensnology AB
10+
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
11+
*
12+
* Documentation: http://www.mysensors.org
13+
* Support Forum: http://forum.mysensors.org
14+
*
15+
* This program is free software; you can redistribute it and/or
16+
* modify it under the terms of the GNU General Public License
17+
* version 2 as published by the Free Software Foundation.
18+
*/
19+
20+
#ifndef MyIndication_h
21+
#define MyIndication_h
22+
23+
/**
24+
* Indication type
25+
*/
26+
typedef enum {
27+
INDICATION_TX = 0, //!< Sent a message.
28+
INDICATION_RX, //!< Received a message.
29+
30+
INDICATION_GW_TX, //!< Gateway transmit message.
31+
INDICATION_GW_RX, //!< Gateway receive message.
32+
33+
INDICATION_FIND_PARENT, //!< Start finding parent node.
34+
INDICATION_GOT_PARENT, //!< Found parent node.
35+
INDICATION_REQ_NODEID, //!< Request node ID.
36+
INDICATION_GOT_NODEID, //!< Got a node ID.
37+
INDICATION_REBOOT, //!< Rebooting node.
38+
INDICATION_PRESENT, //!< Presenting node to gateway.
39+
INDICATION_CLEAR_ROUTING, //!< Clear rrouting table requested.
40+
INDICATION_SLEEP, //!< Node goes to sleep.
41+
INDICATION_WAKEUP, //!< Node just woke from sleep.
42+
INDICATION_FW_UPDATE_START, //!< Start of OTA firmware update process.
43+
INDICATION_FW_UPDATE_RX, //!< Received a piece of firmware data.
44+
45+
INDICATION_ERR_START = 100,
46+
INDICATION_ERR_TX, //!< Failed to transmit message.
47+
INDICATION_ERR_INIT_TRANSPORT, //!< MySensors transport hardware (radio) init failure.
48+
INDICATION_ERR_FIND_PARENT, //!< Failed to find parent node.
49+
INDICATION_ERR_GET_NODEID, //!< Failed to receive node ID.
50+
INDICATION_ERR_SIGN, //!< Error signing.
51+
INDICATION_ERR_VERSION, //!< Protocol version mismatch.
52+
INDICATION_ERR_NET_FULL, //!< Network full. All node ID's are taken.
53+
INDICATION_ERR_INIT_GWTRANSPORT, //!< Gateway transport hardware init failure.
54+
INDICATION_ERR_LOCKED, //!< Node is locked.
55+
INDICATION_ERR_FW_FLASH_INIT, //!< Firmware update flash initialisation failure.
56+
INDICATION_ERR_FW_TIMEOUT, //!< Firmware update timeout.
57+
INDICATION_ERR_FW_CHECKSUM, //!< Firmware update checksum mismatch.
58+
INDICATION_ERR_END
59+
} indication_t;
60+
61+
/**
62+
* Function which is called when something changes about the internal state of MySensors.
63+
* @param ind Event indication of what happened.
64+
*/
65+
void setIndication( const indication_t ind );
66+
67+
/**
68+
* Allow user to define their own indication handler.
69+
*/
70+
void indication( const indication_t ) __attribute__((weak));
71+
72+
#endif

libraries/MySensors/core/MyLeds.cpp

Lines changed: 41 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -19,81 +19,64 @@
1919

2020
#include "MyLeds.h"
2121

22+
#define LED_ON_OFF_RATIO (4) // Power of 2 please
23+
#define LED_PROCESS_INTERVAL_MS (MY_DEFAULT_LED_BLINK_PERIOD/LED_ON_OFF_RATIO)
24+
2225
// these variables don't need to be volatile, since we are not using interrupts
23-
uint8_t _countRx;
24-
uint8_t _countTx;
25-
uint8_t _countErr;
26-
unsigned long _blink_next_time;
26+
static uint8_t countRx;
27+
static uint8_t countTx;
28+
static uint8_t countErr;
29+
static unsigned long prevTime = millis() - LED_PROCESS_INTERVAL_MS; // Substract some, to make sure leds gets updated on first run.
30+
31+
32+
inline void ledsInit()
33+
{
34+
// initialize counters
35+
countRx = 0;
36+
countTx = 0;
37+
countErr = 0;
2738

28-
inline void ledsInit() {
2939
// Setup led pins
30-
pinMode(MY_DEFAULT_RX_LED_PIN, OUTPUT);
31-
pinMode(MY_DEFAULT_TX_LED_PIN, OUTPUT);
40+
pinMode(MY_DEFAULT_RX_LED_PIN, OUTPUT);
41+
pinMode(MY_DEFAULT_TX_LED_PIN, OUTPUT);
3242
pinMode(MY_DEFAULT_ERR_LED_PIN, OUTPUT);
3343

34-
// Set initial state of leds
35-
hwDigitalWrite(MY_DEFAULT_RX_LED_PIN, LED_OFF);
36-
hwDigitalWrite(MY_DEFAULT_TX_LED_PIN, LED_OFF);
37-
hwDigitalWrite(MY_DEFAULT_ERR_LED_PIN, LED_OFF);
38-
39-
// initialize counters
40-
_countRx = 0;
41-
_countTx = 0;
42-
_countErr = 0;
44+
ledsProcess();
4345
}
4446

45-
inline void ledsProcess() {
47+
void ledsProcess() {
4648
// Just return if it is not the time...
47-
// http://playground.arduino.cc/Code/TimingRollover
48-
if ((long)(hwMillis() - _blink_next_time) < 0)
49+
if ((hwMillis() - prevTime) < LED_PROCESS_INTERVAL_MS)
4950
return;
50-
else
51-
_blink_next_time = hwMillis() + MY_DEFAULT_LED_BLINK_PERIOD;
52-
53-
// do the actual blinking
54-
if(_countRx && _countRx != 255) {
55-
// switch led on
56-
hwDigitalWrite(MY_DEFAULT_RX_LED_PIN, LED_ON);
57-
}
58-
else if(!_countRx) {
59-
// switching off
60-
hwDigitalWrite(MY_DEFAULT_RX_LED_PIN, LED_OFF);
61-
}
62-
if(_countRx != 255)
63-
--_countRx;
64-
65-
if(_countTx && _countTx != 255) {
66-
// switch led on
67-
hwDigitalWrite(MY_DEFAULT_TX_LED_PIN, LED_ON);
68-
}
69-
else if(!_countTx) {
70-
// switching off
71-
hwDigitalWrite(MY_DEFAULT_TX_LED_PIN, LED_OFF);
72-
}
73-
if(_countTx != 255)
74-
--_countTx;
75-
76-
if(_countErr && _countErr != 255) {
77-
// switch led on
78-
hwDigitalWrite(MY_DEFAULT_ERR_LED_PIN, LED_ON);
79-
}
80-
else if(!_countErr) {
81-
// switching off
82-
hwDigitalWrite(MY_DEFAULT_ERR_LED_PIN, LED_OFF);
83-
}
84-
if(_countErr != 255)
85-
--_countErr;
51+
52+
prevTime += LED_PROCESS_INTERVAL_MS;
53+
54+
uint8_t state;
55+
56+
// For an On/Off ratio of 4, the pattern repeated will be [on, on, on, off]
57+
// until the counter becomes 0.
58+
state = (countRx & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF;
59+
hwDigitalWrite(MY_DEFAULT_RX_LED_PIN, state);
60+
if (countRx) --countRx;
61+
62+
state = (countTx & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF;
63+
hwDigitalWrite(MY_DEFAULT_TX_LED_PIN, state);
64+
if (countTx) --countTx;
65+
66+
state = (countErr & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF;
67+
hwDigitalWrite(MY_DEFAULT_ERR_LED_PIN, state);
68+
if (countErr) --countErr;
8669
}
8770

8871
void ledsBlinkRx(uint8_t cnt) {
89-
if(_countRx == 255) { _countRx = cnt; }
72+
if (!countRx) { countRx = cnt*LED_ON_OFF_RATIO; }
9073
}
9174

9275
void ledsBlinkTx(uint8_t cnt) {
93-
if(_countTx == 255) { _countTx = cnt; }
76+
if(!countTx) { countTx = cnt*LED_ON_OFF_RATIO; }
9477
}
9578

9679
void ledsBlinkErr(uint8_t cnt) {
97-
if(_countErr == 255) { _countErr = cnt; }
80+
if(!countErr) { countErr = cnt*LED_ON_OFF_RATIO; }
9881
}
9982

libraries/MySensors/core/MyOTAFirmwareUpdate.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ inline void firmwareOTAUpdateRequest() {
3434
unsigned long enter = hwMillis();
3535
if (_fwUpdateOngoing && (enter - _fwLastRequestTime > MY_OTA_RETRY_DELAY)) {
3636
if (!_fwRetry) {
37+
setIndication(INDICATION_ERR_FW_TIMEOUT);
3738
debug(PSTR("fw upd fail\n"));
3839
// Give up. We have requested MY_OTA_RETRY times without any packet in return.
3940
_fwUpdateOngoing = false;
@@ -57,11 +58,13 @@ inline bool firmwareOTAUpdateProcess() {
5758
NodeFirmwareConfig *firmwareConfigResponse = (NodeFirmwareConfig *)_msg.data;
5859
// compare with current node configuration, if they differ, start fw fetch process
5960
if (memcmp(&_fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig))) {
61+
setIndication(INDICATION_FW_START);
6062
debug(PSTR("fw update\n"));
6163
// copy new FW config
6264
memcpy(&_fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig));
6365
// Init flash
6466
if (!_flash.initialize()) {
67+
setIndication(INDICATION_ERR_FW_FLASH_INIT);
6568
debug(PSTR("flash init fail\n"));
6669
_fwUpdateOngoing = false;
6770
} else {
@@ -81,6 +84,7 @@ inline bool firmwareOTAUpdateProcess() {
8184
} else if (_msg.type == ST_FIRMWARE_RESPONSE) {
8285
if (_fwUpdateOngoing) {
8386
// Save block to flash
87+
setIndication(INDICATION_FW_RX);
8488
debug(PSTR("fw block %d\n"), _fwBlock);
8589
// extract FW block
8690
ReplyFWBlock *firmwareResponse = (ReplyFWBlock *)_msg.data;
@@ -102,6 +106,7 @@ inline bool firmwareOTAUpdateProcess() {
102106
hwWriteConfigBlock((void*)&_fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig));
103107
hwReboot();
104108
} else {
109+
setIndication(INDICATION_ERR_FW_CHECKSUM);
105110
debug(PSTR("fw checksum fail\n"));
106111
}
107112
}

0 commit comments

Comments
 (0)