Skip to content

Comments

Thunder team review#212

Open
ManimaranRenganathan wants to merge 23 commits intodevelopfrom
Thunder-Team-Review
Open

Thunder team review#212
ManimaranRenganathan wants to merge 23 commits intodevelopfrom
Thunder-Team-Review

Conversation

@ManimaranRenganathan
Copy link

No description provided.

@ManimaranRenganathan ManimaranRenganathan requested a review from a team as a code owner February 5, 2026 13:00
Copilot AI review requested due to automatic review settings February 5, 2026 13:00
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request introduces Thunder COM-RPC support for the Front Panel Display (FPD) functionality as an alternative to the existing IARM-based implementation. The PR enables conditional compilation to support both communication frameworks.

Changes:

  • Adds new dsFPD-com.cpp implementation using Thunder COM-RPC framework
  • Implements conditional compilation in build system (Makefile, Makefile.am, configure.ac) to select between IARM and Thunder modes
  • Adds Thunder library dependencies when Thunder plugin support is enabled

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
rpc/cli/dsFPD-com.cpp New Thunder COM-RPC implementation for FPD client, providing C API wrappers around Thunder interface
rpc/cli/Makefile.am Conditional source file selection and Thunder library linking based on configuration flag
rpc/cli/Makefile Conditional object file compilation and library linking for Thunder vs IARM modes
configure.ac Adds --enable-thunder-plugin configuration option with USE_WPE_THUNDER_PLUGIN define
cov_build.sh Exports USE_WPE_THUNDER_PLUGIN environment variable for coverage builds

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +36 to +37
#OBJS := $(patsubst %.cpp,%.o,$(wildcard *.cpp))
#OBJS += $(patsubst %.c,%.o,$(wildcard *.c))
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These commented-out lines should be removed rather than kept in the codebase. The version control system preserves the history, so keeping commented code creates clutter and confusion about what the intended implementation should be.

Suggested change
#OBJS := $(patsubst %.cpp,%.o,$(wildcard *.cpp))
#OBJS += $(patsubst %.c,%.o,$(wildcard *.c))

Copilot uses AI. Check for mistakes.
Comment on lines 66 to 79
bool _shutdown;

DeviceSettingsFPD()
: BaseClass()
, _fpdInterface(nullptr)
, _connected(false)
, _shutdown(false)
{
(void)Connect();
}

