Moved callbacks (which live in the top-level namespace) into a separate file, so I have a clear overview of all these.

This commit is contained in:
Maurice Makaay 2020-07-15 16:03:16 +02:00
parent 578c0aa626
commit 7f5f60a6ac
8 changed files with 112 additions and 108 deletions

View File

@ -9,7 +9,7 @@ namespace Dough
} }
App::App() : config(), App::App() : config(),
ui(), ui(onoffButtonInterruptCallback, setupButtonInterruptCallback),
wifi(), wifi(),
mqtt(&wifi, mqttOnConnectCallback, mqttOnMessageCallback), mqtt(&wifi, mqttOnConnectCallback, mqttOnMessageCallback),
temperatureSensor( temperatureSensor(
@ -32,9 +32,6 @@ namespace Dough
void App::setup() void App::setup()
{ {
ui.setup(); ui.setup();
ui.onoffButton.onInterrupt(::onoffButtonInterruptCallback);
ui.setupButton.onInterrupt(::setupButtonInterruptCallback);
wifi.setup(); wifi.setup();
mqtt.setup(); mqtt.setup();
temperatureSensor.setup(); temperatureSensor.setup();
@ -63,60 +60,4 @@ namespace Dough
humiditySensor.clearHistory(); humiditySensor.clearHistory();
distanceSensor.clearHistory(); distanceSensor.clearHistory();
} }
} // namespace Dough } // namespace Dough
Dough::Logger callbackLogger("CALLBACK");
void mqttOnConnectCallback(Dough::MQTT *mqtt)
{
callbackLogger.log("s", "MQTT connection establish, subscribing to topics");
mqtt->subscribe("container_height");
mqtt->subscribe("temperature_offset");
}
void mqttOnMessageCallback(String &topic, String &payload)
{
callbackLogger.log("ssss", "MQTT message received: ", topic.c_str(), " = ", payload.c_str());
if (topic.endsWith("/container_height"))
{
Dough::App::Instance()->config.setContainerHeight(payload.toInt());
}
else if (topic.endsWith("/temperature_offset"))
{
Dough::App::Instance()->config.setTemperatureOffset(payload.toInt());
}
else
{
callbackLogger.log("ss", "ERROR - Unhandled MQTT message, topic = ", topic.c_str());
}
}
void onoffButtonInterruptCallback()
{
Dough::App::Instance()->ui.onoffButton.handleButtonState();
}
void setupButtonInterruptCallback()
{
Dough::App::Instance()->ui.setupButton.handleButtonState();
}
void sensorOnMeasureCallback()
{
Dough::App::Instance()->ui.notifySensorActivity();
}
void sensorOnPublishCallback()
{
Dough::App::Instance()->ui.notifyNetworkActivity();
}
// This callback is called when the TC4 timer from the UI code hits an overflow
// interrupt. It is defined outside the Dough namespace, because TC4_Handler is
// a hard-coded root namespace function name.
void TC4_Handler()
{
Dough::App::Instance()->ui.updateLEDs();
REG_TC4_INTFLAG = TC_INTFLAG_OVF; // Clear the OVF interrupt flag.
}

View File

@ -4,6 +4,7 @@
#include <Arduino.h> #include <Arduino.h>
#include "UI/UI.h" #include "UI/UI.h"
#include "App/Configuration.h" #include "App/Configuration.h"
#include "App/callbacks.h"
#include "Data/SensorController.h" #include "Data/SensorController.h"
#include "Sensors/TemperatureSensor.h" #include "Sensors/TemperatureSensor.h"
#include "Sensors/HumiditySensor.h" #include "Sensors/HumiditySensor.h"
@ -34,12 +35,4 @@ namespace Dough
}; };
} }
// Callback functions that need to live in the global namespace.
void mqttOnConnectCallback(Dough::MQTT *mqtt);
void mqttOnMessageCallback(String &topic, String &payload);
void onoffButtonInterruptCallback();
void setupButtonInterruptCallback();
void sensorOnMeasureCallback();
void sensorOnPublishCallback();
#endif #endif

57
src/App/callbacks.cpp Normal file
View File

