diff --git a/examples/closure-app/silabs/BUILD.gn b/examples/closure-app/silabs/BUILD.gn index 37fb02f53ad747..fe45c959a4ecff 100644 --- a/examples/closure-app/silabs/BUILD.gn +++ b/examples/closure-app/silabs/BUILD.gn @@ -139,6 +139,10 @@ silabs_executable("closure_app") { "src/DataModelCallbacks.cpp", ] + if (!disable_lcd) { + sources += [ "src/ClosureUI.cpp" ] + } + deps = [ ":sdk" ] if (wifi_soc) { diff --git a/examples/closure-app/silabs/include/AppEvent.h b/examples/closure-app/silabs/include/AppEvent.h index d4cb0785641bd9..18dccab962046b 100644 --- a/examples/closure-app/silabs/include/AppEvent.h +++ b/examples/closure-app/silabs/include/AppEvent.h @@ -27,6 +27,7 @@ struct AppEvent : public BaseAppEvent { kEventType_Closure = BaseAppEvent::kEventType_Max + 1, kEventType_Install, + kEventType_UpdateUI, }; struct diff --git a/examples/closure-app/silabs/include/AppTask.h b/examples/closure-app/silabs/include/AppTask.h index 21015002885838..9012746e11331c 100644 --- a/examples/closure-app/silabs/include/AppTask.h +++ b/examples/closure-app/silabs/include/AppTask.h @@ -78,6 +78,21 @@ class AppTask : public BaseApplication */ static void ButtonEventHandler(uint8_t button, uint8_t btnAction); +#ifdef DISPLAY_ENABLED + /** + * @brief Updates the closure UI with current closure state + */ + static void UpdateClosureUI(); + + /** + * @brief Event handler for UI update events + * Called from app task context to safely update UI with chip stack locked + * + * @param aEvent pointer to the UI update event being processed + */ + static void UpdateClosureUIHandler(AppEvent * aEvent); +#endif // DISPLAY_ENABLED + /** * @brief Closure button action event handler * Handles button press events for closure control operations diff --git a/examples/closure-app/silabs/include/ClosureManager.h b/examples/closure-app/silabs/include/ClosureManager.h index 0eb34eb9ba0f7d..c85dd6719952de 100644 --- a/examples/closure-app/silabs/include/ClosureManager.h +++ b/examples/closure-app/silabs/include/ClosureManager.h @@ -31,6 +31,10 @@ #include #include +#ifdef DISPLAY_ENABLED +#include "ClosureUI.h" +#endif + class ClosureManager { public: @@ -156,6 +160,16 @@ class ClosureManager */ const Action_t & GetCurrentAction() const { return mCurrentAction; } +#ifdef DISPLAY_ENABLED + /** + * @brief Gets closure data specifically for UI display. + * + * @return ClosureUIData structure containing main state and overall current state + */ + ClosureUIData GetClosureUIData(); + +#endif // DISPLAY_ENABLED + /** * @brief Checks if a MoveTo action is currently in progress. * diff --git a/examples/closure-app/silabs/include/ClosureUI.h b/examples/closure-app/silabs/include/ClosureUI.h new file mode 100644 index 00000000000000..a318f2a0eb7125 --- /dev/null +++ b/examples/closure-app/silabs/include/ClosureUI.h @@ -0,0 +1,64 @@ +/* + * + * Copyright (c) 2025 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "ClosureUIStrings.h" +#include "glib.h" +#include "lcd.h" +#include +#include +#include + +/** + * @brief Structure to hold closure data needed for UI display + */ +struct ClosureUIData +{ + chip::app::Clusters::ClosureControl::MainStateEnum mainState; + chip::app::DataModel::Nullable overallCurrentState; +}; + +struct ClosureUITextInitializer; + +class ClosureUI +{ +public: + static void DrawUI(GLIB_Context_t * glibContext); + static void SetMainState(chip::app::Clusters::ClosureControl::MainStateEnum state); + + static void FormatAndSetPosition(const char * suffix); + static void FormatAndSetLatch(const char * suffix); + static void FormatAndSetSecure(const char * suffix); + static void FormatAndSetSpeed(const char * suffix); + +private: + friend struct ClosureUITextInitializer; + static void DrawHeader(GLIB_Context_t * glibContext); + static void DrawFooter(GLIB_Context_t * glibContext); + static void DrawMainState(GLIB_Context_t * glibContext); + static void DrawOverallCurrentState(GLIB_Context_t * glibContext); + + // Static variables to store the current closure state + static chip::app::Clusters::ClosureControl::MainStateEnum sMainState; + static char sPositionText[ClosureUIStrings::LCD_STRING_BUFFER_SIZE]; + static char sLatchText[ClosureUIStrings::LCD_STRING_BUFFER_SIZE]; + static char sSecureText[ClosureUIStrings::LCD_STRING_BUFFER_SIZE]; + static char sSpeedText[ClosureUIStrings::LCD_STRING_BUFFER_SIZE]; + static char sStateText[ClosureUIStrings::LCD_STRING_BUFFER_SIZE]; +}; diff --git a/examples/closure-app/silabs/include/ClosureUIStrings.h b/examples/closure-app/silabs/include/ClosureUIStrings.h new file mode 100644 index 00000000000000..4af6a812dc8358 --- /dev/null +++ b/examples/closure-app/silabs/include/ClosureUIStrings.h @@ -0,0 +1,78 @@ +/* + * + * Copyright (c) 2025 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +/** + * @file ClosureUIStrings.h + * @brief UI string constants + + * @note IMPORTANT FOR DEVELOPERS: + * If you modify existing strings or add new strings in this file, you MUST ensure + * that all prefix + suffix combinations fit within LCD_CH_LINE_LEN (16 characters), + * as the LCD display can only show 16 characters per line. All text buffers are + * sized to LCD_STRING_BUFFER_SIZE (17 bytes: 16 characters + null terminator). + */ + +namespace ClosureUIStrings { + +// Shared suffix for unknown state +inline constexpr const char SUFFIX_UNKNOWN[] = "Unknown"; + +inline constexpr const char POSITION_PREFIX[] = "Pos: "; +inline constexpr const char POSITION_SUFFIX_CLOSED[] = "Closed"; +inline constexpr const char POSITION_SUFFIX_OPEN[] = "Open"; +inline constexpr const char POSITION_SUFFIX_PARTIAL[] = "Partial"; +inline constexpr const char POSITION_SUFFIX_PEDESTRIAN[] = "Pedest"; +inline constexpr const char POSITION_SUFFIX_VENTILATION[] = "Ventil"; +inline constexpr const char POSITION_SUFFIX_SIGNATURE[] = "Sign"; + +inline constexpr const char LATCH_PREFIX[] = "Latch: "; +inline constexpr const char LATCH_SUFFIX_ENGAGED[] = "Yes"; +inline constexpr const char LATCH_SUFFIX_RELEASED[] = "No"; + +inline constexpr const char SECURE_PREFIX[] = "Secure: "; +inline constexpr const char SECURE_SUFFIX_YES[] = "Yes"; +inline constexpr const char SECURE_SUFFIX_NO[] = "No"; + +inline constexpr const char SPEED_PREFIX[] = "Speed: "; +inline constexpr const char SPEED_SUFFIX_LOW[] = "Low"; +inline constexpr const char SPEED_SUFFIX_MEDIUM[] = "Med"; +inline constexpr const char SPEED_SUFFIX_HIGH[] = "High"; +inline constexpr const char SPEED_SUFFIX_AUTO[] = "Auto"; + +inline constexpr const char STATE_PREFIX[] = "State: "; +inline constexpr const char STATE_SUFFIX_STOPPED[] = "Stopped"; +inline constexpr const char STATE_SUFFIX_MOVING[] = "Moving"; +inline constexpr const char STATE_SUFFIX_WAITING[] = "Waiting"; +inline constexpr const char STATE_SUFFIX_ERROR[] = "Error"; +inline constexpr const char STATE_SUFFIX_CALIBRATING[] = "Calib"; +inline constexpr const char STATE_SUFFIX_PROTECTED[] = "Protect"; +inline constexpr const char STATE_SUFFIX_DISENGAGED[] = "Diseng"; +inline constexpr const char STATE_SUFFIX_SETUP_REQUIRED[] = "SetupReq"; + +inline constexpr const char FOOTER_TEXT[] = "Closure App"; + +// LCD display line maximum length +inline constexpr size_t LCD_CH_LINE_LEN = 16; + +// LCD string buffer size (lcd line length + null terminator) +inline constexpr size_t LCD_STRING_BUFFER_SIZE = LCD_CH_LINE_LEN + 1; +} // namespace ClosureUIStrings diff --git a/examples/closure-app/silabs/src/AppTask.cpp b/examples/closure-app/silabs/src/AppTask.cpp index 6c7401b418c5df..16ae1c715381d8 100644 --- a/examples/closure-app/silabs/src/AppTask.cpp +++ b/examples/closure-app/silabs/src/AppTask.cpp @@ -23,6 +23,8 @@ #include "LEDWidget.h" #ifdef DISPLAY_ENABLED +#include "ClosureUI.h" +#include "ClosureUIStrings.h" #include "lcd.h" #ifdef QR_CODE_ENABLED #include "qrcodegen.h" @@ -48,6 +50,7 @@ #include #include #include +#include #define APP_FUNCTION_BUTTON 0 #define APP_CLOSURE_BUTTON 1 @@ -81,6 +84,7 @@ CHIP_ERROR AppTask::AppInit() #ifdef DISPLAY_ENABLED GetLCD().Init((uint8_t *) "Closure-App"); + GetLCD().SetCustomUI(ClosureUI::DrawUI); #endif // Initialization of Closure Manager and endpoints of closure and closurepanel. @@ -88,7 +92,7 @@ CHIP_ERROR AppTask::AppInit() // Update the LCD with the Stored value. Show QR Code if not provisioned #ifdef DISPLAY_ENABLED - GetLCD().WriteDemoUI(false); + UpdateClosureUI(); #ifdef QR_CODE_ENABLED #ifdef SL_WIFI if (!ConnectivityMgr().IsWiFiStationProvisioned()) @@ -99,7 +103,7 @@ CHIP_ERROR AppTask::AppInit() GetLCD().ShowQRCode(true); } #endif // QR_CODE_ENABLED -#endif +#endif // DISPLAY_ENABLED return err; } @@ -228,3 +232,103 @@ void AppTask::ClosureButtonActionEventHandler(AppEvent * aEvent) ChipLogError(AppServer, "Unhandled event type in ClosureButtonActionEventHandler"); } } + +#ifdef DISPLAY_ENABLED +void AppTask::UpdateClosureUIHandler(AppEvent * aEvent) +{ + if (aEvent->Type == AppEvent::kEventType_UpdateUI) + { + UpdateClosureUI(); + } +} + +void AppTask::UpdateClosureUI() +{ + ClosureManager & closureManager = ClosureManager::GetInstance(); + + // Lock chip stack when accessing CHIP attributes from app task context + DeviceLayer::PlatformMgr().LockChipStack(); + auto uiData = closureManager.GetClosureUIData(); + DeviceLayer::PlatformMgr().UnlockChipStack(); + + ClosureUI::SetMainState(uiData.mainState); + + const char * positionSuffix = ClosureUIStrings::SUFFIX_UNKNOWN; + if (!uiData.overallCurrentState.IsNull() && uiData.overallCurrentState.Value().position.HasValue() && + !uiData.overallCurrentState.Value().position.Value().IsNull()) + { + switch (uiData.overallCurrentState.Value().position.Value().Value()) + { + case chip::app::Clusters::ClosureControl::CurrentPositionEnum::kFullyClosed: + positionSuffix = ClosureUIStrings::POSITION_SUFFIX_CLOSED; + break; + case chip::app::Clusters::ClosureControl::CurrentPositionEnum::kFullyOpened: + positionSuffix = ClosureUIStrings::POSITION_SUFFIX_OPEN; + break; + case chip::app::Clusters::ClosureControl::CurrentPositionEnum::kPartiallyOpened: + positionSuffix = ClosureUIStrings::POSITION_SUFFIX_PARTIAL; + break; + case chip::app::Clusters::ClosureControl::CurrentPositionEnum::kOpenedForPedestrian: + positionSuffix = ClosureUIStrings::POSITION_SUFFIX_PEDESTRIAN; + break; + case chip::app::Clusters::ClosureControl::CurrentPositionEnum::kOpenedForVentilation: + positionSuffix = ClosureUIStrings::POSITION_SUFFIX_VENTILATION; + break; + default: + positionSuffix = ClosureUIStrings::SUFFIX_UNKNOWN; + break; + } + } + ClosureUI::FormatAndSetPosition(positionSuffix); + + const char * latchSuffix = ClosureUIStrings::SUFFIX_UNKNOWN; + if (!uiData.overallCurrentState.IsNull() && uiData.overallCurrentState.Value().latch.HasValue() && + !uiData.overallCurrentState.Value().latch.Value().IsNull()) + { + latchSuffix = uiData.overallCurrentState.Value().latch.Value().Value() ? ClosureUIStrings::LATCH_SUFFIX_ENGAGED + : ClosureUIStrings::LATCH_SUFFIX_RELEASED; + } + ClosureUI::FormatAndSetLatch(latchSuffix); + + const char * secureSuffix = ClosureUIStrings::SUFFIX_UNKNOWN; + if (!uiData.overallCurrentState.IsNull() && !uiData.overallCurrentState.Value().secureState.IsNull()) + { + secureSuffix = uiData.overallCurrentState.Value().secureState.Value() ? ClosureUIStrings::SECURE_SUFFIX_YES + : ClosureUIStrings::SECURE_SUFFIX_NO; + } + ClosureUI::FormatAndSetSecure(secureSuffix); + + const char * speedSuffix = ClosureUIStrings::SUFFIX_UNKNOWN; + if (!uiData.overallCurrentState.IsNull() && uiData.overallCurrentState.Value().speed.HasValue()) + { + switch (uiData.overallCurrentState.Value().speed.Value()) + { + case chip::app::Clusters::Globals::ThreeLevelAutoEnum::kLow: + speedSuffix = ClosureUIStrings::SPEED_SUFFIX_LOW; + break; + case chip::app::Clusters::Globals::ThreeLevelAutoEnum::kMedium: + speedSuffix = ClosureUIStrings::SPEED_SUFFIX_MEDIUM; + break; + case chip::app::Clusters::Globals::ThreeLevelAutoEnum::kHigh: + speedSuffix = ClosureUIStrings::SPEED_SUFFIX_HIGH; + break; + case chip::app::Clusters::Globals::ThreeLevelAutoEnum::kAuto: + speedSuffix = ClosureUIStrings::SPEED_SUFFIX_AUTO; + break; + default: + speedSuffix = ClosureUIStrings::SUFFIX_UNKNOWN; + break; + } + } + ClosureUI::FormatAndSetSpeed(speedSuffix); + +#ifdef SL_WIFI + if (ConnectivityMgr().IsWiFiStationProvisioned()) +#else + if (ConnectivityMgr().IsThreadProvisioned()) +#endif /* !SL_WIFI */ + { + AppTask::GetAppTask().GetLCD().WriteDemoUI(false); // State doesn't matter for custom UI + } +} +#endif // DISPLAY_ENABLED diff --git a/examples/closure-app/silabs/src/ClosureManager.cpp b/examples/closure-app/silabs/src/ClosureManager.cpp index 016e50cadb0f24..3d47d87da0ab32 100644 --- a/examples/closure-app/silabs/src/ClosureManager.cpp +++ b/examples/closure-app/silabs/src/ClosureManager.cpp @@ -1284,6 +1284,17 @@ bool ClosureManager::GetPanelNextPosition(const GenericDimensionStateStruct & cu } return true; } + +#ifdef DISPLAY_ENABLED +ClosureUIData ClosureManager::GetClosureUIData() +{ + ClosureUIData uiData; + mClosureEndpoint1.GetLogic().GetMainState(uiData.mainState); + mClosureEndpoint1.GetLogic().GetOverallCurrentState(uiData.overallCurrentState); + return uiData; +} +#endif // DISPLAY_ENABLED + bool ClosureManager::IsClosureControlMotionInProgress() const { return mIsMoveToInProgress; diff --git a/examples/closure-app/silabs/src/ClosureUI.cpp b/examples/closure-app/silabs/src/ClosureUI.cpp new file mode 100644 index 00000000000000..4b5197ab20f6bf --- /dev/null +++ b/examples/closure-app/silabs/src/ClosureUI.cpp @@ -0,0 +1,214 @@ +/* + * + * Copyright (c) 2025 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "AppConfig.h" +#include "ClosureUI.h" +#include "ClosureUIStrings.h" +#include "demo-ui-bitmaps.h" +#include "dmd.h" +#include "glib.h" +#include "lcd.h" + +// Only needed for wifi NCP devices +#if SL_WIFI && !defined(SLI_SI91X_MCU_INTERFACE) +#include +#endif // SL_WIFI && !defined(SLI_SI91X_MCU_INTERFACE) + +// Layout positions +#define STATUS_ICON_LINE 0 +#define SILABS_ICON_POSITION_X 0 +#define BLE_ICON_POSITION_X 72 +#define NETWORK_ICON_POSITION_X 90 +#define MATTER_ICON_POSITION_X 108 + +// Icon sizes +#define SILABS_LOGO_WIDTH 47 +#define SILABS_LOGO_HEIGHT 18 +#define BLUETOOTH_ICON_SIZE 18 + +// State display positions +#define STATE_DISPLAY_LINE 3 +#define POSITION_DISPLAY_LINE 5 +#define LATCH_DISPLAY_LINE 6 +#define SECURE_DISPLAY_LINE 7 +#define SPEED_DISPLAY_LINE 8 +#define FOOTER_DISPLAY_LINE 11 + +// Bitmap definitions +static const uint8_t silabsLogo[] = { SILABS_LOGO_SMALL }; +static const uint8_t matterLogoBitmap[] = { MATTER_LOGO_BITMAP }; +static const uint8_t wifiLogo[] = { WIFI_BITMAP }; +static const uint8_t threadLogo[] = { THREAD_BITMAP }; +static const uint8_t bleLogo[] = { BLUETOOTH_ICON_SMALL }; + +// Static variables to hold the current closure state +chip::app::Clusters::ClosureControl::MainStateEnum ClosureUI::sMainState = + chip::app::Clusters::ClosureControl::MainStateEnum::kUnknownEnumValue; + +// Initialize arrays using LCD string buffer size +char ClosureUI::sPositionText[ClosureUIStrings::LCD_STRING_BUFFER_SIZE]; +char ClosureUI::sLatchText[ClosureUIStrings::LCD_STRING_BUFFER_SIZE]; +char ClosureUI::sSecureText[ClosureUIStrings::LCD_STRING_BUFFER_SIZE]; +char ClosureUI::sSpeedText[ClosureUIStrings::LCD_STRING_BUFFER_SIZE]; +char ClosureUI::sStateText[ClosureUIStrings::LCD_STRING_BUFFER_SIZE]; + +// Static initializer to set default values using prefix + suffix +struct ClosureUITextInitializer +{ + ClosureUITextInitializer() + { + snprintf(ClosureUI::sPositionText, ClosureUIStrings::LCD_STRING_BUFFER_SIZE, "%s%s", ClosureUIStrings::POSITION_PREFIX, + ClosureUIStrings::SUFFIX_UNKNOWN); + snprintf(ClosureUI::sLatchText, ClosureUIStrings::LCD_STRING_BUFFER_SIZE, "%s%s", ClosureUIStrings::LATCH_PREFIX, + ClosureUIStrings::SUFFIX_UNKNOWN); + snprintf(ClosureUI::sSecureText, ClosureUIStrings::LCD_STRING_BUFFER_SIZE, "%s%s", ClosureUIStrings::SECURE_PREFIX, + ClosureUIStrings::SUFFIX_UNKNOWN); + snprintf(ClosureUI::sSpeedText, ClosureUIStrings::LCD_STRING_BUFFER_SIZE, "%s%s", ClosureUIStrings::SPEED_PREFIX, + ClosureUIStrings::SUFFIX_UNKNOWN); + snprintf(ClosureUI::sStateText, ClosureUIStrings::LCD_STRING_BUFFER_SIZE, "%s%s", ClosureUIStrings::STATE_PREFIX, + ClosureUIStrings::SUFFIX_UNKNOWN); + } +}; +static ClosureUITextInitializer sInitializer; + +void ClosureUI::DrawUI(GLIB_Context_t * glibContext) +{ + if (glibContext == nullptr) + { + SILABS_LOG("ClosureUI: Graphics context is null"); + return; + } + + GLIB_clear(glibContext); + + DrawHeader(glibContext); + DrawMainState(glibContext); + DrawOverallCurrentState(glibContext); + DrawFooter(glibContext); + +#if SL_LCDCTRL_MUX + sl_wfx_host_pre_lcd_spi_transfer(); +#endif // SL_LCDCTRL_MUX + DMD_updateDisplay(); +#if SL_LCDCTRL_MUX + sl_wfx_host_post_lcd_spi_transfer(); +#endif // SL_LCDCTRL_MUX +} + +void ClosureUI::SetMainState(chip::app::Clusters::ClosureControl::MainStateEnum state) +{ + sMainState = state; +} + +void ClosureUI::DrawHeader(GLIB_Context_t * glibContext) +{ + // Draw Silabs Corner icon + GLIB_drawBitmap(glibContext, SILABS_ICON_POSITION_X, STATUS_ICON_LINE, SILABS_LOGO_WIDTH, SILABS_LOGO_HEIGHT, silabsLogo); + // Draw BLE Icon + GLIB_drawBitmap(glibContext, BLE_ICON_POSITION_X, STATUS_ICON_LINE, BLUETOOTH_ICON_SIZE, BLUETOOTH_ICON_SIZE, bleLogo); + // Draw WiFi/OpenThread Icon +#ifdef SL_WIFI + GLIB_drawBitmap(glibContext, NETWORK_ICON_POSITION_X, STATUS_ICON_LINE, WIFI_BITMAP_WIDTH, WIFI_BITMAP_HEIGHT, wifiLogo); +#else + GLIB_drawBitmap(glibContext, NETWORK_ICON_POSITION_X, STATUS_ICON_LINE, THREAD_BITMAP_WIDTH, THREAD_BITMAP_HEIGHT, threadLogo); +#endif // SL_WIFI + // Draw Matter Icon + GLIB_drawBitmap(glibContext, MATTER_ICON_POSITION_X, STATUS_ICON_LINE, MATTER_LOGO_WIDTH, MATTER_LOGO_HEIGHT, matterLogoBitmap); +} + +void ClosureUI::DrawMainState(GLIB_Context_t * glibContext) +{ + const char * stateSuffix = ClosureUIStrings::SUFFIX_UNKNOWN; + + switch (sMainState) + { + case chip::app::Clusters::ClosureControl::MainStateEnum::kStopped: + stateSuffix = ClosureUIStrings::STATE_SUFFIX_STOPPED; + break; + case chip::app::Clusters::ClosureControl::MainStateEnum::kMoving: + stateSuffix = ClosureUIStrings::STATE_SUFFIX_MOVING; + break; + case chip::app::Clusters::ClosureControl::MainStateEnum::kWaitingForMotion: + stateSuffix = ClosureUIStrings::STATE_SUFFIX_WAITING; + break; + case chip::app::Clusters::ClosureControl::MainStateEnum::kError: + stateSuffix = ClosureUIStrings::STATE_SUFFIX_ERROR; + break; + case chip::app::Clusters::ClosureControl::MainStateEnum::kCalibrating: + stateSuffix = ClosureUIStrings::STATE_SUFFIX_CALIBRATING; + break; + case chip::app::Clusters::ClosureControl::MainStateEnum::kProtected: + stateSuffix = ClosureUIStrings::STATE_SUFFIX_PROTECTED; + break; + case chip::app::Clusters::ClosureControl::MainStateEnum::kDisengaged: + stateSuffix = ClosureUIStrings::STATE_SUFFIX_DISENGAGED; + break; + case chip::app::Clusters::ClosureControl::MainStateEnum::kSetupRequired: + stateSuffix = ClosureUIStrings::STATE_SUFFIX_SETUP_REQUIRED; + break; + case chip::app::Clusters::ClosureControl::MainStateEnum::kUnknownEnumValue: + default: + stateSuffix = ClosureUIStrings::SUFFIX_UNKNOWN; + break; + } + + snprintf(sStateText, ClosureUIStrings::LCD_STRING_BUFFER_SIZE, "%s%s", ClosureUIStrings::STATE_PREFIX, stateSuffix); + GLIB_drawStringOnLine(glibContext, sStateText, STATE_DISPLAY_LINE, GLIB_ALIGN_CENTER, 0, 0, true); +} + +void ClosureUI::DrawOverallCurrentState(GLIB_Context_t * glibContext) +{ + GLIB_drawStringOnLine(glibContext, sPositionText, POSITION_DISPLAY_LINE, GLIB_ALIGN_LEFT, 0, 0, true); + + GLIB_drawStringOnLine(glibContext, sLatchText, LATCH_DISPLAY_LINE, GLIB_ALIGN_LEFT, 0, 0, true); + + GLIB_drawStringOnLine(glibContext, sSecureText, SECURE_DISPLAY_LINE, GLIB_ALIGN_LEFT, 0, 0, true); + + GLIB_drawStringOnLine(glibContext, sSpeedText, SPEED_DISPLAY_LINE, GLIB_ALIGN_LEFT, 0, 0, true); +} + +void ClosureUI::DrawFooter(GLIB_Context_t * glibContext) +{ + GLIB_drawStringOnLine(glibContext, ClosureUIStrings::FOOTER_TEXT, FOOTER_DISPLAY_LINE, GLIB_ALIGN_CENTER, 0, 0, true); +} + +void ClosureUI::FormatAndSetPosition(const char * suffix) +{ + const char * safeSuffix = (suffix != nullptr) ? suffix : ClosureUIStrings::SUFFIX_UNKNOWN; + snprintf(sPositionText, ClosureUIStrings::LCD_STRING_BUFFER_SIZE, "%s%s", ClosureUIStrings::POSITION_PREFIX, safeSuffix); +} + +void ClosureUI::FormatAndSetLatch(const char * suffix) +{ + const char * safeSuffix = (suffix != nullptr) ? suffix : ClosureUIStrings::SUFFIX_UNKNOWN; + snprintf(sLatchText, ClosureUIStrings::LCD_STRING_BUFFER_SIZE, "%s%s", ClosureUIStrings::LATCH_PREFIX, safeSuffix); +} + +void ClosureUI::FormatAndSetSecure(const char * suffix) +{ + const char * safeSuffix = (suffix != nullptr) ? suffix : ClosureUIStrings::SUFFIX_UNKNOWN; + snprintf(sSecureText, ClosureUIStrings::LCD_STRING_BUFFER_SIZE, "%s%s", ClosureUIStrings::SECURE_PREFIX, safeSuffix); +} + +void ClosureUI::FormatAndSetSpeed(const char * suffix) +{ + const char * safeSuffix = (suffix != nullptr) ? suffix : ClosureUIStrings::SUFFIX_UNKNOWN; + snprintf(sSpeedText, ClosureUIStrings::LCD_STRING_BUFFER_SIZE, "%s%s", ClosureUIStrings::SPEED_PREFIX, safeSuffix); +} diff --git a/examples/closure-app/silabs/src/DataModelCallbacks.cpp b/examples/closure-app/silabs/src/DataModelCallbacks.cpp index 6eae4e8ae3c5e1..fe66cdf894b471 100644 --- a/examples/closure-app/silabs/src/DataModelCallbacks.cpp +++ b/examples/closure-app/silabs/src/DataModelCallbacks.cpp @@ -21,6 +21,7 @@ */ #include +#include #include #include @@ -53,6 +54,23 @@ void MatterPostAttributeChangeCallback(const app::ConcreteAttributePath & attrib void MatterClosureControlClusterServerAttributeChangedCallback(const app::ConcreteAttributePath & attributePath) { ChipLogProgress(Zcl, "Closure Control cluster ID: " ChipLogFormatMEI, ChipLogValueMEI(attributePath.mAttributeId)); +#ifdef DISPLAY_ENABLED + using namespace chip::app::Clusters::ClosureControl::Attributes; + + switch (attributePath.mAttributeId) + { + case MainState::Id: + case OverallCurrentState::Id: { + AppEvent event; + event.Type = AppEvent::kEventType_UpdateUI; + event.Handler = AppTask::UpdateClosureUIHandler; + AppTask::GetAppTask().PostEvent(&event); + break; + } + default: + break; + } +#endif // DISPLAY_ENABLED } void MatterClosureDimensionClusterServerAttributeChangedCallback(const app::ConcreteAttributePath & attributePath)