~DeviceSettingsFPD()
{
_shutdown = true;
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The _shutdown member variable is initialized and set to true in the destructor, but it's never actually used anywhere in the code. Consider removing this unused member variable to reduce code clutter.

Suggested change
bool _shutdown;
DeviceSettingsFPD()
: BaseClass()
, _fpdInterface(nullptr)
, _connected(false)
, _shutdown(false)
{
(void)Connect();
}
~DeviceSettingsFPD()
{
_shutdown = true;
DeviceSettingsFPD()
: BaseClass()
, _fpdInterface(nullptr)
, _connected(false)
{
(void)Connect();
}
~DeviceSettingsFPD()
{

Copilot uses AI. Check for mistakes.
return (nullptr != _fpdInterface);
}

inline bool isConnected() const
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method name "isConnected" uses camelCase, which is inconsistent with the PascalCase naming convention used by other methods in this class like "IsOperational" and "IsActivatedLocked". For consistency with the class's public interface, this should be renamed to "IsConnected".

Copilot uses AI. Check for mistakes.
Comment on lines 107 to 111
inline bool IsActivatedLocked() const
{
return (nullptr != _fpdInterface);
}

Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method "IsActivatedLocked" is defined but never called anywhere in the code. Consider removing this unused method to reduce code clutter, or if it's intended for future use, add a comment explaining its purpose.

Suggested change
inline bool IsActivatedLocked() const
{
return (nullptr != _fpdInterface);
}

Copilot uses AI. Check for mistakes.

static DeviceSettingsFPD* Instance()
{
return _instance;
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The static Instance method is not thread-safe. It returns the _instance pointer without any locking, which could lead to a race condition if called concurrently with Init or Term methods. The caller could receive a partially initialized pointer or a pointer that's being deleted. Consider acquiring _apiLock before returning the instance, or better yet, ensure callers use Init/Instance pattern within locked sections.

Suggested change
return _instance;
_apiLock.Lock();
DeviceSettingsFPD* instance = _instance;
_apiLock.Unlock();
return instance;

Copilot uses AI. Check for mistakes.
Comment on lines 483 to 485
// 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);
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parameters are being incorrectly mapped. The Thunder interface expects "minutes" and "seconds" as parameters (line 217-218), but the C API provides "uHour" and "uMinutes". Currently, uHour is passed as the minutes parameter and uMinutes is passed as the seconds parameter, which will cause incorrect time values to be set. The correct mapping should convert hours and minutes to the appropriate format expected by the Thunder interface, or there's a mismatch in the interface definition that needs to be addressed.

Suggested change
// 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);
// Note: Interface expects minutes and seconds, but API provides hour and minutes.
// Convert hours and minutes to total minutes, and use 0 seconds (no second-level precision in API).
const uint32_t totalMinutes = (uHour * 60u) + (uMinutes % 60u);
const uint32_t seconds = 0u;
uint32_t result = instance->SetFPDTime(timeFormat, totalMinutes, seconds);

Copilot uses AI. Check for mistakes.

dsError_t dsSetFPDBrightness(dsFPDIndicator_t eIndicator, dsFPDBrightness_t eBrightness, bool toPersist)
{
if (eIndicator >= dsFPD_INDICATOR_MAX || eBrightness > 100) {
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The validation check for brightness should use a comparison with dsFPDBrightness_t enum max value or a defined constant instead of hardcoding "100". This makes the code more maintainable and ensures consistency if the brightness range changes. Consider defining a constant like MAX_BRIGHTNESS or using the enum's maximum value.

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings February 9, 2026 02:43
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 12 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

clean:
@echo "Cleaning the directory..."
@$(RM) $(BINARIES)
@$(RM) DSApp
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clean removes DSApp in the sample directory, but the dsapp target builds the executable to ../DSApp. This leaves the built artifact behind after make clean. Update clean to remove ../DSApp (or invoke dsapp-clean) so cleanup is consistent with the build output path.

Suggested change
@$(RM) DSApp
@$(RM) ../DSApp

Copilot uses AI. Check for mistakes.
sample/Makefile Outdated
Comment on lines 85 to 87
$(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 \
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The success message says DSApp is built at devicesettings/DSApp, but the command outputs to ../DSApp. Please update the message to reflect the real output location (ideally derived from variables) so users aren’t misled when running the target from different directories.

Copilot uses AI. Check for mistakes.
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();
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On curl_global_init failure, the code calls cleanup_resources(), which unconditionally calls curl_global_cleanup(). libcurl documents curl_global_cleanup() should only be called after a successful curl_global_init(), otherwise behavior can be undefined. Track whether curl was initialized successfully and only call global cleanup when appropriate (or avoid calling cleanup_resources() on this failure path).

Suggested change
cleanup_resources();
// Avoid calling cleanup_resources() here because curl was not initialized
// and cleanup_resources() may call curl_global_cleanup(), which would be undefined.
if (gDebugPrintBuffer) {
delete[] gDebugPrintBuffer;
gDebugPrintBuffer = nullptr;
}
closelog();

Copilot uses AI. Check for mistakes.
Comment on lines +118 to +119
libds_Initialize();
printf("libds.so initialized successfully!\n");
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

libds_Initialize() can throw, but it’s called before the try/catch that wraps showMainMenu(). If initialization fails, the exception will escape main() and skip cleanup/logging. Wrap libds_Initialize() in a try/catch in main (and ensure any partially initialized resources are cleaned up) to make startup failures graceful.

Suggested change
libds_Initialize();
printf("libds.so initialized successfully!\n");
try {
libds_Initialize();
printf("libds.so initialized successfully!\n");
} catch (const std::exception& e) {
LOGE("Failed to initialize libds.so: %s", e.what());
cleanup_resources();
return -1;
} catch (...) {
LOGE("Failed to initialize libds.so: unknown exception");
cleanup_resources();
return -1;
}

Copilot uses AI. Check for mistakes.
Comment on lines 32 to 42
# 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)
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When USE_THUNDER_PLUGIN is enabled, dsFPD-com.cpp is compiled, but there’s no corresponding -DUSE_WPE_THUNDER_PLUGIN added to CPPFLAGS/CXXFLAGS. Because the file is wrapped in #ifdef USE_WPE_THUNDER_PLUGIN, this can result in an empty translation unit and missing dsFPD* symbols at link time. Add the define to the build flags under the conditional (or remove the #ifdef wrapper).

Copilot uses AI. Check for mistakes.
Comment on lines +27 to +33
#ifdef USE_WPE_THUNDER_PLUGIN

#include <stdio.h>
#include <string.h>
#include <chrono>
#include <thread>

Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The entire file is wrapped in #ifdef USE_WPE_THUNDER_PLUGIN, but the build toggles for Thunder mode in this PR are primarily make-conditionals (USE_THUNDER_PLUGIN / USE_WPE_THUNDER_PLUGIN make var). If the preprocessor macro isn’t defined, this will compile to an empty object and the library will miss required C API symbols. Either remove this #ifdef (and rely on conditional source selection), or ensure the macro is always defined when compiling this file.

Copilot uses AI. Check for mistakes.
Comment on lines +176 to +198
// 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);
}
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The signal handler calls non-async-signal-safe functions (syslog, pthread_mutex_lock, cleanup_resources, closelog, exit). This can deadlock or crash if the signal interrupts code holding locks or inside libc. Prefer setting an atomic/volatile shutdown flag (or writing to a self-pipe) and letting the main loop perform cleanup outside the signal context.

Copilot uses AI. Check for mistakes.
Comment on lines 25 to 34
# 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
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This Makefile switches object selection based on the make variable USE_WPE_THUNDER_PLUGIN, but it never defines the C/C++ preprocessor macro USE_WPE_THUNDER_PLUGIN. Since dsFPD-com.cpp is guarded by #ifdef USE_WPE_THUNDER_PLUGIN, enabling the make variable will compile an object with no symbols and likely break linking (because dsFPD.c is filtered out). Ensure the macro is passed in compiler flags when Thunder mode is enabled (or remove the #ifdef guard and rely solely on source selection).

Copilot uses AI. Check for mistakes.
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])
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AC_DEFINE([USE_WPE_THUNDER_PLUGIN], ...) places the macro in cfg/config.h, but none of the rpc/cli sources include that header, and the Makefiles don’t -include it either (verified by searching for config.h). As a result, --enable-thunder-plugin may not actually enable the #ifdef USE_WPE_THUNDER_PLUGIN code. Ensure cfg/config.h is included in compilation (e.g., add -include $(top_builddir)/cfg/config.h or explicitly add -DUSE_WPE_THUNDER_PLUGIN when the option is enabled).

Suggested change
[AC_DEFINE([USE_WPE_THUNDER_PLUGIN], [1], [Define to 1 to enable Thunder COM-RPC plugin support])
[AC_DEFINE([USE_WPE_THUNDER_PLUGIN], [1], [Define to 1 to enable Thunder COM-RPC plugin support])
CPPFLAGS="$CPPFLAGS -DUSE_WPE_THUNDER_PLUGIN"

Copilot uses AI. Check for mistakes.
#include <signal.h>
#include <curl/curl.h>
#include <iostream>
#include <cstdint>
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file uses printf/scanf/getchar and std::nothrow, but it doesn’t include the headers that declare them (<cstdio>/<stdio.h> and <new> respectively). Depending on the toolchain and included headers, this can fail to compile or rely on non-portable transitive includes. Add the appropriate standard headers explicitly.

Suggested change
#include <cstdint>
#include <cstdint>
#include <cstdio> // For printf and related C I/O functions
#include <new> // For std::nothrow

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings February 9, 2026 11:22
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.

Comments suppressed due to low confidence (1)

cov_build.sh:76

  • cov_build.sh sets USE_WPE_THUNDER_PLUGIN=y, which triggers the non-autotools Makefiles to select Thunder sources and link -lWPEFrameworkCore/-lWPEFrameworkCOM, but the script does not add -DUSE_WPE_THUNDER_PLUGIN to CFLAGS (needed by #ifdef USE_WPE_THUNDER_PLUGIN), nor does it ensure the Thunder libs/headers are available in this Coverity build environment. This will likely either compile out the implementation or fail at link time. Pass the macro via CFLAGS (or remove the guard) and add the required include/lib paths (or stubs) for the Thunder libraries.
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"


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@echo "Copying the binaries to bin install folder..."
@cp $(BINARIES) $(INSTALL)/bin
@if [ -n "$(BINARIES)" ]; then \
@cp $(BINARIES) $(INSTALL)/bin
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The install recipe’s shell if block is malformed: the cp line is missing a trailing ; \ and it is prefixed with @, which will be passed to the shell as part of the command (likely causing @cp: not found). This will break make install when BINARIES is non-empty. Remove the @ inside the shell block and ensure each continued line is properly terminated (e.g., cp ...; \).

Suggested change
@cp $(BINARIES) $(INSTALL)/bin
cp $(BINARIES) $(INSTALL)/bin; \

Copilot uses AI. Check for mistakes.
* @{
**/

#ifdef USE_WPE_THUNDER_PLUGIN
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is fully wrapped in #ifdef USE_WPE_THUNDER_PLUGIN, but the non-autotools build (rpc/cli/Makefile) enables Thunder mode via a make variable and does not add -DUSE_WPE_THUNDER_PLUGIN to compilation flags. That combination will compile this translation unit as effectively empty and omit all dsFPD symbols at runtime. Either remove the #ifdef wrapper and rely on the build system selecting the correct source file, or ensure the build defines USE_WPE_THUNDER_PLUGIN when Thunder mode is enabled.

Suggested change
#ifdef USE_WPE_THUNDER_PLUGIN
#if 1 // Previously `#ifdef USE_WPE_THUNDER_PLUGIN`; now always compiled when this file is built.

Copilot uses AI. Check for mistakes.
Comment on lines +62 to +63
[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])],
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--enable-thunder-plugin toggles compilation/linking against WPEFramework (Core/COM), but configure.ac does not validate that the required headers and libraries are present (no PKG_CHECK_MODULES / AC_CHECK_HEADERS / AC_CHECK_LIB for Thunder). Enabling this option will likely fail later during compilation/linking with a less actionable error. Add explicit checks and surface a clear configure-time failure or disable the option when dependencies are missing.

Suggested change
[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])],
[PKG_CHECK_MODULES([THUNDER], [WPEFrameworkCore WPEFrameworkCOM],
[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_ERROR([Thunder COM-RPC plugin support requested, but WPEFramework Core/COM (pkg-config modules WPEFrameworkCore and WPEFrameworkCOM) were not found. Install the appropriate development packages or re-run configure without --enable-thunder-plugin.])])],

Copilot uses AI. Check for mistakes.
all: $(BINARIES)
@echo "Build Finished...."
all: $(BINARIES) dsapp
@echo "Build Finished and Installed (including DSApp) ..."
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The all target prints "Build Finished and Installed ..." but it does not invoke the install target (it only builds binaries + dsapp). This message is misleading and makes it hard to tell whether anything was actually installed.

Suggested change
@echo "Build Finished and Installed (including DSApp) ..."
@echo "Build finished (binaries and DSApp built). Run 'make install' to install ..."

Copilot uses AI. Check for mistakes.
Comment on lines 192 to 196
_apiLock.Lock();
if (nullptr == _instance) {
_instance = new DeviceSettingsFPD();
}
_apiLock.Unlock();
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DeviceSettingsFPD::Init() takes _apiLock and then constructs DeviceSettingsFPD, whose constructor immediately calls Connect(), which tries to take _apiLock again. Since Core::CriticalSection is not recursive, this can deadlock on initialization. Construct the singleton without holding _apiLock, or remove Connect() from the constructor and call it after releasing the lock.

Suggested change
_apiLock.Lock();
if (nullptr == _instance) {
_instance = new DeviceSettingsFPD();
}
_apiLock.Unlock();
// Fast path: if already initialized, avoid any locking.
if (_instance != nullptr) {
return;
}
// Construct outside the lock to avoid potential deadlock if the
// constructor calls methods that take _apiLock (e.g., Connect()).
DeviceSettingsFPD* newInstance = new DeviceSettingsFPD();
_apiLock.Lock();
// Another thread may have initialized _instance while we were
// constructing newInstance; only assign if it's still null.
if (_instance == nullptr) {
_instance = newInstance;
newInstance = nullptr;
}
_apiLock.Unlock();
// If we lost the race, clean up the extra instance.
if (newInstance != nullptr) {
delete newInstance;
}

Copilot uses AI. Check for mistakes.
Manimaran Renganathan added 2 commits February 9, 2026 14:06
	device::Manager::Initialize();

and init FPD only
Copilot AI review requested due to automatic review settings February 9, 2026 15:55
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 91 to 96
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 \
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dsapp builds the output as ../DSApp, which writes outside the sample/ directory. This is fragile for out-of-tree builds and conflicts with the top-level Makefile.am messaging that suggests $(abs_top_builddir)/DSApp. Prefer writing the artifact into the build dir (e.g., $(top_builddir)/$(abs_top_builddir)) and using that same path in install/copy logic.

Copilot uses AI. Check for mistakes.
Comment on lines +189 to +211
// 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);
}
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

signal_handler calls non-async-signal-safe functions (syslog, pthread_mutex_lock/unlock, cleanup_resources, closelog, exit). This is undefined behavior and can deadlock/crash if the signal interrupts those same functions. Prefer setting a volatile sig_atomic_t shutdown flag (or writing to a self-pipe) and handling cleanup/exit in the main loop/context instead of inside the handler.

Copilot uses AI. Check for mistakes.
Comment on lines 25 to 34
# 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
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Makefile ifdef USE_WPE_THUNDER_PLUGIN is used to pick Thunder objects, but it does not add -DUSE_WPE_THUNDER_PLUGIN to the compiler flags. Because dsFPD-com.cpp is wrapped in #ifdef USE_WPE_THUNDER_PLUGIN, compiling it without the macro will omit all implementations and cause link errors. Ensure the macro is passed via CFLAGS/CPPFLAGS in this branch (or remove the source-level guard).

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +14
#include <unistd.h>
#include <pthread.h>
#include <sched.h>
#include <cstdlib>
#include <cstring>
#include <signal.h>
#include <curl/curl.h>
#include <iostream>
#include <cstdint>
#include <sys/time.h>
#include <errno.h>
#include <syslog.h>
#include <sys/resource.h>

Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file uses printf/scanf extensively and std::nothrow, but it doesn’t include headers that guarantee those declarations in C++ (<cstdio>/<stdio.h> for printf/scanf, <new> for std::nothrow). This can fail to compile on stricter toolchains. Add the required standard headers explicitly.

Copilot uses AI. Check for mistakes.
dsapp:
@echo "Building DSApp..."
$(MAKE) -C sample dsapp
@echo "DSApp executable: $(abs_top_builddir)/DSApp"
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This target prints DSApp executable: $(abs_top_builddir)/DSApp, but the underlying sample/Makefile currently builds DSApp to ../DSApp relative to sample/, which won’t match $(abs_top_builddir) in out-of-tree builds. Align the build output path and the reported path (ideally output into $(abs_top_builddir)/$(top_builddir)).

Suggested change
@echo "DSApp executable: $(abs_top_builddir)/DSApp"
@echo "DSApp executable: $(top_builddir)/DSApp"

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings February 16, 2026 12:07
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 7 comments.

Comments suppressed due to low confidence (1)

sample/Makefile:82

  • install copies ../DSApp into $(INSTALL)/bin, but uninstall only removes $(UNINSTALL) (the sample binaries) and leaves DSApp behind. Add removal of $(INSTALL)/bin/DSApp for symmetry so uninstall fully reverts install.
uninstall:
	@echo "Removing bin from install folder..."
	@$(RM) $(UNINSTALL)


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +292 to +328
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");
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cleanup_resources() destroys global mutexes (pthread_mutex_destroy) even though it can be invoked multiple times (normal exit path and also from the signal handler). Double-destroy is undefined behavior; also destroying a mutex while another thread might still use it is unsafe. Make cleanup idempotent (guard with a once-flag) and avoid destroying process-lifetime mutexes (or only destroy them at a single well-defined point).

Copilot uses AI. Check for mistakes.
export STANDALONE_BUILD_ENABLED=y
export DS_MGRS=$WORKDIR

export USE_WPE_THUNDER_PLUGIN=y
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This script enables USE_WPE_THUNDER_PLUGIN, which changes rpc/cli/Makefile to link against -lWPEFrameworkCore -lWPEFrameworkCOM, but the script doesn’t build/install stubs for those libraries (it only stubs libWPEFrameworkPowerController.so). Unless those libs are guaranteed to exist in the build environment, this will break the Coverity build. Either keep Thunder disabled here by default or add the required dependency setup for the Thunder libraries.

Suggested change
export USE_WPE_THUNDER_PLUGIN=y
# Thunder/WPEFramework plugin is disabled by default for Coverity builds to
# avoid introducing unresolved link-time dependencies on WPEFrameworkCore/COM.
# It can still be enabled explicitly by exporting USE_WPE_THUNDER_PLUGIN=y
# before invoking this script, in environments where the libraries are present.
export USE_WPE_THUNDER_PLUGIN=${USE_WPE_THUNDER_PLUGIN-n}

Copilot uses AI. Check for mistakes.
@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"; \
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The success message says DSApp is built at devicesettings/DSApp, but the command outputs to ../DSApp. This can confuse users trying to locate the binary; update the message (or change the output path) so they match.

Suggested change
echo "DSApp built successfully at devicesettings/DSApp"; \
echo "DSApp built successfully at ../DSApp"; \

Copilot uses AI. Check for mistakes.
Comment on lines 461 to 466
/* // 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;
}
*/
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This new Thunder COM-RPC implementation introduces a large alternate code path for the FPD client, but the existing test suite doesn’t appear to exercise Thunder mode (no tests reference USE_WPE_THUNDER_PLUGIN). Consider adding at least a minimal test (even if guarded/optional) that validates the Thunder client wiring and basic error mapping, so regressions in the COM-RPC path are caught.

Suggested change
/* // 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;
}
*/
// 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;
}

Copilot uses AI. Check for mistakes.
Comment on lines 507 to 509
// 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);
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dsSetFPTime() receives uHour and uMinutes, but forwards them to SetFPDTime(timeFormat, minutes, seconds) as (uHour, uMinutes). This effectively treats hours as minutes and minutes as seconds, producing an incorrect time value. Convert the inputs properly (e.g., minutes = uHour * 60 + uMinutes; seconds = 0) or adjust the mapping to match the Thunder interface semantics.

Suggested change
// 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);
// Interface expects minutes and seconds, but API provides hours and minutes.
// Convert to total minutes and set seconds to 0 for Thunder interface.
uint32_t totalMinutes = (uHour * 60U) + uMinutes;
uint32_t seconds = 0U;
uint32_t result = instance->SetFPDTime(timeFormat, totalMinutes, seconds);

Copilot uses AI. Check for mistakes.
Comment on lines +48 to +49
LDLIBS := -lWPEFrameworkCore -lWPEFrameworkCOM
else
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Thunder mode, LDLIBS drops -lIARMBus, but most other rpc/cli sources (e.g., dsAudio.c, dsDisplay.c, dsHost.cpp, dsVideo*.c) still call IARM_Bus_Call and require IARMBus symbols. This will either fail to link or produce a lib with unresolved dependencies. Keep -lIARMBus in Thunder mode as well (and add Thunder libs on top), or conditionally exclude/replace the other IARM-based sources too.

Suggested change
LDLIBS := -lWPEFrameworkCore -lWPEFrameworkCOM
else
# Thunder mode: still need IARMBus symbols plus Thunder libraries
LDLIBS := -lIARMBus -lWPEFrameworkCore -lWPEFrameworkCOM
else
# IARM-only mode

Copilot uses AI. Check for mistakes.
Comment on lines +149 to +187
// 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(); As of now FPD only communicate through COM-RPC

LOGI("Initializing Front Panel from libds.so...");
LOGI("Front panel init");
fpIndicators = device::FrontPanelConfig::getInstance().getIndicators();

for (size_t i = 0; i < fpIndicators.size(); i++) {
std::string IndicatorName = fpIndicators.at(i).getName();
LOGI("Initializing Front Panel Indicator: %s", IndicatorName.c_str());
}

LOGI("Device Settings FPD initialized successfully");

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());
}
}
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

