diff --git a/Makefile.am b/Makefile.am index 22cfac37..d7945d96 100644 --- a/Makefile.am +++ b/Makefile.am @@ -38,3 +38,15 @@ package_ipk: rm -rf $(IPK_GEN_PATH)/data.tar.gz rm -rf $(IPK_GEN_PATH)/control.tar.gz rm -rf $(IPK_GEN_STAGING_DIR) + +# DSApp - Device Settings Test Application +.PHONY: dsapp dsapp-clean + +dsapp: + @echo "Building DSApp..." + $(MAKE) -C sample dsapp + @echo "DSApp executable: $(abs_top_builddir)/DSApp" + +dsapp-clean: + @echo "Cleaning DSApp..." + $(MAKE) -C sample dsapp-clean diff --git a/configure.ac b/configure.ac index 081cb2be..7445ffc2 100644 --- a/configure.ac +++ b/configure.ac @@ -50,6 +50,19 @@ PKG_CHECK_MODULES([DBUS], [dbus-1]) AC_CHECK_LIB(gthread-2.0, g_thread_init) +# Thunder COM-RPC plugin support +AC_ARG_ENABLE([thunder-plugin], + AS_HELP_STRING([--enable-thunder-plugin], [Enable Thunder COM-RPC plugin support (default: no)]), + [enable_thunder_plugin=$enableval], + [enable_thunder_plugin=no]) + +AM_CONDITIONAL([USE_THUNDER_PLUGIN], [test "x$enable_thunder_plugin" = "xyes"]) + +AS_IF([test "x$enable_thunder_plugin" = "xyes"], + [AC_DEFINE([USE_WPE_THUNDER_PLUGIN], [1], [Define to 1 to enable Thunder COM-RPC plugin support]) + AC_MSG_NOTICE([Thunder COM-RPC plugin support enabled])], + [AC_MSG_NOTICE([Thunder COM-RPC plugin support disabled])]) + # Checks for typedefs, structures, and compiler characteristics. AC_TYPE_PID_T AC_TYPE_SIZE_T diff --git a/cov_build.sh b/cov_build.sh index 22e8d7d4..1f1a6463 100644 --- a/cov_build.sh +++ b/cov_build.sh @@ -66,8 +66,10 @@ cd ${RDK_SOURCE_PATH} export STANDALONE_BUILD_ENABLED=y export DS_MGRS=$WORKDIR +export USE_WPE_THUNDER_PLUGIN=y + find $WORKDIR -iname "*.o" -exec rm -v {} \; find $WORKDIR -iname "*.so*" -exec rm -v {} \; echo "##### Triggering make" -make CFLAGS+='-fPIC -DDSMGR_LOGGER_ENABLED=ON -DRDK_DSHAL_NAME=\"libdshal.so\" -I${DS_IF_PATH}/include -I${DS_HAL_PATH} -I${DS_MGRS}/stubs -I${IARMBUS_PATH}/core -I${IARMBUS_PATH}/core/include -I${IARM_MGRS}/sysmgr/include -I${DS_MGRS}/ds/include -I${DS_MGRS}/rpc/include -I${POWER_IF_PATH}/include/ -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I${IARM_MGRS}/mfr/include/ -I${IARM_MGRS}/mfr/common -I${DEEPSLEEP_IF_PATH}/include -I${IARM_MGRS}/hal/include -I${IARM_MGRS}/power -I${IARM_MGRS}/power/include' LDFLAGS="-L/usr/lib/x86_64-linux-gnu/ -L/usr/local/include -lglib-2.0 -lIARMBus -lWPEFrameworkPowerController -ldshal" \ No newline at end of file +make CFLAGS+='-fPIC -DDSMGR_LOGGER_ENABLED=ON -DRDK_DSHAL_NAME=\"libdshal.so\" -I${DS_IF_PATH}/include -I${DS_HAL_PATH} -I${DS_MGRS}/stubs -I${IARMBUS_PATH}/core -I${IARMBUS_PATH}/core/include -I${IARM_MGRS}/sysmgr/include -I${DS_MGRS}/ds/include -I${DS_MGRS}/rpc/include -I${POWER_IF_PATH}/include/ -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I${IARM_MGRS}/mfr/include/ -I${IARM_MGRS}/mfr/common -I${DEEPSLEEP_IF_PATH}/include -I${IARM_MGRS}/hal/include -I${IARM_MGRS}/power -I${IARM_MGRS}/power/include' LDFLAGS="-L/usr/lib/x86_64-linux-gnu/ -L/usr/local/include -lglib-2.0 -lIARMBus -lWPEFrameworkPowerController -ldshal" diff --git a/rpc/cli/Makefile b/rpc/cli/Makefile index ab24c14f..7b2575ee 100644 --- a/rpc/cli/Makefile +++ b/rpc/cli/Makefile @@ -21,8 +21,20 @@ CFLAGS += -g -fPIC -D_REENTRANT -Wall LIBNAME := dshalcli LIBNAMEFULL := lib$(LIBNAME).so INSTALL := $(PWD)/install -OBJS := $(patsubst %.cpp,%.o,$(wildcard *.cpp)) -OBJS += $(patsubst %.c,%.o,$(wildcard *.c)) + +# Conditional compilation: Thunder vs IARM +ifdef USE_WPE_THUNDER_PLUGIN + # Thunder mode - use dsFPD-com.cpp, exclude dsFPD.c + OBJS := $(patsubst %.cpp,%.o,$(wildcard *.cpp)) + OBJS += $(patsubst %.c,%.o,$(filter-out dsFPD.c,$(wildcard *.c))) +else + # IARM mode - use dsFPD.c, exclude dsFPD-com.cpp + OBJS := $(patsubst %.cpp,%.o,$(filter-out dsFPD-com.cpp,$(wildcard *.cpp))) + OBJS += $(patsubst %.c,%.o,$(wildcard *.c)) +endif + +#OBJS := $(patsubst %.cpp,%.o,$(wildcard *.cpp)) +#OBJS += $(patsubst %.c,%.o,$(wildcard *.c)) INCLUDE := -I$(PWD) \ -I$(PWD)/hal/include \ -I$(PWD)/rpc/include @@ -31,13 +43,19 @@ INCLUDE += $(HAL_INCLUDE) CFLAGS += $(INCLUDE) +# Conditional linking flags +ifdef USE_WPE_THUNDER_PLUGIN + LDLIBS := -lWPEFrameworkCore -lWPEFrameworkCOM +else + LDLIBS := -lIARMBus +endif all: install @echo "Build Finished...." library: $(OBJS) @echo "Building $(LIBNAMEFULL) ...." - $(CXX) $(OBJS) $(CFLAGS) -lIARMBus -shared -o $(LIBNAMEFULL) + $(CXX) $(OBJS) $(CFLAGS) $(LDLIBS) -shared -o $(LIBNAMEFULL) %.o: %.cpp @echo "Building $@ ...." diff --git a/rpc/cli/Makefile.am b/rpc/cli/Makefile.am index fe48bb37..27f50c1b 100644 --- a/rpc/cli/Makefile.am +++ b/rpc/cli/Makefile.am @@ -28,4 +28,15 @@ INCLUDE_FILES = -I=$(includedir)/rdk/halif/ds-hal \ lib_LTLIBRARIES = libdshalcli.la libdshalcli_la_CPPFLAGS = $(INCLUDE_FILES) libdshalcli_la_CFLAGS = -g -fPIC -D_REENTRANT -Wall -libdshalcli_la_SOURCES = dsAudio.c dsclientlogger.c dsDisplay.c dsFPD.c dsHost.cpp dsVideoDevice.c dsVideoPort.c + +# Conditional compilation for Thunder COM-RPC +if USE_THUNDER_PLUGIN + FPD_SOURCE = dsFPD-com.cpp + THUNDER_LIBS = -lWPEFrameworkCore -lWPEFrameworkCOM +else + FPD_SOURCE = dsFPD.c + THUNDER_LIBS = +endif + +libdshalcli_la_SOURCES = dsAudio.c dsclientlogger.c dsDisplay.c $(FPD_SOURCE) dsHost.cpp dsVideoDevice.c dsVideoPort.c +libdshalcli_la_LIBADD = $(THUNDER_LIBS) diff --git a/rpc/cli/dsFPD-com.cpp b/rpc/cli/dsFPD-com.cpp new file mode 100644 index 00000000..53631e05 --- /dev/null +++ b/rpc/cli/dsFPD-com.cpp @@ -0,0 +1,760 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2016 RDK Management + * + * 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. +*/ + +/** +* @defgroup devicesettings +* @{ +* @defgroup rpc +* @{ +**/ + +#ifdef USE_WPE_THUNDER_PLUGIN + +#include +#include +#include +#include + +#include "dsFPD.h" +#include "dsError.h" +#include "dsclientlogger.h" + +// Thunder COM-RPC includes +#ifndef MODULE_NAME +#define MODULE_NAME DeviceSettings_FPD_Client +#endif + +#include +#include +#include +#include + +using namespace WPEFramework; + +// Thunder callsign for DeviceSettings plugin +static constexpr const TCHAR callSign[] = _T("org.rdk.DeviceSettings"); + +/** + * @brief DeviceSettingsFPD class manages Thunder COM-RPC connection for FPD + */ +class DeviceSettingsFPD : public RPC::SmartInterfaceType { +private: + using BaseClass = RPC::SmartInterfaceType; + + Exchange::IDeviceSettingsFPD* _fpdInterface; + + static DeviceSettingsFPD* _instance; + static Core::CriticalSection _apiLock; + + bool _connected; + bool _shutdown; + + DeviceSettingsFPD() + : BaseClass() + , _fpdInterface(nullptr) + , _connected(false) + , _shutdown(false) + { + (void)Connect(); + } + + ~DeviceSettingsFPD() + { + _shutdown = true; + BaseClass::Close(Core::infinite); + } + + virtual void Operational(const bool upAndRunning) override + { + _apiLock.Lock(); + + if (upAndRunning) { + // Communicator opened && DeviceSettings is Activated + if (nullptr == _fpdInterface) { + _fpdInterface = BaseClass::Interface(); + if (_fpdInterface != nullptr) { + printf("[dsFPD-com] Successfully established COM-RPC connection with DeviceSettings plugin\n"); + } else { + fprintf(stderr, "[dsFPD-com] Failed to get interface - plugin implementation may have failed to load\n"); + } + } + } else { + // DeviceSettings is Deactivated || Communicator closed + if (nullptr != _fpdInterface) { + _fpdInterface->Release(); + _fpdInterface = nullptr; + } + } + _apiLock.Unlock(); + } + + inline bool IsActivatedLocked() const + { + return (nullptr != _fpdInterface); + } + + inline bool isConnected() const + { + return _connected; + } + +public: + bool IsOperational() const + { + _apiLock.Lock(); + bool result = (isConnected() && (nullptr != _fpdInterface)); + _apiLock.Unlock(); + return result; + } + + bool WaitForOperational(uint32_t timeoutMs = 5000) const + { + const uint32_t pollIntervalMs = 100; + uint32_t elapsedMs = 0; + + while (elapsedMs < timeoutMs) { + if (IsOperational()) { + return true; + } + std::this_thread::sleep_for(std::chrono::milliseconds(pollIntervalMs)); + elapsedMs += pollIntervalMs; + } + return false; + } + + uint32_t Connect() + { + uint32_t status = Core::ERROR_NONE; + + _apiLock.Lock(); + + if (!isConnected()) { + printf("[dsFPD-com] Attempting to connect to Thunder with callsign: %s\n", callSign); + uint32_t res = BaseClass::Open(RPC::CommunicationTimeOut, BaseClass::Connector(), callSign); + if (Core::ERROR_NONE == res) { + _connected = true; + printf("[dsFPD-com] Successfully opened RPC connection to Thunder\n"); + } else { + fprintf(stderr, "[dsFPD-com] Failed to open RPC connection, error: %u. Is Thunder running?\n", res); + status = Core::ERROR_UNAVAILABLE; + } + } + + if (nullptr == _fpdInterface) { + status = Core::ERROR_NOT_EXIST; + printf("[dsFPD-com] DeviceSettings plugin not yet operational\n"); + } + + _apiLock.Unlock(); + + return status; + } + + uint32_t Disconnect() + { + uint32_t status = Core::ERROR_GENERAL; + bool close = false; + + _apiLock.Lock(); + + if (isConnected()) { + close = true; + _connected = false; + } + + _apiLock.Unlock(); + + if (close) { + status = BaseClass::Close(Core::infinite); + } + + return status; + } + + static void Init() + { + _apiLock.Lock(); + if (nullptr == _instance) { + _instance = new DeviceSettingsFPD(); + } + _apiLock.Unlock(); + } + + static void Term() + { + _apiLock.Lock(); + if (nullptr != _instance) { + delete _instance; + _instance = nullptr; + } + _apiLock.Unlock(); + } + + static DeviceSettingsFPD* Instance() + { + return _instance; + } + + // FPD API implementations + // Note: Thunder interface doesn't have FPDInit/FPDTerm/SetFPDText methods + + Core::hresult SetFPDTime(const Exchange::IDeviceSettingsFPD::FPDTimeFormat timeFormat, + const uint32_t minutes, const uint32_t seconds) + { + Core::hresult result = Core::ERROR_UNAVAILABLE; + _apiLock.Lock(); + if (_fpdInterface) { + result = _fpdInterface->SetFPDTime(timeFormat, minutes, seconds); + } + _apiLock.Unlock(); + return result; + } + + Core::hresult SetFPDScroll(const uint32_t scrollHoldOnDur, const uint32_t horzScrollIterations, + const uint32_t vertScrollIterations) + { + Core::hresult result = Core::ERROR_UNAVAILABLE; + _apiLock.Lock(); + if (_fpdInterface) { + result = _fpdInterface->SetFPDScroll(scrollHoldOnDur, horzScrollIterations, vertScrollIterations); + } + _apiLock.Unlock(); + return result; + } + + Core::hresult SetFPDBlink(const Exchange::IDeviceSettingsFPD::FPDIndicator indicator, + const uint32_t blinkDuration, const uint32_t blinkIterations) + { + Core::hresult result = Core::ERROR_UNAVAILABLE; + _apiLock.Lock(); + if (_fpdInterface) { + result = _fpdInterface->SetFPDBlink(indicator, blinkDuration, blinkIterations); + } + _apiLock.Unlock(); + return result; + } + + Core::hresult GetFPDBrightness(const Exchange::IDeviceSettingsFPD::FPDIndicator indicator, + uint32_t& brightness) + { + Core::hresult result = Core::ERROR_UNAVAILABLE; + _apiLock.Lock(); + if (_fpdInterface) { + result = _fpdInterface->GetFPDBrightness(indicator, brightness); + } + _apiLock.Unlock(); + return result; + } + + Core::hresult SetFPDBrightness(const Exchange::IDeviceSettingsFPD::FPDIndicator indicator, + const uint32_t brightness, const bool persist) + { + Core::hresult result = Core::ERROR_UNAVAILABLE; + _apiLock.Lock(); + if (_fpdInterface) { + result = _fpdInterface->SetFPDBrightness(indicator, brightness, persist); + } + _apiLock.Unlock(); + return result; + } + + Core::hresult GetFPDTextBrightness(const Exchange::IDeviceSettingsFPD::FPDTextDisplay indicator, + uint32_t& brightness) + { + Core::hresult result = Core::ERROR_UNAVAILABLE; + _apiLock.Lock(); + if (_fpdInterface) { + result = _fpdInterface->GetFPDTextBrightness(indicator, brightness); + } + _apiLock.Unlock(); + return result; + } + + Core::hresult SetFPDTextBrightness(const Exchange::IDeviceSettingsFPD::FPDTextDisplay indicator, + const uint32_t brightness) + { + Core::hresult result = Core::ERROR_UNAVAILABLE; + _apiLock.Lock(); + if (_fpdInterface) { + result = _fpdInterface->SetFPDTextBrightness(indicator, brightness); + } + _apiLock.Unlock(); + return result; + } + + Core::hresult GetFPDColor(const Exchange::IDeviceSettingsFPD::FPDIndicator indicator, + uint32_t& color) + { + Core::hresult result = Core::ERROR_UNAVAILABLE; + _apiLock.Lock(); + if (_fpdInterface) { + result = _fpdInterface->GetFPDColor(indicator, color); + } + _apiLock.Unlock(); + return result; + } + + Core::hresult SetFPDColor(const Exchange::IDeviceSettingsFPD::FPDIndicator indicator, + const uint32_t color) + { + Core::hresult result = Core::ERROR_UNAVAILABLE; + _apiLock.Lock(); + if (_fpdInterface) { + result = _fpdInterface->SetFPDColor(indicator, color); + } + _apiLock.Unlock(); + return result; + } + + Core::hresult EnableFPDClockDisplay(const bool enable) + { + Core::hresult result = Core::ERROR_UNAVAILABLE; + _apiLock.Lock(); + if (_fpdInterface) { + result = _fpdInterface->EnableFPDClockDisplay(enable); + } + _apiLock.Unlock(); + return result; + } + + Core::hresult SetFPDState(const Exchange::IDeviceSettingsFPD::FPDIndicator indicator, + const Exchange::IDeviceSettingsFPD::FPDState state) + { + Core::hresult result = Core::ERROR_UNAVAILABLE; + _apiLock.Lock(); + if (_fpdInterface) { + result = _fpdInterface->SetFPDState(indicator, state); + } + _apiLock.Unlock(); + return result; + } + + Core::hresult GetFPDState(const Exchange::IDeviceSettingsFPD::FPDIndicator indicator, + Exchange::IDeviceSettingsFPD::FPDState& state) + { + Core::hresult result = Core::ERROR_UNAVAILABLE; + _apiLock.Lock(); + if (_fpdInterface) { + result = _fpdInterface->GetFPDState(indicator, state); + } + _apiLock.Unlock(); + return result; + } + + Core::hresult GetFPDTimeFormat(Exchange::IDeviceSettingsFPD::FPDTimeFormat& timeFormat) + { + Core::hresult result = Core::ERROR_UNAVAILABLE; + _apiLock.Lock(); + if (_fpdInterface) { + result = _fpdInterface->GetFPDTimeFormat(timeFormat); + } + _apiLock.Unlock(); + return result; + } + + Core::hresult SetFPDTimeFormat(const Exchange::IDeviceSettingsFPD::FPDTimeFormat timeFormat) + { + Core::hresult result = Core::ERROR_UNAVAILABLE; + _apiLock.Lock(); + if (_fpdInterface) { + result = _fpdInterface->SetFPDTimeFormat(timeFormat); + } + _apiLock.Unlock(); + return result; + } + + Core::hresult SetFPDMode(const Exchange::IDeviceSettingsFPD::FPDMode mode) + { + Core::hresult result = Core::ERROR_UNAVAILABLE; + _apiLock.Lock(); + if (_fpdInterface) { + result = _fpdInterface->SetFPDMode(mode); + } + _apiLock.Unlock(); + return result; + } +}; + +// Static member initialization +DeviceSettingsFPD* DeviceSettingsFPD::_instance = nullptr; +Core::CriticalSection DeviceSettingsFPD::_apiLock; + +/** + * @brief Convert Thunder error code to dsError_t + */ +static dsError_t ConvertThunderError(uint32_t thunderError) +{ + if (thunderError == Core::ERROR_NONE) { + return dsERR_NONE; + } else if (thunderError == Core::ERROR_UNAVAILABLE) { + return dsERR_OPERATION_NOT_SUPPORTED; + } else if (thunderError == Core::ERROR_BAD_REQUEST) { + return dsERR_INVALID_PARAM; + } else { + return dsERR_GENERAL; + } +} + +// C API implementations using Thunder COM-RPC + +extern "C" { + +// Forward declarations +dsError_t dsSetFPDBrightness(dsFPDIndicator_t eIndicator, dsFPDBrightness_t eBrightness, bool toPersist); +dsError_t dsSetFPDColor(dsFPDIndicator_t eIndicator, dsFPDColor_t eColor, bool toPersist); + +dsError_t dsFPInit(void) +{ + printf("<<<<< Front Panel is initialized in Thunder Mode >>>>>>>>\r\n"); + + DeviceSettingsFPD* instance = DeviceSettingsFPD::Instance(); + if (!instance) { + DeviceSettingsFPD::Init(); + instance = DeviceSettingsFPD::Instance(); + } + + if (!instance) { + fprintf(stderr, "[dsFPD-com] Failed to create DeviceSettingsFPD instance\n"); + return dsERR_GENERAL; + } + + // Wait for plugin to become operational + if (!instance->WaitForOperational(5000)) { + fprintf(stderr, "[dsFPD-com] DeviceSettings plugin not operational after 5 seconds\n"); + return dsERR_GENERAL; + } + + // Thunder interface doesn't have explicit Init method - connection is sufficient + return dsERR_NONE; +} + +dsError_t dsFPTerm(void) +{ + DeviceSettingsFPD* instance = DeviceSettingsFPD::Instance(); + if (!instance) { + return dsERR_GENERAL; + } + + // Thunder interface doesn't have explicit Term method + // Terminate instance + DeviceSettingsFPD::Term(); + + return dsERR_NONE; +} + +dsError_t dsSetFPText(const char* pszChars) +{ + if (pszChars == NULL) { + fprintf(stderr, "[dsFPD-com] Invalid parameter: pszChars is NULL\n"); + return dsERR_INVALID_PARAM; + } + + // Thunder interface doesn't support text display + fprintf(stderr, "[dsFPD-com] SetFPText not supported in Thunder mode\n"); + return dsERR_OPERATION_NOT_SUPPORTED; +} + +dsError_t dsSetFPTime(dsFPDTimeFormat_t eTime, const unsigned int uHour, const unsigned int uMinutes) +{ + DeviceSettingsFPD* instance = DeviceSettingsFPD::Instance(); + if (!instance || !instance->IsOperational()) { + return dsERR_GENERAL; + } + + Exchange::IDeviceSettingsFPD::FPDTimeFormat timeFormat = + static_cast(eTime); + + // Note: Interface expects minutes and seconds, but API provides hour and minutes + // Converting: treating uMinutes as seconds for interface compatibility + uint32_t result = instance->SetFPDTime(timeFormat, uHour, uMinutes); + return ConvertThunderError(result); +} + +dsError_t dsSetFPScroll(unsigned int nScrollHoldOnDur, unsigned int nHorzScrollIterations, unsigned int nVertScrollIterations) +{ + DeviceSettingsFPD* instance = DeviceSettingsFPD::Instance(); + if (!instance || !instance->IsOperational()) { + return dsERR_GENERAL; + } + + uint32_t result = instance->SetFPDScroll(nScrollHoldOnDur, nHorzScrollIterations, nVertScrollIterations); + return ConvertThunderError(result); +} + +dsError_t dsSetFPBlink(dsFPDIndicator_t eIndicator, unsigned int nBlinkDuration, unsigned int nBlinkIterations) +{ + DeviceSettingsFPD* instance = DeviceSettingsFPD::Instance(); + if (!instance || !instance->IsOperational()) { + return dsERR_GENERAL; + } + + Exchange::IDeviceSettingsFPD::FPDIndicator indicator = + static_cast(eIndicator); + + uint32_t result = instance->SetFPDBlink(indicator, nBlinkDuration, nBlinkIterations); + return ConvertThunderError(result); +} + +dsError_t dsGetFPBrightness(dsFPDIndicator_t eIndicator, dsFPDBrightness_t *pBrightness) +{ + if (pBrightness == NULL) { + fprintf(stderr, "[dsFPD-com] Invalid parameter: pBrightness is NULL\n"); + return dsERR_INVALID_PARAM; + } + + DeviceSettingsFPD* instance = DeviceSettingsFPD::Instance(); + if (!instance || !instance->IsOperational()) { + return dsERR_GENERAL; + } + + Exchange::IDeviceSettingsFPD::FPDIndicator indicator = + static_cast(eIndicator); + + uint32_t brightness = 0; + uint32_t result = instance->GetFPDBrightness(indicator, brightness); + + if (result == Core::ERROR_NONE) { + *pBrightness = static_cast(brightness); + } + + return ConvertThunderError(result); +} + +dsError_t dsGetFPDBrightness(dsFPDIndicator_t eIndicator, dsFPDBrightness_t *pBrightness, bool persist) +{ + // Note: persist parameter may not be used in GET operation for Thunder + return dsGetFPBrightness(eIndicator, pBrightness); +} + +dsError_t dsSetFPBrightness(dsFPDIndicator_t eIndicator, dsFPDBrightness_t eBrightness) +{ + return dsSetFPDBrightness(eIndicator, eBrightness, true); +} + +dsError_t dsSetFPDBrightness(dsFPDIndicator_t eIndicator, dsFPDBrightness_t eBrightness, bool toPersist) +{ + if (eIndicator >= dsFPD_INDICATOR_MAX || eBrightness > 100) { + fprintf(stderr, "[dsFPD-com] Invalid parameter\n"); + return dsERR_INVALID_PARAM; + } + + DeviceSettingsFPD* instance = DeviceSettingsFPD::Instance(); + if (!instance || !instance->IsOperational()) { + return dsERR_GENERAL; + } + + Exchange::IDeviceSettingsFPD::FPDIndicator indicator = + static_cast(eIndicator); + + uint32_t result = instance->SetFPDBrightness(indicator, static_cast(eBrightness), toPersist); + return ConvertThunderError(result); +} + +dsError_t dsGetFPTextBrightness(dsFPDTextDisplay_t eIndicator, dsFPDBrightness_t *pBrightness) +{ + if (pBrightness == NULL) { + fprintf(stderr, "[dsFPD-com] Invalid parameter: pBrightness is NULL\n"); + return dsERR_INVALID_PARAM; + } + + DeviceSettingsFPD* instance = DeviceSettingsFPD::Instance(); + if (!instance || !instance->IsOperational()) { + return dsERR_GENERAL; + } + + Exchange::IDeviceSettingsFPD::FPDTextDisplay indicator = + static_cast(eIndicator); + + uint32_t brightness = 0; + uint32_t result = instance->GetFPDTextBrightness(indicator, brightness); + + if (result == Core::ERROR_NONE) { + *pBrightness = static_cast(brightness); + } + + return ConvertThunderError(result); +} + +dsError_t dsSetFPTextBrightness(dsFPDTextDisplay_t eIndicator, dsFPDBrightness_t eBrightness) +{ + DeviceSettingsFPD* instance = DeviceSettingsFPD::Instance(); + if (!instance || !instance->IsOperational()) { + return dsERR_GENERAL; + } + + Exchange::IDeviceSettingsFPD::FPDTextDisplay indicator = + static_cast(eIndicator); + + uint32_t result = instance->SetFPDTextBrightness(indicator, static_cast(eBrightness)); + return ConvertThunderError(result); +} + +dsError_t dsGetFPColor(dsFPDIndicator_t eIndicator, dsFPDColor_t *pColor) +{ + if (pColor == NULL) { + fprintf(stderr, "[dsFPD-com] Invalid parameter: pColor is NULL\n"); + return dsERR_INVALID_PARAM; + } + + DeviceSettingsFPD* instance = DeviceSettingsFPD::Instance(); + if (!instance || !instance->IsOperational()) { + return dsERR_GENERAL; + } + + Exchange::IDeviceSettingsFPD::FPDIndicator indicator = + static_cast(eIndicator); + + uint32_t color = 0; + uint32_t result = instance->GetFPDColor(indicator, color); + + if (result == Core::ERROR_NONE) { + *pColor = static_cast(color); + } + + return ConvertThunderError(result); +} + +dsError_t dsSetFPColor(dsFPDIndicator_t eIndicator, dsFPDColor_t eColor) +{ + return dsSetFPDColor(eIndicator, eColor, true); +} + +dsError_t dsSetFPDColor(dsFPDIndicator_t eIndicator, dsFPDColor_t eColor, bool toPersist) +{ + DeviceSettingsFPD* instance = DeviceSettingsFPD::Instance(); + if (!instance || !instance->IsOperational()) { + return dsERR_GENERAL; + } + + Exchange::IDeviceSettingsFPD::FPDIndicator indicator = + static_cast(eIndicator); + + // Thunder interface doesn't support persist flag - ignore it + uint32_t result = instance->SetFPDColor(indicator, static_cast(eColor)); + return ConvertThunderError(result); +} + +dsError_t dsFPEnableCLockDisplay(int enable) +{ + DeviceSettingsFPD* instance = DeviceSettingsFPD::Instance(); + if (!instance || !instance->IsOperational()) { + return dsERR_GENERAL; + } + + uint32_t result = instance->EnableFPDClockDisplay(enable != 0); + return ConvertThunderError(result); +} + +dsError_t dsSetFPState(dsFPDIndicator_t eIndicator, dsFPDState_t state) +{ + DeviceSettingsFPD* instance = DeviceSettingsFPD::Instance(); + if (!instance || !instance->IsOperational()) { + return dsERR_GENERAL; + } + + Exchange::IDeviceSettingsFPD::FPDIndicator indicator = + static_cast(eIndicator); + Exchange::IDeviceSettingsFPD::FPDState fpdState = + static_cast(state); + + uint32_t result = instance->SetFPDState(indicator, fpdState); + return ConvertThunderError(result); +} + +dsError_t dsGetFPState(dsFPDIndicator_t eIndicator, dsFPDState_t* state) +{ + if (state == NULL) { + fprintf(stderr, "[dsFPD-com] Invalid parameter: state is NULL\n"); + return dsERR_INVALID_PARAM; + } + + DeviceSettingsFPD* instance = DeviceSettingsFPD::Instance(); + if (!instance || !instance->IsOperational()) { + return dsERR_GENERAL; + } + + Exchange::IDeviceSettingsFPD::FPDIndicator indicator = + static_cast(eIndicator); + + Exchange::IDeviceSettingsFPD::FPDState fpdState; + uint32_t result = instance->GetFPDState(indicator, fpdState); + + if (result == Core::ERROR_NONE) { + *state = static_cast(fpdState); + } + + return ConvertThunderError(result); +} + +dsError_t dsGetFPTimeFormat(dsFPDTimeFormat_t *pTimeFormat) +{ + if (pTimeFormat == NULL) { + fprintf(stderr, "[dsFPD-com] Invalid parameter: pTimeFormat is NULL\n"); + return dsERR_INVALID_PARAM; + } + + DeviceSettingsFPD* instance = DeviceSettingsFPD::Instance(); + if (!instance || !instance->IsOperational()) { + return dsERR_GENERAL; + } + + Exchange::IDeviceSettingsFPD::FPDTimeFormat timeFormat; + uint32_t result = instance->GetFPDTimeFormat(timeFormat); + + if (result == Core::ERROR_NONE) { + *pTimeFormat = static_cast(timeFormat); + } + + return ConvertThunderError(result); +} + +dsError_t dsSetFPTimeFormat(dsFPDTimeFormat_t eTimeFormat) +{ + DeviceSettingsFPD* instance = DeviceSettingsFPD::Instance(); + if (!instance || !instance->IsOperational()) { + return dsERR_GENERAL; + } + + Exchange::IDeviceSettingsFPD::FPDTimeFormat timeFormat = + static_cast(eTimeFormat); + + uint32_t result = instance->SetFPDTimeFormat(timeFormat); + return ConvertThunderError(result); +} + +dsError_t dsSetFPDMode(dsFPDMode_t eMode) +{ + DeviceSettingsFPD* instance = DeviceSettingsFPD::Instance(); + if (!instance || !instance->IsOperational()) { + return dsERR_GENERAL; + } + + Exchange::IDeviceSettingsFPD::FPDMode mode = + static_cast(eMode); + + uint32_t result = instance->SetFPDMode(mode); + return ConvertThunderError(result); +} + +} // extern "C" + +#endif // USE_WPE_THUNDER_PLUGIN + +/** @} */ +/** @} */ diff --git a/sample/DSCliLibStandaloneApp.cpp b/sample/DSCliLibStandaloneApp.cpp new file mode 100644 index 00000000..ed512166 --- /dev/null +++ b/sample/DSCliLibStandaloneApp.cpp @@ -0,0 +1,762 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// RDK specific includes - libds.so API +#include "manager.hpp" // Device Settings Manager from libds.so +#include "host.hpp" // Host class from libds.so +#include "frontPanelIndicator.hpp" // FrontPanelIndicator class from libds.so +#include "frontPanelTextDisplay.hpp" // FrontPanelTextDisplay class from libds.so +// #include "libIBus.h" // Uncomment if using IARM Bus +// #include "libIBusDaemon.h" // Uncomment if using IARM Bus daemon + +using namespace std; +using namespace device; // For libds.so classes + +// RDK/Yocto specific constants +#define MAX_DEBUG_LOG_BUFF_SIZE 8192 +#define DEVICE_SETTINGS_ERROR_NONE 0 +#define DEVICE_SETTINGS_ERROR_GENERAL 1 +#define DEVICE_SETTINGS_ERROR_UNAVAILABLE 2 +#define DEVICE_SETTINGS_ERROR_NOT_EXIST 43 + +// Define logging macros +#define LOGI(fmt, ...) printf("[INFO] " fmt "\n", ##__VA_ARGS__) +#define LOGE(fmt, ...) printf("[ERROR] " fmt "\n", ##__VA_ARGS__) +#define LOGD(fmt, ...) printf("[DEBUG] " fmt "\n", ##__VA_ARGS__) + +// Global variables +static pthread_mutex_t gCurlInitMutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t gDSAppMutex = PTHREAD_MUTEX_INITIALIZER; +CURLSH* mCurlShared = nullptr; +char* gDebugPrintBuffer = nullptr; + +// RDK specific globals +static bool gAppInitialized = false; +static bool gSignalHandlersSet = false; + +// Function declarations (libds.so functions) +void libds_Initialize(); +void libds_Terminate(); +int setup_signals(); +int breakpad_ExceptionHandler(); +void cleanup_resources(); + +// Menu system functions +void showMainMenu(); +void handleFPDModule(); +void handleAudioPortsModule(); +void handleVideoPortsModule(); +void handleHDMIInModule(); +void handleCompositeInModule(); +int getUserChoice(); +void clearScreen(); + + +int main(int argc, char **argv) +{ + // Initialize syslog for RDK environment + openlog("DSApp", LOG_PID | LOG_CONS, LOG_DAEMON); + + printf("\n=== DeviceSettings Interactive Test Application ===\n"); + printf("Build: %s %s\n", __DATE__, __TIME__); + + // Parse command line arguments + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) { + printf("Usage: %s [options]\n", argv[0]); + printf("Options:\n"); + printf(" -h, --help Show this help message\n"); + printf(" --version Show version information\n"); + return 0; + } else if (strcmp(argv[i], "--version") == 0) { + printf("DSApp version 1.0.0 (RDK/Yocto build)\n"); + return 0; + } + } + + // Set up signal handlers early + if (setup_signals() != 0) { + LOGE("Failed to setup signal handlers"); + return -1; + } + + // Allocate debug buffer with error checking + gDebugPrintBuffer = new(std::nothrow) char[MAX_DEBUG_LOG_BUFF_SIZE]; + if (!gDebugPrintBuffer) { + LOGE("Failed to allocate debug buffer of size %d", MAX_DEBUG_LOG_BUFF_SIZE); + return -1; + } + memset(gDebugPrintBuffer, 0, MAX_DEBUG_LOG_BUFF_SIZE); + + // Initialize curl for network operations + CURLcode curl_result = curl_global_init(CURL_GLOBAL_ALL); + if (curl_result != CURLE_OK) { + LOGE("Failed to initialize curl: %s", curl_easy_strerror(curl_result)); + cleanup_resources(); + return -1; + } + + // Initialize breakpad for crash reporting + if (breakpad_ExceptionHandler() != 0) { + LOGE("Failed to initialize exception handler"); + // Continue anyway, not critical + } + + // Initialize libds.so (Device Settings library) + printf("\nInitializing libds.so (Device Settings library)...\n"); + libds_Initialize(); + printf("libds.so initialized successfully!\n"); + + // Set application as initialized + pthread_mutex_lock(&gDSAppMutex); + gAppInitialized = true; + pthread_mutex_unlock(&gDSAppMutex); + + // Main interactive menu loop + int result = 0; + try { + showMainMenu(); + printf("\nApplication completed successfully\n"); + } catch (const std::exception& e) { + LOGE("Application exception: %s", e.what()); + result = -1; + } catch (...) { + LOGE("Unknown application exception"); + result = -1; + } + + // Cleanup before exit + cleanup_resources(); + + printf("\nDevice Settings Application exiting with code %d\n", result); + closelog(); + return result; +} + +// Initialize libds.so Device Settings library +void libds_Initialize() +{ + try { + LOGI("Initializing Device Settings Manager from libds.so..."); + + // Initialize the Device Settings Manager + // This will internally call dsFPInit() and other init functions from libdshalcli.so + device::Manager::Initialize(); + + LOGI("Device Settings Manager initialized successfully"); + } catch (const std::exception& e) { + LOGE("Failed to initialize Device Settings Manager: %s", e.what()); + throw; + } +} + +// Terminate libds.so Device Settings library +void libds_Terminate() +{ + try { + LOGI("Terminating Device Settings Manager from libds.so..."); + device::Manager::DeInitialize(); + LOGI("Device Settings Manager terminated successfully"); + } catch (const std::exception& e) { + LOGE("Error during Device Settings Manager termination: %s", e.what()); + } +} + +// Signal handler for graceful shutdown +static void signal_handler(int signum) { + const char* signal_name = "UNKNOWN"; + switch (signum) { + case SIGTERM: signal_name = "SIGTERM"; break; + case SIGINT: signal_name = "SIGINT"; break; + case SIGHUP: signal_name = "SIGHUP"; break; + case SIGUSR1: signal_name = "SIGUSR1"; break; + case SIGUSR2: signal_name = "SIGUSR2"; break; + } + + syslog(LOG_INFO, "[DSApp] Received signal %s (%d), initiating graceful shutdown", signal_name, signum); + + // Mark application as not initialized to trigger cleanup + pthread_mutex_lock(&gDSAppMutex); + gAppInitialized = false; + pthread_mutex_unlock(&gDSAppMutex); + + // Cleanup and exit + cleanup_resources(); + closelog(); + exit(0); +} + +int setup_signals() { + LOGI("Setting up signal handlers for RDK environment..."); + + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = signal_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + + // Handle common termination signals + if (sigaction(SIGTERM, &sa, nullptr) == -1) { + LOGE("Failed to set SIGTERM handler: %s", strerror(errno)); + return -1; + } + + if (sigaction(SIGINT, &sa, nullptr) == -1) { + LOGE("Failed to set SIGINT handler: %s", strerror(errno)); + return -1; + } + + if (sigaction(SIGHUP, &sa, nullptr) == -1) { + LOGE("Failed to set SIGHUP handler: %s", strerror(errno)); + return -1; + } + + // Handle user-defined signals for debugging + if (sigaction(SIGUSR1, &sa, nullptr) == -1) { + LOGE("Failed to set SIGUSR1 handler: %s", strerror(errno)); + return -1; + } + + if (sigaction(SIGUSR2, &sa, nullptr) == -1) { + LOGE("Failed to set SIGUSR2 handler: %s", strerror(errno)); + return -1; + } + + // Ignore SIGPIPE to handle broken pipe gracefully + signal(SIGPIPE, SIG_IGN); + + gSignalHandlersSet = true; + LOGI("Signal handlers configured successfully"); + return 0; +} + +int breakpad_ExceptionHandler() { + LOGI("Initializing crash reporting for RDK environment..."); + + // Set core dump parameters for RDK debugging + struct rlimit core_limit; + core_limit.rlim_cur = RLIM_INFINITY; + core_limit.rlim_max = RLIM_INFINITY; + + if (setrlimit(RLIMIT_CORE, &core_limit) != 0) { + LOGE("Failed to set core dump limit: %s", strerror(errno)); + } else { + LOGI("Core dump enabled for crash analysis"); + } + + // Set up crash dump directory (typical RDK location) + const char* crash_dir = "/opt/logs/crashes"; + if (access(crash_dir, W_OK) == 0) { + LOGI("Crash dumps will be written to: %s", crash_dir); + } else { + LOGD("Crash directory %s not accessible, using default location", crash_dir); + } + + // TODO: Initialize actual breakpad/crashpad when available + // For now, rely on system core dumps and signal handlers + + LOGI("Crash reporting initialization complete"); + return 0; +} + +// DeviceSettings_Init() is now implemented in device_settings.cpp + +// DeviceSettings_IsOperational() is now implemented in device_settings.cpp + +// DeviceSettings_Connect() is now implemented in device_settings.cpp + +void cleanup_resources() { + LOGI("Cleaning up application resources..."); + + // Mark application as shutting down + pthread_mutex_lock(&gDSAppMutex); + gAppInitialized = false; + pthread_mutex_unlock(&gDSAppMutex); + + // Clean up curl resources + if (mCurlShared) { + curl_share_cleanup(mCurlShared); + mCurlShared = nullptr; + LOGD("CURL shared handle cleaned up"); + } + + curl_global_cleanup(); + LOGD("CURL global cleanup completed"); + + // Free debug buffer + if (gDebugPrintBuffer) { + delete[] gDebugPrintBuffer; + gDebugPrintBuffer = nullptr; + LOGD("Debug buffer freed"); + } + + // Clean up RDK-specific resources + LOGD("Terminating libds.so Device Settings..."); + libds_Terminate(); // Call libds.so cleanup + + // TODO: Add IARM Bus cleanup if used + // IARM_Bus_Disconnect(); + // IARM_Bus_Term(); + + // Destroy mutexes + pthread_mutex_destroy(&gDSAppMutex); + pthread_mutex_destroy(&gCurlInitMutex); + LOGD("Mutexes destroyed"); + + LOGI("Resource cleanup complete"); +} + +// Menu system implementation +void clearScreen() { + printf("\033[2J\033[H"); // ANSI escape codes to clear screen +} + +int getUserChoice() { + int choice; + printf("\nEnter your choice: "); + if (scanf("%d", &choice) != 1) { + // Clear input buffer on invalid input + int c; + while ((c = getchar()) != '\n' && c != EOF); + return -1; + } + return choice; +} + +void showMainMenu() { + int choice; + + do { + clearScreen(); + printf("\n=== DeviceSettings Module Test Menu ===\n"); + printf("1. FPD (Front Panel Display)\n"); + printf("2. Audio Ports\n"); + printf("3. Video Ports\n"); + printf("4. HDMI Input\n"); + printf("5. Composite Input\n"); + printf("0. Exit\n"); + printf("========================================\n"); + + choice = getUserChoice(); + + switch (choice) { + case 1: + handleFPDModule(); + break; + case 2: + handleAudioPortsModule(); + break; + case 3: + handleVideoPortsModule(); + break; + case 4: + handleHDMIInModule(); + break; + case 5: + handleCompositeInModule(); + break; + case 0: + printf("\nExiting...\n"); + break; + default: + printf("\nInvalid choice! Please try again.\n"); + printf("Press Enter to continue..."); + getchar(); // consume newline + getchar(); // wait for Enter + break; + } + } while (choice != 0); +} + +void handleFPDModule() { + int choice; + + do { + clearScreen(); + printf("\n=== FPD (Front Panel Display) Module ===\n"); + printf("Using libds.so → libdshalcli.so → COM-RPC → DeviceSettings plugin\n"); + printf("1. GetFPDBrightness (Power LED)\n"); + printf("2. SetFPDBrightness (Power LED)\n"); + printf("3. GetFPDState (Power LED)\n"); + printf("4. SetFPDState (Power LED)\n"); + printf("5. GetFPDColor (Power LED)\n"); + printf("6. SetFPDColor (Power LED)\n"); + printf("7. Set Blink (Power LED)\n"); + printf("8. Test All Indicators\n"); + printf("0. Back to Main Menu\n"); + printf("=========================================\n"); + + choice = getUserChoice(); + + switch (choice) { + case 1: { + try { + printf("\nCalling libds.so FrontPanelIndicator::getBrightness()...\n"); + + // Get the Power LED indicator from libds.so + FrontPanelIndicator& powerLED = FrontPanelIndicator::getInstance(FrontPanelIndicator::kPower); + + // Get brightness - this will call dsGetFPDBrightness from libdshalcli.so + int brightness = powerLED.getBrightness(); + + printf("SUCCESS: Power LED Brightness: %d\n", brightness); + } catch (const std::exception& e) { + printf("ERROR: %s\n", e.what()); + } + printf("Press Enter to continue..."); + getchar(); getchar(); + break; + } + case 2: { + int brightness; + printf("\nEnter brightness level (0-100): "); + if (scanf("%d", &brightness) == 1) { + try { + printf("Calling libds.so FrontPanelIndicator::setBrightness(%d)...\n", brightness); + + // Get the Power LED indicator from libds.so + FrontPanelIndicator& powerLED = FrontPanelIndicator::getInstance(FrontPanelIndicator::kPower); + + // Set brightness - this will call dsSetFPDBrightness from libdshalcli.so + powerLED.setBrightness(brightness, true); + + printf("SUCCESS: Power LED brightness set to %d\n", brightness); + } catch (const std::exception& e) { + printf("ERROR: %s\n", e.what()); + } + } else { + printf("Invalid input!\n"); + } + printf("Press Enter to continue..."); + getchar(); getchar(); + break; + } + case 3: { + try { + printf("\nCalling libds.so FrontPanelIndicator::getState()...\n"); + + // Get the Power LED indicator from libds.so + FrontPanelIndicator& powerLED = FrontPanelIndicator::getInstance(FrontPanelIndicator::kPower); + + // Get state - this will call dsGetFPDState from libdshalcli.so + bool state = powerLED.getState(); + + printf("SUCCESS: Power LED State: %s\n", state ? "ON" : "OFF"); + } catch (const std::exception& e) { + printf("ERROR: %s\n", e.what()); + } + printf("Press Enter to continue..."); + getchar(); getchar(); + break; + } + case 4: { + int state; + printf("\nEnter FPD state (0=Off, 1=On): "); + if (scanf("%d", &state) == 1) { + try { + printf("Calling libds.so FrontPanelIndicator::setState(%d)...\n", state); + + // Get the Power LED indicator from libds.so + FrontPanelIndicator& powerLED = FrontPanelIndicator::getInstance(FrontPanelIndicator::kPower); + + // Set state - this will call dsSetFPDState from libdshalcli.so + powerLED.setState(state != 0); + + printf("SUCCESS: Power LED state set to %s\n", state ? "ON" : "OFF"); + } catch (const std::exception& e) { + printf("ERROR: %s\n", e.what()); + } + } else { + printf("Invalid input!\n"); + } + printf("Press Enter to continue..."); + getchar(); getchar(); + break; + } + case 5: { + try { + printf("\nCalling libds.so FrontPanelIndicator::getColor()...\n"); + + // Get the Power LED indicator from libds.so + FrontPanelIndicator& powerLED = FrontPanelIndicator::getInstance(FrontPanelIndicator::kPower); + + // Get color - this will call dsGetFPColor from libdshalcli.so + uint32_t color = powerLED.getColor(); + + printf("SUCCESS: Power LED Color: 0x%08X\n", color); + } catch (const std::exception& e) { + printf("ERROR: %s\n", e.what()); + } + printf("Press Enter to continue..."); + getchar(); getchar(); + break; + } + case 6: { + unsigned int color; + printf("\nEnter FPD color (hex, e.g., 0xFF0000 for red): 0x"); + if (scanf("%x", &color) == 1) { + try { + printf("Calling libds.so FrontPanelIndicator::setColor(0x%08X)...\n", color); + + // Get the Power LED indicator from libds.so + FrontPanelIndicator& powerLED = FrontPanelIndicator::getInstance(FrontPanelIndicator::kPower); + + // Set color - this will call dsSetFPDColor from libdshalcli.so + powerLED.setColor(color, true); + + printf("SUCCESS: Power LED color set to 0x%08X\n", color); + } catch (const std::exception& e) { + printf("ERROR: %s\n", e.what()); + } + } else { + printf("Invalid input!\n"); + } + printf("Press Enter to continue..."); + getchar(); getchar(); + break; + } + case 7: { + int interval, iterations; + printf("\nEnter blink interval (ms): "); + if (scanf("%d", &interval) != 1) { + printf("Invalid input!\n"); + printf("Press Enter to continue..."); + getchar(); getchar(); + break; + } + printf("Enter blink iterations: "); + if (scanf("%d", &iterations) == 1) { + try { + printf("Calling libds.so FrontPanelIndicator::setBlink(%d, %d)...\n", interval, iterations); + + // Get the Power LED indicator from libds.so + FrontPanelIndicator& powerLED = FrontPanelIndicator::getInstance(FrontPanelIndicator::kPower); + + // Set blink - this will call dsSetFPBlink from libdshalcli.so + FrontPanelIndicator::Blink blink(interval, iterations); + powerLED.setBlink(blink); + + printf("SUCCESS: Power LED blink set (interval=%d ms, iterations=%d)\n", interval, iterations); + } catch (const std::exception& e) { + printf("ERROR: %s\n", e.what()); + } + } else { + printf("Invalid input!\n"); + } + printf("Press Enter to continue..."); + getchar(); getchar(); + break; + } + case 8: { + printf("\nTesting all FPD indicators...\n"); + try { + const char* indicatorNames[] = {"Message", "Power", "Record", "Remote", "RFBypass"}; + int indicatorIds[] = { + FrontPanelIndicator::kMessage, + FrontPanelIndicator::kPower, + FrontPanelIndicator::kRecord, + FrontPanelIndicator::kRemote, + FrontPanelIndicator::kRFBypass + }; + + for (int i = 0; i < 5; i++) { + try { + FrontPanelIndicator& indicator = FrontPanelIndicator::getInstance(indicatorIds[i]); + int brightness = indicator.getBrightness(); + bool state = indicator.getState(); + printf(" %s LED: Brightness=%d, State=%s\n", + indicatorNames[i], brightness, state ? "ON" : "OFF"); + } catch (const std::exception& e) { + printf(" %s LED: ERROR - %s\n", indicatorNames[i], e.what()); + } + } + printf("Test completed!\n"); + } catch (const std::exception& e) { + printf("ERROR: %s\n", e.what()); + } + printf("Press Enter to continue..."); + getchar(); getchar(); + break; + } + case 0: + printf("\nReturning to main menu...\n"); + break; + default: + printf("\nInvalid choice! Please try again.\n"); + printf("Press Enter to continue..."); + getchar(); getchar(); + break; + } + } while (choice != 0); +} + +void handleAudioPortsModule() { + int choice; + + do { + clearScreen(); + printf("\n=== Audio Ports Module ===\n"); + printf("1. DeviceSettings_GetAudioPort\n"); + printf("2. DeviceSettings_SetAudioPort\n"); + printf("3. DeviceSettings_GetAudioFormat\n"); + printf("4. DeviceSettings_SetAudioFormat\n"); + printf("5. DeviceSettings_GetAudioCompression\n"); + printf("6. DeviceSettings_SetAudioCompression\n"); + printf("7. DeviceSettings_GetDialogEnhancement\n"); + printf("8. DeviceSettings_SetDialogEnhancement\n"); + printf("9. DeviceSettings_GetDolbyVolumeMode\n"); + printf("10. DeviceSettings_SetDolbyVolumeMode\n"); + printf("0. Back to Main Menu\n"); + printf("===============================\n"); + + choice = getUserChoice(); + + switch (choice) { + case 1: + printf("\nCalling DeviceSettings_GetAudioPort()...\n"); + // TODO: Add actual function call + printf("Function called successfully!\n"); + printf("Press Enter to continue..."); + getchar(); getchar(); + break; + case 2: + printf("\nCalling DeviceSettings_SetAudioPort()...\n"); + // TODO: Add actual function call + printf("Function called successfully!\n"); + printf("Press Enter to continue..."); + getchar(); getchar(); + break; + // Add more cases as needed + case 0: + printf("\nReturning to main menu...\n"); + break; + default: + printf("\nInvalid choice! Please try again.\n"); + printf("Press Enter to continue..."); + getchar(); getchar(); + break; + } + } while (choice != 0); +} + +void handleVideoPortsModule() { + int choice; + + do { + clearScreen(); + printf("\n=== Video Ports Module ===\n"); + printf("1. DeviceSettings_GetVideoPort\n"); + printf("2. DeviceSettings_SetVideoPort\n"); + printf("3. DeviceSettings_GetVideoFormat\n"); + printf("4. DeviceSettings_SetVideoFormat\n"); + printf("5. DeviceSettings_GetVideoResolution\n"); + printf("6. DeviceSettings_SetVideoResolution\n"); + printf("7. DeviceSettings_GetVideoFrameRate\n"); + printf("8. DeviceSettings_SetVideoFrameRate\n"); + printf("0. Back to Main Menu\n"); + printf("===============================\n"); + + choice = getUserChoice(); + + switch (choice) { + case 1: + printf("\nCalling DeviceSettings_GetVideoPort()...\n"); + // TODO: Add actual function call + printf("Function called successfully!\n"); + printf("Press Enter to continue..."); + getchar(); getchar(); + break; + // Add more cases as needed + case 0: + printf("\nReturning to main menu...\n"); + break; + default: + printf("\nInvalid choice! Please try again.\n"); + printf("Press Enter to continue..."); + getchar(); getchar(); + break; + } + } while (choice != 0); +} + +void handleHDMIInModule() { + int choice; + + do { + clearScreen(); + printf("\n=== HDMI Input Module ===\n"); + printf("1. DeviceSettings_GetHDMIInput\n"); + printf("2. DeviceSettings_SetHDMIInput\n"); + printf("3. DeviceSettings_GetHDMIInputStatus\n"); + printf("4. DeviceSettings_GetHDMIInputSignalStatus\n"); + printf("0. Back to Main Menu\n"); + printf("==========================\n"); + + choice = getUserChoice(); + + switch (choice) { + case 1: + printf("\nCalling DeviceSettings_GetHDMIInput()...\n"); + // TODO: Add actual function call + printf("Function called successfully!\n"); + printf("Press Enter to continue..."); + getchar(); getchar(); + break; + // Add more cases as needed + case 0: + printf("\nReturning to main menu...\n"); + break; + default: + printf("\nInvalid choice! Please try again.\n"); + printf("Press Enter to continue..."); + getchar(); getchar(); + break; + } + } while (choice != 0); +} + +void handleCompositeInModule() { + int choice; + + do { + clearScreen(); + printf("\n=== Composite Input Module ===\n"); + printf("1. DeviceSettings_GetCompositeInput\n"); + printf("2. DeviceSettings_SetCompositeInput\n"); + printf("3. DeviceSettings_GetCompositeInputStatus\n"); + printf("0. Back to Main Menu\n"); + printf("===============================\n"); + + choice = getUserChoice(); + + switch (choice) { + case 1: + printf("\nCalling DeviceSettings_GetCompositeInput()...\n"); + // TODO: Add actual function call + printf("Function called successfully!\n"); + printf("Press Enter to continue..."); + getchar(); getchar(); + break; + // Add more cases as needed + case 0: + printf("\nReturning to main menu...\n"); + break; + default: + printf("\nInvalid choice! Please try again.\n"); + printf("Press Enter to continue..."); + getchar(); getchar(); + break; + } + } while (choice != 0); +} \ No newline at end of file diff --git a/sample/Makefile b/sample/Makefile index 80b1a2dc..934d3dff 100644 --- a/sample/Makefile +++ b/sample/Makefile @@ -45,12 +45,13 @@ CFLAGS += -g -fPIC -D_REENTRANT -Wall $(INCLUDE) .PHONY: $(OUTPUT) -BINARIES := $(patsubst %.cpp,%,$(wildcard *.cpp)) +# Exclude DSCliLibStandaloneApp.cpp from the automatic build pattern +BINARIES := $(patsubst %.cpp,%,$(filter-out DSCliLibStandaloneApp.cpp,$(wildcard *.cpp))) UNINSTALL := $(patsubst %,$(PWD)/install/bin/%, $(BINARIES)) #all: $(BINARIES) install -all: $(BINARIES) - @echo "Build Finished...." +all: $(BINARIES) dsapp + @echo "Build Finished (including DSApp)...." #frontPanelTest: $(BINARIES): @@ -61,6 +62,10 @@ $(BINARIES): install: @echo "Copying the binaries to bin install folder..." @cp $(BINARIES) $(INSTALL)/bin + @if [ -f ../DSApp ]; then \ + echo "Installing DSApp to $(INSTALL)/bin/..."; \ + cp ../DSApp $(INSTALL)/bin/; \ + fi uninstall: @echo "Removing bin from install folder..." @@ -69,6 +74,23 @@ uninstall: clean: @echo "Cleaning the directory..." @$(RM) $(BINARIES) + @$(RM) DSApp + +# DSApp - Device Settings Test Application +.PHONY: dsapp dsapp-clean + +dsapp: + @if [ -f DSCliLibStandaloneApp.cpp ]; then \ + echo "Building DSApp..."; \ + $(CXX) $(CFLAGS) -std=c++11 DSCliLibStandaloneApp.cpp -o ../DSApp -L$(INSTALL)/lib -lds -ldshalcli -lcurl -lpthread $(LDFLAGS); \ + echo "DSApp built successfully at devicesettings/DSApp"; \ + else \ + echo "DSCliLibStandaloneApp.cpp not found, skipping DSApp build"; \ + fi + +dsapp-clean: + @echo "Cleaning DSApp..." + @$(RM) ../DSApp