| /* |
| * |
| * 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 <stdio.h> |
| |
| #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 defined(SL_WIFI) && SL_WIFI && !defined(SLI_SI91X_MCU_INTERFACE) |
| #include <platform/silabs/wifi/ncp/spi_multiplex.h> |
| #endif // defined(SL_WIFI) && 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 defined(SL_LCDCTRL_MUX) && SL_LCDCTRL_MUX |
| sl_wfx_host_pre_lcd_spi_transfer(); |
| #endif // defined(SL_LCDCTRL_MUX) && SL_LCDCTRL_MUX |
| DMD_updateDisplay(); |
| #if defined(SL_LCDCTRL_MUX) && SL_LCDCTRL_MUX |
| sl_wfx_host_post_lcd_spi_transfer(); |
| #endif // defined(SL_LCDCTRL_MUX) && 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); |
| } |