libds_Initialize() does not call device::Manager::Initialize() (it’s commented out), but libds_Terminate() unconditionally calls device::Manager::DeInitialize(). This init/term mismatch can lead to undefined behavior depending on libds implementation. Either initialize the manager here or make terminate conditional on successful initialize.

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings February 17, 2026 07:44
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 11 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 87 to 121
virtual void Operational(const bool upAndRunning) override
{
_apiLock.Lock();

if (upAndRunning) {
// Communicator opened && DeviceSettings is Activated
if (nullptr == _deviceSettings) {
_deviceSettings = BaseClass::Interface();
if (_deviceSettings != nullptr) {
printf("[dsFPD-com] Successfully obtained IDeviceSettings interface [%p] \n", _deviceSettings);

// Now QueryInterface to get IDeviceSettingsFPD from the aggregated implementation
_fpdInterface = _deviceSettings->QueryInterface<Exchange::IDeviceSettingsFPD>();
if (_fpdInterface != nullptr) {
printf("[dsFPD-com] Successfully established COM-RPC connection with DeviceSettings FPD interface [%p]\n", _fpdInterface);
} else {
fprintf(stderr, "[dsFPD-com] Failed to get IDeviceSettingsFPD interface - plugin implementation may have failed to load\n");
}
} else {
fprintf(stderr, "[dsFPD-com] Failed to get IDeviceSettings interface - plugin may not be activated\n");
}
}
} else {
// DeviceSettings is Deactivated || Communicator closed
if (nullptr != _fpdInterface) {
_fpdInterface->Release();
_fpdInterface = nullptr;
}
if (nullptr != _deviceSettings) {
_deviceSettings->Release();
_deviceSettings = nullptr;
}
}
_apiLock.Unlock();
}
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Operational callback does not check the _shutdown flag before performing operations. If the destructor is called while Operational is executing or about to execute, there could be a race condition where resources are being destroyed while still in use. Consider checking _shutdown at the beginning of Operational and returning early if true.