@ -0,0 +1,57 @@
#include "App/callbacks.h"
Dough::Logger callbackLogger("CALLBACK");
void mqttOnConnectCallback(Dough::MQTT *mqtt)
{
callbackLogger.log("s", "MQTT connection establish, subscribing to topics");
mqtt->subscribe("container_height");
mqtt->subscribe("temperature_offset");
}
void mqttOnMessageCallback(String &topic, String &payload)
{
callbackLogger.log("ssss", "MQTT message received: ", topic.c_str(), " = ", payload.c_str());
if (topic.endsWith("/container_height"))
{
Dough::App::Instance()->config.setContainerHeight(payload.toInt());
}
else if (topic.endsWith("/temperature_offset"))
{
Dough::App::Instance()->config.setTemperatureOffset(payload.toInt());
}
else
{
callbackLogger.log("ss", "ERROR - Unhandled MQTT message, topic = ", topic.c_str());
}
}
void onoffButtonInterruptCallback()
{
Dough::App::Instance()->ui.onoffButton.handleButtonState();
}
void setupButtonInterruptCallback()
{
Dough::App::Instance()->ui.setupButton.handleButtonState();
}
void sensorOnMeasureCallback()
{
Dough::App::Instance()->ui.notifySensorActivity();
}
void sensorOnPublishCallback()
{
Dough::App::Instance()->ui.notifyNetworkActivity();
}
// This callback is called when the TC4 timer from the UI code hits an overflow
// interrupt. It is defined outside the Dough namespace, because TC4_Handler is
// a hard-coded root namespace function name.
void TC4_Handler()
{
Dough::App::Instance()->ui.updateLEDs();
REG_TC4_INTFLAG = TC_INTFLAG_OVF; // Clear the OVF interrupt flag.
}

24
src/App/callbacks.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef DOUGH_APP_CALLBACKS_H
#define DOUGH_APP_CALLBACKS_H
#include "Network/MQTT.h"
#include "UI/Logger.h"
#include "App/App.h"
// This header file defines various callback functions that
// live in the global namespace. All callbacks are bundled here
// to have a clear overview of them.
// Callbacks from the Dough::MQTT module.
void mqttOnConnectCallback(Dough::MQTT *mqtt);
void mqttOnMessageCallback(String &topic, String &payload);
// Callbacks from the Dough::UI module.
void onoffButtonInterruptCallback();
void setupButtonInterruptCallback();
// Callbacks from the Dough::SensorController module.
void sensorOnMeasureCallback();
void sensorOnPublishCallback();
#endif

View File

@ -9,19 +9,17 @@ namespace Dough
// working. An interrupt service routine (ISR) function must be created // working. An interrupt service routine (ISR) function must be created
// and linked to the button to get the interrupts working. Pattern: // and linked to the button to get the interrupts working. Pattern:
// //
// // Construct the button instance.
// Button myButton(MYBUTTON_PIN);
//
// // A function for handling interrupts. // // A function for handling interrupts.
// void myButtonISR() { // void myButtonISR() {
// myButton.handleButtonState(); // myButton.handleButtonState();
// } // }
// //
// // Linking the function ot button interrupts. // // Construct the button instance.
// myButton.onInterrupt(myButtonISR); // Button myButton(MYBUTTON_PIN, myButtonISR);
Button::Button(int pin) Button::Button(int pin, ButtonISR isr)
{ {
_pin = pin; _pin = pin;
attachInterrupt(digitalPinToInterrupt(_pin), isr, CHANGE);
} }
void Button::setup() void Button::setup()
@ -29,30 +27,22 @@ namespace Dough
pinMode(_pin, INPUT_PULLUP); pinMode(_pin, INPUT_PULLUP);
} }
// Assign an interrupt service routine (ISR) for handling button
// interrupts. The provided isr should relay interrupts to the
// handleButtonState() method of this class (see constructor docs).
void Button::onInterrupt(ButtonHandler isr)
{
attachInterrupt(digitalPinToInterrupt(_pin), isr, CHANGE);
}
// Assign an event handler for short and long button presses. // Assign an event handler for short and long button presses.
// When specific handlers for long and/or short presses are // When specific handlers for long and/or short presses are
// configured as well, those have precedence over this one. // configured as well, those have precedence over this one.
void Button::onPress(ButtonHandler handler) void Button::onPress(ButtonISR handler)
{ {
_pressHandler = handler; _pressHandler = handler;
} }
// Assign an event handler for long button presses. // Assign an event handler for long button presses.
void Button::onLongPress(ButtonHandler handler) void Button::onLongPress(ButtonISR handler)
{ {
_longPressHandler = handler; _longPressHandler = handler;
} }
// Assign an event handler for short button presses. // Assign an event handler for short button presses.
void Button::onShortPress(ButtonHandler handler) void Button::onShortPress(ButtonISR handler)
{ {
_shortPressHandler = handler; _shortPressHandler = handler;
} }

