diff --git a/examples/thermostat/efr32/README.md b/examples/thermostat/efr32/README.md index 5bc31b87d2d989..b23e089427e4f3 100644 --- a/examples/thermostat/efr32/README.md +++ b/examples/thermostat/efr32/README.md @@ -7,14 +7,22 @@ An example showing the use of CHIP on the Silicon Labs EFR32 MG12. - [CHIP EFR32 Light Switch Example](#chip-efr32-light-switch-example) - [Introduction](#introduction) - [Building](#building) - - [Note](#note) + - [Linux](#linux) + - [Mac OS X](#mac-os-x) - [Flashing the Application](#flashing-the-application) - [Viewing Logging Output](#viewing-logging-output) - [Running the Complete Example](#running-the-complete-example) - [Notes](#notes) + - [On Border Router:](#on-border-router) + - [On PC(Linux):](#on-pclinux) - [Running RPC console](#running-rpc-console) - [Memory settings](#memory-settings) - [OTA Software Update](#ota-software-update) + - [Building options](#building-options) + - [Disabling logging](#disabling-logging) + - [Debug build / release build](#debug-build--release-build) + - [Disabling LCD](#disabling-lcd) + - [KVS maximum entry count](#kvs-maximum-entry-count)
@@ -253,14 +261,28 @@ combination with JLinkRTTClient as follows: **Push Button 0** - - _Press and Release_ : Start, or restart, BLE advertisement in fast mode. It will advertise in this mode - for 30 seconds. The device will then switch to a slower interval advertisement. - After 15 minutes, the advertisement stops. + - _Press and Release_ : - - _Pressed and hold for 6 s_ : Initiates the factory reset of the device. - Releasing the button within the 6-second window cancels the factory reset - procedure. **LEDs** blink in unison when the factory reset procedure is - initiated. + - Decreases temperature by 0.01C depending on current mode. + + - Start, or restart, BLE advertisement in fast mode. It will advertise + in this mode for 30 seconds. The device will then switch to a + slower interval advertisement. + After 15 minutes, the advertisement stops. + + - _Pressed and hold for 6.5 s_ : Initiates the factory reset of the device. + Releasing button within the 0.5-second window cancels initiation of factory + reset. + Releasing the button within the 6-second window post that cancels the + factory reset procedure. **LEDs** blink in unison when the factory reset + procedure is initiated. + + **Push Button 1** + + - _Press and Release_ : Increases temperature by 0.01C depending on current + mode. + + - _Pressed and hold for 1 s_ : Toggles the mode of the thermostat. * You can provision and control the Chip device using the python controller, [CHIPTool](https://github.com/project-chip/connectedhomeip/blob/master/examples/chip-tool/README.md) diff --git a/examples/thermostat/efr32/include/AppTask.h b/examples/thermostat/efr32/include/AppTask.h index 800dda99ad37ac..8ff69994575c46 100644 --- a/examples/thermostat/efr32/include/AppTask.h +++ b/examples/thermostat/efr32/include/AppTask.h @@ -93,6 +93,15 @@ class AppTask : public BaseApplication */ static void OnIdentifyStop(Identify * identify); + enum ThermoFunction_t + { + kFunction_Nothing = 0, + kFunction_AppFn = 1, + kFunction_Temp = 2, + + kFunction_Invalid + } ThermoFunction; + private: static AppTask sAppTask; @@ -113,10 +122,65 @@ class AppTask : public BaseApplication static void ButtonHandler(AppEvent * aEvent); /** - * @brief PB1 Button event processing function - * Function triggers a thermostat action sent to the CHIP task + * @brief Function called to start the mode timer * - * @param aEvent button event being processed + * @param aTimeoutMs timer duration in ms + */ + static void StartModeTimer(uint32_t aTimeoutInMs); + + /** + * @brief Function to stop the mode timer + */ + static void CancelModeTimer(); + + /** + * @brief Function called to start the app function timer + * + * @param aTimeoutMs timer duration in ms + */ + static void StartAppFnTimer(uint32_t aTimeoutInMs); + + /** + * @brief Function to stop app function timer + */ + static void CancelAppFnTimer(); + + /** + * @brief Mode Timer finished callback function + * Post an ModeHandler event + * + * @param xTimer timer that finished + */ + static void ModeTimerEventHandler(TimerHandle_t xTimer); + + /** + * @brief App Function Timer finished callback function + * Post an AppFnHandler event + * + * @param xTimer timer that finished + */ + static void AppFnTimerEventHandler(TimerHandle_t xTimer); + + /** + * @brief Mode Timer Event processing function + * Handles toggling the mode + * + * @param aEvent post event being processed + */ + static void ModeHandler(AppEvent * aEvent); + + /** + * @brief App Function Timer Event processing function + * Calls factory reset handler from BaseApplication.cpp + * + * @param aEvent post event being processed + */ + static void AppFnHandler(AppEvent * aEvent); + + /** + * @brief Handles temperature changes depending on timer status + * + * @param aEvent post event being processed */ - static void ThermostatActionEventHandler(AppEvent * aEvent); + static void TemperatureHandler(AppEvent * aEvent); }; diff --git a/examples/thermostat/efr32/src/AppTask.cpp b/examples/thermostat/efr32/src/AppTask.cpp index 793e79f3ab8145..0ecc65153ae9c9 100644 --- a/examples/thermostat/efr32/src/AppTask.cpp +++ b/examples/thermostat/efr32/src/AppTask.cpp @@ -36,7 +36,13 @@ #include #include +#include +#include #include +#include +#include +#include +#include #include #include #include @@ -47,6 +53,7 @@ #include #include + /********************************************************** * Defines and Constants *********************************************************/ @@ -54,12 +61,44 @@ #define APP_FUNCTION_BUTTON &sl_button_btn0 #define APP_THERMOSTAT &sl_button_btn1 +#define HEATING_MODE 1 +#define COOLING_MODE 0 + +#define MODE_TIMER 1000 +#define APP_FN_TIMER 500 + +#define MIN_HEATINGSETPOINT_LIMIT 700 +#define MAX_HEATINGSETPOINT_LIMIT 3000 +#define MIN_COOLINGSETPOINT_LIMIT 1600 +#define MAX_COOLINGSETPOINT_LIMIT 3200 + using namespace chip; using namespace ::chip::DeviceLayer; + /********************************************************** * Variable declarations *********************************************************/ + +TimerHandle_t sModeTimer; +TimerHandle_t sAppFnTimer; + +bool mModeTimerActive; +bool mAppFnTimerActive; + +bool startModeTimerVar; +bool startAppFnTimerVar; + +int thermostat_mode = HEATING_MODE; + +int16_t heatingSetpoint = 0; +int16_t coolingSetpoint = 0; + +AppTask::ThermoFunction_t btn1State; +AppTask::ThermoFunction_t btn0State; + +AppEvent reset_button_event = {}; + namespace { EmberAfIdentifyEffectIdentifier sIdentifyEffect = EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_STOP_EFFECT; @@ -140,6 +179,30 @@ CHIP_ERROR AppTask::Init() { CHIP_ERROR err = CHIP_NO_ERROR; + sModeTimer = xTimerCreate("ThermModeTmr", // Just a text name, not used by the RTOS kernel + 1, // == default timer period (mS) + false, // no timer reload (==one-shot) + (void *) this, // init timer id = app task obj context + ModeTimerEventHandler // timer callback handler + ); + if (sModeTimer == NULL) + { + EFR32_LOG("Creation of sModeTimer failed."); + appError(APP_ERROR_CREATE_TIMER_FAILED); + } + + sAppFnTimer = xTimerCreate("ThermFnTmr", // Just a text name, not used by the RTOS kernel + 1, // == default timer period (mS) + false, // no timer reload (==one-shot) + (void *) this, // init timer id = app task obj context + AppFnTimerEventHandler // timer callback handler + ); + if (sAppFnTimer == NULL) + { + EFR32_LOG("Creation of aAppFnTimer failed."); + appError(APP_ERROR_CREATE_TIMER_FAILED); + } + #ifdef DISPLAY_ENABLED GetLCD().Init((uint8_t *) "Thermostat-App"); #endif @@ -183,6 +246,31 @@ void AppTask::AppTaskMain(void * pvParameter) { sAppTask.DispatchEvent(&event); eventReceived = xQueueReceive(sAppEventQueue, &event, 0); + + if(startModeTimerVar == true) + { + StartModeTimer(MODE_TIMER); + startModeTimerVar = false; + } + if(startAppFnTimerVar == true) + { + StartAppFnTimer(APP_FN_TIMER); + startAppFnTimerVar = false; + } + if ((mModeTimerActive == true) && (btn1State == kFunction_Temp)) + { + CancelModeTimer(); + TemperatureHandler(&event); + startModeTimerVar = false; + btn1State = kFunction_Nothing; + } + if ((mAppFnTimerActive == true) && (btn0State == kFunction_Temp)) + { + CancelAppFnTimer(); + TemperatureHandler(&event); + startAppFnTimerVar = false; + btn0State = kFunction_Nothing; + } } } } @@ -205,15 +293,224 @@ void AppTask::OnIdentifyStop(Identify * identify) #endif } -void AppTask::ThermostatActionEventHandler(AppEvent * aEvent) + +void AppTask::CancelModeTimer() +{ + if (xTimerStop(sModeTimer, 0) == pdFAIL) + { + EFR32_LOG("thermostat mode timer stop() failed"); + appError(APP_ERROR_STOP_TIMER_FAILED); + } + mModeTimerActive = false; +} + +void AppTask::StartModeTimer(uint32_t aTimeoutInMs) { - if (aEvent->Type == AppEvent::kEventType_Button) + if (xTimerIsTimerActive(sModeTimer)) + { + EFR32_LOG("mode timer already started!"); + CancelModeTimer(); + } + + if (xTimerChangePeriod(sModeTimer, aTimeoutInMs / portTICK_PERIOD_MS, 100) != pdPASS) { - EFR32_LOG("App Button was pressed!"); - // TODO: Implement button functionnality + EFR32_LOG("mode timer start() failed"); + appError(APP_ERROR_START_TIMER_FAILED); } + mModeTimerActive = true; } + +void AppTask::CancelAppFnTimer() +{ + if (xTimerStop(sAppFnTimer, 0) == pdFAIL) + { + EFR32_LOG("thermostat AppFn timer stop() failed"); + appError(APP_ERROR_STOP_TIMER_FAILED); + } + mAppFnTimerActive = false; +} + +void AppTask::StartAppFnTimer(uint32_t aTimeoutInMs) +{ + if (xTimerIsTimerActive(sAppFnTimer)) + { + EFR32_LOG("thermostat AppFn timer already started!"); + CancelAppFnTimer(); + } + if (xTimerChangePeriod(sAppFnTimer, aTimeoutInMs / portTICK_PERIOD_MS, 100) != pdPASS) + { + EFR32_LOG("thermostat AppFn timer start() failed"); + appError(APP_ERROR_START_TIMER_FAILED); + } + mAppFnTimerActive = true; +} + + +void AppTask::ModeTimerEventHandler(TimerHandle_t xTimer) +{ + AppEvent event; + event.Type = AppEvent::kEventType_Timer; + event.TimerEvent.Context = (void *) xTimer; + event.Handler = ModeHandler; + sAppTask.PostEvent(&event); +} + +void AppTask::AppFnTimerEventHandler(TimerHandle_t xTimer) +{ + AppEvent event; + event.Type = AppEvent::kEventType_Timer; + event.TimerEvent.Context = (void *) xTimer; + event.Handler = AppFnHandler; + sAppTask.PostEvent(&event); +} + + +void AppTask::TemperatureHandler(AppEvent * aEvent) +{ + if (btn1State == kFunction_Temp) + { + CancelModeTimer(); + + chip::EndpointId endpointId = 1; + + if (thermostat_mode == HEATING_MODE) + { + int16_t maxHeatingSetpointLimit = MAX_HEATINGSETPOINT_LIMIT; + + chip::DeviceLayer::PlatformMgr().LockChipStack(); + chip::app::Clusters::Thermostat::Attributes::OccupiedHeatingSetpoint::Get(endpointId, &heatingSetpoint); + chip::app::Clusters::Thermostat::Attributes::AbsMaxHeatSetpointLimit::Get(endpointId, &maxHeatingSetpointLimit); + chip::DeviceLayer::PlatformMgr().UnlockChipStack(); + + if (heatingSetpoint < maxHeatingSetpointLimit) + { + heatingSetpoint += 1; + + chip::DeviceLayer::PlatformMgr().LockChipStack(); + chip::app::Clusters::Thermostat::Attributes::OccupiedHeatingSetpoint::Set(endpointId, heatingSetpoint); + chip::DeviceLayer::PlatformMgr().UnlockChipStack(); + } + else + { + EFR32_LOG("No change: Maximum temperature limit reached.") + } + } + else + { + int16_t maxCoolingSetpointLimit = MAX_COOLINGSETPOINT_LIMIT; + + chip::DeviceLayer::PlatformMgr().LockChipStack(); + chip::app::Clusters::Thermostat::Attributes::OccupiedCoolingSetpoint::Get(endpointId, &coolingSetpoint); + chip::app::Clusters::Thermostat::Attributes::AbsMaxCoolSetpointLimit::Get(endpointId, &maxCoolingSetpointLimit); + chip::DeviceLayer::PlatformMgr().UnlockChipStack(); + + if (coolingSetpoint < maxCoolingSetpointLimit) + { + coolingSetpoint += 1; + + chip::DeviceLayer::PlatformMgr().LockChipStack(); + chip::app::Clusters::Thermostat::Attributes::OccupiedCoolingSetpoint::Set(endpointId, coolingSetpoint); + chip::DeviceLayer::PlatformMgr().UnlockChipStack(); + } + else + { + EFR32_LOG("No change: Maximum temperature limit reached.") + } + } + btn1State = kFunction_Nothing; + EFR32_LOG("Current temperature set to Heating: %d, Cooling: %d, with Mode: %d", heatingSetpoint, coolingSetpoint, thermostat_mode); + } + else if (btn0State == kFunction_Temp) + { + CancelAppFnTimer(); + + chip::EndpointId endpointId = 1; + + if (thermostat_mode == HEATING_MODE) + { + int16_t minHeatingSetpointLimit = MIN_HEATINGSETPOINT_LIMIT; + + chip::DeviceLayer::PlatformMgr().LockChipStack(); + chip::app::Clusters::Thermostat::Attributes::OccupiedHeatingSetpoint::Get(endpointId, &heatingSetpoint); + chip::app::Clusters::Thermostat::Attributes::AbsMinHeatSetpointLimit::Get(endpointId, &minHeatingSetpointLimit); + chip::DeviceLayer::PlatformMgr().UnlockChipStack(); + + if (heatingSetpoint > minHeatingSetpointLimit) + { + heatingSetpoint -= 1; + + chip::DeviceLayer::PlatformMgr().LockChipStack(); + chip::app::Clusters::Thermostat::Attributes::OccupiedHeatingSetpoint::Set(endpointId, heatingSetpoint); + chip::DeviceLayer::PlatformMgr().UnlockChipStack(); + } + else + { + EFR32_LOG("No change: Minimum temperature limit reached.") + } + } + else + { + int16_t minCoolingSetpointLimit = MIN_COOLINGSETPOINT_LIMIT; + + chip::DeviceLayer::PlatformMgr().LockChipStack(); + chip::app::Clusters::Thermostat::Attributes::OccupiedCoolingSetpoint::Get(endpointId, &coolingSetpoint); + chip::app::Clusters::Thermostat::Attributes::AbsMinCoolSetpointLimit::Get(endpointId, &minCoolingSetpointLimit); + chip::DeviceLayer::PlatformMgr().UnlockChipStack(); + + if (coolingSetpoint > minCoolingSetpointLimit) + { + coolingSetpoint -= 1; + + chip::DeviceLayer::PlatformMgr().LockChipStack(); + chip::app::Clusters::Thermostat::Attributes::OccupiedCoolingSetpoint::Set(endpointId, coolingSetpoint); + chip::DeviceLayer::PlatformMgr().UnlockChipStack(); + } + else + { + EFR32_LOG("No change: Minimum temperature limit reached.") + } + } + btn0State = kFunction_Nothing; + EFR32_LOG("Current temperature set to Heating: %d, Cooling: %d, with Mode: %d", heatingSetpoint, coolingSetpoint, thermostat_mode); + } +} + + +void AppTask::ModeHandler(AppEvent * aEvent) +{ + if (aEvent->Type != AppEvent::kEventType_Timer) + { + return; + } + + if (thermostat_mode == HEATING_MODE) + { + thermostat_mode = COOLING_MODE; + } + else + { + thermostat_mode = HEATING_MODE; + } + EFR32_LOG("Thermostat Mode set to: %d, with current temperature Heating: %d, Cooling: %d", thermostat_mode, heatingSetpoint, coolingSetpoint); + btn1State = kFunction_Nothing; + CancelModeTimer(); +} + + +void AppTask::AppFnHandler(AppEvent * aEvent) +{ + if (aEvent->Type != AppEvent::kEventType_Timer) + { + return; + } + EFR32_LOG("Initiating Factory Reset. Release button within %ums to stop.", APP_FN_TIMER); + reset_button_event.Handler = BaseApplication::ButtonHandler; + sAppTask.PostEvent(&reset_button_event); + btn0State = kFunction_Nothing; +} + + void AppTask::ButtonEventHandler(const sl_button_t * buttonHandle, uint8_t btnAction) { if (buttonHandle == NULL) @@ -225,14 +522,58 @@ void AppTask::ButtonEventHandler(const sl_button_t * buttonHandle, uint8_t btnAc button_event.Type = AppEvent::kEventType_Button; button_event.ButtonEvent.Action = btnAction; - if (buttonHandle == APP_THERMOSTAT && btnAction == SL_SIMPLE_BUTTON_PRESSED) + if (buttonHandle == APP_THERMOSTAT) { - button_event.Handler = ThermostatActionEventHandler; + if (btnAction == SL_SIMPLE_BUTTON_PRESSED) + { + btn1State = kFunction_AppFn; + startModeTimerVar = true; + button_event.Handler = ModeHandler; + } + else + { + if (mModeTimerActive == true) + { + btn1State = kFunction_Temp; + } + else + { + btn1State = kFunction_Nothing; + } + startModeTimerVar = false; + button_event.Handler = TemperatureHandler; + } sAppTask.PostEvent(&button_event); } + else if (buttonHandle == APP_FUNCTION_BUTTON) { - button_event.Handler = BaseApplication::ButtonHandler; + if (btnAction) + { + reset_button_event.Type = AppEvent::kEventType_Button; + reset_button_event.ButtonEvent.Action = btnAction; + + btn0State = kFunction_AppFn; + startAppFnTimerVar = true; + button_event.Handler = AppFnHandler; + reset_button_event.Handler = AppFnHandler; + } + else + { + reset_button_event.ButtonEvent.Action = btnAction; + + if (mAppFnTimerActive == true) + { + btn0State = kFunction_Temp; + } + else + { + btn0State = kFunction_Nothing; + } + startAppFnTimerVar = false; + button_event.Handler = TemperatureHandler; + } sAppTask.PostEvent(&button_event); + sAppTask.PostEvent(&reset_button_event); } -} +} \ No newline at end of file