Copilot uses AI. Check for mistakes.
Comment on lines 233 to 234
printf("[dsFPD-com] Returning DeviceSettingsFPD instance [%p]\n", _instance);
return _instance;
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Instance() method does not acquire the lock before accessing _instance, creating a race condition. If one thread is in Init() or Term() modifying _instance while another thread calls Instance(), the returned pointer could be invalid or null when it's about to be deleted. Instance() should acquire _apiLock before reading _instance to ensure thread safety.

Suggested change
printf("[dsFPD-com] Returning DeviceSettingsFPD instance [%p]\n", _instance);
return _instance;
_apiLock.Lock();
DeviceSettingsFPD* instance = _instance;
printf("[dsFPD-com] Returning DeviceSettingsFPD instance [%p]\n", instance);
_apiLock.Unlock();
return instance;

Copilot uses AI. Check for mistakes.
Comment on lines +46 to +51
# Conditional linking flags
ifdef USE_WPE_THUNDER_PLUGIN
LDLIBS := -lWPEFrameworkCore -lWPEFrameworkCOM
else
LDLIBS := -lIARMBus
endif
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Makefile conditionally compiles based on USE_WPE_THUNDER_PLUGIN, but this macro is not added to CFLAGS. The source file dsFPD-com.cpp uses #ifdef USE_WPE_THUNDER_PLUGIN (line 27 in that file) to conditionally compile the Thunder implementation. Without -DUSE_WPE_THUNDER_PLUGIN in CFLAGS, the code in dsFPD-com.cpp will not be compiled even when it's included in the build. Add -DUSE_WPE_THUNDER_PLUGIN to CFLAGS when Thunder mode is enabled.