View File

@ -18,7 +18,7 @@ namespace Dough
READY_FOR_NEXT_PRESS READY_FOR_NEXT_PRESS
} ButtonState; } ButtonState;
typedef void (*ButtonHandler)(); typedef void (*ButtonISR)();
// This class provides a simple interface for handling button presses. // This class provides a simple interface for handling button presses.
// Only a few events are supported: // Only a few events are supported:
@ -30,21 +30,20 @@ namespace Dough
class Button class Button
{ {
public: public:
Button(int pin); Button(int pin, ButtonISR isr);
void setup(); void setup();
void loop(); void loop();
void onInterrupt(ButtonHandler isr); void onPress(ButtonISR handler);
void onPress(ButtonHandler handler); void onShortPress(ButtonISR handler);
void onShortPress(ButtonHandler handler); void onLongPress(ButtonISR handler);
void onLongPress(ButtonHandler handler);
void clearEvents(); void clearEvents();
void handleButtonState(); void handleButtonState();
private: private:
int _pin; int _pin;
ButtonHandler _pressHandler = nullptr; ButtonISR _pressHandler = nullptr;
ButtonHandler _shortPressHandler = nullptr; ButtonISR _shortPressHandler = nullptr;
ButtonHandler _longPressHandler = nullptr; ButtonISR _longPressHandler = nullptr;
bool _debounceState = false; bool _debounceState = false;
unsigned long _debounceTimer = 0; unsigned long _debounceTimer = 0;
ButtonState _state = UP; ButtonState _state = UP;

View File

@ -2,12 +2,14 @@
namespace Dough namespace Dough
{ {
UI::UI() : onoffButton(ONOFF_BUTTON_PIN), UI::UI(
setupButton(SETUP_BUTTON_PIN), ButtonISR onoffButtonISR,
_ledBuiltin(LED_BUILTIN), ButtonISR setupButtonISR) : onoffButton(ONOFF_BUTTON_PIN, onoffButtonISR),
_led1(LED1_PIN), setupButton(SETUP_BUTTON_PIN, setupButtonISR),
_led2(LED2_PIN), _ledBuiltin(LED_BUILTIN),
_led3(LED3_PIN) {} _led1(LED1_PIN),
_led2(LED2_PIN),
_led3(LED3_PIN) {}
void UI::setup() void UI::setup()
{ {
@ -116,7 +118,7 @@ namespace Dough
_led2.off(); _led2.off();
_led3.off(); _led3.off();
} }
void UI::notifyConnectingToMQTT() void UI::notifyConnectingToMQTT()
{ {
_led1.blink()->fast(); _led1.blink()->fast();
@ -163,16 +165,16 @@ namespace Dough
{ {
_led3.off(); _led3.off();
delay(50); delay(50);
_led3.on(); _led3.on();
} }
void UI::notifyNetworkActivity() void UI::notifyNetworkActivity()
{ {
_led1.off(); _led1.off();
delay(50); delay(50);
_led1.on(); _led1.on();
} }
// Flash all LEDs, one at a time in a synchroneous manner, making // Flash all LEDs, one at a time in a synchroneous manner, making
// this work when the UI timer interrupt is inactive. This is used // this work when the UI timer interrupt is inactive. This is used
// as a "Hey, I'm awake!" signal from the device after booting up. // as a "Hey, I'm awake!" signal from the device after booting up.

View File

@ -14,10 +14,8 @@ namespace Dough
class UI class UI
{ {
public: public:
UI(); UI(ButtonISR onoffButtonISR, ButtonISR setupButtonISR);
void setup(); void setup();
static void onoffButtonISR();
static void setupButtonISR();
Button onoffButton; Button onoffButton;
Button setupButton; Button setupButton;
void processButtonEvents(); void processButtonEvents();