blob: 741ea7c413546e653d42a4a095b9e2f43dc86f46 [file] [log] [blame]
/*
*
* 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);
}