Copilot uses AI. Check for mistakes.
Comment on lines +191 to +210
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);
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The signal handler performs several operations that are not async-signal-safe. According to POSIX, signal handlers should only call async-signal-safe functions. This handler calls:

  1. syslog() (line 200) - not async-signal-safe
  2. pthread_mutex_lock() (line 203) - not async-signal-safe
  3. cleanup_resources() (line 208) - which calls multiple non-async-signal-safe functions
  4. exit() (line 210) - not fully safe in signal handlers

These operations can lead to deadlocks, undefined behavior, or data corruption. Consider using a self-pipe trick or setting a volatile sig_atomic_t flag that the main loop checks, rather than performing complex operations directly in the signal handler.

Suggested change
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);
switch (signum) {
case SIGTERM:
/* Async-signal-safe diagnostic message */
write(STDERR_FILENO,
"[DSApp] Received SIGTERM, exiting immediately\n",
sizeof("[DSApp] Received SIGTERM, exiting immediately\n") - 1);
break;
case SIGINT:
write(STDERR_FILENO,
"[DSApp] Received SIGINT, exiting immediately\n",
sizeof("[DSApp] Received SIGINT, exiting immediately\n") - 1);
break;
case SIGHUP:
write(STDERR_FILENO,
"[DSApp] Received SIGHUP, exiting immediately\n",
sizeof("[DSApp] Received SIGHUP, exiting immediately\n") - 1);
break;
case SIGUSR1:
write(STDERR_FILENO,
"[DSApp] Received SIGUSR1, exiting immediately\n",
sizeof("[DSApp] Received SIGUSR1, exiting immediately\n") - 1);
break;
case SIGUSR2:
write(STDERR_FILENO,
"[DSApp] Received SIGUSR2, exiting immediately\n",
sizeof("[DSApp] Received SIGUSR2, exiting immediately\n") - 1);
break;
default:
write(STDERR_FILENO,
"[DSApp] Received unknown signal, exiting immediately\n",
sizeof("[DSApp] Received unknown signal, exiting immediately\n") - 1);
break;
}
/* Use _exit, which is async-signal-safe, to terminate immediately. */
_exit(128 + signum);

Copilot uses AI. Check for mistakes.
Comment on lines 511 to 513
// 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);
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a semantic mismatch in parameter interpretation. The dsSetFPTime API expects (timeFormat, hour, minutes) but the SetFPDTime interface expects (timeFormat, minutes, seconds). The comment on line 512 acknowledges this but the "fix" of treating uMinutes as seconds is incorrect - it's passing uHour as minutes and uMinutes as seconds. This means if someone calls dsSetFPTime with hour=14 and minutes=30, it will set the display to 14 minutes and 30 seconds instead of 14:30. Either the Thunder interface signature is wrong or this conversion logic needs to properly convert hours+minutes to total minutes+seconds, or this mismatch should be documented as a known limitation.

Suggested change
// 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);
// Note: Interface expects minutes and seconds, but API provides hour and minutes.
// Convert hour:minutes into totalMinutes:seconds for the Thunder interface.
const uint32_t totalMinutes = (uHour * 60u) + (uMinutes % 60u);
const uint32_t seconds = 0u;
uint32_t result = instance->SetFPDTime(timeFormat, totalMinutes, seconds);

Copilot uses AI. Check for mistakes.
Comment on lines +158 to +159

LOGI("Initializing Front Panel from libds.so...");
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent indentation detected. Lines 158-159 use tabs for indentation while the surrounding code uses spaces. This should be consistent with the rest of the file which uses spaces for indentation.

Suggested change
LOGI("Initializing Front Panel from libds.so...");
LOGI("Initializing Front Panel from libds.so...");

Copilot uses AI. Check for mistakes.
Comment on lines +324 to +329

// Destroy mutexes
pthread_mutex_destroy(&gDSAppMutex);
pthread_mutex_destroy(&gCurlInitMutex);
LOGD("Mutexes destroyed");

Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Destroying mutexes that may be in use is unsafe. The cleanup_resources function is called from the signal handler (line 208), but it destroys mutexes on lines 326-327 after potentially having locked them. If another thread is holding or waiting on these mutexes when the signal handler fires, destroying them leads to undefined behavior. Signal handlers should be async-signal-safe and avoid such operations. Consider setting a flag instead and handling cleanup in the main thread, or ensure the application is single-threaded when this cleanup occurs.

Suggested change
// Destroy mutexes
pthread_mutex_destroy(&gDSAppMutex);
pthread_mutex_destroy(&gCurlInitMutex);
LOGD("Mutexes destroyed");
// Note: Do not destroy mutexes here. This function may be invoked from
// a signal handler, and destroying mutexes that might be in use by
// other threads is undefined behavior. These global mutexes are
// process-lifetime objects and will be cleaned up by the OS at exit.

Copilot uses AI. Check for mistakes.
Comment on lines +438 to +449
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());
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Input validation is missing for the brightness value. While the range is mentioned in the prompt (0-100), there is no validation to ensure the input is within this range before calling setBrightness. Invalid values could cause unexpected behavior in the device settings layer. Add validation: if (brightness < 0 || brightness > 100) before the try block.

Suggested change
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());
if (brightness < 0 || brightness > 100) {
printf("Brightness must be between 0 and 100.\n");
} else {
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());
}

Copilot uses AI. Check for mistakes.
Comment on lines 465 to 470
/* // 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;
}
*/
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The commented-out code from lines 465-469 uses incorrect C-style block comment delimiters. The opening /* is on line 465, but the closing */ is on line 470 after actual code. This creates a malformed comment structure. If this code were uncommented or if the comment boundaries were adjusted, it would cause compilation issues. Either remove this commented code entirely or fix the comment delimiters to be on their own lines.

Suggested change
/* // 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;
}
*/
// 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;
// }

Copilot uses AI. Check for mistakes.
Comment on lines 34 to 38
FPD_SOURCE = dsFPD-com.cpp
THUNDER_LIBS = -lWPEFrameworkCore -lWPEFrameworkCOM
else
FPD_SOURCE = dsFPD.c
THUNDER_LIBS =
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The indentation of the conditional blocks in Makefile.am is incorrect. In Automake, the if/else/endif statements should not be indented, and the content within them should also not be indented beyond normal Makefile variable assignments. The spaces before FPD_SOURCE and THUNDER_LIBS will cause Automake parsing errors. Remove the leading spaces from lines 34-35 and 37-38.

Suggested change
FPD_SOURCE = dsFPD-com.cpp
THUNDER_LIBS = -lWPEFrameworkCore -lWPEFrameworkCOM
else
FPD_SOURCE = dsFPD.c
THUNDER_LIBS =
FPD_SOURCE = dsFPD-com.cpp
THUNDER_LIBS = -lWPEFrameworkCore -lWPEFrameworkCOM
else
FPD_SOURCE = dsFPD.c
THUNDER_LIBS =

Copilot uses AI. Check for mistakes.
Manimaran Renganathan added 2 commits February 18, 2026 13:39
Modified the dsFPD-com.cpp file based on dsController-com.cpp and
Makefile.am
Copilot AI review requested due to automatic review settings February 18, 2026 14:11
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copilot AI review requested due to automatic review settings February 19, 2026 06:49
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 28 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Exchange::IDeviceSettingsDisplay* result = _displayInterface;
_lock.Unlock();
return result;
*/}
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing return statement. This function is declared to return Exchange::IDeviceSettingsDisplay* but has no return statement, which will cause undefined behavior and compilation warnings/errors.

Suggested change
*/}
*/
return nullptr;
}

Copilot uses AI. Check for mistakes.
Comment on lines +555 to +564
Exchange::IDeviceSettingsVideoDevice* DeviceSettingsController::GetVideoDeviceInterface()
{
/*
_lock.Lock();
QueryComponentInterface<Exchange::IDeviceSettingsVideoDevice>(_videoDeviceInterface, "IDeviceSettingsVideoDevice");
Exchange::IDeviceSettingsVideoDevice* result = _videoDeviceInterface;
_lock.Unlock();
return result;
*/
}
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing return statement. This function is declared to return Exchange::IDeviceSettingsVideoDevice* but has no return statement, which will cause undefined behavior and compilation warnings/errors.

Copilot uses AI. Check for mistakes.
Comment on lines +430 to +432
printf("Press Enter to continue...");
getchar(); getchar();
break;
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential double getchar() issue for input handling. The code uses getchar(); getchar(); pattern multiple times (e.g., lines 431-432) to wait for user input, presumably to consume the newline and then wait for Enter. However, this pattern is fragile - if the input buffer already has a newline from a previous scanf, the first getchar() consumes it and the second one blocks, which is the intended behavior. But if there's no newline (e.g., after a failed scanf), this can cause the program to skip waiting. A more robust approach would be to clear the input buffer first with a while loop, then wait for a single Enter press.

Copilot uses AI. Check for mistakes.
Comment on lines +525 to +533
Exchange::IDeviceSettingsAudio* DeviceSettingsController::GetAudioInterface()
{
/* _lock.Lock();
QueryComponentInterface<Exchange::IDeviceSettingsAudio>(_audioInterface, "IDeviceSettingsAudio");
Exchange::IDeviceSettingsAudio* result = _audioInterface;
_lock.Unlock();
return result;
*/
}
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing return statement. This function is declared to return Exchange::IDeviceSettingsAudio* but has no return statement, which will cause undefined behavior and compilation warnings/errors.

Copilot uses AI. Check for mistakes.
Comment on lines +566 to +575
Exchange::IDeviceSettingsHost* DeviceSettingsController::GetHostInterface()
{
/*
_lock.Lock();
QueryComponentInterface<Exchange::IDeviceSettingsHost>(_hostInterface, "IDeviceSettingsHost");
Exchange::IDeviceSettingsHost* result = _hostInterface;
_lock.Unlock();
return result;
*/
}
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing return statement. This function is declared to return Exchange::IDeviceSettingsHost* but has no return statement, which will cause undefined behavior and compilation warnings/errors.

Copilot uses AI. Check for mistakes.
Comment on lines +758 to +760
printf("\nCalling DeviceSettings_GetCompositeInput()...\n");
// TODO: Add actual function call
printf("Function called successfully!\n");
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Multiple TODO comments for unimplemented functionality. Lines 641, 648, 688, 724, 759 contain TODO comments with placeholder function calls. These menu options are presented to the user but don't actually perform the expected operations. Either implement these functions, remove the menu options, or clearly indicate in the menu that these features are not yet implemented (e.g., "2. Audio Ports (Not yet implemented)").

Suggested change
printf("\nCalling DeviceSettings_GetCompositeInput()...\n");
// TODO: Add actual function call
printf("Function called successfully!\n");
printf("\nDeviceSettings_GetCompositeInput is not yet implemented.\n");

Copilot uses AI. Check for mistakes.
ds/manager.cpp Outdated
Comment on lines 163 to 170
#ifdef USE_THUNDER_PLUGIN
// For Thunder COM-RPC mode, initialize the DeviceSettingsController
if (WPEFramework::DeviceSettingsController::Initialize() != WPEFramework::Core::ERROR_NONE) {
fprintf(stderr, "[Manager] Failed to initialize DeviceSettingsController\n");
throw std::runtime_error("DeviceSettingsController initialization failed");
}
printf("[Manager] DeviceSettingsController initialized successfully\n");
#endif
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent commenting style. Line 163 begins with tabs while line 164 has proper indentation. This creates visual inconsistency. Use consistent indentation for all lines including comments.

Suggested change
#ifdef USE_THUNDER_PLUGIN
// For Thunder COM-RPC mode, initialize the DeviceSettingsController
if (WPEFramework::DeviceSettingsController::Initialize() != WPEFramework::Core::ERROR_NONE) {
fprintf(stderr, "[Manager] Failed to initialize DeviceSettingsController\n");
throw std::runtime_error("DeviceSettingsController initialization failed");
}
printf("[Manager] DeviceSettingsController initialized successfully\n");
#endif
#ifdef USE_THUNDER_PLUGIN
// For Thunder COM-RPC mode, initialize the DeviceSettingsController
if (WPEFramework::DeviceSettingsController::Initialize() != WPEFramework::Core::ERROR_NONE) {
fprintf(stderr, "[Manager] Failed to initialize DeviceSettingsController\n");
throw std::runtime_error("DeviceSettingsController initialization failed");
}
printf("[Manager] DeviceSettingsController initialized successfully\n");
#endif

Copilot uses AI. Check for mistakes.
Comment on lines 31 to 48
#ifdef USE_THUNDER_PLUGIN

#ifndef MODULE_NAME
#define MODULE_NAME DeviceSettings_Client
#endif

#include <core/core.h>
#include <com/com.h>
#include <plugins/Types.h>
#include <interfaces/IDeviceSettings.h>
#include <interfaces/IDeviceSettingsFPD.h>
#include <interfaces/IDeviceSettingsHDMIIn.h>
#include <interfaces/IDeviceSettingsAudio.h>
#include <interfaces/IDeviceSettingsDisplay.h>
#include <interfaces/IDeviceSettingsVideoPort.h>
#include <interfaces/IDeviceSettingsVideoDevice.h>
#include <interfaces/IDeviceSettingsHost.h>
#include <interfaces/IDeviceSettingsCompositeIn.h>
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing include guard or #error for required Thunder headers. The file uses Thunder-specific types and classes (Exchange::IDeviceSettingsFPD, WPEFramework::Core::CriticalSection, etc.) but doesn't verify that the necessary Thunder header files are available. If someone tries to compile this with USE_THUNDER_PLUGIN defined but without the Thunder SDK installed, they'll get confusing compiler errors. Consider adding a comment or compile-time check to ensure Thunder headers are available when USE_THUNDER_PLUGIN is defined.

Copilot uses AI. Check for mistakes.
// Just verify we have FPD interface access
DeviceSettingsController* controller = DeviceSettingsController::GetInstance();
if (!controller) {
fprintf(stderr, "[dsFPD-com] DeviceSettingsController not initialized\n");
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No error handling for fprintf to stderr. Throughout the file, fprintf to stderr is used but the return value is not checked. While uncommon, stderr writes can fail (e.g., if stderr is redirected to a full disk). For critical error messages, consider checking the return value or using syslog as an alternative reliable logging mechanism, especially since this code already uses syslog elsewhere.

Copilot uses AI. Check for mistakes.
Comment on lines +161 to +166
fpIndicators = device::FrontPanelConfig::getInstance().getIndicators();

for (size_t i = 0; i < fpIndicators.size(); i++) {
std::string IndicatorName = fpIndicators.at(i).getName();
LOGI("Initializing Front Panel Indicator: %s", IndicatorName.c_str());
}
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing error check for FrontPanelConfig initialization. Line 161 calls FrontPanelConfig::getInstance().getIndicators() but doesn't wrap it in a try-catch block or check for errors, even though it's called before libds initialization is confirmed complete. If this call fails, it could throw an exception that isn't caught at line 171-174, or it could return an invalid/empty list. Ensure proper error handling for this initialization step.

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings February 19, 2026 10:29
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 13 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +73 to +74
printf("\n=== DeviceSettings Interactive Test Application ===\n");
printf("Build: %s %s\n", __DATE__, __TIME__);
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded build timestamp in production: Lines 73-74 embed DATE and TIME macros which create non-reproducible builds. This makes it impossible to verify that a binary was built from specific source code, which is important for security and debugging. Consider using a version string from the build system instead.

Copilot uses AI. Check for mistakes.
return ConvertThunderError(result);
}

dsError_t dsFPEnableCLockDisplay(int enable)
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in function name: The function is named dsFPEnableCLockDisplay (line 481) with uppercase 'L' in "CLock", but it should likely be dsFPEnableClockDisplay with lowercase 'l' in "Clock". This inconsistent naming could cause confusion.

Suggested change
dsError_t dsFPEnableCLockDisplay(int enable)
dsError_t dsFPEnableClockDisplay(int enable)

Copilot uses AI. Check for mistakes.
Comment on lines +290 to +316
while (1)
{
_connectionRetryCount++;

uint32_t result = controller->Connect();

if (result == Core::ERROR_NONE) {
printf("[DeviceSettingsController] Thunder connection SUCCESS after %u attempts\n",
_connectionRetryCount);

// Post-connection initialization
FetchAndInitializeInterfaces();

_isConnecting = false;
printf("[DeviceSettingsController] RetryThunderConnectionThread completed successfully\n");
break;
}
else {
if (_connectionRetryCount % 10 == 0) { // Log every 3 seconds
printf("[DeviceSettingsController] Connection attempt %u failed, retrying...\n",
_connectionRetryCount);
}

// 300ms wait before retry (matches DSMGR_PWR_CNTRL_CONNECT_WAIT_TIME_MS)
usleep(DS_CONTROLLER_CONNECT_WAIT_TIME_MS);
}
}
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential infinite loop without exit condition: The while loop on line 290 has while (1) with no explicit exit condition other than a successful connection. If the controller instance becomes null or the system is shutting down, the thread may not exit gracefully. Consider adding a check for shutdown conditions or a maximum retry count.

Copilot uses AI. Check for mistakes.
Comment on lines +308 to +313
if (_connectionRetryCount % 10 == 0) { // Log every 3 seconds
printf("[DeviceSettingsController] Connection attempt %u failed, retrying...\n",
_connectionRetryCount);
}

// 300ms wait before retry (matches DSMGR_PWR_CNTRL_CONNECT_WAIT_TIME_MS)
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incorrect comment in logging: Line 308 states "Log every 3 seconds" but the actual wait time is 300ms (DS_CONTROLLER_CONNECT_WAIT_TIME_MS = 300000 microseconds), and logging happens every 10 attempts. This would be 10 * 300ms = 3 seconds, which matches the comment. However, the comment is slightly misleading as it doesn't clarify this is based on the retry interval.

Suggested change
if (_connectionRetryCount % 10 == 0) { // Log every 3 seconds
printf("[DeviceSettingsController] Connection attempt %u failed, retrying...\n",
_connectionRetryCount);
}
// 300ms wait before retry (matches DSMGR_PWR_CNTRL_CONNECT_WAIT_TIME_MS)
if (_connectionRetryCount % 10 == 0) { // Log every 10 attempts (~3s with current 300ms retry interval)
printf("[DeviceSettingsController] Connection attempt %u failed, retrying...\n",
_connectionRetryCount);
}
// 300ms wait before each retry attempt (matches DSMGR_PWR_CNTRL_CONNECT_WAIT_TIME_MS)

Copilot uses AI. Check for mistakes.
*/

/**
* @file DeviceSettingsController.h
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same documentation error in duplicate file: Line 21 states "@file DeviceSettingsController.h" but the actual filename is "dsController-com.h". This is the same issue as in rpc/cli/dsController-com.h, confirming these are duplicate files with the same documentation error.

Suggested change
* @file DeviceSettingsController.h
* @file dsController-com.h

Copilot uses AI. Check for mistakes.

#pragma once

#ifdef USE_THUNDER_PLUGIN
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same macro naming inconsistency in duplicate file: This header also uses USE_THUNDER_PLUGIN (line 31) instead of USE_WPE_THUNDER_PLUGIN which is defined by configure.ac. This confirms the files are duplicates and share the same error.

Copilot uses AI. Check for mistakes.
Comment on lines +97 to +102
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);
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential buffer overflow: Lines 97-102 allocate a debug buffer with MAX_DEBUG_LOG_BUFF_SIZE (8192 bytes) but the buffer is never used in the visible code. If this buffer is intended for formatted output, there should be size checks when writing to it to prevent buffer overflow vulnerabilities.

Copilot uses AI. Check for mistakes.
Comment on lines +325 to +329
// Destroy mutexes
pthread_mutex_destroy(&gDSAppMutex);
pthread_mutex_destroy(&gCurlInitMutex);
LOGD("Mutexes destroyed");

Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mutex destroyed while potentially in use: The cleanup_resources() function destroys mutexes (lines 326-327) but doesn't verify that no other threads are holding these locks. If the connection retry thread is still running when cleanup occurs, this could lead to undefined behavior. Consider joining or canceling threads before destroying their synchronization primitives.

Suggested change
// Destroy mutexes
pthread_mutex_destroy(&gDSAppMutex);
pthread_mutex_destroy(&gCurlInitMutex);
LOGD("Mutexes destroyed");

Copilot uses AI. Check for mistakes.
*/

/**
* @file DeviceSettingsController.h
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incorrect file path reference in comment: Line 21 of dsController-com.h states "@file DeviceSettingsController.h" but the actual filename is "dsController-com.h". This mismatch between the comment and actual filename can cause confusion in documentation generation tools and code navigation.

Suggested change
* @file DeviceSettingsController.h
* @file dsController-com.h

Copilot uses AI. Check for mistakes.
* @brief Implementation of central controller for DeviceSettings COM-RPC connections
*/

#ifdef USE_THUNDER_PLUGIN
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Macro naming inconsistency: dsController-com.cpp is conditionally compiled based on USE_THUNDER_PLUGIN (line 25), but configure.ac defines USE_WPE_THUNDER_PLUGIN. This will cause the entire file to be excluded from compilation when Thunder support is enabled.

Suggested change
#ifdef USE_THUNDER_PLUGIN
#ifdef USE_WPE_THUNDER_PLUGIN

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings February 19, 2026 11:54
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 7 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +157 to +187
// device::Manager::Initialize(); As of now FPD only communicate through COM-RPC

LOGI("Initializing Front Panel from libds.so...");
LOGI("Front panel init");
fpIndicators = device::FrontPanelConfig::getInstance().getIndicators();

for (size_t i = 0; i < fpIndicators.size(); i++) {
std::string IndicatorName = fpIndicators.at(i).getName();
LOGI("Initializing Front Panel Indicator: %s", IndicatorName.c_str());
}

LOGI("Device Settings FPD initialized successfully");

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());
}
}
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commented code contradicts actual behavior. Line 157 has a comment stating "device::Manager::Initialize(); As of now FPD only communicate through COM-RPC" with the Manager::Initialize() call commented out. However, the cleanup in libds_Terminate() (line 182) calls device::Manager::DeInitialize(). This asymmetry suggests either Manager::Initialize() should be called during initialization, or DeInitialize() should not be called during cleanup. The current state may lead to improper cleanup or undefined behavior.

Copilot uses AI. Check for mistakes.
#include "dsController-com.h"
#include <stdio.h>
#include <chrono>
#include <thread>
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing atomic header include causes compilation error. The class uses std::atomic at line 42 (_isConnecting) but does not include the header. This will cause a compilation error in C++11 and later. Add '#include ' at the top of the file.

Suggested change
#include <thread>
#include <thread>
#include <atomic>

Copilot uses AI. Check for mistakes.
dsapp:
@if [ -f DSCliLibStandaloneApp.cpp ]; then \
echo "Building DSApp..."; \
$(CXX) $(CFLAGS) -std=c++11 DSCliLibStandaloneApp.cpp -o ../DSApp -L$(INSTALL)/lib -lds -Wl,--no-as-needed -ldshalcli -Wl,--as-needed -lcurl -lpthread $(LDFLAGS); \
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incorrect linker flag order may cause undefined references. At line 94, the library order places -lds before -ldshalcli, but libds.so depends on libdshalcli.so (as shown in ds/Makefile.am line 67 where libds_la_LIBADD includes libdshalcli.la). In GNU ld, libraries should be ordered so that dependent libraries appear before the libraries they depend on. The correct order should be: -lds -Wl,--no-as-needed -ldshalcli -Wl,--as-needed. However, given the current order with --no-as-needed, this may work but is still semantically incorrect.

Suggested change
$(CXX) $(CFLAGS) -std=c++11 DSCliLibStandaloneApp.cpp -o ../DSApp -L$(INSTALL)/lib -lds -Wl,--no-as-needed -ldshalcli -Wl,--as-needed -lcurl -lpthread $(LDFLAGS); \
$(CXX) $(CFLAGS) -std=c++11 DSCliLibStandaloneApp.cpp -o ../DSApp -L$(INSTALL)/lib -Wl,--no-as-needed -ldshalcli -Wl,--as-needed -lds -lcurl -lpthread $(LDFLAGS); \

Copilot uses AI. Check for mistakes.
export STANDALONE_BUILD_ENABLED=y
export DS_MGRS=$WORKDIR

export USE_WPE_THUNDER_PLUGIN=y
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling error in comment. "Devicesttings" should be "DeviceSettings" (missing 'e' and has extra 't').

Copilot uses AI. Check for mistakes.
static std::atomic<bool> _isConnecting;
static uint32_t _connectionRetryCount;

#define DS_CONTROLLER_CONNECT_WAIT_TIME_MS 300000 // 300ms in microseconds
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incorrect comment in macro definition. The comment states "300ms in microseconds" but the value 300000 represents 300ms in microseconds (300000 µs = 300 ms), not milliseconds. However, the usage at line 314 calls usleep(DS_CONTROLLER_CONNECT_WAIT_TIME_MS), which expects microseconds. Either the macro name should be DS_CONTROLLER_CONNECT_WAIT_TIME_US to reflect that it's in microseconds, or the comment should clarify the unit conversion. The current naming/comment creates confusion about the actual time unit.

Suggested change
#define DS_CONTROLLER_CONNECT_WAIT_TIME_MS 300000 // 300ms in microseconds
#define DS_CONTROLLER_CONNECT_WAIT_TIME_MS 300000 // 300 ms delay, value expressed in microseconds (for usleep)

Copilot uses AI. Check for mistakes.
Comment on lines +37 to +48
#include <core/core.h>
#include <com/com.h>
#include <plugins/Types.h>
#include <interfaces/IDeviceSettings.h>
#include <interfaces/IDeviceSettingsFPD.h>
#include <interfaces/IDeviceSettingsHDMIIn.h>
#include <interfaces/IDeviceSettingsAudio.h>
#include <interfaces/IDeviceSettingsDisplay.h>
#include <interfaces/IDeviceSettingsVideoPort.h>
#include <interfaces/IDeviceSettingsVideoDevice.h>
#include <interfaces/IDeviceSettingsHost.h>
#include <interfaces/IDeviceSettingsCompositeIn.h>
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing atomic header include. The header declares std::atomic at line 107 but does not include the header, which is required for std::atomic. Add '#include ' to the includes section.

Copilot uses AI. Check for mistakes.
Comment on lines +278 to +320
void* DeviceSettingsController::RetryThunderConnectionThread(void* arg)
{
printf("[DeviceSettingsController] RetryThunderConnectionThread entry\n");

DeviceSettingsController* controller = DeviceSettingsController::GetInstance();
if (controller == nullptr) {
fprintf(stderr, "[DeviceSettingsController] Controller instance is null\n");
_isConnecting = false;
return arg;
}

// Infinite retry loop (matches dsMgrPwrRetryEstablishConnThread pattern)
while (1)
{
_connectionRetryCount++;

uint32_t result = controller->Connect();

if (result == Core::ERROR_NONE) {
printf("[DeviceSettingsController] Thunder connection SUCCESS after %u attempts\n",
_connectionRetryCount);

// Post-connection initialization
FetchAndInitializeInterfaces();

_isConnecting = false;
printf("[DeviceSettingsController] RetryThunderConnectionThread completed successfully\n");
break;
}
else {
if (_connectionRetryCount % 10 == 0) { // Log every 3 seconds
printf("[DeviceSettingsController] Connection attempt %u failed, retrying...\n",
_connectionRetryCount);
}

// 300ms wait before retry (matches DSMGR_PWR_CNTRL_CONNECT_WAIT_TIME_MS)
usleep(DS_CONTROLLER_CONNECT_WAIT_TIME_MS);
}
}

printf("[DeviceSettingsController] RetryThunderConnectionThread exit\n");
return arg;
}
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Detached thread accesses instance after potential deletion. The RetryThunderConnectionThread is detached and runs in an infinite loop, but the Terminate function (line 232-248) can delete the controller instance while this thread is still running. There's no mechanism to signal the thread to stop before destroying the instance. This creates a use-after-free vulnerability. Add a shutdown flag that the thread checks in its loop, and ensure the thread completes before destroying the instance.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant