From 6342f271a66978006023c15e0a5e52ab05133c44 Mon Sep 17 00:00:00 2001 From: Gene Gallagher <129112619+egalla204@users.noreply.github.com> Date: Wed, 5 Nov 2025 18:00:16 -0500 Subject: [PATCH 01/81] RDKEMW-10164: update CHANGELOG for release v1.1.5 (#139) --- CHANGELOG.md | 218 +++++++++++++++++++++++++-------------------------- 1 file changed, 105 insertions(+), 113 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9eed8a53..ef1e336b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,140 +1,130 @@ -# Changelog +### Changelog -All notable changes to this project will be documented in this file. +All notable changes to this project will be documented in this file. Dates are displayed in UTC. -* Each RDK Service has a CHANGELOG file that contains all changes done so far. When version is updated, add a entry in the CHANGELOG.md at the top with user friendly information on what was changed with the new version. Please don't mention JIRA tickets in CHANGELOG. +Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). -* Please Add entry in the CHANGELOG for each version change and indicate the type of change with these labels: - * **Added** for new features. - * **Changed** for changes in existing functionality. - * **Deprecated** for soon-to-be removed features. - * **Removed** for now removed features. - * **Fixed** for any bug fixes. - * **Security** in case of vulnerabilities. -* Changes in CHANGELOG should be updated when commits are added to the main or release branches. There should be one CHANGELOG entry per JIRA Ticket. This is not enforced on sprint branches since there could be multiple changes for the same JIRA ticket during development. + -* In the future, generate this file by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [1.1.5](https://github.com/rdkcentral/control/compare/1.1.4...1.1.5) -## [1.1.4] - 2025-09-17 +> 5 November 2025 -### Changed -- move certselector logic into ctrlm-main repo (#102) -- use version/branch from recipe (#109) +- RDKEMW-9924 : ctrlm RF4CE upgrade skipped when BLE enabled [`#137`](https://github.com/rdkcentral/control/pull/137) +- RDKEMW-7225: BLE pairing retries [`#126`](https://github.com/rdkcentral/control/pull/126) +- RDKEMW-8929: Refactor ctrlm_voice_ipc_t to inherit ctrlm_ipc_iarm_t [`#129`](https://github.com/rdkcentral/control/pull/129) +- Update CODEOWNERS [`#130`](https://github.com/rdkcentral/control/pull/130) +- RDKEMW-8815: only return SUCCESS for autolookup if it found at least 1 code. [`#125`](https://github.com/rdkcentral/control/pull/125) +- Deploy fossid_integration_stateless_diffscan_target_repo action [`#121`](https://github.com/rdkcentral/control/pull/121) +- Deploy cla action [`#74`](https://github.com/rdkcentral/control/pull/74) +- RDKEMW-8354: ctrlm-main crash while holding standby during OTA [`#115`](https://github.com/rdkcentral/control/pull/115) +- RDKEMW-8133: Optional param name for voiceSessionRequest [`#108`](https://github.com/rdkcentral/control/pull/108) -### Added -- update AMC APP key mapping (#98) +#### [1.1.4](https://github.com/rdkcentral/control/compare/1.1.3...1.1.4) -### Fixed -- getNetStatus call time out due to SAT download retries (#97) -- remove device from bluez during factory reset (#100) -- Missing Thunder cflags in ctrlm implemenation (#103) +> 18 September 2025 -### Removed -- remove ctrlm compile flags (#104) -- remove ctrlm build flags - CPC, DUNFELL (#105) -- remove ctrlm build flags - RF4CE_PACKET_ANALYSIS (#107) -- remove ctrlm build flags - DISABLE_BLE_VOICE (#106) +- RDKEMW-8349 : ctrlm release v1.1.4 [`#113`](https://github.com/rdkcentral/control/pull/113) +- RDKEMW-7979 : use version/branch from recipe [`#109`](https://github.com/rdkcentral/control/pull/109) +- RDKEMW-7122 : Missing Thunder cflags in ctrlm implementation [`#103`](https://github.com/rdkcentral/control/pull/103) +- RDKEMW-7772 : remove ctrlm build flags - DISABLE_BLE_VOICE [`#106`](https://github.com/rdkcentral/control/pull/106) +- RDKEMW-7834 : remove ctrlm build flags - RF4CE_PACKET_ANALYSIS [`#107`](https://github.com/rdkcentral/control/pull/107) +- RDKEMW-7694 : remove ctrlm build flags - CPC, DUNFELL [`#105`](https://github.com/rdkcentral/control/pull/105) +- RDKEMW-7573 : remove ctrlm compile flags [`#104`](https://github.com/rdkcentral/control/pull/104) +- RDKEMW-7333: remove device from bluez during factory reset [`#100`](https://github.com/rdkcentral/control/pull/100) +- RDKEMW-6767: getNetStatus call time out due to SAT download retries [`#97`](https://github.com/rdkcentral/control/pull/97) +- RDKEMW-3409 : move certselector logic into ctrlm-main repo [`#102`](https://github.com/rdkcentral/control/pull/102) +- RDKEMW-7174 : update AMC APP key mapping [`#98`](https://github.com/rdkcentral/control/pull/98) -## [1.1.3] - 2025-08-19 +#### [1.1.3](https://github.com/rdkcentral/control/compare/1.1.2...1.1.3) -### Changed -- Modify Remote Control plugin for RF4CE support (#80) -- Mac address fetch (#92) +> 19 August 2025 -### Added -- Runtime detection of ASB (#96) +- RDKEMW-7232: update CHANGELOG for controlMgr release v1.1.3 [`#99`](https://github.com/rdkcentral/control/pull/99) +- RDKEMW-5576: ctrlm mac address fetch [`#92`](https://github.com/rdkcentral/control/pull/92) +- RDKEMW-4309 : Modify Remote Control plugin for RF4CE support [`#80`](https://github.com/rdkcentral/control/pull/80) +- RDKEMW-5604 : runtime detection of ASB [`#96`](https://github.com/rdkcentral/control/pull/96) -## [1.1.2] - 2025-08-04 +#### [1.1.2](https://github.com/rdkcentral/control/compare/1.1.1...1.1.2) -### Changed -- use HdmiCecSource instead of deprecated HdmiCec (#93) -- update key code mapping (#91) -- stop BLE audio stream on the RCU when server ends session early (#76) +> 18 August 2025 -### Added -- BLE network discovery (#94) -- try to load VL provided IRDB, upon failure fallback to existing IRDB in MW (#79) -- print raw EDID data at debug log level +- RDKEMW-6034: update CHANGELOG for controlMgr release v1.1.2 [`#95`](https://github.com/rdkcentral/control/pull/95) +- RDKEMW-6538: use HdmiCecSource instead of deprecated HdmiCec [`#93`](https://github.com/rdkcentral/control/pull/93) +- RDKEMW-6383 : update key code mapping [`#91`](https://github.com/rdkcentral/control/pull/91) +- RDKEMW-3797 : BLE network discovery [`#94`](https://github.com/rdkcentral/control/pull/94) +- RDKEMW-6195: try to load VL provided IRDB, upon failure fallback to existing IRDB in MW [`#79`](https://github.com/rdkcentral/control/pull/79) +- RDKEMW-5714: Voice not initiated in ctrlm-main [`#81`](https://github.com/rdkcentral/control/pull/81) +- RDKEMW-6884: Logs indicate missing receiver ID [`#85`](https://github.com/rdkcentral/control/pull/85) +- RDKEMW-5413 : Remove RF4CE HAL from the middleware layer [`#75`](https://github.com/rdkcentral/control/pull/75) +- RDKEMW-5506 : stop BLE audio stream on the RCU when server ends session early [`#76`](https://github.com/rdkcentral/control/pull/76) +- RDKEMW-3965: print raw EDID data at debug log level [`447ae08`](https://github.com/rdkcentral/control/commit/447ae0826d15351fa97ccb12b3b18f435ff40089) -### Fixed -- Voice not initiated due to voice key not initialized to default value - -### Removed -- remove receiver ID, its no longer used (#85) -- Remove RF4CE HAL from the middleware layer (#75) +#### [1.1.1](https://github.com/rdkcentral/control/compare/1.1.0...1.1.1) - +> 30 June 2025 -## [1.1.1] - 2025-06-25 +- RDKEMW-4913: ctrlm release v1.1.1 [`#77`](https://github.com/rdkcentral/control/pull/77) +- RDKEMW-4788: use HDMI Input plugin RDKV and AVInput RDKE [`#67`](https://github.com/rdkcentral/control/pull/67) +- RDKEMW-5247 : BLE audio pipe size too small [`#68`](https://github.com/rdkcentral/control/pull/68) +- RDKEMW-3411 : receive RF4CE IR binding key codes over IR input device [`#69`](https://github.com/rdkcentral/control/pull/69) +- RDKEMW-3563: Enable ASB [`#63`](https://github.com/rdkcentral/control/pull/63) +- RDKEMW-3119: Control Manager to use Power Manager Thunder Plugin [`07c1d22`](https://github.com/rdkcentral/control/commit/07c1d222b5d99849713a4db8dcef3bd847380f4b) -### Changed -- Use the deprecated HDMI Input plugin instead of the new AV Input plugin if compile flag is set +#### [1.1.0](https://github.com/rdkcentral/control/compare/1.0.10...1.1.0) -### Fixed -- BLE audio pipe size too small, set minimum size -- enable RF4CE Advanced Secure Binding (ASB) +> 30 June 2025 -### Added -- receive RF4CE IR binding key codes over IR input device -- use new Power Manager Thunder Plugin for power state events, switch to deprecated IARM interface with compile flag - +- RDKEMW-4793: ctrlm release v1.1.0 [`#61`](https://github.com/rdkcentral/control/pull/61) +- RDKEMW-3408: [ctrlm] refactor interface to ctrlm IR Database for Vendor layer integration [`#18`](https://github.com/rdkcentral/control/pull/18) +- RDKEMW-3798 : RF4CE network discovery [`#53`](https://github.com/rdkcentral/control/pull/53) +- RDKEMW-3410 : Default BLE controller type list [`#29`](https://github.com/rdkcentral/control/pull/29) +- RDKEMW-4381: ctrlm crash during OTA interrupted by unpair or reset [`#54`](https://github.com/rdkcentral/control/pull/54) -## [1.1.0] - 2025-05-30 +#### [1.0.10](https://github.com/rdkcentral/control/compare/1.0.9...1.0.10) -### Changed -- move thunder and IARM dependencies from irdb to ctrlm -- load irdb library as a plugin with dlopen -- use AVInput instead of HDMI Input thunder plugin for HDMI Infoframes +> 4 June 2025 -### Added -- new interface to ctrlm IRDB -- Default BLE controller type list -- RF4CE network discovery at runtime instead of compile time +- RDKEMW-4424: update CHANGELOG for release 1.0.10 [`#55`](https://github.com/rdkcentral/control/pull/55) +- RDKEMW-3916: ctrlm crash from main queue msgs getting to networks prior to initialization [`#38`](https://github.com/rdkcentral/control/pull/38) +- RDKEMW-4146: ctrlm support both old and new deviceType [`#48`](https://github.com/rdkcentral/control/pull/48) +- RDKEMW-3918 : Control manager crashes on rapid MIC button presses [`#42`](https://github.com/rdkcentral/control/pull/42) +- RDK-56578 : Changed deviceType from tv to IpTv. [`#34`](https://github.com/rdkcentral/control/pull/34) +- RDKEMW-3609 : extend adpcm frame info [`#28`](https://github.com/rdkcentral/control/pull/28) +- RDKEMW-3916: IARM calls registered too early [`ae82b1e`](https://github.com/rdkcentral/control/commit/ae82b1e66f70d6f621eb3c680b7bf870379bd84c) +- RDKEMW-3835 - [Logging] Add Invalid firmware version OTA error code (0x8) mapping in ctrlmgr logs [`80e4d59`](https://github.com/rdkcentral/control/commit/80e4d59e841f3e9744fc6d3dd92b8bccec26c3ea) -### Fixed -- crash during OTA interrupted by unpair or reset +#### [1.0.9](https://github.com/rdkcentral/control/compare/1.0.8...1.0.9) +> 7 May 2025 -## [1.0.10] - 2025-05-16 +- update CHANGELOG for controlMgr release 1.0.9 [`#35`](https://github.com/rdkcentral/control/pull/35) +- RDKEMW-3737:Upgrading the halif-headers as iarmmgr [`#30`](https://github.com/rdkcentral/control/pull/30) +- RDKEMW-3564 : Audio samples is always reported as 0 for FFV sessions [`2920c1a`](https://github.com/rdkcentral/control/commit/2920c1a455d1e1afe1d095c0b09fd841a305974d) +- RDKEMW-3605: Remove 'volatile' type qualifier of "binding_in_progress" [`a7d2310`](https://github.com/rdkcentral/control/commit/a7d23104a3b961a26621a1c688ba775c3fe2ad3f) -### Changed -- ctrlm crash from main queue msgs getting to networks prior to initialization -- ctrlm support both old and new deviceType -- Control manager crashes on rapid MIC button presses -- [Logging] Add Invalid firmware version OTA error code (0x8) mapping in ctrlmgr logs -- Changed deviceType from tv to IpTv. -- Extend adpcm frame info. +#### [1.0.8](https://github.com/rdkcentral/control/compare/1.0.7...1.0.8) +> 28 April 2025 -## [1.0.9] - 2025-04-28 +- update CHANGELOG for controlMgr release 1.0.8 [`#25`](https://github.com/rdkcentral/control/pull/25) +- RDKEMW-3276: common udev node and provide list of possible names for IR input device discovery [`#20`](https://github.com/rdkcentral/control/pull/20) -### Changed -- Audio samples is always reported as 0 for FFV sessions -- Remove 'volatile' type qualifier of "binding_in_progress" -- Upgrading the halif-headers as iarmmgr +#### [1.0.7](https://github.com/rdkcentral/control/compare/1.0.6...1.0.7) +> 10 April 2025 -## [1.0.8] - 2025-04-15 - -### Changed -- use list of all possible names for IR input device discovery instead of product specific config - - -## [1.0.7] - 2025-03-31 - -### Changed +- XCTRL-400: add irdb stub implementation if ctrlm-hal-irdb lib does not exist [`#17`](https://github.com/rdkcentral/control/pull/17) +- Merge pull request #14 from rdkcentral/feature/XCTRL-400_rdkv_code_sy… [`#16`](https://github.com/rdkcentral/control/pull/16) +- XCTRL-400: RDKE Release 2025-03-31 (ctrlm v1.0.7) [`#14`](https://github.com/rdkcentral/control/pull/14) - Rationalize Voice Logging - move auth from ctrlm-cpc to ctrlm-main - Add ctrlm HAL certificate interace - Remove irMgr dependencies in controlMgr - create HAL interface for platform specific IRDBs - -### Added - BLE audio stream end time telemetry - voice stream telemetry in single line/event - -### Fixed - Type-Z OTA bug - Remote type changed to type-Z early - controlMgr maintenance time crash at onInitializedTimer @@ -145,28 +135,35 @@ All notable changes to this project will be documented in this file. - Logline error event rcu firmware status -## [1.0.6] - 2025-03-18 +#### [1.0.6](https://github.com/rdkcentral/control/compare/1.0.5...1.0.6) -### Added +> 18 March 2025 + +- RDKEMW-1397: IR input device name move to config file [`#1`](https://github.com/rdkcentral/control/pull/1) +- RDKEMW-1783: controlMgr crash at onInitializedTimer when going to dee… [`#11`](https://github.com/rdkcentral/control/pull/11) - custom target to build ctrlm config file only - additional config override file that can be provided by vendor layer +#### [1.0.5](https://github.com/rdkcentral/control/compare/1.0.4...1.0.5) + +> 25 February 2025 -## [1.0.5] - 2025-02-24 +- RDKEMW-1783: controlMgr crash at onInitializedTimer when going to deepsleep [`#10`](https://github.com/rdkcentral/control/pull/10) -### Changed -- crash at onInitializedTimer when going to deepsleep +#### [1.0.4](https://github.com/rdkcentral/control/compare/1.0.3...1.0.4) +> 25 February 2025 -## [1.0.4] - 2025-02-20 +- RDKEMW-1890: Remove irMgr dependencies in controlMgr [`#6`](https://github.com/rdkcentral/control/pull/6) -### Changed -- removed references to deprecated irMgr component +#### 1.0.3 -## [1.0.3] - 2025-02-07 +> 13 February 2025 -### Changed +- XCTRL-379: CTRLM RDKE Release 2025-02-07 [`#4`](https://github.com/rdkcentral/control/pull/4) +- XCTRL-379: CTRLM RDKE Release 2025-02-07 [`#3`](https://github.com/rdkcentral/control/pull/3) +- Import of source (develop) [`83e2f7b`](https://github.com/rdkcentral/control/commit/83e2f7bd1f5a179b47e0278f49e17466f4b1c457) - check that a file descriptor is valid before FD_SET() - standardize use of singleton pattern ctrlm - speed up BLE auto pairing and surface failures immediately @@ -176,16 +173,13 @@ All notable changes to this project will be documented in this file. - remove legacy url_vrex config field - Add ctrlm Support for XRA BLE key - QAM - ControlMgr crash pairWithMacHash when going to deepsleep - -### Added - RemoteControl plugin methods to pair and unpair targetted RCU devices based on MAC - RemoteControl plugin methods to trigger RCU firmware upgrade and report status of upgrade - ctrlm-factory added to this repo, its no longer a separate repo +#### 1.0.2 -## [1.0.2] - 2024-12-06 - -### Changed +> 6 December 2024 - ctrlm IR uinput device match exact name, simplify IR-initiated BLE pairing event handling - Check for Invalid avDevType - move stop audio stream to separate non iarm related function @@ -194,7 +188,5 @@ All notable changes to this project will be documented in this file. - Detect the platform type (TV vs STB) using DeviceInfo plugin - IR keypresses use same PII mask variable as Voice - fix "last wakeup key code" not received, along with defering gdbus proxy calls for characteristics until they are needed. - -### Added - unit test function to set IR protocol support characteristic on RCU - Added Alexa voice service support in SDT endpoint, along with async voice message support From 47055905f3409ff0e4b53652c14f59268fe6bee5 Mon Sep 17 00:00:00 2001 From: dwolaver <44593664+dwolaver@users.noreply.github.com> Date: Thu, 13 Nov 2025 10:14:03 -0500 Subject: [PATCH 02/81] RDKEMW-10311 : RF4CE update key mapping (#140) --- src/input_event/ctrlm_input_event_writer.h | 3 ++- src/rf4ce/ctrlm_rf4ce_network.cpp | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/input_event/ctrlm_input_event_writer.h b/src/input_event/ctrlm_input_event_writer.h index 54d7c51d..c05876e0 100644 --- a/src/input_event/ctrlm_input_event_writer.h +++ b/src/input_event/ctrlm_input_event_writer.h @@ -66,7 +66,7 @@ const std::map ctrlm_key_to_linux_map {CTRLM_KEY_CODE_CH_DOWN, linux_ui_code_values_t(KEY_PAGEDOWN, 0x59, KEY_LEFTCTRL)}, {CTRLM_KEY_CODE_LAST, linux_ui_code_values_t(KEY_ESC, 0x0, KEY_LEFTCTRL)}, {CTRLM_KEY_CODE_INPUT_SELECT, linux_ui_code_values_t(KEY_F15, 0x0, KEY_RESERVED)}, - {CTRLM_KEY_CODE_INFO, linux_ui_code_values_t(KEY_F9, 0xcb, KEY_LEFTCTRL)}, + {CTRLM_KEY_CODE_INFO, linux_ui_code_values_t(KEY_F20, 0x0, KEY_RESERVED)}, {CTRLM_KEY_CODE_VOL_UP, linux_ui_code_values_t(KEY_KPPLUS, 0x0, KEY_RESERVED)}, {CTRLM_KEY_CODE_VOL_DOWN, linux_ui_code_values_t(KEY_KPMINUS, 0x0, KEY_RESERVED)}, {CTRLM_KEY_CODE_MUTE, linux_ui_code_values_t(KEY_KPASTERISK, 0x0, KEY_RESERVED)}, @@ -86,6 +86,7 @@ const std::map ctrlm_key_to_linux_map {CTRLM_KEY_CODE_OCAP_C, linux_ui_code_values_t(KEY_RESERVED, 0x0, KEY_RESERVED)}, {CTRLM_KEY_CODE_OCAP_D, linux_ui_code_values_t(KEY_RESERVED, 0x0, KEY_RESERVED)}, {CTRLM_KEY_CODE_ASTERISK, linux_ui_code_values_t(KEY_F14, 0x0, KEY_RESERVED)}, + {CTRLM_KEY_CODE_PUSH_TO_TALK, linux_ui_code_values_t(KEY_F8, 0x0, KEY_RESERVED)} }; enum class key_stroke { diff --git a/src/rf4ce/ctrlm_rf4ce_network.cpp b/src/rf4ce/ctrlm_rf4ce_network.cpp index f01c52d5..de5a22ff 100644 --- a/src/rf4ce/ctrlm_rf4ce_network.cpp +++ b/src/rf4ce/ctrlm_rf4ce_network.cpp @@ -3660,6 +3660,11 @@ void ctrlm_obj_network_rf4ce_t::ind_process_voice_session_request(void *data, in device_type = CTRLM_VOICE_DEVICE_FF; } + if(device_type == CTRLM_VOICE_DEVICE_PTT) { + // Send voice key down event since the session was requested + process_event_key(dqm->controller_id, CTRLM_KEY_STATUS_DOWN, CTRLM_KEY_CODE_PUSH_TO_TALK); + } + bool command_status = (controller_type == RF4CE_CONTROLLER_TYPE_XR11 || controller_type == RF4CE_CONTROLLER_TYPE_XR19) ? true : false; @@ -3842,6 +3847,11 @@ void ctrlm_obj_network_rf4ce_t::ind_process_voice_session_request(void *data, in property.state = CTRLM_HAL_FREQUENCY_AGILITY_ENABLE; ctrlm_network_property_set(network_id_get(), CTRLM_HAL_NETWORK_PROPERTY_FREQUENCY_AGILITY, (void *)&property, sizeof(property)); } + + if(device_type == CTRLM_VOICE_DEVICE_PTT) { + // Send voice key up event since the session was not accepted + process_event_key(dqm->controller_id, CTRLM_KEY_STATUS_UP, CTRLM_KEY_CODE_PUSH_TO_TALK); + } } if(dqm->status != VOICE_SESSION_RESPONSE_AVAILABLE && dqm->status != VOICE_SESSION_RESPONSE_AVAILABLE_SKIP_CHAN_CHECK) { // Session was aborted @@ -3937,6 +3947,17 @@ void ctrlm_obj_network_rf4ce_t::ind_process_voice_session_stop(void *data, int s g_assert(dqm); g_assert(size == sizeof(ctrlm_main_queue_msg_voice_session_stop_t)); + if(!controller_exists(dqm->controller_id)) { + XLOGD_INFO("invalid controller id (%u)", dqm->controller_id); + return; + } + + ctrlm_rf4ce_controller_type_t controller_type = controllers_[dqm->controller_id]->controller_type_get(); + if(!ctrlm_is_voice_assistant((ctrlm_rcu_controller_type_t) controller_type)) { + // Send voice key up event since the session stop was received + process_event_key(dqm->controller_id, CTRLM_KEY_STATUS_UP, CTRLM_KEY_CODE_PUSH_TO_TALK); + } + // Check adjacent key press if(CTRLM_VOICE_SESSION_END_REASON_OTHER_KEY_PRESSED == dqm->session_end_reason && true == is_key_adjacent(dqm->controller_id, dqm->key_code)) { dqm->session_end_reason = CTRLM_VOICE_SESSION_END_REASON_ADJACENT_KEY_PRESSED; From 07c0c95bb7591d17119c48227b54565d10dbd49f Mon Sep 17 00:00:00 2001 From: Kelvin Lu <119349872+klu339@users.noreply.github.com> Date: Mon, 17 Nov 2025 08:46:47 -0500 Subject: [PATCH 03/81] Revert "RDKEMW-8929 (#129)" (#145) This reverts commit b47d6f80fb75d1e00a647cc1802ae170272373a5. --- include/ctrlm_ipc_voice.h | 8 +- src/ipc/ctrlm_ipc_iarm.cpp | 44 +++++++-- src/ipc/ctrlm_ipc_iarm.h | 23 +---- src/ipc/ctrlm_rcp_ipc_event.cpp | 17 ++-- src/ipc/ctrlm_rcp_ipc_event.h | 16 ++-- src/ipc/ctrlm_rcp_ipc_iarm_thunder.cpp | 30 ++++++- src/voice/ipc/ctrlm_voice_ipc.h | 5 +- src/voice/ipc/ctrlm_voice_ipc_iarm_legacy.cpp | 25 ++++-- .../ipc/ctrlm_voice_ipc_iarm_thunder.cpp | 90 ++++++++++++++++--- 9 files changed, 187 insertions(+), 71 deletions(-) diff --git a/include/ctrlm_ipc_voice.h b/include/ctrlm_ipc_voice.h index 270b92d9..d5a58bc0 100644 --- a/include/ctrlm_ipc_voice.h +++ b/include/ctrlm_ipc_voice.h @@ -304,11 +304,11 @@ typedef struct { // IARM Event JSON // This structure is used for the following calls: -// CTRLM_VOICE_IARM_EVENT_SESSION_BEGIN_JSON -// CTRLM_VOICE_IARM_EVENT_STREAM_BEGIN_JSON +// CTRLM_VOICE_IARM_EVENT_SESSION_BEGIN_JSON +// CTRLM_VOICE_IARM_EVENT_STREAM_BEGIN_JSON // CTRLM_VOICE_IARM_EVENT_SERVER_MESSAGE_JSON -// CTRLM_VOICE_IARM_EVENT_STREAM_END_JSON -// CTRLM_VOICE_IARM_EVENT_SESSION_END_JSON +// CTRLM_VOICE_IARM_EVENT_STREAM_END_JSON +// CTRLM_VOICE_IARM_EVENT_SESSION_END_JSON // // The payload MUST be a NULL terminated JSON String. typedef struct { diff --git a/src/ipc/ctrlm_ipc_iarm.cpp b/src/ipc/ctrlm_ipc_iarm.cpp index 6d960196..b8d16842 100644 --- a/src/ipc/ctrlm_ipc_iarm.cpp +++ b/src/ipc/ctrlm_ipc_iarm.cpp @@ -35,12 +35,44 @@ bool ctrlm_ipc_iarm_t::register_iarm_call(const char *call, IARM_BusCall_t handl return(ret); } -bool ctrlm_ipc_iarm_t::broadcast_iarm_event_legacy(const char *bus_name, int event, void *data, size_t data_size) const { - bool ret = true; - IARM_Result_t result = IARM_Bus_BroadcastEvent(bus_name, event, data, data_size); - if(IARM_RESULT_SUCCESS != result) { - XLOGD_ERROR("IARM Bus Error!"); - ret = false; +bool ctrlm_ipc_iarm_t::broadcast_iarm_event(const char *bus_name, int event, json_t* event_data) const +{ + bool ret = false; + if(!event_data) { + return(ret); } + + char *payload_str = json_dumps(event_data, JSON_COMPACT); + + if(payload_str != NULL) { + size_t str_size = strlen(payload_str) + 1; + size_t size = sizeof(ctrlm_main_iarm_event_json_t) + str_size; + + ctrlm_main_iarm_event_json_t *data = (ctrlm_main_iarm_event_json_t *)calloc(1, size); + if (data == NULL) { + XLOGD_ERROR("failed to allocate memory for the IARM event, so cannot broadcast...."); + } else { + + data->api_revision = CTRLM_MAIN_IARM_BUS_API_REVISION; + //Can't be replaced with safeC version of this, as safeC string functions doesn't allow string size more than 4K + snprintf(data->payload, str_size, "%s", payload_str); + + IARM_Result_t res = IARM_Bus_BroadcastEvent(bus_name, event, data, size); + if(res != IARM_RESULT_SUCCESS) { + XLOGD_ERROR("IARM Bus Error %d", res); + } else { + ret = true; + } + + free(data); + } + + free(payload_str); + } + + if(event_data) { + json_decref(event_data); + } + return(ret); } diff --git a/src/ipc/ctrlm_ipc_iarm.h b/src/ipc/ctrlm_ipc_iarm.h index 78568186..c966c080 100644 --- a/src/ipc/ctrlm_ipc_iarm.h +++ b/src/ipc/ctrlm_ipc_iarm.h @@ -39,28 +39,7 @@ class ctrlm_ipc_iarm_t { static void turn_off(std::atomic_bool &abool) { abool.store(false); } bool register_iarm_call(const char *call, IARM_BusCall_t handler) const; - bool broadcast_iarm_event_legacy(const char *bus_name, int event, void *data, size_t data_size) const; - - template - bool broadcast_iarm_event(const char *bus_name, unsigned char api_revision, int event, const char *str) const { - bool ret = false; - size_t str_size = strlen(str) + 1; - size_t size = sizeof(T) + str_size; - T *data = (T *)calloc(1, size); - data->api_revision = api_revision; - if(!data) { - return(ret); - } else { - snprintf(data->payload, str_size, "%s", str); - if(IARM_Bus_BroadcastEvent(bus_name, event, data, size)) { - ret = true; - } - if(data) { - free(data); - } - } - return(ret); - } + bool broadcast_iarm_event(const char *bus_name, int event, json_t* event_data) const; }; #endif diff --git a/src/ipc/ctrlm_rcp_ipc_event.cpp b/src/ipc/ctrlm_rcp_ipc_event.cpp index 5c24208e..0ce44bae 100644 --- a/src/ipc/ctrlm_rcp_ipc_event.cpp +++ b/src/ipc/ctrlm_rcp_ipc_event.cpp @@ -135,12 +135,9 @@ void ctrlm_rcp_ipc_net_status_t::populate_status(const ctrlm_obj_network_t &netw } } -std::string ctrlm_base_event_json_t::to_string() const +char *ctrlm_rcp_ipc_net_status_t::to_string() const { - char *json_str = json_dumps(to_json(), JSON_ENCODE_ANY); - std::string copy = json_str; - free(json_str); - return copy; + return json_dumps(to_json(), JSON_ENCODE_ANY); } ctrlm_rcp_ipc_upgrade_status_t::~ctrlm_rcp_ipc_upgrade_status_t() @@ -173,6 +170,11 @@ json_t *ctrlm_rcp_ipc_upgrade_status_t::to_json() const return (err) ? NULL : status; } +char *ctrlm_rcp_ipc_upgrade_status_t::to_string() const +{ + return json_dumps(to_json(), JSON_ENCODE_ANY); +} + ctrlm_rcp_ipc_validation_status_t::~ctrlm_rcp_ipc_validation_status_t() { } @@ -214,3 +216,8 @@ json_t *ctrlm_rcp_ipc_validation_status_t::to_json() const return (err) ? NULL : status; } + +char *ctrlm_rcp_ipc_validation_status_t::to_string() const +{ + return json_dumps(to_json(), JSON_ENCODE_ANY); +} diff --git a/src/ipc/ctrlm_rcp_ipc_event.h b/src/ipc/ctrlm_rcp_ipc_event.h index bf31a823..ae257af6 100644 --- a/src/ipc/ctrlm_rcp_ipc_event.h +++ b/src/ipc/ctrlm_rcp_ipc_event.h @@ -63,18 +63,17 @@ namespace rcp_net_status_json_keys constexpr char const* ERROR_STRING = "errorString"; } -class ctrlm_base_event_json_t +class ctrlm_virtual_json_t { public: - virtual ~ctrlm_base_event_json_t() {}; + virtual ~ctrlm_virtual_json_t() {}; virtual json_t *to_json() const = 0; - virtual std::string to_string() const; }; class ctrlm_obj_controller_t; class ctrlm_obj_network_t; -class ctrlm_rcp_ipc_controller_status_t : public ctrlm_base_event_json_t +class ctrlm_rcp_ipc_controller_status_t : public ctrlm_virtual_json_t { public: ctrlm_rcp_ipc_controller_status_t() = default; @@ -104,7 +103,7 @@ class ctrlm_rcp_ipc_controller_status_t : public ctrlm_base_event_json_t std::string upgrade_session_id_ = ""; }; -class ctrlm_rcp_ipc_net_status_t : public ctrlm_base_event_json_t +class ctrlm_rcp_ipc_net_status_t : public ctrlm_virtual_json_t { public: ctrlm_rcp_ipc_net_status_t() = default; @@ -112,6 +111,7 @@ class ctrlm_rcp_ipc_net_status_t : public ctrlm_base_event_json_t virtual json_t *to_json() const; + char *to_string() const; uint8_t get_api_revision() const { return api_revision_; } bool get_result() const { return (result_ == CTRLM_IARM_CALL_RESULT_SUCCESS) ? true : false; } void set_result(ctrlm_iarm_call_result_t result) { result_ = result; } @@ -131,13 +131,14 @@ class ctrlm_rcp_ipc_net_status_t : public ctrlm_base_event_json_t std::vector controller_status_list_; }; -class ctrlm_rcp_ipc_upgrade_status_t : public ctrlm_base_event_json_t +class ctrlm_rcp_ipc_upgrade_status_t : public ctrlm_virtual_json_t { public: ctrlm_rcp_ipc_upgrade_status_t() = default; ~ctrlm_rcp_ipc_upgrade_status_t(); virtual json_t *to_json() const; + char *to_string() const; bool get_result() const { return (result_ == CTRLM_IARM_CALL_RESULT_SUCCESS) ? true : false; } void set_result(ctrlm_iarm_call_result_t result) { result_ = result; } ctrlm_network_id_t get_net_id() const { return net_id_; } @@ -155,13 +156,14 @@ class ctrlm_rcp_ipc_upgrade_status_t : public ctrlm_base_event_json_t ctrlm_iarm_call_result_t result_ = CTRLM_IARM_CALL_RESULT_INVALID; }; -class ctrlm_rcp_ipc_validation_status_t : public ctrlm_base_event_json_t +class ctrlm_rcp_ipc_validation_status_t : public ctrlm_virtual_json_t { public: ctrlm_rcp_ipc_validation_status_t() = default; ~ctrlm_rcp_ipc_validation_status_t(); virtual json_t *to_json() const; + char *to_string() const; uint8_t get_api_revision() const { return api_revision_; } bool get_result() const { return (result_ == CTRLM_IARM_CALL_RESULT_SUCCESS) ? true : false; } void set_result(ctrlm_iarm_call_result_t result) { result_ = result; } diff --git a/src/ipc/ctrlm_rcp_ipc_iarm_thunder.cpp b/src/ipc/ctrlm_rcp_ipc_iarm_thunder.cpp index 82a005bc..02f4128d 100644 --- a/src/ipc/ctrlm_rcp_ipc_iarm_thunder.cpp +++ b/src/ipc/ctrlm_rcp_ipc_iarm_thunder.cpp @@ -114,7 +114,18 @@ bool ctrlm_rcp_ipc_iarm_thunder_t::on_status(const ctrlm_rcp_ipc_net_status_t &n return(false); } - return broadcast_iarm_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_MAIN_IARM_BUS_API_REVISION, CTRLM_RCU_IARM_EVENT_RCU_STATUS, net_status.to_string().c_str()); + json_t *ret = json_object(); + int err = 0; + + err |= json_object_set_new_nocheck(ret, STATUS, net_status.to_json()); + + if (err) { + XLOGD_ERROR("JSON object set error"); + json_decref(ret); + return(false); + } + + return broadcast_iarm_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_RCU_IARM_EVENT_RCU_STATUS, ret); } bool ctrlm_rcp_ipc_iarm_thunder_t::on_validation_status(const ctrlm_rcp_ipc_validation_status_t &validation_status) const @@ -129,7 +140,18 @@ bool ctrlm_rcp_ipc_iarm_thunder_t::on_validation_status(const ctrlm_rcp_ipc_vali return(false); } - return broadcast_iarm_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_MAIN_IARM_BUS_API_REVISION, CTRLM_RCU_IARM_EVENT_VALIDATION_STATUS, validation_status.to_string().c_str()); + json_t *ret = json_object(); + int err = 0; + + err |= json_object_set_new_nocheck(ret, STATUS, validation_status.to_json()); + + if (err) { + XLOGD_ERROR("JSON object set error"); + json_decref(ret); + return(false); + } + + return broadcast_iarm_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_RCU_IARM_EVENT_VALIDATION_STATUS, ret); } bool ctrlm_rcp_ipc_iarm_thunder_t::on_firmware_update_progress(const ctrlm_rcp_ipc_upgrade_status_t &upgrade_status) const @@ -155,7 +177,7 @@ bool ctrlm_rcp_ipc_iarm_thunder_t::on_firmware_update_progress(const ctrlm_rcp_i return(false); } - return broadcast_iarm_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_MAIN_IARM_BUS_API_REVISION, CTRLM_RCU_IARM_EVENT_FIRMWARE_UPDATE_PROGRESS, upgrade_status.to_string().c_str()); + return broadcast_iarm_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_RCU_IARM_EVENT_FIRMWARE_UPDATE_PROGRESS, ret); } bool ctrlm_rcp_ipc_iarm_thunder_t::on_validation(const ctrlm_rcp_ipc_validation_status_t &validation_status) const @@ -176,7 +198,7 @@ bool ctrlm_rcp_ipc_iarm_thunder_t::on_validation(const ctrlm_rcp_ipc_validation_ return(false); } - return broadcast_iarm_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_MAIN_IARM_BUS_API_REVISION, CTRLM_RCU_IARM_EVENT_VALIDATION_STATUS, validation_status.to_string().c_str()); + return broadcast_iarm_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_RCU_IARM_EVENT_VALIDATION_STATUS, ret); } IARM_Result_t ctrlm_rcp_ipc_iarm_thunder_t::start_pairing(void *arg) diff --git a/src/voice/ipc/ctrlm_voice_ipc.h b/src/voice/ipc/ctrlm_voice_ipc.h index 969a8380..25197ff8 100644 --- a/src/voice/ipc/ctrlm_voice_ipc.h +++ b/src/voice/ipc/ctrlm_voice_ipc.h @@ -22,7 +22,6 @@ #include "ctrlm.h" #include "ctrlm_voice_types.h" #include "ctrlm_ipc_voice.h" -#include "ctrlm_ipc_iarm.h" // Classes for eventing @@ -172,7 +171,7 @@ class ctrlm_voice_ipc_event_session_statistics_t { }; // End classes for eventing -class ctrlm_voice_ipc_t : public ctrlm_ipc_iarm_t { +class ctrlm_voice_ipc_t { public: ctrlm_voice_ipc_t(ctrlm_voice_t *obj_voice) { this->obj_voice = obj_voice; @@ -180,6 +179,7 @@ class ctrlm_voice_ipc_t : public ctrlm_ipc_iarm_t { virtual ~ctrlm_voice_ipc_t() {}; // Interface + virtual bool register_ipc() const = 0; virtual bool session_begin(const ctrlm_voice_ipc_event_session_begin_t &session_begin) = 0; virtual bool stream_begin(const ctrlm_voice_ipc_event_stream_begin_t &stream_begin) = 0; virtual bool stream_end(const ctrlm_voice_ipc_event_stream_end_t &stream_end) = 0; @@ -187,6 +187,7 @@ class ctrlm_voice_ipc_t : public ctrlm_ipc_iarm_t { virtual bool server_message(const char *message, unsigned long size) = 0; // Pass a pointer to the message to avoid copying possible large chunks of data virtual bool keyword_verification(const ctrlm_voice_ipc_event_keyword_verification_t &keyword_verification) = 0; virtual bool session_statistics(const ctrlm_voice_ipc_event_session_statistics_t &session_stats) = 0; + virtual void deregister_ipc() const = 0; // End Interface protected: diff --git a/src/voice/ipc/ctrlm_voice_ipc_iarm_legacy.cpp b/src/voice/ipc/ctrlm_voice_ipc_iarm_legacy.cpp index 1121e795..c07f22b1 100644 --- a/src/voice/ipc/ctrlm_voice_ipc_iarm_legacy.cpp +++ b/src/voice/ipc/ctrlm_voice_ipc_iarm_legacy.cpp @@ -23,6 +23,7 @@ #include "ctrlm_voice_obj.h" static IARM_Result_t update_settings(void *arg); +static bool broadcast_event(const char *bus_name, int event, void *data, size_t data_size); ctrlm_voice_ipc_iarm_legacy_t::ctrlm_voice_ipc_iarm_legacy_t(ctrlm_voice_t *obj_voice) : ctrlm_voice_ipc_t(obj_voice) { this->state = EVENT_ALL; @@ -67,7 +68,7 @@ bool ctrlm_voice_ipc_iarm_legacy_t::session_begin(const ctrlm_voice_ipc_event_se safec_rc = strcpy_s((char *)event.language, sizeof(event.language), session_begin.language.c_str()); ERR_CHK(safec_rc); event.is_voice_assistant = session_begin.common.voice_assistant ? 1 : 0; - ret = broadcast_iarm_event_legacy(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_SESSION_BEGIN, &event, sizeof(event)); + ret = broadcast_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_SESSION_BEGIN, &event, sizeof(event)); } return(ret); } @@ -89,7 +90,7 @@ bool ctrlm_voice_ipc_iarm_legacy_t::stream_end(const ctrlm_voice_ipc_event_strea event.session_id = stream_end.common.session_id_ctrlm; event.reason = (ctrlm_voice_session_end_reason_t)stream_end.reason; event.is_voice_assistant = stream_end.common.voice_assistant ? 1 : 0; - ret = broadcast_iarm_event_legacy(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_SESSION_END, &event, sizeof(event)); + ret = broadcast_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_SESSION_END, &event, sizeof(event)); } return(ret); } @@ -132,7 +133,7 @@ bool ctrlm_voice_ipc_iarm_legacy_t::session_end(const ctrlm_voice_ipc_event_sess event.curl_request_dns_time = session_end.server_stats->dns_time; event.curl_request_connect_time = session_end.server_stats->connect_time; } - ret = broadcast_iarm_event_legacy(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_SESSION_RESULT, &event, sizeof(event)); + ret = broadcast_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_SESSION_RESULT, &event, sizeof(event)); break; } case SESSION_END_ABORT: { @@ -143,7 +144,7 @@ bool ctrlm_voice_ipc_iarm_legacy_t::session_end(const ctrlm_voice_ipc_event_sess event.controller_id = session_end.common.controller_id; event.session_id = session_end.common.session_id_ctrlm; event.reason = (ctrlm_voice_session_abort_reason_t)session_end.reason; - ret = broadcast_iarm_event_legacy(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_SESSION_ABORT, &event, sizeof(event)); + ret = broadcast_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_SESSION_ABORT, &event, sizeof(event)); break; } case SESSION_END_SHORT_UTTERANCE: { @@ -155,7 +156,7 @@ bool ctrlm_voice_ipc_iarm_legacy_t::session_end(const ctrlm_voice_ipc_event_sess event.session_id = session_end.common.session_id_ctrlm; event.reason = (ctrlm_voice_session_end_reason_t)session_end.reason; event.return_code_internal = session_end.return_code_internal; - ret = broadcast_iarm_event_legacy(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_SESSION_SHORT, &event, sizeof(event)); + ret = broadcast_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_SESSION_SHORT, &event, sizeof(event)); break; } } @@ -194,7 +195,7 @@ bool ctrlm_voice_ipc_iarm_legacy_t::session_statistics(const ctrlm_voice_ipc_eve event.session_id = session_stats.common.session_id_ctrlm; event.session = session_stats.session; event.reboot = session_stats.reboot; - return(broadcast_iarm_event_legacy(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_SESSION_STATS, &event, sizeof(event))); + return(broadcast_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_SESSION_STATS, &event, sizeof(event))); } void ctrlm_voice_ipc_iarm_legacy_t::deregister_ipc() const { @@ -228,4 +229,14 @@ IARM_Result_t update_settings(void *arg) { } return(IARM_RESULT_SUCCESS); -} \ No newline at end of file +} + +bool broadcast_event(const char *bus_name, int event, void *data, size_t data_size) { + bool ret = true; + IARM_Result_t result = IARM_Bus_BroadcastEvent(bus_name, event, data, data_size); + if(IARM_RESULT_SUCCESS != result) { + XLOGD_ERROR("IARM Bus Error!"); + ret = false; + } + return(ret); +} diff --git a/src/voice/ipc/ctrlm_voice_ipc_iarm_thunder.cpp b/src/voice/ipc/ctrlm_voice_ipc_iarm_thunder.cpp index ad9cc5db..1dfa80b8 100644 --- a/src/voice/ipc/ctrlm_voice_ipc_iarm_thunder.cpp +++ b/src/voice/ipc/ctrlm_voice_ipc_iarm_thunder.cpp @@ -83,6 +83,7 @@ #define JSON_SESSION_END_SERVER_STATS_DNS_TIME "dnsTime" #define JSON_SESSION_END_SERVER_STATS_CONNECT_TIME "connectTime" +static bool broadcast_event(const char *bus_name, int event, const char *str); static const char *voice_device_str(ctrlm_voice_device_t device); static const char *voice_device_status_str(uint8_t status); @@ -92,31 +93,63 @@ ctrlm_voice_ipc_iarm_thunder_t::ctrlm_voice_ipc_iarm_thunder_t(ctrlm_voice_t *ob bool ctrlm_voice_ipc_iarm_thunder_t::register_ipc() const { bool ret = true; + IARM_Result_t rc; XLOGD_INFO("Thunder"); // NOTE: The IARM events are registered in ctrlm_main.cpp - if(!register_iarm_call(CTRLM_VOICE_IARM_CALL_STATUS, &ctrlm_voice_ipc_iarm_thunder_t::status)) { + XLOGD_INFO("Registering for %s IARM call", CTRLM_VOICE_IARM_CALL_STATUS); + rc = IARM_Bus_RegisterCall(CTRLM_VOICE_IARM_CALL_STATUS, &ctrlm_voice_ipc_iarm_thunder_t::status); + if(rc != IARM_RESULT_SUCCESS) { + XLOGD_ERROR("Failed to register %d", rc); ret = false; } - if(!register_iarm_call(CTRLM_VOICE_IARM_CALL_CONFIGURE_VOICE, &ctrlm_voice_ipc_iarm_thunder_t::configure_voice)) { + + XLOGD_INFO("Registering for %s IARM call", CTRLM_VOICE_IARM_CALL_CONFIGURE_VOICE); + rc = IARM_Bus_RegisterCall(CTRLM_VOICE_IARM_CALL_CONFIGURE_VOICE, &ctrlm_voice_ipc_iarm_thunder_t::configure_voice); + if(rc != IARM_RESULT_SUCCESS) { + XLOGD_ERROR("Failed to register %d", rc); ret = false; } - if(!register_iarm_call(CTRLM_VOICE_IARM_CALL_SET_VOICE_INIT, &ctrlm_voice_ipc_iarm_thunder_t::set_voice_init)) { + + XLOGD_INFO("Registering for %s IARM call", CTRLM_VOICE_IARM_CALL_SET_VOICE_INIT); + rc = IARM_Bus_RegisterCall(CTRLM_VOICE_IARM_CALL_SET_VOICE_INIT, &ctrlm_voice_ipc_iarm_thunder_t::set_voice_init); + if(rc != IARM_RESULT_SUCCESS) { + XLOGD_ERROR("Failed to register %d", rc); ret = false; } - if(!register_iarm_call(CTRLM_VOICE_IARM_CALL_SEND_VOICE_MESSAGE, &ctrlm_voice_ipc_iarm_thunder_t::send_voice_message)) { + + XLOGD_INFO("Registering for %s IARM call", CTRLM_VOICE_IARM_CALL_SEND_VOICE_MESSAGE); + rc = IARM_Bus_RegisterCall(CTRLM_VOICE_IARM_CALL_SEND_VOICE_MESSAGE, &ctrlm_voice_ipc_iarm_thunder_t::send_voice_message); + if(rc != IARM_RESULT_SUCCESS) { + XLOGD_ERROR("Failed to register %d", rc); ret = false; } - if(!register_iarm_call(CTRLM_VOICE_IARM_CALL_SESSION_TYPES, &ctrlm_voice_ipc_iarm_thunder_t::voice_session_types)) { + + XLOGD_INFO("Registering for %s IARM call", CTRLM_VOICE_IARM_CALL_SESSION_TYPES); + rc = IARM_Bus_RegisterCall(CTRLM_VOICE_IARM_CALL_SESSION_TYPES, &ctrlm_voice_ipc_iarm_thunder_t::voice_session_types); + if(rc != IARM_RESULT_SUCCESS) { + XLOGD_ERROR("Failed to register %d", rc); ret = false; } - if(!register_iarm_call(CTRLM_VOICE_IARM_CALL_SESSION_REQUEST, &ctrlm_voice_ipc_iarm_thunder_t::voice_session_request)) { + + XLOGD_INFO("Registering for %s IARM call", CTRLM_VOICE_IARM_CALL_SESSION_REQUEST); + rc = IARM_Bus_RegisterCall(CTRLM_VOICE_IARM_CALL_SESSION_REQUEST, &ctrlm_voice_ipc_iarm_thunder_t::voice_session_request); + if(rc != IARM_RESULT_SUCCESS) { + XLOGD_ERROR("Failed to register %d", rc); ret = false; } - if(!register_iarm_call(CTRLM_VOICE_IARM_CALL_SESSION_TERMINATE, &ctrlm_voice_ipc_iarm_thunder_t::voice_session_terminate)) { + + XLOGD_INFO("Registering for %s IARM call", CTRLM_VOICE_IARM_CALL_SESSION_TERMINATE); + rc = IARM_Bus_RegisterCall(CTRLM_VOICE_IARM_CALL_SESSION_TERMINATE, &ctrlm_voice_ipc_iarm_thunder_t::voice_session_terminate); + if(rc != IARM_RESULT_SUCCESS) { + XLOGD_ERROR("Failed to register %d", rc); ret = false; } - if(!register_iarm_call(CTRLM_VOICE_IARM_CALL_SESSION_AUDIO_STREAM_START, &ctrlm_voice_ipc_iarm_thunder_t::voice_session_audio_stream_start)) { + + XLOGD_INFO("Registering for %s IARM call", CTRLM_VOICE_IARM_CALL_SESSION_AUDIO_STREAM_START); + rc = IARM_Bus_RegisterCall(CTRLM_VOICE_IARM_CALL_SESSION_AUDIO_STREAM_START, &ctrlm_voice_ipc_iarm_thunder_t::voice_session_audio_stream_start); + if(rc != IARM_RESULT_SUCCESS) { + XLOGD_ERROR("Failed to register %d", rc); ret = false; } @@ -142,7 +175,7 @@ bool ctrlm_voice_ipc_iarm_thunder_t::session_begin(const ctrlm_voice_ipc_event_s if(json_str) { //TODO: surface the event through IARM XLOGD_INFO("%s", json_str); - ret = broadcast_iarm_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_BUS_API_REVISION, CTRLM_VOICE_IARM_EVENT_JSON_SESSION_BEGIN, json_str); + ret = broadcast_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_JSON_SESSION_BEGIN, json_str); free(json_str); } else { XLOGD_ERROR("Failed to encode JSON string"); @@ -171,7 +204,7 @@ bool ctrlm_voice_ipc_iarm_thunder_t::stream_begin(const ctrlm_voice_ipc_event_st if(json_str) { //TODO: surface the event through IARM XLOGD_INFO("%s", json_str); - ret = broadcast_iarm_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_BUS_API_REVISION, CTRLM_VOICE_IARM_EVENT_JSON_STREAM_BEGIN, json_str); + ret = broadcast_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_JSON_STREAM_BEGIN, json_str); free(json_str); } else { XLOGD_ERROR("Failed to encode JSON string"); @@ -201,7 +234,7 @@ bool ctrlm_voice_ipc_iarm_thunder_t::stream_end(const ctrlm_voice_ipc_event_stre if(json_str) { //TODO: surface the event through IARM XLOGD_INFO("%s", json_str); - ret = broadcast_iarm_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_BUS_API_REVISION, CTRLM_VOICE_IARM_EVENT_JSON_STREAM_END, json_str); + ret = broadcast_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_JSON_STREAM_END, json_str); free(json_str); } else { XLOGD_ERROR("Failed to encode JSON string"); @@ -325,7 +358,7 @@ bool ctrlm_voice_ipc_iarm_thunder_t::session_end(const ctrlm_voice_ipc_event_ses if(json_str) { //TODO: surface the event through IARM XLOGD_INFO("<%s>", this->obj_voice->voice_stb_data_pii_mask_get() ? "***" : json_str); - ret = broadcast_iarm_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_BUS_API_REVISION, CTRLM_VOICE_IARM_EVENT_JSON_SESSION_END, json_str); + ret = broadcast_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_JSON_SESSION_END, json_str); free(json_str); } else { XLOGD_ERROR("Failed to encode JSON string"); @@ -341,7 +374,7 @@ bool ctrlm_voice_ipc_iarm_thunder_t::server_message(const char *message, unsigne bool ret = false; if(message) { XLOGD_INFO("%ul : <%s>", size, this->obj_voice->voice_stb_data_pii_mask_get() ? "***" : message); //CID -160950 - Printargs - ret = broadcast_iarm_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_BUS_API_REVISION, CTRLM_VOICE_IARM_EVENT_JSON_SERVER_MESSAGE, message); + ret = broadcast_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_JSON_SERVER_MESSAGE, message); } return(ret); } @@ -364,7 +397,7 @@ bool ctrlm_voice_ipc_iarm_thunder_t::keyword_verification(const ctrlm_voice_ipc_ if(json_str) { //TODO: surface the event through IARM XLOGD_INFO("%s", json_str); - ret = broadcast_iarm_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_BUS_API_REVISION, CTRLM_VOICE_IARM_EVENT_JSON_KEYWORD_VERIFICATION, json_str); + ret = broadcast_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_JSON_KEYWORD_VERIFICATION, json_str); free(json_str); } else { XLOGD_ERROR("Failed to encode JSON string"); @@ -951,6 +984,35 @@ const char *voice_device_status_str(uint8_t status) { return("invalid"); } +bool broadcast_event(const char *bus_name, int event, const char *str) { + bool ret = false; + size_t str_size = strlen(str) + 1; + size_t size = sizeof(ctrlm_voice_iarm_event_json_t) + str_size; + ctrlm_voice_iarm_event_json_t *data = (ctrlm_voice_iarm_event_json_t *)malloc(size); + if(data) { + IARM_Result_t result; + + //Can't be replaced with safeC version of this + memset(data, 0, size); + + data->api_revision = CTRLM_VOICE_IARM_BUS_API_REVISION; + //Can't be replaced with safeC version of this, as safeC string functions doesn't allow string size more than 4K + snprintf(data->payload, str_size, "%s", str); + result = IARM_Bus_BroadcastEvent(bus_name, event, data, size); + if(IARM_RESULT_SUCCESS != result) { + XLOGD_ERROR("IARM Bus Error!"); + } else { + ret = true; + } + if(data) { + free(data); + } + } else { + XLOGD_ERROR("Failed to allocate data for IARM event"); + } + return(ret); +} + bool ctrlm_voice_ipc_request_supported_ptt_transcription(ctrlm_voice_ipc_request_config_t *config) { config->requires_transcription = true; config->requires_audio_file = false; From e65264187e036f9c10fc07d98f54dbec40cee04c Mon Sep 17 00:00:00 2001 From: dwolaver <44593664+dwolaver@users.noreply.github.com> Date: Mon, 17 Nov 2025 15:41:45 -0500 Subject: [PATCH 04/81] RDKEMW-7905 : remove ctrlm build flags - ANSI_CODES_DISABLED (#110) --- CMakeLists.txt | 1 - src/ctrlm_log.h | 4 ---- src/ctrlm_main.cpp | 2 +- src/factory/ctrlmf_version.c | 2 +- 4 files changed, 2 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 61dbb8e0..55367138 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,7 +35,6 @@ project(ctrlm-main VERSION ${CMAKE_PROJECT_VERSION}) # OPTIONS option(A5000_ENABLE "ES1 A5000 use libse051" OFF) -option(ANSI_CODES_DISABLED "Disable ANSI code logging" OFF) option(ASSERT_ON_WRONG_THREAD "Assert on wrong thread" OFF) option(AUTH_ENABLED "Enable AUTH" OFF) option(BLE_ENABLED "Enable BLE" ON) diff --git a/src/ctrlm_log.h b/src/ctrlm_log.h index d804cd84..5bf0eb60 100644 --- a/src/ctrlm_log.h +++ b/src/ctrlm_log.h @@ -22,11 +22,7 @@ #include -#ifdef ANSI_CODES_DISABLED -#define XLOG_OPTS_DEFAULT (XLOG_OPTS_DATE | XLOG_OPTS_TIME | XLOG_OPTS_LF | XLOG_OPTS_MOD_NAME | XLOG_OPTS_LEVEL) -#else #define XLOG_OPTS_DEFAULT (XLOG_OPTS_DATE | XLOG_OPTS_TIME | XLOG_OPTS_LF | XLOG_OPTS_MOD_NAME | XLOG_OPTS_LEVEL | XLOG_OPTS_COLOR) -#endif #ifndef XLOG_MODULE_ID #define XLOG_MODULE_ID XLOG_MODULE_ID_CTRLM diff --git a/src/ctrlm_main.cpp b/src/ctrlm_main.cpp index e12749c5..72778ea8 100644 --- a/src/ctrlm_main.cpp +++ b/src/ctrlm_main.cpp @@ -518,7 +518,7 @@ int main(int argc, char *argv[]) { XLOGD_INFO("name <%-24s> version <%-9s> branch <%-20s> commit <%s>", entry->name ? entry->name : "NULL", entry->version ? entry->version : "NULL", entry->branch ? entry->branch : "NULL", entry->commit_id ? entry->commit_id : "NULL"); } } - vsdk_init(); + vsdk_init(true); //struct sched_param param; //param.sched_priority = 10; diff --git a/src/factory/ctrlmf_version.c b/src/factory/ctrlmf_version.c index 9fd9b69a..cffa6584 100644 --- a/src/factory/ctrlmf_version.c +++ b/src/factory/ctrlmf_version.c @@ -36,7 +36,7 @@ bool ctrlmf_init(xlog_level_t level, bool requires_audio_playback) { rdk_version_object_free(&info); - int rc = xlog_init(XLOG_MODULE_ID, NULL, 0); + int rc = xlog_init(XLOG_MODULE_ID, NULL, 0, true); xlog_level_set_all(level); if(rc != 0) { From fc5045c6514f90060ee2ede391c62c0c12830d96 Mon Sep 17 00:00:00 2001 From: dwolaver <44593664+dwolaver@users.noreply.github.com> Date: Mon, 17 Nov 2025 15:53:15 -0500 Subject: [PATCH 05/81] RDKEMW-8295 : remove ctrlm build flags - MEMORY_LOCK (#111) --- CMakeLists.txt | 6 ------ src/ctrlm_main.cpp | 38 -------------------------------------- 2 files changed, 44 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 55367138..ea865c0d 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,7 +50,6 @@ option(IP_ENABLED "Enable IP" OFF) option(LOCAL_MIC "Local Microphone" OFF) option(LOCAL_MIC_DISABLE_VIA_PRIVACY "Use Privacy to disable microphone" OFF) option(MEM_DEBUG "Enable memory debugging" OFF) -option(MEMORY_LOCK "Memory Lock" OFF) option(MIC_TAP "Enable MIC_TAP" OFF) option(RF4CE_ENABLED "Enable RF4CE" ON) option(TELEMETRY_SUPPORT "Enable TELEMETRY_SUPPORT" OFF) @@ -244,11 +243,6 @@ if(MEM_DEBUG) add_compile_definitions(MEM_DEBUG) endif() -if(MEMORY_LOCK) - add_compile_definitions(MEMORY_LOCK) - target_link_libraries(controLMgr clnl) -endif() - # RF4CE options if(RF4CE_ENABLED) # All RF4CE platforms have HAL NVM diff --git a/src/ctrlm_main.cpp b/src/ctrlm_main.cpp index 72778ea8..ed0d3fed 100644 --- a/src/ctrlm_main.cpp +++ b/src/ctrlm_main.cpp @@ -86,9 +86,6 @@ #include "xr_fdc.h" #endif #include -#ifdef MEMORY_LOCK -#include "clnl.h" -#endif using namespace std; @@ -402,17 +399,6 @@ static void control_service_values_read_from_db(); #ifdef USE_DEPRECATED_IRMGR static void ctrlm_check_for_key_tag(int key_tag) __attribute__((unused)); //USE_DEPRECATED_IRMGR #endif -#ifdef MEMORY_LOCK -const char *memory_lock_progs[] = { -"/usr/bin/controlMgr", -"/usr/lib/libctrlm_hal_rf4ce.so.0.0.0", -"/usr/lib/libxraudio.so.0.0.0", -"/usr/lib/libxraudio-hal.so.0.0.0", -"/usr/lib/libxr_mq.so.0.0.0", -"/usr/lib/libxr-timer.so.0.0.0", -"/usr/lib/libxr-timestamp.so.0.0.0" -}; -#endif #if CTRLM_HAL_RF4CE_API_VERSION >= 9 static void ctrlm_crash_recovery_check(); @@ -448,21 +434,6 @@ int main(int argc, char *argv[]) { XLOGD_INFO("name <%-24s> version <%-9s> branch <%-20s> commit <%s>", "ctrlm-main", CTRLM_MAIN_VERSION, CTRLM_MAIN_BRANCH, CTRLM_MAIN_COMMIT_ID); -#ifdef MEMORY_LOCK - clnl_init(); - for(unsigned int i = 0; i < (sizeof(memory_lock_progs) / sizeof(memory_lock_progs[0])); i++) { - if(ctrlm_file_exists(memory_lock_progs[i])) { - if(clnl_lock(memory_lock_progs[i], SECTION_TEXT)) { - XLOGD_ERROR("failed to lock instructions to memory <%s>", memory_lock_progs[i]); - } else { - XLOGD_INFO("successfully locked to memory <%s>", memory_lock_progs[i]); - } - } else { - XLOGD_DEBUG("file doesn't exist, cannot lock to memory <%s>", memory_lock_progs[i]); - } - } -#endif - ctrlm_signals_register(); #ifdef BREAKPAD_SUPPORT @@ -875,15 +846,6 @@ int main(int argc, char *argv[]) { sem_destroy(&g_ctrlm.ctrlm_utils_sem); -#ifdef MEMORY_LOCK - for(unsigned int i = 0; i < (sizeof(memory_lock_progs) / sizeof(memory_lock_progs[0])); i++) { - if(ctrlm_file_exists(memory_lock_progs[i])) { - clnl_unlock(memory_lock_progs[i], SECTION_TEXT); - } - } - clnl_destroy(); -#endif - ctrlm_config_t::destroy_instance(); ctrlm_rfc_t::destroy_instance(); #ifdef TELEMETRY_SUPPORT From 284efc8e29cc4347a959bb85a5e455386b942038 Mon Sep 17 00:00:00 2001 From: dwolaver <44593664+dwolaver@users.noreply.github.com> Date: Mon, 17 Nov 2025 15:56:23 -0500 Subject: [PATCH 06/81] RDKEMW-8296 : remove ctrlm build flags - DEEPSLEEP_CLOSE_DB (#112) --- CMakeLists.txt | 5 --- src/database/ctrlm_database.cpp | 77 ++++++++++++++------------------- 2 files changed, 33 insertions(+), 49 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ea865c0d..341b5607 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,7 +41,6 @@ option(BLE_ENABLED "Enable BLE" ON) option(BLE_SERVICES "Enable BLE Services" OFF) option(BREAKPAD "Enable BREAKPAD" OFF) option(BUILD_CTRLM_FACTORY "Build Control Factory Test" OFF) -option(DEEPSLEEP_CLOSE_DB "Deep Sleep Close DB" OFF) option(ENABLE_NETWORKED_STANDBY_MODE "Enable Networked Standby Mode)" OFF) option(FACTORY_AUDIO_PLAYBACK "Factory test audio playback" OFF) option(FACTORY_CUSTOM_AUDIO_ANALYSIS "Factory custom audio analysis" OFF) @@ -205,10 +204,6 @@ if(BREAKPAD) add_compile_definitions(BREAKPAD_SUPPORT) endif() -if(DEEPSLEEP_CLOSE_DB) - add_compile_definitions(DEEPSLEEP_CLOSE_DB) -endif() - if(ENABLE_ASYNC_SRVR_MSG) add_compile_definitions(SUPPORT_ASYNC_SRVR_MSG) endif() diff --git a/src/database/ctrlm_database.cpp b/src/database/ctrlm_database.cpp index c334cc7a..dfe2bb21 100644 --- a/src/database/ctrlm_database.cpp +++ b/src/database/ctrlm_database.cpp @@ -91,9 +91,7 @@ typedef enum { CTRLM_DB_QUEUE_MSG_TYPE_CONTROLLER_DESTROY = 5, CTRLM_DB_QUEUE_MSG_TYPE_CONTROLLER_CREATE = 6, CTRLM_DB_QUEUE_MSG_TYPE_BACKUP = 7, -#ifdef DEEPSLEEP_CLOSE_DB CTRLM_DB_QUEUE_MSG_TYPE_POWER_STATE_CHANGE = 8, -#endif CTRLM_DB_QUEUE_MSG_TYPE_WRITE_ATTR = 9, CTRLM_DB_QUEUE_MSG_TYPE_TICKLE = CTRLM_MAIN_QUEUE_MSG_TYPE_TICKLE } ctrlm_db_queue_msg_type_t; @@ -147,12 +145,10 @@ typedef struct { bool * ret; } ctrlm_db_queue_msg_backup_t; -#ifdef DEEPSLEEP_CLOSE_DB typedef struct { ctrlm_db_queue_msg_header_t header; gboolean waking_up; } ctrlm_db_queue_msg_power_state_change_t; -#endif typedef struct { sqlite3 * handle; @@ -162,10 +158,9 @@ typedef struct { GAsyncQueue * queue; sem_t semaphore; -#ifdef DEEPSLEEP_CLOSE_DB + bool deepsleep_close_db; char path[PATH_MAX]; sem_t ds_signal; -#endif vector rf4ce_network_list; vector ip_network_list; @@ -216,9 +211,7 @@ static void ctrlm_db_write_blob (const char *table, const char *key, const gucha static void ctrlm_db_write_blob_(const char *table, const char *key, const guchar *value, guint32 length); static void ctrlm_db_write_file_(const char *path, const guchar *data, guint32 length); -#ifdef DEEPSLEEP_CLOSE_DB static void ctrlm_db_power_state_change_(gboolean waking_up); -#endif static int ctrlm_db_insert_or_update(const char *table, const char *key, const int *value_int, const sqlite3_int64 *value_int64, const guchar *value_str, guint32 blob_length); #if 0 static int ctrlm_db_insert(const char *table, const char *key, const int *value_int, const char *value_str, guint32 blob_length); @@ -284,11 +277,13 @@ void ctrlm_db_close() { gboolean ctrlm_db_init(const char *db_path) { g_ctrlm_db.created_default_db = false; -#ifdef DEEPSLEEP_CLOSE_DB - errno_t safec_rc = strcpy_s(g_ctrlm_db.path, sizeof(g_ctrlm_db.path), db_path); - ERR_CHK(safec_rc); - sem_init(&g_ctrlm_db.ds_signal, 0, 0); -#endif + g_ctrlm_db.deepsleep_close_db = true; // Default to true. This can be overridden by vendor layer config as required in the future. + + if(g_ctrlm_db.deepsleep_close_db) { + errno_t safec_rc = strcpy_s(g_ctrlm_db.path, sizeof(g_ctrlm_db.path), db_path); + ERR_CHK(safec_rc); + sem_init(&g_ctrlm_db.ds_signal, 0, 0); + } // check for presence of database file and if not present, create it if(false == ctrlm_db_open(db_path)) { @@ -360,9 +355,9 @@ void ctrlm_db_terminate(void) { } } } -#ifdef DEEPSLEEP_CLOSE_DB - sem_destroy(&g_ctrlm_db.ds_signal); -#endif + if(g_ctrlm_db.deepsleep_close_db) { + sem_destroy(&g_ctrlm_db.ds_signal); + } sem_destroy(&g_ctrlm_db.semaphore); ctrlm_db_close(); @@ -399,29 +394,28 @@ bool ctrlm_db_backup() { } void ctrlm_db_power_state_change(gboolean waking_up) { -#ifdef DEEPSLEEP_CLOSE_DB - ctrlm_db_queue_msg_power_state_change_t *msg = (ctrlm_db_queue_msg_power_state_change_t *)g_malloc(sizeof(ctrlm_db_queue_msg_power_state_change_t)); - if(NULL == msg) { - XLOGD_ERROR("Failed to allocate memory"); - g_assert(0); - return; - } + if(g_ctrlm_db.deepsleep_close_db) { + ctrlm_db_queue_msg_power_state_change_t *msg = (ctrlm_db_queue_msg_power_state_change_t *)g_malloc(sizeof(ctrlm_db_queue_msg_power_state_change_t)); + if(NULL == msg) { + XLOGD_ERROR("Failed to allocate memory"); + g_assert(0); + return; + } - msg->header.type = CTRLM_DB_QUEUE_MSG_TYPE_POWER_STATE_CHANGE; - msg->waking_up = waking_up; + msg->header.type = CTRLM_DB_QUEUE_MSG_TYPE_POWER_STATE_CHANGE; + msg->waking_up = waking_up; - if(waking_up) { - ctrlm_db_queue_msg_push_front(msg); - sem_post(&g_ctrlm_db.ds_signal); + if(waking_up) { + ctrlm_db_queue_msg_push_front(msg); + sem_post(&g_ctrlm_db.ds_signal); + } else { + ctrlm_db_queue_msg_push(msg); + } } else { - ctrlm_db_queue_msg_push(msg); + XLOGD_INFO("No action for DB"); } -#else - XLOGD_INFO("No action for DB"); -#endif } -#ifdef DEEPSLEEP_CLOSE_DB void ctrlm_db_power_state_change_(gboolean waking_up) { if(waking_up == true ) { @@ -432,13 +426,10 @@ void ctrlm_db_power_state_change_(gboolean waking_up) { ctrlm_db_close(); } } -#endif gpointer ctrlm_db_thread(gpointer param) { bool running = true; -#ifdef DEEPSLEEP_CLOSE_DB bool ds_sem_wait = false; -#endif XLOGD_INFO("Started"); // Unblock the caller that launched this thread @@ -531,26 +522,24 @@ gpointer ctrlm_db_thread(gpointer param) { sem_post(&g_ctrlm_db.semaphore); break; } -#ifdef DEEPSLEEP_CLOSE_DB case CTRLM_DB_QUEUE_MSG_TYPE_POWER_STATE_CHANGE: { - XLOGD_DEBUG("POWER STATE CHANGE"); - ctrlm_db_queue_msg_power_state_change_t *power_state_change = (ctrlm_db_queue_msg_power_state_change_t *)msg; - ds_sem_wait = power_state_change->waking_up ? false : true; - ctrlm_db_power_state_change_(power_state_change->waking_up); + if(g_ctrlm_db.deepsleep_close_db) { + XLOGD_DEBUG("POWER STATE CHANGE"); + ctrlm_db_queue_msg_power_state_change_t *power_state_change = (ctrlm_db_queue_msg_power_state_change_t *)msg; + ds_sem_wait = power_state_change->waking_up ? false : true; + ctrlm_db_power_state_change_(power_state_change->waking_up); + } break; } -#endif default: { break; } } ctrlm_db_queue_msg_destroy(msg); -#ifdef DEEPSLEEP_CLOSE_DB if(ds_sem_wait == true) { sem_wait(&g_ctrlm_db.ds_signal); } -#endif } while(running); return(NULL); } From d327435ffe2f810930b672ed1c2d7472e2710f60 Mon Sep 17 00:00:00 2001 From: dwolaver <44593664+dwolaver@users.noreply.github.com> Date: Mon, 17 Nov 2025 16:05:35 -0500 Subject: [PATCH 07/81] RDKEMW-8668 : modify ctrlm build flag - BREAKPAD (#119) --- src/ctrlm_main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ctrlm_main.cpp b/src/ctrlm_main.cpp index ed0d3fed..e832501e 100644 --- a/src/ctrlm_main.cpp +++ b/src/ctrlm_main.cpp @@ -437,6 +437,7 @@ int main(int argc, char *argv[]) { ctrlm_signals_register(); #ifdef BREAKPAD_SUPPORT + XLOGD_INFO("breakpad enabled"); std::string minidump_path = "/opt/minidumps"; #ifdef BREAKPAD_MINIDUMP_PATH_OVERRIDE minidump_path = BREAKPAD_MINIDUMP_PATH_OVERRIDE; @@ -452,6 +453,8 @@ int main(int argc, char *argv[]) { google_breakpad::ExceptionHandler eh(descriptor, NULL, ctrlm_minidump_callback, NULL, true, -1); //ctrlm_crash(); +#else + XLOGD_INFO("breakpad disabled"); #endif XLOGD_INFO("glib run-time version... %d.%d.%d", glib_major_version, glib_minor_version, glib_micro_version); From cd566c448b640c39b2a4c32606208cac82c6a1e2 Mon Sep 17 00:00:00 2001 From: dwolaver <44593664+dwolaver@users.noreply.github.com> Date: Mon, 17 Nov 2025 16:09:28 -0500 Subject: [PATCH 08/81] RDKEMW-8297 : remove ctrlm build flags - A5000_ENABLE (#117) --- CMakeLists.txt | 6 ------ 1 file changed, 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 341b5607..66c5d7f5 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,6 @@ set(CMAKE_NO_SYSTEM_FROM_IMPORTED ON) project(ctrlm-main VERSION ${CMAKE_PROJECT_VERSION}) # OPTIONS -option(A5000_ENABLE "ES1 A5000 use libse051" OFF) option(ASSERT_ON_WRONG_THREAD "Assert on wrong thread" OFF) option(AUTH_ENABLED "Enable AUTH" OFF) option(BLE_ENABLED "Enable BLE" ON) @@ -178,11 +177,6 @@ install(TARGETS controlMgr RUNTIME DESTINATION bin) install(FILES ${CMAKE_BINARY_DIR}/ctrlm_config.json.template DESTINATION ${CMAKE_INSTALL_SYSCONFDIR} COMPONENT config ) # DEFINES FROM OPTIONS -if(A5000_ENABLE) - find_library( SE_HAL_PATH SE_HAL ${CMAKE_SYSROOT}/usr/lib/se051) - target_link_libraries(controlMgr ${SE_HAL_PATH}) -endif() - if(ANSI_CODES_DISABLED) add_compile_definitions(ANSI_CODES_DISABLED) endif() From 97ea7393ffc476688f65f20bbe5a9b75683e3e7b Mon Sep 17 00:00:00 2001 From: dwolaver <44593664+dwolaver@users.noreply.github.com> Date: Mon, 17 Nov 2025 16:26:24 -0500 Subject: [PATCH 09/81] RDKEMW-8664 : remove ctrlm build flags - MEM_DEBUG, ASSERT_ON_WRONG_THREAD (#118) --- CMakeLists.txt | 10 ---------- src/ctrlm_main.cpp | 17 ----------------- 2 files changed, 27 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 66c5d7f5..f8696dea 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,6 @@ set(CMAKE_NO_SYSTEM_FROM_IMPORTED ON) project(ctrlm-main VERSION ${CMAKE_PROJECT_VERSION}) # OPTIONS -option(ASSERT_ON_WRONG_THREAD "Assert on wrong thread" OFF) option(AUTH_ENABLED "Enable AUTH" OFF) option(BLE_ENABLED "Enable BLE" ON) option(BLE_SERVICES "Enable BLE Services" OFF) @@ -47,7 +46,6 @@ option(FDC_ENABLED "Enable FDC" OFF) option(IP_ENABLED "Enable IP" OFF) option(LOCAL_MIC "Local Microphone" OFF) option(LOCAL_MIC_DISABLE_VIA_PRIVACY "Use Privacy to disable microphone" OFF) -option(MEM_DEBUG "Enable memory debugging" OFF) option(MIC_TAP "Enable MIC_TAP" OFF) option(RF4CE_ENABLED "Enable RF4CE" ON) option(TELEMETRY_SUPPORT "Enable TELEMETRY_SUPPORT" OFF) @@ -181,10 +179,6 @@ if(ANSI_CODES_DISABLED) add_compile_definitions(ANSI_CODES_DISABLED) endif() -if(ASSERT_ON_WRONG_THREAD) - add_compile_definitions(ASSERT_ON_WRONG_THREAD) -endif() - if(BLE_ENABLED) target_link_libraries(controlMgr BTMgr) if(BLE_SERVICES) @@ -228,10 +222,6 @@ if(LOCAL_MIC) endif() endif() -if(MEM_DEBUG) - add_compile_definitions(MEM_DEBUG) -endif() - # RF4CE options if(RF4CE_ENABLED) # All RF4CE platforms have HAL NVM diff --git a/src/ctrlm_main.cpp b/src/ctrlm_main.cpp index e832501e..768cedb4 100644 --- a/src/ctrlm_main.cpp +++ b/src/ctrlm_main.cpp @@ -409,13 +409,6 @@ static void ctrlm_ir_controller_thread_poll(void *data); static void ctrlm_vsdk_thread_poll(void *data); static void ctrlm_vsdk_thread_response(void *data); -#ifdef MEM_DEBUG -static gboolean ctrlm_memory_profile(gpointer user_data) { - g_mem_profile(); - return(TRUE); -} -#endif - #ifdef BREAKPAD_SUPPORT static bool ctrlm_minidump_callback(const google_breakpad::MinidumpDescriptor& descriptor, void* context, bool succeeded) { XLOGD_FATAL("Minidump location: %s Status: %s", descriptor.path(), succeeded ? "SUCCEEDED" : "FAILED"); @@ -468,11 +461,6 @@ int main(int argc, char *argv[]) { XLOGD_INFO("Glib run-time library is compatible"); } -#ifdef MEM_DEBUG - XLOGD_WARN("Memory debug is ENABLED."); - g_mem_set_vtable(glib_mem_profiler_table); -#endif - sem_init(&g_ctrlm.ctrlm_utils_sem, 0, 1); if(!ctrlm_iarm_init()) { @@ -586,11 +574,6 @@ int main(int argc, char *argv[]) { g_ctrlm.discovery_remote_type[0] = '\0'; -#ifdef MEM_DEBUG - g_mem_profile(); - g_timeout_add_seconds(10, ctrlm_memory_profile, NULL); -#endif - XLOGD_INFO("load version"); if(!ctrlm_load_version()) { XLOGD_FATAL("failed to load version"); From 84e8ce8bff2e59d35268d9380fcfacd0a61c00c6 Mon Sep 17 00:00:00 2001 From: dwolaver <44593664+dwolaver@users.noreply.github.com> Date: Mon, 17 Nov 2025 16:35:47 -0500 Subject: [PATCH 10/81] RDKEMW-8676 : remove ctrlm build flags - MIC_TAP, LOCAL_MIC, LOCAL_MIC_DISABLE_VIA_PRIVACY (#120) --- CMakeLists.txt | 25 -- src/ctrlm.h | 1 + src/ctrlm_main.cpp | 36 +- src/ctrlm_main_iarm.cpp | 5 - src/ctrlm_powermanager.h | 2 - src/ctrlm_powermanager_factory.cpp | 5 +- src/ctrlm_utils.cpp | 3 +- src/ctrlm_utils.h | 4 +- src/ipc/ctrlm_ipc_iarm_powermanager.cpp | 6 +- src/ipc/ctrlm_ipc_iarm_powermanager.h | 2 - src/shared_memory/ctrlm_shared_memory.cpp | 4 - src/shared_memory/ctrlm_shared_memory.h | 2 - .../ctrlm_thunder_plugin_powermanager.cpp | 2 - .../ctrlm_thunder_plugin_powermanager.h | 2 - src/thunder/ctrlm_thunder_powermanager.cpp | 6 +- src/thunder/ctrlm_thunder_powermanager.h | 2 - src/voice/ctrlm_voice_obj.cpp | 342 ++++++++---------- src/voice/ctrlm_voice_obj.h | 44 +-- src/voice/ctrlm_voice_obj_generic.cpp | 26 +- src/voice/ctrlm_voice_types.h | 4 - .../ipc/ctrlm_voice_ipc_iarm_thunder.cpp | 85 ++--- 21 files changed, 235 insertions(+), 373 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f8696dea..655f17d2 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,21 +39,16 @@ option(BLE_ENABLED "Enable BLE" ON) option(BLE_SERVICES "Enable BLE Services" OFF) option(BREAKPAD "Enable BREAKPAD" OFF) option(BUILD_CTRLM_FACTORY "Build Control Factory Test" OFF) -option(ENABLE_NETWORKED_STANDBY_MODE "Enable Networked Standby Mode)" OFF) option(FACTORY_AUDIO_PLAYBACK "Factory test audio playback" OFF) option(FACTORY_CUSTOM_AUDIO_ANALYSIS "Factory custom audio analysis" OFF) option(FDC_ENABLED "Enable FDC" OFF) option(IP_ENABLED "Enable IP" OFF) -option(LOCAL_MIC "Local Microphone" OFF) -option(LOCAL_MIC_DISABLE_VIA_PRIVACY "Use Privacy to disable microphone" OFF) -option(MIC_TAP "Enable MIC_TAP" OFF) option(RF4CE_ENABLED "Enable RF4CE" ON) option(TELEMETRY_SUPPORT "Enable TELEMETRY_SUPPORT" OFF) option(THUNDER "Enable THUNDER" ON) option(THUNDER_SECURITY "Enable THUNDER_SECURITY" OFF) option(USE_SAFEC "Use safec" OFF) option(USE_IARM_POWER_MANAGER "Use IARM Power Manager" OFF) -option(VOICE_KEYWORD_BEEP "Enable VOICE_KEYWORD_BEEP" OFF) option(XRSR_HTTP "Enable XRSR_HTTP" OFF) option(XRSR_SDT "Enable XRSR_SDT" OFF) option(ENABLE_ASYNC_SRVR_MSG "Enable Asynchronous Server Messaging Feature" OFF) @@ -200,10 +195,6 @@ if(ENABLE_AVS_WITH_SDT) add_compile_definitions(SUPPORT_VOICE_DEST_ALSA SUPPORT_ASYNC_SRVR_MSG) endif() -if(ENABLE_NETWORKED_STANDBY_MODE) - add_compile_definitions(NETWORKED_STANDBY_MODE_ENABLED) -endif() - if(FDC_ENABLED) add_compile_definitions(FDC_ENABLED) endif() @@ -212,16 +203,6 @@ if(IP_ENABLED) add_compile_definitions(CTRLM_NETWORK_IP CTRLM_IP_HAL_LOG_ENABLED) endif() -if(LOCAL_MIC) - add_compile_definitions(CTRLM_LOCAL_MIC) - if(MIC_TAP) - add_compile_definitions(CTRLM_LOCAL_MIC_TAP) - endif() - if(LOCAL_MIC_DISABLE_VIA_PRIVACY) - add_compile_definitions(CTRLM_LOCAL_MIC_DISABLE_VIA_PRIVACY) - endif() -endif() - # RF4CE options if(RF4CE_ENABLED) # All RF4CE platforms have HAL NVM @@ -275,12 +256,6 @@ else() add_compile_definitions(SAFEC_DUMMY_API) endif() -if(VOICE_KEYWORD_BEEP) - add_compile_definitions(BEEP_ON_KWD_ENABLED) - add_definitions(-DBEEP_ON_KWD_FILE=\"${CMAKE_DATADIR}/${BEEP_ON_KWD_FILE}\") - install(FILES ${CMAKE_SOURCE_DIR}/../${BEEP_ON_KWD_FILE} DESTINATION share ) -endif() - if(USE_DEPRECATED_HDMI_INPUT_PLUGIN) add_compile_definitions(USE_DEPRECATED_HDMI_INPUT_PLUGIN) endif() diff --git a/src/ctrlm.h b/src/ctrlm.h index 68fa1818..905803d1 100644 --- a/src/ctrlm.h +++ b/src/ctrlm.h @@ -453,6 +453,7 @@ gboolean ctrlm_is_one_touch_autobind_active(void); gboolean ctrlm_is_binding_table_empty(void); gboolean ctrlm_is_binding_table_full(void); bool ctrlm_is_pii_mask_enabled(void); +bool ctrlm_is_networked_standby_supported(void); gboolean ctrlm_main_has_device_id_get(void); gboolean ctrlm_main_has_device_type_get(void); gboolean ctrlm_main_has_service_account_id_get(void); diff --git a/src/ctrlm_main.cpp b/src/ctrlm_main.cpp index 768cedb4..65f3ad19 100644 --- a/src/ctrlm_main.cpp +++ b/src/ctrlm_main.cpp @@ -285,9 +285,8 @@ typedef struct { gboolean local_conf; guint telemetry_report_interval; ctrlm_ir_controller_t *ir_controller; -#ifdef NETWORKED_STANDBY_MODE_ENABLED + bool networked_standby_supported; gboolean wake_with_voice_allowed; -#endif } ctrlm_global_t; static ctrlm_global_t g_ctrlm; @@ -566,9 +565,16 @@ int main(int argc, char *argv[]) { g_ctrlm.last_key_info.last_ir_remote_type = CTRLM_IR_REMOTE_TYPE_UNKNOWN; g_ctrlm.last_key_info.is_screen_bind_mode = false; g_ctrlm.last_key_info.remote_keypad_config = CTRLM_REMOTE_KEYPAD_CONFIG_INVALID; - #ifdef NETWORKED_STANDBY_MODE_ENABLED + + xrsr_config_t xrsr_config; + if(xrsr_config_get(&xrsr_config)) { + g_ctrlm.networked_standby_supported = xrsr_config.networked_standby; + } else { + g_ctrlm.networked_standby_supported = false; + } + XLOGD_INFO("networked standby supported <%s>", g_ctrlm.networked_standby_supported ? "YES" : "NO"); + g_ctrlm.wake_with_voice_allowed = false; - #endif errno_t safec_rc = strcpy_s(g_ctrlm.last_key_info.source_name, sizeof(g_ctrlm.last_key_info.source_name), ctrlm_rcu_ir_remote_types_str(g_ctrlm.last_key_info.last_ir_remote_type)); ERR_CHK(safec_rc); @@ -2632,9 +2638,9 @@ gpointer ctrlm_main_thread(gpointer param) { if( (old_state == CTRLM_POWER_STATE_DEEP_SLEEP) && (dqm->new_state != CTRLM_POWER_STATE_DEEP_SLEEP) ) { XLOGD_INFO("power_state_change: wake DB and networks"); - #ifdef NETWORKED_STANDBY_MODE_ENABLED - g_ctrlm.wake_with_voice_allowed = true; - #endif + if(g_ctrlm.networked_standby_supported) { + g_ctrlm.wake_with_voice_allowed = true; + } ctrlm_db_power_state_change(true); for(auto const &itr : g_ctrlm.networks) { itr.second->power_state_change(true); @@ -2647,9 +2653,8 @@ gpointer ctrlm_main_thread(gpointer param) { } } - #ifdef NETWORKED_STANDBY_MODE_ENABLED //Wake with voice? Handle NSM voice, do not change power state - if(dqm->new_state == CTRLM_POWER_STATE_ON) { + if(g_ctrlm.networked_standby_supported && dqm->new_state == CTRLM_POWER_STATE_ON) { bool wake_with_voice_allowed = g_ctrlm.wake_with_voice_allowed; g_ctrlm.wake_with_voice_allowed = false; @@ -2663,17 +2668,14 @@ gpointer ctrlm_main_thread(gpointer param) { break; } } - #endif //If execution reaches here, then change power state and inform VSDK of on or deep sleep states g_ctrlm.power_state = dqm->new_state; XLOGD_INFO("Enter power state <%s>", ctrlm_power_state_str(g_ctrlm.power_state)); - #ifdef NETWORKED_STANDBY_MODE_ENABLED - if(g_ctrlm.power_state == CTRLM_POWER_STATE_DEEP_SLEEP) { + if(g_ctrlm.networked_standby_supported && (g_ctrlm.power_state == CTRLM_POWER_STATE_DEEP_SLEEP)) { XLOGD_INFO("NSM is <%s>", (ctrlm_main_get_networked_standby_mode())?"ENABLED":"DISABLED"); } - #endif if(dqm->new_state != CTRLM_POWER_STATE_STANDBY) { // Set VSDK power state @@ -3129,6 +3131,10 @@ bool ctrlm_is_pii_mask_enabled(void) { return(g_ctrlm.mask_pii); } +bool ctrlm_is_networked_standby_supported(void) { + return(g_ctrlm.networked_standby_supported); +} + gboolean ctrlm_timeout_recently_booted(gpointer user_data) { XLOGD_INFO("Timeout - Recently booted."); g_ctrlm.recently_booted = FALSE; @@ -5807,11 +5813,9 @@ ctrlm_power_state_t ctrlm_main_get_system_power_state(void) { gboolean ctrlm_main_get_networked_standby_mode(void) { bool networked_standby_mode = false; - #ifdef NETWORKED_STANDBY_MODE_ENABLED - if(g_ctrlm.power_state == CTRLM_POWER_STATE_DEEP_SLEEP) { + if(g_ctrlm.networked_standby_supported && (g_ctrlm.power_state == CTRLM_POWER_STATE_DEEP_SLEEP)) { networked_standby_mode = g_ctrlm.power_manager->get_networked_standby_mode(); } - #endif return networked_standby_mode ? true : false; } diff --git a/src/ctrlm_main_iarm.cpp b/src/ctrlm_main_iarm.cpp index 92ceb987..8012b334 100644 --- a/src/ctrlm_main_iarm.cpp +++ b/src/ctrlm_main_iarm.cpp @@ -26,9 +26,6 @@ #include "irMgr.h" #endif #include "sysMgr.h" -#ifdef NETWORKED_STANDBY_MODE_ENABLED -#include "deepSleepMgr.h" -#endif #include "comcastIrKeyCodes.h" #include "ctrlm.h" #include "ctrlm_log.h" @@ -62,11 +59,9 @@ static IARM_Result_t ctrlm_main_iarm_call_start_pair_with_code(void *arg); static IARM_Result_t ctrlm_main_iarm_call_chip_status_get(void *arg); static IARM_Result_t ctrlm_main_iarm_call_audio_capture_start(void *arg); static IARM_Result_t ctrlm_main_iarm_call_audio_capture_stop(void *arg); -#ifdef NETWORKED_STANDBY_MODE_ENABLED #if CTRLM_HAL_RF4CE_API_VERSION >= 10 && !defined(CTRLM_DPI_CONTROL_NOT_SUPPORTED) extern IARM_Result_t ctrlm_iarm_powermanager_event_handler_power_pre_change(void* pArgs); #endif -#endif typedef struct { const char * name; diff --git a/src/ctrlm_powermanager.h b/src/ctrlm_powermanager.h index 89705b32..c55223ce 100755 --- a/src/ctrlm_powermanager.h +++ b/src/ctrlm_powermanager.h @@ -28,10 +28,8 @@ class ctrlm_powermanager_t { static ctrlm_powermanager_t *get_instance(); static void destroy_instance(); virtual ctrlm_power_state_t get_power_state() = 0; - #ifdef NETWORKED_STANDBY_MODE_ENABLED virtual bool get_networked_standby_mode() = 0; virtual bool get_wakeup_reason_voice() = 0; - #endif }; #endif diff --git a/src/ctrlm_powermanager_factory.cpp b/src/ctrlm_powermanager_factory.cpp index 93d9dcea..7048c028 100755 --- a/src/ctrlm_powermanager_factory.cpp +++ b/src/ctrlm_powermanager_factory.cpp @@ -16,10 +16,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include #include "ctrlm_powermanager.h" +#ifdef USE_IARM_POWER_MANAGER #include "ctrlm_ipc_iarm_powermanager.h" +#else #include "ctrlm_thunder_powermanager.h" - +#endif static ctrlm_powermanager_t *instance = NULL; diff --git a/src/ctrlm_utils.cpp b/src/ctrlm_utils.cpp index 7166aba5..b77595ac 100644 --- a/src/ctrlm_utils.cpp +++ b/src/ctrlm_utils.cpp @@ -1373,7 +1373,7 @@ const char *ctrlm_linux_key_code_str(uint16_t code, bool mask) { } } -#ifdef NETWORKED_STANDBY_MODE_ENABLED +#ifdef USE_IARM_POWER_MANAGER const char *ctrlm_wakeup_reason_str(DeepSleep_WakeupReason_t wakeup_reason) { switch(wakeup_reason) { case DEEPSLEEP_WAKEUPREASON_IR: return("IR"); @@ -1400,7 +1400,6 @@ const char *ctrlm_wakeup_reason_str(DeepSleep_WakeupReason_t wakeup_reason) { } #endif - bool ctrlm_file_copy(const char* src, const char* dst, bool overwrite, bool follow_dst_symbolic_link) { bool ret = FALSE; GFile *g_src = g_file_new_for_path(src); diff --git a/src/ctrlm_utils.h b/src/ctrlm_utils.h index 5e984a1e..baed40e7 100644 --- a/src/ctrlm_utils.h +++ b/src/ctrlm_utils.h @@ -36,7 +36,7 @@ #include "libIBus.h" #include "libIBusDaemon.h" #include -#ifdef NETWORKED_STANDBY_MODE_ENABLED +#ifdef USE_IARM_POWER_MANAGER #include "deepSleepMgr.h" #endif #ifdef TELEMETRY_SUPPORT @@ -205,7 +205,7 @@ const char *ctrlm_ir_state_str(ctrlm_ir_state_t state); const char *ctrlm_power_state_str(ctrlm_power_state_t state); const char *ctrlm_device_type_str(ctrlm_device_type_t device_type); -#ifdef NETWORKED_STANDBY_MODE_ENABLED +#ifdef USE_IARM_POWER_MANAGER const char *ctrlm_wakeup_reason_str(DeepSleep_WakeupReason_t wakeup_reason); #endif const char *ctrlm_rcu_wakeup_config_str(ctrlm_rcu_wakeup_config_t config); diff --git a/src/ipc/ctrlm_ipc_iarm_powermanager.cpp b/src/ipc/ctrlm_ipc_iarm_powermanager.cpp index 0fb5cd5e..0bef46ce 100755 --- a/src/ipc/ctrlm_ipc_iarm_powermanager.cpp +++ b/src/ipc/ctrlm_ipc_iarm_powermanager.cpp @@ -41,19 +41,16 @@ ctrlm_power_state_t ctrlm_ipc_iarm_powermanager_t::get_power_state() { XLOGD_WARN("IARM bus failed to read power state, defaulting to <%s>", ctrlm_power_state_str(power_state)); } else { power_state = ctrlm_iarm_power_state_map(param.curState); - #ifdef NETWORKED_STANDBY_MODE_ENABLED //If ctrlm restarts with system STANDBY state, set to ON, will receive a DEEP_SLEEP or ON message shortly - if(power_state == CTRLM_POWER_STATE_STANDBY) { + if(ctrlm_is_networked_standby_supported() && (power_state == CTRLM_POWER_STATE_STANDBY)) { power_state = CTRLM_POWER_STATE_ON; } - #endif XLOGD_DEBUG("power state <%s>", ctrlm_power_state_str(power_state)); } return power_state; } -#ifdef NETWORKED_STANDBY_MODE_ENABLED bool ctrlm_ipc_iarm_powermanager_t::get_networked_standby_mode() { IARM_Bus_PWRMgr_NetworkStandbyMode_Param_t param = {0}; IARM_Result_t res = IARM_Bus_Call(IARM_BUS_PWRMGR_NAME, IARM_BUS_PWRMGR_API_GetNetworkStandbyMode, (void *)¶m, sizeof(param)); @@ -89,7 +86,6 @@ bool ctrlm_ipc_iarm_powermanager_t::get_wakeup_reason_voice() { return wakeup_reason_voice; } -#endif #if CTRLM_HAL_RF4CE_API_VERSION >= 10 && !defined(CTRLM_DPI_CONTROL_NOT_SUPPORTED) IARM_Result_t ctrlm_iarm_powermanager_event_handler_power_pre_change(void* pArgs) diff --git a/src/ipc/ctrlm_ipc_iarm_powermanager.h b/src/ipc/ctrlm_ipc_iarm_powermanager.h index 20613c20..4944340a 100755 --- a/src/ipc/ctrlm_ipc_iarm_powermanager.h +++ b/src/ipc/ctrlm_ipc_iarm_powermanager.h @@ -26,10 +26,8 @@ class ctrlm_ipc_iarm_powermanager_t : public ctrlm_powermanager_t { ~ctrlm_ipc_iarm_powermanager_t(); ctrlm_power_state_t get_power_state(); - #ifdef NETWORKED_STANDBY_MODE_ENABLED bool get_networked_standby_mode(); bool get_wakeup_reason_voice(); - #endif private: diff --git a/src/shared_memory/ctrlm_shared_memory.cpp b/src/shared_memory/ctrlm_shared_memory.cpp index 03249419..b53b6db0 100644 --- a/src/shared_memory/ctrlm_shared_memory.cpp +++ b/src/shared_memory/ctrlm_shared_memory.cpp @@ -54,10 +54,8 @@ typedef struct { char url_ptt[CTRLM_VOICE_SERVER_URL_MAX_LENGTH]; bool url_ff_valid; char url_ff[CTRLM_VOICE_SERVER_URL_MAX_LENGTH]; - #ifdef CTRLM_LOCAL_MIC_TAP bool url_mic_tap_valid; char url_mic_tap[CTRLM_VOICE_SERVER_URL_MAX_LENGTH]; - #endif uint32_t query_string_ptt_count; query_string_pair_t query_string_ptt_pairs[CTRLM_VOICE_QUERY_STRING_MAX_PAIRS]; @@ -313,7 +311,6 @@ void ctrlm_sm_voice_url_ff_write(std::string url) { g_ctrlm_sm.mmap->url_ff_valid = true; } -#ifdef CTRLM_LOCAL_MIC_TAP void ctrlm_sm_voice_url_mic_tap_read(std::string &url) { if(g_ctrlm_sm.mmap == NULL) { XLOGD_ERROR("mmap is invalid"); @@ -334,7 +331,6 @@ void ctrlm_sm_voice_url_mic_tap_write(std::string url) { g_ctrlm_sm.mmap->url_mic_tap[sizeof(g_ctrlm_sm.mmap->url_mic_tap) - 1] = '\0'; g_ctrlm_sm.mmap->url_mic_tap_valid = true; } -#endif void ctrlm_sm_voice_query_string_ptt_count_read(uint8_t &count) { if(g_ctrlm_sm.mmap == NULL) { diff --git a/src/shared_memory/ctrlm_shared_memory.h b/src/shared_memory/ctrlm_shared_memory.h index 9c4e05e9..25479c66 100644 --- a/src/shared_memory/ctrlm_shared_memory.h +++ b/src/shared_memory/ctrlm_shared_memory.h @@ -53,10 +53,8 @@ void ctrlm_sm_voice_url_ptt_write(std::string url); void ctrlm_sm_voice_url_ff_read(std::string &url); void ctrlm_sm_voice_url_ff_write(std::string url); -#ifdef CTRLM_LOCAL_MIC_TAP void ctrlm_sm_voice_url_mic_tap_read(std::string &url); void ctrlm_sm_voice_url_mic_tap_write(std::string url); -#endif void ctrlm_sm_voice_query_string_ptt_count_read(uint8_t &count); void ctrlm_sm_voice_query_string_ptt_count_write(uint8_t count); diff --git a/src/thunder/ctrlm_thunder_plugin_powermanager.cpp b/src/thunder/ctrlm_thunder_plugin_powermanager.cpp index 70c9c1d5..6e0c83b0 100755 --- a/src/thunder/ctrlm_thunder_plugin_powermanager.cpp +++ b/src/thunder/ctrlm_thunder_plugin_powermanager.cpp @@ -86,7 +86,6 @@ ctrlm_power_state_t ctrlm_thunder_plugin_powermanager_t::get_power_state() { } -#ifdef NETWORKED_STANDBY_MODE_ENABLED /* root@pioneer-uhd:~# curl --request POST --url http://127.0.0.1:9998/jsonrpc --header 'Content-Type: application/json' --data '{ "jsonrpc": "2.0", "id": 1234567890, "method": "org.rdk.PowerManager.1.getNetworkStandbyMode", "params": {} }' {"jsonrpc":"2.0","id":1234567890,"result":true} */ bool ctrlm_thunder_plugin_powermanager_t::get_networked_standby_mode() { @@ -124,7 +123,6 @@ bool ctrlm_thunder_plugin_powermanager_t::get_wakeup_reason_voice() { return wakeup_reason_voice; } -#endif void ctrlm_thunder_plugin_powermanager_t::on_power_state_changed(const ctrlm_power_state_t ¤t_state, const ctrlm_power_state_t &new_state) { ctrlm_main_queue_power_state_change_t *msg = (ctrlm_main_queue_power_state_change_t *)g_malloc(sizeof(ctrlm_main_queue_power_state_change_t)); diff --git a/src/thunder/ctrlm_thunder_plugin_powermanager.h b/src/thunder/ctrlm_thunder_plugin_powermanager.h index ab6ae554..9d2c51a2 100755 --- a/src/thunder/ctrlm_thunder_plugin_powermanager.h +++ b/src/thunder/ctrlm_thunder_plugin_powermanager.h @@ -54,7 +54,6 @@ class ctrlm_thunder_plugin_powermanager_t : public Thunder::Plugin::ctrlm_thunde */ ctrlm_power_state_t get_power_state(); - #ifdef NETWORKED_STANDBY_MODE_ENABLED /** * This function is used to get the networked standby mode from PowerManager plugin. * @@ -67,7 +66,6 @@ class ctrlm_thunder_plugin_powermanager_t : public Thunder::Plugin::ctrlm_thunde * */ bool get_wakeup_reason_voice(); - #endif void on_power_state_changed(const ctrlm_power_state_t ¤t_state, const ctrlm_power_state_t &new_state); diff --git a/src/thunder/ctrlm_thunder_powermanager.cpp b/src/thunder/ctrlm_thunder_powermanager.cpp index ddc95499..8b80a4aa 100755 --- a/src/thunder/ctrlm_thunder_powermanager.cpp +++ b/src/thunder/ctrlm_thunder_powermanager.cpp @@ -36,14 +36,13 @@ ctrlm_power_state_t ctrlm_thunder_powermanager_t::get_power_state() { } } -#ifdef NETWORKED_STANDBY_MODE_ENABLED bool ctrlm_thunder_powermanager_t::get_networked_standby_mode() { if(this->plugin == NULL) { XLOGD_ERROR("plugin not yet available"); return false; } else { - return this->plugin->get_networked_standby_mode(networked_standby_mode); + return this->plugin->get_networked_standby_mode(); } } @@ -53,7 +52,6 @@ bool ctrlm_thunder_powermanager_t::get_wakeup_reason_voice() { XLOGD_WARN("plugin not yet available"); return false; } else { - return this->plugin->get_wakeup_reason_voice(wakeup_reason_voice); + return this->plugin->get_wakeup_reason_voice(); } } -#endif diff --git a/src/thunder/ctrlm_thunder_powermanager.h b/src/thunder/ctrlm_thunder_powermanager.h index 25dc45e9..b87ef19e 100755 --- a/src/thunder/ctrlm_thunder_powermanager.h +++ b/src/thunder/ctrlm_thunder_powermanager.h @@ -11,10 +11,8 @@ class ctrlm_thunder_powermanager_t : public ctrlm_powermanager_t { bool is_ready(); ctrlm_power_state_t get_power_state(); - #ifdef NETWORKED_STANDBY_MODE bool get_networked_standby_mode(); bool get_wakeup_reason_voice(); - #endif private: Thunder::PowerManager::ctrlm_thunder_plugin_powermanager_t *plugin; diff --git a/src/voice/ctrlm_voice_obj.cpp b/src/voice/ctrlm_voice_obj.cpp index 2491ae9a..93c12ac2 100644 --- a/src/voice/ctrlm_voice_obj.cpp +++ b/src/voice/ctrlm_voice_obj.cpp @@ -56,14 +56,18 @@ #define ADPCM_COMMAND_ID_MIN (0x20) ///< Minimum bound of command id as defined by XVP Spec. #define ADPCM_COMMAND_ID_MAX (0x3F) ///< Maximum bound of command id as defined by XVP Spec. +#define BEEP_ON_KWD_FILE_VD "/vendor/usr/share/keyword_beep.wav" +#define BEEP_ON_KWD_FILE_MW "/usr/share/keyword_beep.wav" + +#define BEEP_ON_KWD_SAP_VD "file://" BEEP_ON_KWD_FILE_VD +#define BEEP_ON_KWD_SAP_MW "file://" BEEP_ON_KWD_FILE_MW + static void ctrlm_voice_session_response_confirm(bool result, signed long long rsp_time, unsigned int rsp_window, const std::string &err_str, ctrlm_timestamp_t *timestamp, void *user_data); static void ctrlm_voice_data_post_processing_cb(int bytes_sent, void *user_data); static ctrlm_voice_session_group_t voice_device_to_session_group(ctrlm_voice_device_t device_type); -#ifdef BEEP_ON_KWD_ENABLED static void ctrlm_voice_system_audio_player_event_handler(system_audio_player_event_t event, void *user_data); -#endif static xrsr_power_mode_t voice_xrsr_power_map(ctrlm_power_state_t ctrlm_power_state); @@ -138,15 +142,38 @@ ctrlm_voice_t::ctrlm_voice_t() { this->session_id = 0; this->software_version = "N/A"; this->mask_pii = ctrlm_is_production_build() ? JSON_ARRAY_VAL_BOOL_CTRLM_GLOBAL_MASK_PII_0 : JSON_ARRAY_VAL_BOOL_CTRLM_GLOBAL_MASK_PII_1; + + xrsr_config_t xrsr_config; + if(xrsr_config_get(&xrsr_config)) { + this->local_mic = xrsr_config.local_mic; + this->local_mic_tap = xrsr_config.local_mic_tap; + this->local_mic_disable_via_privacy = this->local_mic; // set if local mic is present for now + } else { + XLOGD_ERROR("xrsr_config_get failed"); + this->local_mic = false; + this->local_mic_tap = false; + this->local_mic_disable_via_privacy = false; + + } + + if(ctrlm_file_exists(BEEP_ON_KWD_FILE_VD)) { + this->beep_on_kwd_file = BEEP_ON_KWD_SAP_VD; + this->beep_on_kwd_supported = true; + } else if(ctrlm_file_exists(BEEP_ON_KWD_FILE_MW)) { + this->beep_on_kwd_file = BEEP_ON_KWD_SAP_MW; + this->beep_on_kwd_supported = true; + } else { + this->beep_on_kwd_file = NULL; + this->beep_on_kwd_supported = false; + } + this->ocsp_verify_stapling = false; this->ocsp_verify_ca = false; this->capture_active = false; this->device_cert.type = CTRLM_VOICE_CERT_TYPE_NONE; this->prefs.server_url_src_ptt = JSON_STR_VALUE_VOICE_URL_SRC_PTT; this->prefs.server_url_src_ff = JSON_STR_VALUE_VOICE_URL_SRC_FF; - #ifdef CTRLM_LOCAL_MIC_TAP this->prefs.server_url_src_mic_tap = JSON_STR_VALUE_VOICE_URL_SRC_MIC_TAP; - #endif #ifdef JSON_ARRAY_VAL_STR_VOICE_SERVER_HOSTS_0 this->url_hostname_pattern_add(JSON_ARRAY_VAL_STR_VOICE_SERVER_HOSTS_0); #endif @@ -203,14 +230,12 @@ ctrlm_voice_t::ctrlm_voice_t() { } #endif - #ifdef NETWORKED_STANDBY_MODE_ENABLED this->prefs.dst_params_standby.connect_check_interval = JSON_INT_VALUE_VOICE_DST_PARAMS_STANDBY_CONNECT_CHECK_INTERVAL; this->prefs.dst_params_standby.timeout_connect = JSON_INT_VALUE_VOICE_DST_PARAMS_STANDBY_TIMEOUT_CONNECT; this->prefs.dst_params_standby.timeout_inactivity = JSON_INT_VALUE_VOICE_DST_PARAMS_STANDBY_TIMEOUT_INACTIVITY; this->prefs.dst_params_standby.timeout_session = JSON_INT_VALUE_VOICE_DST_PARAMS_STANDBY_TIMEOUT_SESSION; this->prefs.dst_params_standby.ipv4_fallback = JSON_BOOL_VALUE_VOICE_DST_PARAMS_STANDBY_IPV4_FALLBACK; this->prefs.dst_params_standby.backoff_delay = JSON_INT_VALUE_VOICE_DST_PARAMS_STANDBY_BACKOFF_DELAY; - #endif this->prefs.dst_params_low_latency.connect_check_interval = JSON_INT_VALUE_VOICE_DST_PARAMS_LOW_LATENCY_CONNECT_CHECK_INTERVAL; this->prefs.dst_params_low_latency.timeout_connect = JSON_INT_VALUE_VOICE_DST_PARAMS_LOW_LATENCY_TIMEOUT_CONNECT; @@ -225,14 +250,10 @@ ctrlm_voice_t::ctrlm_voice_t() { this->device_requires_stb_data[CTRLM_VOICE_DEVICE_PTT] = true; this->device_status[CTRLM_VOICE_DEVICE_FF] = CTRLM_VOICE_DEVICE_STATUS_NONE; this->device_requires_stb_data[CTRLM_VOICE_DEVICE_FF] = true; -#ifdef CTRLM_LOCAL_MIC this->device_status[CTRLM_VOICE_DEVICE_MICROPHONE] = CTRLM_VOICE_DEVICE_STATUS_NONE; this->device_requires_stb_data[CTRLM_VOICE_DEVICE_MICROPHONE] = true; -#endif -#ifdef CTRLM_LOCAL_MIC_TAP this->device_status[CTRLM_VOICE_DEVICE_MICROPHONE_TAP] = CTRLM_VOICE_DEVICE_STATUS_NONE; this->device_requires_stb_data[CTRLM_VOICE_DEVICE_MICROPHONE_TAP] = true; -#endif this->device_status[CTRLM_VOICE_DEVICE_INVALID] = CTRLM_VOICE_DEVICE_STATUS_NOT_SUPPORTED; this->device_requires_stb_data[CTRLM_VOICE_DEVICE_INVALID] = true; @@ -247,14 +268,14 @@ ctrlm_voice_t::ctrlm_voice_t() { // These semaphores are used to make sure we have all the data before calling the session begin callback sem_init(&this->vsr_semaphore, 0, 0); - #ifdef BEEP_ON_KWD_ENABLED - this->obj_sap = Thunder::SystemAudioPlayer::ctrlm_thunder_plugin_system_audio_player_t::getInstance(); - this->obj_sap->add_event_handler(ctrlm_voice_system_audio_player_event_handler, this); - this->sap_opened = this->obj_sap->open(SYSTEM_AUDIO_PLAYER_AUDIO_TYPE_WAV, SYSTEM_AUDIO_PLAYER_SOURCE_TYPE_FILE, SYSTEM_AUDIO_PLAYER_PLAY_MODE_SYSTEM); - if(!this->sap_opened) { - XLOGD_WARN("unable to open system audio player"); + if(this->beep_on_kwd_supported) { + this->obj_sap = Thunder::SystemAudioPlayer::ctrlm_thunder_plugin_system_audio_player_t::getInstance(); + this->obj_sap->add_event_handler(ctrlm_voice_system_audio_player_event_handler, this); + this->sap_opened = this->obj_sap->open(SYSTEM_AUDIO_PLAYER_AUDIO_TYPE_WAV, SYSTEM_AUDIO_PLAYER_SOURCE_TYPE_FILE, SYSTEM_AUDIO_PLAYER_PLAY_MODE_SYSTEM); + if(!this->sap_opened) { + XLOGD_WARN("unable to open system audio player"); + } } - #endif // Set audio mode to default ctrlm_voice_audio_settings_t settings = CTRLM_VOICE_AUDIO_SETTINGS_INITIALIZER; @@ -293,14 +314,12 @@ ctrlm_voice_t::~ctrlm_voice_t() { } } - #ifdef BEEP_ON_KWD_ENABLED - if(this->sap_opened) { + if(this->beep_on_kwd_supported && this->sap_opened) { if(!this->obj_sap->close()) { XLOGD_WARN("unable to close system audio player"); } this->sap_opened = false; } - #endif /* Close Voice SDK */ @@ -422,9 +441,7 @@ bool ctrlm_voice_t::voice_configure_config_file_json(json_t *obj_voice, json_t * conf.config_value_get(JSON_BOOL_NAME_VOICE_ENABLE, enabled); conf.config_value_get(JSON_STR_NAME_VOICE_URL_SRC_PTT, this->prefs.server_url_src_ptt); conf.config_value_get(JSON_STR_NAME_VOICE_URL_SRC_FF, this->prefs.server_url_src_ff); - #ifdef CTRLM_LOCAL_MIC_TAP conf.config_value_get(JSON_STR_NAME_VOICE_URL_SRC_MIC_TAP, this->prefs.server_url_src_mic_tap); - #endif conf.config_value_get(JSON_STR_NAME_VOICE_LANGUAGE, this->prefs.guide_language); conf.config_value_get(JSON_INT_NAME_VOICE_MINIMUM_DURATION, this->prefs.utterance_duration_min); if(conf.config_value_get(JSON_BOOL_NAME_VOICE_ENABLE_SAT, this->sat_token_required)) { @@ -483,14 +500,12 @@ bool ctrlm_voice_t::voice_configure_config_file_json(json_t *obj_voice, json_t * conf.config_value_get(JSON_FLOAT_NAME_VOICE_AUDIO_DUCKING_LEVEL, audio_settings.ducking_level, 0.0, 1.0); conf.config_value_get(JSON_BOOL_NAME_VOICE_AUDIO_DUCKING_BEEP, audio_settings.ducking_beep); - #ifdef NETWORKED_STANDBY_MODE_ENABLED conf.config_value_get(JSON_INT_NAME_VOICE_DST_PARAMS_STANDBY_CONNECT_CHECK_INTERVAL, this->prefs.dst_params_standby.connect_check_interval); conf.config_value_get(JSON_INT_NAME_VOICE_DST_PARAMS_STANDBY_TIMEOUT_CONNECT, this->prefs.dst_params_standby.timeout_connect); conf.config_value_get(JSON_INT_NAME_VOICE_DST_PARAMS_STANDBY_TIMEOUT_INACTIVITY, this->prefs.dst_params_standby.timeout_inactivity); conf.config_value_get(JSON_INT_NAME_VOICE_DST_PARAMS_STANDBY_TIMEOUT_SESSION, this->prefs.dst_params_standby.timeout_session); conf.config_value_get(JSON_BOOL_NAME_VOICE_DST_PARAMS_STANDBY_IPV4_FALLBACK, this->prefs.dst_params_standby.ipv4_fallback); conf.config_value_get(JSON_INT_NAME_VOICE_DST_PARAMS_STANDBY_BACKOFF_DELAY, this->prefs.dst_params_standby.backoff_delay); - #endif conf.config_value_get(JSON_INT_NAME_VOICE_DST_PARAMS_LOW_LATENCY_CONNECT_CHECK_INTERVAL, this->prefs.dst_params_low_latency.connect_check_interval); conf.config_value_get(JSON_INT_NAME_VOICE_DST_PARAMS_LOW_LATENCY_TIMEOUT_CONNECT, this->prefs.dst_params_low_latency.timeout_connect); @@ -517,11 +532,9 @@ bool ctrlm_voice_t::voice_configure_config_file_json(json_t *obj_voice, json_t * for(int i = CTRLM_VOICE_DEVICE_PTT; i < CTRLM_VOICE_DEVICE_INVALID; i++) { uint8_t voice_device_status = CTRLM_VOICE_DEVICE_STATUS_NONE; ctrlm_db_voice_read_device_status(i, (int *)&voice_device_status); - #ifdef CTRLM_LOCAL_MIC if((i == CTRLM_VOICE_DEVICE_MICROPHONE) && (voice_device_status & CTRLM_VOICE_DEVICE_STATUS_PRIVACY)) { this->voice_privacy_enable(false); } - #endif if((voice_device_status & CTRLM_VOICE_DEVICE_STATUS_LEGACY) && (voice_device_status != CTRLM_VOICE_DEVICE_STATUS_DISABLED)) { // Convert from legacy to current (some value other than DISABLED set) XLOGD_INFO("Converting legacy device status value 0x%02X", voice_device_status); voice_device_status = CTRLM_VOICE_DEVICE_STATUS_NONE; @@ -533,9 +546,7 @@ bool ctrlm_voice_t::voice_configure_config_file_json(json_t *obj_voice, json_t * } ctrlm_sm_voice_url_ptt_read(this->prefs.server_url_src_ptt); ctrlm_sm_voice_url_ff_read(this->prefs.server_url_src_ff); - #ifdef CTRLM_LOCAL_MIC_TAP ctrlm_sm_voice_url_mic_tap_read(this->prefs.server_url_src_mic_tap); - #endif ctrlm_sm_voice_sat_enable_read(this->sat_token_required); ctrlm_sm_voice_mtls_enable_read(this->mtls_required); ctrlm_sm_voice_secure_url_required_read(this->secure_url_required); @@ -584,28 +595,28 @@ bool ctrlm_voice_t::voice_configure_config_file_json(json_t *obj_voice, json_t * // Update routes this->voice_sdk_update_routes(); - #ifdef CTRLM_LOCAL_MIC - // Read privacy mode state from the DB in case power cycle lost HW GPIO state - if(this->device_status[CTRLM_VOICE_DEVICE_MICROPHONE] & CTRLM_VOICE_DEVICE_STATUS_DISABLED) { - XLOGD_INFO("voice is disabled, skip privacy"); - } else { - bool privacy_enabled = this->voice_is_privacy_enabled(); - if(privacy_enabled != this->vsdk_is_privacy_enabled()) { - privacy_enabled ? this->voice_privacy_enable(false) : this->voice_privacy_disable(false); - } - // Check keyword detector sensitivity value against limits; apply default if out of range. - double sensitivity_set = this->vsdk_keyword_sensitivity_limit_check(this->prefs.keyword_sensitivity); - if(sensitivity_set != this->prefs.keyword_sensitivity) { - xrsr_keyword_config_t kw_config; - kw_config.sensitivity = (float)sensitivity_set; - if(!xrsr_keyword_config_set(&kw_config)) { - XLOGD_ERROR("error updating keyword config"); - } else { - this->prefs.keyword_sensitivity = sensitivity_set; + if(this->local_mic) { + // Read privacy mode state from the DB in case power cycle lost HW GPIO state + if(this->device_status[CTRLM_VOICE_DEVICE_MICROPHONE] & CTRLM_VOICE_DEVICE_STATUS_DISABLED) { + XLOGD_INFO("voice is disabled, skip privacy"); + } else { + bool privacy_enabled = this->voice_is_privacy_enabled(); + if(privacy_enabled != this->vsdk_is_privacy_enabled()) { + privacy_enabled ? this->voice_privacy_enable(false) : this->voice_privacy_disable(false); + } + // Check keyword detector sensitivity value against limits; apply default if out of range. + double sensitivity_set = this->vsdk_keyword_sensitivity_limit_check(this->prefs.keyword_sensitivity); + if(sensitivity_set != this->prefs.keyword_sensitivity) { + xrsr_keyword_config_t kw_config; + kw_config.sensitivity = (float)sensitivity_set; + if(!xrsr_keyword_config_set(&kw_config)) { + XLOGD_ERROR("error updating keyword config"); + } else { + this->prefs.keyword_sensitivity = sensitivity_set; + } } } } - #endif // Set init message if read from DB if(!init.empty()) { @@ -726,7 +737,6 @@ bool ctrlm_voice_t::voice_configure(ctrlm_voice_iarm_call_settings_t *settings, ctrlm_sm_voice_url_ff_write(this->prefs.server_url_src_ff); } } - #ifdef CTRLM_LOCAL_MIC_TAP if(settings->available & CTRLM_VOICE_SETTINGS_MIC_TAP_SERVER_URL) { settings->server_url_src_mic_tap[CTRLM_VOICE_SERVER_URL_MAX_LENGTH - 1] = '\0'; XLOGD_INFO("Mic tap URL <%s>", this->mask_pii ? "***" : settings->server_url_src_mic_tap); @@ -736,7 +746,6 @@ bool ctrlm_voice_t::voice_configure(ctrlm_voice_iarm_call_settings_t *settings, ctrlm_sm_voice_url_mic_tap_write(this->prefs.server_url_src_mic_tap); } } - #endif if(update_routes && this->xrsr_opened) { this->voice_sdk_update_routes(); @@ -781,9 +790,7 @@ bool ctrlm_voice_t::voice_configure(json_t *settings, bool db_write) { } } if(conf.config_value_get("urlAll", url)) { - #ifdef CTRLM_LOCAL_MIC_TAP this->prefs.server_url_src_mic_tap = url; - #endif this->prefs.server_url_src_ptt = url; this->prefs.server_url_src_ff = std::move(url); update_routes = true; @@ -796,12 +803,10 @@ bool ctrlm_voice_t::voice_configure(json_t *settings, bool db_write) { this->prefs.server_url_src_ff = std::move(url); update_routes = true; } - #ifdef CTRLM_LOCAL_MIC_TAP if(conf.config_value_get("urlMicTap", url)) { this->prefs.server_url_src_mic_tap = std::move(url); update_routes = true; } - #endif if(conf.config_value_get("prv", prv_enabled)) { this->prefs.par_voice_enabled = prv_enabled; XLOGD_INFO("Press and Release Voice is <%s>", this->prefs.par_voice_enabled ? "ENABLED" : "DISABLED"); @@ -829,45 +834,43 @@ bool ctrlm_voice_t::voice_configure(json_t *settings, bool db_write) { } } } - #ifdef CTRLM_LOCAL_MIC - if(conf.config_object_get("mic", device_config)) { - if(device_config.config_value_get("enable", enable)) { - XLOGD_TELEMETRY("Voice Control MIC is <%s>", enable ? "ENABLED" : "DISABLED"); - #ifdef CTRLM_LOCAL_MIC_DISABLE_VIA_PRIVACY - bool privacy_enabled = this->voice_is_privacy_enabled(); - if(enable) { - if(privacy_enabled) { - this->voice_privacy_disable(true); + if(this->local_mic) { + if(conf.config_object_get("mic", device_config)) { + if(device_config.config_value_get("enable", enable)) { + XLOGD_TELEMETRY("Voice Control MIC is <%s>", enable ? "ENABLED" : "DISABLED"); + if(this->local_mic_disable_via_privacy) { + bool privacy_enabled = this->voice_is_privacy_enabled(); + if(enable) { + if(privacy_enabled) { + this->voice_privacy_disable(true); + } + } else if(!privacy_enabled) { + this->voice_privacy_enable(true); + } + } else { + if(enable) { + this->voice_device_enable(CTRLM_VOICE_DEVICE_MICROPHONE, db_write, &update_routes); + } else { + this->voice_device_disable(CTRLM_VOICE_DEVICE_MICROPHONE, db_write, &update_routes); + } } - } else if(!privacy_enabled) { - this->voice_privacy_enable(true); - } - #else - if(enable) { - this->voice_device_enable(CTRLM_VOICE_DEVICE_MICROPHONE, db_write, &update_routes); - } else { - this->voice_device_disable(CTRLM_VOICE_DEVICE_MICROPHONE, db_write, &update_routes); } - #endif } - } - #endif - if(conf.config_value_get("wwFeedback", enable)) { // This option will enable / disable the Wake Word feedback (typically an audible beep). - XLOGD_INFO("Voice Control kwd feedback is <%s>", enable ? "ENABLED" : "DISABLED"); - this->audio_ducking_beep_enabled = enable; + if(conf.config_value_get("wwFeedback", enable)) { // This option will enable / disable the Wake Word feedback (typically an audible beep). + XLOGD_INFO("Voice Control kwd feedback is <%s>", enable ? "ENABLED" : "DISABLED"); + this->audio_ducking_beep_enabled = enable; - if(db_write) { - ctrlm_db_voice_write_audio_ducking_beep_enable(enable); - } + if(db_write) { + ctrlm_db_voice_write_audio_ducking_beep_enable(enable); + } + } } if(update_routes && this->xrsr_opened) { this->voice_sdk_update_routes(); if(db_write) { ctrlm_sm_voice_url_ptt_write(this->prefs.server_url_src_ptt); ctrlm_sm_voice_url_ff_write(this->prefs.server_url_src_ff); - #ifdef CTRLM_LOCAL_MIC_TAP ctrlm_sm_voice_url_mic_tap_write(this->prefs.server_url_src_mic_tap); - #endif } } } @@ -914,11 +917,7 @@ bool ctrlm_voice_t::voice_status(ctrlm_voice_status_t *status) { */ ctrlm_voice_status_capabilities_t capabilities = { .prv = true, - #ifdef BEEP_ON_KWD_ENABLED - .wwFeedback = true, - #else - .wwFeedback = false, - #endif + .wwFeedback = this->beep_on_kwd_supported, }; if(!this->xrsr_opened) { @@ -928,9 +927,7 @@ bool ctrlm_voice_t::voice_status(ctrlm_voice_status_t *status) { } else { status->urlPtt = this->prefs.server_url_src_ptt; status->urlHf = this->prefs.server_url_src_ff; - #ifdef CTRLM_LOCAL_MIC_TAP status->urlMicTap = this->prefs.server_url_src_mic_tap; - #endif sem_wait(&this->device_status_semaphore); for(int i = CTRLM_VOICE_DEVICE_PTT; i < CTRLM_VOICE_DEVICE_INVALID; i++) { status->status[i] = this->device_status[i]; @@ -2358,6 +2355,14 @@ bool ctrlm_voice_t::voice_stb_data_pii_mask_get() const { return(this->mask_pii); } +bool ctrlm_voice_t::voice_stb_data_local_mic_get() const { + return(this->local_mic); +} + +bool ctrlm_voice_t::voice_stb_data_local_mic_tap_get() const { + return(this->local_mic_tap); +} + bool ctrlm_voice_t::voice_stb_data_device_certificate_set(ctrlm_voice_cert_t &device_cert, bool &ocsp_verify_stapling, bool &ocsp_verify_ca) { this->ocsp_verify_stapling = ocsp_verify_stapling; this->ocsp_verify_ca = ocsp_verify_ca; @@ -2659,29 +2664,20 @@ void ctrlm_voice_t::voice_session_end_callback(ctrlm_voice_session_end_cb_t *ses this->voice_status_set(session); break; } - #ifdef CTRLM_LOCAL_MIC case CTRLM_VOICE_DEVICE_MICROPHONE: { command_status = (session_end->success ? VOICE_COMMAND_STATUS_SUCCESS : VOICE_COMMAND_STATUS_FAILURE); // No need to set, as it's not a controller break; } - #endif default: { break; } } } - #ifdef CTRLM_LOCAL_MIC - #ifdef CTRLM_LOCAL_MIC_TAP if(session->voice_device == CTRLM_VOICE_DEVICE_MICROPHONE || session->voice_device == CTRLM_VOICE_DEVICE_MICROPHONE_TAP) { - #else - if(session->voice_device == CTRLM_VOICE_DEVICE_MICROPHONE) { - #endif XLOGD_INFO("src <%s> reason <%s> voice command status <%s>", ctrlm_voice_device_str(session->voice_device), xrsr_session_end_reason_str(stats->reason), ctrlm_voice_command_status_str(command_status)); - } else - #endif - { + } else { XLOGD_INFO("src <%s> audio sent bytes <%u> samples <%u> reason <%s> voice command status <%s>", ctrlm_voice_device_str(session->voice_device), session->audio_sent_bytes, session->audio_sent_samples, xrsr_session_end_reason_str(stats->reason), ctrlm_voice_command_status_str(command_status)); } @@ -3079,8 +3075,7 @@ void ctrlm_voice_t::voice_action_keyword_verification_callback(const uuid_t uuid } void ctrlm_voice_t::voice_keyword_verified_action(void) { - #ifdef BEEP_ON_KWD_ENABLED - if(this->audio_ducking_beep_enabled) { // play beep audio before ducking audio + if(this->beep_on_kwd_supported && (this->beep_on_kwd_file != NULL) && this->audio_ducking_beep_enabled) { // play beep audio before ducking audio if(this->audio_ducking_beep_in_progress) { XLOGD_WARN("audio ducking beep already in progress!"); this->obj_sap->close(); @@ -3102,8 +3097,8 @@ void ctrlm_voice_t::voice_keyword_verified_action(void) { } } - if(!this->obj_sap->play("file://" BEEP_ON_KWD_FILE)) { - XLOGD_WARN("unable to play beep file <%s>", BEEP_ON_KWD_FILE); + if(!this->obj_sap->play(this->beep_on_kwd_file)) { + XLOGD_WARN("unable to play beep file <%s>", this->beep_on_kwd_file); if(!this->obj_sap->close()) { XLOGD_WARN("unable to close system audio player"); } @@ -3120,11 +3115,9 @@ void ctrlm_voice_t::voice_keyword_verified_action(void) { return; } while(retry >= 0); } - #endif this->audio_state_set(true); } -#ifdef BEEP_ON_KWD_ENABLED void ctrlm_voice_t::voice_keyword_beep_completed_normal(void *data, int size) { this->voice_keyword_beep_completed_callback(false, false); } @@ -3159,7 +3152,6 @@ void ctrlm_voice_t::voice_keyword_beep_completed_callback(bool timeout, bool pla this->audio_state_set(true); } } -#endif void ctrlm_voice_t::voice_session_transcription_callback(const uuid_t uuid, const char *transcription) { // Get session based on uuid @@ -3241,12 +3233,8 @@ const char *ctrlm_voice_device_str(ctrlm_voice_device_t device) { switch(device) { case CTRLM_VOICE_DEVICE_PTT: return("PTT"); case CTRLM_VOICE_DEVICE_FF: return("FF"); - #ifdef CTRLM_LOCAL_MIC case CTRLM_VOICE_DEVICE_MICROPHONE: return("MICROPHONE"); - #endif - #ifdef CTRLM_LOCAL_MIC_TAP case CTRLM_VOICE_DEVICE_MICROPHONE_TAP: return("MICROPHONE_TAP"); - #endif case CTRLM_VOICE_DEVICE_INVALID: return("INVALID"); } return("UNKNOWN"); @@ -3307,18 +3295,14 @@ ctrlm_voice_device_t xrsr_to_voice_device(xrsr_src_t device) { ret = CTRLM_VOICE_DEVICE_FF; break; } - #ifdef CTRLM_LOCAL_MIC case XRSR_SRC_MICROPHONE: { ret = CTRLM_VOICE_DEVICE_MICROPHONE; break; } - #endif - #ifdef CTRLM_LOCAL_MIC_TAP case XRSR_SRC_MICROPHONE_TAP: { ret = CTRLM_VOICE_DEVICE_MICROPHONE_TAP; break; } - #endif default: { XLOGD_ERROR("unrecognized device type %d", device); break; @@ -3338,18 +3322,14 @@ xrsr_src_t voice_device_to_xrsr(ctrlm_voice_device_t device) { ret = XRSR_SRC_RCU_FF; break; } - #ifdef CTRLM_LOCAL_MIC case CTRLM_VOICE_DEVICE_MICROPHONE: { ret = XRSR_SRC_MICROPHONE; break; } - #endif - #ifdef CTRLM_LOCAL_MIC_TAP case CTRLM_VOICE_DEVICE_MICROPHONE_TAP: { ret = XRSR_SRC_MICROPHONE_TAP; break; } - #endif default: { XLOGD_ERROR("unrecognized device type %d", device); break; @@ -3359,11 +3339,9 @@ xrsr_src_t voice_device_to_xrsr(ctrlm_voice_device_t device) { } ctrlm_voice_session_group_t voice_device_to_session_group(ctrlm_voice_device_t device_type) { - #ifdef CTRLM_LOCAL_MIC_TAP if(device_type == CTRLM_VOICE_DEVICE_MICROPHONE_TAP) { return(VOICE_SESSION_GROUP_MIC_TAP); } - #endif return(VOICE_SESSION_GROUP_DEFAULT); } @@ -3463,16 +3441,12 @@ ctrlm_voice_format_t xrsr_to_voice_format(xrsr_audio_format_t format) { bool ctrlm_voice_t::is_voice_assistant(ctrlm_voice_device_t device) { bool voice_assistant = false; switch(device) { - #ifdef CTRLM_LOCAL_MIC case CTRLM_VOICE_DEVICE_MICROPHONE: - #endif case CTRLM_VOICE_DEVICE_FF: { voice_assistant = true; break; } - #ifdef CTRLM_LOCAL_MIC_TAP case CTRLM_VOICE_DEVICE_MICROPHONE_TAP: - #endif case CTRLM_VOICE_DEVICE_PTT: case CTRLM_VOICE_DEVICE_INVALID: default: { @@ -3590,12 +3564,10 @@ int ctrlm_voice_t::ctrlm_voice_controller_command_status_read_timeout(void *data return(false); } -#ifdef BEEP_ON_KWD_ENABLED int ctrlm_voice_t::ctrlm_voice_keyword_beep_end_timeout(void *data) { ctrlm_get_voice_obj()->voice_keyword_beep_completed_callback(true, false); return(false); } -#endif // Timeouts end @@ -3642,9 +3614,7 @@ const char *ctrlm_voice_session_response_status_str(ctrlm_voice_session_response const char *ctrlm_voice_session_group_str(ctrlm_voice_session_group_t group) { switch(group) { case VOICE_SESSION_GROUP_DEFAULT: return("DEFAULT"); - #ifdef CTRLM_LOCAL_MIC_TAP case VOICE_SESSION_GROUP_MIC_TAP: return("MIC_TAP"); - #endif case VOICE_SESSION_GROUP_QTY: break; // fall thru to return an invalid group } return(ctrlm_invalid_return(group)); @@ -3810,14 +3780,14 @@ void ctrlm_voice_t::voice_power_state_change(ctrlm_power_state_t power_state) { xrsr_power_mode_t xrsr_power_mode = voice_xrsr_power_map(power_state); - #ifdef CTRLM_LOCAL_MIC - if(power_state == CTRLM_POWER_STATE_ON) { - bool privacy_enabled = this->vsdk_is_privacy_enabled(); - if(privacy_enabled != this->voice_is_privacy_enabled()) { - privacy_enabled ? this->voice_privacy_enable(false) : this->voice_privacy_disable(false); + if(this->local_mic) { + if(power_state == CTRLM_POWER_STATE_ON) { + bool privacy_enabled = this->vsdk_is_privacy_enabled(); + if(privacy_enabled != this->voice_is_privacy_enabled()) { + privacy_enabled ? this->voice_privacy_enable(false) : this->voice_privacy_disable(false); + } } } - #endif if(!xrsr_power_mode_set(xrsr_power_mode)) { XLOGD_ERROR("failed to set xrsr to power state %s", ctrlm_power_state_str(power_state)); @@ -3851,57 +3821,56 @@ void ctrlm_voice_t::voice_session_set_inactive(ctrlm_voice_device_t device) { } bool ctrlm_voice_t::voice_is_privacy_enabled(void) { - #ifdef CTRLM_LOCAL_MIC - sem_wait(&this->device_status_semaphore); - bool value = (this->device_status[CTRLM_VOICE_DEVICE_MICROPHONE] & CTRLM_VOICE_DEVICE_STATUS_PRIVACY) ? true : false; - sem_post(&this->device_status_semaphore); - return(value); - #else + if(this->local_mic) { + sem_wait(&this->device_status_semaphore); + bool value = (this->device_status[CTRLM_VOICE_DEVICE_MICROPHONE] & CTRLM_VOICE_DEVICE_STATUS_PRIVACY) ? true : false; + sem_post(&this->device_status_semaphore); + return(value); + } return(false); - #endif } void ctrlm_voice_t::voice_privacy_enable(bool update_vsdk) { - #ifdef CTRLM_LOCAL_MIC - sem_wait(&this->device_status_semaphore); - if(this->device_status[CTRLM_VOICE_DEVICE_MICROPHONE] & CTRLM_VOICE_DEVICE_STATUS_PRIVACY) { - sem_post(&this->device_status_semaphore); - XLOGD_WARN("already enabled"); - return; - } + if(this->local_mic) { + sem_wait(&this->device_status_semaphore); + if(this->device_status[CTRLM_VOICE_DEVICE_MICROPHONE] & CTRLM_VOICE_DEVICE_STATUS_PRIVACY) { + sem_post(&this->device_status_semaphore); + XLOGD_WARN("already enabled"); + return; + } - this->device_status[CTRLM_VOICE_DEVICE_MICROPHONE] |= CTRLM_VOICE_DEVICE_STATUS_PRIVACY; - ctrlm_db_voice_write_device_status(CTRLM_VOICE_DEVICE_MICROPHONE, (this->device_status[CTRLM_VOICE_DEVICE_MICROPHONE] & CTRLM_VOICE_DEVICE_STATUS_MASK_DB)); + this->device_status[CTRLM_VOICE_DEVICE_MICROPHONE] |= CTRLM_VOICE_DEVICE_STATUS_PRIVACY; + ctrlm_db_voice_write_device_status(CTRLM_VOICE_DEVICE_MICROPHONE, (this->device_status[CTRLM_VOICE_DEVICE_MICROPHONE] & CTRLM_VOICE_DEVICE_STATUS_MASK_DB)); - #ifdef CTRLM_LOCAL_MIC_DISABLE_VIA_PRIVACY - if(update_vsdk && this->xrsr_opened && !xrsr_privacy_mode_set(true)) { - XLOGD_ERROR("xrsr_privacy_mode_set failed"); - } - #endif + if(this->local_mic_disable_via_privacy) { + if(update_vsdk && this->xrsr_opened && !xrsr_privacy_mode_set(true)) { + XLOGD_ERROR("xrsr_privacy_mode_set failed"); + } + } - sem_post(&this->device_status_semaphore); - #endif + sem_post(&this->device_status_semaphore); + } } void ctrlm_voice_t::voice_privacy_disable(bool update_vsdk) { - #ifdef CTRLM_LOCAL_MIC - sem_wait(&this->device_status_semaphore); - if(!(this->device_status[CTRLM_VOICE_DEVICE_MICROPHONE] & CTRLM_VOICE_DEVICE_STATUS_PRIVACY)) { - sem_post(&this->device_status_semaphore); - XLOGD_WARN("already disabled"); - return; - } + if(this->local_mic) { + sem_wait(&this->device_status_semaphore); + if(!(this->device_status[CTRLM_VOICE_DEVICE_MICROPHONE] & CTRLM_VOICE_DEVICE_STATUS_PRIVACY)) { + sem_post(&this->device_status_semaphore); + XLOGD_WARN("already disabled"); + return; + } - this->device_status[CTRLM_VOICE_DEVICE_MICROPHONE] &= ~CTRLM_VOICE_DEVICE_STATUS_PRIVACY; - ctrlm_db_voice_write_device_status(CTRLM_VOICE_DEVICE_MICROPHONE, (this->device_status[CTRLM_VOICE_DEVICE_MICROPHONE] & CTRLM_VOICE_DEVICE_STATUS_MASK_DB)); + this->device_status[CTRLM_VOICE_DEVICE_MICROPHONE] &= ~CTRLM_VOICE_DEVICE_STATUS_PRIVACY; + ctrlm_db_voice_write_device_status(CTRLM_VOICE_DEVICE_MICROPHONE, (this->device_status[CTRLM_VOICE_DEVICE_MICROPHONE] & CTRLM_VOICE_DEVICE_STATUS_MASK_DB)); - #ifdef CTRLM_LOCAL_MIC_DISABLE_VIA_PRIVACY - if(update_vsdk && this->xrsr_opened && !xrsr_privacy_mode_set(false)) { - XLOGD_ERROR("xrsr_privacy_mode_set failed"); - } - #endif - sem_post(&this->device_status_semaphore); - #endif + if(this->local_mic_disable_via_privacy) { + if(update_vsdk && this->xrsr_opened && !xrsr_privacy_mode_set(false)) { + XLOGD_ERROR("xrsr_privacy_mode_set failed"); + } + } + sem_post(&this->device_status_semaphore); + } } void ctrlm_voice_t::voice_device_enable(ctrlm_voice_device_t device, bool db_write, bool *update_routes) { @@ -3940,7 +3909,6 @@ void ctrlm_voice_t::voice_device_disable(ctrlm_voice_device_t device, bool db_wr sem_post(&this->device_status_semaphore); } -#ifdef BEEP_ON_KWD_ENABLED void ctrlm_voice_system_audio_player_event_handler(system_audio_player_event_t event, void *user_data) { if(user_data == NULL) { return; @@ -3980,27 +3948,24 @@ void ctrlm_voice_system_audio_player_event_handler(system_audio_player_event_t e } } } -#endif -#ifdef NETWORKED_STANDBY_MODE_ENABLED void ctrlm_voice_t::voice_nsm_session_request(void) { ctrlm_network_id_t network_id = CTRLM_MAIN_NETWORK_ID_DSP; ctrlm_controller_id_t controller_id = CTRLM_MAIN_CONTROLLER_ID_DSP; ctrlm_voice_device_t device = CTRLM_VOICE_DEVICE_MICROPHONE; ctrlm_voice_format_t format = { .type = CTRLM_VOICE_FORMAT_PCM_32_BIT }; - #ifdef CTRLM_LOCAL_MIC_DISABLE_VIA_PRIVACY - //If the user un-muted the microphones in standby, we must un-mute our components - if(this->voice_is_privacy_enabled()) { - this->voice_privacy_disable(true); + if(this->local_mic_disable_via_privacy) { + //If the user un-muted the microphones in standby, we must un-mute our components + if(this->voice_is_privacy_enabled()) { + this->voice_privacy_disable(true); + } } - #endif this->nsm_voice_session = true; voice_session_req(network_id, controller_id, device, format, NULL, "NSM", "0.0.0.0", "0.0.0.0", 0.0); } -#endif int ctrlm_voice_t::packet_loss_threshold_get() const { return(this->packet_loss_threshold); @@ -4025,11 +3990,11 @@ xrsr_power_mode_t voice_xrsr_power_map(ctrlm_power_state_t ctrlm_power_state) { switch(ctrlm_power_state) { case CTRLM_POWER_STATE_DEEP_SLEEP: - #ifdef NETWORKED_STANDBY_MODE_ENABLED - xrsr_power_mode = ctrlm_main_get_networked_standby_mode() ? XRSR_POWER_MODE_LOW : XRSR_POWER_MODE_SLEEP; - #else - xrsr_power_mode = XRSR_POWER_MODE_SLEEP; - #endif + if(ctrlm_is_networked_standby_supported()) { + xrsr_power_mode = ctrlm_main_get_networked_standby_mode() ? XRSR_POWER_MODE_LOW : XRSR_POWER_MODE_SLEEP; + } else { + xrsr_power_mode = XRSR_POWER_MODE_SLEEP; + } break; case CTRLM_POWER_STATE_ON: case CTRLM_POWER_STATE_STANDBY: @@ -4149,14 +4114,13 @@ void ctrlm_voice_t::voice_rfc_retrieved_handler(const ctrlm_rfc_attr_t& attr) { // All attributes that need a re-route to apply if(attr.get_rfc_value(JSON_INT_NAME_VOICE_MINIMUM_DURATION, this->prefs.utterance_duration_min) | - #ifdef NETWORKED_STANDBY_MODE_ENABLED attr.get_rfc_value(JSON_INT_NAME_VOICE_DST_PARAMS_STANDBY_CONNECT_CHECK_INTERVAL, this->prefs.dst_params_standby.connect_check_interval) | attr.get_rfc_value(JSON_INT_NAME_VOICE_DST_PARAMS_STANDBY_TIMEOUT_CONNECT, this->prefs.dst_params_standby.timeout_connect) | attr.get_rfc_value(JSON_INT_NAME_VOICE_DST_PARAMS_STANDBY_TIMEOUT_INACTIVITY, this->prefs.dst_params_standby.timeout_inactivity) | attr.get_rfc_value(JSON_INT_NAME_VOICE_DST_PARAMS_STANDBY_TIMEOUT_SESSION, this->prefs.dst_params_standby.timeout_session) | attr.get_rfc_value(JSON_BOOL_NAME_VOICE_DST_PARAMS_STANDBY_IPV4_FALLBACK, this->prefs.dst_params_standby.ipv4_fallback) | attr.get_rfc_value(JSON_INT_NAME_VOICE_DST_PARAMS_STANDBY_BACKOFF_DELAY, this->prefs.dst_params_standby.backoff_delay) | - #endif + attr.get_rfc_value(JSON_INT_NAME_VOICE_DST_PARAMS_LOW_LATENCY_CONNECT_CHECK_INTERVAL, this->prefs.dst_params_low_latency.connect_check_interval) | attr.get_rfc_value(JSON_INT_NAME_VOICE_DST_PARAMS_LOW_LATENCY_TIMEOUT_CONNECT, this->prefs.dst_params_low_latency.timeout_connect) | attr.get_rfc_value(JSON_INT_NAME_VOICE_DST_PARAMS_LOW_LATENCY_TIMEOUT_INACTIVITY, this->prefs.dst_params_low_latency.timeout_inactivity) | @@ -4176,9 +4140,7 @@ void ctrlm_voice_t::voice_rfc_retrieved_handler(const ctrlm_rfc_attr_t& attr) { attr.get_rfc_value(JSON_BOOL_NAME_VOICE_ENABLE, enabled); attr.get_rfc_value(JSON_STR_NAME_VOICE_URL_SRC_PTT, this->prefs.server_url_src_ptt); attr.get_rfc_value(JSON_STR_NAME_VOICE_URL_SRC_FF, this->prefs.server_url_src_ff); - #ifdef CTRLM_LOCAL_MIC_TAP attr.get_rfc_value(JSON_STR_NAME_VOICE_URL_SRC_MIC_TAP, this->prefs.server_url_src_mic_tap); - #endif // Check if enabled if(!enabled) { for(int i = CTRLM_VOICE_DEVICE_PTT; i < CTRLM_VOICE_DEVICE_INVALID; i++) { diff --git a/src/voice/ctrlm_voice_obj.h b/src/voice/ctrlm_voice_obj.h index 70ddb4c7..bd8de16c 100644 --- a/src/voice/ctrlm_voice_obj.h +++ b/src/voice/ctrlm_voice_obj.h @@ -37,21 +37,14 @@ #include "ctrlm_rfc.h" #include "xrsr.h" #include "ctrlm_voice_telemetry_events.h" - -#ifdef BEEP_ON_KWD_ENABLED #include "ctrlm_thunder_plugin_system_audio_player.h" -#endif #define VOICE_SESSION_REQ_DATA_LEN_MAX (33) typedef enum { VOICE_SESSION_GROUP_DEFAULT = 0, // Session index for regular voice sessions (PTT, FFV) - #ifdef CTRLM_LOCAL_MIC_TAP VOICE_SESSION_GROUP_MIC_TAP = 1, // Session index for microphone tap voice sessions VOICE_SESSION_GROUP_QTY = 2 - #else - VOICE_SESSION_GROUP_QTY = 1 - #endif } ctrlm_voice_session_group_t; #ifdef VOICE_BUFFER_STATS @@ -282,9 +275,7 @@ typedef struct { typedef struct { std::string server_url_src_ptt; std::string server_url_src_ff; - #ifdef CTRLM_LOCAL_MIC_TAP std::string server_url_src_mic_tap; - #endif std::vector server_hosts; std::string aspect_ratio; std::string guide_language; @@ -313,9 +304,7 @@ typedef struct { uint8_t opus_encoder_params[CTRLM_RCU_RIB_ATTR_LEN_OPUS_ENCODING_PARAMS]; bool force_toggle_fallback; bool telemetry_session_stats; - #ifdef NETWORKED_STANDBY_MODE_ENABLED xrsr_dst_params_t dst_params_standby; - #endif xrsr_dst_params_t dst_params_low_latency; bool par_voice_enabled; uint8_t par_voice_eos_method; @@ -391,9 +380,7 @@ typedef struct { typedef struct { std::string urlPtt; std::string urlHf; - #ifdef CTRLM_LOCAL_MIC_TAP std::string urlMicTap; - #endif uint8_t status[CTRLM_VOICE_DEVICE_INVALID]; bool prv_enabled; bool wwFeedback; @@ -529,6 +516,8 @@ class ctrlm_voice_t { bool voice_stb_data_bypass_wuw_verify_failure_get() const; virtual void voice_stb_data_pii_mask_set(bool mask_pii); bool voice_stb_data_pii_mask_get() const; + bool voice_stb_data_local_mic_get() const; + bool voice_stb_data_local_mic_tap_get() const; virtual bool voice_stb_data_device_certificate_set(ctrlm_voice_cert_t &device_cert, bool &ocsp_verify_stapling, bool &ocsp_verify_ca); virtual bool voice_stb_data_device_certificate_set(const char *p12_cert, const char *p12_pass); virtual bool voice_stb_data_device_certificate_set(const char *pem_cert, const char *pem_pkey, const char *pem_chain, const char *pem_passphrase); @@ -586,9 +575,7 @@ class ctrlm_voice_t { static int ctrlm_voice_packet_timeout(void *data); static int ctrlm_voice_controller_session_stats_rxd_timeout(void *data); static int ctrlm_voice_controller_command_status_read_timeout(void *data); - #ifdef BEEP_ON_KWD_ENABLED static int ctrlm_voice_keyword_beep_end_timeout(void *data); - #endif // End Static Callbacks // Event Interface @@ -609,15 +596,11 @@ class ctrlm_voice_t { virtual void voice_server_return_code_callback(const uuid_t uuid, const char *reason, long ret_code); virtual void voice_session_transcription_callback(const uuid_t uuid, const char *transcription); virtual void voice_power_state_change(ctrlm_power_state_t power_state); - #ifdef NETWORKED_STANDBY_MODE_ENABLED virtual void voice_nsm_session_request(void); - #endif virtual void voice_keyword_verified_action(void); - #ifdef BEEP_ON_KWD_ENABLED virtual void voice_keyword_beep_completed_normal(void *data, int size); virtual void voice_keyword_beep_completed_error(void *data, int size); virtual void voice_keyword_beep_completed_callback(bool timeout, bool playback_error); - #endif // End Event Interface protected: @@ -663,6 +646,11 @@ class ctrlm_voice_t { bool mtls_required; bool secure_url_required; bool mask_pii; + bool local_mic; + bool local_mic_tap; + bool local_mic_disable_via_privacy; + const char * beep_on_kwd_file; + bool beep_on_kwd_supported; bool ocsp_verify_stapling; bool ocsp_verify_ca; bool capture_active; @@ -685,11 +673,9 @@ class ctrlm_voice_t { bool xrsr_opened; ctrlm_voice_ipc_t *voice_ipc; - #ifdef BEEP_ON_KWD_ENABLED Thunder::SystemAudioPlayer::ctrlm_thunder_plugin_system_audio_player_t *obj_sap; bool sap_opened; ctrlm_timestamp_t sap_play_timestamp; - #endif // Current Session Data unsigned long opus_samples_per_packet; @@ -759,27 +745,11 @@ xrsr_src_t voice_device_to_xrsr(ctrlm_voice_device_t device); __inline bool ctrlm_voice_device_is_mic(ctrlm_voice_device_t device) { - #ifdef CTRLM_LOCAL_MIC - #ifdef CTRLM_LOCAL_MIC_TAP return(device == CTRLM_VOICE_DEVICE_MICROPHONE || device == CTRLM_VOICE_DEVICE_MICROPHONE_TAP); - #else - return(device == CTRLM_VOICE_DEVICE_MICROPHONE); - #endif - #else - return(false); - #endif } __inline bool ctrlm_voice_xrsr_src_is_mic(xrsr_src_t src) { - #ifdef CTRLM_LOCAL_MIC - #ifdef CTRLM_LOCAL_MIC_TAP return(src == XRSR_SRC_MICROPHONE || src == XRSR_SRC_MICROPHONE_TAP); - #else - return(src == XRSR_SRC_MICROPHONE); - #endif - #else - return(false); - #endif } #endif diff --git a/src/voice/ctrlm_voice_obj_generic.cpp b/src/voice/ctrlm_voice_obj_generic.cpp index 340b295d..4cb35f99 100644 --- a/src/voice/ctrlm_voice_obj_generic.cpp +++ b/src/voice/ctrlm_voice_obj_generic.cpp @@ -165,6 +165,8 @@ void ctrlm_voice_generic_t::voice_sdk_update_routes() { errno_t safec_rc = memset_s(&routes, sizeof(routes), 0, sizeof(routes)); ERR_CHK(safec_rc); + bool networked_standby_supported = ctrlm_is_networked_standby_supported(); + // iterate over source to url mapping for(int j = 0; j < XRSR_SRC_INVALID; j++) { xrsr_src_t src = (xrsr_src_t)j; @@ -178,19 +180,15 @@ void ctrlm_voice_generic_t::voice_sdk_update_routes() { url = &this->prefs.server_url_src_ptt; break; } - #ifdef CTRLM_LOCAL_MIC case CTRLM_VOICE_DEVICE_MICROPHONE: - #endif case CTRLM_VOICE_DEVICE_FF: { url = &this->prefs.server_url_src_ff; break; } - #ifdef CTRLM_LOCAL_MIC_TAP case CTRLM_VOICE_DEVICE_MICROPHONE_TAP: { url = &this->prefs.server_url_src_mic_tap; break; } - #endif default: { break; } @@ -243,11 +241,9 @@ void ctrlm_voice_generic_t::voice_sdk_update_routes() { routes[i].dsts[0].stream_from = stream_from; routes[i].dsts[0].stream_offset = stream_offset; routes[i].dsts[0].stream_until = stream_until; - #ifdef NETWORKED_STANDBY_MODE_ENABLED - if(src == XRSR_SRC_MICROPHONE) { + if(networked_standby_supported && (src == XRSR_SRC_MICROPHONE)) { routes[i].dsts[0].params[XRSR_POWER_MODE_LOW] = &this->prefs.dst_params_standby; } - #endif i++; XLOGD_INFO("url translation from %s to %s", url->c_str(), urls_translated[translated_index].c_str()); } @@ -277,11 +273,9 @@ void ctrlm_voice_generic_t::voice_sdk_update_routes() { routes[i].dsts[0].stream_from = XRSR_STREAM_FROM_LIVE; routes[i].dsts[0].stream_offset = 0; routes[i].dsts[0].stream_until = XRSR_STREAM_UNTIL_END_OF_STREAM; - #ifdef NETWORKED_STANDBY_MODE_ENABLED - if(src == XRSR_SRC_MICROPHONE) { + if(networked_standby_supported && (src == XRSR_SRC_MICROPHONE)) { routes[i].dsts[0].params[XRSR_POWER_MODE_LOW] = &this->prefs.dst_params_standby; } - #endif // Set low latency websocket parameters routes[i].dsts[0].params[XRSR_POWER_MODE_FULL] = &this->prefs.dst_params_low_latency; @@ -324,11 +318,9 @@ void ctrlm_voice_generic_t::voice_sdk_update_routes() { routes[i].dsts[0].stream_from = stream_from; routes[i].dsts[0].stream_offset = stream_offset; routes[i].dsts[0].stream_until = stream_until; - #ifdef NETWORKED_STANDBY_MODE_ENABLED - if(src == XRSR_SRC_MICROPHONE) { + if(networked_standby_supported && (src == XRSR_SRC_MICROPHONE)) { routes[i].dsts[0].params[XRSR_POWER_MODE_LOW] = &this->prefs.dst_params_standby; } - #endif i++; } } @@ -351,11 +343,9 @@ void ctrlm_voice_generic_t::voice_sdk_update_routes() { routes[i].dsts[0].stream_from = stream_from; routes[i].dsts[0].stream_offset = stream_offset; routes[i].dsts[0].stream_until = stream_until; - #ifdef NETWORKED_STANDBY_MODE_ENABLED - if(src == XRSR_SRC_MICROPHONE) { + if(networked_standby_supported && (src == XRSR_SRC_MICROPHONE)) { routes[i].dsts[0].params[XRSR_POWER_MODE_LOW] = &this->prefs.dst_params_standby; } - #endif i++; } } else if(url->rfind("avs", 0) == 0) { @@ -376,11 +366,9 @@ void ctrlm_voice_generic_t::voice_sdk_update_routes() { routes[i].dsts[0].stream_from = stream_from; routes[i].dsts[0].stream_offset = stream_offset; routes[i].dsts[0].stream_until = stream_until; - #ifdef NETWORKED_STANDBY_MODE_ENABLED - if(src == XRSR_SRC_MICROPHONE) { + if(networked_standby_supported && (src == XRSR_SRC_MICROPHONE)) { routes[i].dsts[0].params[XRSR_POWER_MODE_LOW] = &this->prefs.dst_params_standby; } - #endif i++; } } diff --git a/src/voice/ctrlm_voice_types.h b/src/voice/ctrlm_voice_types.h index e8f86fe6..e65a49ba 100644 --- a/src/voice/ctrlm_voice_types.h +++ b/src/voice/ctrlm_voice_types.h @@ -31,12 +31,8 @@ typedef enum { CTRLM_VOICE_DEVICE_PTT, CTRLM_VOICE_DEVICE_FF, - #ifdef CTRLM_LOCAL_MIC CTRLM_VOICE_DEVICE_MICROPHONE, - #ifdef CTRLM_LOCAL_MIC_TAP CTRLM_VOICE_DEVICE_MICROPHONE_TAP, - #endif - #endif CTRLM_VOICE_DEVICE_INVALID, } ctrlm_voice_device_t; diff --git a/src/voice/ipc/ctrlm_voice_ipc_iarm_thunder.cpp b/src/voice/ipc/ctrlm_voice_ipc_iarm_thunder.cpp index 1dfa80b8..022b71f4 100644 --- a/src/voice/ipc/ctrlm_voice_ipc_iarm_thunder.cpp +++ b/src/voice/ipc/ctrlm_voice_ipc_iarm_thunder.cpp @@ -444,9 +444,7 @@ IARM_Result_t ctrlm_voice_ipc_iarm_thunder_t::status(void *data) { rc |= json_object_set_new_nocheck(obj, JSON_URL_PTT, json_string(status.urlPtt.c_str())); rc |= json_object_set_new_nocheck(obj, JSON_URL_HF, json_string(status.urlHf.c_str())); - #ifdef CTRLM_LOCAL_MIC_TAP rc |= json_object_set_new_nocheck(obj, JSON_URL_MIC_TAP, json_string(status.urlMicTap.c_str())); - #endif rc |= json_object_set_new_nocheck(obj, JSON_WW_FEEDBACK, status.wwFeedback ? json_true() : json_false()); rc |= json_object_set_new_nocheck(obj, JSON_PRV, status.prv_enabled ? json_true() : json_false()); rc |= json_object_set_new_nocheck(obj, JSON_THUNDER_RESULT, json_true()); @@ -586,14 +584,16 @@ IARM_Result_t ctrlm_voice_ipc_iarm_thunder_t::voice_session_types(void *data) { int rc = json_array_append_new(obj_types, json_string("ptt_transcription")); rc |= json_array_append_new(obj_types, json_string("ptt_audio_file")); - #ifdef CTRLM_LOCAL_MIC - rc |= json_array_append_new(obj_types, json_string("mic_audio_file")); - rc |= json_array_append_new(obj_types, json_string("mic_stream_single")); - rc |= json_array_append_new(obj_types, json_string("mic_stream_multi")); - rc |= json_array_append_new(obj_types, json_string("mic_tap_stream_single")); - rc |= json_array_append_new(obj_types, json_string("mic_tap_stream_multi")); - rc |= json_array_append_new(obj_types, json_string("mic_factory_test")); - #endif + if(voice_obj->voice_stb_data_local_mic_get()) { + rc |= json_array_append_new(obj_types, json_string("mic_audio_file")); + rc |= json_array_append_new(obj_types, json_string("mic_stream_single")); + rc |= json_array_append_new(obj_types, json_string("mic_stream_multi")); + if(voice_obj->voice_stb_data_local_mic_tap_get()) { + rc |= json_array_append_new(obj_types, json_string("mic_tap_stream_single")); + rc |= json_array_append_new(obj_types, json_string("mic_tap_stream_multi")); + } + rc |= json_array_append_new(obj_types, json_string("mic_factory_test")); + } rc |= json_object_set_new_nocheck(obj_result, JSON_TYPES, obj_types); rc |= json_object_set_new_nocheck(obj_result, JSON_THUNDER_RESULT, json_true()); @@ -964,12 +964,8 @@ const char *voice_device_str(ctrlm_voice_device_t device) { switch(device) { case CTRLM_VOICE_DEVICE_PTT: return("ptt"); case CTRLM_VOICE_DEVICE_FF: return("ff"); - #ifdef CTRLM_LOCAL_MIC case CTRLM_VOICE_DEVICE_MICROPHONE: return("mic"); - #ifdef CTRLM_LOCAL_MIC_TAP case CTRLM_VOICE_DEVICE_MICROPHONE_TAP: return("mic_tap"); - #endif - #endif default: break; } return("invalid"); @@ -1051,9 +1047,9 @@ bool ctrlm_voice_ipc_request_supported_mic_transcription(ctrlm_voice_ipc_request } bool ctrlm_voice_ipc_request_supported_mic_audio_file(ctrlm_voice_ipc_request_config_t *config) { - #ifndef CTRLM_LOCAL_MIC - return(false); - #else + if(!ctrlm_get_voice_obj()->voice_stb_data_local_mic_get()) { + return(false); + } config->requires_transcription = false; config->requires_audio_file = true; config->supports_named_pipe = false; @@ -1062,7 +1058,6 @@ bool ctrlm_voice_ipc_request_supported_mic_audio_file(ctrlm_voice_ipc_request_co config->low_latency = false; config->low_cpu_util = false; return(true); - #endif } bool ctrlm_voice_ipc_request_supported_mic_stream_default(ctrlm_voice_ipc_request_config_t *config) { @@ -1081,9 +1076,9 @@ bool ctrlm_voice_ipc_request_supported_mic_stream_default(ctrlm_voice_ipc_reques } bool ctrlm_voice_ipc_request_supported_mic_stream_single(ctrlm_voice_ipc_request_config_t *config) { - #ifndef CTRLM_LOCAL_MIC - return(false); - #else + if(!ctrlm_get_voice_obj()->voice_stb_data_local_mic_get()) { + return(false); + } config->requires_transcription = false; config->requires_audio_file = false; config->supports_named_pipe = false; @@ -1092,13 +1087,12 @@ bool ctrlm_voice_ipc_request_supported_mic_stream_single(ctrlm_voice_ipc_request config->low_latency = true; config->low_cpu_util = false; return(true); - #endif } bool ctrlm_voice_ipc_request_supported_mic_stream_multi(ctrlm_voice_ipc_request_config_t *config) { - #ifndef CTRLM_LOCAL_MIC - return(false); - #else + if(!ctrlm_get_voice_obj()->voice_stb_data_local_mic_get()) { + return(false); + } config->requires_transcription = false; config->requires_audio_file = false; config->supports_named_pipe = false; @@ -1107,13 +1101,12 @@ bool ctrlm_voice_ipc_request_supported_mic_stream_multi(ctrlm_voice_ipc_request_ config->low_latency = true; config->low_cpu_util = false; return(true); - #endif } bool ctrlm_voice_ipc_request_supported_mic_tap_stream_single(ctrlm_voice_ipc_request_config_t *config) { - #ifndef CTRLM_LOCAL_MIC_TAP - return(false); - #else + if(!ctrlm_get_voice_obj()->voice_stb_data_local_mic_tap_get()) { + return(false); + } config->requires_transcription = false; config->requires_audio_file = false; config->supports_named_pipe = false; @@ -1122,13 +1115,12 @@ bool ctrlm_voice_ipc_request_supported_mic_tap_stream_single(ctrlm_voice_ipc_req config->low_latency = true; config->low_cpu_util = true; return(true); - #endif } bool ctrlm_voice_ipc_request_supported_mic_tap_stream_multi(ctrlm_voice_ipc_request_config_t *config) { - #ifndef CTRLM_LOCAL_MIC_TAP - return(false); - #else + if(!ctrlm_get_voice_obj()->voice_stb_data_local_mic_tap_get()) { + return(false); + } config->requires_transcription = false; config->requires_audio_file = false; config->supports_named_pipe = false; @@ -1137,20 +1129,22 @@ bool ctrlm_voice_ipc_request_supported_mic_tap_stream_multi(ctrlm_voice_ipc_requ config->low_latency = true; config->low_cpu_util = true; return(true); - #endif } bool ctrlm_voice_ipc_request_supported_mic_factory_test(ctrlm_voice_ipc_request_config_t *config) { - #ifdef CTRLM_LOCAL_MIC_TAP - config->requires_transcription = false; - config->requires_audio_file = false; - config->supports_named_pipe = false; - config->device = CTRLM_VOICE_DEVICE_MICROPHONE_TAP; - config->format = { .type = CTRLM_VOICE_FORMAT_PCM_RAW }; - config->low_latency = true; - config->low_cpu_util = true; - return(true); - #elif defined(CTRLM_LOCAL_MIC) + if(ctrlm_get_voice_obj()->voice_stb_data_local_mic_tap_get()) { + config->requires_transcription = false; + config->requires_audio_file = false; + config->supports_named_pipe = false; + config->device = CTRLM_VOICE_DEVICE_MICROPHONE_TAP; + config->format = { .type = CTRLM_VOICE_FORMAT_PCM_RAW }; + config->low_latency = true; + config->low_cpu_util = true; + return(true); + } + if(!ctrlm_get_voice_obj()->voice_stb_data_local_mic_get()) { + return(false); + } config->requires_transcription = false; config->requires_audio_file = false; config->supports_named_pipe = false; @@ -1159,7 +1153,4 @@ bool ctrlm_voice_ipc_request_supported_mic_factory_test(ctrlm_voice_ipc_request_ config->low_latency = true; config->low_cpu_util = false; return(true); - #else - return(false); - #endif } From bcc3be830dd5b956b82c3c05c80d25179cf66dd4 Mon Sep 17 00:00:00 2001 From: dwolaver <44593664+dwolaver@users.noreply.github.com> Date: Tue, 18 Nov 2025 19:56:45 -0500 Subject: [PATCH 11/81] RDKEMW-9124 : remove xr-voice-sdk build flags - XRAUDIO_CURTAIL XLOG_CURTAIL (#132) --- src/ctrlm_main.cpp | 5 ++++- src/factory/ctrlmf_version.c | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ctrlm_main.cpp b/src/ctrlm_main.cpp index 65f3ad19..272d254e 100644 --- a/src/ctrlm_main.cpp +++ b/src/ctrlm_main.cpp @@ -479,7 +479,10 @@ int main(int argc, char *argv[]) { XLOGD_INFO("name <%-24s> version <%-9s> branch <%-20s> commit <%s>", entry->name ? entry->name : "NULL", entry->version ? entry->version : "NULL", entry->branch ? entry->branch : "NULL", entry->commit_id ? entry->commit_id : "NULL"); } } - vsdk_init(true); + + const char *filename = NULL; + uint32_t file_size_max = 0; + vsdk_init(true, filename, file_size_max); //struct sched_param param; //param.sched_priority = 10; diff --git a/src/factory/ctrlmf_version.c b/src/factory/ctrlmf_version.c index cffa6584..459f0fd7 100644 --- a/src/factory/ctrlmf_version.c +++ b/src/factory/ctrlmf_version.c @@ -36,7 +36,7 @@ bool ctrlmf_init(xlog_level_t level, bool requires_audio_playback) { rdk_version_object_free(&info); - int rc = xlog_init(XLOG_MODULE_ID, NULL, 0, true); + int rc = xlog_init(XLOG_MODULE_ID, NULL, 0, true, false); xlog_level_set_all(level); if(rc != 0) { From a5109c82635bae5cf6a97f86bf1e43be051c5d5f Mon Sep 17 00:00:00 2001 From: dwolaver <44593664+dwolaver@users.noreply.github.com> Date: Wed, 19 Nov 2025 07:28:04 -0500 Subject: [PATCH 12/81] RDKEMW-10480 : ctrlm release v1.1.6, xr-voice-sdk v1.0.7 (#149) --- CHANGELOG.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef1e336b..ea63c55d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,22 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [1.1.6](https://github.com/rdkcentral/control/compare/1.1.5...1.1.6) + +> 19 November 2025 + +- RDKEMW-9124 : remove xr-voice-sdk build flags - XRAUDIO_CURTAIL XLOG_CURTAIL [`#132`](https://github.com/rdkcentral/control/pull/132) +- RDKEMW-8676 : remove ctrlm build flags - MIC_TAP, LOCAL_MIC, LOCAL_MIC_DISABLE_VIA_PRIVACY [`#120`](https://github.com/rdkcentral/control/pull/120) +- RDKEMW-8664 : remove ctrlm build flags - MEM_DEBUG, ASSERT_ON_WRONG_THREAD [`#118`](https://github.com/rdkcentral/control/pull/118) +- RDKEMW-8297 : remove ctrlm build flags - A5000_ENABLE [`#117`](https://github.com/rdkcentral/control/pull/117) +- RDKEMW-8668 : modify ctrlm build flag - BREAKPAD [`#119`](https://github.com/rdkcentral/control/pull/119) +- RDKEMW-8296 : remove ctrlm build flags - DEEPSLEEP_CLOSE_DB [`#112`](https://github.com/rdkcentral/control/pull/112) +- RDKEMW-8295 : remove ctrlm build flags - MEMORY_LOCK [`#111`](https://github.com/rdkcentral/control/pull/111) +- RDKEMW-7905 : remove ctrlm build flags - ANSI_CODES_DISABLED [`#110`](https://github.com/rdkcentral/control/pull/110) +- Revert "RDKEMW-8929 (#129)" [`#145`](https://github.com/rdkcentral/control/pull/145) +- RDKEMW-10311 : RF4CE update key mapping [`#140`](https://github.com/rdkcentral/control/pull/140) +- RDKEMW-10164: update CHANGELOG for release v1.1.5 [`#139`](https://github.com/rdkcentral/control/pull/139) + #### [1.1.5](https://github.com/rdkcentral/control/compare/1.1.4...1.1.5) > 5 November 2025 From e1fadf0ac1c8191f15e94f2a8e7658dd506c3842 Mon Sep 17 00:00:00 2001 From: Kelvin Lu <119349872+klu339@users.noreply.github.com> Date: Wed, 19 Nov 2025 10:29:46 -0500 Subject: [PATCH 13/81] RDKEMW-9600: FIRST_PACKET_TIMEOUTs (#135) --- src/ble/ctrlm_ble_network.cpp | 79 ++++-- src/ble/ctrlm_ble_network.h | 2 + src/ctrlm_network.cpp | 5 + src/ctrlm_network.h | 2 + src/rf4ce/ctrlm_rf4ce_network.cpp | 226 ++++++++++-------- src/rf4ce/ctrlm_rf4ce_network.h | 2 + src/voice/ctrlm_voice_obj.cpp | 15 +- src/voice/ctrlm_voice_obj.h | 29 ++- .../ipc/ctrlm_voice_ipc_iarm_thunder.cpp | 3 +- 9 files changed, 246 insertions(+), 117 deletions(-) diff --git a/src/ble/ctrlm_ble_network.cpp b/src/ble/ctrlm_ble_network.cpp index dca4c78f..1e141823 100644 --- a/src/ble/ctrlm_ble_network.cpp +++ b/src/ble/ctrlm_ble_network.cpp @@ -525,7 +525,6 @@ void ctrlm_obj_network_ble_t::req_process_voice_session_begin(void *data, int si // only support ADPCM from ble-rcu component ctrlm_hal_ble_VoiceEncoding_t encoding = CTRLM_HAL_BLE_ENCODING_ADPCM; - ctrlm_hal_ble_VoiceStreamEnd_t streamEnd = CTRLM_HAL_BLE_VOICE_STREAM_END_ON_KEY_UP; ctrlm_voice_format_t voice_format = { .type = CTRLM_VOICE_FORMAT_INVALID }; @@ -543,18 +542,21 @@ void ctrlm_obj_network_ble_t::req_process_voice_session_begin(void *data, int si audio_format.getHeaderInfoAdpcm(adpcm_frame->offset_step_size_index, adpcm_frame->offset_predicted_sample_lsb, adpcm_frame->offset_predicted_sample_msb, adpcm_frame->offset_sequence_value, adpcm_frame->shift_sequence_value, adpcm_frame->sequence_value_min, adpcm_frame->sequence_value_max); pressAndHoldSupport = audio_format.getPressAndHoldSupport(); - if(!pressAndHoldSupport) { - streamEnd = CTRLM_HAL_BLE_VOICE_STREAM_END_ON_AUDIO_DURATION; - } controllers_[controller_id]->setPressAndHoldSupport(pressAndHoldSupport); } } + ctrlm_voice_start_audio_params_t audio_start_params; + audio_start_params.m_controller_id = controller_id; + audio_start_params.m_fd = -1; + audio_start_params.m_started = false; + auto audio_start_cb = std::bind(&ctrlm_obj_network_ble_t::start_controller_audio_streaming, this, std::placeholders::_1); + voice_status = ctrlm_get_voice_obj()->voice_session_req(network_id_get(), controller_id, device, voice_format, NULL, controllers_[controller_id]->get_model().c_str(), controllers_[controller_id]->get_sw_revision().to_string().c_str(), controllers_[controller_id]->get_hw_revision().to_string().c_str(), 0.0, - false, NULL, NULL, NULL, true, pressAndHoldSupport); + false, NULL, NULL, NULL, true, pressAndHoldSupport, audio_start_cb, &audio_start_params); if (!controllers_[controller_id]->get_capabilities().has_capability(ctrlm_controller_capabilities_t::capability::PAR) && (VOICE_SESSION_RESPONSE_AVAILABLE_PAR_VOICE == voice_status)) { XLOGD_WARN("PAR voice is enabled but not supported by BLE controller treating as normal voice session"); voice_status = VOICE_SESSION_RESPONSE_AVAILABLE; @@ -562,24 +564,21 @@ void ctrlm_obj_network_ble_t::req_process_voice_session_begin(void *data, int si if (VOICE_SESSION_RESPONSE_AVAILABLE != voice_status) { XLOGD_TELEMETRY("Failed opening voice session in ctrlm_voice_t, error = <%d>", voice_status); } else { + int fd = -1; bool success = false; - if (ble_rcu_interface_) { - int fd = -1; - - if (!ble_rcu_interface_->startAudioStreaming(ieee_address, encoding, streamEnd, fd)) { - XLOGD_ERROR("failed to start audio streaming on remote"); - } else { + if (!audio_start_params.m_started) { // voice session req did not need to start audio + start_controller_audio_streaming(&audio_start_params); + } + fd = audio_start_params.m_fd; - if (fd < 0) { - XLOGD_ERROR("Voice streaming pipe invalid (fd = <%d>), aborting voice session", fd); - success = false; - } else { - XLOGD_INFO("Acquired voice streaming pipe fd = <%d>, sending to voice engine", fd); - //Send the fd acquired from bluez to the voice engine - success = ctrlm_get_voice_obj()->voice_session_data(network_id_get(), controller_id, fd); - } - } + if (fd < 0) { + XLOGD_ERROR("Voice streaming pipe invalid (fd = <%d>), aborting voice session", fd); + success = false; + } else { + XLOGD_INFO("Acquired voice streaming pipe fd = <%d>, sending to voice engine", fd); + //Send the fd acquired from bluez to the voice engine + success = ctrlm_get_voice_obj()->voice_session_data(network_id_get(), controller_id, fd); } if (false == success) { @@ -2616,3 +2615,43 @@ ctrlm_controller_id_t ctrlm_obj_network_ble_t::find_controller_from_upgrade_sess } return id; } + +void ctrlm_obj_network_ble_t::start_controller_audio_streaming(ctrlm_voice_start_audio_params_t *params) { + THREAD_ID_VALIDATE(); + int fd = -1; + ctrlm_controller_id_t id = params->m_controller_id; + params->m_fd = fd; + params->m_started = false; + + if (!ready_) { + XLOGD_FATAL("Network is not ready!"); + return; + } + + if(!controller_exists(id)) { + XLOGD_WARN("Controller %u doesn't exist.", id); + return; + } + + if (!ble_rcu_interface_) { + XLOGD_WARN("ble rcu interface not ready"); + return; + } + + ctrlm_hal_ble_VoiceEncoding_t encoding = CTRLM_HAL_BLE_ENCODING_ADPCM; + ctrlm_hal_ble_VoiceStreamEnd_t streamEnd = CTRLM_HAL_BLE_VOICE_STREAM_END_ON_KEY_UP; + auto rcu = controllers_.at(id); + + if (rcu->getPressAndHoldSupport()) { + streamEnd = CTRLM_HAL_BLE_VOICE_STREAM_END_ON_AUDIO_DURATION; + } + + uint64_t ieee_address = rcu->ieee_address_get().get_value(); + if (!ble_rcu_interface_->startAudioStreaming(ieee_address, encoding, streamEnd, fd)) { + XLOGD_ERROR("failed to start audio streaming on remote"); + return; + } + + params->m_fd = fd; + params->m_started = true; +} diff --git a/src/ble/ctrlm_ble_network.h b/src/ble/ctrlm_ble_network.h index 92868ca1..787bb8b8 100644 --- a/src/ble/ctrlm_ble_network.h +++ b/src/ble/ctrlm_ble_network.h @@ -192,6 +192,8 @@ class ctrlm_obj_network_ble_t : public ctrlm_obj_network_t { std::shared_ptr getConfigSettings(); + virtual void start_controller_audio_streaming(ctrlm_voice_start_audio_params_t *params); + private: ctrlm_obj_network_ble_t(); diff --git a/src/ctrlm_network.cpp b/src/ctrlm_network.cpp index 74ff4129..69fa462b 100644 --- a/src/ctrlm_network.cpp +++ b/src/ctrlm_network.cpp @@ -1074,3 +1074,8 @@ void ctrlm_obj_network_t::iarm_event_rcu_firmware_status(const ctrlm_obj_control } #endif } + +void ctrlm_obj_network_t::start_controller_audio_streaming(ctrlm_voice_start_audio_params_t *params) { + XLOGD_WARN("not implemented for %s network", name_get()); + return; +} diff --git a/src/ctrlm_network.h b/src/ctrlm_network.h index ab22b51b..c39f3285 100644 --- a/src/ctrlm_network.h +++ b/src/ctrlm_network.h @@ -289,6 +289,8 @@ class ctrlm_obj_network_t virtual void iarm_event_rcu_validation_status(void); virtual void iarm_event_rcu_firmware_status(const ctrlm_obj_controller_t &rcu); + virtual void start_controller_audio_streaming(ctrlm_voice_start_audio_params_t *params); + // Internal methods std::string version_; diff --git a/src/rf4ce/ctrlm_rf4ce_network.cpp b/src/rf4ce/ctrlm_rf4ce_network.cpp index de5a22ff..5fea2cd3 100644 --- a/src/rf4ce/ctrlm_rf4ce_network.cpp +++ b/src/rf4ce/ctrlm_rf4ce_network.cpp @@ -3751,94 +3751,35 @@ void ctrlm_obj_network_rf4ce_t::ind_process_voice_session_request(void *data, in XLOGD_INFO("processing session request - type <%s> voice format <%s>", ctrlm_voice_device_str(device_type), ctrlm_voice_format_str(voice_format)); } - std::string controller_name = controllers_[dqm->controller_id]->product_name_get(); - ctrlm_hal_rf4ce_cfm_data_t cb_confirm_rf4ce = NULL; - void * cb_confirm_param = NULL; + std::string controller_name = controllers_[dqm->controller_id]->product_name_get(); + void * cb_confirm_param = NULL; ctrlm_voice_session_rsp_confirm_t cb_confirm_voice_obj = NULL; + ctrlm_voice_start_audio_params_t start_audio_params; + start_audio_params.m_controller_id = dqm->controller_id; + start_audio_params.m_use_stream_params = use_stream_params; + start_audio_params.m_offset = offset; + start_audio_params.m_started = false; + start_audio_params.m_timestamp = dqm->timestamp; + start_audio_params.m_device_type = device_type; + auto audio_start_cb = std::bind(&ctrlm_obj_network_rf4ce_t::start_controller_audio_streaming, this, std::placeholders::_1); + session = ctrlm_get_voice_obj()->voice_session_req(network_id_get(), dqm->controller_id, device_type, voice_format, use_stream_params ? &stream_params : NULL, controller_name.c_str(), sw_version.to_string().c_str(), hw_version.to_string().c_str(), (((double)battery_status.get_voltage_loaded()) * 4.0 / 255), command_status, - &dqm->timestamp, &cb_confirm_voice_obj, &cb_confirm_param); - if(session == VOICE_SESSION_RESPONSE_AVAILABLE_PAR_VOICE) { - if(controllers_[dqm->controller_id]->get_capabilities().has_capability(ctrlm_controller_capabilities_t::capability::PAR)) { - session = VOICE_SESSION_RESPONSE_AVAILABLE_SKIP_CHAN_CHECK_PAR_VOICE; - } else { - session = VOICE_SESSION_RESPONSE_AVAILABLE; - } - } - if(session == VOICE_SESSION_RESPONSE_AVAILABLE) { - session = VOICE_SESSION_RESPONSE_AVAILABLE_SKIP_CHAN_CHECK; - } - - XLOGD_INFO("Voice Session Response Status <%#x>", session); - - // Send the response back to the HAL device - guchar response[5]; - guchar response_len = 2; - - response[0] = MSO_VOICE_CMD_ID_VOICE_SESSION_RESPONSE; - response[1] = session; - if(use_stream_params && session == VOICE_SESSION_RESPONSE_AVAILABLE_SKIP_CHAN_CHECK) { // Add stream params in the response - response[1] |= 0x80; - response[2] = (guchar) stream_begin_; - response[3] = (offset & 0xFF); - response[4] = (offset >> 8); - response_len = 5; - } - - if(session == VOICE_SESSION_RESPONSE_AVAILABLE_SKIP_CHAN_CHECK_PAR_VOICE) { - voice_params_par_t params; - ctrlm_get_voice_obj()->voice_params_par_get(¶ms); + &dqm->timestamp, &cb_confirm_voice_obj, &cb_confirm_param, + false, false, audio_start_cb, &start_audio_params); - XLOGD_INFO("PAR Voice EOS data bytes timeout <%d> method <%d>", params.par_voice_eos_timeout, params.par_voice_eos_method); - response[2] = params.par_voice_eos_method; - response[3] = (params.par_voice_eos_timeout & 0xFF); - response[4] = (params.par_voice_eos_timeout >> 8); - response_len = 5; + if(!start_audio_params.m_started) { + start_audio_params.m_cb_confirm_voice_obj = cb_confirm_voice_obj; + start_audio_params.m_cb_confirm_param = cb_confirm_param; + start_audio_params.m_status = session; + start_controller_audio_streaming(&start_audio_params); } - ctrlm_timestamp_t hal_timestamp = dqm->timestamp; - - // Determine when to send the response (50 ms after receipt) - if(controller_type_get(dqm->controller_id) == RF4CE_CONTROLLER_TYPE_XR19) { - ctrlm_timestamp_add_ms(&dqm->timestamp, response_idle_time_ff_); - } else { - ctrlm_timestamp_add_ms(&dqm->timestamp, CTRLM_RF4CE_CONST_RESPONSE_IDLE_TIME); - } - - - if(cb_confirm_voice_obj != NULL && (session == VOICE_SESSION_RESPONSE_AVAILABLE_SKIP_CHAN_CHECK || - session == VOICE_SESSION_RESPONSE_AVAILABLE_SKIP_CHAN_CHECK_PAR_VOICE)) { // Only confirm response for accepted session so there is only ever one response stored - voice_session_rsp_confirm_ = cb_confirm_voice_obj; - voice_session_rsp_confirm_param_ = cb_confirm_param; - - timestamp_voice_session_request_ = hal_timestamp; - timestamp_voice_first_packet_ = hal_timestamp; - - cb_confirm_rf4ce = ctrlm_network_rf4ce_cfm_voice_session_rsp; - cb_confirm_param = voice_session_rsp_params_.network_id; - - // Store controller id, packet and timestamp for retransmission in case of send error - voice_session_rsp_params_.controller_id = dqm->controller_id; - voice_session_rsp_params_.response_len = response_len; - voice_session_rsp_params_.timestamp_hal = hal_timestamp; - voice_session_rsp_params_.timestamp_begin = dqm->timestamp; - voice_session_rsp_params_.timestamp_end = dqm->timestamp; - voice_session_rsp_params_.retries = 0; - ctrlm_timestamp_add_ms(&voice_session_rsp_params_.timestamp_end, CTRLM_RF4CE_CONST_RESPONSE_WAIT_TIME); - errno_t safec_rc = memcpy_s(&voice_session_rsp_params_.response, sizeof(voice_session_rsp_params_.response),response, response_len); - ERR_CHK(safec_rc); - ctrlm_timestamp_get(&voice_session_rsp_params_.timestamp_rsp_req); - } - - req_data(CTRLM_RF4CE_PROFILE_ID_VOICE, dqm->controller_id, dqm->timestamp, response_len, response, NULL, NULL, false, single_channel_rsp_, cb_confirm_rf4ce, cb_confirm_param); - - XLOGD_INFO("session response delivered"); - if(session != VOICE_SESSION_RESPONSE_AVAILABLE_SKIP_CHAN_CHECK && session != VOICE_SESSION_RESPONSE_AVAILABLE && session != VOICE_SESSION_RESPONSE_AVAILABLE_SKIP_CHAN_CHECK_PAR_VOICE && session != VOICE_SESSION_RESPONSE_AVAILABLE_PAR_VOICE) { voice_session_active_count_--; @@ -3847,26 +3788,10 @@ void ctrlm_obj_network_rf4ce_t::ind_process_voice_session_request(void *data, in property.state = CTRLM_HAL_FREQUENCY_AGILITY_ENABLE; ctrlm_network_property_set(network_id_get(), CTRLM_HAL_NETWORK_PROPERTY_FREQUENCY_AGILITY, (void *)&property, sizeof(property)); } - - if(device_type == CTRLM_VOICE_DEVICE_PTT) { - // Send voice key up event since the session was not accepted - process_event_key(dqm->controller_id, CTRLM_KEY_STATUS_UP, CTRLM_KEY_CODE_PUSH_TO_TALK); - } } if(dqm->status != VOICE_SESSION_RESPONSE_AVAILABLE && dqm->status != VOICE_SESSION_RESPONSE_AVAILABLE_SKIP_CHAN_CHECK) { // Session was aborted XLOGD_INFO("voice session abort"); - - // // Broadcast the event over the iarm bus - // ctrlm_voice_iarm_event_session_abort_t event; - // event.api_revision = CTRLM_VOICE_IARM_BUS_API_REVISION; - // event.network_id = dqm->header.network_id; - // event.network_type = ctrlm_network_type_get(dqm->header.network_id); - // event.controller_id = dqm->controller_id; - // event.session_id = ctrlm_voice_session_id_get_next(); - // event.reason = dqm->reason; - - // ctrlm_voice_iarm_event_session_abort(&event); } } @@ -3901,7 +3826,6 @@ void ctrlm_obj_network_rf4ce_t::cfm_voice_session_rsp(void *data, int size) { } ctrlm_timestamp_t now; ctrlm_timestamp_get(&now); - double loadavg[3] = { -1, -1, -1 }; getloadavg(loadavg, 3); struct sysinfo s_info; @@ -5093,3 +5017,117 @@ void ctrlm_obj_network_rf4ce_t::controller_init_uinput(ctrlm_controller_id_t con return; } } + +void ctrlm_obj_network_rf4ce_t::start_controller_audio_streaming(ctrlm_voice_start_audio_params_t *params) { + THREAD_ID_VALIDATE(); + params->m_started = false; + ctrlm_controller_id_t controller_id = params->m_controller_id; + ctrlm_voice_device_t device_type = params->m_device_type; + + if(!ready_) { + XLOGD_FATAL("Network is not ready!"); + return; + } + + if(!controller_exists(controller_id)) { + XLOGD_WARN("Controller %u doesn't exist.", controller_id); + return; + } + + ctrlm_voice_session_response_status_t session = params->m_status; + + if(session == VOICE_SESSION_RESPONSE_AVAILABLE_PAR_VOICE) { + if(controllers_[controller_id]->get_capabilities().has_capability(ctrlm_controller_capabilities_t::capability::PAR)) { + session = VOICE_SESSION_RESPONSE_AVAILABLE_SKIP_CHAN_CHECK_PAR_VOICE; + } else { + session = VOICE_SESSION_RESPONSE_AVAILABLE; + } + } + if(session == VOICE_SESSION_RESPONSE_AVAILABLE) { + session = VOICE_SESSION_RESPONSE_AVAILABLE_SKIP_CHAN_CHECK; + } + + XLOGD_INFO("Voice Session Response Status <%#x>", session); + + // Send the response back to the HAL device + guchar response[5]; + guchar response_len = 2; + gint16 offset = params->m_offset; + + response[0] = MSO_VOICE_CMD_ID_VOICE_SESSION_RESPONSE; + response[1] = session; + if(params->m_use_stream_params && session == VOICE_SESSION_RESPONSE_AVAILABLE_SKIP_CHAN_CHECK) { // Add stream params in the response + response[1] |= 0x80; + response[2] = (guchar) stream_begin_; + response[3] = (offset & 0xFF); + response[4] = (offset >> 8); + response_len = 5; + } + + if(session == VOICE_SESSION_RESPONSE_AVAILABLE_SKIP_CHAN_CHECK_PAR_VOICE) { + voice_params_par_t voice_params; + ctrlm_get_voice_obj()->voice_params_par_get(&voice_params); + + XLOGD_INFO("PAR Voice EOS data bytes timeout <%d> method <%d>", voice_params.par_voice_eos_timeout, voice_params.par_voice_eos_method); + response[2] = voice_params.par_voice_eos_method; + response[3] = (voice_params.par_voice_eos_timeout & 0xFF); + response[4] = (voice_params.par_voice_eos_timeout >> 8); + response_len = 5; + } + + ctrlm_timestamp_t hal_timestamp = params->m_timestamp; + + // Determine when to send the response (50 ms after receipt) + if(controller_type_get(controller_id) == RF4CE_CONTROLLER_TYPE_XR19) { + ctrlm_timestamp_add_ms(¶ms->m_timestamp, response_idle_time_ff_); + } else { + ctrlm_timestamp_add_ms(¶ms->m_timestamp, CTRLM_RF4CE_CONST_RESPONSE_IDLE_TIME); + } + + ctrlm_hal_rf4ce_cfm_data_t cb_confirm_rf4ce = NULL; + + if(params->m_cb_confirm_voice_obj != NULL && (session == VOICE_SESSION_RESPONSE_AVAILABLE_SKIP_CHAN_CHECK || + session == VOICE_SESSION_RESPONSE_AVAILABLE_SKIP_CHAN_CHECK_PAR_VOICE)) { // Only confirm response for accepted session so there is only ever one response stored + voice_session_rsp_confirm_ = params->m_cb_confirm_voice_obj; + voice_session_rsp_confirm_param_ = params->m_cb_confirm_param; + + timestamp_voice_session_request_ = hal_timestamp; + timestamp_voice_first_packet_ = hal_timestamp; + + cb_confirm_rf4ce = ctrlm_network_rf4ce_cfm_voice_session_rsp; + params->m_cb_confirm_param = voice_session_rsp_params_.network_id; + + // Store controller id, packet and timestamp for retransmission in case of send error + voice_session_rsp_params_.controller_id = controller_id; + voice_session_rsp_params_.response_len = response_len; + voice_session_rsp_params_.timestamp_hal = hal_timestamp; + voice_session_rsp_params_.timestamp_begin = params->m_timestamp; + voice_session_rsp_params_.timestamp_end = params->m_timestamp; + voice_session_rsp_params_.retries = 0; + ctrlm_timestamp_add_ms(&voice_session_rsp_params_.timestamp_end, CTRLM_RF4CE_CONST_RESPONSE_WAIT_TIME); + errno_t safec_rc = memcpy_s(&voice_session_rsp_params_.response, sizeof(voice_session_rsp_params_.response),response, response_len); + ERR_CHK(safec_rc); + ctrlm_timestamp_get(&voice_session_rsp_params_.timestamp_rsp_req); + } + + req_data(CTRLM_RF4CE_PROFILE_ID_VOICE, controller_id, params->m_timestamp, response_len, response, NULL, NULL, false, single_channel_rsp_, cb_confirm_rf4ce, params->m_cb_confirm_param); + + XLOGD_INFO("session response delivered"); + + if(session != VOICE_SESSION_RESPONSE_AVAILABLE_SKIP_CHAN_CHECK && session != VOICE_SESSION_RESPONSE_AVAILABLE && + session != VOICE_SESSION_RESPONSE_AVAILABLE_SKIP_CHAN_CHECK_PAR_VOICE && session != VOICE_SESSION_RESPONSE_AVAILABLE_PAR_VOICE) { + voice_session_active_count_--; + if(voice_session_active_count_ == 0) { // Re-enable frequency agility if the no other active RF4CE voice sessions + ctrlm_hal_network_property_frequency_agility_t property; + property.state = CTRLM_HAL_FREQUENCY_AGILITY_ENABLE; + ctrlm_network_property_set(network_id_get(), CTRLM_HAL_NETWORK_PROPERTY_FREQUENCY_AGILITY, (void *)&property, sizeof(property)); + } + + if(device_type == CTRLM_VOICE_DEVICE_PTT) { + // Send voice key up event since the session was not accepted + process_event_key(controller_id, CTRLM_KEY_STATUS_UP, CTRLM_KEY_CODE_PUSH_TO_TALK); + } + } + + params->m_started = true; +} diff --git a/src/rf4ce/ctrlm_rf4ce_network.h b/src/rf4ce/ctrlm_rf4ce_network.h index 1e4ce251..07298971 100644 --- a/src/rf4ce/ctrlm_rf4ce_network.h +++ b/src/rf4ce/ctrlm_rf4ce_network.h @@ -462,6 +462,8 @@ class ctrlm_obj_network_rf4ce_t : public ctrlm_obj_network_t virtual std::vector get_controller_obj_list() const; void rcu_timeout_key_release(void *data, int data_size); + virtual void start_controller_audio_streaming(ctrlm_voice_start_audio_params_t *params); + protected: virtual gboolean key_event_hook(ctrlm_network_id_t network_id, ctrlm_controller_id_t controller_id, ctrlm_key_status_t key_status, ctrlm_key_code_t key_code); diff --git a/src/voice/ctrlm_voice_obj.cpp b/src/voice/ctrlm_voice_obj.cpp index 93c12ac2..4a26f316 100644 --- a/src/voice/ctrlm_voice_obj.cpp +++ b/src/voice/ctrlm_voice_obj.cpp @@ -1344,7 +1344,7 @@ ctrlm_voice_session_response_status_t ctrlm_voice_t::voice_session_req(ctrlm_net ctrlm_voice_device_t device_type, ctrlm_voice_format_t format, voice_session_req_stream_params *stream_params, const char *controller_name, const char *sw_version, const char *hw_version, double voltage, bool command_status, - ctrlm_timestamp_t *timestamp, ctrlm_voice_session_rsp_confirm_t *cb_confirm, void **cb_confirm_param, bool use_external_data_pipe, bool press_and_hold, const char *l_transcription_in, const char *audio_file_in, const uuid_t *uuid, bool low_latency, bool low_cpu_util, int audio_fd) { + ctrlm_timestamp_t *timestamp, ctrlm_voice_session_rsp_confirm_t *cb_confirm, void **cb_confirm_param, bool use_external_data_pipe, bool press_and_hold, std::function cb_start_audio, ctrlm_voice_start_audio_params_t *cb_audio_start_params, const char *l_transcription_in, const char *audio_file_in, const uuid_t *uuid, bool low_latency, bool low_cpu_util, int audio_fd) { ctrlm_voice_session_t *session = &this->voice_session[voice_device_to_session_group(device_type)]; @@ -1376,6 +1376,7 @@ ctrlm_voice_session_response_status_t ctrlm_voice_t::voice_session_req(ctrlm_net // Cancel current speech router session XLOGD_INFO("Waiting on the results from previous session, aborting this and continuing.."); + pre_session_terminate(cb_start_audio, cb_audio_start_params, cb_confirm, cb_confirm_param); xrsr_session_terminate(voice_device_to_xrsr(session->voice_device)); // Synchronous - this will take a bit of time. Might need to revisit this down the road. } bool request_new_session = true; @@ -1387,6 +1388,7 @@ ctrlm_voice_session_response_status_t ctrlm_voice_t::voice_session_req(ctrlm_net request_new_session = false; } else { // Cancel current speech router session XLOGD_WARN("Session in progress with same controller - src <%s> dst <%s>, aborting this and continuing..", ctrlm_voice_state_src_str(session->state_src), ctrlm_voice_state_dst_str(session->state_dst)); + pre_session_terminate(cb_start_audio, cb_audio_start_params, cb_confirm, cb_confirm_param); xrsr_session_terminate(voice_device_to_xrsr(session->voice_device)); // Synchronous - this will take a bit of time. Might need to revisit this down the road. } } else { // session in progress with different controller @@ -4244,3 +4246,14 @@ void ctrlm_voice_t::url_hostname_patterns(const std::vector &obj_se this->url_hostname_pattern_add(itr.c_str()); } } + +void ctrlm_voice_t::pre_session_terminate(std::function cb_start_audio, ctrlm_voice_start_audio_params_t *cb_audio_start_params, ctrlm_voice_session_rsp_confirm_t *cb_confirm, void **cb_confirm_param) { + if (cb_start_audio != nullptr && cb_audio_start_params != nullptr) { + if(cb_confirm != NULL && cb_confirm_param != NULL) { + cb_audio_start_params->m_cb_confirm_voice_obj = ctrlm_voice_session_response_confirm; + cb_audio_start_params->m_cb_confirm_param = NULL; + cb_audio_start_params->m_status = (this->prefs.par_voice_enabled) ? VOICE_SESSION_RESPONSE_AVAILABLE_PAR_VOICE : VOICE_SESSION_RESPONSE_AVAILABLE; + } + cb_start_audio(cb_audio_start_params); + } +} diff --git a/src/voice/ctrlm_voice_obj.h b/src/voice/ctrlm_voice_obj.h index bd8de16c..3976a62c 100644 --- a/src/voice/ctrlm_voice_obj.h +++ b/src/voice/ctrlm_voice_obj.h @@ -389,6 +389,29 @@ typedef struct { typedef void (*ctrlm_voice_session_rsp_confirm_t)(bool result, signed long long rsp_time, unsigned int rsp_window, const std::string &err_str, ctrlm_timestamp_t *timestamp, void *user_data); +class ctrlm_voice_start_audio_params_t +{ +public: + // Generic + ctrlm_voice_start_audio_params_t() = default; + virtual ~ctrlm_voice_start_audio_params_t() = default; + + ctrlm_controller_id_t m_controller_id = -1; + bool m_started = false; + + // BLE + int m_fd = -1; + + // RF4CE + bool m_use_stream_params = false; + int16_t m_offset = 0; + ctrlm_timestamp_t m_timestamp; + ctrlm_voice_session_rsp_confirm_t m_cb_confirm_voice_obj; + void * m_cb_confirm_param; + ctrlm_voice_session_response_status_t m_status; + ctrlm_voice_device_t m_device_type; +}; + typedef struct { ctrlm_network_id_t network_id; ctrlm_network_type_t network_type; @@ -471,7 +494,7 @@ class ctrlm_voice_t { ctrlm_voice_t(); virtual ~ctrlm_voice_t(); - ctrlm_voice_session_response_status_t voice_session_req(ctrlm_network_id_t network_id, ctrlm_controller_id_t controller_id, ctrlm_voice_device_t device_type, ctrlm_voice_format_t format, voice_session_req_stream_params *stream_params, const char *controller_name, const char *sw_version, const char *hw_version, double voltage, bool command_status=false, ctrlm_timestamp_t *timestamp=NULL, ctrlm_voice_session_rsp_confirm_t *cb_confirm=NULL, void **cb_confirm_param=NULL, bool use_external_data_pipe=false, bool press_and_hold=true, const char *transcription_in=NULL, const char *audio_file_in=NULL, const uuid_t *uuid = NULL, bool low_latency=false, bool low_cpu_util=false, int audio_fd = -1); + ctrlm_voice_session_response_status_t voice_session_req(ctrlm_network_id_t network_id, ctrlm_controller_id_t controller_id, ctrlm_voice_device_t device_type, ctrlm_voice_format_t format, voice_session_req_stream_params *stream_params, const char *controller_name, const char *sw_version, const char *hw_version, double voltage, bool command_status=false, ctrlm_timestamp_t *timestamp=NULL, ctrlm_voice_session_rsp_confirm_t *cb_confirm=NULL, void **cb_confirm_param=NULL, bool use_external_data_pipe=false, bool press_and_hold=true, std::function cb_start_audio=NULL, ctrlm_voice_start_audio_params_t *cb_audio_start_params=NULL, const char *transcription_in=NULL, const char *audio_file_in=NULL, const uuid_t *uuid = NULL, bool low_latency=false, bool low_cpu_util=false, int audio_fd = -1); void voice_session_rsp_confirm(bool result, signed long long rsp_time, unsigned int rsp_window, const std::string &err_str, ctrlm_timestamp_t *timestamp); bool voice_session_data(ctrlm_network_id_t network_id, ctrlm_controller_id_t controller_id, const char *buffer, long unsigned int length, ctrlm_timestamp_t *timestamp=NULL, uint8_t *lqi=NULL); bool voice_session_data(ctrlm_network_id_t network_id, ctrlm_controller_id_t controller_id, int fd, const uuid_t *uuid=NULL); @@ -723,6 +746,10 @@ class ctrlm_voice_t { void audio_state_set(bool session); bool vsdk_is_privacy_enabled(void); double vsdk_keyword_sensitivity_limit_check(double sensitivity); + void pre_session_terminate(std::function cb_start_audio, + ctrlm_voice_start_audio_params_t *cb_audio_start_params, + ctrlm_voice_session_rsp_confirm_t *cb_confirm, + void **cb_confirm_param); }; // Helper Functions diff --git a/src/voice/ipc/ctrlm_voice_ipc_iarm_thunder.cpp b/src/voice/ipc/ctrlm_voice_ipc_iarm_thunder.cpp index 022b71f4..f88d6fb9 100644 --- a/src/voice/ipc/ctrlm_voice_ipc_iarm_thunder.cpp +++ b/src/voice/ipc/ctrlm_voice_ipc_iarm_thunder.cpp @@ -793,7 +793,8 @@ IARM_Result_t ctrlm_voice_ipc_iarm_thunder_t::voice_session_request(void *data) ctrlm_voice_session_response_status_t voice_status = voice_obj->voice_session_req( CTRLM_MAIN_NETWORK_ID_INVALID, CTRLM_MAIN_CONTROLLER_ID_INVALID, request_config.device, request_config.format, NULL, str_name_of_source.c_str(), "0.0.0.0", "0.0.0.0", 0.0, - false, NULL, NULL, NULL, (fd >= 0) ? true : false, true, str_transcription.empty() ? NULL : str_transcription.c_str(), str_audio_file.empty() ? NULL : str_audio_file.c_str(), &request_uuid, request_config.low_latency, request_config.low_cpu_util, fd); + false, NULL, NULL, NULL, (fd >= 0) ? true : false, true, NULL, NULL, + str_transcription.empty() ? NULL : str_transcription.c_str(), str_audio_file.empty() ? NULL : str_audio_file.c_str(), &request_uuid, request_config.low_latency, request_config.low_cpu_util, fd); if (voice_status != VOICE_SESSION_RESPONSE_AVAILABLE && voice_status != VOICE_SESSION_RESPONSE_AVAILABLE_PAR_VOICE) { XLOGD_ERROR("Failed opening voice session <%s>", ctrlm_voice_session_response_status_str(voice_status)); From baebbf2e09e5f01bebb36a974618fc208a3a7540 Mon Sep 17 00:00:00 2001 From: Kelvin Lu <119349872+klu339@users.noreply.github.com> Date: Tue, 2 Dec 2025 12:09:49 -0500 Subject: [PATCH 14/81] RDKEMW-10425: Automation Logging (#144) --- src/ble/ctrlm_ble_controller.cpp | 6 ++--- src/ble/ctrlm_ble_network.cpp | 22 +++++++++---------- .../hal/blercu/blercupairingstatemachine.cpp | 12 +++++----- src/ble/hal/blercu/bluez/blercuadapter.cpp | 4 ++-- src/ble/hal/blercu/bluez/blercudevice.cpp | 2 +- src/ctrlm_controller.cpp | 10 ++++----- src/ctrlm_ir_controller.cpp | 2 +- src/ctrlm_main.cpp | 8 +++---- src/ctrlm_main_iarm.cpp | 2 +- src/ipc/ctrlm_ipc_iarm_powermanager.cpp | 2 +- src/voice/ctrlm_voice_obj.cpp | 14 ++++++------ .../endpoints/ctrlm_voice_endpoint_http.cpp | 2 +- .../endpoints/ctrlm_voice_endpoint_sdt.cpp | 2 +- .../ctrlm_voice_endpoint_ws_nextgen.cpp | 4 ++-- .../endpoints/ctrlm_voice_endpoint_ws_nsp.cpp | 2 +- .../ipc/ctrlm_voice_ipc_iarm_thunder.cpp | 4 ++-- 16 files changed, 49 insertions(+), 49 deletions(-) diff --git a/src/ble/ctrlm_ble_controller.cpp b/src/ble/ctrlm_ble_controller.cpp index d8886150..d86650db 100644 --- a/src/ble/ctrlm_ble_controller.cpp +++ b/src/ble/ctrlm_ble_controller.cpp @@ -615,13 +615,13 @@ void ctrlm_obj_controller_ble_t::print_status() { XLOGD_INFO("Model : %s", model_->to_string().c_str()); XLOGD_INFO("MAC Address : %s", ieee_address_->to_string().c_str()); XLOGD_INFO("Device Minor ID : %d", device_minor_id_); - XLOGD_INFO("Battery Level : %u%%", get_battery_percent()); + XLOGD_AUTOMATION_INFO("Battery Level : %u%%", get_battery_percent()); XLOGD_INFO("HW Revision : %s", hw_revision_->to_string().c_str()); XLOGD_INFO("FW Revision : %s", fw_revision_->to_string().c_str()); - XLOGD_INFO("SW Revision : %s", sw_revision_->to_string().c_str()); + XLOGD_AUTOMATION_INFO("SW Revision : %s", sw_revision_->to_string().c_str()); XLOGD_INFO("Serial Number : %s", serial_number_->to_string().c_str()); XLOGD_INFO(""); - XLOGD_INFO("Connected : %s", (connected_==true) ? "true" : "false"); + XLOGD_AUTOMATION_INFO("Connected : %s", (connected_==true) ? "true" : "false"); XLOGD_INFO("Last Activity Time : %s", ctrlm_utils_time_as_string(this->last_activity_time_get()).c_str()); XLOGD_INFO("Bound Time : %s", ctrlm_utils_time_as_string(this->time_binding_get()).c_str()); XLOGD_INFO(""); diff --git a/src/ble/ctrlm_ble_network.cpp b/src/ble/ctrlm_ble_network.cpp index 1e141823..8965b71a 100644 --- a/src/ble/ctrlm_ble_network.cpp +++ b/src/ble/ctrlm_ble_network.cpp @@ -576,7 +576,7 @@ void ctrlm_obj_network_ble_t::req_process_voice_session_begin(void *data, int si XLOGD_ERROR("Voice streaming pipe invalid (fd = <%d>), aborting voice session", fd); success = false; } else { - XLOGD_INFO("Acquired voice streaming pipe fd = <%d>, sending to voice engine", fd); + XLOGD_AUTOMATION_INFO("Acquired voice streaming pipe fd = <%d>, sending to voice engine", fd); //Send the fd acquired from bluez to the voice engine success = ctrlm_get_voice_obj()->voice_session_data(network_id_get(), controller_id, fd); } @@ -1825,7 +1825,7 @@ void ctrlm_obj_network_ble_t::ind_process_rcu_status(void *data, int size) { print_status = false; break; case CTRLM_HAL_BLE_PROPERTY_IS_UPGRADING: - XLOGD_INFO("Controller <%s> firmware upgrading = %s", controller->ieee_address_get().to_string().c_str(), dqm->rcu_data.is_upgrading ? "TRUE" : "FALSE"); + XLOGD_AUTOMATION_INFO("Controller <%s> firmware upgrading = %s", controller->ieee_address_get().to_string().c_str(), dqm->rcu_data.is_upgrading ? "TRUE" : "FALSE"); upgrade_in_progress_ = dqm->rcu_data.is_upgrading; if (!dqm->rcu_data.is_upgrading) { // If we get FALSE here, make sure the controller upgrade progress flag is cleared. But we don't want to set the controller progress @@ -1836,7 +1836,7 @@ void ctrlm_obj_network_ble_t::ind_process_rcu_status(void *data, int size) { print_status = false; break; case CTRLM_HAL_BLE_PROPERTY_UPGRADE_PROGRESS: - XLOGD_INFO("Controller <%s> firmware upgrade %d%% complete...", controller->ieee_address_get().to_string().c_str(), dqm->rcu_data.upgrade_progress); + XLOGD_AUTOMATION_INFO("Controller <%s> firmware upgrade %d%% complete...", controller->ieee_address_get().to_string().c_str(), dqm->rcu_data.upgrade_progress); // From a controller perspective, we cannot use the CTRLM_HAL_BLE_PROPERTY_IS_UPGRADING flag above to determine if its actively upgrading. // Instead, its more accurate to use the progress percentage to determine if the remote is actively receiving firmware packets. controller->setUpgradeInProgress(dqm->rcu_data.upgrade_progress > 0 && dqm->rcu_data.upgrade_progress < 100); @@ -1849,7 +1849,7 @@ void ctrlm_obj_network_ble_t::ind_process_rcu_status(void *data, int size) { print_status = false; break; case CTRLM_HAL_BLE_PROPERTY_UPGRADE_ERROR: - XLOGD_ERROR("Controller <%s> firmware upgrade FAILED with error <%s>.", controller->ieee_address_get().to_string().c_str(), dqm->rcu_data.upgrade_error); + XLOGD_AUTOMATION_ERROR("Controller <%s> firmware upgrade FAILED with error <%s>.", controller->ieee_address_get().to_string().c_str(), dqm->rcu_data.upgrade_error); report_status = false; print_status = false; controller->set_upgrade_error(dqm->rcu_data.upgrade_error); @@ -1882,7 +1882,7 @@ void ctrlm_obj_network_ble_t::ind_process_rcu_status(void *data, int size) { controller->ota_failure_cnt_incr(); break; case CTRLM_HAL_BLE_PROPERTY_UNPAIR_REASON: - XLOGD_INFO("Controller <%s> notified reason for unpairing = <%s>", controller->ieee_address_get().to_string().c_str(), ctrlm_ble_unpair_reason_str(dqm->rcu_data.unpair_reason)); + XLOGD_AUTOMATION_INFO("Controller <%s> notified reason for unpairing = <%s>", controller->ieee_address_get().to_string().c_str(), ctrlm_ble_unpair_reason_str(dqm->rcu_data.unpair_reason)); last_rcu_unpair_metrics_.write_rcu_unpair_event(controller->ieee_address_get().get_value(), string(ctrlm_ble_unpair_reason_str(dqm->rcu_data.unpair_reason))); report_status = false; print_status = false; @@ -1897,7 +1897,7 @@ void ctrlm_obj_network_ble_t::ind_process_rcu_status(void *data, int size) { } break; case CTRLM_HAL_BLE_PROPERTY_REBOOT_REASON: - XLOGD_TELEMETRY("Controller <%s> notified reason for rebooting = <%s%s%s%s>", + XLOGD_AUTOMATION_TELEMETRY("Controller <%s> notified reason for rebooting = <%s%s%s%s>", controller->ieee_address_get().to_string().c_str(), ctrlm_ble_reboot_reason_str(dqm->rcu_data.reboot_reason), dqm->rcu_data.reboot_reason == CTRLM_BLE_RCU_REBOOT_REASON_ASSERT ? " - \"" : "", @@ -2205,7 +2205,7 @@ void ctrlm_obj_network_ble_t::ind_process_keypress(void *data, int size) { controller->setVoiceStartTime(keyDownTime); XLOGD_INFO("------------------------------------------------------------------------"); - XLOGD_INFO("CODE_VOICE_KEY button PRESSED event for device: %s", controller->ieee_address_get().to_string().c_str()); + XLOGD_AUTOMATION_INFO("CODE_VOICE_KEY button PRESSED event for device: %s", controller->ieee_address_get().to_string().c_str()); XLOGD_INFO("------------------------------------------------------------------------"); ctrlm_voice_iarm_call_voice_session_t v_params; @@ -2255,7 +2255,7 @@ void ctrlm_obj_network_ble_t::ind_process_keypress(void *data, int size) { if (controller->isVoiceKey(dqm->event.code)) { if(!controller->getPressAndHoldSupport()) { // if the voice session is "Press and Release" then don't end session on voice key up event XLOGD_INFO("------------------------------------------------------------------------"); - XLOGD_INFO("CODE_VOICE_KEY button RELEASED event for device: %s (ignored for PAR session)", controller->ieee_address_get().to_string().c_str()); + XLOGD_AUTOMATION_INFO("CODE_VOICE_KEY button RELEASED event for device: %s (ignored for PAR session)", controller->ieee_address_get().to_string().c_str()); XLOGD_INFO("------------------------------------------------------------------------"); } else { rdkx_timestamp_t keyUpTime, keyUpTimeLocal, voiceStartTimeLocal, firstAudioDataTime; @@ -2290,11 +2290,11 @@ void ctrlm_obj_network_ble_t::ind_process_keypress(void *data, int size) { } XLOGD_INFO("------------------------------------------------------------------------"); - XLOGD_INFO("CODE_VOICE_KEY button RELEASED event for device: %s duration <%lld ms> start lag <%lld ms>", controller->ieee_address_get().to_string().c_str(), audioDurationKeys, startAudioLag); + XLOGD_AUTOMATION_INFO("CODE_VOICE_KEY button RELEASED event for device: %s duration <%lld ms> start lag <%lld ms>", controller->ieee_address_get().to_string().c_str(), audioDurationKeys, startAudioLag); XLOGD_INFO("------------------------------------------------------------------------"); } else { XLOGD_INFO("------------------------------------------------------------------------"); - XLOGD_INFO("CODE_VOICE_KEY button RELEASED event for device: %s duration <%lld ms>", controller->ieee_address_get().to_string().c_str(), audioDurationKeys); + XLOGD_AUTOMATION_INFO("CODE_VOICE_KEY button RELEASED event for device: %s duration <%lld ms>", controller->ieee_address_get().to_string().c_str(), audioDurationKeys); XLOGD_INFO("------------------------------------------------------------------------"); } @@ -2497,7 +2497,7 @@ void ctrlm_obj_network_ble_t::printStatus() { it->second->print_status(); } XLOGD_INFO("BLE Network Status: <%s>", ctrlm_rf_pair_state_str(state_)); - XLOGD_TELEMETRY("IR Programming Status: <%s>", ctrlm_ir_state_str(ir_state_)); + XLOGD_AUTOMATION_TELEMETRY("IR Programming Status: <%s>", ctrlm_ir_state_str(ir_state_)); XLOGD_WARN("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"); } diff --git a/src/ble/hal/blercu/blercupairingstatemachine.cpp b/src/ble/hal/blercu/blercupairingstatemachine.cpp index 0a5572c5..b55613ed 100644 --- a/src/ble/hal/blercu/blercupairingstatemachine.cpp +++ b/src/ble/hal/blercu/blercupairingstatemachine.cpp @@ -517,19 +517,19 @@ void BleRcuPairingStateMachine::onStateTransition(int oldState, int newState) { if (newState == FinishedState) { if (oldState == UnpairingState) { - XLOGD_WARN("timed-out in un-pairing phase (failed rcu may be left paired)"); + XLOGD_AUTOMATION_WARN("timed-out in un-pairing phase (failed rcu may be left paired)"); } else if (oldState == StartingDiscoveryState) { - XLOGD_ERROR("timed-out waiting for discovery started signal"); + XLOGD_AUTOMATION_ERROR("timed-out waiting for discovery started signal"); } else if (oldState == DiscoveringState) { - XLOGD_ERROR("timed-out in discovery phase (didn't find target rcu device to pair to)"); + XLOGD_AUTOMATION_ERROR("timed-out in discovery phase (didn't find target rcu device to pair to)"); } else if (oldState == StoppingDiscoveryState) { - XLOGD_ERROR("timed-out waiting for discovery to stop (suggesting something has gone wrong inside bluez)"); + XLOGD_AUTOMATION_ERROR("timed-out waiting for discovery to stop (suggesting something has gone wrong inside bluez)"); } } else if (newState == UnpairingState) { if (oldState == EnablePairableState || oldState == PairingState) { - XLOGD_WARN("timed-out in pairing phase (rcu device didn't pair within %dms)", m_pairingTimeout); + XLOGD_AUTOMATION_WARN("timed-out in pairing phase (rcu device didn't pair within %dms)", m_pairingTimeout); } else if (oldState == SetupState) { - XLOGD_WARN("timed-out in setup phase (rcu didn't response to all requests within %dms)", m_setupTimeout); + XLOGD_AUTOMATION_WARN("timed-out in setup phase (rcu didn't response to all requests within %dms)", m_setupTimeout); } } } diff --git a/src/ble/hal/blercu/bluez/blercuadapter.cpp b/src/ble/hal/blercu/bluez/blercuadapter.cpp index f8e0bcbd..c7d5834e 100644 --- a/src/ble/hal/blercu/bluez/blercuadapter.cpp +++ b/src/ble/hal/blercu/bluez/blercuadapter.cpp @@ -1721,7 +1721,7 @@ void BleRcuAdapterBluez::onDevicePairedChanged(const BleAddress &address, void BleRcuAdapterBluez::onDeviceReadyChanged(const BleAddress &address, bool ready) { - XLOGD_INFO("device with address %s is %sREADY", address.toString().c_str(), ready ? "" : "NOT "); + XLOGD_AUTOMATION_INFO("device with address %s is %sREADY", address.toString().c_str(), ready ? "" : "NOT "); map>::const_iterator it = m_devices.find(address); @@ -1768,7 +1768,7 @@ bool BleRcuAdapterBluez::setConnectionParams(BleAddress address, double minInter if (address == deviceInfo.address) { - XLOGD_INFO("HCI connection handle: %u, device: %s requesting an update of connection parameters to " + XLOGD_AUTOMATION_INFO("HCI connection handle: %u, device: %s requesting an update of connection parameters to " "minInterval=%f, maxInterval=%f, latency=%d, supervisionTimeout=%d", deviceInfo.handle, deviceInfo.address.toString().c_str(), minInterval, maxInterval, latency, supervisionTimeout); diff --git a/src/ble/hal/blercu/bluez/blercudevice.cpp b/src/ble/hal/blercu/bluez/blercudevice.cpp index 8212a3a1..08aa0287 100644 --- a/src/ble/hal/blercu/bluez/blercudevice.cpp +++ b/src/ble/hal/blercu/bluez/blercudevice.cpp @@ -668,7 +668,7 @@ void BleRcuDeviceBluez::onEnteredRecoveryDisconnectingState() m_recoveryAttempts++; // log the attempt - XLOGD_ERROR("entered recovery state after device %s failed to resolve services (attempt #%d)", + XLOGD_AUTOMATION_ERROR("entered recovery state after device %s failed to resolve services (attempt #%d)", m_address.toString().c_str(), m_recoveryAttempts); diff --git a/src/ctrlm_controller.cpp b/src/ctrlm_controller.cpp index 0088b414..aaae3b40 100644 --- a/src/ctrlm_controller.cpp +++ b/src/ctrlm_controller.cpp @@ -172,11 +172,11 @@ void ctrlm_obj_controller_t::process_event_key(ctrlm_key_status_t key_status, ui last_key_code_->set_value((uint64_t)key_code); last_key_time_update(); - XLOGD_TELEMETRY("ind_process_keypress: %s - MAC Address <%s>, code = <%d> (%s key), status = <%s>", controller_type_str_get().c_str(), - ieee_address_get().to_string().c_str(), - mask ? -1 : key_code, - ctrlm_linux_key_code_str(key_code, mask), - ctrlm_key_status_str(key_status)); + XLOGD_AUTOMATION_TELEMETRY("ind_process_keypress: %s - MAC Address <%s>, code = <%d> (%s key), status = <%s>", controller_type_str_get().c_str(), + ieee_address_get().to_string().c_str(), + mask ? -1 : key_code, + ctrlm_linux_key_code_str(key_code, mask), + ctrlm_key_status_str(key_status)); } ctrlm_controller_capabilities_t ctrlm_obj_controller_t::get_capabilities() const { diff --git a/src/ctrlm_ir_controller.cpp b/src/ctrlm_ir_controller.cpp index db978c7c..17db165b 100644 --- a/src/ctrlm_ir_controller.cpp +++ b/src/ctrlm_ir_controller.cpp @@ -489,7 +489,7 @@ void* ctrlm_ir_key_monitor_thread(void *data) { case 2: { key_status = CTRLM_KEY_STATUS_REPEAT; break; } default: break; } - XLOGD_TELEMETRY("%s - code = <%d> (%s key), status = <%s>", ir_controller->name_get().c_str(), + XLOGD_AUTOMATION_TELEMETRY("%s - code = <%d> (%s key), status = <%s>", ir_controller->name_get().c_str(), ir_controller->mask_key_codes_get() ? -1 : event.code, ctrlm_linux_key_code_str(event.code, ir_controller->mask_key_codes_get()), ctrlm_key_status_str(key_status)); diff --git a/src/ctrlm_main.cpp b/src/ctrlm_main.cpp index 272d254e..1bffc6df 100644 --- a/src/ctrlm_main.cpp +++ b/src/ctrlm_main.cpp @@ -806,7 +806,7 @@ int main(int argc, char *argv[]) { ctrlm_trigger_startup_actions(); - XLOGD_INFO("Enter main loop"); + XLOGD_AUTOMATION_INFO("Enter main loop"); g_main_loop_run(g_ctrlm.main_loop); //Save the shutdown time if it is valid @@ -988,7 +988,7 @@ gboolean ctrlm_thread_monitor(gpointer user_data) { XLOGD_DEBUG("Checking %s", it->name); if(it->response != CTRLM_THREAD_MONITOR_RESPONSE_ALIVE) { - XLOGD_TELEMETRY("Thread %s is unresponsive", it->name); + XLOGD_AUTOMATION_TELEMETRY("Thread %s is unresponsive", it->name); #ifdef BREAKPAD_SUPPORT if(g_ctrlm.thread_monitor_minidump) { XLOGD_FATAL("Thread Monitor Minidump is enabled"); @@ -2329,7 +2329,7 @@ gpointer ctrlm_main_thread(gpointer param) { // Unblock the caller that launched this thread sem_post(&g_ctrlm.semaphore); - XLOGD_INFO("Enter main loop"); + XLOGD_AUTOMATION_INFO("Enter main loop"); do { gpointer msg = g_async_queue_pop(g_ctrlm.queue); @@ -2675,7 +2675,7 @@ gpointer ctrlm_main_thread(gpointer param) { //If execution reaches here, then change power state and inform VSDK of on or deep sleep states g_ctrlm.power_state = dqm->new_state; - XLOGD_INFO("Enter power state <%s>", ctrlm_power_state_str(g_ctrlm.power_state)); + XLOGD_AUTOMATION_INFO("Enter power state <%s>", ctrlm_power_state_str(g_ctrlm.power_state)); if(g_ctrlm.networked_standby_supported && (g_ctrlm.power_state == CTRLM_POWER_STATE_DEEP_SLEEP)) { XLOGD_INFO("NSM is <%s>", (ctrlm_main_get_networked_standby_mode())?"ENABLED":"DISABLED"); } diff --git a/src/ctrlm_main_iarm.cpp b/src/ctrlm_main_iarm.cpp index 8012b334..db124af4 100644 --- a/src/ctrlm_main_iarm.cpp +++ b/src/ctrlm_main_iarm.cpp @@ -753,7 +753,7 @@ IARM_Result_t ctrlm_main_iarm_call_start_pair_with_code(void *arg) { return(IARM_RESULT_INVALID_PARAM); } - XLOGD_INFO("params->network_id = <%d>, params->pair_code = 0x%X", params->network_id, params->pair_code); + XLOGD_AUTOMATION_INFO("params->network_id = <%d>, params->pair_code = 0x%X", params->network_id, params->pair_code); // Signal completion of the operation sem_t semaphore; diff --git a/src/ipc/ctrlm_ipc_iarm_powermanager.cpp b/src/ipc/ctrlm_ipc_iarm_powermanager.cpp index 0bef46ce..24897391 100755 --- a/src/ipc/ctrlm_ipc_iarm_powermanager.cpp +++ b/src/ipc/ctrlm_ipc_iarm_powermanager.cpp @@ -80,7 +80,7 @@ bool ctrlm_ipc_iarm_powermanager_t::get_wakeup_reason_voice() { return false; } - XLOGD_INFO("wakeup_reason <%s>", ctrlm_wakeup_reason_str(wakeup_reason)); + XLOGD_AUTOMATION_INFO("wakeup_reason <%s>", ctrlm_wakeup_reason_str(wakeup_reason)); wakeup_reason_voice = (wakeup_reason == DEEPSLEEP_WAKEUPREASON_VOICE) ? true: false; diff --git a/src/voice/ctrlm_voice_obj.cpp b/src/voice/ctrlm_voice_obj.cpp index 4a26f316..d114aeea 100644 --- a/src/voice/ctrlm_voice_obj.cpp +++ b/src/voice/ctrlm_voice_obj.cpp @@ -1772,16 +1772,16 @@ void ctrlm_voice_t::voice_session_data_post_processing(int bytes_sent, const cha float rx_rate = (elapsed == 0) ? 0 : (session->audio_sent_samples * 2 * 8) / elapsed; session->timeout_packet_tag = g_timeout_add(timeout, ctrlm_voice_packet_timeout, NULL); - XLOGD_DEBUG("Audio %s bytes <%lu> samples <%lu> rate <%6.2f kbps> timeout <%lu ms>", action, session->audio_sent_bytes, session->audio_sent_samples, rx_rate, timeout); + XLOGD_AUTOMATION_DEBUG("Audio %s bytes <%lu> samples <%lu> rate <%6.2f kbps> timeout <%lu ms>", action, session->audio_sent_bytes, session->audio_sent_samples, rx_rate, timeout); } else { #ifdef VOICE_BUFFER_STATS if(voice_buffer_warning_triggered) { - XLOGD_DEBUG("Audio %s bytes <%lu> samples <%lu> pkt cnt <%3u> elapsed <%8llu ms> lag <%8lld ms> (%4.2f packets)", action, session->audio_sent_bytes, session->audio_sent_samples, packets_total, session_time / 1000, session_delta / 1000, (((float)session_delta) / this->voice_packet_interval)); + XLOGD_AUTOMATION_DEBUG("Audio %s bytes <%lu> samples <%lu> pkt cnt <%3u> elapsed <%8llu ms> lag <%8lld ms> (%4.2f packets)", action, session->audio_sent_bytes, session->audio_sent_samples, packets_total, session_time / 1000, session_delta / 1000, (((float)session_delta) / this->voice_packet_interval)); } else { - XLOGD_DEBUG("Audio %s bytes <%lu> samples <%lu>", action, session->audio_sent_bytes, session->audio_sent_samples); + XLOGD_AUTOMATION_DEBUG("Audio %s bytes <%lu> samples <%lu>", action, session->audio_sent_bytes, session->audio_sent_samples); } #else - XLOGD_DEBUG("Audio %s bytes <%lu> samples <%lu>", action, session->audio_sent_bytes, session->audio_sent_samples); + XLOGD_AUTOMATION_DEBUG("Audio %s bytes <%lu> samples <%lu>", action, session->audio_sent_bytes, session->audio_sent_samples); #endif } } @@ -2061,10 +2061,10 @@ void ctrlm_voice_t::voice_session_timeout() { signed long long elapsed = rdkx_timestamp_subtract_ms(session->session_timing.ctrl_audio_rxd_first, timestamp); float rx_rate = (elapsed == 0) ? 0 : (session->audio_sent_samples * 2 * 8) / elapsed; - XLOGD_INFO("elapsed time <%llu> ms rx samples <%u> rate <%6.1f> kbps", elapsed, session->audio_sent_samples, rx_rate); + XLOGD_AUTOMATION_INFO("elapsed time <%llu> ms rx samples <%u> rate <%6.1f> kbps", elapsed, session->audio_sent_samples, rx_rate); reason = CTRLM_VOICE_SESSION_END_REASON_MINIMUM_QOS; } - XLOGD_INFO("%s", ctrlm_voice_session_end_reason_str(reason)); + XLOGD_AUTOMATION_INFO("%s", ctrlm_voice_session_end_reason_str(reason)); this->voice_session_end(session, reason); } @@ -2981,7 +2981,7 @@ void ctrlm_voice_t::voice_stream_end_callback(ctrlm_voice_stream_end_cb_t *strea stream_duration = (session->packets_processed * frame_duration_us) / 1000; samples_per_packet = (session->format.value.adpcm_frame.size_packet - session->format.value.adpcm_frame.size_header) * 2; // 2 samples per byte for ADPCM } - XLOGD_TELEMETRY("src <%s> Packets Lost/Total <%u/%u> %.02f%% duration <%u> ms", ctrlm_voice_device_str(session->voice_device), session->packets_lost, session->packets_lost + session->packets_processed, 100.0 * ((double)session->packets_lost / (double)(session->packets_lost + session->packets_processed)), stream_duration); + XLOGD_AUTOMATION_TELEMETRY("src <%s> Packets Lost/Total <%u/%u> %.02f%% duration <%u> ms", ctrlm_voice_device_str(session->voice_device), session->packets_lost, session->packets_lost + session->packets_processed, 100.0 * ((double)session->packets_lost / (double)(session->packets_lost + session->packets_processed)), stream_duration); #ifdef TELEMETRY_SUPPORT if(this->prefs.telemetry_session_stats) { uint32_t packets_total = session->packets_lost + session->packets_processed; diff --git a/src/voice/endpoints/ctrlm_voice_endpoint_http.cpp b/src/voice/endpoints/ctrlm_voice_endpoint_http.cpp index 653e2260..93396a4b 100644 --- a/src/voice/endpoints/ctrlm_voice_endpoint_http.cpp +++ b/src/voice/endpoints/ctrlm_voice_endpoint_http.cpp @@ -194,7 +194,7 @@ void ctrlm_voice_endpoint_http_t::voice_session_begin_callback_http(void *data, has_sat = true; } - XLOGD_TELEMETRY("session begin - src <%s> h_SAT <%s> h_MTLS <%s> h_OCSPst <%s> h_OCSPca <%s>", ctrlm_voice_device_str(source), has_sat ? "YES" : "NO", use_mtls ? "YES" : "NO", ocsp_verify_stapling ? "YES" : "NO", ocsp_verify_ca ? "YES" : "NO"); + XLOGD_AUTOMATION_TELEMETRY("session begin - src <%s> h_SAT <%s> h_MTLS <%s> h_OCSPst <%s> h_OCSPca <%s>", ctrlm_voice_device_str(source), has_sat ? "YES" : "NO", use_mtls ? "YES" : "NO", ocsp_verify_stapling ? "YES" : "NO", ocsp_verify_ca ? "YES" : "NO"); errno_t safec_rc = strcpy_s(this->user_agent, sizeof(this->user_agent), user_agent.str().c_str()); ERR_CHK(safec_rc); diff --git a/src/voice/endpoints/ctrlm_voice_endpoint_sdt.cpp b/src/voice/endpoints/ctrlm_voice_endpoint_sdt.cpp index ca4fe980..2324878c 100644 --- a/src/voice/endpoints/ctrlm_voice_endpoint_sdt.cpp +++ b/src/voice/endpoints/ctrlm_voice_endpoint_sdt.cpp @@ -250,7 +250,7 @@ void ctrlm_voice_endpoint_sdt_t::voice_session_begin_callback_sdt(void *data, in keyword_verification = true; } } - XLOGD_INFO("session begin - ptt <%s> keyword begin <%u> end <%u> doa <%u> gain <%4.1f> db", (stream_params->push_to_talk ? "TRUE" : "FALSE"), stream_params->keyword_sample_begin, stream_params->keyword_sample_end, stream_params->keyword_doa, stream_params->dynamic_gain); + XLOGD_AUTOMATION_INFO("session begin - ptt <%s> keyword begin <%u> end <%u> doa <%u> gain <%4.1f> db", (stream_params->push_to_talk ? "TRUE" : "FALSE"), stream_params->keyword_sample_begin, stream_params->keyword_sample_end, stream_params->keyword_doa, stream_params->dynamic_gain); } // End handle stream parameters diff --git a/src/voice/endpoints/ctrlm_voice_endpoint_ws_nextgen.cpp b/src/voice/endpoints/ctrlm_voice_endpoint_ws_nextgen.cpp index 248832cc..fcf9b12a 100644 --- a/src/voice/endpoints/ctrlm_voice_endpoint_ws_nextgen.cpp +++ b/src/voice/endpoints/ctrlm_voice_endpoint_ws_nextgen.cpp @@ -365,7 +365,7 @@ void ctrlm_voice_endpoint_ws_nextgen_t::voice_session_begin_callback_ws_nextgen( } config_in.ws.app_config = stream_params_out; - XLOGD_TELEMETRY("session begin - src <%s> ptt <%s> w_SAT <%s> w_MTLS <%s> w_OCSPst <%s> w_OCSPca <%s> keyword begin <%u> end <%u> doa <%u> gain <%4.1f> db", ctrlm_voice_device_str(source), (stream_params->push_to_talk ? "TRUE" : "FALSE"), has_sat ? "YES" : "NO", use_mtls ? "YES" : "NO", ocsp_verify_stapling ? "YES" : "NO", ocsp_verify_ca ? "YES" : "NO", stream_params->keyword_sample_begin, stream_params->keyword_sample_end, stream_params->keyword_doa, stream_params->dynamic_gain); + XLOGD_AUTOMATION_TELEMETRY("session begin - src <%s> ptt <%s> w_SAT <%s> w_MTLS <%s> w_OCSPst <%s> w_OCSPca <%s> keyword begin <%u> end <%u> doa <%u> gain <%4.1f> db", ctrlm_voice_device_str(source), (stream_params->push_to_talk ? "TRUE" : "FALSE"), has_sat ? "YES" : "NO", use_mtls ? "YES" : "NO", ocsp_verify_stapling ? "YES" : "NO", ocsp_verify_ca ? "YES" : "NO", stream_params->keyword_sample_begin, stream_params->keyword_sample_end, stream_params->keyword_doa, stream_params->dynamic_gain); } else if(!is_mic || dqm->configuration.user_initiated) { xrsv_ws_nextgen_stream_params_t *stream_params = (xrsv_ws_nextgen_stream_params_t *)malloc(sizeof(xrsv_ws_nextgen_stream_params_t)); @@ -378,7 +378,7 @@ void ctrlm_voice_endpoint_ws_nextgen_t::voice_session_begin_callback_ws_nextgen( } config_in.ws.app_config = stream_params; - XLOGD_TELEMETRY("session begin - src <%s> ptt w_SAT <%s> w_MTLS <%s> w_OCSPst <%s> w_OCSPca <%s>", ctrlm_voice_device_str(source), has_sat ? "YES" : "NO", use_mtls ? "YES" : "NO", ocsp_verify_stapling ? "YES" : "NO", ocsp_verify_ca ? "YES" : "NO"); + XLOGD_AUTOMATION_TELEMETRY("session begin - src <%s> ptt w_SAT <%s> w_MTLS <%s> w_OCSPst <%s> w_OCSPca <%s>", ctrlm_voice_device_str(source), has_sat ? "YES" : "NO", use_mtls ? "YES" : "NO", ocsp_verify_stapling ? "YES" : "NO", ocsp_verify_ca ? "YES" : "NO"); } else { XLOGD_ERROR("session begin - invalid params - src <%s>", ctrlm_voice_device_str(source)); } diff --git a/src/voice/endpoints/ctrlm_voice_endpoint_ws_nsp.cpp b/src/voice/endpoints/ctrlm_voice_endpoint_ws_nsp.cpp index 45ad9714..da4d4035 100644 --- a/src/voice/endpoints/ctrlm_voice_endpoint_ws_nsp.cpp +++ b/src/voice/endpoints/ctrlm_voice_endpoint_ws_nsp.cpp @@ -133,7 +133,7 @@ void ctrlm_voice_endpoint_ws_nsp_t::voice_session_begin_callback_ws_nsp(void *da config_in.ws.cert_revoked_allow = false; config_in.ws.ocsp_expired_allow = false; - XLOGD_TELEMETRY("session begin - src <%s> x_MTLS <%s> x_OCSPst <%s> x_OCSPca <%s>", ctrlm_voice_device_str(source), use_mtls ? "YES" : "NO", ocsp_verify_stapling ? "YES" : "NO", ocsp_verify_ca ? "YES" : "NO"); + XLOGD_AUTOMATION_TELEMETRY("session begin - src <%s> x_MTLS <%s> x_OCSPst <%s> x_OCSPca <%s>", ctrlm_voice_device_str(source), use_mtls ? "YES" : "NO", ocsp_verify_stapling ? "YES" : "NO", ocsp_verify_ca ? "YES" : "NO"); ctrlm_voice_session_begin_cb_t session_begin; uuid_copy(session_begin.header.uuid, dqm->uuid); diff --git a/src/voice/ipc/ctrlm_voice_ipc_iarm_thunder.cpp b/src/voice/ipc/ctrlm_voice_ipc_iarm_thunder.cpp index f88d6fb9..02b4408e 100644 --- a/src/voice/ipc/ctrlm_voice_ipc_iarm_thunder.cpp +++ b/src/voice/ipc/ctrlm_voice_ipc_iarm_thunder.cpp @@ -357,7 +357,7 @@ bool ctrlm_voice_ipc_iarm_thunder_t::session_end(const ctrlm_voice_ipc_event_ses char *json_str = json_dumps(event_data, JSON_ENCODE_FLAGS); if(json_str) { //TODO: surface the event through IARM - XLOGD_INFO("<%s>", this->obj_voice->voice_stb_data_pii_mask_get() ? "***" : json_str); + XLOGD_AUTOMATION_INFO("<%s>", this->obj_voice->voice_stb_data_pii_mask_get() ? "***" : json_str); ret = broadcast_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_JSON_SESSION_END, json_str); free(json_str); } else { @@ -373,7 +373,7 @@ bool ctrlm_voice_ipc_iarm_thunder_t::session_end(const ctrlm_voice_ipc_event_ses bool ctrlm_voice_ipc_iarm_thunder_t::server_message(const char *message, unsigned long size) { bool ret = false; if(message) { - XLOGD_INFO("%ul : <%s>", size, this->obj_voice->voice_stb_data_pii_mask_get() ? "***" : message); //CID -160950 - Printargs + XLOGD_AUTOMATION_INFO("%ul : <%s>", size, this->obj_voice->voice_stb_data_pii_mask_get() ? "***" : message); //CID -160950 - Printargs ret = broadcast_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_JSON_SERVER_MESSAGE, message); } return(ret); From d72398a041fef8118a40204ac80c9743cd91e356 Mon Sep 17 00:00:00 2001 From: Gene Gallagher <129112619+egalla204@users.noreply.github.com> Date: Thu, 4 Dec 2025 11:44:32 -0500 Subject: [PATCH 15/81] RDKEMW-11159: new_certselector_type (#157) --- src/auth/ctrlm_auth_certificate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/auth/ctrlm_auth_certificate.cpp b/src/auth/ctrlm_auth_certificate.cpp index 63ff900c..63ae514e 100644 --- a/src/auth/ctrlm_auth_certificate.cpp +++ b/src/auth/ctrlm_auth_certificate.cpp @@ -42,7 +42,7 @@ ctrlm_auth_certificate_t::ctrlm_auth_certificate_t() { char *cert_path = NULL; char *cert_password = NULL; - rdkcertselector_h cert_selector = rdkcertselector_new( NULL, NULL, "MTLS" ); + rdkcertselector_h cert_selector = rdkcertselector_new( NULL, NULL, "FBK_MTLS" ); if(cert_selector == NULL){ XLOGD_TELEMETRY("cert selector init failed"); From 4f688c6aca99e5c5d8674d4b3edc60fe97eb0633 Mon Sep 17 00:00:00 2001 From: Gene Gallagher <129112619+egalla204@users.noreply.github.com> Date: Thu, 4 Dec 2025 14:07:59 -0500 Subject: [PATCH 16/81] RDKEMW-11249: update CHANGELOG for ctrlm release v1.1.7 (#158) --- CHANGELOG.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea63c55d..cd51fc43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,16 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - +#### [1.1.7](https://github.com/rdkcentral/control/compare/1.1.6...1.1.7) + +> 4 December 2025 + +- RDKEMW-11159: new_certselector_type [`#157`](https://github.com/rdkcentral/control/pull/157) +- RDKEMW-10425: Automation Logging [`#144`](https://github.com/rdkcentral/control/pull/144) +- RDKEMW-9600: FIRST_PACKET_TIMEOUTs [`#135`](https://github.com/rdkcentral/control/pull/135) + #### [1.1.6](https://github.com/rdkcentral/control/compare/1.1.5...1.1.6) > 19 November 2025 From 2f1050b142d14a66bf31c7279c3900c6b876bda9 Mon Sep 17 00:00:00 2001 From: dwolaver <44593664+dwolaver@users.noreply.github.com> Date: Mon, 8 Dec 2025 16:50:44 -0500 Subject: [PATCH 17/81] RDKEMW-8930 : remove ctrlm build flags - FACTORY_AUDIO_PLAYBACK (#143) --- CMakeLists.txt | 2 - src/factory/CMakeLists.txt | 73 +++--------- src/factory/ctrlm_fta_caa.h | 2 + src/factory/ctrlm_fta_lib.h | 4 +- src/factory/ctrlmf_audio_capture.cpp | 74 +++++++----- src/factory/ctrlmf_audio_capture.h | 2 +- src/factory/ctrlmf_main.c | 29 +---- src/factory/ctrlmf_mic_test.cpp | 98 ++++++++-------- src/factory/ctrlmf_version.c | 101 ++++++++++++---- src/factory/ctrlmf_ws.c | 167 ++++++++++++++++----------- src/factory/ctrlmf_ws.h | 2 +- 11 files changed, 291 insertions(+), 263 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 655f17d2..c38b5657 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,8 +39,6 @@ option(BLE_ENABLED "Enable BLE" ON) option(BLE_SERVICES "Enable BLE Services" OFF) option(BREAKPAD "Enable BREAKPAD" OFF) option(BUILD_CTRLM_FACTORY "Build Control Factory Test" OFF) -option(FACTORY_AUDIO_PLAYBACK "Factory test audio playback" OFF) -option(FACTORY_CUSTOM_AUDIO_ANALYSIS "Factory custom audio analysis" OFF) option(FDC_ENABLED "Enable FDC" OFF) option(IP_ENABLED "Enable IP" OFF) option(RF4CE_ENABLED "Enable RF4CE" ON) diff --git a/src/factory/CMakeLists.txt b/src/factory/CMakeLists.txt index a16ae0eb..530cbf5b 100644 --- a/src/factory/CMakeLists.txt +++ b/src/factory/CMakeLists.txt @@ -17,8 +17,6 @@ # limitations under the License. ########################################################################## -option(FACTORY_AUDIO_PLAYBACK "AUDIO PLAYBACK" OFF) - add_executable(controlFactory ctrlmf_main.c) add_library(ctrlm-fta SHARED) set_target_properties( ctrlm-fta PROPERTIES @@ -30,6 +28,9 @@ include_directories( . iarm thunder + ${CMAKE_SYSROOT}/usr/include/rdk/ds + ${CMAKE_SYSROOT}/usr/include/rdk/ds-rpc + ${CMAKE_SYSROOT}/usr/include/rdk/ds-hal ) target_sources(ctrlm-fta PRIVATE @@ -37,37 +38,21 @@ target_sources(ctrlm-fta PRIVATE ctrlmf_reset.cpp ctrlmf_systemd.c ctrlmf_utils.c + ctrlmf_audio_capture.cpp + ctrlmf_audio_control.cpp + ctrlmf_audio_playback.cpp + ctrlmf_mic_test.cpp + ctrlmf_ws.c iarm/ctrlmf_iarm_client.cpp iarm/ctrlmf_iarm_control_manager.cpp ) -target_link_libraries(ctrlm-fta c rdkversion dbus-1 glib-2.0 IARMBus xr-voice-sdk pthread nopoll secure_wrapper) +target_link_libraries(ctrlm-fta c rdkversion dbus-1 glib-2.0 IARMBus xr-voice-sdk pthread nopoll secure_wrapper ds) target_link_libraries(controlFactory c ctrlm-fta secure_wrapper) -if(CUSTOM_AUDIO_ANALYSIS_LIB) - add_compile_definitions(PRIVATE CTRLMF_CUSTOM_AUDIO_ANALYSIS) - target_link_libraries(controlFactory ${CUSTOM_AUDIO_ANALYSIS_LIB}) -endif() - -if(CUSTOM_AUTH_LIB) +if(AUTH_ENABLED) add_compile_definitions(PRIVATE CTRLMF_WSS_ENABLED) - target_link_libraries(controlFactory ${CUSTOM_AUTH_LIB}) -endif() - -if(EXISTS ${CMAKE_SYSROOT}/usr/lib/libctrlm-hal-certificate.so) - target_link_libraries(controlFactory ctrlm-hal-certificate) -else() - if(AUTH_ENABLED) - message(WARNING "ctrlm-hal-certificate library is not provided, disabling authentication") - unset(AUTH_ENABLED) - endif() -endif() - -if(LOCAL_MIC) - add_compile_definitions(PRIVATE CTRLMF_LOCAL_MIC) - if(MIC_TAP) - add_compile_definitions(PRIVATE CTRLMF_LOCAL_MIC_TAP) - endif() + target_link_libraries(ctrlm-fta RdkCertSelector rdkconfig) endif() if(THUNDER) @@ -75,6 +60,7 @@ if(THUNDER) target_sources(ctrlm-fta PRIVATE thunder/ctrlmf_thunder_controller.cpp thunder/ctrlmf_thunder_plugin.cpp + thunder/ctrlmf_thunder_plugin_system_audio_player.cpp ) target_link_libraries(controlFactory WPEFrameworkCore WPEFrameworkPlugins) @@ -84,40 +70,11 @@ if(THUNDER) if(WPE_FRAMEWORK_PROTO_TRACING) target_link_libraries(controlFactory WPEFrameworkProtocols WPEFrameworkTracing) endif() -endif() -if(THUNDER_SECURITY) - add_compile_definitions(PRIVATE THUNDER_SECURITY) - target_link_libraries(controlFactory WPEFrameworkSecurityUtil secure_wrapper) -endif() - -if(FACTORY_AUDIO_PLAYBACK) - add_compile_definitions(PRIVATE CTRLMF_AUDIO_PLAYBACK) - include_directories( ${CMAKE_SYSROOT}/usr/include/rdk/ds - ${CMAKE_SYSROOT}/usr/include/rdk/ds-rpc - ${CMAKE_SYSROOT}/usr/include/rdk/ds-hal - ) - target_sources(ctrlm-fta PRIVATE ctrlmf_audio_playback.cpp) - if(THUNDER) - target_sources(ctrlm-fta PRIVATE thunder/ctrlmf_thunder_plugin_system_audio_player.cpp) + if(THUNDER_SECURITY) + add_compile_definitions(PRIVATE THUNDER_SECURITY) + target_link_libraries(controlFactory WPEFrameworkSecurityUtil secure_wrapper) endif() - - install(FILES ${CMAKE_SOURCE_DIR}/../tone_1khz.wav DESTINATION share ) -endif() - -if(FACTORY_AUDIO_CONTROL) - add_compile_definitions(PRIVATE CTRLMF_AUDIO_CONTROL) - target_sources(ctrlm-fta PRIVATE - ctrlmf_audio_control.cpp - ) -endif() - -if(LOCAL_MIC) - target_sources(ctrlm-fta PRIVATE - ctrlmf_audio_capture.cpp - ctrlmf_mic_test.cpp - ctrlmf_ws.c - ) endif() install(TARGETS controlFactory DESTINATION bin) diff --git a/src/factory/ctrlm_fta_caa.h b/src/factory/ctrlm_fta_caa.h index ee0b6a97..39373a55 100644 --- a/src/factory/ctrlm_fta_caa.h +++ b/src/factory/ctrlm_fta_caa.h @@ -48,6 +48,8 @@ extern "C" { bool ctrlmf_mic_test_audio_analyze(ctrlmf_test_type_t test_type, const char *output_filename, uint32_t level, ctrlmf_audio_frame_t audio_frames_noise, ctrlmf_audio_frame_t audio_frames_signal, uint32_t frame_qty, uint32_t mic_qty, ctrlmf_test_result_t *test_result); +typedef bool (*ctrlmf_mic_test_audio_analyze_t)(ctrlmf_test_type_t test_type, const char *output_filename, uint32_t level, ctrlmf_audio_frame_t audio_frames_noise, ctrlmf_audio_frame_t audio_frames_signal, uint32_t frame_qty, uint32_t mic_qty, ctrlmf_test_result_t *test_result); + #ifdef __cplusplus } #endif diff --git a/src/factory/ctrlm_fta_lib.h b/src/factory/ctrlm_fta_lib.h index f45f26eb..b4700a7f 100644 --- a/src/factory/ctrlm_fta_lib.h +++ b/src/factory/ctrlm_fta_lib.h @@ -38,7 +38,7 @@ extern "C" { #endif -bool ctrlmf_init(xlog_level_t level, bool requires_audio_playback); +bool ctrlmf_init(xlog_level_t level, bool requires_audio_playback, bool requires_audio_control, ctrlmf_mic_test_audio_analyze_t *audio_analyze_func); void ctrlmf_term(void); bool ctrlmf_factory_reset(void); @@ -51,7 +51,7 @@ bool ctrlmf_audio_control_attenuate(bool enable, bool relative, double vol); bool ctrlmf_audio_playback_start(const char *filename); -bool ctrlmf_mic_test_factory(uint32_t duration, const char *output_filename, uint32_t level, const char *audio_filename, double *snr_min, double *snr_max, double *snr_var, ctrlmf_test_result_t *test_result); +bool ctrlmf_mic_test_factory(uint32_t duration, const char *output_filename, uint32_t level, const char *audio_filename, double *snr_min, double *snr_max, double *snr_var, ctrlmf_test_result_t *test_result, ctrlmf_mic_test_audio_analyze_t audio_analyze_func); #ifdef __cplusplus } diff --git a/src/factory/ctrlmf_audio_capture.cpp b/src/factory/ctrlmf_audio_capture.cpp index d9ed82f5..0d76772a 100644 --- a/src/factory/ctrlmf_audio_capture.cpp +++ b/src/factory/ctrlmf_audio_capture.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -16,13 +17,8 @@ #define CTRLMF_WS_PORT_STR "9880" #define CTRLMF_WS_PORT_INT (9880) -#ifdef CTRLMF_WSS_ENABLED -#define CTRLMF_WS_URL_BASE "aowss://" -#else -#define CTRLMF_WS_URL_BASE "aows://" -#endif - -#define CTRLMF_WS_URL CTRLMF_WS_URL_BASE CTRLMF_WS_HOST ":" CTRLMF_WS_PORT_STR "/mic_test" +#define CTRLMF_WS_URL "aows://" CTRLMF_WS_HOST ":" CTRLMF_WS_PORT_STR "/mic_test" +#define CTRLMF_WSS_URL "aowss://" CTRLMF_WS_HOST ":" CTRLMF_WS_PORT_STR "/mic_test" typedef struct { sem_t semaphore_connected; @@ -50,7 +46,7 @@ static ctrlmf_audio_cap_global_t g_audio_cap; // Capture an audio clip using websocket -bool ctrlmf_audio_capture_init(uint32_t audio_frame_size, bool use_mic_tap) { +bool ctrlmf_audio_capture_init(uint32_t audio_frame_size, bool *has_local_mic_tap) { g_audio_cap.obj_ctrlm = new Iarm::ControlManager::ctrlm_iarm_client_control_manager_t; @@ -60,20 +56,8 @@ bool ctrlmf_audio_capture_init(uint32_t audio_frame_size, bool use_mic_tap) { } g_audio_cap.obj_ctrlm->add_event_handler(ctrlmf_audio_capture_event_handler, NULL); - g_audio_cap.use_mic_tap = use_mic_tap; + g_audio_cap.use_mic_tap = false; - // Get the current url - if(g_audio_cap.use_mic_tap) { - if(!g_audio_cap.obj_ctrlm->status_voice_mic_tap(g_audio_cap.url, &g_audio_cap.url_enabled)) { - XLOGD_ERROR("unable to get mic tap status"); - return(false); - } - } else { - if(!g_audio_cap.obj_ctrlm->status_voice_hf(g_audio_cap.url, &g_audio_cap.url_enabled)) { - XLOGD_ERROR("unable to get hf status"); - return(false); - } - } if(!g_audio_cap.obj_ctrlm->voice_session_types(g_audio_cap.request_types)) { XLOGD_ERROR("unable to get voice session request types"); return(false); @@ -90,23 +74,34 @@ bool ctrlmf_audio_capture_init(uint32_t audio_frame_size, bool use_mic_tap) { first = false; } - XLOGD_INFO("get url <%s> enabled <%s> request types <%s>", g_audio_cap.url.c_str(), g_audio_cap.url_enabled ? "YES" : "NO", request_types.str().c_str()); + bool has_local_mic = false; + if(std::find(g_audio_cap.request_types.begin(), g_audio_cap.request_types.end(), "mic_stream_single") != g_audio_cap.request_types.end()) { + has_local_mic = true; + } + if(std::find(g_audio_cap.request_types.begin(), g_audio_cap.request_types.end(), "mic_tap_stream_single") != g_audio_cap.request_types.end()) { + g_audio_cap.use_mic_tap = true; + } - // Set the FFV url to our websocket - std::string url_new = CTRLMF_WS_URL; + if(!has_local_mic) { + XLOGD_ERROR("platform does not support local mic stream"); + return(false); + } + // Get the current url if(g_audio_cap.use_mic_tap) { - if(!g_audio_cap.obj_ctrlm->configure_voice_mic_tap(url_new, true)) { - XLOGD_ERROR("unable to set mic tap url"); + if(!g_audio_cap.obj_ctrlm->status_voice_mic_tap(g_audio_cap.url, &g_audio_cap.url_enabled)) { + XLOGD_ERROR("unable to get mic tap status"); return(false); } } else { - if(!g_audio_cap.obj_ctrlm->configure_voice_hf(url_new, true)) { - XLOGD_ERROR("unable to set hf url"); + if(!g_audio_cap.obj_ctrlm->status_voice_hf(g_audio_cap.url, &g_audio_cap.url_enabled)) { + XLOGD_ERROR("unable to get hf status"); return(false); } } + XLOGD_INFO("get url <%s> enabled <%s> request types <%s>", g_audio_cap.url.c_str(), g_audio_cap.url_enabled ? "YES" : "NO", request_types.str().c_str()); + // Start websocket server sem_init(&g_audio_cap.callback_data.semaphore_connected, 0, 0); sem_init(&g_audio_cap.callback_data.semaphore_disconnected, 0, 0); @@ -115,7 +110,28 @@ bool ctrlmf_audio_capture_init(uint32_t audio_frame_size, bool use_mic_tap) { g_audio_cap.callbacks.disconnected = ctrlmf_ws_disconnected; g_audio_cap.callbacks.data = &g_audio_cap.callback_data; g_audio_cap.session_id = ""; - ctrlmf_ws_init(audio_frame_size, CTRLMF_WS_PORT_INT, true, &g_audio_cap.callbacks); + + bool has_valid_cert = false; + ctrlmf_ws_init(audio_frame_size, CTRLMF_WS_PORT_INT, true, &g_audio_cap.callbacks, &has_valid_cert); + + // Set the FFV url to our websocket + std::string url_new = has_valid_cert ? CTRLMF_WSS_URL : CTRLMF_WS_URL; + + if(g_audio_cap.use_mic_tap) { + if(!g_audio_cap.obj_ctrlm->configure_voice_mic_tap(url_new, true)) { + XLOGD_ERROR("unable to set mic tap url"); + return(false); + } + } else { + if(!g_audio_cap.obj_ctrlm->configure_voice_hf(url_new, true)) { + XLOGD_ERROR("unable to set hf url"); + return(false); + } + } + + if(has_local_mic_tap != NULL) { + *has_local_mic_tap = g_audio_cap.use_mic_tap; + } return(true); } diff --git a/src/factory/ctrlmf_audio_capture.h b/src/factory/ctrlmf_audio_capture.h index dfcf343e..79e14e1f 100644 --- a/src/factory/ctrlmf_audio_capture.h +++ b/src/factory/ctrlmf_audio_capture.h @@ -26,7 +26,7 @@ extern "C" { #endif -bool ctrlmf_audio_capture_init(uint32_t audio_frame_size, bool use_mic_tap); +bool ctrlmf_audio_capture_init(uint32_t audio_frame_size, bool *has_local_mic_tap); bool ctrlmf_audio_capture_term(void); bool ctrlmf_audio_capture_start(const char *request_type, ctrlmf_audio_frame_t audio_frames, uint32_t audio_frame_qty, uint32_t duration); diff --git a/src/factory/ctrlmf_main.c b/src/factory/ctrlmf_main.c index b923c9db..e70337d9 100644 --- a/src/factory/ctrlmf_main.c +++ b/src/factory/ctrlmf_main.c @@ -44,10 +44,7 @@ static struct argp_option options[] = { {"factory-reset", 'F', 0, 0, "Perform control manager factory reset and restart the application." }, {"soft-factory-reset",'f', 0, 0, "Perform control manager factory reset" }, {"ctrlm-restart", 'r', 0, 0, "Restart the control manager application" }, - #ifdef CTRLMF_LOCAL_MIC - #ifdef CTRLMF_AUDIO_PLAYBACK {"mic-test-audio", 'a', "", 0, "Microphone test audio file" }, - #endif {"mic-test-factory", 'd', 0, 0, "Factory microphone test" }, {"mic-test-duration", 'u', "", 0, "Microphone test duration in milliseconds" }, {"mic-test-snr-min", 'x', "", 0, "Microphone test SNR minimum value" }, @@ -55,10 +52,7 @@ static struct argp_option options[] = { {"mic-test-snr-var", 'z', "", 0, "Microphone test SNR maximum variance" }, {"mic-test-output", 'g', "", 0, "Microphone test output filename" }, {"mic-test-level", 'l', "", 0, "Microphone test level" }, - #endif - #ifdef CTRLMF_AUDIO_CONTROL {"mute-main-audio", 'm', 0, 0, "Mute the main audio output" }, - #endif { 0 } }; @@ -99,8 +93,9 @@ int main(int argc, char* argv[]) { } bool requires_audio_playback = (g_ctrlmf_opts.audio_file_path != NULL) ? true : false; + ctrlmf_mic_test_audio_analyze_t audio_analyze_func = NULL; - if(!ctrlmf_init(level, requires_audio_playback)) { + if(!ctrlmf_init(level, requires_audio_playback, g_ctrlmf_opts.mute_main_audio, &audio_analyze_func)) { XLOGD_ERROR("ctrlmf_main: init failed"); } else { XLOGD_INFO("ctrlmf_main: Run main loop"); @@ -110,30 +105,22 @@ int main(int argc, char* argv[]) { if(g_ctrlmf_opts.ctrlm_restart) { ctrlmf_systemd_service_exec("ctrlm-main.service", CTRLMF_SYSTEMD_METHOD_RESTART); } - #ifdef CTRLMF_AUDIO_CONTROL if(g_ctrlmf_opts.mute_main_audio) { ctrlmf_audio_control_mute(true); } - #endif if(g_ctrlmf_opts.mic_test_factory) { - #ifdef CTRLMF_LOCAL_MIC ctrlmf_test_result_t test_result; - if(!ctrlmf_mic_test_factory(g_ctrlmf_opts.mic_test_duration, g_ctrlmf_opts.output_file_path, g_ctrlmf_opts.mic_test_level, g_ctrlmf_opts.audio_file_path, g_ctrlmf_opts.mic_test_snr_min, g_ctrlmf_opts.mic_test_snr_max, g_ctrlmf_opts.mic_test_snr_var, &test_result)) { + if(!ctrlmf_mic_test_factory(g_ctrlmf_opts.mic_test_duration, g_ctrlmf_opts.output_file_path, g_ctrlmf_opts.mic_test_level, g_ctrlmf_opts.audio_file_path, g_ctrlmf_opts.mic_test_snr_min, g_ctrlmf_opts.mic_test_snr_max, g_ctrlmf_opts.mic_test_snr_var, &test_result, audio_analyze_func)) { XLOGD_ERROR("ctrlmf_main: mic test failed"); } else { XLOGD_INFO("ctrlmf_main: test result <%s>", test_result.pass ? "PASS" : "FAIL"); } - #endif } else if(g_ctrlmf_opts.audio_file_path != NULL) { - #ifdef CTRLMF_AUDIO_PLAYBACK ctrlmf_audio_playback_start(g_ctrlmf_opts.audio_file_path); - #endif } - #ifdef CTRLMF_AUDIO_CONTROL if(g_ctrlmf_opts.mute_main_audio) { ctrlmf_audio_control_mute(false); } - #endif XLOGD_INFO("ctrlmf_main: main loop ended"); } @@ -169,14 +156,11 @@ error_t ctrlmf_parse_opt(int key, char *arg, struct argp_state *state) { arguments->ctrlm_restart = true; break; } - #ifdef CTRLMF_LOCAL_MIC - #ifdef CTRLMF_AUDIO_PLAYBACK case 'a': { XLOGD_INFO("mic test audio file <%s>", arg); arguments->audio_file_path = arg; break; } - #endif case 'g': { XLOGD_INFO("output file path <%s>", arg); arguments->output_file_path = arg; @@ -221,13 +205,10 @@ error_t ctrlmf_parse_opt(int key, char *arg, struct argp_state *state) { arguments->mic_test_snr_var = &arguments->snr_var; break; } - #endif - #ifdef CTRLMF_AUDIO_CONTROL case 'm': { arguments->mute_main_audio = true; break; } - #endif case ARGP_KEY_ARG: { argp_usage(state); return(ARGP_ERR_UNKNOWN); @@ -257,14 +238,10 @@ bool ctrlmf_cmdline_args(int argc, char *argv[]) { XLOGD_INFO("ctrlm restart <%s>", g_ctrlmf_opts.ctrlm_restart ? "YES" : "NO"); XLOGD_INFO("audio file <%s>", g_ctrlmf_opts.audio_file_path ? g_ctrlmf_opts.audio_file_path : "NULL"); XLOGD_INFO("output file path <%s>", g_ctrlmf_opts.output_file_path ? g_ctrlmf_opts.output_file_path : "NULL"); - #ifdef CTRLMF_LOCAL_MIC if(g_ctrlmf_opts.mic_test_factory) { XLOGD_INFO("mic test duration <%d ms> snr min <%f> max <%f> var <%f>", g_ctrlmf_opts.mic_test_duration, *g_ctrlmf_opts.mic_test_snr_min, *g_ctrlmf_opts.mic_test_snr_max, *g_ctrlmf_opts.mic_test_snr_var); } - #endif - #ifdef CTRLMF_AUDIO_CONTROL XLOGD_INFO("mute main audio <%s>", g_ctrlmf_opts.mute_main_audio ? "YES" : "NO"); - #endif return(true); } diff --git a/src/factory/ctrlmf_mic_test.cpp b/src/factory/ctrlmf_mic_test.cpp index b3eab24c..1db94630 100644 --- a/src/factory/ctrlmf_mic_test.cpp +++ b/src/factory/ctrlmf_mic_test.cpp @@ -22,19 +22,17 @@ #define FILENAME_WAV_NOISE "/opt/logs/mic_test_noise.wav" #define FILENAME_WAV_SIGNAL "/opt/logs/mic_test_signal.wav" -#ifndef CTRLMF_CUSTOM_AUDIO_ANALYSIS -static bool ctrlmf_mic_test_audio_analyze(const char *output_filename, uint32_t level, ctrlmf_audio_frame_t audio_frames_noise, ctrlmf_audio_frame_t audio_frames_signal, uint32_t frame_qty, uint32_t mic_qty, double snr_min, double snr_max, double snr_var, ctrlmf_test_result_t *test_result); -#endif +static bool ctrlmf_mic_test_audio_analyze_default(const char *output_filename, uint32_t level, ctrlmf_audio_frame_t audio_frames_noise, ctrlmf_audio_frame_t audio_frames_signal, uint32_t frame_qty, uint32_t mic_qty, double snr_min, double snr_max, double snr_var, ctrlmf_test_result_t *test_result); -#if defined(CTRLMF_THUNDER) && defined(CTRLMF_AUDIO_PLAYBACK) -static bool ctrlmf_mic_test_via_audio_file(uint32_t duration, const char *output_filename, uint32_t level, const char *audio_filename, double snr_min, double snr_max, double snr_var, ctrlmf_test_result_t *test_result); +#ifdef CTRLMF_THUNDER +static bool ctrlmf_mic_test_via_audio_file(uint32_t duration, const char *output_filename, uint32_t level, const char *audio_filename, double snr_min, double snr_max, double snr_var, ctrlmf_test_result_t *test_result, ctrlmf_mic_test_audio_analyze_t audio_analyze_func); #endif -static bool ctrlmf_mic_test_via_ambient(uint32_t duration, const char *output_filename, uint32_t level, double snr_min, double snr_max, double snr_var, ctrlmf_test_result_t *test_result); +static bool ctrlmf_mic_test_via_ambient(uint32_t duration, const char *output_filename, uint32_t level, double snr_min, double snr_max, double snr_var, ctrlmf_test_result_t *test_result, ctrlmf_mic_test_audio_analyze_t audio_analyze_func); static void ctrlmf_mic_test_audio_export(const char *filename, ctrlmf_audio_frame_t audio_frames, uint32_t frame_qty, uint32_t channel_qty); static void ctrlmf_wave_header_gen(uint8_t *header, uint16_t audio_format, uint16_t num_channels, uint32_t sample_rate, uint16_t bits_per_sample, uint32_t pcm_data_size); -bool ctrlmf_mic_test_factory(uint32_t duration, const char *output_filename, uint32_t level, const char *audio_filename, double *snr_min, double *snr_max, double *snr_var, ctrlmf_test_result_t *test_result) { +bool ctrlmf_mic_test_factory(uint32_t duration, const char *output_filename, uint32_t level, const char *audio_filename, double *snr_min, double *snr_max, double *snr_var, ctrlmf_test_result_t *test_result, ctrlmf_mic_test_audio_analyze_t audio_analyze_func) { if(!ctrlmf_is_initialized()) { XLOGD_ERROR("not initialized"); return(false); @@ -44,18 +42,18 @@ bool ctrlmf_mic_test_factory(uint32_t duration, const char *output_filename, uin double snr_var_val = (snr_var != NULL) ? *snr_var : SNR_VAR; if(audio_filename != NULL) { - #if defined(CTRLMF_THUNDER) && defined(CTRLMF_AUDIO_PLAYBACK) - return(ctrlmf_mic_test_via_audio_file(duration, output_filename, level, audio_filename, snr_min_val, snr_max_val, snr_var_val, test_result)); + #ifdef CTRLMF_THUNDER + return(ctrlmf_mic_test_via_audio_file(duration, output_filename, level, audio_filename, snr_min_val, snr_max_val, snr_var_val, test_result, audio_analyze_func)); #else XLOGD_ERROR("audio playback is disabled"); return(false); #endif } - return(ctrlmf_mic_test_via_ambient(duration, output_filename, level, snr_min_val, snr_max_val, snr_var_val, test_result)); + return(ctrlmf_mic_test_via_ambient(duration, output_filename, level, snr_min_val, snr_max_val, snr_var_val, test_result, audio_analyze_func)); } -#if defined(CTRLMF_THUNDER) && defined(CTRLMF_AUDIO_PLAYBACK) -bool ctrlmf_mic_test_via_audio_file(uint32_t duration, const char *output_filename, uint32_t level, const char *audio_filename, double snr_min, double snr_max, double snr_var, ctrlmf_test_result_t *test_result) { +#ifdef CTRLMF_THUNDER +bool ctrlmf_mic_test_via_audio_file(uint32_t duration, const char *output_filename, uint32_t level, const char *audio_filename, double snr_min, double snr_max, double snr_var, ctrlmf_test_result_t *test_result, ctrlmf_mic_test_audio_analyze_t audio_analyze_func) { ctrlmf_audio_frame_t audio_frames_noise = NULL; ctrlmf_audio_frame_t audio_frames_signal = NULL; bool result = false; @@ -84,21 +82,19 @@ bool ctrlmf_mic_test_via_audio_file(uint32_t duration, const char *output_filena memset(audio_frames_noise, 0, audio_buffer_size); memset(audio_frames_signal, 0, audio_buffer_size); - #ifdef CTRLMF_LOCAL_MIC_TAP - if(!ctrlmf_audio_capture_init(audio_frame_size, true)) { - #else - if(!ctrlmf_audio_capture_init(audio_frame_size, false)) { - #endif + bool use_local_mic_tap = false; + if(!ctrlmf_audio_capture_init(audio_frame_size, &use_local_mic_tap)) { XLOGD_ERROR("unable to init audio capture"); break; } audio_capture_initialized = true; - #ifdef CTRLMF_LOCAL_MIC_TAP - const char *request_type = (MIC_RAW_AUDIO) ? "mic_factory_test" : (MIC_CHANNEL_QTY == 1) ? "mic_tap_stream_single" : "mic_tap_stream_multi"; - #else - const char *request_type = (MIC_RAW_AUDIO) ? "mic_factory_test" : (MIC_CHANNEL_QTY == 1) ? "mic_stream_single" : "mic_stream_multi"; - #endif + const char *request_type = NULL; + if(use_local_mic_tap) { + request_type = (MIC_RAW_AUDIO) ? "mic_factory_test" : (MIC_CHANNEL_QTY == 1) ? "mic_tap_stream_single" : "mic_tap_stream_multi"; + } else { + request_type = (MIC_RAW_AUDIO) ? "mic_factory_test" : (MIC_CHANNEL_QTY == 1) ? "mic_stream_single" : "mic_stream_multi"; + } // Capture noise if(!ctrlmf_audio_capture_start(request_type, audio_frames_noise, audio_frame_qty, duration)) { @@ -120,13 +116,16 @@ bool ctrlmf_mic_test_via_audio_file(uint32_t duration, const char *output_filena } XLOGD_INFO("analyze audio capture"); - #ifndef CTRLMF_CUSTOM_AUDIO_ANALYSIS - if(!ctrlmf_mic_test_audio_analyze(output_filename, level, audio_frames_noise, audio_frames_signal, audio_frame_qty, MIC_CHANNEL_QTY, snr_min, snr_max, snr_var, test_result)) { - #else - if(!ctrlmf_mic_test_audio_analyze(CTRLMF_TEST_FACTORY, output_filename, level, audio_frames_noise, audio_frames_signal, audio_frame_qty, MIC_CHANNEL_QTY, test_result)) { - #endif - XLOGD_ERROR("unable to analyze audio"); - break; + if(audio_analyze_func != NULL) { + if(!(*audio_analyze_func)(CTRLMF_TEST_FACTORY, output_filename, level, audio_frames_noise, audio_frames_signal, audio_frame_qty, MIC_CHANNEL_QTY, test_result)) { + XLOGD_ERROR("unable to analyze audio"); + break; + } + } else { + if(!ctrlmf_mic_test_audio_analyze_default(output_filename, level, audio_frames_noise, audio_frames_signal, audio_frame_qty, MIC_CHANNEL_QTY, snr_min, snr_max, snr_var, test_result)) { + XLOGD_ERROR("unable to analyze audio"); + break; + } } if(!ctrlmf_is_production()) { ctrlmf_mic_test_audio_export(FILENAME_WAV_NOISE, audio_frames_noise, audio_frame_qty, MIC_CHANNEL_QTY); @@ -149,7 +148,7 @@ bool ctrlmf_mic_test_via_audio_file(uint32_t duration, const char *output_filena } #endif -bool ctrlmf_mic_test_via_ambient(uint32_t duration, const char *output_filename, uint32_t level, double snr_min, double snr_max, double snr_var, ctrlmf_test_result_t *test_result) { +bool ctrlmf_mic_test_via_ambient(uint32_t duration, const char *output_filename, uint32_t level, double snr_min, double snr_max, double snr_var, ctrlmf_test_result_t *test_result, ctrlmf_mic_test_audio_analyze_t audio_analyze_func) { ctrlmf_audio_frame_t audio_frames_signal = NULL; bool result = false; bool audio_capture_initialized = false; @@ -170,21 +169,19 @@ bool ctrlmf_mic_test_via_ambient(uint32_t duration, const char *output_filename, memset(audio_frames_signal, 0, audio_buffer_size); - #ifdef CTRLMF_LOCAL_MIC_TAP - if(!ctrlmf_audio_capture_init(audio_frame_size, true)) { - #else - if(!ctrlmf_audio_capture_init(audio_frame_size, false)) { - #endif + bool use_local_mic_tap = false; + if(!ctrlmf_audio_capture_init(audio_frame_size, &use_local_mic_tap)) { XLOGD_ERROR("unable to init audio capture"); break; } audio_capture_initialized = true; - #ifdef CTRLMF_LOCAL_MIC_TAP - const char *request_type = (MIC_RAW_AUDIO) ? "mic_factory_test" : (MIC_CHANNEL_QTY == 1) ? "mic_tap_stream_single" : "mic_tap_stream_multi"; - #else - const char *request_type = (MIC_RAW_AUDIO) ? "mic_factory_test" : (MIC_CHANNEL_QTY == 1) ? "mic_stream_single" : "mic_stream_multi"; - #endif + const char *request_type = NULL; + if(use_local_mic_tap) { + request_type = (MIC_RAW_AUDIO) ? "mic_factory_test" : (MIC_CHANNEL_QTY == 1) ? "mic_tap_stream_single" : "mic_tap_stream_multi"; + } else { + request_type = (MIC_RAW_AUDIO) ? "mic_factory_test" : (MIC_CHANNEL_QTY == 1) ? "mic_stream_single" : "mic_stream_multi"; + } // Capture signal if(!ctrlmf_audio_capture_start(request_type, audio_frames_signal, audio_frame_qty, duration)) { @@ -193,13 +190,16 @@ bool ctrlmf_mic_test_via_ambient(uint32_t duration, const char *output_filename, } XLOGD_INFO("analyze audio capture"); - #ifndef CTRLMF_CUSTOM_AUDIO_ANALYSIS - if(!ctrlmf_mic_test_audio_analyze(output_filename, level, NULL, audio_frames_signal, audio_frame_qty, MIC_CHANNEL_QTY, snr_min, snr_max, snr_var, test_result)) { - #else - if(!ctrlmf_mic_test_audio_analyze(CTRLMF_TEST_FACTORY, output_filename, level, NULL, audio_frames_signal, audio_frame_qty, MIC_CHANNEL_QTY, test_result)) { - #endif - XLOGD_ERROR("unable to analyze audio"); - break; + if(audio_analyze_func != NULL) { + if(!(*audio_analyze_func)(CTRLMF_TEST_FACTORY, output_filename, level, NULL, audio_frames_signal, audio_frame_qty, MIC_CHANNEL_QTY, test_result)) { + XLOGD_ERROR("unable to analyze audio"); + break; + } + } else { + if(!ctrlmf_mic_test_audio_analyze_default(output_filename, level, NULL, audio_frames_signal, audio_frame_qty, MIC_CHANNEL_QTY, snr_min, snr_max, snr_var, test_result)) { + XLOGD_ERROR("unable to analyze audio"); + break; + } } if(!ctrlmf_is_production()) { ctrlmf_mic_test_audio_export(FILENAME_WAV_SIGNAL, audio_frames_signal, audio_frame_qty, MIC_CHANNEL_QTY); @@ -217,8 +217,7 @@ bool ctrlmf_mic_test_via_ambient(uint32_t duration, const char *output_filename, return(result); } -#ifndef CTRLMF_CUSTOM_AUDIO_ANALYSIS -bool ctrlmf_mic_test_audio_analyze(const char *output_filename, uint32_t level, ctrlmf_audio_frame_t audio_frames_noise, ctrlmf_audio_frame_t audio_frames_signal, uint32_t frame_qty, uint32_t mic_qty, double snr_min, double snr_max, double snr_var, ctrlmf_test_result_t *test_result) { +bool ctrlmf_mic_test_audio_analyze_default(const char *output_filename, uint32_t level, ctrlmf_audio_frame_t audio_frames_noise, ctrlmf_audio_frame_t audio_frames_signal, uint32_t frame_qty, uint32_t mic_qty, double snr_min, double snr_max, double snr_var, ctrlmf_test_result_t *test_result) { double pcm_sq_sum_noise[mic_qty]; double pcm_sq_sum_signal[mic_qty]; @@ -295,7 +294,6 @@ bool ctrlmf_mic_test_audio_analyze(const char *output_filename, uint32_t level, } return(true); } -#endif void ctrlmf_mic_test_audio_export(const char *filename, ctrlmf_audio_frame_t audio_frames, uint32_t frame_qty, uint32_t channel_qty) { uint8_t header[WAVE_HEADER_SIZE_MIN]; diff --git a/src/factory/ctrlmf_version.c b/src/factory/ctrlmf_version.c index 459f0fd7..7d52efc0 100644 --- a/src/factory/ctrlmf_version.c +++ b/src/factory/ctrlmf_version.c @@ -1,7 +1,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -10,20 +12,25 @@ #include typedef struct { - bool initialized; - bool audio_control_init; - bool audio_playback_init; - bool is_production; + bool initialized; + void *handle_audio_analysis; + bool audio_control_init; + bool audio_playback_init; + bool is_production; } ctrlmf_global_t; ctrlmf_global_t g_ctrlmf = { - .initialized = false, - .audio_control_init = false, - .audio_playback_init = false, - .is_production = true + .initialized = false, + .handle_audio_analysis = NULL, + .audio_control_init = false, + .audio_playback_init = false, + .is_production = true }; -bool ctrlmf_init(xlog_level_t level, bool requires_audio_playback) { +static bool ctrlmf_file_exists(const char *filename); +static void *ctrlmf_load_plugin_audio_analysis(ctrlmf_mic_test_audio_analyze_t *audio_analyze_func); + +bool ctrlmf_init(xlog_level_t level, bool requires_audio_playback, bool requires_audio_control, ctrlmf_mic_test_audio_analyze_t *audio_analyze_func) { rdk_version_info_t info; int ret_val = rdk_version_parse_version(&info); @@ -44,42 +51,40 @@ bool ctrlmf_init(xlog_level_t level, bool requires_audio_playback) { return(false); } - #ifdef CTRLMF_AUDIO_CONTROL - if(!ctrlmf_audio_control_init()) { + if(requires_audio_control && !ctrlmf_audio_control_init()) { XLOGD_ERROR("failed to init audio control"); return(false); } - #endif - #ifdef CTRLMF_AUDIO_PLAYBACK if(requires_audio_playback && !ctrlmf_audio_playback_init()) { XLOGD_ERROR("failed to init audio playback"); - #ifdef CTRLMF_AUDIO_CONTROL - ctrlmf_audio_control_term(); - #endif + if(requires_audio_control) { + ctrlmf_audio_control_term(); + } return(false); } - #endif - g_ctrlmf.audio_control_init = true; - g_ctrlmf.audio_playback_init = requires_audio_playback; - g_ctrlmf.initialized = true; + g_ctrlmf.handle_audio_analysis = ctrlmf_load_plugin_audio_analysis(audio_analyze_func); + g_ctrlmf.audio_control_init = requires_audio_control; + g_ctrlmf.audio_playback_init = requires_audio_playback; + g_ctrlmf.initialized = true; return(true); } void ctrlmf_term(void) { - #ifdef CTRLMF_AUDIO_PLAYBACK if(g_ctrlmf.audio_playback_init) { ctrlmf_audio_playback_term(); } - #endif - #ifdef CTRLMF_AUDIO_CONTROL if(g_ctrlmf.audio_control_init) { ctrlmf_audio_control_term(); } - #endif + + if(g_ctrlmf.handle_audio_analysis != NULL) { + dlclose(g_ctrlmf.handle_audio_analysis); + g_ctrlmf.handle_audio_analysis = NULL; + } g_ctrlmf.audio_playback_init = false; g_ctrlmf.audio_control_init = false; @@ -95,3 +100,51 @@ bool ctrlmf_is_production(void) { return(g_ctrlmf.is_production); } +bool ctrlmf_file_exists(const char *filename) { + if(filename == NULL) { + return false; + } + struct stat buffer; + if(stat(filename, &buffer) == 0) { + return true; + } + return false; +} + +void *ctrlmf_load_plugin_audio_analysis(ctrlmf_mic_test_audio_analyze_t *audio_analyze_func) { + if(audio_analyze_func == NULL) { + XLOGD_INFO("Audio Analysis plugin not requested."); + return(NULL); + } + void *handle = NULL; + + const char *so_path_vd = "/vendor/lib/libctrlmf_audio_analysis.so"; + const char *so_path_mw = "/usr/lib/libctrlmf_audio_analysis.so"; + if(ctrlmf_file_exists(so_path_vd)) { + handle = dlopen(so_path_vd, RTLD_NOW); + } else if(ctrlmf_file_exists(so_path_mw)) { + handle = dlopen(so_path_mw, RTLD_NOW); + } else { + XLOGD_INFO("Audio Analysis plugin is not present."); + return(NULL); + } + + if(NULL == handle) { + XLOGD_ERROR("Failed to load Audio Analysis plugin <%s>", dlerror()); + return(NULL); + } + + dlerror(); // Clear any existing error + + *audio_analyze_func = (ctrlmf_mic_test_audio_analyze_t)dlsym(handle, "ctrlmf_mic_test_audio_analyze"); + char *error = dlerror(); + + if(error != NULL) { + XLOGD_ERROR("Failed to find plugin method (ctrlmf_mic_test_audio_analyze), error <%s>", error); + dlclose(handle); + return(NULL); + } + + XLOGD_INFO("Audio Analysis plugin is loaded."); + return(handle); +} diff --git a/src/factory/ctrlmf_ws.c b/src/factory/ctrlmf_ws.c index ea175c06..4befff0a 100644 --- a/src/factory/ctrlmf_ws.c +++ b/src/factory/ctrlmf_ws.c @@ -16,11 +16,13 @@ #include #ifdef CTRLMF_WSS_ENABLED +#include "rdkcertselector.h" #include #define CTRLMF_WS_CIPHER_LIST "AES256-SHA256:AES128-GCM-SHA256:AES128-SHA256" #define CTRLMF_WS_TLS_CERT_KEY_FILE "/tmp/serverXXXXXX" #define CTRLMF_WS_CERT_NAME_LEN (1024) #define CTRLMF_WS_CERT_PW_LEN (128) +#define CTRLMF_CERT_FILENAME_PREFIX "file://" #endif typedef enum { @@ -37,6 +39,7 @@ typedef struct { uint32_t * audio_frame_qty; uint32_t audio_frame_size; ctrlmf_ws_callbacks_t *callbacks; + bool *has_valid_cert; } ctrlmf_ws_thread_params_t; typedef struct { @@ -72,7 +75,7 @@ static bool ctrlmf_ws_add_chain(FILE *cert_key_fp, STACK_OF(X509) *additi ctrlmf_ws_global_t g_ctrlmf_ws; -bool ctrlmf_ws_init(uint32_t audio_frame_size, uint16_t port, bool log_enable, ctrlmf_ws_callbacks_t *callbacks) { +bool ctrlmf_ws_init(uint32_t audio_frame_size, uint16_t port, bool log_enable, ctrlmf_ws_callbacks_t *callbacks, bool *has_valid_cert) { ctrlmf_ws_thread_params_t params; sem_t semaphore; @@ -87,6 +90,7 @@ bool ctrlmf_ws_init(uint32_t audio_frame_size, uint16_t port, bool log_enable, c params.audio_frame_qty = &g_ctrlmf_ws.audio_frame_qty; params.audio_frame_size = audio_frame_size; params.callbacks = callbacks; + params.has_valid_cert = has_valid_cert; g_ctrlmf_ws.nopoll_ctx = NULL; g_ctrlmf_ws.audio_frames = NULL; @@ -146,52 +150,56 @@ void *ctrlmf_ws_main(void *param) { return(NULL); } - #ifdef CTRLMF_WSS_ENABLED - int cert_key_fd = -1; - FILE *cert_key_fp = NULL; char tmp_cert[32] = {0}; - int err_store; - - safec_rc = sprintf_s(tmp_cert, sizeof(tmp_cert), "%s", CTRLMF_WS_TLS_CERT_KEY_FILE); - if(safec_rc < EOK) { - ERR_CHK(safec_rc); - } + bool cert_valid = false; + #ifdef CTRLMF_WSS_ENABLED + do { + int cert_key_fd = -1; + FILE *cert_key_fp = NULL; + int err_store; - umask(0600); - cert_key_fd = mkstemp(tmp_cert); - if (cert_key_fd == -1) - { - err_store = errno; - XLOGD_ERROR("mkstemp failed: <%s>", strerror(err_store)); - return(NULL); - } + safec_rc = sprintf_s(tmp_cert, sizeof(tmp_cert), "%s", CTRLMF_WS_TLS_CERT_KEY_FILE); + if(safec_rc < EOK) { + ERR_CHK(safec_rc); + } - cert_key_fp = fdopen(cert_key_fd, "w"); - if(cert_key_fp == NULL) { - err_store = errno; - XLOGD_ERROR("fdopen failed: <%s>", strerror(err_store)); - if(0 != unlink(&tmp_cert[0])) { + umask(0600); + cert_key_fd = mkstemp(tmp_cert); + if (cert_key_fd == -1) + { err_store = errno; - XLOGD_ERROR("failed to remove temp cert <%s>", strerror(err_store)); + XLOGD_ERROR("mkstemp failed: <%s>", strerror(err_store)); + break; } - return(NULL); - } - if(!ctrlmf_ws_cert_config(cert_key_fp)) { - XLOGD_ERROR("failed to set cert or key, exit"); - fclose(cert_key_fp); - if(0 != unlink(&tmp_cert[0])) { + cert_key_fp = fdopen(cert_key_fd, "w"); + if(cert_key_fp == NULL) { err_store = errno; - XLOGD_ERROR("failed to remove temp cert <%s>", strerror(err_store)); + XLOGD_ERROR("fdopen failed: <%s>", strerror(err_store)); + if(0 != unlink(&tmp_cert[0])) { + err_store = errno; + XLOGD_ERROR("failed to remove temp cert <%s>", strerror(err_store)); + } + break; } - return(NULL); - } - fclose(cert_key_fp); - // Init OpenSSL - SSL_library_init(); - SSL_load_error_strings(); - OpenSSL_add_all_algorithms(); + if(!ctrlmf_ws_cert_config(cert_key_fp)) { + XLOGD_ERROR("failed to set cert or key"); + fclose(cert_key_fp); + if(0 != unlink(&tmp_cert[0])) { + err_store = errno; + XLOGD_ERROR("failed to remove temp cert <%s>", strerror(err_store)); + } + break; + } + fclose(cert_key_fp); + + // Init OpenSSL + SSL_library_init(); + SSL_load_error_strings(); + OpenSSL_add_all_algorithms(); + cert_valid = true; + } while(0); #endif if(params.log_enable) { @@ -203,17 +211,17 @@ void *ctrlmf_ws_main(void *param) { nopoll_ctx_set_on_ready(g_ctrlmf_ws.nopoll_ctx, ctrlmf_ws_on_ready, &state); nopoll_ctx_set_on_msg(g_ctrlmf_ws.nopoll_ctx, ctrlmf_ws_on_message, &state); - #ifdef CTRLMF_WSS_ENABLED - nopoll_conn_opts_set_ssl_protocol(opts, NOPOLL_METHOD_TLSV1_2); - nopoll_conn_opts_ssl_host_verify(opts, nopoll_false); //localhost will not match host specified in certificate - - if(!nopoll_conn_opts_set_ssl_certs(opts, &tmp_cert[0], &tmp_cert[0], NULL, NULL)) { - XLOGD_ERROR("Failed to add cert/key files to nopoll_conn"); - nopoll_ctx_unref(g_ctrlmf_ws.nopoll_ctx); - nopoll_conn_opts_free(opts); - return(NULL); + if(cert_valid) { + nopoll_conn_opts_set_ssl_protocol(opts, NOPOLL_METHOD_TLSV1_2); + nopoll_conn_opts_ssl_host_verify(opts, nopoll_false); //localhost will not match host specified in certificate + + if(!nopoll_conn_opts_set_ssl_certs(opts, &tmp_cert[0], &tmp_cert[0], NULL, NULL)) { + XLOGD_ERROR("Failed to add cert/key files to nopoll_conn"); + nopoll_ctx_unref(g_ctrlmf_ws.nopoll_ctx); + nopoll_conn_opts_free(opts); + return(NULL); + } } - #endif char port[6]; safec_rc = sprintf_s(port, sizeof(port), "%u", params.port); @@ -222,11 +230,11 @@ void *ctrlmf_ws_main(void *param) { } // Start IPv4/6 listener - #ifdef CTRLMF_WSS_ENABLED - state.nopoll_conn = nopoll_listener_tls_new_opts6(g_ctrlmf_ws.nopoll_ctx, opts, "::", port); - #else - state.nopoll_conn = nopoll_listener_new_opts6(g_ctrlmf_ws.nopoll_ctx, opts, "::", port); - #endif + if(cert_valid) { + state.nopoll_conn = nopoll_listener_tls_new_opts6(g_ctrlmf_ws.nopoll_ctx, opts, "::", port); + } else { + state.nopoll_conn = nopoll_listener_new_opts6(g_ctrlmf_ws.nopoll_ctx, opts, "::", port); + } if(!nopoll_conn_is_ok(state.nopoll_conn)) { XLOGD_ERROR("Listener connection IPv6 NOT ok"); nopoll_ctx_unref(g_ctrlmf_ws.nopoll_ctx); @@ -234,6 +242,10 @@ void *ctrlmf_ws_main(void *param) { return(NULL); } + if(params.has_valid_cert != NULL) { + *(params.has_valid_cert) = cert_valid; + } + // Unblock the caller that launched this thread sem_post(params.semaphore); params.semaphore = NULL; @@ -247,12 +259,12 @@ void *ctrlmf_ws_main(void *param) { nopoll_ctx_unref(g_ctrlmf_ws.nopoll_ctx); g_ctrlmf_ws.nopoll_ctx = NULL; - #ifdef CTRLMF_WSS_ENABLED - if(0 != unlink(tmp_cert)) { - int err_store = errno; - XLOGD_ERROR("failed to remove temp cert <%s>", strerror(err_store)); + if(cert_valid) { + if(0 != unlink(tmp_cert)) { + int err_store = errno; + XLOGD_ERROR("failed to remove temp cert <%s>", strerror(err_store)); + } } - #endif return(NULL); } @@ -372,9 +384,9 @@ void ctrlmf_ws_on_close(noPollCtx *ctx, noPollConn *conn, noPollPtr user_data) { #ifdef CTRLMF_WSS_ENABLED bool ctrlmf_ws_cert_config(FILE* cert_key_fp) { - bool ret = false; - ctrlm_fta_platform_cert_info_t *cert_info = NULL; + + rdkcertselector_h cert_selector = NULL; do { FILE *device_cert_fp = NULL; PKCS12 *p12_cert = NULL; @@ -382,18 +394,33 @@ bool ctrlmf_ws_cert_config(FILE* cert_key_fp) { X509 *x509_cert = NULL; STACK_OF(X509) *additional_certs = NULL; - cert_info = ctrlm_fta_platform_cert_info_get(false); - if(cert_info == NULL) { - XLOGD_ERROR("unable to get certificate info"); + char *cert_path = NULL; + char *cert_password = NULL; + cert_selector = rdkcertselector_new(NULL, NULL, "FBK_MTLS"); + + if(cert_selector == NULL){ + XLOGD_TELEMETRY("cert selector init failed"); break; } - if(cert_info->type != CTRLM_FTA_PLATFORM_VOICE_CERT_TYPE_P12) { - XLOGD_ERROR("unable to parse certificates that are not of PKCS12 type"); + rdkcertselectorStatus_t cert_status = rdkcertselector_getCert(cert_selector, &cert_path, &cert_password); + + if(cert_status != certselectorOk) { + XLOGD_TELEMETRY("cert selector retrieval failed"); + break; + } + + if(cert_path == NULL || cert_password == NULL) { + XLOGD_TELEMETRY("cert selector get failed"); break; } - device_cert_fp = fopen(cert_info->filename, "rb"); + char *local_path = cert_path; + if(strncmp(local_path, CTRLMF_CERT_FILENAME_PREFIX, strlen(CTRLMF_CERT_FILENAME_PREFIX)) == 0) { + local_path += strlen(CTRLMF_CERT_FILENAME_PREFIX); + } + + device_cert_fp = fopen(local_path, "rb"); if(device_cert_fp == NULL) { XLOGD_ERROR("unable to open P12 certificate"); break; @@ -408,7 +435,7 @@ bool ctrlmf_ws_cert_config(FILE* cert_key_fp) { break; } - if(1 != PKCS12_parse(p12_cert, cert_info->password, &pkey, &x509_cert, &additional_certs)) { + if(1 != PKCS12_parse(p12_cert, cert_password, &pkey, &x509_cert, &additional_certs)) { XLOGD_ERROR("unable to parse P12 certificate"); break; } @@ -423,7 +450,7 @@ bool ctrlmf_ws_cert_config(FILE* cert_key_fp) { break; } - if(1 != PEM_write_PrivateKey(cert_key_fp, pkey, NULL, (unsigned char*)cert_info->password, strlen(cert_info->password), NULL, NULL)) { + if(1 != PEM_write_PrivateKey(cert_key_fp, pkey, NULL, (unsigned char*)cert_password, strlen(cert_password), NULL, NULL)) { XLOGD_ERROR("failed to write temp key"); break; } @@ -431,8 +458,8 @@ bool ctrlmf_ws_cert_config(FILE* cert_key_fp) { ret = true; }while(0); - if(cert_info != NULL) { - ctrlm_fta_platform_cert_info_free(cert_info); + if(cert_selector != NULL) { + rdkcertselector_free(&cert_selector); } return ret; diff --git a/src/factory/ctrlmf_ws.h b/src/factory/ctrlmf_ws.h index f68490e3..203a2ac2 100644 --- a/src/factory/ctrlmf_ws.h +++ b/src/factory/ctrlmf_ws.h @@ -35,7 +35,7 @@ typedef struct { extern "C" { #endif -bool ctrlmf_ws_init(uint32_t audio_frame_size, uint16_t port, bool log_enable, ctrlmf_ws_callbacks_t *callbacks); +bool ctrlmf_ws_init(uint32_t audio_frame_size, uint16_t port, bool log_enable, ctrlmf_ws_callbacks_t *callbacks, bool *has_valid_cert); bool ctrlmf_ws_capture_set(ctrlmf_audio_frame_t audio_frames, uint32_t audio_frame_qty); void ctrlmf_ws_term(void); From f7ef989dd14c2690d7ef32ca22be6956dfe13074 Mon Sep 17 00:00:00 2001 From: Gene Gallagher <129112619+egalla204@users.noreply.github.com> Date: Tue, 9 Dec 2025 09:01:05 -0500 Subject: [PATCH 18/81] RDKEMW-11283: add product description docs (#159) --- PRODUCT.md | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 PRODUCT.md diff --git a/PRODUCT.md b/PRODUCT.md new file mode 100644 index 00000000..0279a77b --- /dev/null +++ b/PRODUCT.md @@ -0,0 +1,64 @@ +# rdkcentral/control Product Functionality + +This document summarizes the core product features, capabilities, and user-facing functionality provided by the `rdkcentral/control` project. + +## 1. Product Overview + +`rdkcentral/control` provides the central control and management solution for RDK-based devices, focusing on remote control integration, device state management, configuration handling, and hardware abstraction. It enables flexible, reliable control of device functions, typically in set-top boxes and smart TV platforms. + +## 2. Key Functional Areas + +### 2.1 Remote Control Manager + +- **Multi-protocol Support:** Integrates with RF4CE and BLE-based remote controls, supporting automatic pairing and discovery of devices. +- **Key Mapping & Input:** Manages IR, RF, and BLE key events, including vendor-specific key mappings (e.g., for AMC App). +- **Telemetry & Logging:** Captures and processes telemetry data from voice streams, key events, and audio sessions for diagnostics and monitoring. +- **OTA & Firmware Management:** Handles remote control firmware updates and network discovery, with stability features when interrupted (e.g., OTA interrupted by reset). + +### 2.2 Device State & Power Management + +- **Deep Sleep & Wake Handling:** Responds to device state changes, ensuring proper initialization/timer handling during deep sleep or wake events. +- **Power Plugin Integration:** Uses RDK's Power Manager Thunder plugin for system power state management and interaction. + +### 2.3 Configuration Management + +- **Dynamic Configuration:** Reads, updates, and applies runtime configuration changes from files, including support for vendor override files. +- **Device Discovery:** Provides mechanisms to discover IR input devices, support for multiple device types and fallback/stub implementations if hardware is absent. +- **HAL Abstraction:** Exposes interfaces to control hardware-specific features via C++ classes (see `ctrlm_hal.h`, `ctrlm_hal_rf4ce.h`, `ctrlm_hal_ble.h`). + +### 2.4 Audio & Voice Control + +- **Voice Session Management:** Supports BLE/RF voice streaming; logs sessions; manages session state, end times, and error reporting. +- **Audio Stream Management:** Reports and optimizes audio pipe size; ensures reliable audio sample reporting for voice sessions. + +### 2.5 API & Service Integration + +- **Thunder & HDMI Plugins:** Integrates with plugin frameworks to extend support for HDMI input, AV input, MAC address fetch, and advanced service bridging. +- **ASB Detection:** Offers runtime detection for Advanced Service Bridge capabilities. + +## 3. Product Extensibility + +- **Vendor Layer Integration:** Provides hooks for vendor-specific features, such as configuration overrides and device database stubs. +- **Flexible Build & Runtime Flags:** Build flags allow enabling/disabling features (e.g., BLE audio, packet analysis, deepsleep, memory lock). +- **Plugin & Target Customization:** Can build custom targets (e.g., just the control config file). + +## 4. Typical Use Cases + +- **User Experience:** Enables seamless remote pairing and input handling, responsive device wake/sleep, and dynamic feature provisioning. +- **Monitoring/Diagnostics:** Logs device events and telemetry, aiding both advanced diagnostics and data-driven product improvement. +- **Integration Point:** Forms the backbone for device control in RDK deployments where remote management and hardware abstraction are required. + +## 5. Recent Product Updates (Selected Highlights) + +- Multi-protocol remote integration (BLE and RF4CE support). +- Overhaul of key mapping and vendor integration logic. +- Telemetry improvements for voice stream analytics. +- Refactoring to enhance HAL interface extensibility. +- Crash and stability fixes for deep sleep, rapid input, and device discovery. +- Improved runtime configuration and plugin extensibility. + +_For full release notes, please see the [CHANGELOG](https://github.com/rdkcentral/control/blob/develop/CHANGELOG.md)._ + +## 6. Summary + +`rdkcentral/control` delivers a comprehensive control and management solution for RDK devices, emphasizing extensibility, reliability, and integration with modern remote protocols and power management frameworks. It remains the canonical product for remote control, device state, and configuration management within the RDK platform. From 3ab9e9275912dd8e609a3bb6a2867176f8c37319 Mon Sep 17 00:00:00 2001 From: Kelvin Lu <119349872+klu339@users.noreply.github.com> Date: Tue, 16 Dec 2025 12:00:56 -0500 Subject: [PATCH 19/81] RDKEMW-8929: Refactor base ipc class (#162) * RDKEMW-8929: Refactor base ipc class Reason for change: Test Procedure: Risks: Signed-off-by: Kelvin Lu * Updating based on Copilot review comments --------- Signed-off-by: Kelvin Lu --- include/ctrlm_ipc_voice.h | 8 +- src/ipc/ctrlm_ipc_iarm.cpp | 53 ++++-------- src/ipc/ctrlm_ipc_iarm.h | 52 +++++++++++- src/ipc/ctrlm_rcp_ipc_iarm_thunder.cpp | 9 +- src/voice/ipc/ctrlm_voice_ipc.h | 5 +- src/voice/ipc/ctrlm_voice_ipc_iarm_legacy.cpp | 23 ++--- .../ipc/ctrlm_voice_ipc_iarm_thunder.cpp | 85 ++++--------------- 7 files changed, 98 insertions(+), 137 deletions(-) diff --git a/include/ctrlm_ipc_voice.h b/include/ctrlm_ipc_voice.h index d5a58bc0..270b92d9 100644 --- a/include/ctrlm_ipc_voice.h +++ b/include/ctrlm_ipc_voice.h @@ -304,11 +304,11 @@ typedef struct { // IARM Event JSON // This structure is used for the following calls: -// CTRLM_VOICE_IARM_EVENT_SESSION_BEGIN_JSON -// CTRLM_VOICE_IARM_EVENT_STREAM_BEGIN_JSON +// CTRLM_VOICE_IARM_EVENT_SESSION_BEGIN_JSON +// CTRLM_VOICE_IARM_EVENT_STREAM_BEGIN_JSON // CTRLM_VOICE_IARM_EVENT_SERVER_MESSAGE_JSON -// CTRLM_VOICE_IARM_EVENT_STREAM_END_JSON -// CTRLM_VOICE_IARM_EVENT_SESSION_END_JSON +// CTRLM_VOICE_IARM_EVENT_STREAM_END_JSON +// CTRLM_VOICE_IARM_EVENT_SESSION_END_JSON // // The payload MUST be a NULL terminated JSON String. typedef struct { diff --git a/src/ipc/ctrlm_ipc_iarm.cpp b/src/ipc/ctrlm_ipc_iarm.cpp index b8d16842..420b44ce 100644 --- a/src/ipc/ctrlm_ipc_iarm.cpp +++ b/src/ipc/ctrlm_ipc_iarm.cpp @@ -20,6 +20,15 @@ #include "ctrlm_ipc_iarm.h" #include "ctrlm.h" #include "ctrlm_log.h" +#include "ctrlm_ipc_voice.h" + +void ctrlm_ipc_iarm_t::set_api_revision(unsigned char api_revision) { + api_revision_ = api_revision; +} + +unsigned char ctrlm_ipc_iarm_t::get_api_revision(void) const { + return api_revision_; +} bool ctrlm_ipc_iarm_t::register_iarm_call(const char *call, IARM_BusCall_t handler) const { @@ -35,44 +44,12 @@ bool ctrlm_ipc_iarm_t::register_iarm_call(const char *call, IARM_BusCall_t handl return(ret); } -bool ctrlm_ipc_iarm_t::broadcast_iarm_event(const char *bus_name, int event, json_t* event_data) const -{ - bool ret = false; - if(!event_data) { - return(ret); - } - - char *payload_str = json_dumps(event_data, JSON_COMPACT); - - if(payload_str != NULL) { - size_t str_size = strlen(payload_str) + 1; - size_t size = sizeof(ctrlm_main_iarm_event_json_t) + str_size; - - ctrlm_main_iarm_event_json_t *data = (ctrlm_main_iarm_event_json_t *)calloc(1, size); - if (data == NULL) { - XLOGD_ERROR("failed to allocate memory for the IARM event, so cannot broadcast...."); - } else { - - data->api_revision = CTRLM_MAIN_IARM_BUS_API_REVISION; - //Can't be replaced with safeC version of this, as safeC string functions doesn't allow string size more than 4K - snprintf(data->payload, str_size, "%s", payload_str); - - IARM_Result_t res = IARM_Bus_BroadcastEvent(bus_name, event, data, size); - if(res != IARM_RESULT_SUCCESS) { - XLOGD_ERROR("IARM Bus Error %d", res); - } else { - ret = true; - } - - free(data); - } - - free(payload_str); - } - - if(event_data) { - json_decref(event_data); +bool ctrlm_ipc_iarm_t::broadcast_iarm_event_legacy(const char *bus_name, int event, void *data, size_t data_size) const { + bool ret = true; + IARM_Result_t result = IARM_Bus_BroadcastEvent(bus_name, event, data, data_size); + if(IARM_RESULT_SUCCESS != result) { + XLOGD_ERROR("IARM Bus Error!"); + ret = false; } - return(ret); } diff --git a/src/ipc/ctrlm_ipc_iarm.h b/src/ipc/ctrlm_ipc_iarm.h index c966c080..51e487b5 100644 --- a/src/ipc/ctrlm_ipc_iarm.h +++ b/src/ipc/ctrlm_ipc_iarm.h @@ -26,6 +26,9 @@ #include class ctrlm_ipc_iarm_t { +private: + unsigned char api_revision_ = 0; + public: ctrlm_ipc_iarm_t() {}; virtual ~ctrlm_ipc_iarm_t() {}; @@ -38,8 +41,55 @@ class ctrlm_ipc_iarm_t { static void turn_on(std::atomic_bool &abool) { abool.store(true); } static void turn_off(std::atomic_bool &abool) { abool.store(false); } + void set_api_revision(unsigned char api_revision); + unsigned char get_api_revision(void) const; + bool register_iarm_call(const char *call, IARM_BusCall_t handler) const; - bool broadcast_iarm_event(const char *bus_name, int event, json_t* event_data) const; + bool broadcast_iarm_event_legacy(const char *bus_name, int event, void *data, size_t data_size) const; + + template + bool broadcast_iarm_event(const char *bus_name, int event, json_t* event_data) const + { + bool ret = false; + if(!event_data) { + return(ret); + } + + char *payload_str = json_dumps(event_data, JSON_COMPACT); + + if(payload_str != NULL) { + ret = broadcast_iarm_event(bus_name, event, payload_str); + free(payload_str); + } + + if(event_data) { + json_decref(event_data); + } + + return(ret); + } + + template + bool broadcast_iarm_event(const char *bus_name, int event, const char *str) const + { + bool ret = false; + size_t str_size = strlen(str) + 1; + size_t size = sizeof(T) + str_size; + + T *data = (T *)calloc(1, size); + if (data != nullptr) { + data->api_revision = api_revision_; + //Can't be replaced with safeC version of this, as safeC string functions doesn't allow string size more than 4K + snprintf(data->payload, str_size, "%s", str); + + IARM_Result_t res = IARM_Bus_BroadcastEvent(bus_name, event, data, size); + if(res == IARM_RESULT_SUCCESS) { + ret = true; + } + free(data); + } + return(ret); + } }; #endif diff --git a/src/ipc/ctrlm_rcp_ipc_iarm_thunder.cpp b/src/ipc/ctrlm_rcp_ipc_iarm_thunder.cpp index 02f4128d..88d2a38f 100644 --- a/src/ipc/ctrlm_rcp_ipc_iarm_thunder.cpp +++ b/src/ipc/ctrlm_rcp_ipc_iarm_thunder.cpp @@ -36,6 +36,7 @@ ctrlm_rcp_ipc_iarm_thunder_t::ctrlm_rcp_ipc_iarm_thunder_t() : ctrlm_ipc_iarm_t( { XLOGD_INFO(""); configure(); + set_api_revision(CTRLM_MAIN_IARM_BUS_API_REVISION); } ctrlm_rcp_ipc_iarm_thunder_t::~ctrlm_rcp_ipc_iarm_thunder_t() @@ -125,7 +126,7 @@ bool ctrlm_rcp_ipc_iarm_thunder_t::on_status(const ctrlm_rcp_ipc_net_status_t &n return(false); } - return broadcast_iarm_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_RCU_IARM_EVENT_RCU_STATUS, ret); + return broadcast_iarm_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_RCU_IARM_EVENT_RCU_STATUS, ret); } bool ctrlm_rcp_ipc_iarm_thunder_t::on_validation_status(const ctrlm_rcp_ipc_validation_status_t &validation_status) const @@ -151,7 +152,7 @@ bool ctrlm_rcp_ipc_iarm_thunder_t::on_validation_status(const ctrlm_rcp_ipc_vali return(false); } - return broadcast_iarm_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_RCU_IARM_EVENT_VALIDATION_STATUS, ret); + return broadcast_iarm_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_RCU_IARM_EVENT_VALIDATION_STATUS, ret); } bool ctrlm_rcp_ipc_iarm_thunder_t::on_firmware_update_progress(const ctrlm_rcp_ipc_upgrade_status_t &upgrade_status) const @@ -177,7 +178,7 @@ bool ctrlm_rcp_ipc_iarm_thunder_t::on_firmware_update_progress(const ctrlm_rcp_i return(false); } - return broadcast_iarm_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_RCU_IARM_EVENT_FIRMWARE_UPDATE_PROGRESS, ret); + return broadcast_iarm_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_RCU_IARM_EVENT_FIRMWARE_UPDATE_PROGRESS, ret); } bool ctrlm_rcp_ipc_iarm_thunder_t::on_validation(const ctrlm_rcp_ipc_validation_status_t &validation_status) const @@ -198,7 +199,7 @@ bool ctrlm_rcp_ipc_iarm_thunder_t::on_validation(const ctrlm_rcp_ipc_validation_ return(false); } - return broadcast_iarm_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_RCU_IARM_EVENT_VALIDATION_STATUS, ret); + return broadcast_iarm_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_RCU_IARM_EVENT_VALIDATION_STATUS, ret); } IARM_Result_t ctrlm_rcp_ipc_iarm_thunder_t::start_pairing(void *arg) diff --git a/src/voice/ipc/ctrlm_voice_ipc.h b/src/voice/ipc/ctrlm_voice_ipc.h index 25197ff8..969a8380 100644 --- a/src/voice/ipc/ctrlm_voice_ipc.h +++ b/src/voice/ipc/ctrlm_voice_ipc.h @@ -22,6 +22,7 @@ #include "ctrlm.h" #include "ctrlm_voice_types.h" #include "ctrlm_ipc_voice.h" +#include "ctrlm_ipc_iarm.h" // Classes for eventing @@ -171,7 +172,7 @@ class ctrlm_voice_ipc_event_session_statistics_t { }; // End classes for eventing -class ctrlm_voice_ipc_t { +class ctrlm_voice_ipc_t : public ctrlm_ipc_iarm_t { public: ctrlm_voice_ipc_t(ctrlm_voice_t *obj_voice) { this->obj_voice = obj_voice; @@ -179,7 +180,6 @@ class ctrlm_voice_ipc_t { virtual ~ctrlm_voice_ipc_t() {}; // Interface - virtual bool register_ipc() const = 0; virtual bool session_begin(const ctrlm_voice_ipc_event_session_begin_t &session_begin) = 0; virtual bool stream_begin(const ctrlm_voice_ipc_event_stream_begin_t &stream_begin) = 0; virtual bool stream_end(const ctrlm_voice_ipc_event_stream_end_t &stream_end) = 0; @@ -187,7 +187,6 @@ class ctrlm_voice_ipc_t { virtual bool server_message(const char *message, unsigned long size) = 0; // Pass a pointer to the message to avoid copying possible large chunks of data virtual bool keyword_verification(const ctrlm_voice_ipc_event_keyword_verification_t &keyword_verification) = 0; virtual bool session_statistics(const ctrlm_voice_ipc_event_session_statistics_t &session_stats) = 0; - virtual void deregister_ipc() const = 0; // End Interface protected: diff --git a/src/voice/ipc/ctrlm_voice_ipc_iarm_legacy.cpp b/src/voice/ipc/ctrlm_voice_ipc_iarm_legacy.cpp index c07f22b1..6564ef4c 100644 --- a/src/voice/ipc/ctrlm_voice_ipc_iarm_legacy.cpp +++ b/src/voice/ipc/ctrlm_voice_ipc_iarm_legacy.cpp @@ -23,7 +23,6 @@ #include "ctrlm_voice_obj.h" static IARM_Result_t update_settings(void *arg); -static bool broadcast_event(const char *bus_name, int event, void *data, size_t data_size); ctrlm_voice_ipc_iarm_legacy_t::ctrlm_voice_ipc_iarm_legacy_t(ctrlm_voice_t *obj_voice) : ctrlm_voice_ipc_t(obj_voice) { this->state = EVENT_ALL; @@ -68,7 +67,7 @@ bool ctrlm_voice_ipc_iarm_legacy_t::session_begin(const ctrlm_voice_ipc_event_se safec_rc = strcpy_s((char *)event.language, sizeof(event.language), session_begin.language.c_str()); ERR_CHK(safec_rc); event.is_voice_assistant = session_begin.common.voice_assistant ? 1 : 0; - ret = broadcast_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_SESSION_BEGIN, &event, sizeof(event)); + ret = broadcast_iarm_event_legacy(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_SESSION_BEGIN, &event, sizeof(event)); } return(ret); } @@ -90,7 +89,7 @@ bool ctrlm_voice_ipc_iarm_legacy_t::stream_end(const ctrlm_voice_ipc_event_strea event.session_id = stream_end.common.session_id_ctrlm; event.reason = (ctrlm_voice_session_end_reason_t)stream_end.reason; event.is_voice_assistant = stream_end.common.voice_assistant ? 1 : 0; - ret = broadcast_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_SESSION_END, &event, sizeof(event)); + ret = broadcast_iarm_event_legacy(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_SESSION_END, &event, sizeof(event)); } return(ret); } @@ -133,7 +132,7 @@ bool ctrlm_voice_ipc_iarm_legacy_t::session_end(const ctrlm_voice_ipc_event_sess event.curl_request_dns_time = session_end.server_stats->dns_time; event.curl_request_connect_time = session_end.server_stats->connect_time; } - ret = broadcast_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_SESSION_RESULT, &event, sizeof(event)); + ret = broadcast_iarm_event_legacy(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_SESSION_RESULT, &event, sizeof(event)); break; } case SESSION_END_ABORT: { @@ -144,7 +143,7 @@ bool ctrlm_voice_ipc_iarm_legacy_t::session_end(const ctrlm_voice_ipc_event_sess event.controller_id = session_end.common.controller_id; event.session_id = session_end.common.session_id_ctrlm; event.reason = (ctrlm_voice_session_abort_reason_t)session_end.reason; - ret = broadcast_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_SESSION_ABORT, &event, sizeof(event)); + ret = broadcast_iarm_event_legacy(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_SESSION_ABORT, &event, sizeof(event)); break; } case SESSION_END_SHORT_UTTERANCE: { @@ -156,7 +155,7 @@ bool ctrlm_voice_ipc_iarm_legacy_t::session_end(const ctrlm_voice_ipc_event_sess event.session_id = session_end.common.session_id_ctrlm; event.reason = (ctrlm_voice_session_end_reason_t)session_end.reason; event.return_code_internal = session_end.return_code_internal; - ret = broadcast_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_SESSION_SHORT, &event, sizeof(event)); + ret = broadcast_iarm_event_legacy(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_SESSION_SHORT, &event, sizeof(event)); break; } } @@ -195,7 +194,7 @@ bool ctrlm_voice_ipc_iarm_legacy_t::session_statistics(const ctrlm_voice_ipc_eve event.session_id = session_stats.common.session_id_ctrlm; event.session = session_stats.session; event.reboot = session_stats.reboot; - return(broadcast_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_SESSION_STATS, &event, sizeof(event))); + return(broadcast_iarm_event_legacy(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_SESSION_STATS, &event, sizeof(event))); } void ctrlm_voice_ipc_iarm_legacy_t::deregister_ipc() const { @@ -230,13 +229,3 @@ IARM_Result_t update_settings(void *arg) { return(IARM_RESULT_SUCCESS); } - -bool broadcast_event(const char *bus_name, int event, void *data, size_t data_size) { - bool ret = true; - IARM_Result_t result = IARM_Bus_BroadcastEvent(bus_name, event, data, data_size); - if(IARM_RESULT_SUCCESS != result) { - XLOGD_ERROR("IARM Bus Error!"); - ret = false; - } - return(ret); -} diff --git a/src/voice/ipc/ctrlm_voice_ipc_iarm_thunder.cpp b/src/voice/ipc/ctrlm_voice_ipc_iarm_thunder.cpp index 02b4408e..6b407173 100644 --- a/src/voice/ipc/ctrlm_voice_ipc_iarm_thunder.cpp +++ b/src/voice/ipc/ctrlm_voice_ipc_iarm_thunder.cpp @@ -83,73 +83,47 @@ #define JSON_SESSION_END_SERVER_STATS_DNS_TIME "dnsTime" #define JSON_SESSION_END_SERVER_STATS_CONNECT_TIME "connectTime" -static bool broadcast_event(const char *bus_name, int event, const char *str); static const char *voice_device_str(ctrlm_voice_device_t device); static const char *voice_device_status_str(uint8_t status); ctrlm_voice_ipc_iarm_thunder_t::ctrlm_voice_ipc_iarm_thunder_t(ctrlm_voice_t *obj_voice): ctrlm_voice_ipc_t(obj_voice) { - + set_api_revision(CTRLM_VOICE_IARM_BUS_API_REVISION); } bool ctrlm_voice_ipc_iarm_thunder_t::register_ipc() const { bool ret = true; - IARM_Result_t rc; XLOGD_INFO("Thunder"); // NOTE: The IARM events are registered in ctrlm_main.cpp - XLOGD_INFO("Registering for %s IARM call", CTRLM_VOICE_IARM_CALL_STATUS); - rc = IARM_Bus_RegisterCall(CTRLM_VOICE_IARM_CALL_STATUS, &ctrlm_voice_ipc_iarm_thunder_t::status); - if(rc != IARM_RESULT_SUCCESS) { - XLOGD_ERROR("Failed to register %d", rc); + if(!register_iarm_call(CTRLM_VOICE_IARM_CALL_STATUS, &ctrlm_voice_ipc_iarm_thunder_t::status)) { ret = false; } - XLOGD_INFO("Registering for %s IARM call", CTRLM_VOICE_IARM_CALL_CONFIGURE_VOICE); - rc = IARM_Bus_RegisterCall(CTRLM_VOICE_IARM_CALL_CONFIGURE_VOICE, &ctrlm_voice_ipc_iarm_thunder_t::configure_voice); - if(rc != IARM_RESULT_SUCCESS) { - XLOGD_ERROR("Failed to register %d", rc); + if(!register_iarm_call(CTRLM_VOICE_IARM_CALL_CONFIGURE_VOICE, &ctrlm_voice_ipc_iarm_thunder_t::configure_voice)) { ret = false; } - XLOGD_INFO("Registering for %s IARM call", CTRLM_VOICE_IARM_CALL_SET_VOICE_INIT); - rc = IARM_Bus_RegisterCall(CTRLM_VOICE_IARM_CALL_SET_VOICE_INIT, &ctrlm_voice_ipc_iarm_thunder_t::set_voice_init); - if(rc != IARM_RESULT_SUCCESS) { - XLOGD_ERROR("Failed to register %d", rc); + if(!register_iarm_call(CTRLM_VOICE_IARM_CALL_SET_VOICE_INIT, &ctrlm_voice_ipc_iarm_thunder_t::set_voice_init)) { ret = false; } - XLOGD_INFO("Registering for %s IARM call", CTRLM_VOICE_IARM_CALL_SEND_VOICE_MESSAGE); - rc = IARM_Bus_RegisterCall(CTRLM_VOICE_IARM_CALL_SEND_VOICE_MESSAGE, &ctrlm_voice_ipc_iarm_thunder_t::send_voice_message); - if(rc != IARM_RESULT_SUCCESS) { - XLOGD_ERROR("Failed to register %d", rc); + if(!register_iarm_call(CTRLM_VOICE_IARM_CALL_SEND_VOICE_MESSAGE, &ctrlm_voice_ipc_iarm_thunder_t::send_voice_message)) { ret = false; } - XLOGD_INFO("Registering for %s IARM call", CTRLM_VOICE_IARM_CALL_SESSION_TYPES); - rc = IARM_Bus_RegisterCall(CTRLM_VOICE_IARM_CALL_SESSION_TYPES, &ctrlm_voice_ipc_iarm_thunder_t::voice_session_types); - if(rc != IARM_RESULT_SUCCESS) { - XLOGD_ERROR("Failed to register %d", rc); + if(!register_iarm_call(CTRLM_VOICE_IARM_CALL_SESSION_TYPES, &ctrlm_voice_ipc_iarm_thunder_t::voice_session_types)) { ret = false; } - XLOGD_INFO("Registering for %s IARM call", CTRLM_VOICE_IARM_CALL_SESSION_REQUEST); - rc = IARM_Bus_RegisterCall(CTRLM_VOICE_IARM_CALL_SESSION_REQUEST, &ctrlm_voice_ipc_iarm_thunder_t::voice_session_request); - if(rc != IARM_RESULT_SUCCESS) { - XLOGD_ERROR("Failed to register %d", rc); + if(!register_iarm_call(CTRLM_VOICE_IARM_CALL_SESSION_REQUEST, &ctrlm_voice_ipc_iarm_thunder_t::voice_session_request)) { ret = false; } - XLOGD_INFO("Registering for %s IARM call", CTRLM_VOICE_IARM_CALL_SESSION_TERMINATE); - rc = IARM_Bus_RegisterCall(CTRLM_VOICE_IARM_CALL_SESSION_TERMINATE, &ctrlm_voice_ipc_iarm_thunder_t::voice_session_terminate); - if(rc != IARM_RESULT_SUCCESS) { - XLOGD_ERROR("Failed to register %d", rc); + if(!register_iarm_call(CTRLM_VOICE_IARM_CALL_SESSION_TERMINATE, &ctrlm_voice_ipc_iarm_thunder_t::voice_session_terminate)) { ret = false; } - XLOGD_INFO("Registering for %s IARM call", CTRLM_VOICE_IARM_CALL_SESSION_AUDIO_STREAM_START); - rc = IARM_Bus_RegisterCall(CTRLM_VOICE_IARM_CALL_SESSION_AUDIO_STREAM_START, &ctrlm_voice_ipc_iarm_thunder_t::voice_session_audio_stream_start); - if(rc != IARM_RESULT_SUCCESS) { - XLOGD_ERROR("Failed to register %d", rc); + if(!register_iarm_call(CTRLM_VOICE_IARM_CALL_SESSION_AUDIO_STREAM_START, &ctrlm_voice_ipc_iarm_thunder_t::voice_session_audio_stream_start)) { ret = false; } @@ -175,7 +149,7 @@ bool ctrlm_voice_ipc_iarm_thunder_t::session_begin(const ctrlm_voice_ipc_event_s if(json_str) { //TODO: surface the event through IARM XLOGD_INFO("%s", json_str); - ret = broadcast_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_JSON_SESSION_BEGIN, json_str); + ret = broadcast_iarm_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_JSON_SESSION_BEGIN, json_str); free(json_str); } else { XLOGD_ERROR("Failed to encode JSON string"); @@ -204,7 +178,7 @@ bool ctrlm_voice_ipc_iarm_thunder_t::stream_begin(const ctrlm_voice_ipc_event_st if(json_str) { //TODO: surface the event through IARM XLOGD_INFO("%s", json_str); - ret = broadcast_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_JSON_STREAM_BEGIN, json_str); + ret = broadcast_iarm_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_JSON_STREAM_BEGIN, json_str); free(json_str); } else { XLOGD_ERROR("Failed to encode JSON string"); @@ -234,7 +208,7 @@ bool ctrlm_voice_ipc_iarm_thunder_t::stream_end(const ctrlm_voice_ipc_event_stre if(json_str) { //TODO: surface the event through IARM XLOGD_INFO("%s", json_str); - ret = broadcast_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_JSON_STREAM_END, json_str); + ret = broadcast_iarm_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_JSON_STREAM_END, json_str); free(json_str); } else { XLOGD_ERROR("Failed to encode JSON string"); @@ -358,7 +332,7 @@ bool ctrlm_voice_ipc_iarm_thunder_t::session_end(const ctrlm_voice_ipc_event_ses if(json_str) { //TODO: surface the event through IARM XLOGD_AUTOMATION_INFO("<%s>", this->obj_voice->voice_stb_data_pii_mask_get() ? "***" : json_str); - ret = broadcast_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_JSON_SESSION_END, json_str); + ret = broadcast_iarm_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_JSON_SESSION_END, json_str); free(json_str); } else { XLOGD_ERROR("Failed to encode JSON string"); @@ -374,7 +348,7 @@ bool ctrlm_voice_ipc_iarm_thunder_t::server_message(const char *message, unsigne bool ret = false; if(message) { XLOGD_AUTOMATION_INFO("%ul : <%s>", size, this->obj_voice->voice_stb_data_pii_mask_get() ? "***" : message); //CID -160950 - Printargs - ret = broadcast_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_JSON_SERVER_MESSAGE, message); + ret = broadcast_iarm_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_JSON_SERVER_MESSAGE, message); } return(ret); } @@ -397,7 +371,7 @@ bool ctrlm_voice_ipc_iarm_thunder_t::keyword_verification(const ctrlm_voice_ipc_ if(json_str) { //TODO: surface the event through IARM XLOGD_INFO("%s", json_str); - ret = broadcast_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_JSON_KEYWORD_VERIFICATION, json_str); + ret = broadcast_iarm_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_JSON_KEYWORD_VERIFICATION, json_str); free(json_str); } else { XLOGD_ERROR("Failed to encode JSON string"); @@ -981,35 +955,6 @@ const char *voice_device_status_str(uint8_t status) { return("invalid"); } -bool broadcast_event(const char *bus_name, int event, const char *str) { - bool ret = false; - size_t str_size = strlen(str) + 1; - size_t size = sizeof(ctrlm_voice_iarm_event_json_t) + str_size; - ctrlm_voice_iarm_event_json_t *data = (ctrlm_voice_iarm_event_json_t *)malloc(size); - if(data) { - IARM_Result_t result; - - //Can't be replaced with safeC version of this - memset(data, 0, size); - - data->api_revision = CTRLM_VOICE_IARM_BUS_API_REVISION; - //Can't be replaced with safeC version of this, as safeC string functions doesn't allow string size more than 4K - snprintf(data->payload, str_size, "%s", str); - result = IARM_Bus_BroadcastEvent(bus_name, event, data, size); - if(IARM_RESULT_SUCCESS != result) { - XLOGD_ERROR("IARM Bus Error!"); - } else { - ret = true; - } - if(data) { - free(data); - } - } else { - XLOGD_ERROR("Failed to allocate data for IARM event"); - } - return(ret); -} - bool ctrlm_voice_ipc_request_supported_ptt_transcription(ctrlm_voice_ipc_request_config_t *config) { config->requires_transcription = true; config->requires_audio_file = false; From d66eb1d6ea15455c26069bd834d2fa23edd89bdb Mon Sep 17 00:00:00 2001 From: dwolaver <44593664+dwolaver@users.noreply.github.com> Date: Mon, 5 Jan 2026 15:23:30 -0500 Subject: [PATCH 20/81] RDKEMW-12151 : ctrlm release v1.1.8, xr-voice-sdk v1.0.9 (#166) --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd51fc43..18d43be6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,14 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [1.1.8](https://github.com/rdkcentral/control/compare/1.1.7...1.1.8) + +> 5 January 2026 + +- RDKEMW-8929: Refactor base ipc class [`#162`](https://github.com/rdkcentral/control/pull/162) +- RDKEMW-11283: add product description docs [`#159`](https://github.com/rdkcentral/control/pull/159) +- RDKEMW-8930 : remove ctrlm build flags - FACTORY_AUDIO_PLAYBACK [`#143`](https://github.com/rdkcentral/control/pull/143) + #### [1.1.7](https://github.com/rdkcentral/control/compare/1.1.6...1.1.7) > 4 December 2025 From e502de17994b8f1e9b7303171626d39e622665ec Mon Sep 17 00:00:00 2001 From: Kelvin Lu <119349872+klu339@users.noreply.github.com> Date: Mon, 12 Jan 2026 13:51:10 -0500 Subject: [PATCH 21/81] RDKEMW-11471: Remove netType param (#164) --- src/ble/ctrlm_ble_controller.cpp | 17 ++++ src/ble/ctrlm_ble_controller.h | 2 + src/ble/ctrlm_ble_network.cpp | 58 +++++++++----- src/ble/ctrlm_ble_network.h | 5 ++ src/ble/hal/blercu/blercucontroller.cpp | 2 +- src/ble/hal/blercu/blercucontroller_p.h | 4 +- src/ctrlm_controller.cpp | 17 ++++ src/ctrlm_controller.h | 1 + src/ctrlm_main.cpp | 5 -- src/ctrlm_network.cpp | 5 ++ src/ctrlm_network.h | 6 ++ src/ipc/ctrlm_rcp_ipc_event.cpp | 17 ++++ src/ipc/ctrlm_rcp_ipc_event.h | 25 +++--- src/ipc/ctrlm_rcp_ipc_iarm_thunder.cpp | 84 ++++++++++---------- src/irdb/ctrlm_irdb_interface.cpp | 68 ++++++++++++---- src/irdb/ctrlm_irdb_interface.h | 5 +- src/irdb/ipc/ctrlm_irdb_ipc_iarm_thunder.cpp | 18 +---- src/rf4ce/ctrlm_rf4ce_network.cpp | 27 +++++-- src/rf4ce/ctrlm_rf4ce_network.h | 4 + 19 files changed, 250 insertions(+), 120 deletions(-) diff --git a/src/ble/ctrlm_ble_controller.cpp b/src/ble/ctrlm_ble_controller.cpp index d86650db..fdbd155f 100644 --- a/src/ble/ctrlm_ble_controller.cpp +++ b/src/ble/ctrlm_ble_controller.cpp @@ -654,4 +654,21 @@ void ctrlm_obj_controller_ble_t::print_status() { XLOGD_WARN("------------------------------------------------------------"); } +void ctrlm_obj_controller_ble_t::update_controller_id_and_db_entry(std::string db_name, ctrlm_network_id_t network_id, ctrlm_controller_id_t new_id) { + ctrlm_obj_controller_t::update_controller_id_and_db_entry(db_name, network_id, new_id); + + std::stringstream new_controller_db_table; + new_controller_db_table << db_name << "_" << COUT_HEX_MODIFIER << (int)network_id << "_controller_" << COUT_HEX_MODIFIER << (int)new_id; + std::string new_table = new_controller_db_table.str(); + + product_name_->set_table(new_table); + serial_number_->set_table(new_table); + manufacturer_->set_table(new_table); + model_->set_table(new_table); + fw_revision_->set_table(new_table); + sw_revision_->set_table(new_table); + hw_revision_->set_table(new_table); + battery_percent_->set_table(new_table); +} + // End Function Implementations diff --git a/src/ble/ctrlm_ble_controller.h b/src/ble/ctrlm_ble_controller.h index 5179578c..432f5c76 100644 --- a/src/ble/ctrlm_ble_controller.h +++ b/src/ble/ctrlm_ble_controller.h @@ -147,6 +147,8 @@ class ctrlm_obj_controller_ble_t : public ctrlm_obj_controller_t { ctrlm_timestamp_t getVoiceStartTimeKey() const; ctrlm_timestamp_t getVoiceStartTimeLocal() const; + void update_controller_id_and_db_entry(std::string name, ctrlm_network_id_t network_id, ctrlm_controller_id_t new_id); + private: ctrlm_obj_network_ble_t *obj_network_ble_ = NULL; diff --git a/src/ble/ctrlm_ble_network.cpp b/src/ble/ctrlm_ble_network.cpp index 8965b71a..aff81aeb 100644 --- a/src/ble/ctrlm_ble_network.cpp +++ b/src/ble/ctrlm_ble_network.cpp @@ -779,13 +779,15 @@ void ctrlm_obj_network_ble_t::req_process_program_ir_codes(void *data, int size) g_assert(dqm); g_assert(size == sizeof(ctrlm_main_queue_msg_program_ir_codes_t)); - if(dqm->success) {*(dqm->success) = false;} + bool success = false; if (!ready_) { XLOGD_FATAL("Network is not ready!"); } else { ctrlm_controller_id_t controller_id = dqm->controller_id; - if (!controller_exists(controller_id)) { + if (!is_managed_by_network(controller_id)) { + XLOGD_ERROR("Controller %d is not managed by the %s network", controller_id, name_get()); + } else if (!controller_exists(controller_id)) { XLOGD_ERROR("Controller doesn't exist!"); } else if (!controllers_[controller_id]->isSupportedIrdb(dqm->vendor_info)) { XLOGD_ERROR("Unsupported IRDB - not continuing with ir code download!"); @@ -815,12 +817,10 @@ void ctrlm_obj_network_ble_t::req_process_program_ir_codes(void *data, int size) XLOGD_ERROR("failed to program IR signal waveforms on remote"); } else { - - if (dqm->success) { *(dqm->success) = true; } - - controllers_[controller_id]->irdb_entry_id_name_set(CTRLM_IRDB_DEV_TYPE_TV, ir_rf_database_.get_tv_ir_code_id()); - controllers_[controller_id]->irdb_entry_id_name_set(CTRLM_IRDB_DEV_TYPE_AVR, ir_rf_database_.get_avr_ir_code_id()); - XLOGD_INFO("irdb_entry_id_name = <%s>", dqm->ir_codes->id.c_str()); + success = true; + controllers_[controller_id]->irdb_entry_id_name_set(CTRLM_IRDB_DEV_TYPE_TV, ir_rf_database_.get_tv_ir_code_id()); + controllers_[controller_id]->irdb_entry_id_name_set(CTRLM_IRDB_DEV_TYPE_AVR, ir_rf_database_.get_avr_ir_code_id()); + XLOGD_INFO("irdb_entry_id_name = <%s>", dqm->ir_codes->id.c_str()); } } // Store the IR codes in the database @@ -828,6 +828,7 @@ void ctrlm_obj_network_ble_t::req_process_program_ir_codes(void *data, int size) } } } + if(dqm->success) {dqm->success->push_back(success);} if(dqm->semaphore) { sem_post(dqm->semaphore); } @@ -842,13 +843,15 @@ void ctrlm_obj_network_ble_t::req_process_ir_clear_codes(void *data, int size) { g_assert(dqm); g_assert(size == sizeof(ctrlm_main_queue_msg_ir_clear_t)); - if(dqm->success) {*(dqm->success) = false;} + bool success = false; if (!ready_) { XLOGD_FATAL("Network is not ready!"); } else { ctrlm_controller_id_t controller_id = dqm->controller_id; - if (!controller_exists(controller_id)) { + if (!is_managed_by_network(controller_id)) { + XLOGD_ERROR("Controller %d is not managed by the %s network", controller_id, name_get()); + } else if (!controller_exists(controller_id)) { XLOGD_ERROR("Controller doesn't exist!"); } else { @@ -856,9 +859,7 @@ void ctrlm_obj_network_ble_t::req_process_ir_clear_codes(void *data, int size) { if (!ble_rcu_interface_->eraseIrSignals(controllers_[controller_id]->ieee_address_get().get_value())) { XLOGD_ERROR("failed to erase IR signal waveforms on remote"); } else { - - if (dqm->success) { *(dqm->success) = true; } - + success = true; ir_rf_database_.clear_ir_codes(); XLOGD_INFO("\n%s", ir_rf_database_.to_string(true).c_str()); controllers_[controller_id]->irdb_entry_id_name_set(CTRLM_IRDB_DEV_TYPE_TV, "0"); @@ -868,6 +869,7 @@ void ctrlm_obj_network_ble_t::req_process_ir_clear_codes(void *data, int size) { ir_rf_database_.store_db(); } } + if(dqm->success) {dqm->success->push_back(success);} if(dqm->semaphore) { sem_post(dqm->semaphore); } @@ -973,7 +975,7 @@ void ctrlm_obj_network_ble_t::req_process_find_my_remote(void *data, int size) { ctrlm_controller_id_t controller_id = get_last_used_controller(); if (CTRLM_HAL_CONTROLLER_ID_INVALID == controller_id) { - XLOGD_ERROR("no connected controllers to find!!"); + XLOGD_ERROR("no connected %s controllers to find!!", name_get()); dqm->params->set_result(CTRLM_IARM_CALL_RESULT_ERROR, network_id_get()); } else { if (ble_rcu_interface_) { @@ -2440,7 +2442,7 @@ void ctrlm_obj_network_ble_t::controller_remove(ctrlm_controller_id_t controller ctrlm_controller_id_t ctrlm_obj_network_ble_t::controller_id_assign() { // Get the next available controller id - for(ctrlm_controller_id_t index = 1; index < CTRLM_MAIN_CONTROLLER_ID_ALL; index++) { + for(ctrlm_controller_id_t index = BLE_RCU_ID_RANGE_MIN; index < BLE_RCU_ID_RANGE_MAX; index++) { if(!controller_exists(index)) { XLOGD_INFO("controller id %u", index); return(index); @@ -2463,10 +2465,26 @@ void ctrlm_obj_network_ble_t::controllers_load() { XLOGD_WARN("deleting legacy IR controller object"); add_controller->db_destroy(); delete add_controller; - } else { - XLOGD_INFO("adding BLE controller with ID = 0x%X", id); - controllers_[id] = add_controller; + continue; } + if (!is_managed_by_network(id)) { + ctrlm_controller_id_t new_id = controller_id_assign(); + + add_controller->db_destroy(); // safely can destroy the old entry since it was loaded earlier + + if (new_id == 0) { + XLOGD_ERROR("Unable to assign a new ID - deleting controller <%d>", id); + delete add_controller; + continue; + } + + add_controller->update_controller_id_and_db_entry(db_name_get(), network_id_get(), new_id); + add_controller->db_create(); // create the new entry with its new ID + XLOGD_WARN("Legacy BLE RCU controller id <%d> found - updating controller id to <%d>", id, new_id); + id = new_id; + } + XLOGD_INFO("adding BLE controller with ID = 0x%X", id); + controllers_[id] = add_controller; } } @@ -2655,3 +2673,7 @@ void ctrlm_obj_network_ble_t::start_controller_audio_streaming(ctrlm_voice_start params->m_fd = fd; params->m_started = true; } + +bool ctrlm_obj_network_ble_t::is_managed_by_network(ctrlm_controller_id_t id) { + return (id >= BLE_RCU_ID_RANGE_MIN && id < BLE_RCU_ID_RANGE_MAX); +} diff --git a/src/ble/ctrlm_ble_network.h b/src/ble/ctrlm_ble_network.h index 787bb8b8..1182889a 100644 --- a/src/ble/ctrlm_ble_network.h +++ b/src/ble/ctrlm_ble_network.h @@ -41,6 +41,8 @@ // End Includes +#define BLE_RCU_ID_RANGE_MIN (NETWORK_ID_BASE_BLE) +#define BLE_RCU_ID_RANGE_MAX ((BLE_RCU_ID_RANGE_MIN)+BLE_MAX_MANAGED_RCUS+1) // +1 as a buffer for pairing typedef struct { ctrlm_main_queue_msg_header_t header; @@ -194,6 +196,9 @@ class ctrlm_obj_network_ble_t : public ctrlm_obj_network_t { virtual void start_controller_audio_streaming(ctrlm_voice_start_audio_params_t *params); +protected: + virtual bool is_managed_by_network(ctrlm_controller_id_t id); + private: ctrlm_obj_network_ble_t(); diff --git a/src/ble/hal/blercu/blercucontroller.cpp b/src/ble/hal/blercu/blercucontroller.cpp index 6ebfc14f..eb1b39ac 100644 --- a/src/ble/hal/blercu/blercucontroller.cpp +++ b/src/ble/hal/blercu/blercucontroller.cpp @@ -65,7 +65,7 @@ BleRcuControllerImpl::BleRcuControllerImpl(const shared_ptr +#define BLE_MAX_MANAGED_RCUS (1) + class ConfigSettings; class BleRcuAdapter; class BleRcuDevice; - - class BleRcuControllerImpl final : public BleRcuController { public: diff --git a/src/ctrlm_controller.cpp b/src/ctrlm_controller.cpp index aaae3b40..0d8b2154 100644 --- a/src/ctrlm_controller.cpp +++ b/src/ctrlm_controller.cpp @@ -410,3 +410,20 @@ uint8_t ctrlm_obj_controller_t::get_upgrade_increment() const { bool ctrlm_obj_controller_t::is_upgrade_progress_at_increment() const { return ((upgrade_progress_ % upgrade_increment_ == 0) || (upgrade_progress_ == 100)); } + +void ctrlm_obj_controller_t::update_controller_id_and_db_entry(std::string db_name, ctrlm_network_id_t network_id, ctrlm_controller_id_t new_id) { + controller_id_ = new_id; + std::stringstream new_controller_db_table; + new_controller_db_table << db_name << "_" << COUT_HEX_MODIFIER << (int)network_id << "_controller_" << COUT_HEX_MODIFIER << (int)new_id; + std::string new_table = new_controller_db_table.str(); + + ieee_address_->set_table(new_table); + time_binding_->set_table(new_table); + last_activity_time_->set_table(new_table); + last_key_time_->set_table(new_table); + last_key_code_->set_table(new_table); + irdb_entry_id_name_tv_->set_table(new_table); + irdb_entry_id_name_avr_->set_table(new_table); + voice_metrics_->set_table(new_table); + ota_failure_cnt_from_last_success_->set_table(new_table); +} diff --git a/src/ctrlm_controller.h b/src/ctrlm_controller.h index d31159fc..66749062 100644 --- a/src/ctrlm_controller.h +++ b/src/ctrlm_controller.h @@ -67,6 +67,7 @@ class ctrlm_obj_controller_t std::string stb_name_get() const; void set_device_minor_id(int device_minor_id); int get_device_minor_id() const; + void update_controller_id_and_db_entry(std::string db_name, ctrlm_network_id_t network_id, ctrlm_controller_id_t id); virtual ctrlm_controller_capabilities_t get_capabilities() const; diff --git a/src/ctrlm_main.cpp b/src/ctrlm_main.cpp index 1bffc6df..0794c861 100644 --- a/src/ctrlm_main.cpp +++ b/src/ctrlm_main.cpp @@ -113,11 +113,6 @@ using namespace std; #define CTRLM_MAIN_QUEUE_REPEAT_DELAY (5000) -#define NETWORK_ID_BASE_RF4CE 1 -#define NETWORK_ID_BASE_IP 11 -#define NETWORK_ID_BASE_BLE 21 -#define NETWORK_ID_BASE_CUSTOM 41 - #define CTRLM_MAIN_FIRST_BOOT_TIME_MAX (180) // maximum amount of uptime allowed (in seconds) for declaring "first boot" typedef void (*ctrlm_queue_push_t)(gpointer); diff --git a/src/ctrlm_network.cpp b/src/ctrlm_network.cpp index 69fa462b..e8f591c3 100644 --- a/src/ctrlm_network.cpp +++ b/src/ctrlm_network.cpp @@ -1079,3 +1079,8 @@ void ctrlm_obj_network_t::start_controller_audio_streaming(ctrlm_voice_start_aud XLOGD_WARN("not implemented for %s network", name_get()); return; } + +bool ctrlm_obj_network_t::is_managed_by_network(ctrlm_controller_id_t) { + XLOGD_WARN("not implemented for %s network", name_get()); + return false; +} diff --git a/src/ctrlm_network.h b/src/ctrlm_network.h index c39f3285..90ea909f 100644 --- a/src/ctrlm_network.h +++ b/src/ctrlm_network.h @@ -36,6 +36,11 @@ #define THREAD_ID_VALIDATE() thread_id_validate(__FUNCTION__) +#define NETWORK_ID_BASE_RF4CE 1 +#define NETWORK_ID_BASE_IP 11 +#define NETWORK_ID_BASE_BLE 21 +#define NETWORK_ID_BASE_CUSTOM 41 + typedef struct : public ctrlm_network_all_ipc_result_wrapper_t { unsigned char api_revision; unsigned int timeout; @@ -313,6 +318,7 @@ class ctrlm_obj_network_t const char * get_thread_name(const GThread *thread_id) const; void thread_id_validate(const char *pCallingFunction) const; virtual gboolean key_event_hook(ctrlm_network_id_t network_id, ctrlm_controller_id_t controller_id, ctrlm_key_status_t key_status, ctrlm_key_code_t key_code); + virtual bool is_managed_by_network(ctrlm_controller_id_t id); private: gboolean mask_key_codes_ = true; diff --git a/src/ipc/ctrlm_rcp_ipc_event.cpp b/src/ipc/ctrlm_rcp_ipc_event.cpp index 0ce44bae..510be650 100644 --- a/src/ipc/ctrlm_rcp_ipc_event.cpp +++ b/src/ipc/ctrlm_rcp_ipc_event.cpp @@ -135,6 +135,23 @@ void ctrlm_rcp_ipc_net_status_t::populate_status(const ctrlm_obj_network_t &netw } } +ctrlm_ir_state_t ctrlm_rcp_ipc_net_status_t::get_ir_prog_state(void) +{ + return irdb_state_; +} + +ctrlm_rf_pair_state_t ctrlm_rcp_ipc_net_status_t::get_rf_pair_state(void) +{ + return pair_state_; +} + +void ctrlm_rcp_ipc_net_status_t::get_controller_status_list(std::vector &list) +{ + for (const auto &status : controller_status_list_) { + list.push_back(status); + } +} + char *ctrlm_rcp_ipc_net_status_t::to_string() const { return json_dumps(to_json(), JSON_ENCODE_ANY); diff --git a/src/ipc/ctrlm_rcp_ipc_event.h b/src/ipc/ctrlm_rcp_ipc_event.h index ae257af6..e2c36e7c 100644 --- a/src/ipc/ctrlm_rcp_ipc_event.h +++ b/src/ipc/ctrlm_rcp_ipc_event.h @@ -111,13 +111,18 @@ class ctrlm_rcp_ipc_net_status_t : public ctrlm_virtual_json_t virtual json_t *to_json() const; - char *to_string() const; - uint8_t get_api_revision() const { return api_revision_; } - bool get_result() const { return (result_ == CTRLM_IARM_CALL_RESULT_SUCCESS) ? true : false; } - void set_result(ctrlm_iarm_call_result_t result) { result_ = result; } - ctrlm_network_id_t get_net_id() const { return net_id_; } - void set_net_id(ctrlm_network_id_t net_id) { net_id_ = net_id; } - void populate_status(const ctrlm_obj_network_t &network); + char *to_string() const; + uint8_t get_api_revision() const { return api_revision_; } + bool get_result() const { return (result_ == CTRLM_IARM_CALL_RESULT_SUCCESS) ? true : false; } + void set_result(ctrlm_iarm_call_result_t result) { result_ = result; } + ctrlm_network_id_t get_net_id() const { return net_id_; } + void set_net_id(ctrlm_network_id_t net_id) { net_id_ = net_id; } + ctrlm_network_type_t get_type() const { return net_type_; } + + void populate_status(const ctrlm_obj_network_t &network); + ctrlm_ir_state_t get_ir_prog_state(void); + ctrlm_rf_pair_state_t get_rf_pair_state(void); + void get_controller_status_list(std::vector &list); private: uint8_t api_revision_ = 0; @@ -197,11 +202,11 @@ class ctrlm_network_all_ipc_result_wrapper_t { return (result_map_[network_id_] == CTRLM_IARM_CALL_RESULT_SUCCESS); } else { for (const auto &it : result_map_) { - if (it.second != CTRLM_IARM_CALL_RESULT_SUCCESS) { - return false; + if (it.second == CTRLM_IARM_CALL_RESULT_SUCCESS) { + return true; } } - return true; + return false; } } }; diff --git a/src/ipc/ctrlm_rcp_ipc_iarm_thunder.cpp b/src/ipc/ctrlm_rcp_ipc_iarm_thunder.cpp index 88d2a38f..5ed63e70 100644 --- a/src/ipc/ctrlm_rcp_ipc_iarm_thunder.cpp +++ b/src/ipc/ctrlm_rcp_ipc_iarm_thunder.cpp @@ -397,32 +397,55 @@ IARM_Result_t ctrlm_rcp_ipc_iarm_thunder_t::get_net_status(void *arg) return(IARM_RESULT_INVALID_PARAM); } - int net_type = CTRLM_NETWORK_TYPE_INVALID; - if (!config.config_value_get(NET_TYPE, net_type)) { - XLOGD_INFO("Missing %s parameter - defaulting to all networks", NET_TYPE); - } std::shared_ptr> params = std::make_shared>(); - params->set_net_id((net_type == CTRLM_NETWORK_TYPE_INVALID) ? CTRLM_MAIN_NETWORK_ID_ALL : ctrlm_network_id_get(static_cast(net_type))); + params->set_net_id(CTRLM_MAIN_NETWORK_ID_ALL); sync_send_netw_handler_to_main_queue_new, ctrlm_main_queue_msg_get_rcu_status_t> (params, (ctrlm_msg_handler_network_t)&ctrlm_obj_network_t::req_process_get_rcu_status); - json_t *ret = json_object(); - json_t *status_array = json_array(); + json_t *ret = json_object(); + json_t *status = json_object(); + json_t *net_type_supported = json_array(); + json_t *remote_array = json_array(); + std::map status_map = params->get_reply(); + std::vector remotes; + + ctrlm_network_type_t type = CTRLM_NETWORK_TYPE_INVALID; + ctrlm_ir_state_t ir_prog_state = CTRLM_IR_STATE_UNKNOWN; + ctrlm_rf_pair_state_t rf_pair_state = CTRLM_RF_PAIR_STATE_UNKNOWN; int err = 0; - if (params->get_net_id() != CTRLM_MAIN_NETWORK_ID_ALL) { - err |= json_object_set_new_nocheck(ret, STATUS, status_map[params->get_net_id()].to_json()); - } else { - for (const auto &it : status_map) { - err |= json_array_append_new(status_array, it.second.to_json()); + for (auto const &it : ctrlm_network_types_get()) { + err |= json_array_append_new(net_type_supported, json_integer(it)); + } + for (auto &it : status_map) { + it.second.get_controller_status_list(remotes); + } + for (const auto &remote : remotes) { + err |= json_array_append_new(remote_array, remote.to_json()); + } + // For now default to RF4CE network reporting if available + for (auto &it : status_map) { + ir_prog_state = it.second.get_ir_prog_state(); + rf_pair_state = it.second.get_rf_pair_state(); + type = it.second.get_type(); + + if (type == CTRLM_NETWORK_TYPE_RF4CE) { + break; } - err |= json_object_set_new_nocheck(ret, STATUS, status_array); } + + err |= json_object_set_new_nocheck(status, REMOTE_DATA, remote_array); + err |= json_object_set_new_nocheck(status, NET_TYPES_SUPPORTED, net_type_supported); + err |= json_object_set_new_nocheck(status, NET_TYPE, json_integer(type)); + err |= json_object_set_new_nocheck(status, IR_PROG_STATE, json_string(ctrlm_ir_state_str(ir_prog_state))); + err |= json_object_set_new_nocheck(status, PAIRING_STATE, json_string(ctrlm_rf_pair_state_str(rf_pair_state))); + + err |= json_object_set_new_nocheck(ret, STATUS, status); err |= json_object_set_new_nocheck(ret, SUCCESS, json_boolean(params->get_result())); if (err) { @@ -463,13 +486,8 @@ IARM_Result_t ctrlm_rcp_ipc_iarm_thunder_t::get_last_keypress(void *arg) return(IARM_RESULT_INVALID_PARAM); } - int net_type = CTRLM_NETWORK_TYPE_INVALID; - if (!config.config_value_get(NET_TYPE, net_type)) { - XLOGD_INFO("Missing %s parameter - defaulting to all networks", NET_TYPE); - } - std::shared_ptr> params = std::make_shared>(); - params->set_net_id((net_type == CTRLM_NETWORK_TYPE_INVALID) ? CTRLM_MAIN_NETWORK_ID_ALL : ctrlm_network_id_get(static_cast(net_type))); + params->set_net_id(CTRLM_MAIN_NETWORK_ID_ALL); sync_send_netw_handler_to_main_queue_new, ctrlm_main_queue_msg_get_last_keypress_t> @@ -484,18 +502,13 @@ IARM_Result_t ctrlm_rcp_ipc_iarm_thunder_t::get_last_keypress(void *arg) ctrlm_network_id_t net_id_index = 0; int err = 0; - if (params->get_net_id() != CTRLM_MAIN_NETWORK_ID_ALL) { - itr = key_info_map.find(params->get_net_id()); - key_info = itr->second; - } else { - for (itr = key_info_map.begin(); itr != key_info_map.end(); itr++) { - if (itr->second.timestamp > time_last_key) { - time_last_key = itr->second.timestamp; - net_id_index = itr->first; - } + for (itr = key_info_map.begin(); itr != key_info_map.end(); itr++) { + if (itr->second.timestamp > time_last_key) { + time_last_key = itr->second.timestamp; + net_id_index = itr->first; } - key_info = key_info_map[net_id_index]; } + key_info = key_info_map[net_id_index]; err |= json_object_set_new_nocheck(ret, CONTROLLER_ID, json_integer(key_info.controller_id)); err |= json_object_set_new_nocheck(ret, TIMESTAMP, json_integer(key_info.timestamp)); @@ -544,11 +557,6 @@ IARM_Result_t ctrlm_rcp_ipc_iarm_thunder_t::find_my_remote(void *arg) return(IARM_RESULT_INVALID_PARAM); } - int net_type = CTRLM_NETWORK_TYPE_INVALID; - if(!config.config_value_get(NET_TYPE, net_type)) { - XLOGD_INFO("Missing %s parameter - defaulting to all networks", NET_TYPE); - } - std::string level; if(!config.config_value_get(LEVEL, level)) { XLOGD_ERROR("Missing %s parameter", LEVEL); @@ -556,7 +564,7 @@ IARM_Result_t ctrlm_rcp_ipc_iarm_thunder_t::find_my_remote(void *arg) } std::shared_ptr params = std::make_shared(); - params->set_net_id((net_type == CTRLM_NETWORK_TYPE_INVALID) ? CTRLM_MAIN_NETWORK_ID_ALL : ctrlm_network_id_get(static_cast(net_type))); + params->set_net_id(CTRLM_MAIN_NETWORK_ID_ALL); params->level = ctrlm_utils_str_to_fmr_level(level); params->duration = 0; @@ -645,10 +653,6 @@ IARM_Result_t ctrlm_rcp_ipc_iarm_thunder_t::write_rcu_wakeup_config(void *arg) return(IARM_RESULT_INVALID_PARAM); } - int net_type = CTRLM_NETWORK_TYPE_INVALID; - if(!config.config_value_get(NET_TYPE, net_type)) { - XLOGD_INFO("Missing %s parameter - defaulting to all networks", NET_TYPE); - } std::string wakeup_config; if(!config.config_value_get(WAKEUP_CONFIG, wakeup_config)) { @@ -665,7 +669,7 @@ IARM_Result_t ctrlm_rcp_ipc_iarm_thunder_t::write_rcu_wakeup_config(void *arg) } ctrlm_iarm_call_WriteRcuWakeupConfig_params_t params = {}; - params.network_id = (net_type == CTRLM_NETWORK_TYPE_INVALID) ? CTRLM_MAIN_NETWORK_ID_ALL : ctrlm_network_id_get(static_cast(net_type)); + params.network_id = CTRLM_MAIN_NETWORK_ID_ALL; params.config = ctrlm_utils_str_to_wakeup_config(wakeup_config); params.customListSize = ctrlm_utils_custom_key_str_to_array(custom_keys, params.customList); diff --git a/src/irdb/ctrlm_irdb_interface.cpp b/src/irdb/ctrlm_irdb_interface.cpp index 1bc55ffd..18a02e57 100644 --- a/src/irdb/ctrlm_irdb_interface.cpp +++ b/src/irdb/ctrlm_irdb_interface.cpp @@ -41,6 +41,7 @@ #include #include +#include using namespace std; @@ -543,17 +544,34 @@ bool ctrlm_irdb_interface_t::program_ir_codes(ctrlm_network_id_t network_id, ctr bool ctrlm_irdb_interface_t::_program_ir_codes(ctrlm_network_id_t network_id, ctrlm_controller_id_t controller_id, ctrlm_irdb_ir_code_set_t *ir_codes) { bool ret = false; + vector success_vec; - ctrlm_main_queue_msg_program_ir_codes_t msg = {0}; - msg.network_id = network_id; - msg.controller_id = controller_id; - msg.ir_codes = ir_codes; - msg.success = &ret; + std::shared_ptr msg = std::make_shared(); + msg->network_id = network_id; + msg->controller_id = controller_id; + msg->ir_codes = ir_codes; + msg->success = &success_vec; - if (false == get_vendor_info(msg.vendor_info)) { - msg.vendor_info.rcu_support_bitmask = 0; + if (false == get_vendor_info(msg->vendor_info)) { + msg->vendor_info.rcu_support_bitmask = 0; + } + ctrlm_main_queue_handler_push_new + (CTRLM_HANDLER_NETWORK, + (ctrlm_msg_handler_network_t)&ctrlm_obj_network_t::req_process_program_ir_codes, + std::move(msg), + NULL, + network_id, + true); + + for (char success : success_vec) { + if (success) { + ret = true; + break; + } else { + ret = false; + } } - ctrlm_main_queue_handler_push(CTRLM_HANDLER_NETWORK, (ctrlm_msg_handler_network_t)&ctrlm_obj_network_t::req_process_program_ir_codes, &msg, sizeof(msg), NULL, network_id, true); return(ret); } @@ -566,14 +584,30 @@ bool ctrlm_irdb_interface_t::clear_ir_codes(ctrlm_network_id_t network_id, ctrlm bool ctrlm_irdb_interface_t::_clear_ir_codes(ctrlm_network_id_t network_id, ctrlm_controller_id_t controller_id) { bool ret = false; - - ctrlm_main_queue_msg_ir_clear_t msg = {0}; - - msg.network_id = network_id; - msg.controller_id = controller_id; - msg.success = &ret; - - ctrlm_main_queue_handler_push(CTRLM_HANDLER_NETWORK, (ctrlm_msg_handler_network_t)&ctrlm_obj_network_t::req_process_ir_clear_codes, &msg, sizeof(msg), NULL, network_id, true); - + vector success_vec; + + std::shared_ptr msg = std::make_shared(); + + msg->network_id = network_id; + msg->controller_id = controller_id; + msg->success = &success_vec; + + ctrlm_main_queue_handler_push_new + (CTRLM_HANDLER_NETWORK, + (ctrlm_msg_handler_network_t)&ctrlm_obj_network_t::req_process_ir_clear_codes, + std::move(msg), + NULL, + network_id, + true); + + for (char success : success_vec) { + if (success) { + ret = true; + break; + } else { + ret = false; + } + } return(ret); } diff --git a/src/irdb/ctrlm_irdb_interface.h b/src/irdb/ctrlm_irdb_interface.h index 9e7da14e..76669356 100644 --- a/src/irdb/ctrlm_irdb_interface.h +++ b/src/irdb/ctrlm_irdb_interface.h @@ -31,7 +31,6 @@ #include "ctrlm_hal.h" #include "ctrlm_irdb_plugin.h" - inline bool operator==(const ctrlm_irdb_autolookup_entry_ranked_t& lhs, const ctrlm_irdb_autolookup_entry_ranked_t& rhs) { return (lhs.id.compare(rhs.id) == 0); } @@ -42,7 +41,7 @@ typedef struct { ctrlm_network_id_t network_id; ctrlm_controller_id_t controller_id; ctrlm_irdb_ir_code_set_t * ir_codes; - bool * success; + std::vector * success; sem_t * semaphore; ctrlm_irdb_vendor_info_t vendor_info; } ctrlm_main_queue_msg_program_ir_codes_t; @@ -50,7 +49,7 @@ typedef struct { typedef struct { ctrlm_network_id_t network_id; ctrlm_controller_id_t controller_id; - bool * success; + std::vector * success; sem_t * semaphore; } ctrlm_main_queue_msg_ir_clear_t; diff --git a/src/irdb/ipc/ctrlm_irdb_ipc_iarm_thunder.cpp b/src/irdb/ipc/ctrlm_irdb_ipc_iarm_thunder.cpp index 84351718..48b7c29a 100644 --- a/src/irdb/ipc/ctrlm_irdb_ipc_iarm_thunder.cpp +++ b/src/irdb/ipc/ctrlm_irdb_ipc_iarm_thunder.cpp @@ -390,7 +390,6 @@ IARM_Result_t ctrlm_irdb_ipc_iarm_thunder_t::program_ir_codes(void *arg) { bool success = false; ctrlm_irdb_dev_type_t dev_type = CTRLM_IRDB_DEV_TYPE_INVALID; ctrlm_ir_device_type_t ir_dev_type = CTRLM_IR_DEVICE_UNKNOWN; - int network_type_val = CTRLM_NETWORK_TYPE_INVALID; int remote_id = 0; std::string av_dev_str, code; json_config conf; @@ -406,10 +405,6 @@ IARM_Result_t ctrlm_irdb_ipc_iarm_thunder_t::program_ir_codes(void *arg) { return(IARM_RESULT_INVALID_PARAM); } - if(!conf.config_value_get(NET_TYPE, network_type_val)) { - XLOGD_INFO("Missing %s parameter - defaulting to all networks", NET_TYPE); - } - if(!conf.config_value_get(AV_DEV_TYPE, av_dev_str)) { XLOGD_ERROR("Missing %s parameter", AV_DEV_TYPE); return(IARM_RESULT_INVALID_PARAM); @@ -425,9 +420,7 @@ IARM_Result_t ctrlm_irdb_ipc_iarm_thunder_t::program_ir_codes(void *arg) { return(IARM_RESULT_INVALID_PARAM); } - ctrlm_network_id_t network_id = (network_type_val == CTRLM_NETWORK_TYPE_INVALID) ? - CTRLM_MAIN_NETWORK_ID_ALL : - ctrlm_network_id_get(static_cast(network_type_val)); + ctrlm_network_id_t network_id = CTRLM_MAIN_NETWORK_ID_ALL; ctrlm_controller_id_t controller_id = static_cast(remote_id); if(!ctrlm_irdb_dev_type_is_valid(av_dev_str, ir_dev_type)) { @@ -460,7 +453,6 @@ IARM_Result_t ctrlm_irdb_ipc_iarm_thunder_t::clear_ir_codes(void *arg) { json_t *payload = NULL; ctrlm_irdb_interface_t *irdb = ctrlm_main_irdb_get(); bool success = false; - int network_type_val = CTRLM_NETWORK_TYPE_INVALID; int remote_id = 0; json_config conf; @@ -475,18 +467,12 @@ IARM_Result_t ctrlm_irdb_ipc_iarm_thunder_t::clear_ir_codes(void *arg) { return(IARM_RESULT_INVALID_PARAM); } - if(!conf.config_value_get(NET_TYPE, network_type_val)) { - XLOGD_INFO("Missing %s parameter - defaulting to all networks", NET_TYPE); - } - if(!conf.config_value_get(REMOTE_ID, remote_id)){ XLOGD_ERROR("Missing %s parameter", REMOTE_ID); return(IARM_RESULT_INVALID_PARAM); } - ctrlm_network_id_t network_id = (network_type_val == CTRLM_NETWORK_TYPE_INVALID) ? - CTRLM_MAIN_NETWORK_ID_ALL : - ctrlm_network_id_get(static_cast(network_type_val)); + ctrlm_network_id_t network_id = CTRLM_MAIN_NETWORK_ID_ALL; ctrlm_controller_id_t controller_id = static_cast(remote_id); if(irdb) { diff --git a/src/rf4ce/ctrlm_rf4ce_network.cpp b/src/rf4ce/ctrlm_rf4ce_network.cpp index 5fea2cd3..de3adb73 100644 --- a/src/rf4ce/ctrlm_rf4ce_network.cpp +++ b/src/rf4ce/ctrlm_rf4ce_network.cpp @@ -1179,7 +1179,7 @@ void ctrlm_obj_network_rf4ce_t::controllers_load() { ctrlm_controller_id_t ctrlm_obj_network_rf4ce_t::controller_id_assign(void) { // Get the next available controller id - for(ctrlm_controller_id_t index = 1; index < 255; index++) { + for(ctrlm_controller_id_t index = RF4CE_RCU_ID_RANGE_MIN; index < RF4CE_RCU_ID_RANGE_MAX; index++) { if(!controller_exists(index)) { XLOGD_INFO("controller id %u", index); return(index); @@ -4393,7 +4393,11 @@ void ctrlm_obj_network_rf4ce_t::req_process_program_ir_codes(void *data, int siz g_assert(dqm); g_assert(size == sizeof(ctrlm_main_queue_msg_program_ir_codes_t)); - if(controller_exists(dqm->controller_id)) { + bool success = false; + + if(!is_managed_by_network(dqm->controller_id)) { + XLOGD_ERROR("controller %d is not managed by the %s network", dqm->controller_id, name_get()); + } else if(controller_exists(dqm->controller_id)) { if(dqm->ir_codes) { XLOGD_INFO("Setting IR Codes on Controller %u", dqm->controller_id); unsigned char status[1] = {IR_RF_DATABASE_STATUS_DB_DOWNLOAD_YES | IR_RF_DATABASE_STATUS_FORCE_DOWNLOAD}; @@ -4403,16 +4407,15 @@ void ctrlm_obj_network_rf4ce_t::req_process_program_ir_codes(void *data, int siz controllers_[dqm->controller_id]->irdb_entry_id_name_set(CTRLM_IRDB_DEV_TYPE_TV, ir_rf_database_.get_tv_ir_code_id()); controllers_[dqm->controller_id]->irdb_entry_id_name_set(CTRLM_IRDB_DEV_TYPE_AVR, ir_rf_database_.get_avr_ir_code_id()); this->ir_rf_database_.store_db(); - if(dqm->success) *dqm->success = true; + success = true; } else { XLOGD_ERROR("Invalid IR Codes"); - if(dqm->success) *dqm->success = false; } } else { XLOGD_ERROR("Controller %u doesn't exist", dqm->controller_id); - if(dqm->success) *dqm->success = false; } + if(dqm->success) dqm->success->push_back(success); // post the semaphore if(dqm->semaphore) { sem_post(dqm->semaphore); @@ -4424,7 +4427,11 @@ void ctrlm_obj_network_rf4ce_t::req_process_ir_clear_codes(void *data, int size) g_assert(dqm); g_assert(size == sizeof(ctrlm_main_queue_msg_ir_clear_t)); - if(controller_exists(dqm->controller_id)) { + bool success = false; + + if(!is_managed_by_network(dqm->controller_id)) { + XLOGD_ERROR("controller %d is not managed by the %s network", dqm->controller_id, name_get()); + } else if(controller_exists(dqm->controller_id)) { XLOGD_INFO("Clearing IR Codes on Controller %u", dqm->controller_id); unsigned char status[1] = {IR_RF_DATABASE_STATUS_DB_DOWNLOAD_YES | IR_RF_DATABASE_STATUS_FORCE_DOWNLOAD}; this->ir_rf_database_.clear_ir_codes(); @@ -4433,12 +4440,12 @@ void ctrlm_obj_network_rf4ce_t::req_process_ir_clear_codes(void *data, int size) controllers_[dqm->controller_id]->irdb_entry_id_name_set(CTRLM_IRDB_DEV_TYPE_TV, "0"); controllers_[dqm->controller_id]->irdb_entry_id_name_set(CTRLM_IRDB_DEV_TYPE_AVR, "0"); controllers_[dqm->controller_id]->rf4ce_rib_set_target(CTRLM_RF4CE_RIB_ATTR_ID_IR_RF_DATABASE_STATUS, CTRLM_RF4CE_RIB_ATTR_INDEX_GENERAL, CTRLM_RF4CE_RIB_ATTR_LEN_IR_RF_DATABASE_STATUS, status); - if(dqm->success) *dqm->success = true; + success = true; } else { XLOGD_ERROR("Controller %u doesn't exist", dqm->controller_id); - if(dqm->success) *dqm->success = false; } + if(dqm->success) dqm->success->push_back(success); // post the semaphore if(dqm->semaphore) { sem_post(dqm->semaphore); @@ -5131,3 +5138,7 @@ void ctrlm_obj_network_rf4ce_t::start_controller_audio_streaming(ctrlm_voice_sta params->m_started = true; } + +bool ctrlm_obj_network_rf4ce_t::is_managed_by_network(ctrlm_controller_id_t id) { + return (id >= RF4CE_RCU_ID_RANGE_MIN && id < RF4CE_RCU_ID_RANGE_MAX); +} diff --git a/src/rf4ce/ctrlm_rf4ce_network.h b/src/rf4ce/ctrlm_rf4ce_network.h index 07298971..10cc771a 100644 --- a/src/rf4ce/ctrlm_rf4ce_network.h +++ b/src/rf4ce/ctrlm_rf4ce_network.h @@ -67,6 +67,9 @@ #define IR_RF_DATABASE_STATUS_DB_DOWNLOAD_YES (0x80) #define IR_RF_DATABASE_STATUS_RESERVED (0x20) +#define RF4CE_RCU_ID_RANGE_MIN (NETWORK_ID_BASE_RF4CE) +#define RF4CE_RCU_ID_RANGE_MAX (RF4CE_RCU_ID_RANGE_MIN + CTRLM_MAIN_MAX_BOUND_CONTROLLERS) + typedef enum { CTRLM_RF4CE_DEVICE_TYPE_STB = 0x09, CTRLM_RF4CE_DEVICE_TYPE_AUTOBIND = 0xD0, @@ -466,6 +469,7 @@ class ctrlm_obj_network_rf4ce_t : public ctrlm_obj_network_t protected: virtual gboolean key_event_hook(ctrlm_network_id_t network_id, ctrlm_controller_id_t controller_id, ctrlm_key_status_t key_status, ctrlm_key_code_t key_code); + virtual bool is_managed_by_network(ctrlm_controller_id_t id); private: ctrlm_hal_rf4ce_network_main_t hal_api_main_; From fc1c94a8e2de9b196a5f274316eaee5c07c2fbf5 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Tue, 13 Jan 2026 11:01:35 -0500 Subject: [PATCH 22/81] RDKEMW-10631: Filter out unpaired devices when reconnecting all devices --- src/ble/hal/blercu/bluez/blercuadapter.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/ble/hal/blercu/bluez/blercuadapter.cpp b/src/ble/hal/blercu/bluez/blercuadapter.cpp index c7d5834e..56949f40 100644 --- a/src/ble/hal/blercu/bluez/blercuadapter.cpp +++ b/src/ble/hal/blercu/bluez/blercuadapter.cpp @@ -1257,14 +1257,22 @@ bool BleRcuAdapterBluez::addDevice(const BleAddress &address) /*! \internal - Sends a request to bluez to reconnect all devices stored in our internal map + Sends a request to bluez to reconnect all devices stored in our internal map if paired */ void BleRcuAdapterBluez::reconnectAllDevices() { for (auto const &device : m_devices) { - XLOGD_INFO("reconnecting to %s", device.first.toString().c_str()); - device.second->connect(); + bool isPaired = false; + if (device.second->m_deviceProxy) { + device.second->m_deviceProxy->paired(isPaired); + } + if (isPaired) { + XLOGD_INFO("reconnecting to %s", device.first.toString().c_str()); + device.second->connect(); + } else { + XLOGD_INFO("not paired, skipping reconnecting to %s", device.first.toString().c_str()); + } } } From 084f51900da55542dde54d670738ed8f52263ff3 Mon Sep 17 00:00:00 2001 From: Kelvin Lu <119349872+klu339@users.noreply.github.com> Date: Tue, 13 Jan 2026 14:43:53 -0500 Subject: [PATCH 23/81] RDKEMW-12512: ctrlm release v1.1.9 (#169) --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18d43be6..2548677a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,13 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +> 13 January 2026 + +#### [1.1.9](https://github.com/rdkcentral/control/compare/1.1.8...1.1.9) + +- RDKEMW-11471: Remove netType param [`#164`](https://github.com/rdkcentral/control/pull/164) +- RDKEMW-10631: Filter out unpaired devices when reconnecting all devices [`fc1c94a`](https://github.com/rdkcentral/control/commit/fc1c94a8e2de9b196a5f274316eaee5c07c2fbf5) + #### [1.1.8](https://github.com/rdkcentral/control/compare/1.1.7...1.1.8) > 5 January 2026 From 932b09e4933a8ceb9d2d22edde48aa43aa51143d Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Wed, 21 Jan 2026 09:51:18 -0500 Subject: [PATCH 24/81] RDKEMW-9843: report loaded and unloaded voltage from RCU (#163) --- .../bleservices/blercuremotecontrolservice.h | 5 + .../gatt/gatt_remotecontrolservice.cpp | 109 ++++++++++++++++++ .../gatt/gatt_remotecontrolservice.h | 8 ++ src/ble/hal/utils/bleuuid.cpp | 1 + src/ble/hal/utils/bleuuid.h | 1 + 5 files changed, 124 insertions(+) diff --git a/src/ble/hal/blercu/bleservices/blercuremotecontrolservice.h b/src/ble/hal/blercu/bleservices/blercuremotecontrolservice.h index 63752f73..653fd872 100644 --- a/src/ble/hal/blercu/bleservices/blercuremotecontrolservice.h +++ b/src/ble/hal/blercu/bleservices/blercuremotecontrolservice.h @@ -64,6 +64,10 @@ class BleRcuRemoteControlService { m_lastKeypressChangedSlots.addSlot(func); } + inline void addRawBatteryVoltageChangedSlot(const Slot &> &func) + { + m_rawBatteryVoltageChangedSlots.addSlot(func); + } inline void addAdvConfigChangedSlot(const Slot &func) { m_advConfigChangedSlots.addSlot(func); @@ -77,6 +81,7 @@ class BleRcuRemoteControlService Slots m_unpairReasonChangedSlots; Slots m_rebootReasonChangedSlots; Slots m_lastKeypressChangedSlots; + Slots &> m_rawBatteryVoltageChangedSlots; Slots m_advConfigChangedSlots; Slots &> m_advConfigCustomListChangedSlots; }; diff --git a/src/ble/hal/blercu/bleservices/gatt/gatt_remotecontrolservice.cpp b/src/ble/hal/blercu/bleservices/gatt/gatt_remotecontrolservice.cpp index 74d36e3e..a6c89198 100644 --- a/src/ble/hal/blercu/bleservices/gatt/gatt_remotecontrolservice.cpp +++ b/src/ble/hal/blercu/bleservices/gatt/gatt_remotecontrolservice.cpp @@ -47,6 +47,7 @@ const BleUuid GattRemoteControlService::m_lastKeypressCharUuid(BleUuid::LastKeyp const BleUuid GattRemoteControlService::m_advConfigCharUuid(BleUuid::AdvertisingConfig); const BleUuid GattRemoteControlService::m_advConfigCustomListCharUuid(BleUuid::AdvertisingConfigCustomList); const BleUuid GattRemoteControlService::m_assertReportCharUuid(BleUuid::AssertReport); +const BleUuid GattRemoteControlService::m_rawBatteryVoltageCharUuid(BleUuid::RawBatteryVoltage); using namespace std; @@ -182,6 +183,12 @@ bool GattRemoteControlService::start(const shared_ptr &gat XLOGD_WARN("failed to get optional Assert Reporting characteristic, continuing anyway..."); } } + if (!m_rawBatteryVoltageCharacteristic || !m_rawBatteryVoltageCharacteristic->isValid()) { + m_rawBatteryVoltageCharacteristic = gattService->characteristic(m_rawBatteryVoltageCharUuid); + if (!m_rawBatteryVoltageCharacteristic || !m_rawBatteryVoltageCharacteristic->isValid()) { + XLOGD_WARN("failed to get Raw Battery Voltage characteristic, continuing anyway..."); + } + } // check we're not already started if (m_stateMachine.state() != IdleState) { @@ -228,6 +235,7 @@ void GattRemoteControlService::onEnteredState(int state) m_rebootReasonCharacteristic.reset(); m_rcuActionCharacteristic.reset(); m_assertReportCharacteristic.reset(); + m_rawBatteryVoltageCharacteristic.reset(); } else if (state == RetrieveInitialValuesState) { @@ -237,12 +245,14 @@ void GattRemoteControlService::onEnteredState(int state) requestAdvConfigCustomList(); requestUnpairReason(); requestRebootReason(); + requestRawBatteryVoltage(); m_readySlots.invoke(); } else if (state == EnableNotificationsState) { requestStartUnpairNotify(); requestStartRebootNotify(); + requestRawBatteryVoltageChangedNotify(); } } @@ -303,6 +313,35 @@ void GattRemoteControlService::requestStartRebootNotify() PendingReply<>(m_isAlive, replyHandler)); } +void GattRemoteControlService::requestRawBatteryVoltageChangedNotify() +{ + if (!m_rawBatteryVoltageCharacteristic || !m_rawBatteryVoltageCharacteristic->isValid()) { + XLOGD_WARN("Invalid raw battery voltage characteristic, skipping notification setup"); + return; + } + + auto replyHandler = [this](PendingReply<> *reply) + { + // check for errors + if (reply->isError()) { + // this is bad if this happens as we won't get updates, so we install a timer to + // retry enabling notifications in a couple of seconds time + XLOGD_ERROR("failed to enable raw battery voltage characteristic notifications due to <%s>", + reply->errorMessage().c_str()); + + m_stateMachine.cancelDelayedEvents(RetryStartNotifyEvent); + m_stateMachine.postDelayedEvent(RetryStartNotifyEvent, 2000); + } else { + XLOGD_INFO("request to start notifications on Raw Battery Voltage characteristic succeeded"); + } + }; + + m_rawBatteryVoltageCharacteristic->enableNotifications( + Slot &>(m_isAlive, + std::bind(&GattRemoteControlService::onRawBatteryVoltageChanged, this, std::placeholders::_1)), + PendingReply<>(m_isAlive, replyHandler)); +} + // ----------------------------------------------------------------------------- /*! Write RCU Action characteristic. @@ -525,6 +564,45 @@ void GattRemoteControlService::requestLastKeypress() } } +// ----------------------------------------------------------------------------- +/*! + \internal + + Sends a request to org.bluez.GattCharacteristic1.Value() to get the value + property of the characteristic which contains the raw battery voltage. + + */ +void GattRemoteControlService::requestRawBatteryVoltage() +{ + // lambda invoked when the request returns + auto replyHandler = [this](PendingReply> *reply) + { + // check for errors + if (reply->isError()) { + XLOGD_ERROR("Failed to read raw battery voltage due to <%s>", reply->errorMessage().c_str()); + } else { + std::vector value; + value = reply->result(); + + if (value.size() == 3) { + onRawBatteryVoltageChanged(value); + } else { + XLOGD_ERROR("Raw battery voltage received has invalid length (%d bytes)", value.size()); + } + } + }; + + + if (m_rawBatteryVoltageCharacteristic && m_rawBatteryVoltageCharacteristic->isValid()) { + + // send a request to the bluez daemon to read the characteristic + m_rawBatteryVoltageCharacteristic->readValue(PendingReply>(m_isAlive, replyHandler)); + + } else { + XLOGD_WARN("Raw battery voltage characteristic is not valid, check that the remote firmware version supports this feature."); + } +} + // ----------------------------------------------------------------------------- /*! \internal @@ -601,7 +679,38 @@ void GattRemoteControlService::requestAdvConfigCustomList() } } +// ----------------------------------------------------------------------------- +/*! + \internal + Internal slot called when a notification from the remote device is sent + due to raw battery voltage changing. + */ +void GattRemoteControlService::onRawBatteryVoltageChanged(const std::vector &newValue) { + m_unloadedVoltage = newValue[0]; + m_loadedVoltage = newValue[1]; + m_voltagePercentage = std::clamp(newValue[2], uint8_t(0), uint8_t(100)); // Clamp percentage between 0 - 100 + + // Formats an 8-bit unsigned integer as a voltage string. + // Upper 2 bits = whole voltage (0-3v), lower 6 bits = 1/64v increments. + // Example: 137 (0x89 = 0b10001001) + // - Upper 2 bits: 0b10 = 2v + // - Lower 6 bits: 0b001001 = 9 = 9/64 = 0.14v + // - Result: "2.14v" + auto formatVoltage = [](uint8_t value) -> std::string { + const uint8_t wholeVolts = (value >> 6) & 0x03; // Upper 2 bits + const uint8_t fractionalBits = value & 0x3F; // Lower 6 bits + const float totalVolts = wholeVolts + (fractionalBits / 64.0f); + + char buffer[16]; + snprintf(buffer, sizeof(buffer), "%.2fv", totalVolts); + return buffer; + }; + + XLOGD_TELEMETRY("Successfully read raw battery voltage characteristic, unloaded = %s, loaded = %s, loaded percentage = %u%%", + formatVoltage(m_unloadedVoltage).c_str(), formatVoltage(m_loadedVoltage).c_str(), (unsigned int)m_voltagePercentage); + m_rawBatteryVoltageChangedSlots.invoke(newValue); +} // ----------------------------------------------------------------------------- /*! diff --git a/src/ble/hal/blercu/bleservices/gatt/gatt_remotecontrolservice.h b/src/ble/hal/blercu/bleservices/gatt/gatt_remotecontrolservice.h index 07f3a511..02534640 100644 --- a/src/ble/hal/blercu/bleservices/gatt/gatt_remotecontrolservice.h +++ b/src/ble/hal/blercu/bleservices/gatt/gatt_remotecontrolservice.h @@ -92,13 +92,16 @@ class GattRemoteControlService : public BleRcuRemoteControlService private: void requestStartUnpairNotify(); void requestStartRebootNotify(); + void requestRawBatteryVoltageChangedNotify(); void requestUnpairReason(); void requestRebootReason(); void requestAssertReport(); void requestLastKeypress(); + void requestRawBatteryVoltage(); void requestAdvConfig(); void requestAdvConfigCustomList(); + void onRawBatteryVoltageChanged(const std::vector &newValue); void onWriteAdvConfigReply(PendingReply<> *reply); void onWriteAdvConfigCustomListReply(PendingReply<> *reply); @@ -112,6 +115,7 @@ class GattRemoteControlService : public BleRcuRemoteControlService std::shared_ptr m_advConfigCharacteristic; std::shared_ptr m_advConfigCustomListCharacteristic; std::shared_ptr m_assertReportCharacteristic; + std::shared_ptr m_rawBatteryVoltageCharacteristic; StateMachine m_stateMachine; @@ -119,6 +123,9 @@ class GattRemoteControlService : public BleRcuRemoteControlService uint8_t m_rebootReason; uint8_t m_rcuAction; uint8_t m_lastKeypress; + uint8_t m_unloadedVoltage; + uint8_t m_loadedVoltage; + uint8_t m_voltagePercentage; uint8_t m_advConfig; std::vector m_advConfigCustomList; @@ -135,6 +142,7 @@ class GattRemoteControlService : public BleRcuRemoteControlService static const BleUuid m_advConfigCharUuid; static const BleUuid m_advConfigCustomListCharUuid; static const BleUuid m_assertReportCharUuid; + static const BleUuid m_rawBatteryVoltageCharUuid; private: static const Event::Type StartServiceRequestEvent = Event::Type(Event::User + 1); diff --git a/src/ble/hal/utils/bleuuid.cpp b/src/ble/hal/utils/bleuuid.cpp index fd7b0636..62d4294c 100644 --- a/src/ble/hal/utils/bleuuid.cpp +++ b/src/ble/hal/utils/bleuuid.cpp @@ -74,6 +74,7 @@ bool ble_uuid_names_init(void) BleUuid(BleUuid::AdvertisingConfig, std::string("Advertising Config")); BleUuid(BleUuid::AdvertisingConfigCustomList, std::string("Advertising Config Custom List")); BleUuid(BleUuid::AssertReport, std::string("Assert Report")); + BleUuid(BleUuid::RawBatteryVoltage, std::string("Raw Battery Voltage")); BleUuid(BleUuid::InfraredSignalReference, std::string("Infrared Signal Reference")); BleUuid(BleUuid::InfraredSignalConfiguration, std::string("Infrared Signal Configuration")); BleUuid(BleUuid::FirmwarePacketWindowSize, std::string("Firmware Packet Window Size")); diff --git a/src/ble/hal/utils/bleuuid.h b/src/ble/hal/utils/bleuuid.h index 3552b8e8..7b9df4f2 100644 --- a/src/ble/hal/utils/bleuuid.h +++ b/src/ble/hal/utils/bleuuid.h @@ -104,6 +104,7 @@ class BleUuid AdvertisingConfig = 0xed05, AdvertisingConfigCustomList = 0xed06, AssertReport = 0xed07, + RawBatteryVoltage = 0xed08, }; enum DescriptorType { From 7517d91517dde97e6e73d75eefba49c17110a0fd Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Fri, 23 Jan 2026 11:10:40 -0500 Subject: [PATCH 25/81] RDKEMW-12457: No longer ignoring device re-pair if it's already paired and connected. (#171) --- src/ble/hal/blercu/blercupairingstatemachine.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/ble/hal/blercu/blercupairingstatemachine.cpp b/src/ble/hal/blercu/blercupairingstatemachine.cpp index b55613ed..bb769b41 100644 --- a/src/ble/hal/blercu/blercupairingstatemachine.cpp +++ b/src/ble/hal/blercu/blercupairingstatemachine.cpp @@ -917,12 +917,6 @@ void BleRcuPairingStateMachine::processDevice(const BleAddress &address, // is the device currently paired? if so we have to remove (unpair) // it and then remain in the current state if (m_adapter->isDevicePaired(address)) { - if (m_adapter->isDeviceConnected(address)) { - XLOGD_INFO("Ignoring device (%s, %s)... it is currently paired and connected, no need to re-pair.", - name.c_str(), address.toString().c_str()); - return; - } - XLOGD_INFO("Found target device (%s, %s) but it's currently paired. Will unpair and wait till it shows up in a scan again.", name.c_str(), address.toString().c_str()); From e6a6bd6e13e15885fd0bb76945d980b958b54fa1 Mon Sep 17 00:00:00 2001 From: dwolaver <44593664+dwolaver@users.noreply.github.com> Date: Mon, 9 Feb 2026 12:46:19 -0500 Subject: [PATCH 26/81] RDKEMW-11792 : FFV config file isolation (#165) --- CMakeLists.txt | 14 +++---- src/config/ctrlm_config.cpp | 48 ++++++++++++++++++++-- src/config/ctrlm_config.h | 8 +++- src/ctrlm_config_default.json | 4 -- src/ctrlm_main.cpp | 76 ++++++++++++++++++++++++++--------- src/voice/ctrlm_voice_obj.cpp | 60 ++------------------------- src/voice/ctrlm_voice_obj.h | 2 - 7 files changed, 120 insertions(+), 92 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c38b5657..565ab874 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -165,7 +165,7 @@ target_link_libraries( install(TARGETS controlMgr RUNTIME DESTINATION bin) -install(FILES ${CMAKE_BINARY_DIR}/ctrlm_config.json.template DESTINATION ${CMAKE_INSTALL_SYSCONFDIR} COMPONENT config ) +install(FILES ${CMAKE_BINARY_DIR}/ctrlm_config.json DESTINATION ${CMAKE_INSTALL_SYSCONFDIR} COMPONENT config ) # DEFINES FROM OPTIONS if(ANSI_CODES_DISABLED) @@ -260,7 +260,7 @@ endif() install(TARGETS controlMgr RUNTIME DESTINATION bin) -install(FILES ${CMAKE_BINARY_DIR}/ctrlm_config.json.template DESTINATION ${CMAKE_INSTALL_SYSCONFDIR} COMPONENT config ) +install(FILES ${CMAKE_BINARY_DIR}/ctrlm_config.json DESTINATION ${CMAKE_INSTALL_SYSCONFDIR} COMPONENT config ) # GENERATED FILES add_custom_command( OUTPUT ctrlm_version_build.h @@ -276,16 +276,16 @@ add_custom_command( OUTPUT ctrlm_version_build.h ) add_custom_command( - OUTPUT ${CMAKE_BINARY_DIR}/ctrlm_config.json.template - COMMAND python3 ${CTRLM_UTILS_JSON_COMBINE} -i ${CMAKE_CURRENT_SOURCE_DIR}/src/ctrlm_config_default.json -a ${CTRLM_CONFIG_JSON_VSDK}:vsdk -a ${CTRLM_CONFIG_JSON_CPC} -s ${CTRLM_CONFIG_JSON_CPC_SUB} -a ${CTRLM_CONFIG_JSON_CPC_ADD} -s ${CTRLM_CONFIG_JSON_OEM_SUB} -a ${CTRLM_CONFIG_JSON_OEM_ADD} -s ${CTRLM_CONFIG_JSON_MAIN_SUB} -a ${CTRLM_CONFIG_JSON_MAIN_ADD} -o ${CMAKE_BINARY_DIR}/ctrlm_config.json.template + OUTPUT ${CMAKE_BINARY_DIR}/ctrlm_config.json + COMMAND python3 ${CTRLM_UTILS_JSON_COMBINE} -i ${CMAKE_CURRENT_SOURCE_DIR}/src/ctrlm_config_default.json -a ${CTRLM_CONFIG_JSON_CPC} -s ${CTRLM_CONFIG_JSON_CPC_SUB} -a ${CTRLM_CONFIG_JSON_CPC_ADD} -s ${CTRLM_CONFIG_JSON_MAIN_SUB} -a ${CTRLM_CONFIG_JSON_MAIN_ADD} -o ${CMAKE_BINARY_DIR}/ctrlm_config.json DEPENDS src/ctrlm_config_default.json VERBATIM ) add_custom_command( OUTPUT ctrlm_config_default.h ${CMAKE_CURRENT_SOURCE_DIR}/src/ctrlm_config_default.c - COMMAND python3 ${CTRLM_UTILS_JSON_TO_HEADER} -i ${CMAKE_BINARY_DIR}/ctrlm_config.json.template -o ctrlm_config_default.h -c ${CMAKE_CURRENT_SOURCE_DIR}/src/ctrlm_config_default.c -v "ctrlm_global,network_rf4ce,network_ip,network_ble,ir,voice,device_update" -d "network_ble" - DEPENDS ${CMAKE_BINARY_DIR}/ctrlm_config.json.template + COMMAND python3 ${CTRLM_UTILS_JSON_TO_HEADER} -i ${CMAKE_BINARY_DIR}/ctrlm_config.json -o ctrlm_config_default.h -c ${CMAKE_CURRENT_SOURCE_DIR}/src/ctrlm_config_default.c -v "ctrlm_global,network_rf4ce,network_ip,network_ble,ir,voice,device_update" -d "network_ble" + DEPENDS ${CMAKE_BINARY_DIR}/ctrlm_config.json VERBATIM ) @@ -296,5 +296,5 @@ add_custom_command( ) add_custom_target( ctrlm_config - DEPENDS ${CMAKE_BINARY_DIR}/ctrlm_config.json.template + DEPENDS ${CMAKE_BINARY_DIR}/ctrlm_config.json ) diff --git a/src/config/ctrlm_config.cpp b/src/config/ctrlm_config.cpp index f49b523e..eb0ed60e 100644 --- a/src/config/ctrlm_config.cpp +++ b/src/config/ctrlm_config.cpp @@ -54,7 +54,7 @@ ctrlm_config_t::~ctrlm_config_t() { } } -bool ctrlm_config_t::load_config(const std::string &file_path) { +bool ctrlm_config_t::load_config(const std::string &file_path, bool verbose) { bool ret = false; std::string contents = file_to_string(file_path); if(this->root) { @@ -63,13 +63,19 @@ bool ctrlm_config_t::load_config(const std::string &file_path) { } if(!contents.empty()) { json_error_t json_error; - XLOGD_INFO_OPTS(XLOG_OPTS_DEFAULT, 20 * 1024, "Loading Configuration for <%s> <%s>", file_path.c_str(), contents.c_str()); + if(verbose) { + XLOGD_INFO_OPTS(XLOG_OPTS_DEFAULT, 20 * 1024, "Loading Configuration for <%s> <%s>", file_path.c_str(), contents.c_str()); + } else { + XLOGD_INFO("Loading Configuration for <%s>", file_path.c_str()); + } this->root = json_loads(contents.c_str(), JSON_REJECT_DUPLICATES, &json_error); if(this->root != NULL) { - XLOGD_INFO("config loaded successfully as JSON"); + if(verbose) { + XLOGD_INFO("config loaded successfully as JSON for <%s>", file_path.c_str()); + } ret = true; } else { - XLOGD_ERROR("JSON ERROR: Line <%u> Column <%u> Text <%s>", json_error.line, json_error.column, json_error.text); + XLOGD_ERROR("JSON ERROR: Line <%u> Column <%u> Text <%s> Contents <%s>", json_error.line, json_error.column, json_error.text, contents.c_str()); } } else { XLOGD_ERROR("no config file contents"); @@ -77,6 +83,40 @@ bool ctrlm_config_t::load_config(const std::string &file_path) { return(ret); } +bool ctrlm_config_t::append_config(const std::string &file_path, bool verbose) { + if(this->root == NULL) { + XLOGD_ERROR("no config file loaded"); + return(false); + } + bool ret = false; + std::string contents = file_to_string(file_path); + if(contents.empty()) { + XLOGD_ERROR("no config file contents"); + } else { + json_error_t json_error; + if(verbose) { + XLOGD_INFO_OPTS(XLOG_OPTS_DEFAULT, 20 * 1024, "Appending Configuration for <%s> <%s>", file_path.c_str(), contents.c_str()); + } else { + XLOGD_INFO("Appending Configuration for <%s>", file_path.c_str()); + } + json_t *append_root = json_loads(contents.c_str(), JSON_REJECT_DUPLICATES, &json_error); + if(append_root == NULL) { + XLOGD_ERROR("JSON ERROR: Line <%u> Column <%u> Text <%s> Contents <%s>", json_error.line, json_error.column, json_error.text, contents.c_str()); + } else { + if(json_object_update(this->root, append_root) != 0) { + XLOGD_ERROR("Failed to merge JSON objects"); + } else { + if(verbose) { + XLOGD_INFO("config appended successfully as JSON for <%s>", file_path.c_str()); + } + ret = true; + } + json_decref(append_root); + } + } + return(ret); +} + bool ctrlm_config_t::path_exists(const std::string &path) { return(ctrlm_utils_json_from_path(this->root, path, false) != NULL ? true : false); } diff --git a/src/config/ctrlm_config.h b/src/config/ctrlm_config.h index a64eb6f7..755e5b4b 100644 --- a/src/config/ctrlm_config.h +++ b/src/config/ctrlm_config.h @@ -49,7 +49,13 @@ class ctrlm_config_t { * @param file_path The path to the configuration file * @return True on success, otherwise False */ - bool load_config(const std::string &file_path); + bool load_config(const std::string &file_path, bool verbose = false); + /** + * Function which appends a configuration file into the configuration object. + * @param file_path The path to the configuration file + * @return True on success, otherwise False + */ + bool append_config(const std::string &file_path, bool verbose = false); /** * Function to check if object exists from a path * @param path A period seperated string used to navigate a JSON object i.e. "network_rf4ce.polling.enabled" diff --git a/src/ctrlm_config_default.json b/src/ctrlm_config_default.json index a30bde8a..af65c196 100755 --- a/src/ctrlm_config_default.json +++ b/src/ctrlm_config_default.json @@ -7,8 +7,6 @@ "authservice_poll_period" : 5, "authservice_fast_poll_period" : 1000, "authservice_fast_max_retries" : 25, - "keycode_logging_poll_period" : 30, - "keycode_logging_max_retries" : 5, "url_auth_service" : "", "timeout_recently_booted" : 1800000, "timeout_line_of_sight" : 10000, @@ -16,7 +14,6 @@ "timeout_button_binding" : 600000, "timeout_screen_bind" : 600000, "timeout_one_touch_autobind" : 600000, - "mask_key_codes" : false, "mask_pii" : [true, false], "crash_recovery_threshold" : 2, "device_id" : "", @@ -263,7 +260,6 @@ "utterance_path" : "/opt/logs/rf4ce_adpcm_header_vrex.raw", "force_voice_settings" : false, "vrex_response_timeout" : 10000, - "keyword_detect_sensitivity" : 0.3, "opus_encoder_params" : "4080084410", "packet_loss_threshold" : 5, "vrex_test_flag" : false, diff --git a/src/ctrlm_main.cpp b/src/ctrlm_main.cpp index 0794c861..4c9d9faa 100644 --- a/src/ctrlm_main.cpp +++ b/src/ctrlm_main.cpp @@ -1601,8 +1601,7 @@ gboolean ctrlm_load_authservice_data(void) { gboolean ctrlm_load_config(json_t **json_obj_root, json_t **json_obj_net_rf4ce, json_t **json_obj_voice, json_t **json_obj_device_update, json_t **json_obj_validation, json_t **json_obj_vsdk) { std::string config_fn_opt = "/opt/ctrlm_config.json"; - std::string config_fn_etc = "/etc/ctrlm_config.json"; - std::string config_fn_etc_override = "/etc/ctrlm_config.json.OVERRIDE"; + std::string config_fn_oem = "/etc/vendor/input/ctrlm_config.json"; json_t *json_obj_ctrlm; ctrlm_config_t *ctrlm_config = ctrlm_config_t::get_instance(); gboolean local_conf = false; @@ -1612,18 +1611,44 @@ gboolean ctrlm_load_config(json_t **json_obj_root, json_t **json_obj_net_rf4ce, if(ctrlm_config == NULL) { XLOGD_ERROR("Failed to get config manager instance"); return(false); - } else if(!ctrlm_is_production_build() && g_file_test(config_fn_opt.c_str(), G_FILE_TEST_EXISTS) && ctrlm_config->load_config(config_fn_opt)) { - XLOGD_INFO("Read configuration from <%s>", config_fn_opt.c_str()); - local_conf = true; - } else if(g_file_test(config_fn_etc.c_str(), G_FILE_TEST_EXISTS) && ctrlm_config->load_config(config_fn_etc)) { - XLOGD_INFO("Read configuration from <%s>", config_fn_etc.c_str()); - } else if(g_file_test(config_fn_etc_override.c_str(), G_FILE_TEST_EXISTS) && ctrlm_config->load_config(config_fn_etc_override)) { - XLOGD_INFO("Read configuration from <%s>", config_fn_etc_override.c_str()); - } else { - XLOGD_WARN("Configuration error. Configuration file(s) missing, using defaults"); + } + + bool oem_append = g_file_test(config_fn_oem.c_str(), G_FILE_TEST_EXISTS); + bool opt_append = ctrlm_is_production_build() ? false : g_file_test(config_fn_opt.c_str(), G_FILE_TEST_EXISTS); + + if(!oem_append && !opt_append) { + XLOGD_INFO("Using default configuration"); return(false); } + // Check for OEM config file override + if(oem_append) { + XLOGD_INFO("Loading OEM configuration from <%s>", config_fn_oem.c_str()); + if(!ctrlm_config->load_config(config_fn_oem)) { + XLOGD_ERROR("Failed to load OEM configuration from <%s>", config_fn_oem.c_str()); + return(false); + } + } + + // Check for OPT config file override + if(opt_append) { + if(!oem_append) { + XLOGD_INFO("Loading OPT configuration from <%s>", config_fn_opt.c_str()); + if(!ctrlm_config->load_config(config_fn_opt)) { + XLOGD_ERROR("Failed to load OPT configuration from <%s>", config_fn_opt.c_str()); + return(false); + } + } else { + XLOGD_INFO("Appending OPT configuration from <%s>", config_fn_opt.c_str()); + + if(!ctrlm_config->append_config(config_fn_opt)) { + XLOGD_ERROR("Failed to append OPT configuration from <%s>", config_fn_opt.c_str()); + return(false); + } + } + local_conf = true; + } + // Parse the JSON data *json_obj_root = ctrlm_config->json_from_path("", true); // Get root AND add ref to it, since this code derefs it if(*json_obj_root == NULL) { @@ -1637,37 +1662,52 @@ gboolean ctrlm_load_config(json_t **json_obj_root, json_t **json_obj_net_rf4ce, return(false); } + // Print the configuration since it was loaded from files + char *json_dump = json_dumps(*json_obj_root, JSON_INDENT(3) | JSON_SORT_KEYS); + if(json_dump == NULL) { + XLOGD_ERROR("unable to dump JSON object"); + json_decref(*json_obj_root); + *json_obj_root = NULL; + return(false); + } else { + XLOGD_INFO_OPTS(XLOG_OPTS_DEFAULT, 20 * 1024, "Final configuration:\n%s", json_dump); + free(json_dump); + } + // Extract the RF4CE network configuration object if(g_ctrlm.rf4ce_enabled) { *json_obj_net_rf4ce = json_object_get(*json_obj_root, JSON_OBJ_NAME_NETWORK_RF4CE); if(*json_obj_net_rf4ce == NULL || !json_is_object(*json_obj_net_rf4ce)) { - XLOGD_WARN("RF4CE network object not found"); + XLOGD_INFO("RF4CE network object not found"); + *json_obj_net_rf4ce = NULL; } } // Extract the voice configuration object *json_obj_voice = json_object_get(*json_obj_root, JSON_OBJ_NAME_VOICE); if(*json_obj_voice == NULL || !json_is_object(*json_obj_voice)) { - XLOGD_WARN("voice object not found"); + XLOGD_INFO("voice object not found"); + *json_obj_voice = NULL; } // Extract the device update configuration object *json_obj_device_update = json_object_get(*json_obj_root, JSON_OBJ_NAME_DEVICE_UPDATE); if(*json_obj_device_update == NULL || !json_is_object(*json_obj_device_update)) { - XLOGD_WARN("device update object not found"); + XLOGD_INFO("device update object not found"); + *json_obj_device_update = NULL; } //Extract the vsdk configuration object *json_obj_vsdk = json_object_get( *json_obj_root, JSON_OBJ_NAME_VSDK); if(*json_obj_vsdk == NULL || !json_is_object(*json_obj_vsdk)) { - XLOGD_WARN("vsdk object not found"); - json_obj_vsdk = NULL; + XLOGD_INFO("vsdk object not found"); + *json_obj_vsdk = NULL; } // Extract the ctrlm global configuration object json_obj_ctrlm = json_object_get(*json_obj_root, JSON_OBJ_NAME_CTRLM_GLOBAL); if(json_obj_ctrlm == NULL || !json_is_object(json_obj_ctrlm)) { - XLOGD_WARN("control manger object not found"); + XLOGD_INFO("control manager object not found"); } else { json_config conf_global; if(!conf_global.config_object_set(json_obj_ctrlm)) { @@ -1677,7 +1717,7 @@ gboolean ctrlm_load_config(json_t **json_obj_root, json_t **json_obj_net_rf4ce, // Extract the validation configuration object *json_obj_validation = json_object_get(json_obj_ctrlm, JSON_OBJ_NAME_CTRLM_GLOBAL_VALIDATION_CONFIG); if(*json_obj_validation == NULL || !json_is_object(*json_obj_validation)) { - XLOGD_WARN("validation object not found"); + XLOGD_INFO("validation object not found"); } // Now parse the control manager object diff --git a/src/voice/ctrlm_voice_obj.cpp b/src/voice/ctrlm_voice_obj.cpp index d114aeea..ba00c02b 100644 --- a/src/voice/ctrlm_voice_obj.cpp +++ b/src/voice/ctrlm_voice_obj.cpp @@ -205,7 +205,6 @@ ctrlm_voice_t::ctrlm_voice_t() { this->prefs.utterance_duration_min = JSON_INT_VALUE_VOICE_MINIMUM_DURATION; this->prefs.ffv_leading_samples = JSON_INT_VALUE_VOICE_FFV_LEADING_SAMPLES; this->prefs.force_voice_settings = JSON_BOOL_VALUE_VOICE_FORCE_VOICE_SETTINGS; - this->prefs.keyword_sensitivity = JSON_FLOAT_VALUE_VOICE_KEYWORD_DETECT_SENSITIVITY; this->prefs.vrex_test_flag = JSON_BOOL_VALUE_VOICE_VREX_TEST_FLAG; this->prefs.vrex_wuw_bypass_success_flag = JSON_BOOL_VALUE_VOICE_VREX_WUW_BYPASS_SUCCESS_FLAG; this->prefs.vrex_wuw_bypass_failure_flag = JSON_BOOL_VALUE_VOICE_VREX_WUW_BYPASS_FAILURE_FLAG; @@ -340,29 +339,12 @@ bool ctrlm_voice_t::vsdk_is_privacy_enabled(void) { return privacy; } -double ctrlm_voice_t::vsdk_keyword_sensitivity_limit_check(double sensitivity) { - float sensitivity_min; - float sensitivity_max; - - if(!xrsr_keyword_sensitivity_limits_get(&sensitivity_min, &sensitivity_max)) { - XLOGD_WARN("Unable to get keyword detector sensitivity limits. Using default sensitivity <%f>.", JSON_FLOAT_VALUE_VOICE_KEYWORD_DETECT_SENSITIVITY); - return(JSON_FLOAT_VALUE_VOICE_KEYWORD_DETECT_SENSITIVITY); - } else { - if(((float)(sensitivity) < sensitivity_min) || ((float)(sensitivity) > sensitivity_max)) { - XLOGD_WARN("Keyword detector sensitivity <%f> outside of range <%f to %f>. Using default sensitivity <%f>.", (float)(sensitivity), sensitivity_min, sensitivity_max, JSON_FLOAT_VALUE_VOICE_KEYWORD_DETECT_SENSITIVITY); - return(JSON_FLOAT_VALUE_VOICE_KEYWORD_DETECT_SENSITIVITY); - } - } - return(sensitivity); -} - void ctrlm_voice_t::voice_sdk_open(json_t *json_obj_vsdk) { if(this->xrsr_opened) { XLOGD_ERROR("already open"); return; } xrsr_route_t routes[1]; - xrsr_keyword_config_t kw_config; xrsr_capture_config_t capture_config = { .delete_files = !this->prefs.utterance_save, .enable = this->prefs.utterance_save, @@ -382,7 +364,6 @@ void ctrlm_voice_t::voice_sdk_open(json_t *json_obj_vsdk) { /* Open Voice SDK */ routes[0].src = XRSR_SRC_INVALID; routes[0].dst_qty = 0; - kw_config.sensitivity = this->prefs.keyword_sensitivity; char host_name[HOST_NAME_MAX]; host_name[0] = '\0'; @@ -398,7 +379,7 @@ void ctrlm_voice_t::voice_sdk_open(json_t *json_obj_vsdk) { ctrlm_power_state_t ctrlm_power_state = ctrlm_main_get_internal_power_state(); xrsr_power_mode_t xrsr_power_mode = voice_xrsr_power_map(ctrlm_power_state); - if(!xrsr_open(host_name, routes, &kw_config, &capture_config, xrsr_power_mode, privacy, this->mask_pii, json_obj_vsdk)) { + if(!xrsr_open(host_name, routes, NULL, &capture_config, xrsr_power_mode, privacy, this->mask_pii, json_obj_vsdk)) { XLOGD_ERROR("Failed to open speech router"); g_assert(0); } @@ -479,7 +460,6 @@ bool ctrlm_voice_t::voice_configure_config_file_json(json_t *obj_voice, json_t * conf.config_value_get(JSON_INT_NAME_VOICE_FFV_LEADING_SAMPLES, this->prefs.ffv_leading_samples, 0); conf.config_value_get(JSON_STR_NAME_VOICE_APP_ID_HTTP, this->prefs.app_id_http); conf.config_value_get(JSON_STR_NAME_VOICE_APP_ID_WS, this->prefs.app_id_ws); - conf.config_value_get(JSON_FLOAT_NAME_VOICE_KEYWORD_DETECT_SENSITIVITY, this->prefs.keyword_sensitivity, 0.0, DBL_MAX); conf.config_value_get(JSON_BOOL_NAME_VOICE_VREX_TEST_FLAG, this->prefs.vrex_test_flag); conf.config_value_get(JSON_BOOL_NAME_VOICE_VREX_WUW_BYPASS_SUCCESS_FLAG,this->prefs.vrex_wuw_bypass_success_flag); conf.config_value_get(JSON_BOOL_NAME_VOICE_VREX_WUW_BYPASS_FAILURE_FLAG,this->prefs.vrex_wuw_bypass_failure_flag); @@ -487,8 +467,9 @@ bool ctrlm_voice_t::voice_configure_config_file_json(json_t *obj_voice, json_t * conf.config_value_get(JSON_BOOL_NAME_VOICE_TELEMETRY_SESSION_STATS, this->prefs.telemetry_session_stats); std::string opus_encoder_params_str; - conf.config_value_get(JSON_STR_NAME_VOICE_OPUS_ENCODER_PARAMS, opus_encoder_params_str); - this->voice_params_opus_encoder_validate(opus_encoder_params_str); + if(conf.config_value_get(JSON_STR_NAME_VOICE_OPUS_ENCODER_PARAMS, opus_encoder_params_str)) { + this->voice_params_opus_encoder_validate(opus_encoder_params_str); + } conf.config_value_get(JSON_INT_NAME_VOICE_PAR_VOICE_EOS_METHOD, this->prefs.par_voice_eos_method); conf.config_value_get(JSON_INT_NAME_VOICE_PAR_VOICE_EOS_TIMEOUT, this->prefs.par_voice_eos_timeout); @@ -604,17 +585,6 @@ bool ctrlm_voice_t::voice_configure_config_file_json(json_t *obj_voice, json_t * if(privacy_enabled != this->vsdk_is_privacy_enabled()) { privacy_enabled ? this->voice_privacy_enable(false) : this->voice_privacy_disable(false); } - // Check keyword detector sensitivity value against limits; apply default if out of range. - double sensitivity_set = this->vsdk_keyword_sensitivity_limit_check(this->prefs.keyword_sensitivity); - if(sensitivity_set != this->prefs.keyword_sensitivity) { - xrsr_keyword_config_t kw_config; - kw_config.sensitivity = (float)sensitivity_set; - if(!xrsr_keyword_config_set(&kw_config)) { - XLOGD_ERROR("error updating keyword config"); - } else { - this->prefs.keyword_sensitivity = sensitivity_set; - } - } } } @@ -1011,12 +981,6 @@ void ctrlm_voice_t::process_xconf(json_t **json_obj_vsdk, bool local_conf) { // CTRLM_TR181_VOICE_PARAMS_AUDIO_DUCKING_BEEP doesn't exist because this is a user configurable setting via configureVoice thunder api - double keyword_sensitivity = 0.0; - result = ctrlm_tr181_real_get(CTRLM_TR181_VOICE_PARAMS_KEYWORD_SENSITIVITY, &keyword_sensitivity); - if(result == CTRLM_TR181_RESULT_SUCCESS) { - this->prefs.keyword_sensitivity = (keyword_sensitivity < 0.0) ? JSON_FLOAT_VALUE_VOICE_KEYWORD_DETECT_SENSITIVITY : keyword_sensitivity; - } - result = ctrlm_tr181_string_get(CTRLM_TR181_VOICE_PARAMS_VSDK_CONFIGURATION, &vsdk_config_str[0], CTRLM_RFC_MAX_PARAM_LEN); if(result == CTRLM_TR181_RESULT_SUCCESS) { json_error_t jerror; @@ -4038,22 +4002,6 @@ void ctrlm_voice_t::voice_rfc_retrieved_handler(const ctrlm_rfc_attr_t& attr) { attr.get_rfc_value(JSON_STR_NAME_VOICE_APP_ID_WS, this->prefs.app_id_ws); attr.get_rfc_value(JSON_STR_NAME_VOICE_LANGUAGE, this->prefs.guide_language); - double keyword_sensitivity = 0.0; - if(attr.get_rfc_value(JSON_FLOAT_NAME_VOICE_KEYWORD_DETECT_SENSITIVITY, keyword_sensitivity)) { - // Check keyword detector sensitivity value against limits; apply default if out of range. - double sensitivity_set = this->vsdk_keyword_sensitivity_limit_check(keyword_sensitivity); - if(sensitivity_set != keyword_sensitivity) { - XLOGD_ERROR("keyword sensitivity <%5.2f> out of limits", keyword_sensitivity); - } else { - this->prefs.keyword_sensitivity = keyword_sensitivity; - XLOGD_INFO("keyword sensitivity <%5.2f>", this->prefs.keyword_sensitivity); - xrsr_keyword_config_t kw_config; - kw_config.sensitivity = (float)this->prefs.keyword_sensitivity; - if(!xrsr_keyword_config_set(&kw_config)) { - XLOGD_ERROR("error updating keyword config"); - } - } - } attr.get_rfc_value(JSON_BOOL_NAME_VOICE_VREX_TEST_FLAG, this->prefs.vrex_test_flag); attr.get_rfc_value(JSON_BOOL_NAME_VOICE_VREX_WUW_BYPASS_SUCCESS_FLAG,this->prefs.vrex_wuw_bypass_success_flag); attr.get_rfc_value(JSON_BOOL_NAME_VOICE_VREX_WUW_BYPASS_FAILURE_FLAG,this->prefs.vrex_wuw_bypass_failure_flag); diff --git a/src/voice/ctrlm_voice_obj.h b/src/voice/ctrlm_voice_obj.h index 3976a62c..c4395b18 100644 --- a/src/voice/ctrlm_voice_obj.h +++ b/src/voice/ctrlm_voice_obj.h @@ -296,7 +296,6 @@ typedef struct { unsigned long utterance_duration_min; unsigned long ffv_leading_samples; bool force_voice_settings; - double keyword_sensitivity; bool vrex_test_flag; bool vrex_wuw_bypass_success_flag; bool vrex_wuw_bypass_failure_flag; @@ -745,7 +744,6 @@ class ctrlm_voice_t { void set_audio_mode(ctrlm_voice_audio_settings_t *settings); void audio_state_set(bool session); bool vsdk_is_privacy_enabled(void); - double vsdk_keyword_sensitivity_limit_check(double sensitivity); void pre_session_terminate(std::function cb_start_audio, ctrlm_voice_start_audio_params_t *cb_audio_start_params, ctrlm_voice_session_rsp_confirm_t *cb_confirm, From 517b50145dabb0e63c573d55cb5a76e008dc37b8 Mon Sep 17 00:00:00 2001 From: Gene Gallagher <129112619+egalla204@users.noreply.github.com> Date: Mon, 9 Feb 2026 14:12:00 -0500 Subject: [PATCH 27/81] RDKEMW-9474: ctrlm multiple simultaneous IR databases (#161) add support for having multiple IR database vendor implementations simultaneously --- src/ble/ctrlm_ble_controller.cpp | 29 ++++++++++++--- src/ble/ctrlm_ble_network.cpp | 3 +- .../bleservices/gatt/gatt_infraredservice.cpp | 8 +++- src/irdb/ctrlm_irdb_interface.cpp | 37 +++++++++++++++++++ src/irdb/ctrlm_irdb_interface.h | 1 + src/irdb/ctrlm_irdb_plugin.h | 6 +++ src/irdb/ctrlm_irdb_stub.cpp | 10 +++++ src/irdb/ctrlm_irdb_stub.h | 4 ++ 8 files changed, 90 insertions(+), 8 deletions(-) diff --git a/src/ble/ctrlm_ble_controller.cpp b/src/ble/ctrlm_ble_controller.cpp index fdbd155f..f1a87c22 100644 --- a/src/ble/ctrlm_ble_controller.cpp +++ b/src/ble/ctrlm_ble_controller.cpp @@ -531,13 +531,30 @@ void ctrlm_obj_controller_ble_t::setSupportedIrdbs(uint8_t vendor_support_bitmas this->irdbs_supported_ = vendor_support_bitmask; ctrlm_irdb_interface_t *irdb = ctrlm_main_irdb_get(); - ctrlm_irdb_vendor_info_t vendor_info; - if (irdb && irdb->get_vendor_info(vendor_info)) { - XLOGD_INFO("Controller <%s> IRDBs supported bitmask = <0x%X>, which %s support the loaded IRDB plugin vendor <%s>", - ieee_address_get().to_string().c_str(), vendor_support_bitmask, - isSupportedIrdb(vendor_info) ? "DOES" : "does NOT", vendor_info.name.c_str()); + + if (irdb == NULL) { + XLOGD_ERROR("IRDB interface is NULL!!!"); + return; + } + + ctrlm_irdb_vendor_info_t rcu_vendor_info{}; + rcu_vendor_info.rcu_support_bitmask = vendor_support_bitmask; + if (!irdb->set_vendor(rcu_vendor_info)) { + XLOGD_ERROR("Failed to set IRDB vendor info for controller <%s> with bitmask <0x%X>.", + ieee_address_get().to_string().c_str(), vendor_support_bitmask); + } + + ctrlm_irdb_vendor_info_t vendor_info{}; + if (irdb->get_vendor_info(vendor_info)) { + if (isSupportedIrdb(vendor_info)) { + XLOGD_INFO("Controller <%s> IRDBs supported bitmask = <0x%X>, which DOES support the loaded IRDB plugin vendor <%s>", + ieee_address_get().to_string().c_str(), vendor_support_bitmask, vendor_info.name.c_str()); + } else { + XLOGD_ERROR("Controller <%s> IRDBs supported bitmask = <0x%X>, which does NOT support the loaded IRDB plugin vendor <%s>", + ieee_address_get().to_string().c_str(), vendor_support_bitmask, vendor_info.name.c_str()); + } } else { - XLOGD_INFO("Controller <%s> IRDBs supported bitmask = <0x%X>, couldn't retrieve IRDB plugin vendor info.", + XLOGD_WARN("Controller <%s> IRDBs supported bitmask = <0x%X>, couldn't retrieve IRDB plugin vendor info.", ieee_address_get().to_string().c_str(), vendor_support_bitmask); } } diff --git a/src/ble/ctrlm_ble_network.cpp b/src/ble/ctrlm_ble_network.cpp index aff81aeb..03e1322f 100644 --- a/src/ble/ctrlm_ble_network.cpp +++ b/src/ble/ctrlm_ble_network.cpp @@ -2031,6 +2031,8 @@ ctrlm_controller_id_t ctrlm_obj_network_ble_t::controller_add(ctrlm_hal_ble_rcu_ controller->setName(string(rcu_data.name)); controller->setAudioCodecs(rcu_data.audio_codecs); controller->setConnected(rcu_data.connected); + controller->setSupportedIrdbs(rcu_data.irdbs_supported); + // only update these parameters if they are not empty or invalid. if (rcu_data.serial_number[0] != '\0') { controller->setSerialNumber(string(rcu_data.serial_number)); } if (rcu_data.manufacturer[0] != '\0') { controller->setManufacturer(string(rcu_data.manufacturer)); } @@ -2042,7 +2044,6 @@ ctrlm_controller_id_t ctrlm_obj_network_ble_t::controller_add(ctrlm_hal_ble_rcu_ if (rcu_data.battery_level != 0xFF) { controller->setBatteryPercent(rcu_data.battery_level); } if (rcu_data.wakeup_config != 0xFF) { controller->setWakeupConfig(rcu_data.wakeup_config); } if (rcu_data.wakeup_custom_list_size != 0) { controller->setWakeupCustomList(rcu_data.wakeup_custom_list, rcu_data.wakeup_custom_list_size); } - if (rcu_data.irdbs_supported != 0) { controller->setSupportedIrdbs(rcu_data.irdbs_supported); } if (rcu_data.last_wakeup_key != 0xFF) { controller->setLastWakeupKey(rcu_data.last_wakeup_key); } controller->db_store(); diff --git a/src/ble/hal/blercu/bleservices/gatt/gatt_infraredservice.cpp b/src/ble/hal/blercu/bleservices/gatt/gatt_infraredservice.cpp index 8d8061d5..40dff3c6 100644 --- a/src/ble/hal/blercu/bleservices/gatt/gatt_infraredservice.cpp +++ b/src/ble/hal/blercu/bleservices/gatt/gatt_infraredservice.cpp @@ -422,6 +422,11 @@ void GattInfraredService::requestIrSupport() // sanity check we actually have a ir support characteristic if (!m_irSupportCharacteristic || !m_irSupportCharacteristic->isValid()) { XLOGD_WARN("missing ir support characteristic"); + + // Set ir support back to invalid value and notify + m_irSupport = 0; + m_irSupportChangedSlots.invoke(m_irSupport); + return; } @@ -434,8 +439,9 @@ void GattInfraredService::requestIrSupport() XLOGD_ERROR("failed to get initial ir support code due to <%s>", reply->errorMessage().c_str()); + // Set ir support back to invalid value and notify m_irSupport = 0; - + m_irSupportChangedSlots.invoke(m_irSupport); } else { std::vector value; diff --git a/src/irdb/ctrlm_irdb_interface.cpp b/src/irdb/ctrlm_irdb_interface.cpp index 18a02e57..01fa6588 100644 --- a/src/irdb/ctrlm_irdb_interface.cpp +++ b/src/irdb/ctrlm_irdb_interface.cpp @@ -69,6 +69,8 @@ typedef struct { std::string (*pluginVersion)() = NULL; bool (*pluginInitialize)() = NULL; bool (*pluginGetVendorInfo)(ctrlm_irdb_vendor_info_t &info) = NULL; + bool (*pluginGetSupportedVendors)(std::vector &info) = NULL; + bool (*pluginSetPreferredVendor)(const ctrlm_irdb_vendor_info_t &vendor) = NULL; bool (*pluginGetManufacturers)(ctrlm_irdb_manufacturer_list_t &manufacturers, ctrlm_irdb_dev_type_t type, const std::string &prefix) = NULL; bool (*pluginGetModels)(ctrlm_irdb_model_list_t &models, ctrlm_irdb_dev_type_t type, const std::string &manufacturer, const std::string &prefix) = NULL; bool (*pluginGetEntryIds)(ctrlm_irdb_entry_id_list_t &codes, ctrlm_irdb_dev_type_t type, const std::string &manufacturer, const std::string &model) = NULL; @@ -133,6 +135,8 @@ ctrlm_irdb_interface_t::ctrlm_irdb_interface_t(bool platform_tv) { g_irdb.pluginVersion = STUB_irdb_version; g_irdb.pluginInitialize = STUB_ctrlm_irdb_initialize; g_irdb.pluginGetVendorInfo = STUB_ctrlm_irdb_get_vendor_info; + g_irdb.pluginSetPreferredVendor = STUB_ctrlm_irdb_set_preferred_vendor; + g_irdb.pluginGetSupportedVendors = STUB_ctrlm_irdb_get_supported_vendor_info; g_irdb.pluginGetManufacturers = STUB_ctrlm_irdb_get_manufacturers; g_irdb.pluginGetModels = STUB_ctrlm_irdb_get_models; g_irdb.pluginGetEntryIds = STUB_ctrlm_irdb_get_entry_ids; @@ -183,6 +187,20 @@ ctrlm_irdb_interface_t::ctrlm_irdb_interface_t(bool platform_tv) { } dlerror(); // Clear any existing error + *(void **) (&g_irdb.pluginGetSupportedVendors) = dlsym(m_irdbPluginHandle, "ctrlm_irdb_get_supported_vendor_info"); + if ((error = dlerror()) != NULL) { + XLOGD_ERROR("Failed to find plugin method (ctrlm_irdb_get_supported_vendor_info), error <%s>, Using STUB implementation", error); + g_irdb.pluginGetSupportedVendors = STUB_ctrlm_irdb_get_supported_vendor_info; + } + dlerror(); // Clear any existing error + + *(void **) (&g_irdb.pluginSetPreferredVendor) = dlsym(m_irdbPluginHandle, "ctrlm_irdb_set_preferred_vendor"); + if ((error = dlerror()) != NULL) { + XLOGD_ERROR("Failed to find plugin method (ctrlm_irdb_set_preferred_vendor), error <%s>, Using STUB implementation", error); + g_irdb.pluginSetPreferredVendor = STUB_ctrlm_irdb_set_preferred_vendor; + } + dlerror(); // Clear any existing error + *(void **) (&g_irdb.pluginGetManufacturers) = dlsym(m_irdbPluginHandle, "ctrlm_irdb_get_manufacturers"); if ((error = dlerror()) != NULL) { XLOGD_ERROR("Failed to find plugin method (ctrlm_irdb_get_manufacturers), error <%s>, Using STUB implementation", error); @@ -279,6 +297,17 @@ bool ctrlm_irdb_interface_t::open_plugin() { } } XLOGD_INFO("IRDB plugin opened, ret = <%s>", ret ? "SUCCESS" : "ERROR"); + + if (g_irdb.pluginGetSupportedVendors) { + std::vector supported_vendors; + if ((*g_irdb.pluginGetSupportedVendors)(supported_vendors) == true) { + for (const auto &it : supported_vendors) { + XLOGD_INFO("Found supported IRDB Vendor <%s, 0x%X>", it.name.c_str(), it.rcu_support_bitmask); + } + } else { + XLOGD_WARN("Unable to query IRDB plugin for list of supported vendors, check version of the plugin..."); + } + } return ret; } @@ -300,6 +329,14 @@ bool ctrlm_irdb_interface_t::get_vendor_info(ctrlm_irdb_vendor_info_t &info) { return false; } +bool ctrlm_irdb_interface_t::set_vendor(const ctrlm_irdb_vendor_info_t &info) { + std::unique_lock guard(m_mutex); + if (g_irdb.pluginSetPreferredVendor) { + return (*g_irdb.pluginSetPreferredVendor)(info); + } + return false; +} + void ctrlm_irdb_interface_t::on_thunder_ready() { #if defined(CTRLM_THUNDER) diff --git a/src/irdb/ctrlm_irdb_interface.h b/src/irdb/ctrlm_irdb_interface.h index 76669356..2f532b15 100644 --- a/src/irdb/ctrlm_irdb_interface.h +++ b/src/irdb/ctrlm_irdb_interface.h @@ -69,6 +69,7 @@ class ctrlm_irdb_interface_t { virtual ~ctrlm_irdb_interface_t(); bool get_vendor_info(ctrlm_irdb_vendor_info_t &info); + bool set_vendor(const ctrlm_irdb_vendor_info_t &info); bool get_manufacturers(ctrlm_irdb_manufacturer_list_t &manufacturers, ctrlm_irdb_dev_type_t type, const std::string &prefix = ""); bool get_models(ctrlm_irdb_model_list_t &models, ctrlm_irdb_dev_type_t type, const std::string &manufacturer, const std::string &prefix = ""); bool get_irdb_entry_ids(ctrlm_irdb_entry_id_list_t &codes, ctrlm_irdb_dev_type_t type, const std::string &manufacturer, const std::string &model = ""); diff --git a/src/irdb/ctrlm_irdb_plugin.h b/src/irdb/ctrlm_irdb_plugin.h index 7e1ced22..b115773d 100644 --- a/src/irdb/ctrlm_irdb_plugin.h +++ b/src/irdb/ctrlm_irdb_plugin.h @@ -88,6 +88,12 @@ bool ctrlm_irdb_close(); bool ctrlm_irdb_initialize(); +// Will return info on all the IRDB vendors currently installed, could be multiple vendors returned +bool ctrlm_irdb_get_supported_vendor_info(std::vector &info); + +// Tell the IRDB plugin which vendor(s) the RCU supports +bool ctrlm_irdb_set_preferred_vendor(const ctrlm_irdb_vendor_info_t &vendor); + bool ctrlm_irdb_get_vendor_info(ctrlm_irdb_vendor_info_t &info); bool ctrlm_irdb_get_manufacturers(ctrlm_irdb_manufacturer_list_t &manufacturers, ctrlm_irdb_dev_type_t type, const std::string &prefix); diff --git a/src/irdb/ctrlm_irdb_stub.cpp b/src/irdb/ctrlm_irdb_stub.cpp index 898cb4f0..8161e45c 100644 --- a/src/irdb/ctrlm_irdb_stub.cpp +++ b/src/irdb/ctrlm_irdb_stub.cpp @@ -46,6 +46,16 @@ bool STUB_ctrlm_irdb_get_vendor_info(ctrlm_irdb_vendor_info_t &info) XLOGD_ERROR("not implemented"); return(false); } +bool STUB_ctrlm_irdb_get_supported_vendor_info(std::vector &info) +{ + XLOGD_ERROR("not implemented"); + return(false); +} +bool STUB_ctrlm_irdb_set_preferred_vendor(const ctrlm_irdb_vendor_info_t &info) +{ + XLOGD_ERROR("not implemented"); + return(false); +} bool STUB_ctrlm_irdb_get_manufacturers(ctrlm_irdb_manufacturer_list_t &manufacturers, ctrlm_irdb_dev_type_t type, const std::string &prefix) { XLOGD_ERROR("not implemented"); diff --git a/src/irdb/ctrlm_irdb_stub.h b/src/irdb/ctrlm_irdb_stub.h index 477ec9f3..a03f6f83 100644 --- a/src/irdb/ctrlm_irdb_stub.h +++ b/src/irdb/ctrlm_irdb_stub.h @@ -32,6 +32,10 @@ bool STUB_ctrlm_irdb_initialize(); bool STUB_ctrlm_irdb_get_vendor_info(ctrlm_irdb_vendor_info_t &info); +bool STUB_ctrlm_irdb_get_supported_vendor_info(std::vector &info); + +bool STUB_ctrlm_irdb_set_preferred_vendor(const ctrlm_irdb_vendor_info_t &info); + bool STUB_ctrlm_irdb_get_manufacturers(ctrlm_irdb_manufacturer_list_t &manufacturers, ctrlm_irdb_dev_type_t type, const std::string &prefix); bool STUB_ctrlm_irdb_get_models(ctrlm_irdb_model_list_t &models, ctrlm_irdb_dev_type_t type, const std::string &manufacturer, const std::string &prefix); From 57a584043078aedc7dd28ef6489d27fc9b7a011c Mon Sep 17 00:00:00 2001 From: Gene Gallagher <129112619+egalla204@users.noreply.github.com> Date: Mon, 9 Feb 2026 18:51:20 -0500 Subject: [PATCH 28/81] RDKEMW-13049: remove RCU firmware upgrade retries on failure (#173) --- src/ctrlm_controller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ctrlm_controller.cpp b/src/ctrlm_controller.cpp index 0d8b2154..8048ac2c 100644 --- a/src/ctrlm_controller.cpp +++ b/src/ctrlm_controller.cpp @@ -28,7 +28,7 @@ using namespace std; -#define OTA_MAX_RETRIES (2) +#define OTA_MAX_RETRIES (0) ctrlm_obj_controller_t::ctrlm_obj_controller_t(ctrlm_controller_id_t controller_id, ctrlm_obj_network_t &network, unsigned long long ieee_address) : controller_id_(controller_id), From a48ef129f9e8f4b560b3eb4ad2210be178319b4f Mon Sep 17 00:00:00 2001 From: Kelvin Lu <119349872+klu339@users.noreply.github.com> Date: Wed, 11 Feb 2026 11:16:58 -0500 Subject: [PATCH 29/81] RDKEMW-12828: device minor id, vendor, and product value updates (#175) --- src/input_event/ctrlm_input_event_writer.cpp | 67 ++++++++++++++++++-- src/input_event/ctrlm_input_event_writer.h | 5 +- src/rf4ce/ctrlm_rf4ce_controller.cpp | 18 +++++- src/rf4ce/ctrlm_rf4ce_pairing.cpp | 4 -- src/rf4ce/ctrlm_rf4ce_rib.cpp | 1 + 5 files changed, 84 insertions(+), 11 deletions(-) diff --git a/src/input_event/ctrlm_input_event_writer.cpp b/src/input_event/ctrlm_input_event_writer.cpp index c463a78e..007dd436 100644 --- a/src/input_event/ctrlm_input_event_writer.cpp +++ b/src/input_event/ctrlm_input_event_writer.cpp @@ -28,6 +28,8 @@ #include #include #include +#include +#include bool ctrlm_input_event_writer::init(std::string uinput_name, uint32_t vendor, uint32_t product) { if (initialized_) { @@ -59,8 +61,32 @@ bool ctrlm_input_event_writer::init(std::string uinput_name, uint32_t vendor, ui errno_t safec_rc = strcpy_s(usetup.name, sizeof(usetup.name), uinput_name.c_str()); ERR_CHK(safec_rc); - ioctl(fd, UI_DEV_SETUP, &usetup); - ioctl(fd, UI_DEV_CREATE); + int err = ioctl(fd, UI_DEV_SETUP, &usetup); + if (err == -1) { + int errsv = errno; + XLOGD_ERROR("UI_DEV_SETUP failed with errno %d (%s)", errsv, std::strerror(errsv)); + close(fd); + return false; + } + + err = ioctl(fd, UI_DEV_CREATE); + if (err == -1) { + int errsv = errno; + XLOGD_ERROR("UI_DEV_CREATE failed with errno %d (%s)", errsv, std::strerror(errsv)); + close(fd); + return false; + } + + char sysfs_name[16] = {0}; + err = ioctl(fd, UI_GET_SYSNAME(sizeof(sysfs_name)), sysfs_name); + if (err == -1) { + int errsv = errno; + XLOGD_ERROR("UI_GET_SYSNAME failed with errno %d (%s)", errsv, std::strerror(errsv)); + ioctl(fd, UI_DEV_DESTROY); + close(fd); + return false; + } + sysfs_name_ = sysfs_name; fd_ = fd; initialized_ = true; @@ -147,10 +173,43 @@ uint16_t ctrlm_input_event_writer::write_event(ctrlm_key_code_t code, ctrlm_key_ } bool ctrlm_input_event_writer::get_meta_data(struct stat &file_meta_data) { - int ret = fstat(fd_, &file_meta_data); + std::ostringstream oss; + oss << "/sys/devices/virtual/input/" << sysfs_name_; + std::string dir_path = oss.str(); + XLOGD_DEBUG("virtual input path = %s", dir_path.c_str()); + + DIR *dir = opendir(dir_path.c_str()); + if (dir == nullptr) { + int errsv = errno; + XLOGD_ERROR("Failed to open virtual input device dir at path <%s>: error = <%d>, <%s>", + dir_path.c_str(), errsv, strerror(errsv)); + return false; + } + + struct dirent *entry; + std::string stat_path = "/dev/input/"; + bool event_node_found = false; + + while ((entry = readdir(dir)) != nullptr) { + std::string filename = entry->d_name; + if (filename.find("event") == 0) { + event_node_found = true; + stat_path += filename; + break; + } + } + closedir(dir); + + XLOGD_DEBUG("dev input event path = %s", stat_path.c_str()); + if (!event_node_found) { + XLOGD_ERROR("no event node found in virtual device dir <%s>", dir_path.c_str()); + return false; + } + + int ret = stat(stat_path.c_str(), &file_meta_data); if (ret == -1) { int errsv = errno; - XLOGD_ERROR("fstat() failed: error = <%d>, <%s>", errsv, std::strerror(errsv)); + XLOGD_ERROR("stat() failed: error = <%d>, <%s>", errsv, std::strerror(errsv)); return false; } return true; diff --git a/src/input_event/ctrlm_input_event_writer.h b/src/input_event/ctrlm_input_event_writer.h index c05876e0..a9bc4064 100644 --- a/src/input_event/ctrlm_input_event_writer.h +++ b/src/input_event/ctrlm_input_event_writer.h @@ -105,8 +105,9 @@ const std::map ev_key_value_map = class ctrlm_input_event_writer { private: - bool initialized_ = false; - int fd_ = -1; + bool initialized_ = false; + int fd_ = -1; + std::string sysfs_name_ = ""; protected: bool write_event_internal(uint32_t scan_code, uint16_t key_code, key_stroke stroke); diff --git a/src/rf4ce/ctrlm_rf4ce_controller.cpp b/src/rf4ce/ctrlm_rf4ce_controller.cpp index 6dd7387d..08217279 100644 --- a/src/rf4ce/ctrlm_rf4ce_controller.cpp +++ b/src/rf4ce/ctrlm_rf4ce_controller.cpp @@ -3261,7 +3261,23 @@ bool ctrlm_obj_controller_rf4ce_t::init_uinput_writer() { } std::string uinput_name = product_name_get() + " " + std::to_string(controller_id_get()); - ret = uinput_writer_->init(uinput_name, version_hardware_->get_manufacturer(), version_hardware_->get_model()); + uint32_t vendor = 0x293c; + uint32_t product = 0; + uint32_t manufacturer = version_hardware_->get_manufacturer(); + uint32_t model = version_hardware_->get_model(); + uint32_t revision = version_hardware_->get_revision(); + uint32_t lot = version_hardware_->get_lot(); + + if (manufacturer > 0xF || model > 0xF || revision > 0xF || lot > 0xF) { + XLOGD_WARN("Controller <%s><%d> hardware revision fields exceed 4-bit range", ctrlm_rf4ce_controller_type_str(controller_type_), controller_id_get()); + } + + product |= ((manufacturer & 0xF) << 12); + product |= ((model & 0xF) << 8); + product |= ((revision & 0xF) << 4); + product |= (lot & 0xF); + + ret = uinput_writer_->init(uinput_name, vendor, product); if (!ret) { XLOGD_ERROR("Controller <%s><%d> failed to initialize a uinput device", ctrlm_rf4ce_controller_type_str(controller_type_), controller_id_get()); return ret; diff --git a/src/rf4ce/ctrlm_rf4ce_pairing.cpp b/src/rf4ce/ctrlm_rf4ce_pairing.cpp index e3bfa63c..a30d559e 100644 --- a/src/rf4ce/ctrlm_rf4ce_pairing.cpp +++ b/src/rf4ce/ctrlm_rf4ce_pairing.cpp @@ -244,7 +244,6 @@ void ctrlm_obj_network_rf4ce_t::ind_process_pair_stb(ctrlm_main_queue_msg_rf4ce_ user_string[CTRLM_HAL_RF4CE_USER_STRING_SIZE - 1] = '\0'; } controller_user_string_set(params.controller_id, (guchar*)user_string); - controller_init_uinput(params.controller_id); } controller_autobind_in_progress_set(params.controller_id, false); controller_binding_button_in_progress_set(params.controller_id, false); @@ -326,7 +325,6 @@ void ctrlm_obj_network_rf4ce_t::ind_process_pair_autobind(ctrlm_main_queue_msg_r // Create the controller object controller_insert(params.controller_id, dqm->params.src_ieee_addr, true); controller_user_string_set(params.controller_id, dqm->params.org_user_string); - controller_init_uinput(params.controller_id); } controller_autobind_in_progress_set(params.controller_id, true); controller_binding_button_in_progress_set(params.controller_id, false); @@ -423,7 +421,6 @@ void ctrlm_obj_network_rf4ce_t::ind_process_pair_binding_button(ctrlm_main_queue user_string[CTRLM_HAL_RF4CE_USER_STRING_SIZE - 1] = '\0'; } controller_user_string_set(params.controller_id, (guchar*)user_string); - controller_init_uinput(params.controller_id); } controller_autobind_in_progress_set(params.controller_id, false); controller_binding_button_in_progress_set(params.controller_id, true); @@ -506,7 +503,6 @@ void ctrlm_obj_network_rf4ce_t::ind_process_pair_screen_bind(ctrlm_main_queue_ms // Create the controller object controller_insert(params.controller_id, dqm->params.src_ieee_addr, true); controller_user_string_set(params.controller_id, dqm->params.org_user_string); - controller_init_uinput(params.controller_id); } controller_autobind_in_progress_set(params.controller_id, false); controller_binding_button_in_progress_set(params.controller_id, false); diff --git a/src/rf4ce/ctrlm_rf4ce_rib.cpp b/src/rf4ce/ctrlm_rf4ce_rib.cpp index 4eaab800..77b86293 100644 --- a/src/rf4ce/ctrlm_rf4ce_rib.cpp +++ b/src/rf4ce/ctrlm_rf4ce_rib.cpp @@ -294,6 +294,7 @@ void ctrlm_obj_controller_rf4ce_t::rf4ce_rib_get(gboolean target, ctrlm_timestam ctrlm_inform_configuration_complete(network_id_get(), controller_id_get(), CTRLM_RCU_CONFIGURATION_RESULT_SUCCESS); obj_network_rf4ce_->set_rf_pair_state(CTRLM_RF_PAIR_STATE_COMPLETE); obj_network_rf4ce_->iarm_event_rcu_status(); + init_uinput_writer(); } } } From 7706a0cfc7af9823854d5f6865bb5548a0543494 Mon Sep 17 00:00:00 2001 From: Gene Gallagher <129112619+egalla204@users.noreply.github.com> Date: Wed, 11 Feb 2026 13:47:15 -0500 Subject: [PATCH 30/81] RDKEMW-13881: update CHANGELOG for release v1.1.10 (#178) --- CHANGELOG.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2548677a..ef7ba7f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,10 +6,21 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). -> 13 January 2026 +#### [1.1.10](https://github.com/rdkcentral/control/compare/1.1.9...1.1.10) + +> 11 February 2026 + +- RDKEMW-12828: device minor id, vendor, and product value updates [`#175`](https://github.com/rdkcentral/control/pull/175) +- RDKEMW-13049: remove RCU firmware upgrade retries on failure [`#173`](https://github.com/rdkcentral/control/pull/173) +- RDKEMW-9474: ctrlm multiple simultaneous IR databases [`#161`](https://github.com/rdkcentral/control/pull/161) +- RDKEMW-11792 : FFV config file isolation [`#165`](https://github.com/rdkcentral/control/pull/165) +- RDKEMW-12457: No longer ignoring device re-pair if it's already paired and connected. [`#171`](https://github.com/rdkcentral/control/pull/171) +- RDKEMW-9843: report loaded and unloaded voltage from RCU [`#163`](https://github.com/rdkcentral/control/pull/163) #### [1.1.9](https://github.com/rdkcentral/control/compare/1.1.8...1.1.9) +> 13 January 2026 + - RDKEMW-11471: Remove netType param [`#164`](https://github.com/rdkcentral/control/pull/164) - RDKEMW-10631: Filter out unpaired devices when reconnecting all devices [`fc1c94a`](https://github.com/rdkcentral/control/commit/fc1c94a8e2de9b196a5f274316eaee5c07c2fbf5) From d5d14f05aee9e76bf1a44660c743f4811f373677 Mon Sep 17 00:00:00 2001 From: Kelvin Lu <119349872+klu339@users.noreply.github.com> Date: Wed, 18 Feb 2026 11:27:05 -0500 Subject: [PATCH 31/81] RDKEMW-13833: Remove duplicate RFC fetch attempts in listeners (#179) --- src/ctrlm_main.cpp | 1 - src/voice/ctrlm_voice_obj.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/src/ctrlm_main.cpp b/src/ctrlm_main.cpp index 4c9d9faa..f76c3682 100644 --- a/src/ctrlm_main.cpp +++ b/src/ctrlm_main.cpp @@ -1986,7 +1986,6 @@ void ctrlm_global_rfc_values_retrieved(const ctrlm_rfc_attr_t &attr) { if(attr.get_rfc_value(JSON_ARRAY_NAME_CTRLM_GLOBAL_MASK_PII, g_ctrlm.mask_pii, ctrlm_is_production_build() ? CTRLM_JSON_ARRAY_INDEX_PRD : CTRLM_JSON_ARRAY_INDEX_DEV)) { g_ctrlm.voice_session->voice_stb_data_pii_mask_set(g_ctrlm.mask_pii); } - attr.get_rfc_value(JSON_INT_NAME_CTRLM_GLOBAL_AUTHSERVICE_POLL_PERIOD, g_ctrlm.authservice_poll_val); attr.get_rfc_value(JSON_INT_NAME_CTRLM_GLOBAL_AUTHSERVICE_FAST_POLL_PERIOD, g_ctrlm.authservice_fast_poll_val); attr.get_rfc_value(JSON_INT_NAME_CTRLM_GLOBAL_AUTHSERVICE_FAST_MAX_RETRIES, g_ctrlm.authservice_fast_retries_max); } diff --git a/src/voice/ctrlm_voice_obj.cpp b/src/voice/ctrlm_voice_obj.cpp index ba00c02b..1af6f059 100644 --- a/src/voice/ctrlm_voice_obj.cpp +++ b/src/voice/ctrlm_voice_obj.cpp @@ -4085,7 +4085,6 @@ void ctrlm_voice_t::voice_rfc_retrieved_handler(const ctrlm_rfc_attr_t& attr) { this->url_hostname_patterns(obj_server_hosts); } - attr.get_rfc_value(JSON_BOOL_NAME_VOICE_FORCE_VOICE_SETTINGS, this->prefs.force_voice_settings); if(attr.get_rfc_value(JSON_BOOL_NAME_VOICE_FORCE_VOICE_SETTINGS, this->prefs.force_voice_settings) && this->prefs.force_voice_settings) { attr.get_rfc_value(JSON_BOOL_NAME_VOICE_ENABLE, enabled); attr.get_rfc_value(JSON_STR_NAME_VOICE_URL_SRC_PTT, this->prefs.server_url_src_ptt); From 2eaa356a595428d56a4486dc6004c3a1b633f963 Mon Sep 17 00:00:00 2001 From: Kelvin Lu <119349872+klu339@users.noreply.github.com> Date: Thu, 19 Feb 2026 09:50:33 -0500 Subject: [PATCH 32/81] RDKEMW-12930: RF4CE network export XCONF on pair/unpair/etc. (#177) --- src/rf4ce/ctrlm_rf4ce_device_update.cpp | 8 ++++++++ src/rf4ce/ctrlm_rf4ce_network.cpp | 7 +++++++ src/rf4ce/ctrlm_rf4ce_pairing.cpp | 8 ++++++++ src/rf4ce/ctrlm_rf4ce_rcu.cpp | 15 +++++++++++++++ 4 files changed, 38 insertions(+) diff --git a/src/rf4ce/ctrlm_rf4ce_device_update.cpp b/src/rf4ce/ctrlm_rf4ce_device_update.cpp index 81391246..c2d232eb 100644 --- a/src/rf4ce/ctrlm_rf4ce_device_update.cpp +++ b/src/rf4ce/ctrlm_rf4ce_device_update.cpp @@ -549,6 +549,14 @@ void ctrlm_obj_controller_rf4ce_t::device_update_image_download_complete(ctrlm_t } } + ctrlm_main_queue_msg_header_t *msg = (ctrlm_main_queue_msg_header_t *)g_malloc(sizeof(ctrlm_main_queue_msg_header_t)); + if(msg == NULL) { + XLOGD_ERROR("Out of memory"); + } else { + msg->type = CTRLM_MAIN_QUEUE_MSG_TYPE_EXPORT_CONTROLLER_LIST; + ctrlm_main_queue_msg_push((gpointer)msg); + } + print_remote_firmware_debug_info(RF4CE_PRINT_FIRMWARE_LOG_IMAGE_DOWNLOAD_COMPLETE, log_string); if(download_in_progress_) { // End the download session since the controller has finished loading the image diff --git a/src/rf4ce/ctrlm_rf4ce_network.cpp b/src/rf4ce/ctrlm_rf4ce_network.cpp index de3adb73..5009c592 100644 --- a/src/rf4ce/ctrlm_rf4ce_network.cpp +++ b/src/rf4ce/ctrlm_rf4ce_network.cpp @@ -1445,6 +1445,13 @@ void ctrlm_obj_network_rf4ce_t::factory_reset(void) { // Delete control manager persistent data // TODO + ctrlm_main_queue_msg_header_t *msg = (ctrlm_main_queue_msg_header_t *)g_malloc(sizeof(ctrlm_main_queue_msg_header_t)); + if(msg == NULL) { + XLOGD_ERROR("Out of memory"); + } else { + msg->type = CTRLM_MAIN_QUEUE_MSG_TYPE_EXPORT_CONTROLLER_LIST; + ctrlm_main_queue_msg_push((gpointer)msg); + } } bool ctrlm_obj_network_rf4ce_t::controller_exists(ctrlm_controller_id_t controller_id) { diff --git a/src/rf4ce/ctrlm_rf4ce_pairing.cpp b/src/rf4ce/ctrlm_rf4ce_pairing.cpp index a30d559e..ae08132d 100644 --- a/src/rf4ce/ctrlm_rf4ce_pairing.cpp +++ b/src/rf4ce/ctrlm_rf4ce_pairing.cpp @@ -678,6 +678,14 @@ void ctrlm_obj_network_rf4ce_t::ind_process_unpair(void *data, int size) { //ctr controller_unbind(controller_id, CTRLM_UNBIND_REASON_CONTROLLER); params.result = CTRLM_HAL_RESULT_UNPAIR_SUCCESS; + + ctrlm_main_queue_msg_header_t *msg = (ctrlm_main_queue_msg_header_t *)g_malloc(sizeof(ctrlm_main_queue_msg_header_t)); + if(msg == NULL) { + XLOGD_ERROR("Out of memory"); + } else { + msg->type = CTRLM_MAIN_QUEUE_MSG_TYPE_EXPORT_CONTROLLER_LIST; + ctrlm_main_queue_msg_push((gpointer)msg); + } } ctrlm_network_queue_deliver_result_unpair(dqm, params); diff --git a/src/rf4ce/ctrlm_rf4ce_rcu.cpp b/src/rf4ce/ctrlm_rf4ce_rcu.cpp index 767f0ea3..ae352a67 100644 --- a/src/rf4ce/ctrlm_rf4ce_rcu.cpp +++ b/src/rf4ce/ctrlm_rf4ce_rcu.cpp @@ -479,6 +479,13 @@ void ctrlm_obj_network_rf4ce_t::ind_process_data_rcu(ctrlm_main_queue_msg_rf4ce_ function == CTRLM_RCU_FUNCTION_MODE_CLIP_DISCOVERY) { // Unbind the controller since it has effectively unpaired controller_unbind(dqm->controller_id, CTRLM_UNBIND_REASON_CONTROLLER_RESET); + ctrlm_main_queue_msg_header_t *msg = (ctrlm_main_queue_msg_header_t *)g_malloc(sizeof(ctrlm_main_queue_msg_header_t)); + if(msg == NULL) { + XLOGD_ERROR("Out of memory"); + } else { + msg->type = CTRLM_MAIN_QUEUE_MSG_TYPE_EXPORT_CONTROLLER_LIST; + ctrlm_main_queue_msg_push((gpointer)msg); + } } if((function != CTRLM_RCU_FUNCTION_INVALID) && (function != CTRLM_RCU_FUNCTION_INVALID_KEY_COMBO)) { @@ -579,6 +586,14 @@ void ctrlm_obj_network_rf4ce_t::ind_process_data_rcu(ctrlm_main_queue_msg_rf4ce_ controllers_[dqm->controller_id]->rib_configuration_complete(dqm->timestamp, (ctrlm_rf4ce_rib_configuration_complete_status_t)cmd_data[1]); set_rf_pair_state(CTRLM_RF_PAIR_STATE_COMPLETE); iarm_event_rcu_status(); + + ctrlm_main_queue_msg_header_t *msg = (ctrlm_main_queue_msg_header_t *)g_malloc(sizeof(ctrlm_main_queue_msg_header_t)); + if(msg == NULL) { + XLOGD_ERROR("Out of memory"); + } else { + msg->type = CTRLM_MAIN_QUEUE_MSG_TYPE_EXPORT_CONTROLLER_LIST; + ctrlm_main_queue_msg_push((gpointer)msg); + } break; } default: { From add759e3a88fd6cddee80b7f9996ef0ecdb1f427 Mon Sep 17 00:00:00 2001 From: Kelvin Lu <119349872+klu339@users.noreply.github.com> Date: Thu, 19 Feb 2026 09:59:53 -0500 Subject: [PATCH 33/81] RDKEMW-13753: Report manually set IRDB codes RF4CE remotes (#176) --- src/rf4ce/ctrlm_rf4ce_controller.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/rf4ce/ctrlm_rf4ce_controller.cpp b/src/rf4ce/ctrlm_rf4ce_controller.cpp index 08217279..960b3fd2 100644 --- a/src/rf4ce/ctrlm_rf4ce_controller.cpp +++ b/src/rf4ce/ctrlm_rf4ce_controller.cpp @@ -2756,6 +2756,12 @@ void ctrlm_obj_controller_rf4ce_t::controller_product_name_updated(const ctrlm_r void ctrlm_obj_controller_rf4ce_t::controller_irdb_status_updated(const ctrlm_rf4ce_controller_irdb_status_t& status) { if(controller_type_ != RF4CE_CONTROLLER_TYPE_XR19) { obj_network_rf4ce_->target_irdb_status_set(*controller_irdb_status_); + if(controller_irdb_status_->is_flag_set(ctrlm_rf4ce_controller_irdb_status_t::flag::IR_DB_CODE_TV)) { + irdb_entry_id_name_set(CTRLM_IRDB_DEV_TYPE_TV, controller_irdb_status_->get_tv_code_str()); + } + if(controller_irdb_status_->is_flag_set(ctrlm_rf4ce_controller_irdb_status_t::flag::IR_DB_CODE_AVR)) { + irdb_entry_id_name_set(CTRLM_IRDB_DEV_TYPE_AVR, controller_irdb_status_->get_avr_code_str()); + } } } From 5a90734ed30bbd6087df9f2c8d75fe05bbce4184 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Thu, 19 Feb 2026 12:02:47 -0500 Subject: [PATCH 34/81] RDKEMW-11359: Logging proximity key as debug instead of telemetry (#167) --- src/ctrlm_controller.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/ctrlm_controller.cpp b/src/ctrlm_controller.cpp index 8048ac2c..15496dd3 100644 --- a/src/ctrlm_controller.cpp +++ b/src/ctrlm_controller.cpp @@ -172,11 +172,18 @@ void ctrlm_obj_controller_t::process_event_key(ctrlm_key_status_t key_status, ui last_key_code_->set_value((uint64_t)key_code); last_key_time_update(); - XLOGD_AUTOMATION_TELEMETRY("ind_process_keypress: %s - MAC Address <%s>, code = <%d> (%s key), status = <%s>", controller_type_str_get().c_str(), - ieee_address_get().to_string().c_str(), - mask ? -1 : key_code, - ctrlm_linux_key_code_str(key_code, mask), - ctrlm_key_status_str(key_status)); + xlog_level_t level = XLOG_LEVEL_TELEMETRY; + const char *color = XLOG_COLOR_BLU; + // Proximity key (KEY_F17) is logged to debug while the rest is logged to telemetry + if(key_code == KEY_F17) { + level = XLOG_LEVEL_DEBUG; + color = XLOG_COLOR_GRN; + } + XLOGD(level, XLOG_OPTS_DEFAULT, color, XLOG_BUF_SIZE_DEFAULT, "ind_process_keypress: %s - MAC Address <%s>, code = <%d> (%s key), status = <%s>", controller_type_str_get().c_str(), + ieee_address_get().to_string().c_str(), + mask ? -1 : key_code, + ctrlm_linux_key_code_str(key_code, mask), + ctrlm_key_status_str(key_status)); } ctrlm_controller_capabilities_t ctrlm_obj_controller_t::get_capabilities() const { From 1f68214bb3c6d62be72ea3c8cbde7ae86747cd2d Mon Sep 17 00:00:00 2001 From: jthomp007c Date: Thu, 5 Mar 2026 11:04:42 -0500 Subject: [PATCH 35/81] RDKEMW-14445 : Add session end and protocol return to telemetry (#182) * RDKEMW-14445 : Add session end and protocol return to telemetry Reason for change: ctrlm currently does not know why xrsr might have ended a session. Also it does not know what protocol error may have occurred only that one did. Test Procedure: check telemetry for new fields, parse them, confirm that new data exists and is correct Priority: P0 Signed-off-by: Jason Thomson * Fixing whitespace * Order of vars * Update telemetry markers version number * Reverting enum name change * Renaming vars for clarity, reordering vars for consistency * Fix whitespace * Adding stream end reason to telemetry log * Adding stream reason end to telemetry --------- Signed-off-by: Jason Thomson --- include/ctrlm_ipc_voice.h | 2 +- src/telemetry/ctrlm_telemetry_markers.h | 2 +- src/voice/ctrlm_voice_obj.cpp | 28 +++++++++---------- src/voice/ctrlm_voice_obj.h | 2 +- .../endpoints/ctrlm_voice_endpoint_http.cpp | 2 +- .../ctrlm_voice_endpoint_ws_nextgen.cpp | 2 +- .../endpoints/ctrlm_voice_endpoint_ws_nsp.cpp | 2 +- .../ctrlm_voice_telemetry_events.cpp | 21 ++++++++------ .../telemetry/ctrlm_voice_telemetry_events.h | 8 ++++-- 9 files changed, 38 insertions(+), 31 deletions(-) diff --git a/include/ctrlm_ipc_voice.h b/include/ctrlm_ipc_voice.h index 270b92d9..665ffaa5 100644 --- a/include/ctrlm_ipc_voice.h +++ b/include/ctrlm_ipc_voice.h @@ -228,7 +228,7 @@ typedef struct { ctrlm_network_type_t network_type; ///< Type of network on which the controller is bound ctrlm_controller_id_t controller_id; ///< A unique identifier of the remote unsigned long session_id; ///< A unique id for the voice session. - ctrlm_voice_session_end_reason_t reason; ///< The reason for ending + ctrlm_voice_session_end_reason_t reason; ///< The reason for ending session unsigned char is_voice_assistant; ///< Boolean indicating if the device is a far-field device (1) as opposed to a hand-held remote (0). } ctrlm_voice_iarm_event_session_end_t; diff --git a/src/telemetry/ctrlm_telemetry_markers.h b/src/telemetry/ctrlm_telemetry_markers.h index 9c0ba3a3..23c0f775 100644 --- a/src/telemetry/ctrlm_telemetry_markers.h +++ b/src/telemetry/ctrlm_telemetry_markers.h @@ -117,7 +117,7 @@ // - server message. // - flag to indicate if session was successful. #define MARKER_VOICE_SESSION_STATS "ctrlm.voice.session.stats" -#define MARKER_VOICE_SESSION_STATS_VERSION "1" +#define MARKER_VOICE_SESSION_STATS_VERSION "2" // End Voice Session Statistics diff --git a/src/voice/ctrlm_voice_obj.cpp b/src/voice/ctrlm_voice_obj.cpp index 1af6f059..6e4b354f 100644 --- a/src/voice/ctrlm_voice_obj.cpp +++ b/src/voice/ctrlm_voice_obj.cpp @@ -95,7 +95,7 @@ ctrlm_voice_t::ctrlm_voice_t() { session->session_active_controller = false; session->state_src = CTRLM_VOICE_STATE_SRC_INVALID; session->state_dst = CTRLM_VOICE_STATE_DST_INVALID; - session->end_reason = CTRLM_VOICE_SESSION_END_REASON_DONE; + session->end_reason_rcu = CTRLM_VOICE_SESSION_END_REASON_DONE; session->audio_pipe[PIPE_READ] = -1; session->audio_pipe[PIPE_WRITE] = -1; @@ -1872,7 +1872,7 @@ void ctrlm_voice_t::voice_session_end(ctrlm_voice_session_t *session, ctrlm_voic return; } - session->end_reason = reason; + session->end_reason_rcu = reason; if(timestamp != NULL) { session->session_timing.ctrl_stop = *timestamp; @@ -2522,7 +2522,7 @@ void ctrlm_voice_t::voice_session_begin_callback(ctrlm_voice_session_begin_cb_t session->ipc_common_data.voice_assistant = is_voice_assistant(session->voice_device); session->ipc_common_data.device_type = session->voice_device; session->endpoint_current = session_begin->endpoint; - session->end_reason = CTRLM_VOICE_SESSION_END_REASON_DONE; + session->end_reason_rcu = CTRLM_VOICE_SESSION_END_REASON_DONE; errno_t safec_rc = memset_s(&session->status, sizeof(session->status), 0 , sizeof(session->status)); ERR_CHK(safec_rc); @@ -2625,7 +2625,7 @@ void ctrlm_voice_t::voice_session_end_callback(ctrlm_voice_session_end_cb_t *ses if(command_status == VOICE_COMMAND_STATUS_PENDING) { switch(session->voice_device) { case CTRLM_VOICE_DEVICE_FF: { - session->status.status = (stats->reason == XRSR_SESSION_END_REASON_EOS) ? VOICE_COMMAND_STATUS_SUCCESS : VOICE_COMMAND_STATUS_FAILURE; + session->status.status = (stats->session_end_reason == XRSR_SESSION_END_REASON_EOS) ? VOICE_COMMAND_STATUS_SUCCESS : VOICE_COMMAND_STATUS_FAILURE; command_status = session->status.status; this->voice_status_set(session); break; @@ -2642,9 +2642,9 @@ void ctrlm_voice_t::voice_session_end_callback(ctrlm_voice_session_end_cb_t *ses } if(session->voice_device == CTRLM_VOICE_DEVICE_MICROPHONE || session->voice_device == CTRLM_VOICE_DEVICE_MICROPHONE_TAP) { - XLOGD_INFO("src <%s> reason <%s> voice command status <%s>", ctrlm_voice_device_str(session->voice_device), xrsr_session_end_reason_str(stats->reason), ctrlm_voice_command_status_str(command_status)); + XLOGD_INFO("src <%s> reason <%s> voice command status <%s>", ctrlm_voice_device_str(session->voice_device), xrsr_session_end_reason_str(stats->session_end_reason), ctrlm_voice_command_status_str(command_status)); } else { - XLOGD_INFO("src <%s> audio sent bytes <%u> samples <%u> reason <%s> voice command status <%s>", ctrlm_voice_device_str(session->voice_device), session->audio_sent_bytes, session->audio_sent_samples, xrsr_session_end_reason_str(stats->reason), ctrlm_voice_command_status_str(command_status)); + XLOGD_INFO("src <%s> audio sent bytes <%u> samples <%u> reason <%s> voice command status <%s>", ctrlm_voice_device_str(session->voice_device), session->audio_sent_bytes, session->audio_sent_samples, xrsr_session_end_reason_str(stats->session_end_reason), ctrlm_voice_command_status_str(command_status)); } // Update device status @@ -2657,18 +2657,18 @@ void ctrlm_voice_t::voice_session_end_callback(ctrlm_voice_session_end_cb_t *ses // Send Results IARM Event if(this->voice_ipc) { - if(stats->reason == XRSR_SESSION_END_REASON_ERROR_AUDIO_DURATION) { + if(stats->session_end_reason == XRSR_SESSION_END_REASON_ERROR_AUDIO_DURATION) { ctrlm_voice_ipc_event_session_end_t end; end.common = session->ipc_common_data; end.result = SESSION_END_SHORT_UTTERANCE; - end.reason = (int)session->end_reason; + end.reason = (int)session->end_reason_rcu; this->voice_ipc->session_end(end); } else { ctrlm_voice_ipc_event_session_end_server_stats_t server_stats; ctrlm_voice_ipc_event_session_end_t end; end.common = session->ipc_common_data; end.result = (session_end->success ? SESSION_END_SUCCESS : SESSION_END_FAILURE); - end.reason = stats->reason; + end.reason = stats->session_end_reason; end.return_code_protocol = stats->ret_code_protocol; end.return_code_protocol_library = stats->ret_code_library; end.return_code_server = session->server_ret_code; @@ -2690,7 +2690,7 @@ void ctrlm_voice_t::voice_session_end_callback(ctrlm_voice_session_end_cb_t *ses // Update controller metrics ctrlm_main_queue_msg_controller_voice_metrics_t metrics = {0}; metrics.controller_id = session->controller_id; - metrics.short_utterance = (stats->reason == XRSR_SESSION_END_REASON_ERROR_AUDIO_DURATION ? 1 : 0); + metrics.short_utterance = (stats->session_end_reason == XRSR_SESSION_END_REASON_ERROR_AUDIO_DURATION ? 1 : 0); metrics.packets_total = session->packets_processed + session->packets_lost; metrics.packets_lost = session->packets_lost; @@ -2719,8 +2719,8 @@ void ctrlm_voice_t::voice_session_end_callback(ctrlm_voice_session_end_cb_t *ses if(telemetry) { ctrlm_telemetry_event_t vs_marker(MARKER_VOICE_SESSION_TOTAL, 1); ctrlm_telemetry_event_t vs_status_marker(session_end->success ? MARKER_VOICE_SESSION_SUCCESS : MARKER_VOICE_SESSION_FAILURE, 1); - ctrlm_telemetry_event_t vs_end_reason_marker(MARKER_VOICE_END_REASON_PREFIX + std::string(ctrlm_voice_session_end_reason_str(session->end_reason)), 1); - ctrlm_telemetry_event_t vs_xrsr_end_reason_marker(MARKER_VOICE_XRSR_END_REASON_PREFIX + std::string(xrsr_session_end_reason_str(stats->reason)), 1); + ctrlm_telemetry_event_t vs_end_reason_marker(MARKER_VOICE_END_REASON_PREFIX + std::string(ctrlm_voice_session_end_reason_str(session->end_reason_rcu)), 1); + ctrlm_telemetry_event_t vs_xrsr_end_reason_marker(MARKER_VOICE_XRSR_END_REASON_PREFIX + std::string(xrsr_session_end_reason_str(stats->session_end_reason)), 1); // Handle all VSRsp error telemetry if(session->current_vsr_err_string != "") { @@ -2745,7 +2745,7 @@ void ctrlm_voice_t::voice_session_end_callback(ctrlm_voice_session_end_cb_t *ses telemetry->event(ctrlm_telemetry_report_t::VOICE, vs_xrsr_end_reason_marker); if(this->prefs.telemetry_session_stats) { - if(!session->telemetry_session_stats.update_on_session_end(session_end->success, session->end_reason, stats->reason, session->server_ret_code, session->server_message, session->stats_session.voice_key_held_ms)) { + if(!session->telemetry_session_stats.update_on_session_end(session_end->success, session->end_reason_rcu, stats->session_end_reason, session->server_ret_code, session->server_message, session->stats_session.voice_key_held_ms, stats->ret_code_protocol, stats->stream_end_reason)) { XLOGD_ERROR("failed to generate session stats event"); } } @@ -2980,7 +2980,7 @@ void ctrlm_voice_t::voice_stream_end_callback(ctrlm_voice_stream_end_cb_t *strea // This is a STREAM end.. ctrlm_voice_ipc_event_stream_end_t end; end.common = session->ipc_common_data; - end.reason = (int)session->end_reason; + end.reason = (int)session->end_reason_rcu; this->voice_ipc->stream_end(end); } diff --git a/src/voice/ctrlm_voice_obj.h b/src/voice/ctrlm_voice_obj.h index c4395b18..38699a6b 100644 --- a/src/voice/ctrlm_voice_obj.h +++ b/src/voice/ctrlm_voice_obj.h @@ -443,7 +443,7 @@ typedef struct { uint32_t packets_lost; uint32_t lqi_total; - ctrlm_voice_session_end_reason_t end_reason; + ctrlm_voice_session_end_reason_t end_reason_rcu; bool is_press_and_release; bool is_session_by_text; diff --git a/src/voice/endpoints/ctrlm_voice_endpoint_http.cpp b/src/voice/endpoints/ctrlm_voice_endpoint_http.cpp index 93396a4b..1ec3e647 100644 --- a/src/voice/endpoints/ctrlm_voice_endpoint_http.cpp +++ b/src/voice/endpoints/ctrlm_voice_endpoint_http.cpp @@ -286,7 +286,7 @@ void ctrlm_voice_endpoint_http_t::voice_session_end_callback_http(void *data, in } // Check if HTTP was successful - if((stats->reason != XRSR_SESSION_END_REASON_EOS && stats->reason != XRSR_SESSION_END_REASON_TERMINATE && stats->reason != XRSR_SESSION_END_REASON_EOT) + if((stats->session_end_reason != XRSR_SESSION_END_REASON_EOS && stats->session_end_reason != XRSR_SESSION_END_REASON_TERMINATE && stats->session_end_reason != XRSR_SESSION_END_REASON_EOT) || (stats->ret_code_library != 0) || (stats->ret_code_protocol != 200) || (this->server_ret_code != 0)) { success = false; } diff --git a/src/voice/endpoints/ctrlm_voice_endpoint_ws_nextgen.cpp b/src/voice/endpoints/ctrlm_voice_endpoint_ws_nextgen.cpp index fcf9b12a..e5165cd7 100644 --- a/src/voice/endpoints/ctrlm_voice_endpoint_ws_nextgen.cpp +++ b/src/voice/endpoints/ctrlm_voice_endpoint_ws_nextgen.cpp @@ -460,7 +460,7 @@ void ctrlm_voice_endpoint_ws_nextgen_t::voice_session_end_callback_ws_nextgen(vo } // Check if WS was successful - if((stats->reason != XRSR_SESSION_END_REASON_EOS && stats->reason != XRSR_SESSION_END_REASON_EOT) || (this->server_ret_code != 0 && this->server_ret_code != 200)) { + if((stats->session_end_reason != XRSR_SESSION_END_REASON_EOS && stats->session_end_reason != XRSR_SESSION_END_REASON_EOT) || (this->server_ret_code != 0 && this->server_ret_code != 200)) { success = false; } diff --git a/src/voice/endpoints/ctrlm_voice_endpoint_ws_nsp.cpp b/src/voice/endpoints/ctrlm_voice_endpoint_ws_nsp.cpp index da4d4035..a123c0d6 100644 --- a/src/voice/endpoints/ctrlm_voice_endpoint_ws_nsp.cpp +++ b/src/voice/endpoints/ctrlm_voice_endpoint_ws_nsp.cpp @@ -203,7 +203,7 @@ void ctrlm_voice_endpoint_ws_nsp_t::voice_session_end_callback_ws_nsp(void *data } // Check if WS was successful - if((stats->reason != XRSR_SESSION_END_REASON_DISCONNECT_REMOTE) || (this->server_ret_code != 0 && this->server_ret_code != 200)) { + if((stats->session_end_reason != XRSR_SESSION_END_REASON_DISCONNECT_REMOTE) || (this->server_ret_code != 0 && this->server_ret_code != 200)) { success = false; } diff --git a/src/voice/telemetry/ctrlm_voice_telemetry_events.cpp b/src/voice/telemetry/ctrlm_voice_telemetry_events.cpp index e7ac6e71..d5f6bba3 100644 --- a/src/voice/telemetry/ctrlm_voice_telemetry_events.cpp +++ b/src/voice/telemetry/ctrlm_voice_telemetry_events.cpp @@ -206,11 +206,13 @@ bool ctrlm_voice_telemetry_session_t::event() { ss << m_samples_lost << ","; ss << m_decoder_failures << ","; ss << m_samples_buffered_max << ","; - ss << m_end_reason_stream << ","; - ss << m_end_reason_protocol << ","; + ss << m_end_reason_rcu << ","; + ss << m_end_reason_session << ","; ss << m_end_reason_server << ","; ss << "\"" << m_server_message << "\","; - ss << m_result << "]]"; + ss << m_result << ","; + ss << m_end_reason_stream << ","; + ss << m_ret_code_protocol << "]]"; if(m_event_list.length() + ss.str().length() > m_event_list_max_size) { // Maximum data size exceeded XLOGD_WARN("telemetry event exceeds max size <%s,%s>", val_marker.c_str(), ss.str().c_str()); @@ -279,12 +281,14 @@ void ctrlm_voice_telemetry_session_t::update_on_stream_end(uint32_t time_stream_ } } -bool ctrlm_voice_telemetry_session_t::update_on_session_end(bool result, int32_t end_reason_stream, int32_t end_reason_protocol, int32_t end_reason_server, const std::string &server_message, int32_t time_stream_len_exp) { +bool ctrlm_voice_telemetry_session_t::update_on_session_end(bool result, int32_t end_reason_rcu, int32_t end_reason_session, int32_t end_reason_server, const std::string &server_message, int32_t time_stream_len_exp, int32_t ret_code_protocol, int32_t stream_end_reason) { m_result = result; - m_end_reason_stream = end_reason_stream; - m_end_reason_protocol = end_reason_protocol; + m_end_reason_rcu = end_reason_rcu; + m_end_reason_session = end_reason_session; m_end_reason_server = end_reason_server; m_server_message = server_message; + m_ret_code_protocol = ret_code_protocol; + m_end_reason_stream = stream_end_reason; if(!m_has_key_release) { // if there is no key release, the start time and end time are not known rdkx_timestamp_get(&m_time_prev_session_end); @@ -310,10 +314,11 @@ void ctrlm_voice_telemetry_session_t::reset_stats() { m_decoder_failures = 0; m_samples_buffered_max = 0; - m_end_reason_stream = 0; - m_end_reason_protocol = 0; + m_end_reason_rcu = 0; + m_end_reason_session = 0; m_end_reason_server = 0; m_result = false; + m_ret_code_protocol = 0; m_server_message.clear(); m_device_type.clear(); diff --git a/src/voice/telemetry/ctrlm_voice_telemetry_events.h b/src/voice/telemetry/ctrlm_voice_telemetry_events.h index d8bf90dd..adadfde6 100644 --- a/src/voice/telemetry/ctrlm_voice_telemetry_events.h +++ b/src/voice/telemetry/ctrlm_voice_telemetry_events.h @@ -76,7 +76,7 @@ class ctrlm_voice_telemetry_session_t : public ctrlm_telemetry_event_t Date: Thu, 5 Mar 2026 13:36:54 -0500 Subject: [PATCH 36/81] RDKEMW-14589: No UI action with "Info" keypress from rf4ce remote in RF mode (#181) --- src/input_event/ctrlm_input_event_writer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/input_event/ctrlm_input_event_writer.h b/src/input_event/ctrlm_input_event_writer.h index a9bc4064..2f6c89cc 100644 --- a/src/input_event/ctrlm_input_event_writer.h +++ b/src/input_event/ctrlm_input_event_writer.h @@ -66,7 +66,7 @@ const std::map ctrlm_key_to_linux_map {CTRLM_KEY_CODE_CH_DOWN, linux_ui_code_values_t(KEY_PAGEDOWN, 0x59, KEY_LEFTCTRL)}, {CTRLM_KEY_CODE_LAST, linux_ui_code_values_t(KEY_ESC, 0x0, KEY_LEFTCTRL)}, {CTRLM_KEY_CODE_INPUT_SELECT, linux_ui_code_values_t(KEY_F15, 0x0, KEY_RESERVED)}, - {CTRLM_KEY_CODE_INFO, linux_ui_code_values_t(KEY_F20, 0x0, KEY_RESERVED)}, + {CTRLM_KEY_CODE_INFO, linux_ui_code_values_t(KEY_F9, 0x0, KEY_RESERVED)}, {CTRLM_KEY_CODE_VOL_UP, linux_ui_code_values_t(KEY_KPPLUS, 0x0, KEY_RESERVED)}, {CTRLM_KEY_CODE_VOL_DOWN, linux_ui_code_values_t(KEY_KPMINUS, 0x0, KEY_RESERVED)}, {CTRLM_KEY_CODE_MUTE, linux_ui_code_values_t(KEY_KPASTERISK, 0x0, KEY_RESERVED)}, From 6dcab578a94365e2da2619c05ed85bc817711f86 Mon Sep 17 00:00:00 2001 From: Gene Gallagher Date: Thu, 5 Mar 2026 14:42:15 -0500 Subject: [PATCH 37/81] 1.1.11 release changelog updates --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef7ba7f2..be2c769d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [1.1.11](https://github.com/rdkcentral/control/compare/1.1.10...1.1.11) + +- RDKEMW-14589: No UI action with "Info" keypress from rf4ce remote in RF mode [`#181`](https://github.com/rdkcentral/control/pull/181) +- RDKEMW-14445 : Add session end and protocol return to telemetry [`#182`](https://github.com/rdkcentral/control/pull/182) +- RDKEMW-11359: Logging proximity key as debug instead of telemetry [`#167`](https://github.com/rdkcentral/control/pull/167) +- RDKEMW-13753: Report manually set IRDB codes RF4CE remotes [`#176`](https://github.com/rdkcentral/control/pull/176) +- RDKEMW-12930: RF4CE network export XCONF on pair/unpair/etc. [`#177`](https://github.com/rdkcentral/control/pull/177) +- RDKEMW-13833: Remove duplicate RFC fetch attempts in listeners [`#179`](https://github.com/rdkcentral/control/pull/179) + #### [1.1.10](https://github.com/rdkcentral/control/compare/1.1.9...1.1.10) From f3b6611c6fd22cff65a2a7cb96b14a669ecc24b4 Mon Sep 17 00:00:00 2001 From: Gene Gallagher Date: Thu, 5 Mar 2026 16:18:54 -0500 Subject: [PATCH 38/81] add date' --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index be2c769d..52e8cb2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). #### [1.1.11](https://github.com/rdkcentral/control/compare/1.1.10...1.1.11) +> 5 March 2026 + - RDKEMW-14589: No UI action with "Info" keypress from rf4ce remote in RF mode [`#181`](https://github.com/rdkcentral/control/pull/181) - RDKEMW-14445 : Add session end and protocol return to telemetry [`#182`](https://github.com/rdkcentral/control/pull/182) - RDKEMW-11359: Logging proximity key as debug instead of telemetry [`#167`](https://github.com/rdkcentral/control/pull/167) From ecd0f6dc4aa5d4a9b4ccb61ced5acfd54a72497c Mon Sep 17 00:00:00 2001 From: jthomp007c Date: Tue, 17 Mar 2026 11:30:03 -0400 Subject: [PATCH 39/81] RDKEMW-5849 : remove deprecated "experience" code (#185) * RDKEMW-5849 : remove deprecated "experience" code Reason for change: the app controls experience, ctrlm does is no longer involved Test Procedure: nothing new to test. Check that normal functionality is not affected Priority; P2 Signed-off-by: Jason Thomson * Align CTRLM_VOICE_QUERY_STRING_MAX_PAIRS with xrsr without including xrsr.h --------- Signed-off-by: Jason Thomson --- CMakeLists.txt | 2 - include/ctrlm_ipc_voice.h | 2 +- src/auth/ctrlm_auth.h | 1 - src/auth/ctrlm_auth_thunder.cpp | 5 -- src/auth/ctrlm_auth_thunder.h | 1 - src/auth/ctrlm_thunder_plugin_authservice.cpp | 18 -------- src/auth/ctrlm_thunder_plugin_authservice.h | 7 --- src/ctrlm.h | 1 - src/ctrlm_controller.cpp | 4 -- src/ctrlm_controller.h | 1 - src/ctrlm_main.cpp | 46 ------------------- src/ctrlm_network.cpp | 10 ---- src/ctrlm_network.h | 3 -- src/voice/ctrlm_voice_obj.cpp | 18 -------- src/voice/ctrlm_voice_obj.h | 3 -- src/voice/endpoints/ctrlm_voice_endpoint.cpp | 1 - src/voice/endpoints/ctrlm_voice_endpoint.h | 1 - .../endpoints/ctrlm_voice_endpoint_http.cpp | 8 ---- .../endpoints/ctrlm_voice_endpoint_http.h | 1 - .../ctrlm_voice_endpoint_ws_nextgen.cpp | 8 ---- .../ctrlm_voice_endpoint_ws_nextgen.h | 1 - 21 files changed, 1 insertion(+), 141 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 565ab874..112b3c00 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -234,8 +234,6 @@ if(THUNDER) if(AUTH_ACTIVATION_STATUS) add_compile_definitions(AUTH_ACTIVATION_STATUS) endif() - #By default disabled but can be enabled - #add_compile_definitions(AUTH_EXPERIENCE) target_link_libraries(controlMgr RdkCertSelector) endif() endif() diff --git a/include/ctrlm_ipc_voice.h b/include/ctrlm_ipc_voice.h index 665ffaa5..ed96c951 100644 --- a/include/ctrlm_ipc_voice.h +++ b/include/ctrlm_ipc_voice.h @@ -64,7 +64,7 @@ #define CTRLM_VOICE_SESSION_TEXT_MAX_LENGTH (512) ///< Session text string maximum length #define CTRLM_VOICE_SESSION_MSG_MAX_LENGTH (128) ///< Session message string maximum length #define CTRLM_VOICE_QUERY_STRING_MAX_LENGTH (128) ///< Query string maximum name or value length -#define CTRLM_VOICE_QUERY_STRING_MAX_PAIRS (16) ///< Query string maximum number of name/value pairs +#define CTRLM_VOICE_QUERY_STRING_MAX_PAIRS (24) ///< Query string maximum number of name/value pairs #define CTRLM_VOICE_REQUEST_IP_MAX_LENGTH (48) ///< cURL request primary IP address string maximum length (big enough for IPv6) #define CTRLM_VOICE_MIN_UTTERANCE_DURATION_MAXIMUM (600) ///< Maximum value of the utterance duration minimum setting (in milliseconds) diff --git a/src/auth/ctrlm_auth.h b/src/auth/ctrlm_auth.h index 0964335f..bda34998 100644 --- a/src/auth/ctrlm_auth.h +++ b/src/auth/ctrlm_auth.h @@ -34,7 +34,6 @@ class ctrlm_auth_t { virtual bool get_device_id(std::string &device_id) = 0; virtual bool get_account_id(std::string &account_id) = 0; virtual bool get_partner_id(std::string &partner_id) = 0; - virtual bool get_experience(std::string &experience) = 0; virtual bool get_sat(std::string &sat, time_t &expiration) = 0; virtual bool supports_sat_expiration() const = 0; diff --git a/src/auth/ctrlm_auth_thunder.cpp b/src/auth/ctrlm_auth_thunder.cpp index 2f954df3..7e37f8b4 100644 --- a/src/auth/ctrlm_auth_thunder.cpp +++ b/src/auth/ctrlm_auth_thunder.cpp @@ -48,11 +48,6 @@ bool ctrlm_auth_thunder_t::get_partner_id(std::string &partner_id) { return(ret); } -bool ctrlm_auth_thunder_t::get_experience(std::string &experience) { - bool ret = this->plugin->get_experience(experience); - return(ret); -} - bool ctrlm_auth_thunder_t::get_sat(std::string &sat, time_t &expiration) { bool ret = this->plugin->get_sat(sat, expiration); return(ret); diff --git a/src/auth/ctrlm_auth_thunder.h b/src/auth/ctrlm_auth_thunder.h index 3a476e67..67a385db 100644 --- a/src/auth/ctrlm_auth_thunder.h +++ b/src/auth/ctrlm_auth_thunder.h @@ -13,7 +13,6 @@ class ctrlm_auth_thunder_t : public ctrlm_auth_t { virtual bool get_device_id(std::string &device_id); virtual bool get_account_id(std::string &account_id); virtual bool get_partner_id(std::string &partner_id); - virtual bool get_experience(std::string &experience); virtual bool get_sat(std::string &sat, time_t &expiration); virtual bool supports_sat_expiration() const; diff --git a/src/auth/ctrlm_thunder_plugin_authservice.cpp b/src/auth/ctrlm_thunder_plugin_authservice.cpp index 60c57d7a..e5913d07 100644 --- a/src/auth/ctrlm_thunder_plugin_authservice.cpp +++ b/src/auth/ctrlm_thunder_plugin_authservice.cpp @@ -125,24 +125,6 @@ bool ctrlm_thunder_plugin_authservice_t::get_account_id(std::string &account_id) return(ret); } -bool ctrlm_thunder_plugin_authservice_t::get_experience(std::string &experience) { - bool ret = false; - JsonObject params, response; - if(this->call_plugin("getExperience", (void *)¶ms, (void *)&response)) { - if(response["success"].Boolean()) { // If success doesn't exist, it defaults to false which is fine. - experience = response["experience"].String(); - if(!experience.empty()) { - ret = true; - } - } else { - XLOGD_WARN("Success for getExperience was false"); - } - } else { - XLOGD_WARN("Call for getExperience failed"); - } - return(ret); -} - bool ctrlm_thunder_plugin_authservice_t::get_sat(std::string &sat, time_t &expiration) { bool ret = false; JsonObject params, response; diff --git a/src/auth/ctrlm_thunder_plugin_authservice.h b/src/auth/ctrlm_thunder_plugin_authservice.h index c39de41d..169cee88 100644 --- a/src/auth/ctrlm_thunder_plugin_authservice.h +++ b/src/auth/ctrlm_thunder_plugin_authservice.h @@ -75,13 +75,6 @@ class ctrlm_thunder_plugin_authservice_t : public Thunder::Plugin::ctrlm_thunder */ bool get_account_id(std::string &account_id); - /** - * Function that retrieves the Experience String from Authservice. - * @param experience The reference to a string which will contain the Experience String. - * @return True on success otherwise False. - */ - bool get_experience(std::string &experience); - /** * Function that retrieves the SAT Token from Authservice. * @param sat The reference to a string which will contain the SAT Token. diff --git a/src/ctrlm.h b/src/ctrlm.h index 905803d1..376608b3 100644 --- a/src/ctrlm.h +++ b/src/ctrlm.h @@ -458,7 +458,6 @@ gboolean ctrlm_main_has_device_id_get(void); gboolean ctrlm_main_has_device_type_get(void); gboolean ctrlm_main_has_service_account_id_get(void); gboolean ctrlm_main_has_partner_id_get(void); -gboolean ctrlm_main_has_experience_get(void); gboolean ctrlm_main_needs_service_access_token_get(void); void ctrlm_main_invalidate_service_access_token(void); void ctrlm_main_sat_enabled_set(gboolean sat_enabled); diff --git a/src/ctrlm_controller.cpp b/src/ctrlm_controller.cpp index 15496dd3..60173d47 100644 --- a/src/ctrlm_controller.cpp +++ b/src/ctrlm_controller.cpp @@ -118,10 +118,6 @@ string ctrlm_obj_controller_t::partner_id_get() const { return(obj_network_->partner_id_get()); } -string ctrlm_obj_controller_t::experience_get() const { - return(obj_network_->experience_get()); -} - string ctrlm_obj_controller_t::stb_name_get() const { return(obj_network_->stb_name_get()); } diff --git a/src/ctrlm_controller.h b/src/ctrlm_controller.h index 66749062..ae9b800b 100644 --- a/src/ctrlm_controller.h +++ b/src/ctrlm_controller.h @@ -63,7 +63,6 @@ class ctrlm_obj_controller_t std::string device_id_get() const; std::string service_account_id_get() const; std::string partner_id_get() const; - std::string experience_get() const; std::string stb_name_get() const; void set_device_minor_id(int device_minor_id); int get_device_minor_id() const; diff --git a/src/ctrlm_main.cpp b/src/ctrlm_main.cpp index f76c3682..c3da8d6d 100644 --- a/src/ctrlm_main.cpp +++ b/src/ctrlm_main.cpp @@ -302,10 +302,6 @@ static void ctrlm_main_has_service_account_id_set(gboolean has_id); static gboolean ctrlm_load_partner_id(void); static void ctrlm_main_has_partner_id_set(gboolean has_id); #endif -#ifdef AUTH_EXPERIENCE -static gboolean ctrlm_load_experience(void); -static void ctrlm_main_has_experience_set(gboolean has_experience); -#endif #ifdef AUTH_SAT_TOKEN static gboolean ctrlm_load_service_access_token(void); static void ctrlm_main_has_service_access_token_set(gboolean has_token); @@ -1421,30 +1417,6 @@ gboolean ctrlm_load_partner_id(void) { } #endif -#ifdef AUTH_EXPERIENCE -gboolean ctrlm_main_has_experience_get(void) { - return(g_ctrlm.has_experience); -} - -void ctrlm_main_has_experience_set(gboolean has_experience) { - g_ctrlm.has_experience = has_experience; -} - -gboolean ctrlm_load_experience(void) { - if(!g_ctrlm.authservice->get_experience(g_ctrlm.experience)) { - ctrlm_main_has_experience_set(false); - return(false); - } - g_ctrlm.voice_session->voice_stb_data_experience_set(g_ctrlm.experience); - - for(auto const &itr : g_ctrlm.networks) { - itr.second->experience_set(g_ctrlm.experience); - } - ctrlm_main_has_experience_set(true); - return(true); -} -#endif - #ifdef AUTH_SAT_TOKEN gboolean ctrlm_main_needs_service_access_token_get(void) { gboolean ret = false; @@ -1510,12 +1482,6 @@ gboolean ctrlm_has_authservice_data(void) { } #endif -#ifdef AUTH_EXPERIENCE - if(!ctrlm_main_has_experience_get()) { - ret = FALSE; - } -#endif - #ifdef AUTH_SAT_TOKEN if(ctrlm_main_needs_service_access_token_get()) { ret = FALSE; @@ -1566,18 +1532,6 @@ gboolean ctrlm_load_authservice_data(void) { } #endif -#ifdef AUTH_EXPERIENCE - if(!ctrlm_main_has_experience_get()) { - XLOGD_INFO("load experience"); - if(!ctrlm_load_experience()) { - XLOGD_TELEMETRY("failed to load experience"); - ret = FALSE; - } else { - XLOGD_INFO("load experience successfully <%s>", ctrlm_is_pii_mask_enabled() ? "***" : g_ctrlm.experience.c_str()); - } - } -#endif - #ifdef AUTH_SAT_TOKEN if(ctrlm_main_needs_service_access_token_get()) { XLOGD_INFO("load sat token"); diff --git a/src/ctrlm_network.cpp b/src/ctrlm_network.cpp index e8f591c3..26201231 100644 --- a/src/ctrlm_network.cpp +++ b/src/ctrlm_network.cpp @@ -187,16 +187,6 @@ string ctrlm_obj_network_t::partner_id_get() const { return(partner_id_); } -void ctrlm_obj_network_t::experience_set(const string& experience) { - THREAD_ID_VALIDATE(); - experience_ = experience; -} - -string ctrlm_obj_network_t::experience_get() const { - THREAD_ID_VALIDATE(); - return(experience_); -} - void ctrlm_obj_network_t::stb_name_set(const string& stb_name) { THREAD_ID_VALIDATE(); XLOGD_INFO("STB Name <%s>", stb_name.c_str()); diff --git a/src/ctrlm_network.h b/src/ctrlm_network.h index 90ea909f..ca6ad547 100644 --- a/src/ctrlm_network.h +++ b/src/ctrlm_network.h @@ -192,8 +192,6 @@ class ctrlm_obj_network_t std::string service_account_id_get() const; void partner_id_set(const std::string& partner_id); std::string partner_id_get() const; - void experience_set(const std::string& experience); - std::string experience_get() const; void mask_key_codes_set(gboolean mask_key_codes); gboolean mask_key_codes_get() const; void stb_name_set(const std::string& stb_name); @@ -325,7 +323,6 @@ class ctrlm_obj_network_t std::string device_id_; std::string service_account_id_; std::string partner_id_; - std::string experience_; std::string stb_name_; ctrlm_rcu_validation_result_t validation_result_ = CTRLM_RCU_VALIDATION_RESULT_MAX; ctrlm_key_code_t validation_key_ = CTRLM_KEY_CODE_INVALID; diff --git a/src/voice/ctrlm_voice_obj.cpp b/src/voice/ctrlm_voice_obj.cpp index 6e4b354f..a6787b1e 100644 --- a/src/voice/ctrlm_voice_obj.cpp +++ b/src/voice/ctrlm_voice_obj.cpp @@ -2252,18 +2252,6 @@ std::string ctrlm_voice_t::voice_stb_data_partner_id_get() const { return(this->partner_id); } -void ctrlm_voice_t::voice_stb_data_experience_set(std::string &experience) { - XLOGD_DEBUG("Experience Tag set to %s", experience.c_str()); - this->experience = experience; - for(const auto &itr : this->endpoints) { - itr->voice_stb_data_experience_set(experience); - } -} - -std::string ctrlm_voice_t::voice_stb_data_experience_get() const { - return(this->experience); -} - std::string ctrlm_voice_t::voice_stb_data_app_id_http_get() const { return(this->prefs.app_id_http); } @@ -2427,12 +2415,6 @@ bool ctrlm_voice_t::voice_session_has_stb_data() { return(false); } #endif -#ifdef AUTH_EXPERIENCE - if(this->experience == "") { - XLOGD_INFO("No experience tag"); - return(false); - } -#endif #ifdef AUTH_SAT_TOKEN if(this->sat_token_required && this->sat_token[0] == '\0') { XLOGD_INFO("No SAT token"); diff --git a/src/voice/ctrlm_voice_obj.h b/src/voice/ctrlm_voice_obj.h index 38699a6b..3ec217b2 100644 --- a/src/voice/ctrlm_voice_obj.h +++ b/src/voice/ctrlm_voice_obj.h @@ -525,8 +525,6 @@ class ctrlm_voice_t { ctrlm_device_type_t voice_stb_data_device_type_get() const; virtual void voice_stb_data_partner_id_set(std::string &partner_id); std::string voice_stb_data_partner_id_get() const; - virtual void voice_stb_data_experience_set(std::string &experience); - std::string voice_stb_data_experience_get() const; std::string voice_stb_data_app_id_http_get() const; std::string voice_stb_data_app_id_ws_get() const; virtual void voice_stb_data_guide_language_set(const char *language); @@ -662,7 +660,6 @@ class ctrlm_voice_t { std::string device_id; ctrlm_device_type_t device_type; std::string partner_id; - std::string experience; char sat_token[XRSR_SAT_TOKEN_LEN_MAX]; bool sat_token_required; bool mtls_required; diff --git a/src/voice/endpoints/ctrlm_voice_endpoint.cpp b/src/voice/endpoints/ctrlm_voice_endpoint.cpp index 7815cd27..1aed8d46 100644 --- a/src/voice/endpoints/ctrlm_voice_endpoint.cpp +++ b/src/voice/endpoints/ctrlm_voice_endpoint.cpp @@ -63,7 +63,6 @@ void ctrlm_voice_endpoint_t::voice_stb_data_account_number_set(std::string &acco void ctrlm_voice_endpoint_t::voice_stb_data_device_id_set(std::string &device_id) {} void ctrlm_voice_endpoint_t::voice_stb_data_device_type_set(ctrlm_device_type_t device_type) {} void ctrlm_voice_endpoint_t::voice_stb_data_partner_id_set(std::string &partner_id) {} -void ctrlm_voice_endpoint_t::voice_stb_data_experience_set(std::string &experience) {} void ctrlm_voice_endpoint_t::voice_stb_data_guide_language_set(const char *language) {} void ctrlm_voice_endpoint_t::voice_stb_data_mask_pii_set(bool enable) {} diff --git a/src/voice/endpoints/ctrlm_voice_endpoint.h b/src/voice/endpoints/ctrlm_voice_endpoint.h index ac881880..3298348f 100644 --- a/src/voice/endpoints/ctrlm_voice_endpoint.h +++ b/src/voice/endpoints/ctrlm_voice_endpoint.h @@ -50,7 +50,6 @@ class ctrlm_voice_endpoint_t { virtual void voice_stb_data_device_id_set(std::string &device_id); virtual void voice_stb_data_device_type_set(ctrlm_device_type_t device_type); virtual void voice_stb_data_partner_id_set(std::string &partner_id); - virtual void voice_stb_data_experience_set(std::string &experience); virtual void voice_stb_data_guide_language_set(const char *language); virtual void voice_stb_data_mask_pii_set(bool enable); // End Data Setters diff --git a/src/voice/endpoints/ctrlm_voice_endpoint_http.cpp b/src/voice/endpoints/ctrlm_voice_endpoint_http.cpp index 1ec3e647..c119ee43 100644 --- a/src/voice/endpoints/ctrlm_voice_endpoint_http.cpp +++ b/src/voice/endpoints/ctrlm_voice_endpoint_http.cpp @@ -72,14 +72,12 @@ bool ctrlm_voice_endpoint_http_t::open() { std::string device_id = this->voice_obj->voice_stb_data_device_id_get(); std::string partner_id = this->voice_obj->voice_stb_data_partner_id_get(); - std::string experience = this->voice_obj->voice_stb_data_experience_get(); std::string app_id = this->voice_obj->voice_stb_data_app_id_http_get(); std::string language = this->voice_obj->voice_stb_data_guide_language_get().c_str(); xrsv_http_params_t params_http = { .device_id = device_id.c_str(), .partner_id = partner_id.c_str(), - .experience = experience.c_str(), .app_id = app_id.c_str(), .language = language.c_str(), .test_flag = this->voice_obj->voice_stb_data_test_get(), @@ -138,12 +136,6 @@ void ctrlm_voice_endpoint_http_t::voice_stb_data_partner_id_set(std::string &par } } -void ctrlm_voice_endpoint_http_t::voice_stb_data_experience_set(std::string &experience) { - if(this->xrsv_obj_http) { - xrsv_http_update_experience(this->xrsv_obj_http, experience.c_str()); - } -} - void ctrlm_voice_endpoint_http_t::voice_stb_data_guide_language_set(const char *language) { if(this->xrsv_obj_http) { xrsv_http_update_language(this->xrsv_obj_http, language); diff --git a/src/voice/endpoints/ctrlm_voice_endpoint_http.h b/src/voice/endpoints/ctrlm_voice_endpoint_http.h index 9338e20d..79a0d50d 100644 --- a/src/voice/endpoints/ctrlm_voice_endpoint_http.h +++ b/src/voice/endpoints/ctrlm_voice_endpoint_http.h @@ -32,7 +32,6 @@ class ctrlm_voice_endpoint_http_t : public ctrlm_voice_endpoint_t { public: void voice_stb_data_device_id_set(std::string &device_id); void voice_stb_data_partner_id_set(std::string &partner_id); - void voice_stb_data_experience_set(std::string &experience); void voice_stb_data_guide_language_set(const char *language); void voice_stb_data_pii_mask_set(bool enable); diff --git a/src/voice/endpoints/ctrlm_voice_endpoint_ws_nextgen.cpp b/src/voice/endpoints/ctrlm_voice_endpoint_ws_nextgen.cpp index e5165cd7..9abc27db 100644 --- a/src/voice/endpoints/ctrlm_voice_endpoint_ws_nextgen.cpp +++ b/src/voice/endpoints/ctrlm_voice_endpoint_ws_nextgen.cpp @@ -86,7 +86,6 @@ bool ctrlm_voice_endpoint_ws_nextgen_t::open() { } std::string device_id = this->voice_obj->voice_stb_data_device_id_get(); std::string partner_id = this->voice_obj->voice_stb_data_partner_id_get(); - std::string experience = this->voice_obj->voice_stb_data_experience_get(); std::string language = this->voice_obj->voice_stb_data_guide_language_get().c_str(); std::string account_number = this->voice_obj->voice_stb_data_account_number_get(); std::string device_mac = ctrlm_device_mac_get(); @@ -96,7 +95,6 @@ bool ctrlm_voice_endpoint_ws_nextgen_t::open() { .device_id = (device_id.empty() == false ? device_id.c_str() : NULL), .account_id = (account_number.empty() == false ? account_number.c_str() : NULL), .partner_id = (partner_id.empty() == false ? partner_id.c_str() : NULL), - .experience = (experience.empty() == false ? experience.c_str() : NULL), .audio_profile = controller_name_to_audio_profile(""), .audio_model = controller_name_to_audio_model(""), .language = language.c_str(), @@ -235,12 +233,6 @@ void ctrlm_voice_endpoint_ws_nextgen_t::voice_stb_data_partner_id_set(std::strin } } -void ctrlm_voice_endpoint_ws_nextgen_t::voice_stb_data_experience_set(std::string &experience) { - if(this->xrsv_obj_ws_nextgen) { - xrsv_ws_nextgen_update_experience(this->xrsv_obj_ws_nextgen, experience.c_str()); - } -} - void ctrlm_voice_endpoint_ws_nextgen_t::voice_stb_data_guide_language_set(const char *language) { if(this->xrsv_obj_ws_nextgen) { xrsv_ws_nextgen_update_language(this->xrsv_obj_ws_nextgen, language); diff --git a/src/voice/endpoints/ctrlm_voice_endpoint_ws_nextgen.h b/src/voice/endpoints/ctrlm_voice_endpoint_ws_nextgen.h index 16667f2f..218e1d39 100644 --- a/src/voice/endpoints/ctrlm_voice_endpoint_ws_nextgen.h +++ b/src/voice/endpoints/ctrlm_voice_endpoint_ws_nextgen.h @@ -37,7 +37,6 @@ class ctrlm_voice_endpoint_ws_nextgen_t : public ctrlm_voice_endpoint_t { void voice_stb_data_device_id_set(std::string &device_id); void voice_stb_data_device_type_set(ctrlm_device_type_t device_type); void voice_stb_data_partner_id_set(std::string &partner_id); - void voice_stb_data_experience_set(std::string &experience); void voice_stb_data_guide_language_set(const char *language); void voice_stb_data_mask_pii_set(bool enable); From 2d3d84cfd43b8ca8453cc3eb1c5fae1b8dd600c6 Mon Sep 17 00:00:00 2001 From: jthomp007c Date: Thu, 9 Apr 2026 07:30:06 -0400 Subject: [PATCH 40/81] RDKEMW-16333: Update Thunder plugin to use _string and _boolean (#197) * RDKEMW-16711: Update Thunder plugin to use _string and _boolean Reason for change: Thunder API now returns a string for last wakeup reason and a boolean for Networked Standby Mode Enabled, rather than a JsonObject. Updating ctrlm accordingly Test Procedure: NSM testing Priority: P0 Risks: Low Signed-off-by: Jason Thomson * Update ctrlm_thunder_plugin.h Address co-pilot comments * Update ctrlm_thunder_plugin.h * Update ctrlm_thunder_plugin.h --------- Signed-off-by: Jason Thomson --- src/thunder/ctrlm_thunder_plugin.cpp | 47 +++++++++++++++++++ src/thunder/ctrlm_thunder_plugin.h | 29 +++++++++--- .../ctrlm_thunder_plugin_powermanager.cpp | 21 +++++---- 3 files changed, 82 insertions(+), 15 deletions(-) diff --git a/src/thunder/ctrlm_thunder_plugin.cpp b/src/thunder/ctrlm_thunder_plugin.cpp index 3040fae5..ca6afffc 100644 --- a/src/thunder/ctrlm_thunder_plugin.cpp +++ b/src/thunder/ctrlm_thunder_plugin.cpp @@ -261,6 +261,53 @@ bool ctrlm_thunder_plugin_t::call_plugin(std::string method, void *params, void return(ret); } +bool ctrlm_thunder_plugin_t::call_plugin_boolean(std::string method, void *params, bool *response) { + bool ret = false; + auto clientObject = (JSONRPC::LinkType*)this->plugin_client; + JsonObject *jsonParams = (JsonObject *)params; + if(clientObject) { + if(!method.empty() && jsonParams && response) { + Core::JSON::Boolean jsonResponse; + uint32_t thunderRet = clientObject->Invoke(CALL_TIMEOUT, _T(method), *jsonParams, jsonResponse); + if(thunderRet != Core::ERROR_NONE) { + XLOGD_ERROR("Thunder call failed <%s> <%u>", method.c_str(), thunderRet); + } else { + *response = jsonResponse.Value(); + ret = true; + } + } else { + XLOGD_ERROR("Invalid parameters"); + } + } else { + XLOGD_ERROR("Client is NULL"); + } + return(ret); +} + +bool ctrlm_thunder_plugin_t::call_plugin_string(std::string method, void *params, std::string *response) { + bool ret = false; + auto clientObject = (JSONRPC::LinkType*)this->plugin_client; + JsonObject *jsonParams = (JsonObject *)params; + if(clientObject) { + if(!method.empty() && jsonParams && response) { + Core::JSON::String jsonString; + uint32_t thunderRet = clientObject->Invoke(CALL_TIMEOUT, _T(method), *jsonParams, jsonString); + if(thunderRet != Core::ERROR_NONE) { + XLOGD_ERROR("Thunder call failed <%s> <%u>", method.c_str(), thunderRet); + } else { + *response = jsonString.Value(); + ret = true; + } + } else { + XLOGD_ERROR("Invalid parameters"); + } + } else { + XLOGD_ERROR("Client is NULL"); + } + return(ret); +} + + bool ctrlm_thunder_plugin_t::call_controller(std::string method, void *params, void *response) { bool ret = false; if(this->controller) { diff --git a/src/thunder/ctrlm_thunder_plugin.h b/src/thunder/ctrlm_thunder_plugin.h index f1a3944a..9bf6d780 100644 --- a/src/thunder/ctrlm_thunder_plugin.h +++ b/src/thunder/ctrlm_thunder_plugin.h @@ -105,9 +105,8 @@ class ctrlm_thunder_plugin_t { std::string callsign_with_api(); /** - * This functions is used to get a Thunder Plugin property. - * @param method The method in which the user wants to call. - * @param params The WPEFramework JsonObject containing the parameters for the call. (We can't include WPEFramework headers in controlMgr .h files as their logging macros clash) + * This function is used to get a Thunder Plugin property. + * @param property The name of the property that the user wants to get * @param response The WPEFramework JsonObject containing the response from the call. (We can't include WPEFramework headers in controlMgr .h files as their logging macros clash) * @param retries The number of retries if the call times out. * @return True if the call succeeded, otherwise False. @@ -115,7 +114,7 @@ class ctrlm_thunder_plugin_t { bool property_get(std::string property, void *response, unsigned int retries = 0); /** - * This functions is used to call a Thunder Plugin method. + * This function is used to call a Thunder Plugin method. * @param method The method in which the user wants to call. * @param params The WPEFramework JsonObject containing the parameters for the call. (We can't include WPEFramework headers in controlMgr .h files as their logging macros clash) * @param response The WPEFramework JsonObject containing the response from the call. (We can't include WPEFramework headers in controlMgr .h files as their logging macros clash) @@ -125,7 +124,25 @@ class ctrlm_thunder_plugin_t { bool call_plugin(std::string method, void *params, void *response, unsigned int retries = 0); /** - * This functions is used to call a Thunder Controller method. + * This function is used to call a Thunder Plugin method. + * @param method The method in which the user wants to call. + * @param params The WPEFramework JsonObject containing the parameters for the call. (We can't include WPEFramework headers in controlMgr .h files as their logging macros clash) + * @param response The boolean pointer which will be assigned the response from the call + * @return True if the call succeeded, otherwise False. + */ + bool call_plugin_boolean(std::string method, void *params, bool *response); + + /** + * This function is used to call a Thunder Plugin method. + * @param method The method in which the user wants to call. + * @param params The WPEFramework JsonObject containing the parameters for the call. (We can't include WPEFramework headers in controlMgr .h files as their logging macros clash) + * @param response The string pointer which will be assigned containing the response from the call. + * @return True if the call succeeded, otherwise False. + */ + bool call_plugin_string(std::string method, void *params, std::string *response); + + /** + * This function is used to call a Thunder Controller method. * @param method The method in which the user wants to call. * @param params The WPEFramework JsonObject containing the parameters for the call. (We can't include WPEFramework headers in controlMgr .h files as their logging macros clash) * @param params The WPEFramework JsonObject containing the response from the call. (We can't include WPEFramework headers in controlMgr .h files as their logging macros clash) @@ -164,4 +181,4 @@ class ctrlm_thunder_plugin_t { }; }; -#endif \ No newline at end of file +#endif diff --git a/src/thunder/ctrlm_thunder_plugin_powermanager.cpp b/src/thunder/ctrlm_thunder_plugin_powermanager.cpp index 6e0c83b0..e84fa983 100755 --- a/src/thunder/ctrlm_thunder_plugin_powermanager.cpp +++ b/src/thunder/ctrlm_thunder_plugin_powermanager.cpp @@ -89,16 +89,15 @@ ctrlm_power_state_t ctrlm_thunder_plugin_powermanager_t::get_power_state() { /* root@pioneer-uhd:~# curl --request POST --url http://127.0.0.1:9998/jsonrpc --header 'Content-Type: application/json' --data '{ "jsonrpc": "2.0", "id": 1234567890, "method": "org.rdk.PowerManager.1.getNetworkStandbyMode", "params": {} }' {"jsonrpc":"2.0","id":1234567890,"result":true} */ bool ctrlm_thunder_plugin_powermanager_t::get_networked_standby_mode() { - JsonObject params, response; + JsonObject params; params = {}; bool networked_standby_mode = false; - sem_wait(&this->semaphore); - if(this->call_plugin("getNetworkStandbyMode", (void *)¶ms, (void *)&response)) { - networked_standby_mode = response["result"].Boolean(); + sem_wait(&this->semaphore); + if(this->call_plugin_boolean("getNetworkStandbyMode", (void *)¶ms, &networked_standby_mode)) { XLOGD_DEBUG("networked_standby_mode is %s", networked_standby_mode?"TRUE":"FALSE"); } else { - XLOGD_ERROR("getNetworkedStandbyMode call failed"); + XLOGD_ERROR("getNetworkStandbyMode call failed"); } sem_post(&this->semaphore); @@ -108,19 +107,23 @@ bool ctrlm_thunder_plugin_powermanager_t::get_networked_standby_mode() { /* root@pioneer-uhd:~# curl --request POST --url http://127.0.0.1:9998/jsonrpc --header 'Content-Type: application/json' --data '{ "jsonrpc": "2.0", "id": 1234567890, "method": "org.rdk.PowerManager.1.getLastWakeupReason", "params": {} }' {"jsonrpc":"2.0","id":1234567890,"result":"COLDBOOT"} */ bool ctrlm_thunder_plugin_powermanager_t::get_wakeup_reason_voice() { - JsonObject params, response; + JsonObject params; + std::string response; params = {}; bool wakeup_reason_voice = false; sem_wait(&this->semaphore); - if(this->call_plugin("getLastWakeupReason", (void *)¶ms, (void *)&response)) { - wakeup_reason_voice = (0 == strncmp(response["result"].String().c_str(), "VOICE", 5)); - XLOGD_DEBUG("voice_wakeup is %s", wakeup_reason_voice?"TRUE":"FALSE"); + if(this->call_plugin_string("getLastWakeupReason", (void *)¶ms, &response)) { + if(response == "VOICE") { + wakeup_reason_voice = true; + } } else { XLOGD_ERROR("getLastWakeupReason call failed"); } sem_post(&this->semaphore); + XLOGD_DEBUG("voice_wakeup is %s", wakeup_reason_voice?"TRUE":"FALSE"); + return wakeup_reason_voice; } From 793ed9c8618606b0808d25b4a7fbd8caba198a64 Mon Sep 17 00:00:00 2001 From: Gene Gallagher Date: Thu, 9 Apr 2026 14:42:02 -0400 Subject: [PATCH 41/81] 1.1.12 release changelog updates --- CHANGELOG.md | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 52e8cb2d..8121aa80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,32 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). + + +#### [1.1.12](https://github.com/rdkcentral/control/compare/1.1.11...1.1.12) + +> 9 April 2026 + +- RDKEMW-16333: Update Thunder plugin to use _string and _boolean [`#197`](https://github.com/rdkcentral/control/pull/197) +- RDKEMW-5849 : remove deprecated "experience" code [`#185`](https://github.com/rdkcentral/control/pull/185) + +#### [1.1.11.2](https://github.com/rdkcentral/control/compare/1.1.11.1...1.1.11.2) + +> 7 April 2026 + +- RDKEMW-16711: CHANGELOG for ctrlm hotfix release 1.1.11.2 [`#196`](https://github.com/rdkcentral/control/pull/196) +- RDKEMW-16711 : Add wakeup reason string, on support/1.1.11 [`#195`](https://github.com/rdkcentral/control/pull/195) + +#### [1.1.11.1](https://github.com/rdkcentral/control/compare/1.1.11...1.1.11.1) + +> 1 April 2026 + +- RDKEMW-16330: Update Control Manager to use bool for NSM [`#188`](https://github.com/rdkcentral/control/pull/188) +- RDKEMW-16330: update CHANGELOG for release 1.1.11p1 [`98ea5f5`](https://github.com/rdkcentral/control/commit/98ea5f51f8da9ef6ded7038d760baa3b41cc4a90) + #### [1.1.11](https://github.com/rdkcentral/control/compare/1.1.10...1.1.11) -> 5 March 2026 +> 6 March 2026 - RDKEMW-14589: No UI action with "Info" keypress from rf4ce remote in RF mode [`#181`](https://github.com/rdkcentral/control/pull/181) - RDKEMW-14445 : Add session end and protocol return to telemetry [`#182`](https://github.com/rdkcentral/control/pull/182) @@ -15,7 +38,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - RDKEMW-12930: RF4CE network export XCONF on pair/unpair/etc. [`#177`](https://github.com/rdkcentral/control/pull/177) - RDKEMW-13833: Remove duplicate RFC fetch attempts in listeners [`#179`](https://github.com/rdkcentral/control/pull/179) - #### [1.1.10](https://github.com/rdkcentral/control/compare/1.1.9...1.1.10) From 67e73a039ec0c37e059dce8f982c9d07d16a1a03 Mon Sep 17 00:00:00 2001 From: Gene Gallagher <129112619+egalla204@users.noreply.github.com> Date: Thu, 9 Apr 2026 15:05:19 -0400 Subject: [PATCH 42/81] 1.1.12 release changelog updates (#201) https://ccp.sys.comcast.net/browse/RDKEMW-16915 --- CHANGELOG.md | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 52e8cb2d..8121aa80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,32 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). + + +#### [1.1.12](https://github.com/rdkcentral/control/compare/1.1.11...1.1.12) + +> 9 April 2026 + +- RDKEMW-16333: Update Thunder plugin to use _string and _boolean [`#197`](https://github.com/rdkcentral/control/pull/197) +- RDKEMW-5849 : remove deprecated "experience" code [`#185`](https://github.com/rdkcentral/control/pull/185) + +#### [1.1.11.2](https://github.com/rdkcentral/control/compare/1.1.11.1...1.1.11.2) + +> 7 April 2026 + +- RDKEMW-16711: CHANGELOG for ctrlm hotfix release 1.1.11.2 [`#196`](https://github.com/rdkcentral/control/pull/196) +- RDKEMW-16711 : Add wakeup reason string, on support/1.1.11 [`#195`](https://github.com/rdkcentral/control/pull/195) + +#### [1.1.11.1](https://github.com/rdkcentral/control/compare/1.1.11...1.1.11.1) + +> 1 April 2026 + +- RDKEMW-16330: Update Control Manager to use bool for NSM [`#188`](https://github.com/rdkcentral/control/pull/188) +- RDKEMW-16330: update CHANGELOG for release 1.1.11p1 [`98ea5f5`](https://github.com/rdkcentral/control/commit/98ea5f51f8da9ef6ded7038d760baa3b41cc4a90) + #### [1.1.11](https://github.com/rdkcentral/control/compare/1.1.10...1.1.11) -> 5 March 2026 +> 6 March 2026 - RDKEMW-14589: No UI action with "Info" keypress from rf4ce remote in RF mode [`#181`](https://github.com/rdkcentral/control/pull/181) - RDKEMW-14445 : Add session end and protocol return to telemetry [`#182`](https://github.com/rdkcentral/control/pull/182) @@ -15,7 +38,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - RDKEMW-12930: RF4CE network export XCONF on pair/unpair/etc. [`#177`](https://github.com/rdkcentral/control/pull/177) - RDKEMW-13833: Remove duplicate RFC fetch attempts in listeners [`#179`](https://github.com/rdkcentral/control/pull/179) - #### [1.1.10](https://github.com/rdkcentral/control/compare/1.1.9...1.1.10) From 56f9fafbd2d37ef6fbfa298510c5ea536edc1d7e Mon Sep 17 00:00:00 2001 From: dwolaver <44593664+dwolaver@users.noreply.github.com> Date: Tue, 21 Apr 2026 11:23:27 -0400 Subject: [PATCH 43/81] RDKEMW-17187 : PTT audio buffering feature aborting voice session before mic key release (#203) --- src/ble/ctrlm_ble_network.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ble/ctrlm_ble_network.cpp b/src/ble/ctrlm_ble_network.cpp index 03e1322f..2b4fc40e 100644 --- a/src/ble/ctrlm_ble_network.cpp +++ b/src/ble/ctrlm_ble_network.cpp @@ -2661,7 +2661,7 @@ void ctrlm_obj_network_ble_t::start_controller_audio_streaming(ctrlm_voice_start ctrlm_hal_ble_VoiceStreamEnd_t streamEnd = CTRLM_HAL_BLE_VOICE_STREAM_END_ON_KEY_UP; auto rcu = controllers_.at(id); - if (rcu->getPressAndHoldSupport()) { + if (!rcu->getPressAndHoldSupport()) { // if the voice session is "Press and Release" then end stream on audio duration instead of key up event streamEnd = CTRLM_HAL_BLE_VOICE_STREAM_END_ON_AUDIO_DURATION; } From d1afc0746699dcd42519f341d50676b4fe52dfe3 Mon Sep 17 00:00:00 2001 From: dwolaver <44593664+dwolaver@users.noreply.github.com> Date: Tue, 21 Apr 2026 11:24:45 -0400 Subject: [PATCH 44/81] RDKEMW-16763 : rf4ce init failure causes deadlock (#198) --- src/rf4ce/ctrlm_rf4ce_network.cpp | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/rf4ce/ctrlm_rf4ce_network.cpp b/src/rf4ce/ctrlm_rf4ce_network.cpp index 5009c592..d1ac409f 100644 --- a/src/rf4ce/ctrlm_rf4ce_network.cpp +++ b/src/rf4ce/ctrlm_rf4ce_network.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include "ctrlm.h" #include "ctrlm_log.h" @@ -411,8 +412,31 @@ ctrlm_hal_result_t ctrlm_obj_network_rf4ce_t::hal_init_request(GThread *ctrlm_ma // Block until initialization is complete or a timeout occurs XLOGD_INFO("Waiting for %s initialization...", name_get()); - sem_wait(&semaphore_); - sem_destroy(&semaphore_); + struct timespec timeout; + clock_gettime(CLOCK_REALTIME, &timeout); + timeout.tv_sec += 2; // this operation should complete in under 100 ms under normal circumstances + + int sem_result = -1; + do { + errno = 0; + sem_result = sem_timedwait(&semaphore_, &timeout); + if(sem_result == -1 && errno == EINTR) { + XLOGD_INFO("interrupted"); + } else { + break; + } + } while(1); + + if(sem_result == -1) { + if(errno == ETIMEDOUT) { + XLOGD_ERROR("Timeout waiting for %s initialization", name_get()); + } else { + XLOGD_ERROR("Error waiting for %s initialization: %s", name_get(), strerror(errno)); + } + init_result_ = CTRLM_HAL_RESULT_ERROR; + } else { + sem_destroy(&semaphore_); + } ready_ = (CTRLM_HAL_RESULT_SUCCESS == init_result_); From c9c6f6ad59ca820ebe8389ee134fa50f97f459e5 Mon Sep 17 00:00:00 2001 From: Gene Gallagher Date: Tue, 21 Apr 2026 11:37:37 -0400 Subject: [PATCH 45/81] 1.1.13 release changelog updates --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8121aa80..643efb94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,13 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [1.1.13](https://github.com/rdkcentral/control/compare/1.1.12...1.1.13) + +> 21 April 2026 + +- RDKEMW-16763 : rf4ce init failure causes deadlock [`#198`](https://github.com/rdkcentral/control/pull/198) +- RDKEMW-17187 : PTT audio buffering feature aborting voice session before mic key release [`#203`](https://github.com/rdkcentral/control/pull/203) + #### [1.1.12](https://github.com/rdkcentral/control/compare/1.1.11...1.1.12) > 9 April 2026 From 48775fcf533d8506408d2223829af0fbd89b6cea Mon Sep 17 00:00:00 2001 From: Kelvin Lu <119349872+klu339@users.noreply.github.com> Date: Wed, 22 Apr 2026 15:19:16 -0400 Subject: [PATCH 46/81] Revert "RDKEMW-16763 : rf4ce init failure causes deadlock (#198)" (#211) This reverts commit d1afc0746699dcd42519f341d50676b4fe52dfe3. --- src/rf4ce/ctrlm_rf4ce_network.cpp | 28 ++-------------------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/src/rf4ce/ctrlm_rf4ce_network.cpp b/src/rf4ce/ctrlm_rf4ce_network.cpp index d1ac409f..5009c592 100644 --- a/src/rf4ce/ctrlm_rf4ce_network.cpp +++ b/src/rf4ce/ctrlm_rf4ce_network.cpp @@ -35,7 +35,6 @@ #include #include #include -#include #include #include "ctrlm.h" #include "ctrlm_log.h" @@ -412,31 +411,8 @@ ctrlm_hal_result_t ctrlm_obj_network_rf4ce_t::hal_init_request(GThread *ctrlm_ma // Block until initialization is complete or a timeout occurs XLOGD_INFO("Waiting for %s initialization...", name_get()); - struct timespec timeout; - clock_gettime(CLOCK_REALTIME, &timeout); - timeout.tv_sec += 2; // this operation should complete in under 100 ms under normal circumstances - - int sem_result = -1; - do { - errno = 0; - sem_result = sem_timedwait(&semaphore_, &timeout); - if(sem_result == -1 && errno == EINTR) { - XLOGD_INFO("interrupted"); - } else { - break; - } - } while(1); - - if(sem_result == -1) { - if(errno == ETIMEDOUT) { - XLOGD_ERROR("Timeout waiting for %s initialization", name_get()); - } else { - XLOGD_ERROR("Error waiting for %s initialization: %s", name_get(), strerror(errno)); - } - init_result_ = CTRLM_HAL_RESULT_ERROR; - } else { - sem_destroy(&semaphore_); - } + sem_wait(&semaphore_); + sem_destroy(&semaphore_); ready_ = (CTRLM_HAL_RESULT_SUCCESS == init_result_); From 26c6dc8b21f3f93ab3fb7d76facb1a695f073fba Mon Sep 17 00:00:00 2001 From: Gene Gallagher Date: Wed, 22 Apr 2026 15:30:34 -0400 Subject: [PATCH 47/81] 1.1.14 release changelog updates --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 643efb94..00d71742 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,13 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [1.1.14](https://github.com/rdkcentral/control/compare/1.1.13...1.1.14) + +> 22 April 2026 + +- Revert "RDKEMW-16763 : rf4ce init failure causes deadlock (#198)" [`#211`](https://github.com/rdkcentral/control/pull/211) + + #### [1.1.13](https://github.com/rdkcentral/control/compare/1.1.12...1.1.13) > 21 April 2026 From de7fa447105fa63ef894edec2f70535ff2652240 Mon Sep 17 00:00:00 2001 From: dwolaver <44593664+dwolaver@users.noreply.github.com> Date: Mon, 27 Apr 2026 14:30:52 -0400 Subject: [PATCH 48/81] RDKEMW-17614 : mask_pii RFC not applied correctly (#218) --- src/ctrlm_main.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/ctrlm_main.cpp b/src/ctrlm_main.cpp index c3da8d6d..81168180 100644 --- a/src/ctrlm_main.cpp +++ b/src/ctrlm_main.cpp @@ -1938,7 +1938,15 @@ void ctrlm_global_rfc_values_retrieved(const ctrlm_rfc_attr_t &attr) { attr.get_rfc_value(JSON_INT_NAME_CTRLM_GLOBAL_TIMEOUT_ONE_TOUCH_AUTOBIND, g_ctrlm.one_touch_autobind_timeout_val, 0); attr.get_rfc_value(JSON_INT_NAME_CTRLM_GLOBAL_CRASH_RECOVERY_THRESHOLD, g_ctrlm.crash_recovery_threshold, 0); if(attr.get_rfc_value(JSON_ARRAY_NAME_CTRLM_GLOBAL_MASK_PII, g_ctrlm.mask_pii, ctrlm_is_production_build() ? CTRLM_JSON_ARRAY_INDEX_PRD : CTRLM_JSON_ARRAY_INDEX_DEV)) { - g_ctrlm.voice_session->voice_stb_data_pii_mask_set(g_ctrlm.mask_pii); + if(g_ctrlm.voice_session != NULL) { + g_ctrlm.voice_session->voice_stb_data_pii_mask_set(g_ctrlm.mask_pii); + } + if(g_ctrlm.ir_controller != NULL) { + g_ctrlm.ir_controller->mask_key_codes_set(g_ctrlm.mask_pii); + } + for(auto const &itr : g_ctrlm.networks) { + itr.second->mask_key_codes_set(g_ctrlm.mask_pii); + } } attr.get_rfc_value(JSON_INT_NAME_CTRLM_GLOBAL_AUTHSERVICE_FAST_POLL_PERIOD, g_ctrlm.authservice_fast_poll_val); attr.get_rfc_value(JSON_INT_NAME_CTRLM_GLOBAL_AUTHSERVICE_FAST_MAX_RETRIES, g_ctrlm.authservice_fast_retries_max); From cdfa87f2674ead12a6c66b1a9d02a611219bf14f Mon Sep 17 00:00:00 2001 From: Gene Gallagher <129112619+egalla204@users.noreply.github.com> Date: Wed, 29 Apr 2026 19:50:44 -0400 Subject: [PATCH 49/81] RDKEMW-13607: merge pair code with mac hash methods (#191) --- include/ctrlm_ipc.h | 1 - src/ble/ctrlm_ble_network.cpp | 30 +-- src/ble/ctrlm_ble_rcu_interface.cpp | 25 -- src/ble/ctrlm_ble_rcu_interface.h | 1 - src/ble/hal/blercu/blercucontroller.cpp | 59 +---- src/ble/hal/blercu/blercucontroller.h | 1 - src/ble/hal/blercu/blercucontroller_p.h | 1 - .../hal/blercu/blercupairingstatemachine.cpp | 152 +++-------- .../hal/blercu/blercupairingstatemachine.h | 4 +- .../configsettings/configmodelsettings.cpp | 246 ++++++++---------- src/ble/hal/configsettings/configsettings.cpp | 2 +- src/ctrlm_ir_controller.cpp | 1 - 12 files changed, 157 insertions(+), 366 deletions(-) diff --git a/include/ctrlm_ipc.h b/include/ctrlm_ipc.h index 341d4ff9..32d0dea1 100644 --- a/include/ctrlm_ipc.h +++ b/include/ctrlm_ipc.h @@ -753,7 +753,6 @@ typedef struct { typedef struct { unsigned char api_revision; ///< Revision of this API ctrlm_network_id_t network_id; ///< IN - Identifier of network - unsigned int key_code; ///< IN - Key code from device unsigned int pair_code; ///< IN - Pairing code from device ctrlm_iarm_call_result_t result; ///< OUT - return code of the operation } ctrlm_iarm_call_StartPairWithCode_params_t; diff --git a/src/ble/ctrlm_ble_network.cpp b/src/ble/ctrlm_ble_network.cpp index 2b4fc40e..57cdb6da 100644 --- a/src/ble/ctrlm_ble_network.cpp +++ b/src/ble/ctrlm_ble_network.cpp @@ -677,7 +677,7 @@ void ctrlm_obj_network_ble_t::req_process_start_pairing(void *data, int size) { dqm->params->set_result(CTRLM_IARM_CALL_RESULT_SUCCESS, network_id_get()); } } else { - XLOGD_INFO("Starting pairing with a list of mac addresses! Pairing with first available..."); + XLOGD_INFO("Starting pairing with a list of MAC addresses! Pairing with first available..."); if(!ble_rcu_interface_->pairWithMacAddrs(dqm->params->ieee_address_list)) { XLOGD_ERROR("failed to start BLE remote scan"); dqm->params->set_result(CTRLM_IARM_CALL_RESULT_ERROR, network_id_get()); @@ -740,29 +740,13 @@ void ctrlm_obj_network_ble_t::req_process_pair_with_code(void *data, int size) { XLOGD_FATAL("Network is not ready!"); } else { if (ble_rcu_interface_) { - - if (dqm->params->key_code == KEY_BLUETOOTH) { - // KEY_BLUETOOTH means the pairing code is random 3 digit code embedded in the name - // so use pairWithCode - if (!ble_rcu_interface_->pairWithCode(dqm->params->pair_code)) { - // don't log error here, pairWithCode will handle printing the error. We do - // this because there is an error that is merely a warning that we don't want - // logged because it only confuses those analyzing the logs. - // XLOGD_ERROR("failed to start pairing with code"); - } else { - dqm->params->result = CTRLM_IARM_CALL_RESULT_SUCCESS; - } + if (!ble_rcu_interface_->pairWithCode(dqm->params->pair_code)) { + // don't log error here, pairWithCode will handle printing the error. We do + // this because there is an error that is merely a warning that we don't want + // logged because it only confuses those analyzing the logs. + // XLOGD_ERROR("failed to start pairing with code"); } else { - // if key_code is either not available or KEY_CONNECT, it means the pairing code is a - // hash of the MAC, so use pairWithMacHash - if (!ble_rcu_interface_->pairWithMacHash(dqm->params->pair_code)) { - // don't log error here, pairWithMacHash will handle printing the error. We do - // this because there is an error that is merely a warning that we don't want - // logged because it only confuses those analyzing the logs. - // XLOGD_ERROR("failed to start pairing with MAC hash"); - } else { - dqm->params->result = CTRLM_IARM_CALL_RESULT_SUCCESS; - } + dqm->params->result = CTRLM_IARM_CALL_RESULT_SUCCESS; } } } diff --git a/src/ble/ctrlm_ble_rcu_interface.cpp b/src/ble/ctrlm_ble_rcu_interface.cpp index 6abecad1..f90cdc67 100644 --- a/src/ble/ctrlm_ble_rcu_interface.cpp +++ b/src/ble/ctrlm_ble_rcu_interface.cpp @@ -697,31 +697,6 @@ bool ctrlm_ble_rcu_interface_t::pairWithCode(unsigned int code) XLOGD_ERROR("controller failed to start pairing, %s: %s", error.name().c_str(), error.message().c_str()); } return false; - } else { - XLOGD_INFO("started pairing with code %hhu", code); - } - return true; -} - -bool ctrlm_ble_rcu_interface_t::pairWithMacHash(unsigned int code) -{ - if (!m_controller) { - XLOGD_ERROR("m_controller is NULL!!!"); - return false; - } - - if (!m_controller->startPairingWithMacHash((uint8_t) code)) { - BleRcuError error = m_controller->lastError(); - - // Remote will continually send out IR pairing signals until the BLE pair request - // has been received. This means that the "Already in pairing state" error is normal. - // Let's omit this error print because it only serves to confuse those analyzing the logs. - if (error.message() != "Already in pairing state") { - XLOGD_ERROR("controller failed to start pairing, %s: %s", error.name().c_str(), error.message().c_str()); - } - return false; - } else { - XLOGD_INFO("started pairing with MAC hash 0x%X", code); } return true; } diff --git a/src/ble/ctrlm_ble_rcu_interface.h b/src/ble/ctrlm_ble_rcu_interface.h index a6526e1b..c9209c6f 100644 --- a/src/ble/ctrlm_ble_rcu_interface.h +++ b/src/ble/ctrlm_ble_rcu_interface.h @@ -92,7 +92,6 @@ class ctrlm_ble_rcu_interface_t void handleDeepsleep(bool wakingUp); bool pairWithCode(unsigned int code); - bool pairWithMacHash(unsigned int code); bool pairWithMacAddrs(const std::vector &macAddrList); bool pairAutoWithTimeout(int timeoutMs); bool pairCancel(); diff --git a/src/ble/hal/blercu/blercucontroller.cpp b/src/ble/hal/blercu/blercucontroller.cpp index eb1b39ac..9924c9df 100644 --- a/src/ble/hal/blercu/blercucontroller.cpp +++ b/src/ble/hal/blercu/blercucontroller.cpp @@ -243,7 +243,7 @@ bool BleRcuControllerImpl::startPairingAutoWithTimeout(int timeoutMs) bool BleRcuControllerImpl::startPairingWithCode(uint8_t pairingCode) { if (m_pairingStateMachine.isRunning()) { - if (m_pairingStateMachine.isAutoPairing()) { + if (m_pairingStateMachine.isScanningForAutoPair()) { XLOGD_WARN("received targeted pairing request in auto pair mode, cancelling auto pair first..."); @@ -271,61 +271,6 @@ bool BleRcuControllerImpl::startPairingWithCode(uint8_t pairingCode) return true; } -// ----------------------------------------------------------------------------- -/*! - \fn bool BleRcuController::startPairingWithMacHash(uint8_t macHash) - - Attempts to start the pairing procedure looking for a device that has - a MAC address matching the supplied MAC hash. - - The MAC hash is calculated by adding all the bytes of the MAC address - together, and masking with 0xFF. - e.g., MAC = AA:BB:CC:DD:EE:FF, hash = (AA+BB+CC+DD+EE+FF) & 0xFF - - If the controller is currently in pairing mode this method will fail and - return \c false. If the bluetooth adaptor is not available or not powered - then this function will also fail and return \c false. - - If \c false is returned use BleRcuController::lastError() to get the failure - reason. - - \note This object doesn't actually run the pairing procedure, instead it - just starts and stops the \l{BleRcuPairingStateMachine} object. - - \see cancelPairing(), isPairing() & pairingCode() - */ -bool BleRcuControllerImpl::startPairingWithMacHash(uint8_t macHash) -{ - if (m_pairingStateMachine.isRunning()) { - if (m_pairingStateMachine.isAutoPairing()) { - - XLOGD_WARN("received targeted pairing request in auto pair mode, cancelling auto pair first..."); - - m_ignorePairingFailure = true; - m_pairingStateMachine.stop(); - - m_lastError = BleRcuError(BleRcuError::Busy, "Cancelling auto pair operation, send another request."); - } else { - XLOGD_DEBUG("requested pairing while currently running a pairing operation, ignoring request"); - m_lastError = BleRcuError(BleRcuError::Busy, "Already in pairing state"); - } - return false; - } - - // check that the manager has powered on the adapter, without this we - // obviously can't scan / pair / etc. The only time the adaptor should - // (legitimately) be unavailable is right at start-up - if (!m_adapter->isAvailable() || !m_adapter->isPowered()) { - m_lastError = BleRcuError(BleRcuError::General, "Adaptor not available or not powered"); - return false; - } - - // start the pairing process - m_pairingStateMachine.startWithMacHash(macHash); - - return true; -} - // ----------------------------------------------------------------------------- /*! \fn bool BleRcuController::startPairingWithList(std::vector macAddrList) @@ -348,7 +293,7 @@ bool BleRcuControllerImpl::startPairingWithMacHash(uint8_t macHash) bool BleRcuControllerImpl::startPairingWithList(const std::vector &macAddrList) { if (m_pairingStateMachine.isRunning()) { - if (m_pairingStateMachine.isAutoPairing()) { + if (m_pairingStateMachine.isScanningForAutoPair()) { XLOGD_WARN("received targeted pairing request in auto pair mode, cancelling auto pair first..."); diff --git a/src/ble/hal/blercu/blercucontroller.h b/src/ble/hal/blercu/blercucontroller.h index a0b678cf..770d4d07 100644 --- a/src/ble/hal/blercu/blercucontroller.h +++ b/src/ble/hal/blercu/blercucontroller.h @@ -73,7 +73,6 @@ class BleRcuController virtual bool startPairingAutoWithTimeout(int timeoutMs) = 0; virtual bool startPairingWithCode(uint8_t pairingCode) = 0; - virtual bool startPairingWithMacHash(uint8_t macHash) = 0; virtual bool startPairingWithList(const std::vector &macAddrList) = 0; virtual bool cancelPairing() = 0; diff --git a/src/ble/hal/blercu/blercucontroller_p.h b/src/ble/hal/blercu/blercucontroller_p.h index 7d8411d3..ccbe62ea 100644 --- a/src/ble/hal/blercu/blercucontroller_p.h +++ b/src/ble/hal/blercu/blercucontroller_p.h @@ -61,7 +61,6 @@ class BleRcuControllerImpl final : public BleRcuController bool startPairingAutoWithTimeout(int timeoutMs) override; bool startPairingWithCode(uint8_t pairingCode) override; - bool startPairingWithMacHash(uint8_t macHash) override; bool startPairingWithList(const std::vector &macAddrList) override; bool cancelPairing() override; diff --git a/src/ble/hal/blercu/blercupairingstatemachine.cpp b/src/ble/hal/blercu/blercupairingstatemachine.cpp index bb769b41..e23c6939 100644 --- a/src/ble/hal/blercu/blercupairingstatemachine.cpp +++ b/src/ble/hal/blercu/blercupairingstatemachine.cpp @@ -198,13 +198,12 @@ bool BleRcuPairingStateMachine::isRunning() const This special state is needed because auto pairing consists of running a scan for an undeterminate amount of time until one of the supported devices listed in the config file is found. We want to be able to cancel this operation if another - pair request comes in that targets a specific device (like pairWithCode or - pairWithMacHash) + pair request comes in that targets a specific device (like pairWithCode) */ -bool BleRcuPairingStateMachine::isAutoPairing() const +bool BleRcuPairingStateMachine::isScanningForAutoPair() const { - return isRunning() && m_isAutoPairing; + return isRunning() && m_isAutoPairing && m_stateMachine.inState(DiscoverySuperState); } @@ -228,13 +227,13 @@ void BleRcuPairingStateMachine::startAutoWithTimeout(int timeoutMs) // clear the target device m_targetAddress.clear(); - // clear the pairing code and mac hash + // clear data for other pairing methods m_pairingCode = -1; m_pairingMacHash = -1; + m_pairingMacList.clear(); // create list of supported remotes regex to match to the name of the device m_targetedPairingNames.clear(); - for (const auto &name : m_supportedPairingNames) { // add to the list to use for compare when a device is found m_targetedPairingNames.push_back(name); @@ -269,23 +268,22 @@ void BleRcuPairingStateMachine::startWithCode(uint8_t pairingCode) // clear the target device m_targetAddress.clear(); - // clear the list of addresses to filter for + // clear data for other pairing methods m_pairingMacList.clear(); - // store the pairing code + // the pairing could be either the mac hash or the code embedded in the name, + // so store both for use when processing found devices m_pairingCode = pairingCode; - m_pairingMacHash = -1; + m_pairingMacHash = pairingCode; // create list of supported remotes regex to match to the name of the device m_targetedPairingNames.clear(); - char nameWithCode[100]; - for (const auto &pairingFormat : m_pairingPrefixFormats) { // construct the wildcard match snprintf(nameWithCode, sizeof(nameWithCode), pairingFormat.c_str(), pairingCode); - XLOGD_INFO("added pairing regex for supported remote '%s'", nameWithCode); + XLOGD_INFO("added pairing name '%s' to targeted names list ", nameWithCode); // add to the list to use for compare when a device is found m_targetedPairingNames.push_back(std::regex(nameWithCode, std::regex_constants::ECMAScript)); @@ -296,86 +294,7 @@ void BleRcuPairingStateMachine::startWithCode(uint8_t pairingCode) m_pairingAttempts++; m_pairingSucceeded = false; - XLOGD_INFO("started pairing using name prefix code %03d", m_pairingCode); -} - -// ----------------------------------------------------------------------------- -/*! - Starts the state machine using the supplied \a pairingCode and - \a namePrefixes. - - */ -void BleRcuPairingStateMachine::startWithMacHash(uint8_t macHash) -{ - // sanity check the statemachine is not already running - if (m_stateMachine.isRunning()) { - XLOGD_WARN("state machine already running"); - return; - } - - m_discoveryTimeout = m_discoveryTimeoutDefault; - m_isAutoPairing = false; - - // clear the target device - m_targetAddress.clear(); - - // clear the pairing code - m_pairingCode = -1; - - // clear the list of addresses to filter for - m_pairingMacList.clear(); - - // store the MAC hash - m_pairingMacHash = macHash; - - // clear the maps, we are trying to pair to a specific device using a hash of the MAC address - m_targetedPairingNames.clear(); - - // start the state machine - m_stateMachine.start(); - - m_pairingAttempts++; - m_pairingSucceeded = false; - XLOGD_INFO("started pairing, searching for device with MAC hash 0x%02X", m_pairingMacHash); -} - -// ----------------------------------------------------------------------------- -/*! - Starts the pairing state machine, but skips the discovery phase as we - already have a \a target device. - - */ -void BleRcuPairingStateMachine::start(const BleAddress &target, const string &name) -{ - // sanity check the state machine is not already running - if (m_stateMachine.isRunning()) { - XLOGD_WARN("state machine already running"); - return; - } - - m_discoveryTimeout = m_discoveryTimeoutDefault; - m_isAutoPairing = false; - - // set the target device - m_targetAddress = target; - - // clear the pairing code - m_pairingCode = -1; - m_pairingMacHash = -1; - - // clear the list of addresses to filter for - m_pairingMacList.clear(); - - // set the pairing prefix map to contain just the one name match - m_targetedPairingNames.clear(); - m_targetedPairingNames.push_back(std::regex(name, std::regex_constants::ECMAScript)); - - // start the state machine - m_stateMachine.start(); - - m_pairingAttempts++; - m_pairingSucceeded = false; - XLOGD_INFO("started pairing targeting %s", target.toString().c_str()); + XLOGD_INFO("started pairing, searching for device with prefix code %03d or MAC hash 0x%02X", m_pairingCode, m_pairingMacHash); } // ----------------------------------------------------------------------------- @@ -394,12 +313,10 @@ void BleRcuPairingStateMachine::startWithMacList(const std::vector & // clear the target device m_targetAddress.clear(); - // store the pairing code + // clear data for other pairing methods, this method is for MAC address match only m_pairingCode = -1; m_pairingMacHash = -1; - - // create list of supported remotes regex to match to the name of the device - m_supportedPairingNames.clear(); + m_targetedPairingNames.clear(); // set the list of addresses to filter for m_pairingMacList = macList; @@ -862,44 +779,47 @@ void BleRcuPairingStateMachine::processDevice(const BleAddress &address, vector::const_iterator it_name = m_targetedPairingNames.begin(); for (; it_name != m_targetedPairingNames.end(); ++it_name) { if (std::regex_match(name.c_str(), *it_name)) { - XLOGD_INFO("Device (%s, %s) has a name targeted for pairing!", + XLOGD_INFO("Device (%s, %s) name has a match in the pairing name target list!", name.c_str(), address.toString().c_str()); break; } } if (it_name == m_targetedPairingNames.end()) { - // Device not found through conventional means, see if we are pairing based on MAC hash - // Because if we are pairing based on MAC hash, m_targetedPairingNames is first cleared + XLOGD_INFO("Device (%s, %s) name not in name target list, checking other pairing methods...", name.c_str(), address.toString().c_str()); + if (m_pairingMacHash != -1) { + // Device not found through name match, see if there is a MAC hash match // Check if MAC hash matches int macHash = 0; for (int i = 0; i < 6; ++i) { macHash += (int)address[i]; } macHash &= 0xFF; - XLOGD_INFO("Pairing based on MAC hash, requested MAC hash = 0x%02X, this device = 0x%02X (%s, %s)", - m_pairingMacHash, macHash, name.c_str(), address.toString().c_str()); if (m_pairingMacHash != macHash) { + XLOGD_INFO("Device (%s, %s) MAC hash (0x%02X) does not match requested MAC hash (0x%02X), ignoring... ", + name.c_str(), address.toString().c_str(), macHash, m_pairingMacHash); return; + } else { + XLOGD_INFO("Device (%s, %s) MAC hash matches!", name.c_str(), address.toString().c_str()); } - // Device not found through conventional means or MAC hash so let's check a mac address list - // Pairing via a mac address list clears supported names and the pairing mac hash } else if (m_pairingMacList.size() != 0) { - if (m_pairingMacList.size() != 0) { - // check if the mac address matches any of the ones in the filter list (if it exists) - bool found = false; - for (const auto &filterAddress : m_pairingMacList) { - if (address == filterAddress) { - found = true; - break; - } + // Device not found through name match or MAC hash so let's check the mac address list + // Pairing via a mac address list clears other pairing methods so execution should always fall here + + bool found = false; + for (const auto &filterAddress : m_pairingMacList) { + if (address == filterAddress) { + found = true; + break; } + } - if (!found) { - XLOGD_DEBUG("device with address %s is not in the mac address filter list - ignoring", address.toString().c_str()); - return; - } + if (!found) { + XLOGD_INFO("Device (%s, %s) is not in the mac address filter list - ignoring...", name.c_str(), address.toString().c_str()); + return; + } else { + XLOGD_INFO("Device (%s, %s) has a match in the MAC address filter list!", name.c_str(), address.toString().c_str()); } } else { // log an error if we don't already have a target device @@ -924,7 +844,7 @@ void BleRcuPairingStateMachine::processDevice(const BleAddress &address, return; } - XLOGD_INFO("Found target device (%s, %s)", name.c_str(), address.toString().c_str()); + XLOGD_INFO("Device (%s, %s) is targeted for pairing!", name.c_str(), address.toString().c_str()); // store the target address m_targetAddress = address; diff --git a/src/ble/hal/blercu/blercupairingstatemachine.h b/src/ble/hal/blercu/blercupairingstatemachine.h index d21b46b1..cfb15c31 100644 --- a/src/ble/hal/blercu/blercupairingstatemachine.h +++ b/src/ble/hal/blercu/blercupairingstatemachine.h @@ -70,14 +70,12 @@ class BleRcuPairingStateMachine public: bool isRunning() const; - bool isAutoPairing() const; + bool isScanningForAutoPair() const; int pairingCode() const; // public slots: - void start(const BleAddress &target, const std::string &name); void startAutoWithTimeout(int timeoutMs); void startWithCode(uint8_t pairingCode); - void startWithMacHash(uint8_t macHash); void startWithMacList(const std::vector &macList); void stop(); diff --git a/src/ble/hal/configsettings/configmodelsettings.cpp b/src/ble/hal/configsettings/configmodelsettings.cpp index de8c1dee..685bfa73 100644 --- a/src/ble/hal/configsettings/configmodelsettings.cpp +++ b/src/ble/hal/configsettings/configmodelsettings.cpp @@ -71,36 +71,6 @@ ConfigModelSettingsData::ConfigModelSettingsData(const ConfigModelSettingsData & Constructs some vendor settings from the supplied json object, if the json object has errors then an invalid object is created. - - The object should be formatted like the following: - - \code - [ - { - "name": "PR3", - "scanNameFormat": "U-PR3 EntOS RCU", - "connectNameFormat": "[UP]-PR3 EntOS RCU", - "otaProductName": "PR3-10", - "standbyMode": "C", - "services": { - "type": "gatt", - "required": [ - "Battery", - "Device Info", - "Immediate Alert", - "RDK Voice", - "RDK Infrared", - "RDK Firmware Upgrade" - ], - "optional": [ - "RDK Remote Control" - ] - } - }, - ... - ] - \endcode - */ ConfigModelSettingsData::ConfigModelSettingsData(json_t *json) : m_valid(false) @@ -116,10 +86,12 @@ ConfigModelSettingsData::ConfigModelSettingsData(json_t *json) , m_hasConnParams(false) , m_servicesType(ConfigModelSettings::GattServiceType) { + XLOGD_INFO("--------------------------------------"); + // name field json_t *obj = json_object_get(json, "name"); if (!obj || !json_is_string(obj)) { - XLOGD_ERROR("invalid 'name' field"); + XLOGD_ERROR("Required field 'name' INVALID, aborting..."); return; } m_name = json_string_value(obj); @@ -130,54 +102,79 @@ ConfigModelSettingsData::ConfigModelSettingsData(json_t *json) obj = json_object_get(json, "disabled"); if (obj) { if (!json_is_boolean(obj)) { - XLOGD_ERROR("invalid 'disabled' field"); - return; + XLOGD_WARN("Optional field 'disabled' invalid, continuing..."); } else { m_disabled = json_is_true(obj); + XLOGD_INFO("parsed 'disabled' field value <%s>", m_disabled ? "TRUE" : "FALSE"); } } - // (optional) pairingFormat field - obj = json_object_get(json, "pairingNameFormat"); - if (!obj || !json_is_string(obj)) { - XLOGD_WARN("invalid 'pairingNameFormat' field, not fatal, continuing to parse info"); - } else { - m_pairingNameFormat = json_string_value(obj); + // Advertising names field + json_t *advertisingNamesObj = json_object_get(json, "advertisingNames"); + if (!advertisingNamesObj || !json_is_object(advertisingNamesObj)) { + XLOGD_ERROR("Required field 'advertisingNames' INVALID, aborting..."); + return; } - - // scanNameFormat field - obj = json_object_get(json, "scanNameFormat"); + // advertisingNames.regexPairing field + obj = json_object_get(advertisingNamesObj, "regexPairing"); if (!obj || !json_is_string(obj)) { - XLOGD_ERROR("invalid 'scanNameFormat' field, this is required so returning..."); + XLOGD_ERROR("Required field 'advertisingNames.regexPairing' INVALID, aborting..."); return; } m_scanNameMatcher = std::regex(json_string_value(obj), std::regex_constants::ECMAScript); - XLOGD_INFO("Pairing name regex <%s>", json_string_value(obj)); - - // (optional) connectNameFormat field - obj = json_object_get(json, "connectNameFormat"); - if (!obj || !json_is_string(obj)) { - XLOGD_WARN("invalid 'connectNameFormat' field, not fatal, setting to scanNameFormat"); - m_connectNameMatcher = m_scanNameMatcher; - } else { - m_connectNameMatcher = std::regex(json_string_value(obj), std::regex_constants::ECMAScript); + m_connectNameMatcher = m_scanNameMatcher; + XLOGD_INFO("Pairing and reconnect advertising name regex <%s>", json_string_value(obj)); + + + // (optional) advertisingNames.optional object + json_t *optionalNames = json_object_get(advertisingNamesObj, "optional"); + if (optionalNames) { + if (!json_is_object(optionalNames)) { + XLOGD_WARN("Optional field 'advertisingNames.optional' invalid, continuing..."); + } else { + // (optional) formatSpecifierTargetedPairing field + obj = json_object_get(optionalNames, "formatSpecifierTargetedPairing"); + if (obj) { + if (!json_is_string(obj)) { + XLOGD_WARN("Optional field 'advertisingNames.optional.formatSpecifierTargetedPairing' invalid, continuing..."); + } else { + m_pairingNameFormat = json_string_value(obj); + XLOGD_INFO("Pairing name printf format specifier for targeted pairing <%s>", m_pairingNameFormat.c_str()); + } + } + + // (optional) regexReconnect field + obj = json_object_get(optionalNames, "regexReconnect"); + if (obj) { + if (!json_is_string(obj)) { + XLOGD_WARN("Optional field 'advertisingNames.optional.regexReconnect' invalid, continuing..."); + } else { + m_connectNameMatcher = std::regex(json_string_value(obj), std::regex_constants::ECMAScript); + XLOGD_INFO("Reconnect advertising name regex overridden with <%s>", json_string_value(obj)); + } + } + } } // (optional) otaProductName field obj = json_object_get(json, "otaProductName"); - if (!obj || !json_is_string(obj)) { - XLOGD_WARN("invalid 'otaProductName' field, not fatal, continuing to parse info"); - } else { - m_otaProductName = json_string_value(obj); + if (obj) { + if (!json_is_string(obj)) { + XLOGD_WARN("Optional field 'otaProductName' invalid, continuing..."); + } else { + m_otaProductName = json_string_value(obj); + XLOGD_INFO("parsed 'otaProductName' field value <%s>", m_otaProductName.c_str()); + } } // (optional) typeZ field obj = json_object_get(json, "typeZ"); if (obj) { if (!json_is_boolean(obj)) { - XLOGD_WARN("invalid 'typeZ' field, not fatal, continuing to parse info"); + XLOGD_WARN("Optional field 'typeZ' invalid, continuing..."); } else { m_typeZ = json_is_true(obj); + XLOGD_INFO("parsed 'typeZ' field value <%s>", m_typeZ ? "true" : "false"); } } @@ -185,9 +182,10 @@ ConfigModelSettingsData::ConfigModelSettingsData(json_t *json) obj = json_object_get(json, "connParamUpdateBeforeOtaVersion"); if (obj) { if (!json_is_string(obj)) { - XLOGD_WARN("invalid 'connParamUpdateBeforeOtaVersion' field, not fatal, continuing to parse info"); + XLOGD_WARN("Optional field 'connParamUpdateBeforeOtaVersion' invalid, continuing..."); } else { m_connParamUpdateBeforeOtaVersion = json_string_value(obj); + XLOGD_INFO("parsed 'connParamUpdateBeforeOtaVersion' field value <%s>", m_connParamUpdateBeforeOtaVersion.c_str()); } } @@ -195,9 +193,10 @@ ConfigModelSettingsData::ConfigModelSettingsData(json_t *json) obj = json_object_get(json, "upgradePauseVersion"); if (obj) { if (!json_is_string(obj)) { - XLOGD_WARN("invalid 'upgradePauseVersion' field, not fatal, continuing to parse info"); + XLOGD_WARN("Optional field 'upgradePauseVersion' invalid, continuing..."); } else { m_upgradePauseVersion = json_string_value(obj); + XLOGD_INFO("parsed 'upgradePauseVersion' field value <%s>", m_upgradePauseVersion.c_str()); } } @@ -205,32 +204,37 @@ ConfigModelSettingsData::ConfigModelSettingsData(json_t *json) obj = json_object_get(json, "upgradeStuckVersion"); if (obj) { if (!json_is_string(obj)) { - XLOGD_WARN("invalid 'upgradeStuckVersion' field, not fatal, continuing to parse info"); + XLOGD_WARN("Optional field 'upgradeStuckVersion' invalid, continuing..."); } else { m_upgradeStuckVersion = json_string_value(obj); + XLOGD_INFO("parsed 'upgradeStuckVersion' field value <%s>", m_upgradeStuckVersion.c_str()); } } // (optional) standbyMode field obj = json_object_get(json, "standbyMode"); - if (!obj || !json_is_string(obj)) { - XLOGD_WARN("invalid or missing 'standbyMode' field, not fatal, continuing to parse info"); - } else { - m_standbyMode = json_string_value(obj); + if (obj) { + if (!json_is_string(obj)) { + XLOGD_WARN("Optional field 'standbyMode' invalid, continuing..."); + } else { + m_standbyMode = json_string_value(obj); + XLOGD_INFO("parsed 'standbyMode' field value <%s>", m_standbyMode.c_str()); + } } // (optional) voiceKeyCode field obj = json_object_get(json, "voiceKeyCode"); if (obj) { if(!json_is_integer(obj)) { - XLOGD_WARN("invalid 'voiceKeyCode' field, not fatal, continuing to parse info"); + XLOGD_WARN("Optional field 'voiceKeyCode' invalid, continuing..."); } else { json_int_t keyCode = json_integer_value(obj); if(keyCode < 0 || keyCode > 0xFFFF) { - XLOGD_WARN("out of range 'voiceKeyCode' field, not fatal, continuing to parse info"); + XLOGD_WARN("Optional field 'voiceKeyCode' out of range, continuing..."); } else { m_voiceKeyCode = keyCode; m_voiceKeyCodePresent = true; + XLOGD_INFO("parsed 'voiceKeyCode' field value <%u>", m_voiceKeyCode); } } } @@ -238,28 +242,29 @@ ConfigModelSettingsData::ConfigModelSettingsData(json_t *json) // services field json_t *servicesObj = json_object_get(json, "services"); if (!servicesObj || !json_is_object(servicesObj)) { - XLOGD_ERROR("missing or invalid 'services' field"); + XLOGD_ERROR("Required field 'services' INVALID, aborting..."); return; } // services.type field obj = json_object_get(servicesObj, "type"); if (!obj || !json_is_string(obj)) { - XLOGD_ERROR("missing 'service.type' field"); + XLOGD_ERROR("Required field 'service.type' INVALID, aborting..."); return; } string typeStr = json_string_value(obj); + XLOGD_INFO("parsed 'service.type' field value <%s>", typeStr.c_str()); if (typeStr.compare("gatt") == 0) { m_servicesType = ConfigModelSettings::GattServiceType; } else { - XLOGD_ERROR("invalid 'service.type' field value"); + XLOGD_ERROR("Required field 'service.type' not supported, aborting..."); return; } // services.required array json_t *requiredArray = json_object_get(servicesObj, "required"); if (!requiredArray || !json_is_array(requiredArray)) { - XLOGD_ERROR( "missing or invalid 'services.required' field"); + XLOGD_ERROR("Required field 'services.required' INVALID, aborting..."); return; } size_t array_size = json_array_size(requiredArray); @@ -267,13 +272,13 @@ ConfigModelSettingsData::ConfigModelSettingsData(json_t *json) for (unsigned int i = 0; i < array_size; i++) { obj = json_array_get(requiredArray, i); if (!obj || !json_is_string(obj)) { - XLOGD_ERROR("invalid 'services.required' array entry"); + XLOGD_ERROR("Invalid 'services.required' array entry, aborting..."); return; } string serviceStr = json_string_value(obj); if (!BleUuid().doesServiceExist(serviceStr)) { - XLOGD_ERROR("invalid service name <%s>", serviceStr.c_str()); + XLOGD_ERROR("invalid service name <%s>, aborting...", serviceStr.c_str()); return; } m_servicesRequired.insert(serviceStr); @@ -283,78 +288,47 @@ ConfigModelSettingsData::ConfigModelSettingsData(json_t *json) for (const auto& service : m_servicesRequired) { servicesRequiredStr += service + ", "; } - servicesRequiredStr = servicesRequiredStr.substr(0, servicesRequiredStr.length() - 2); // Remove the trailing comma and space + if (!m_servicesRequired.empty()) { + servicesRequiredStr = servicesRequiredStr.substr(0, servicesRequiredStr.length() - 2); // Remove the trailing comma and space + } - XLOGD_DEBUG("m_servicesRequired = <%s>", servicesRequiredStr.c_str()); + XLOGD_INFO("Services required = <%s>", servicesRequiredStr.c_str()); // services.optional array json_t *optionalArray = json_object_get(servicesObj, "optional"); - if (!optionalArray || !json_is_array(optionalArray)) { - XLOGD_ERROR( "missing or invalid 'services.optional' field"); - return; - } - array_size = json_array_size(optionalArray); - - for (unsigned int i = 0; i < array_size; i++) { - obj = json_array_get(optionalArray, i); - if (!obj || !json_is_string(obj)) { - XLOGD_ERROR("invalid 'services.optional' array entry"); - return; - } - string serviceStr = json_string_value(obj); - - if (!BleUuid().doesServiceExist(serviceStr)) { - XLOGD_ERROR("invalid service name <%s>", serviceStr.c_str()); - return; - } - m_servicesOptional.insert(serviceStr); - } - - std::string servicesOptionalStr; - for (const auto& service : m_servicesOptional) { - servicesOptionalStr += service + ", "; - } - servicesOptionalStr = servicesOptionalStr.substr(0, servicesOptionalStr.length() - 2); // Remove the trailing comma and space - - XLOGD_DEBUG("m_servicesOptional = <%s>\n", servicesOptionalStr.c_str()); - - // (optional) connectionParams - // if (json.contains("connectionParams")) { - - // const QJsonValue connParams = json["connectionParams"]; - // if (!connParams.isObject()) { - // qWarning("invalid 'connectionParams' field"); - // return; - // } - - // const QJsonObject connParamsObj = connParams.toObject(); - // const QJsonValue maxInterval = connParamsObj["maxInterval"]; - // const QJsonValue minInterval = connParamsObj["minInterval"]; - - // if (maxInterval.isDouble() && minInterval.isDouble()) { - // m_connParams.setIntervalRange(minInterval.toDouble(), - // maxInterval.toDouble()); - // } else if (maxInterval.type() != minInterval.type()) { - // qWarning("both 'maxInterval' and 'minInterval' must be set to set " - // "connection interval"); - // } - - // const QJsonValue latency = connParamsObj["latency"]; + if (optionalArray) { + if (!json_is_array(optionalArray)) { + XLOGD_WARN("Optional field 'services.optional' invalid, continuing..."); + } else { + array_size = json_array_size(optionalArray); - // if (latency.isDouble()) - // m_connParams.setLatency(latency.toInt(m_connParams.latency())); - // else if (!latency.isUndefined()) - // qWarning("invalid type for latency setting"); + for (unsigned int i = 0; i < array_size; i++) { + obj = json_array_get(optionalArray, i); + if (!obj || !json_is_string(obj)) { + XLOGD_ERROR("Invalid 'services.optional' array entry, aborting..."); + return; + } + string serviceStr = json_string_value(obj); - // const QJsonValue supervisionTimeout = connParamsObj["supervisionTimeout"]; + if (!BleUuid().doesServiceExist(serviceStr)) { + XLOGD_ERROR("invalid service name <%s>, aborting...", serviceStr.c_str()); + return; + } + m_servicesOptional.insert(serviceStr); + } - // if (supervisionTimeout.isDouble()) - // m_connParams.setSupervisionTimeout(supervisionTimeout.toInt(m_connParams.supervisionTimeout())); - // else if (!supervisionTimeout.isUndefined()) - // qWarning("invalid type for supervisionTimeout setting"); + std::string servicesOptionalStr; + for (const auto& service : m_servicesOptional) { + servicesOptionalStr += service + ", "; + } + if (!m_servicesOptional.empty()) { + servicesOptionalStr = servicesOptionalStr.substr(0, servicesOptionalStr.length() - 2); // Remove the trailing comma and space + } - // m_hasConnParams = true; - // } + XLOGD_INFO("Services optional = <%s>", servicesOptionalStr.c_str()); + } + } + XLOGD_INFO("--------------------------------------"); m_valid = true; } diff --git a/src/ble/hal/configsettings/configsettings.cpp b/src/ble/hal/configsettings/configsettings.cpp index 053e93a5..ce8cc3a7 100644 --- a/src/ble/hal/configsettings/configsettings.cpp +++ b/src/ble/hal/configsettings/configsettings.cpp @@ -102,7 +102,7 @@ ConfigSettings::TimeOuts ConfigSettings::parseTimeouts(json_t *json) } else { *(fields[i].storage) = (int)value; } - XLOGD_DEBUG("'%s' field = %d", fields[i].name, *(fields[i].storage)); + XLOGD_INFO("'%s' field = %d ms", fields[i].name, *(fields[i].storage)); } } diff --git a/src/ctrlm_ir_controller.cpp b/src/ctrlm_ir_controller.cpp index 17db165b..c42b8eae 100644 --- a/src/ctrlm_ir_controller.cpp +++ b/src/ctrlm_ir_controller.cpp @@ -206,7 +206,6 @@ void ctrlm_ir_controller_t::process_event_key(uint16_t key_code) { XLOGD_INFO("received IR key for BLE pairing (scan code 0x%06x : pairCode=%hhu)", scan_code_, commandCode); ctrlm_iarm_call_StartPairWithCode_params_t params; - params.key_code = key_code; params.pair_code = commandCode; ctrlm_main_queue_msg_pair_with_code_t msg; From 38c2413c69a16538671609dfbb3b16d6b3a4ead3 Mon Sep 17 00:00:00 2001 From: dwolaver <44593664+dwolaver@users.noreply.github.com> Date: Mon, 4 May 2026 11:13:35 -0400 Subject: [PATCH 50/81] RDKEMW-16763 : rf4ce init failure causes deadlock (#217) --- src/ctrlm_main.cpp | 57 +++++++++++++++++++++++++------ src/rf4ce/ctrlm_rf4ce_network.cpp | 34 ++++++++++++++++-- 2 files changed, 79 insertions(+), 12 deletions(-) diff --git a/src/ctrlm_main.cpp b/src/ctrlm_main.cpp index 81168180..54ddb884 100644 --- a/src/ctrlm_main.cpp +++ b/src/ctrlm_main.cpp @@ -23,8 +23,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -347,6 +349,8 @@ static gboolean ctrlm_authservice_expired(gpointer user_data); static gboolean ctrlm_ntp_check(gpointer user_data); static void ctrlm_signals_register(void); static void ctrlm_signal_handler(int signal); +static gboolean ctrlm_unix_signal_terminate(gpointer user_data); +static gboolean ctrlm_unix_signal_quit(gpointer user_data); static void ctrlm_main_iarm_call_status_get_(ctrlm_main_iarm_call_status_t *status); static void ctrlm_main_iarm_call_property_get_(ctrlm_main_iarm_call_property_t *property); @@ -1098,27 +1102,51 @@ gboolean ctrlm_authservice_poll(gpointer user_data) { } #endif +// GLib main-loop callbacks for Unix signals — run in the main loop context so +// they are safe to call g_main_loop_quit() and other non-async-signal-safe APIs. +static gboolean ctrlm_unix_signal_terminate(gpointer user_data) { + int sig = GPOINTER_TO_INT(user_data); + XLOGD_INFO("Received %s", sig == SIGINT ? "SIGINT" : "SIGTERM"); + ctrlm_quit_main_loop(); + return G_SOURCE_CONTINUE; +} + +static gboolean ctrlm_unix_signal_quit(gpointer user_data) { + XLOGD_INFO("Received SIGQUIT"); +#ifdef BREAKPAD_SUPPORT + ctrlm_crash(); +#endif + return G_SOURCE_CONTINUE; +} + void ctrlm_signals_register(void) { - // Handle these signals + // Use g_unix_signal_add() so callbacks run inside the GLib main loop context + // rather than from an async signal handler, avoiding undefined behavior from + // calling non-async-signal-safe functions (e.g. g_main_loop_quit). XLOGD_INFO("Registering SIGINT..."); - if(signal(SIGINT, ctrlm_signal_handler) == SIG_ERR) { + if(0 == g_unix_signal_add(SIGINT, ctrlm_unix_signal_terminate, GINT_TO_POINTER(SIGINT))) { XLOGD_ERROR("Unable to register for SIGINT."); } XLOGD_INFO("Registering SIGTERM..."); - if(signal(SIGTERM, ctrlm_signal_handler) == SIG_ERR) { + if(0 == g_unix_signal_add(SIGTERM, ctrlm_unix_signal_terminate, GINT_TO_POINTER(SIGTERM))) { XLOGD_ERROR("Unable to register for SIGTERM."); } XLOGD_INFO("Registering SIGQUIT..."); - if(signal(SIGQUIT, ctrlm_signal_handler) == SIG_ERR) { + if(0 == g_unix_signal_add(SIGQUIT, ctrlm_unix_signal_quit, NULL)) { XLOGD_ERROR("Unable to register for SIGQUIT."); } - XLOGD_INFO("Registering SIGPIPE..."); - if(signal(SIGPIPE, ctrlm_signal_handler) == SIG_ERR) { - XLOGD_ERROR("Unable to register for SIGPIPE."); + // Ignore SIGPIPE — broken-pipe errors are handled at the call site via errno. + XLOGD_INFO("Ignoring SIGPIPE..."); + errno = 0; + if(SIG_ERR == signal(SIGPIPE, SIG_IGN)) { + int errsv = errno; + XLOGD_ERROR("Unable to ignore SIGPIPE <%s>", strerror(errsv)); } } -void ctrlm_signal_handler(int signal) { +// Direct-call fallback only (e.g. from ctrlm_on_network_assert when kill() fails). +// No longer registered as an OS signal handler, so non-async-signal-safe calls are safe. +static void ctrlm_signal_handler(int signal) { switch(signal) { case SIGTERM: case SIGINT: { @@ -1233,9 +1261,18 @@ void ctrlm_on_network_assert(ctrlm_network_id_t network_id) { // Invalidate main thread so terminate does not attempt to terminate it g_ctrlm.main_thread = NULL; } - // g_main_loop_quit() will be called in ctrlm_signal_handler(SIGTERM) + // g_main_loop_quit() will be called when the SIGTERM GLib source fires, + // or directly via ctrlm_signal_handler() in the kill() fallback below. g_ctrlm.return_code = -1; - ctrlm_signal_handler(SIGTERM); + + errno = 0; + int rc = kill(getpid(), SIGTERM); + if(rc != 0) { + int errsv = errno; + XLOGD_ERROR("Failed to send SIGTERM to self <%s> - invoking shutdown handler directly", strerror(errsv)); + ctrlm_signal_handler(SIGTERM); + } + // give main() time to clean up sleep(5); // Exit here in case main fails to exit diff --git a/src/rf4ce/ctrlm_rf4ce_network.cpp b/src/rf4ce/ctrlm_rf4ce_network.cpp index 5009c592..11a81c3c 100644 --- a/src/rf4ce/ctrlm_rf4ce_network.cpp +++ b/src/rf4ce/ctrlm_rf4ce_network.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include "ctrlm.h" #include "ctrlm_log.h" @@ -411,8 +412,37 @@ ctrlm_hal_result_t ctrlm_obj_network_rf4ce_t::hal_init_request(GThread *ctrlm_ma // Block until initialization is complete or a timeout occurs XLOGD_INFO("Waiting for %s initialization...", name_get()); - sem_wait(&semaphore_); - sem_destroy(&semaphore_); + struct timespec timeout; + + int sem_result = 0; + errno = 0; + int rc = clock_gettime(CLOCK_REALTIME, &timeout); + if(rc != 0) { + int errsv = errno; + // If we fail to get the current time, we should still wait on the semaphore, but we will wait indefinitely instead of timing out + XLOGD_ERROR("Failed to get current time <%s>. wait indefinitely", strerror(errsv)); + errno = 0; + sem_result = sem_wait(&semaphore_); + } else { + timeout.tv_sec += 60; // this operation has been tested to complete in about 6 seconds in worst case scenario (set the timeout to 10x) + + errno = 0; + sem_result = sem_timedwait(&semaphore_, &timeout); + } + + if(sem_result == -1) { + if(errno == ETIMEDOUT) { + XLOGD_ERROR("Timeout waiting for %s initialization", name_get()); + } else if(errno == EINTR) { + XLOGD_ERROR("Interrupted while waiting for %s initialization", name_get()); + } else { + int errsv = errno; + XLOGD_ERROR("Error waiting for %s initialization <%s>", name_get(), strerror(errsv)); + } + init_result_ = CTRLM_HAL_RESULT_ERROR; + } else { + sem_destroy(&semaphore_); + } ready_ = (CTRLM_HAL_RESULT_SUCCESS == init_result_); From e101ccd4fcf0c6c9e9dbbc750e8d7cba05f56242 Mon Sep 17 00:00:00 2001 From: Gene Gallagher Date: Tue, 5 May 2026 07:38:16 -0400 Subject: [PATCH 51/81] 1.1.15 release changelog updates --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 00d71742..da765996 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,15 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [1.1.15](https://github.com/rdkcentral/control/compare/1.1.14...1.1.15) + +> 5 May 2026 + +- RDKEMW-16763 : rf4ce init failure causes deadlock [`#217`](https://github.com/rdkcentral/control/pull/217) +- RDKEMW-13607: merge pair code with mac hash methods [`#191`](https://github.com/rdkcentral/control/pull/191) +- RDKEMW-17614 : mask_pii RFC not applied correctly [`#218`](https://github.com/rdkcentral/control/pull/218) + + #### [1.1.14](https://github.com/rdkcentral/control/compare/1.1.13...1.1.14) > 22 April 2026 From 6ea34319800b4541b26d67c8cefa2ca4bb761c95 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Tue, 5 May 2026 13:24:36 -0400 Subject: [PATCH 52/81] RDKEMW-14537: Coverity integration for ctrlm (#199) --- .github/copilot-instructions.md | 18 +++ .github/workflows/native_full_build.yml | 29 ++++ ci/build_dependencies.sh | 204 ++++++++++++++++++++++++ ci/cov_build.sh | 112 +++++++++++++ ci/mocks/devicesettings_ctrlm.patch | 40 +++++ ci/mocks/safec_lib.h | 44 +++++ ci/mocks/testframework_overrides.h | 48 ++++++ ci/mocks/xlog_ci_compat.h | 42 +++++ 8 files changed, 537 insertions(+) create mode 100644 .github/copilot-instructions.md create mode 100644 .github/workflows/native_full_build.yml create mode 100644 ci/build_dependencies.sh create mode 100644 ci/cov_build.sh create mode 100644 ci/mocks/devicesettings_ctrlm.patch create mode 100644 ci/mocks/safec_lib.h create mode 100644 ci/mocks/testframework_overrides.h create mode 100644 ci/mocks/xlog_ci_compat.h diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 00000000..ff832a34 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,18 @@ +# Copilot Instructions + +## Repository overview +This is the **ctrlm-main** (Control Manager) plugin — a Thunder/WPEFramework plugin for RDK remote control management. + +## ci/ directory +The `ci/` directory contains **native CI build support files only**. It is not part of the application. + +- `ci/build_dependencies.sh` / `ci/cov_build.sh` — scripts that build the plugin in a CI container without a full RDK target image +- `ci/mocks/xlog_ci_compat.h` — minimal shim that pulls `std::string`, `std::map`, `std::tuple`, `std::get` into the global namespace (mirrors the transitive effect of the real rdkx_logger.h in the Yocto build) +- `ci/mocks/testframework_overrides.h` — supplements testframework mocks with declarations ctrlm needs that are not yet upstream +- `ci/mocks/devicesettings_ctrlm.patch` — patch applied to the testframework `devicesettings.h` at CI time for ctrlm-specific additions (ducking types, `setAudioDucking`, `Manager::IsInitialized`). Remove once these land in testframework develop. +- `ci/mocks/safec_lib.h` — compatibility shim mapping `safec_lib.h` to system libsafec headers +- `ci/headers/` — empty stub headers and real xr-voice-sdk headers generated/copied at CI build time; not committed to source + +CI currently pins `xr-voice-sdk` to tag `1.0.13` in `build_dependencies.sh`. Real xr-voice-sdk headers (including `rdkx_logger.h`, `xr_voice_sdk.h`, and generated `rdkx_logger_modules.h`) are produced by `build_dependencies.sh` and placed in `ci/headers/xr-voice-sdk/`. Mock/stub headers for platform libraries (IARM, DeviceSettings, RFC, etc.) are sourced from `entservices-testframework/` at CI build time. + +When suggesting code or answering questions, treat CI mocks as scaffolding, not as authoritative API definitions. For real API shapes refer to the installed headers under `install/usr/include/` or the upstream repositories (Thunder, entservices-apis, xr-voice-sdk). diff --git a/.github/workflows/native_full_build.yml b/.github/workflows/native_full_build.yml new file mode 100644 index 00000000..cff24b88 --- /dev/null +++ b/.github/workflows/native_full_build.yml @@ -0,0 +1,29 @@ +name: Build Control Manager in Native Environment + +on: + push: + branches: [ main, 'sprint/**', 'release/**', develop ] + pull_request: + branches: [ main, 'sprint/**', 'release/**', topic/RDK*, develop ] + +permissions: + contents: read + +jobs: + build-control-on-pr: + name: Build Control Manager in github rdkcentral + runs-on: ubuntu-latest + container: + image: ghcr.io/rdkcentral/docker-rdk-ci:latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: build dependencies + run: | + sh -x ci/build_dependencies.sh + + - name: cov build + run: | + sh -x ci/cov_build.sh diff --git a/ci/build_dependencies.sh b/ci/build_dependencies.sh new file mode 100644 index 00000000..9abff1c9 --- /dev/null +++ b/ci/build_dependencies.sh @@ -0,0 +1,204 @@ +#!/bin/bash +# +# If not stated otherwise in this file or this component's license file the +# following copyright and licenses apply: +# +# Copyright 2026 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. + +set -x +set -e +############################## +GITHUB_WORKSPACE="${PWD}" +cd "${GITHUB_WORKSPACE}" + +git config --global --add safe.directory "${GITHUB_WORKSPACE}" + +# ############################# +# 1. Install Dependencies and packages + +apt update +apt install -y \ + pkg-config \ + libsqlite3-dev \ + libcurl4-openssl-dev \ + libsystemd-dev \ + libglib2.0-dev \ + libjansson-dev \ + libarchive-dev \ + libssl-dev \ + zlib1g-dev \ + libdbus-1-dev \ + uuid-dev \ + libevdev-dev \ + libdrm-dev \ + libsafec-dev \ + python3-pip +python3 -m pip install jsonref + +########################################### +# 2. Clone the required repositories + +XRSDK_REF="1.0.13" +git clone --depth 1 --filter=blob:none --branch "${XRSDK_REF}" https://github.com/rdkcentral/xr-voice-sdk.git + +git clone --depth 1 --filter=blob:none --branch develop https://github.com/rdkcentral/entservices-testframework.git + +# Patch the upstream testframework devicesettings.h with ctrlm-specific +# additions (ducking types, setAudioDucking, Manager::IsInitialized). +# We can remove this if added to upstream testframework +git -C entservices-testframework apply "$GITHUB_WORKSPACE/ci/mocks/devicesettings_ctrlm.patch" + +git clone --depth 1 --filter=blob:none --sparse --branch develop https://github.com/rdkcentral/iarmmgrs.git +git -C iarmmgrs sparse-checkout set hal + +git clone --depth 1 --filter=blob:none --sparse https://github.com/rdkcentral/rdk-halif-deepsleep_manager.git +git -C rdk-halif-deepsleep_manager sparse-checkout set include + +git clone --depth 1 --filter=blob:none --sparse https://github.com/rdkcentral/rdk-halif-power_manager.git +git -C rdk-halif-power_manager sparse-checkout set include + +git clone --depth 1 --filter=blob:none --sparse --branch develop https://github.com/rdkcentral/rdkversion.git +git -C rdkversion sparse-checkout set src + +IARMMGRS_DIR="$GITHUB_WORKSPACE/iarmmgrs" +DEEPSLEEP_HAL_DIR="$GITHUB_WORKSPACE/rdk-halif-deepsleep_manager" +POWER_HAL_DIR="$GITHUB_WORKSPACE/rdk-halif-power_manager" +RDKVERSION_DIR="$GITHUB_WORKSPACE/rdkversion" + +############################ +# 3. Create stub/empty headers for external dependencies +echo "======================================================================================" +echo "Creating stub headers" + +HEADERS_DIR="$GITHUB_WORKSPACE/ci/headers" +XRSDK_HEADERS_DIR="$HEADERS_DIR/xr-voice-sdk" +mkdir -p "${HEADERS_DIR}" +mkdir -p "${HEADERS_DIR}/rdk/iarmbus" +mkdir -p "${HEADERS_DIR}/rdk/ds" +mkdir -p "${HEADERS_DIR}/rdk/iarmmgrs-hal" +mkdir -p "${XRSDK_HEADERS_DIR}" + +# Copy real xr-voice-sdk headers. +# xr_fdc.h is NOT copied: only needed when FDC_ENABLED=ON +cp "$GITHUB_WORKSPACE/xr-voice-sdk/src/xr-speech-vrex/xrsv.h" "${XRSDK_HEADERS_DIR}/" +cp "$GITHUB_WORKSPACE/xr-voice-sdk/src/xr-speech-router/xrsr.h" "${XRSDK_HEADERS_DIR}/" +cp "$GITHUB_WORKSPACE/xr-voice-sdk/src/xr-mq/xr_mq.h" "${XRSDK_HEADERS_DIR}/" +cp "$GITHUB_WORKSPACE/xr-voice-sdk/src/xr-speech-vrex/xrsv_http/xrsv_http.h" "${XRSDK_HEADERS_DIR}/" +cp "$GITHUB_WORKSPACE/xr-voice-sdk/src/xr-speech-vrex/xrsv_ws_nextgen/xrsv_ws_nextgen.h" "${XRSDK_HEADERS_DIR}/" +cp "$GITHUB_WORKSPACE/xr-voice-sdk/src/xr-timestamp/xr_timestamp.h" "${XRSDK_HEADERS_DIR}/" + +# Generate rdkx_logger_modules.h from xr-voice-sdk's module configuration, +# then copy the real rdkx_logger and xr_voice_sdk headers. +# This replaces the hand-written ci/mocks/control/ stubs. +python3 "$GITHUB_WORKSPACE/xr-voice-sdk/scripts/rdkx_logger_modules_to_c.py" \ + "$GITHUB_WORKSPACE/xr-voice-sdk/src/xr-logger/rdkv/rdkx_logger_modules.json" \ + "${XRSDK_HEADERS_DIR}/rdkx_logger_modules" "mw" +cp "$GITHUB_WORKSPACE/xr-voice-sdk/src/xr-logger/rdkx_logger_mw.h" "${XRSDK_HEADERS_DIR}/rdkx_logger.h" +cp "$GITHUB_WORKSPACE/xr-voice-sdk/src/xr_voice_sdk.h" "${XRSDK_HEADERS_DIR}/xr_voice_sdk.h" + +cd "${HEADERS_DIR}" + +# IARM headers (types provided via -include Iarm.h) +touch rdk/iarmbus/libIARM.h +touch rdk/iarmbus/libIBus.h +touch rdk/iarmbus/libIBusDaemon.h + +# IARM manager headers +# sysMgr.h conflicts with the forced Iarm.h mock, which already provides the +# needed SYSMgr types. Use a shim here. To remove it later, either stop +# force-including those overlapping Iarm.h declarations or drop sysMgr.h from +# ctrlm source. +cat > rdk/iarmmgrs-hal/sysMgr.h <<'EOF' +#ifndef CTRLM_CI_SYSMGR_SHIM_H +#define CTRLM_CI_SYSMGR_SHIM_H + +/* SYSMgr declarations are provided by the forced Iarm.h mock in CI. */ + +#endif +EOF +cp "$DEEPSLEEP_HAL_DIR/include/deepSleepMgr.h" rdk/iarmmgrs-hal/deepSleepMgr.h +cp "$POWER_HAL_DIR/include/plat_power.h" rdk/iarmmgrs-hal/pwrMgr.h +[ -f rdk/iarmmgrs-hal/sysMgr.h ] +[ -f rdk/iarmmgrs-hal/deepSleepMgr.h ] +[ -f rdk/iarmmgrs-hal/pwrMgr.h ] + +# Device settings headers (types provided via force-included devicesettings.h mock) +touch rdk/ds/audioOutputPort.hpp +touch rdk/ds/dsDisplay.h +touch rdk/ds/dsError.h +touch rdk/ds/dsMgr.h +touch rdk/ds/dsRpc.h +touch rdk/ds/dsTypes.h +touch rdk/ds/dsUtl.h +touch rdk/ds/exception.hpp +touch rdk/ds/host.hpp +touch rdk/ds/manager.hpp +touch rdk/ds/videoOutputPort.hpp +touch rdk/ds/videoOutputPortConfig.hpp +touch rdk/ds/videoOutputPortType.hpp +touch rdk/ds/videoResolution.hpp +touch rdk/ds/frontPanelIndicator.hpp +touch rdk/ds/frontPanelConfig.hpp + +# rfcapi.h (types provided via -include Rfc.h) +touch rfcapi.h + +# comcastIrKeyCodes.h (unconditionally included by ctrlm_main.cpp) +find "$IARMMGRS_DIR" -name comcastIrKeyCodes.h -print -quit | xargs -r -I{} cp "{}" comcastIrKeyCodes.h +[ -f comcastIrKeyCodes.h ] + +# rdkversion.h (used by ctrlm_main.cpp) +cp "$RDKVERSION_DIR/src/rdkversion.h" rdkversion.h +[ -f rdkversion.h ] + +# secure_wrapper (types provided via empty stub — no v_secure_* calls in core) +touch secure_wrapper.h + +# safec compatibility header - committed in ci/mocks, copied here so it is +# resolved on the generated-headers include path. +cp "$GITHUB_WORKSPACE/ci/mocks/safec_lib.h" safec_lib.h + +echo "Stub headers created successfully" + +cd "${GITHUB_WORKSPACE}" + +mkdir -p "${GITHUB_WORKSPACE}/install/usr/include" +printf '{}\n' > "${GITHUB_WORKSPACE}/install/usr/include/ctrlm_config_empty.json" + +############################ +# 4. Create stub shared libraries for linking +echo "======================================================================================" +echo "Creating stub libraries" + +STUB_LIB_DIR="$GITHUB_WORKSPACE/install/usr/lib" +mkdir -p "${STUB_LIB_DIR}" + +# Create a minimal C stub source +cat > /tmp/stub.c << 'STUB_EOF' +void __stub_placeholder(void) {} +STUB_EOF + +# Build stub .so for each missing library +# nopoll and dshalcli are unused (factory-only) but unconditionally linked by CMakeLists.txt +# We can remove them from the link list in the future if desired, but for now just provide stubs to satisfy the linker. +for lib in xr-voice-sdk rdkversion IARMBus ds nopoll dshalcli rfcapi secure_wrapper evdev; do + gcc -shared -fPIC -o "${STUB_LIB_DIR}/lib${lib}.so" /tmp/stub.c +done + +rm /tmp/stub.c + +echo "Stub libraries created in ${STUB_LIB_DIR}" +echo "======================================================================================" +echo "build_dependencies.sh complete" diff --git a/ci/cov_build.sh b/ci/cov_build.sh new file mode 100644 index 00000000..3a51b921 --- /dev/null +++ b/ci/cov_build.sh @@ -0,0 +1,112 @@ +#!/bin/bash +# +# If not stated otherwise in this file or this component's license file the +# following copyright and licenses apply: +# +# Copyright 2026 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. + +set -x +set -e +############################## +GITHUB_WORKSPACE="${PWD}" +ls -la "${GITHUB_WORKSPACE}" +############################ + +# Build control (ctrlm-main) +echo "building control (ctrlm-main)" + +XRSDK_REAL_HEADERS="$GITHUB_WORKSPACE/ci/headers/xr-voice-sdk" +XLOG_COMPAT="$GITHUB_WORKSPACE/ci/mocks/xlog_ci_compat.h" +MOCK_DIR="$GITHUB_WORKSPACE/entservices-testframework/Tests/mocks" +MOCK_OVERRIDES="$GITHUB_WORKSPACE/ci/mocks/testframework_overrides.h" +HEADERS_DIR="$GITHUB_WORKSPACE/ci/headers" +EMPTY_JSON="$GITHUB_WORKSPACE/install/usr/include/ctrlm_config_empty.json" +GLIB_CFLAGS="$(pkg-config --cflags glib-2.0)" + +cmake -G Ninja -S "$GITHUB_WORKSPACE" -B build/control \ +-DCMAKE_INSTALL_PREFIX="${GITHUB_WORKSPACE}/install/usr" \ +-DCMAKE_INSTALL_SYSCONFDIR="${GITHUB_WORKSPACE}/install/etc" \ +-DCMAKE_MODULE_PATH="${GITHUB_WORKSPACE}/install/tools/cmake" \ +-DCMAKE_VERBOSE_MAKEFILE=ON \ +-DCMAKE_PROJECT_VERSION="1.0.0" \ +-DTHUNDER=OFF \ +-DTHUNDER_SECURITY=OFF \ +-DBLE_ENABLED=OFF \ +-DRF4CE_ENABLED=OFF \ +-DIP_ENABLED=OFF \ +-DTELEMETRY_SUPPORT=OFF \ +-DAUTH_ENABLED=OFF \ +-DXRSR_HTTP=OFF \ +-DXRSR_SDT=OFF \ +-DBUILD_CTRLM_FACTORY=OFF \ +-DBUILD_FACTORY_TEST=OFF \ +-DUSE_SAFEC=OFF \ +-DUSE_IARM_POWER_MANAGER=ON \ +-DBREAKPAD=OFF \ +-DFDC_ENABLED=OFF \ +-DENABLE_ASYNC_SRVR_MSG=OFF \ +-DHIDE_NON_EXTERNAL_SYMBOLS=OFF \ +-DBUILD_SYSTEM=NONE \ +-DCTRLM_UTILS_JSON_COMBINE="${GITHUB_WORKSPACE}/xr-voice-sdk/scripts/vsdk_json_combine.py" \ +-DCTRLM_UTILS_JSON_TO_HEADER="${GITHUB_WORKSPACE}/xr-voice-sdk/scripts/vsdk_json_to_header.py" \ +-DCTRLM_CONFIG_JSON_CPC="${EMPTY_JSON}" \ +-DCTRLM_CONFIG_JSON_CPC_SUB="${EMPTY_JSON}" \ +-DCTRLM_CONFIG_JSON_CPC_ADD="${EMPTY_JSON}" \ +-DCTRLM_CONFIG_JSON_MAIN_SUB="${EMPTY_JSON}" \ +-DCTRLM_CONFIG_JSON_MAIN_ADD="${EMPTY_JSON}" \ +-DCMAKE_CXX_FLAGS=" \ +-I ${XRSDK_REAL_HEADERS} \ +-I ${MOCK_DIR} \ +-I ${MOCK_DIR}/devicesettings \ +-I ${HEADERS_DIR} \ +-I ${HEADERS_DIR}/rdk/iarmbus \ +-I ${HEADERS_DIR}/rdk/ds \ +-I ${HEADERS_DIR}/rdk/iarmmgrs-hal \ +-I ${GITHUB_WORKSPACE}/install/usr/include \ +-I /usr/include/libdrm \ +${GLIB_CFLAGS} \ +-include ${XLOG_COMPAT} \ +-include ${MOCK_DIR}/Iarm.h \ +-include ${MOCK_OVERRIDES} \ +-include ${MOCK_DIR}/devicesettings.h \ +-include ${MOCK_DIR}/Rfc.h \ +-Wall -Wno-error \ +-DSAFEC_DUMMY_API \ +-DDISABLE_SECURITY_TOKEN" \ +-DCMAKE_C_FLAGS=" \ +-I ${XRSDK_REAL_HEADERS} \ +-I ${MOCK_DIR} \ +-I ${HEADERS_DIR} \ +-I ${HEADERS_DIR}/rdk/iarmbus \ +-I ${HEADERS_DIR}/rdk/ds \ +-I ${HEADERS_DIR}/rdk/iarmmgrs-hal \ +-I ${GITHUB_WORKSPACE}/install/usr/include \ +-I /usr/include/libdrm \ +${GLIB_CFLAGS} \ +-Wall -Wno-error \ +-DSAFEC_DUMMY_API \ +-DDISABLE_SECURITY_TOKEN" \ +-DCMAKE_EXE_LINKER_FLAGS="-L${GITHUB_WORKSPACE}/install/usr/lib -Wl,--unresolved-symbols=ignore-all" + +# CMakeLists.txt unconditionally appends -Werror via target_compile_options, which +# comes after CMAKE_CXX_FLAGS and overrides -Wno-error. Strip it from the generated +# build files after cmake configure. To remove this, add an ENABLE_WERROR option to +# CMakeLists.txt that appends -Wno-error when OFF, and pass -DENABLE_WERROR=OFF here. +find "${GITHUB_WORKSPACE}/build/control" \( -name "*.ninja" -o -name "flags.make" \) -exec sed -i 's/\(^\|[[:space:]]\)-Werror\([[:space:]]\|$\)/\1\2/g' {} \; + +cmake --build build/control -j$(nproc) 2>&1 +echo "======================================================================================" +echo "control build complete" +exit 0 diff --git a/ci/mocks/devicesettings_ctrlm.patch b/ci/mocks/devicesettings_ctrlm.patch new file mode 100644 index 00000000..d2faf8a8 --- /dev/null +++ b/ci/mocks/devicesettings_ctrlm.patch @@ -0,0 +1,40 @@ +--- a/Tests/mocks/devicesettings.h 2026-04-21 19:12:58.154981897 +0000 ++++ b/Tests/mocks/devicesettings.h 2026-04-21 19:13:50.591192520 +0000 +@@ -72,6 +72,16 @@ + dsAUDIOPORT_TYPE_MAX /**< Maximum index for audio port type. */ + } dsAudioPortType_t; + ++typedef enum _dsAudioDuckingAction_t { ++ dsAUDIO_DUCKINGACTION_START = 0, ++ dsAUDIO_DUCKINGACTION_STOP = 1 ++} dsAudioDuckingAction_t; ++ ++typedef enum _dsAudioDuckingType_t { ++ dsAUDIO_DUCKINGTYPE_ABSOLUTE = 0, ++ dsAUDIO_DUCKINGTYPE_RELATIVE = 1 ++} dsAudioDuckingType_t; ++ + typedef enum _dsVideoPortType_t { + dsVIDEOPORT_TYPE_RF = 0, ///< RF modulator (channel 3/4) video output + dsVIDEOPORT_TYPE_BB, ///< Baseband (composite, RCA) video output +@@ -934,6 +944,11 @@ + void enableARC(dsAudioARCTypes_t type, bool enable); + uint32_t getDolbyVolumeMode() const; + void setStereoMode(const std::string &mode, bool persist); ++ void setAudioDucking(dsAudioDuckingAction_t action, dsAudioDuckingType_t type, float level) { ++ (void)action; ++ (void)type; ++ (void)level; ++ } + + + +@@ -1420,6 +1435,8 @@ + static ManagerImpl* impl; + + public: ++ static bool IsInitialized; ++ + Manager(); + + static void setImpl(ManagerImpl* newImpl); diff --git a/ci/mocks/safec_lib.h b/ci/mocks/safec_lib.h new file mode 100644 index 00000000..37d75748 --- /dev/null +++ b/ci/mocks/safec_lib.h @@ -0,0 +1,44 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2026 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. + */ + +/* + * Compatibility header: maps ctrlm's local include name to the real libsafec + * package headers (libsafec-dev / safec-common-wrapper in production). + * + * In CI this file is copied from ci/mocks/ into ci/headers/ by + * build_dependencies.sh so it is resolved on the generated-headers include + * path used by cov_build.sh. + * + * This exists because ctrlm includes safec_lib.h directly, while the native CI + * environment provides the underlying libsafec package headers instead of that + * project-local wrapper. + */ + +#ifndef CTRLM_CI_SAFEC_LIB_H_ +#define CTRLM_CI_SAFEC_LIB_H_ + +#include +#include +#include + +#ifndef ERR_CHK +#define ERR_CHK(rc) do { (void)(rc); } while(0) +#endif + +#endif /* CTRLM_CI_SAFEC_LIB_H_ */ diff --git a/ci/mocks/testframework_overrides.h b/ci/mocks/testframework_overrides.h new file mode 100644 index 00000000..22b8a0a2 --- /dev/null +++ b/ci/mocks/testframework_overrides.h @@ -0,0 +1,48 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2026 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. + */ +/* + * CI patch layer for gaps in the entservices-testframework mock headers. + * + * ctrlm needs a few IARM declarations that are missing from the testframework + * headers used by this reduced build. This file adds only those missing pieces + * and can be removed once they exist upstream. + */ +#ifndef CTRLM_CI_TESTFRAMEWORK_OVERRIDES_H_ +#define CTRLM_CI_TESTFRAMEWORK_OVERRIDES_H_ + +/* Pinned testframework Iarm.h stops at UNKNOWN; ctrlm also references MAX. */ +#ifndef DEEPSLEEP_WAKEUPREASON_MAX +#define DEEPSLEEP_WAKEUPREASON_MAX (DEEPSLEEP_WAKEUPREASON_UNKNOWN + 1) +#endif + +/* IARM common API string not present in the pinned testframework mock */ +#ifndef IARM_BUS_COMMON_API_PowerPreChange +#define IARM_BUS_COMMON_API_PowerPreChange "PowerPreChange" +#endif + +/* Struct not present in the pinned testframework mock */ +#ifndef CTRLM_IARM_BUS_COMMON_API_POWERPRECHANGE_PARAM_T_DEFINED +#define CTRLM_IARM_BUS_COMMON_API_POWERPRECHANGE_PARAM_T_DEFINED +typedef struct { + IARM_Bus_PWRMgr_PowerState_t newState; + IARM_Bus_PWRMgr_PowerState_t curState; +} IARM_Bus_CommonAPI_PowerPreChange_Param_t; +#endif + +#endif /* CTRLM_CI_TESTFRAMEWORK_OVERRIDES_H_ */ diff --git a/ci/mocks/xlog_ci_compat.h b/ci/mocks/xlog_ci_compat.h new file mode 100644 index 00000000..43836b73 --- /dev/null +++ b/ci/mocks/xlog_ci_compat.h @@ -0,0 +1,42 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2026 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. + */ + +/* + * CI compatibility shim. + * + * The production rdkx_logger.h is included transitively everywhere via + * ctrlm_log.h. In the Yocto build the SDK headers pull several std:: names + * into the global namespace. A handful of ctrlm TUs (e.g. ctrlm_utils.cpp) + * rely on those names being globally visible. This tiny header replicates + * that behaviour for the CI native build. + */ +#ifndef CTRLM_CI_XLOG_COMPAT_H_ +#define CTRLM_CI_XLOG_COMPAT_H_ + +#ifdef __cplusplus +#include +#include +#include +using std::get; +using std::map; +using std::string; +using std::tuple; +#endif + +#endif /* CTRLM_CI_XLOG_COMPAT_H_ */ From aac9257430f63c17d2f3fd900ab6876b8c5af1f8 Mon Sep 17 00:00:00 2001 From: dwolaver <44593664+dwolaver@users.noreply.github.com> Date: Fri, 8 May 2026 14:01:01 -0400 Subject: [PATCH 53/81] RDKEMW-16763 : rf4ce init failure causes deadlock (#226) --- src/rf4ce/ctrlm_rf4ce_network.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rf4ce/ctrlm_rf4ce_network.cpp b/src/rf4ce/ctrlm_rf4ce_network.cpp index 11a81c3c..2caa75c2 100644 --- a/src/rf4ce/ctrlm_rf4ce_network.cpp +++ b/src/rf4ce/ctrlm_rf4ce_network.cpp @@ -416,7 +416,7 @@ ctrlm_hal_result_t ctrlm_obj_network_rf4ce_t::hal_init_request(GThread *ctrlm_ma int sem_result = 0; errno = 0; - int rc = clock_gettime(CLOCK_REALTIME, &timeout); + int rc = clock_gettime(CLOCK_MONOTONIC, &timeout); if(rc != 0) { int errsv = errno; // If we fail to get the current time, we should still wait on the semaphore, but we will wait indefinitely instead of timing out @@ -427,7 +427,7 @@ ctrlm_hal_result_t ctrlm_obj_network_rf4ce_t::hal_init_request(GThread *ctrlm_ma timeout.tv_sec += 60; // this operation has been tested to complete in about 6 seconds in worst case scenario (set the timeout to 10x) errno = 0; - sem_result = sem_timedwait(&semaphore_, &timeout); + sem_result = sem_clockwait(&semaphore_, CLOCK_MONOTONIC, &timeout); } if(sem_result == -1) { From 79b2c6e99f2d34e3d6a7f2cb68d996338c08404b Mon Sep 17 00:00:00 2001 From: Gene Gallagher Date: Fri, 8 May 2026 14:47:34 -0400 Subject: [PATCH 54/81] 1.1.16 release changelog updates --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index da765996..27ed797d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,14 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [1.1.16](https://github.com/rdkcentral/control/compare/1.1.15...1.1.16) + +> 8 May 2026 + +- RDKEMW-16763 : rf4ce init failure causes deadlock [`#226`](https://github.com/rdkcentral/control/pull/226) +- RDKEMW-14537: Coverity integration for ctrlm [`#199`](https://github.com/rdkcentral/control/pull/199) + + #### [1.1.15](https://github.com/rdkcentral/control/compare/1.1.14...1.1.15) > 5 May 2026 From 76e6e78369996294c07f37a7b6fccf618c4d97f4 Mon Sep 17 00:00:00 2001 From: dwolaver <44593664+dwolaver@users.noreply.github.com> Date: Fri, 15 May 2026 11:23:07 -0400 Subject: [PATCH 55/81] RDKEMW-18299 : only register SIGQUIT when process is interactive (#229) --- src/ctrlm_main.cpp | 45 ++++++++++++++++++--------------------------- 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/src/ctrlm_main.cpp b/src/ctrlm_main.cpp index 54ddb884..becaac7a 100644 --- a/src/ctrlm_main.cpp +++ b/src/ctrlm_main.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -350,7 +351,6 @@ static gboolean ctrlm_ntp_check(gpointer user_data); static void ctrlm_signals_register(void); static void ctrlm_signal_handler(int signal); static gboolean ctrlm_unix_signal_terminate(gpointer user_data); -static gboolean ctrlm_unix_signal_quit(gpointer user_data); static void ctrlm_main_iarm_call_status_get_(ctrlm_main_iarm_call_status_t *status); static void ctrlm_main_iarm_call_property_get_(ctrlm_main_iarm_call_property_t *property); @@ -1111,14 +1111,6 @@ static gboolean ctrlm_unix_signal_terminate(gpointer user_data) { return G_SOURCE_CONTINUE; } -static gboolean ctrlm_unix_signal_quit(gpointer user_data) { - XLOGD_INFO("Received SIGQUIT"); -#ifdef BREAKPAD_SUPPORT - ctrlm_crash(); -#endif - return G_SOURCE_CONTINUE; -} - void ctrlm_signals_register(void) { // Use g_unix_signal_add() so callbacks run inside the GLib main loop context // rather than from an async signal handler, avoiding undefined behavior from @@ -1131,9 +1123,15 @@ void ctrlm_signals_register(void) { if(0 == g_unix_signal_add(SIGTERM, ctrlm_unix_signal_terminate, GINT_TO_POINTER(SIGTERM))) { XLOGD_ERROR("Unable to register for SIGTERM."); } - XLOGD_INFO("Registering SIGQUIT..."); - if(0 == g_unix_signal_add(SIGQUIT, ctrlm_unix_signal_quit, NULL)) { - XLOGD_ERROR("Unable to register for SIGQUIT."); + bool interactive = isatty(STDIN_FILENO); + if(!interactive) { + XLOGD_INFO("Skipping SIGQUIT registration."); + } else { + XLOGD_INFO("Registering SIGQUIT..."); + if(signal(SIGQUIT, ctrlm_signal_handler) == SIG_ERR) { // SIGQUIT is not supported by g_unix_signal_add, so use signal() with a direct handler + int errsv = errno; + XLOGD_ERROR("Unable to register for SIGQUIT <%s>", strerror(errsv)); + } } // Ignore SIGPIPE — broken-pipe errors are handled at the call site via errno. XLOGD_INFO("Ignoring SIGPIPE..."); @@ -1144,29 +1142,22 @@ void ctrlm_signals_register(void) { } } -// Direct-call fallback only (e.g. from ctrlm_on_network_assert when kill() fails). -// No longer registered as an OS signal handler, so non-async-signal-safe calls are safe. +// Registered as an OS signal handler (must use async-signal-safe calls only). static void ctrlm_signal_handler(int signal) { switch(signal) { - case SIGTERM: - case SIGINT: { - XLOGD_INFO("Received %s", signal == SIGINT ? "SIGINT" : "SIGTERM"); - ctrlm_quit_main_loop(); - break; - } case SIGQUIT: { - XLOGD_INFO("Received SIGQUIT"); -#ifdef BREAKPAD_SUPPORT + XLOGD_SAFE_INFO("Received SIGQUIT"); + #ifdef BREAKPAD_SUPPORT ctrlm_crash(); -#endif + #endif break; } case SIGPIPE: { - XLOGD_ERROR("Received SIGPIPE. Pipe is broken"); + XLOGD_SAFE_ERROR("Received SIGPIPE. Pipe is broken"); break; } default: - XLOGD_ERROR("Received unhandled signal %d", signal); + XLOGD_SAFE_ERROR("Received unhandled signal"); break; } } @@ -1262,7 +1253,7 @@ void ctrlm_on_network_assert(ctrlm_network_id_t network_id) { g_ctrlm.main_thread = NULL; } // g_main_loop_quit() will be called when the SIGTERM GLib source fires, - // or directly via ctrlm_signal_handler() in the kill() fallback below. + // or directly in the kill() fallback below. g_ctrlm.return_code = -1; errno = 0; @@ -1270,7 +1261,7 @@ void ctrlm_on_network_assert(ctrlm_network_id_t network_id) { if(rc != 0) { int errsv = errno; XLOGD_ERROR("Failed to send SIGTERM to self <%s> - invoking shutdown handler directly", strerror(errsv)); - ctrlm_signal_handler(SIGTERM); + ctrlm_quit_main_loop(); } // give main() time to clean up From 76fe3577890fcc9441912521a932b8b310466a44 Mon Sep 17 00:00:00 2001 From: dwolaver <44593664+dwolaver@users.noreply.github.com> Date: Fri, 15 May 2026 11:46:34 -0400 Subject: [PATCH 56/81] RDKEMW-17620 : ctrlm rfc value groups not updating (#219) --- src/config/ctrlm_config.cpp | 12 +++++- src/config/ctrlm_config.h | 14 ++++++- src/ctrlm_main.cpp | 5 ++- src/rfc/ctrlm_rfc_attr.cpp | 8 ++-- src/voice/ctrlm_voice_obj.cpp | 73 +++++++++++++++++++++-------------- 5 files changed, 74 insertions(+), 38 deletions(-) diff --git a/src/config/ctrlm_config.cpp b/src/config/ctrlm_config.cpp index eb0ed60e..4d8f5404 100644 --- a/src/config/ctrlm_config.cpp +++ b/src/config/ctrlm_config.cpp @@ -45,6 +45,7 @@ void ctrlm_config_t::destroy_instance() { ctrlm_config_t::ctrlm_config_t() { this->root = NULL; + this->local_config = false; } ctrlm_config_t::~ctrlm_config_t() { @@ -52,9 +53,10 @@ ctrlm_config_t::~ctrlm_config_t() { json_decref(this->root); this->root = NULL; } + this->local_config = false; } -bool ctrlm_config_t::load_config(const std::string &file_path, bool verbose) { +bool ctrlm_config_t::load_config(const std::string &file_path, bool local_config, bool verbose) { bool ret = false; std::string contents = file_to_string(file_path); if(this->root) { @@ -73,6 +75,7 @@ bool ctrlm_config_t::load_config(const std::string &file_path, bool verbose) { if(verbose) { XLOGD_INFO("config loaded successfully as JSON for <%s>", file_path.c_str()); } + this->local_config = local_config; ret = true; } else { XLOGD_ERROR("JSON ERROR: Line <%u> Column <%u> Text <%s> Contents <%s>", json_error.line, json_error.column, json_error.text, contents.c_str()); @@ -83,7 +86,7 @@ bool ctrlm_config_t::load_config(const std::string &file_path, bool verbose) { return(ret); } -bool ctrlm_config_t::append_config(const std::string &file_path, bool verbose) { +bool ctrlm_config_t::append_config(const std::string &file_path, bool local_config, bool verbose) { if(this->root == NULL) { XLOGD_ERROR("no config file loaded"); return(false); @@ -109,6 +112,7 @@ bool ctrlm_config_t::append_config(const std::string &file_path, bool verbose) { if(verbose) { XLOGD_INFO("config appended successfully as JSON for <%s>", file_path.c_str()); } + this->local_config |= local_config; ret = true; } json_decref(append_root); @@ -121,6 +125,10 @@ bool ctrlm_config_t::path_exists(const std::string &path) { return(ctrlm_utils_json_from_path(this->root, path, false) != NULL ? true : false); } +bool ctrlm_config_t::has_local_config() const { + return(this->local_config); +} + json_t *ctrlm_config_t::json_from_path(const std::string &path, bool add_ref) { return(ctrlm_utils_json_from_path(this->root, path, add_ref)); } diff --git a/src/config/ctrlm_config.h b/src/config/ctrlm_config.h index 755e5b4b..52951db9 100644 --- a/src/config/ctrlm_config.h +++ b/src/config/ctrlm_config.h @@ -47,15 +47,24 @@ class ctrlm_config_t { /** * Function which loads a configuration file into the configuration object. * @param file_path The path to the configuration file + * @param local_config True if the configuration file is a local config, else False + * @param verbose True to enable verbose logging, else False * @return True on success, otherwise False */ - bool load_config(const std::string &file_path, bool verbose = false); + bool load_config(const std::string &file_path, bool local_config = false, bool verbose = false); /** * Function which appends a configuration file into the configuration object. * @param file_path The path to the configuration file + * @param local_config True if the configuration file is a local config, else False + * @param verbose True to enable verbose logging, else False * @return True on success, otherwise False */ - bool append_config(const std::string &file_path, bool verbose = false); + bool append_config(const std::string &file_path, bool local_config = false, bool verbose = false); + /** + * Function to check if local config exists + * @return True if the local config exists, else False + */ + bool has_local_config() const; /** * Function to check if object exists from a path * @param path A period seperated string used to navigate a JSON object i.e. "network_rf4ce.polling.enabled" @@ -83,6 +92,7 @@ class ctrlm_config_t { private: json_t *root; + bool local_config; }; #endif diff --git a/src/ctrlm_main.cpp b/src/ctrlm_main.cpp index becaac7a..902b4331 100644 --- a/src/ctrlm_main.cpp +++ b/src/ctrlm_main.cpp @@ -1614,16 +1614,17 @@ gboolean ctrlm_load_config(json_t **json_obj_root, json_t **json_obj_net_rf4ce, // Check for OPT config file override if(opt_append) { + bool local_config = true; if(!oem_append) { XLOGD_INFO("Loading OPT configuration from <%s>", config_fn_opt.c_str()); - if(!ctrlm_config->load_config(config_fn_opt)) { + if(!ctrlm_config->load_config(config_fn_opt, local_config)) { XLOGD_ERROR("Failed to load OPT configuration from <%s>", config_fn_opt.c_str()); return(false); } } else { XLOGD_INFO("Appending OPT configuration from <%s>", config_fn_opt.c_str()); - if(!ctrlm_config->append_config(config_fn_opt)) { + if(!ctrlm_config->append_config(config_fn_opt, local_config)) { XLOGD_ERROR("Failed to append OPT configuration from <%s>", config_fn_opt.c_str()); return(false); } diff --git a/src/rfc/ctrlm_rfc_attr.cpp b/src/rfc/ctrlm_rfc_attr.cpp index 263d9d6c..f9e996bb 100644 --- a/src/rfc/ctrlm_rfc_attr.cpp +++ b/src/rfc/ctrlm_rfc_attr.cpp @@ -99,9 +99,11 @@ bool ctrlm_rfc_attr_t::check_config_file(const std::string &path) const { bool ret = false; ctrlm_config_t *config = ctrlm_config_t::get_instance(); if(config) { - ret = config->path_exists(this->config_key + std::string(JSON_PATH_SEPERATOR) + path); - if(ret) { - XLOGD_DEBUG("%s exists in the config file", path.c_str()); + if(config->has_local_config()) { + ret = config->path_exists(this->config_key + std::string(JSON_PATH_SEPERATOR) + path); + if(ret) { + XLOGD_WARN("%s exists in the config file", path.c_str()); + } } } else { XLOGD_ERROR("config object is NULL"); diff --git a/src/voice/ctrlm_voice_obj.cpp b/src/voice/ctrlm_voice_obj.cpp index a6787b1e..d8d87159 100644 --- a/src/voice/ctrlm_voice_obj.cpp +++ b/src/voice/ctrlm_voice_obj.cpp @@ -3959,7 +3959,8 @@ xrsr_power_mode_t voice_xrsr_power_map(ctrlm_power_state_t ctrlm_power_state) { void ctrlm_voice_t::voice_rfc_retrieved_handler(const ctrlm_rfc_attr_t& attr) { bool enabled = true; - bool reroute = false; + + XLOGD_INFO("processing RFC values"); attr.get_rfc_value(JSON_INT_NAME_VOICE_VREX_REQUEST_TIMEOUT, this->prefs.timeout_vrex_connect,0); attr.get_rfc_value(JSON_INT_NAME_VOICE_VREX_RESPONSE_TIMEOUT, this->prefs.timeout_vrex_session,0); @@ -4007,22 +4008,34 @@ void ctrlm_voice_t::voice_rfc_retrieved_handler(const ctrlm_rfc_attr_t& attr) { } attr.get_rfc_value(JSON_INT_NAME_VOICE_PACKET_LOSS_THRESHOLD, this->packet_loss_threshold, 0); - if(attr.get_rfc_value(JSON_INT_NAME_VOICE_AUDIO_MODE, this->audio_mode) | - attr.get_rfc_value(JSON_INT_NAME_VOICE_AUDIO_TIMING, this->audio_timing) | - attr.get_rfc_value(JSON_FLOAT_NAME_VOICE_AUDIO_CONFIDENCE_THRESHOLD, this->audio_confidence_threshold, 0.0, 1.0) | - attr.get_rfc_value(JSON_INT_NAME_VOICE_AUDIO_DUCKING_TYPE, this->audio_ducking_type, CTRLM_VOICE_AUDIO_DUCKING_TYPE_ABSOLUTE, CTRLM_VOICE_AUDIO_DUCKING_TYPE_RELATIVE) | - attr.get_rfc_value(JSON_FLOAT_NAME_VOICE_AUDIO_DUCKING_LEVEL, this->audio_ducking_level, 0.0, 1.0) | - attr.get_rfc_value(JSON_BOOL_NAME_VOICE_AUDIO_DUCKING_BEEP, this->audio_ducking_beep_enabled)) { + + bool audio_mode_updated = false; + audio_mode_updated |= attr.get_rfc_value(JSON_INT_NAME_VOICE_AUDIO_MODE, this->audio_mode); + audio_mode_updated |= attr.get_rfc_value(JSON_INT_NAME_VOICE_AUDIO_TIMING, this->audio_timing); + audio_mode_updated |= attr.get_rfc_value(JSON_FLOAT_NAME_VOICE_AUDIO_CONFIDENCE_THRESHOLD, this->audio_confidence_threshold, 0.0, 1.0); + audio_mode_updated |= attr.get_rfc_value(JSON_INT_NAME_VOICE_AUDIO_DUCKING_TYPE, this->audio_ducking_type, CTRLM_VOICE_AUDIO_DUCKING_TYPE_ABSOLUTE, CTRLM_VOICE_AUDIO_DUCKING_TYPE_RELATIVE); + audio_mode_updated |= attr.get_rfc_value(JSON_FLOAT_NAME_VOICE_AUDIO_DUCKING_LEVEL, this->audio_ducking_level, 0.0, 1.0); + + // JSON_BOOL_NAME_VOICE_AUDIO_DUCKING_BEEP is updated via Voice Control plugin so it cannot be overridden via RFC + + XLOGD_INFO("audio mode updated <%s>", audio_mode_updated ? "YES" : "NO"); + + if(audio_mode_updated) { ctrlm_voice_audio_settings_t audio_settings = {this->audio_mode, this->audio_timing, this->audio_confidence_threshold, this->audio_ducking_type, this->audio_ducking_level, this->audio_ducking_beep_enabled}; this->set_audio_mode(&audio_settings); } // All attributes that need capture configuration to be set - if(attr.get_rfc_value(JSON_ARRAY_NAME_VOICE_SAVE_LAST_UTTERANCE, this->prefs.utterance_save, ctrlm_is_production_build() ? CTRLM_JSON_ARRAY_INDEX_PRD : CTRLM_JSON_ARRAY_INDEX_DEV) | - attr.get_rfc_value(JSON_BOOL_NAME_VOICE_UTTERANCE_USE_CURTAIL, this->prefs.utterance_use_curtail) | - attr.get_rfc_value(JSON_INT_NAME_VOICE_UTTERANCE_FILE_QTY_MAX, this->prefs.utterance_file_qty_max, 1, 100000) | - attr.get_rfc_value(JSON_INT_NAME_VOICE_UTTERANCE_FILE_SIZE_MAX, this->prefs.utterance_file_size_max, 4 * 1024) | - attr.get_rfc_value(JSON_STR_NAME_VOICE_UTTERANCE_PATH, this->prefs.utterance_path)) { + bool capture_config_updated = false; + capture_config_updated |= attr.get_rfc_value(JSON_ARRAY_NAME_VOICE_SAVE_LAST_UTTERANCE, this->prefs.utterance_save, ctrlm_is_production_build() ? CTRLM_JSON_ARRAY_INDEX_PRD : CTRLM_JSON_ARRAY_INDEX_DEV); + capture_config_updated |= attr.get_rfc_value(JSON_BOOL_NAME_VOICE_UTTERANCE_USE_CURTAIL, this->prefs.utterance_use_curtail); + capture_config_updated |= attr.get_rfc_value(JSON_INT_NAME_VOICE_UTTERANCE_FILE_QTY_MAX, this->prefs.utterance_file_qty_max, 1, 100000); + capture_config_updated |= attr.get_rfc_value(JSON_INT_NAME_VOICE_UTTERANCE_FILE_SIZE_MAX, this->prefs.utterance_file_size_max, 4 * 1024); + capture_config_updated |= attr.get_rfc_value(JSON_STR_NAME_VOICE_UTTERANCE_PATH, this->prefs.utterance_path); + + XLOGD_INFO("capture config updated <%s>", capture_config_updated ? "YES" : "NO"); + + if(capture_config_updated) { xrsr_capture_config_t capture_config = { .delete_files = !this->prefs.utterance_save, .enable = this->prefs.utterance_save, @@ -4045,22 +4058,21 @@ void ctrlm_voice_t::voice_rfc_retrieved_handler(const ctrlm_rfc_attr_t& attr) { } // All attributes that need a re-route to apply - if(attr.get_rfc_value(JSON_INT_NAME_VOICE_MINIMUM_DURATION, this->prefs.utterance_duration_min) | - attr.get_rfc_value(JSON_INT_NAME_VOICE_DST_PARAMS_STANDBY_CONNECT_CHECK_INTERVAL, this->prefs.dst_params_standby.connect_check_interval) | - attr.get_rfc_value(JSON_INT_NAME_VOICE_DST_PARAMS_STANDBY_TIMEOUT_CONNECT, this->prefs.dst_params_standby.timeout_connect) | - attr.get_rfc_value(JSON_INT_NAME_VOICE_DST_PARAMS_STANDBY_TIMEOUT_INACTIVITY, this->prefs.dst_params_standby.timeout_inactivity) | - attr.get_rfc_value(JSON_INT_NAME_VOICE_DST_PARAMS_STANDBY_TIMEOUT_SESSION, this->prefs.dst_params_standby.timeout_session) | - attr.get_rfc_value(JSON_BOOL_NAME_VOICE_DST_PARAMS_STANDBY_IPV4_FALLBACK, this->prefs.dst_params_standby.ipv4_fallback) | - attr.get_rfc_value(JSON_INT_NAME_VOICE_DST_PARAMS_STANDBY_BACKOFF_DELAY, this->prefs.dst_params_standby.backoff_delay) | + bool routing_config_updated = false; + routing_config_updated |= attr.get_rfc_value(JSON_INT_NAME_VOICE_MINIMUM_DURATION, this->prefs.utterance_duration_min); + routing_config_updated |= attr.get_rfc_value(JSON_INT_NAME_VOICE_DST_PARAMS_STANDBY_CONNECT_CHECK_INTERVAL, this->prefs.dst_params_standby.connect_check_interval); + routing_config_updated |= attr.get_rfc_value(JSON_INT_NAME_VOICE_DST_PARAMS_STANDBY_TIMEOUT_CONNECT, this->prefs.dst_params_standby.timeout_connect); + routing_config_updated |= attr.get_rfc_value(JSON_INT_NAME_VOICE_DST_PARAMS_STANDBY_TIMEOUT_INACTIVITY, this->prefs.dst_params_standby.timeout_inactivity); + routing_config_updated |= attr.get_rfc_value(JSON_INT_NAME_VOICE_DST_PARAMS_STANDBY_TIMEOUT_SESSION, this->prefs.dst_params_standby.timeout_session); + routing_config_updated |= attr.get_rfc_value(JSON_BOOL_NAME_VOICE_DST_PARAMS_STANDBY_IPV4_FALLBACK, this->prefs.dst_params_standby.ipv4_fallback); + routing_config_updated |= attr.get_rfc_value(JSON_INT_NAME_VOICE_DST_PARAMS_STANDBY_BACKOFF_DELAY, this->prefs.dst_params_standby.backoff_delay); - attr.get_rfc_value(JSON_INT_NAME_VOICE_DST_PARAMS_LOW_LATENCY_CONNECT_CHECK_INTERVAL, this->prefs.dst_params_low_latency.connect_check_interval) | - attr.get_rfc_value(JSON_INT_NAME_VOICE_DST_PARAMS_LOW_LATENCY_TIMEOUT_CONNECT, this->prefs.dst_params_low_latency.timeout_connect) | - attr.get_rfc_value(JSON_INT_NAME_VOICE_DST_PARAMS_LOW_LATENCY_TIMEOUT_INACTIVITY, this->prefs.dst_params_low_latency.timeout_inactivity) | - attr.get_rfc_value(JSON_INT_NAME_VOICE_DST_PARAMS_LOW_LATENCY_TIMEOUT_SESSION, this->prefs.dst_params_low_latency.timeout_session) | - attr.get_rfc_value(JSON_BOOL_NAME_VOICE_DST_PARAMS_LOW_LATENCY_IPV4_FALLBACK, this->prefs.dst_params_low_latency.ipv4_fallback) | - attr.get_rfc_value(JSON_INT_NAME_VOICE_DST_PARAMS_LOW_LATENCY_BACKOFF_DELAY, this->prefs.dst_params_low_latency.backoff_delay)) { - reroute = true; - } + routing_config_updated |= attr.get_rfc_value(JSON_INT_NAME_VOICE_DST_PARAMS_LOW_LATENCY_CONNECT_CHECK_INTERVAL, this->prefs.dst_params_low_latency.connect_check_interval); + routing_config_updated |= attr.get_rfc_value(JSON_INT_NAME_VOICE_DST_PARAMS_LOW_LATENCY_TIMEOUT_CONNECT, this->prefs.dst_params_low_latency.timeout_connect); + routing_config_updated |= attr.get_rfc_value(JSON_INT_NAME_VOICE_DST_PARAMS_LOW_LATENCY_TIMEOUT_INACTIVITY, this->prefs.dst_params_low_latency.timeout_inactivity); + routing_config_updated |= attr.get_rfc_value(JSON_INT_NAME_VOICE_DST_PARAMS_LOW_LATENCY_TIMEOUT_SESSION, this->prefs.dst_params_low_latency.timeout_session); + routing_config_updated |= attr.get_rfc_value(JSON_BOOL_NAME_VOICE_DST_PARAMS_LOW_LATENCY_IPV4_FALLBACK, this->prefs.dst_params_low_latency.ipv4_fallback); + routing_config_updated |= attr.get_rfc_value(JSON_INT_NAME_VOICE_DST_PARAMS_LOW_LATENCY_BACKOFF_DELAY, this->prefs.dst_params_low_latency.backoff_delay); std::vector obj_server_hosts; if(attr.get_rfc_value(JSON_ARRAY_NAME_VOICE_SERVER_HOSTS, obj_server_hosts)) { @@ -4078,9 +4090,12 @@ void ctrlm_voice_t::voice_rfc_retrieved_handler(const ctrlm_rfc_attr_t& attr) { this->voice_device_disable((ctrlm_voice_device_t)i, true, NULL); } } - reroute = true; + routing_config_updated = true; } - if(reroute) { + + XLOGD_INFO("routing config updated <%s>", routing_config_updated ? "YES" : "NO"); + + if(routing_config_updated) { this->voice_sdk_update_routes(); } } From 5a6dbfbf88cdb7d62128a93b3990bdb595bc0141 Mon Sep 17 00:00:00 2001 From: dwolaver <44593664+dwolaver@users.noreply.github.com> Date: Mon, 18 May 2026 14:26:04 -0400 Subject: [PATCH 57/81] RDKEMW-14906 : VAD detector in Control Manager/Voice SDK (#186) --- include/ctrlm_ipc.h | 3 +- include/ctrlm_ipc_voice.h | 11 ++ src/ctrlm_config_default.json | 4 +- src/telemetry/ctrlm_telemetry_markers.h | 16 ++- src/voice/ctrlm_voice_obj.cpp | 115 ++++++++++++------ src/voice/ctrlm_voice_obj.h | 73 +++++------ src/voice/ctrlm_voice_obj_generic.cpp | 102 +++++++++------- src/voice/ipc/ctrlm_voice_ipc.h | 3 +- src/voice/ipc/ctrlm_voice_ipc_iarm_legacy.cpp | 12 ++ .../ipc/ctrlm_voice_ipc_iarm_thunder.cpp | 16 +++ .../ctrlm_voice_telemetry_events.cpp | 17 ++- .../telemetry/ctrlm_voice_telemetry_events.h | 6 +- 12 files changed, 251 insertions(+), 127 deletions(-) diff --git a/include/ctrlm_ipc.h b/include/ctrlm_ipc.h index 32d0dea1..7d87d12c 100644 --- a/include/ctrlm_ipc.h +++ b/include/ctrlm_ipc.h @@ -302,7 +302,8 @@ typedef enum { CTRLM_RCU_IARM_EVENT_RF4CE_PAIRING_WINDOW_TIMEOUT = 35, ///< Indicates that a battery milestone event occured CTRLM_RCU_IARM_EVENT_FIRMWARE_UPDATE_PROGRESS = 36, ///< Generated when an milestone is reached for remote firmware upgrade CTRLM_RCU_IARM_EVENT_VALIDATION_STATUS = 37, ///< Generated when the validation status changes - CTRLM_MAIN_IARM_EVENT_MAX = 38 ///< Placeholder for the last event (used in registration) + CTRLM_VOICE_IARM_EVENT_SESSION_SILENT = 38, ///< Voice session was silent (no speech detected) + CTRLM_MAIN_IARM_EVENT_MAX = 39 ///< Placeholder for the last event (used in registration) } ctrlm_main_iarm_event_t; /// @brief Remote Control Key Status diff --git a/include/ctrlm_ipc_voice.h b/include/ctrlm_ipc_voice.h index ed96c951..4a912cad 100644 --- a/include/ctrlm_ipc_voice.h +++ b/include/ctrlm_ipc_voice.h @@ -281,6 +281,16 @@ typedef struct { long return_code_internal; ///< Internally generated return code } ctrlm_voice_iarm_event_session_short_t; +typedef struct { + unsigned char api_revision; ///< The revision of this API. + ctrlm_network_id_t network_id; ///< Identifier of network on which the controller is bound + ctrlm_network_type_t network_type; ///< Type of network on which the controller is bound + ctrlm_controller_id_t controller_id; ///< A unique identifier of the remote + unsigned long session_id; ///< A unique id for the voice session. + ctrlm_voice_session_end_reason_t reason; ///< The reason that the voice session was silent + long return_code_internal; ///< Internally generated return code +} ctrlm_voice_iarm_event_session_silent_t; + typedef struct { unsigned char api_revision; ///< The revision of this API char media_service_url[2083]; ///< The url for the media service (null terminated string) @@ -376,6 +386,7 @@ typedef struct { /// | CTRLM_MAIN_IARM_BUS_NAME | CTRLM_VOICE_IARM_EVENT_SESSION_STATS | ctrlm_voice_iarm_event_session_stats_t * | Generated when the statistics of the voice session are available | /// | CTRLM_MAIN_IARM_BUS_NAME | CTRLM_VOICE_IARM_EVENT_SESSION_ABORT | ctrlm_voice_iarm_event_session_abort_t * | Generated when a voice session is aborted (denied) | /// | CTRLM_MAIN_IARM_BUS_NAME | CTRLM_VOICE_IARM_EVENT_SESSION_SHORT | ctrlm_voice_iarm_event_session_short_t * | Generated when a short voice session is detected | +/// | CTRLM_MAIN_IARM_BUS_NAME | CTRLM_VOICE_IARM_EVENT_SESSION_SILENT | ctrlm_voice_iarm_event_session_silent_t * | Generated when a silent voice session is detected | /// | CTRLM_MAIN_IARM_BUS_NAME | CTRLM_VOICE_IARM_EVENT_MEDIA_SERVICE | ctrlm_voice_iarm_event_media_service_t * | Generated when a media service response is received | /// /// IARM events are available on a subscription basis. In order to receive an event, a client must explicitly register to receive the event by calling diff --git a/src/ctrlm_config_default.json b/src/ctrlm_config_default.json index af65c196..21aa49c6 100755 --- a/src/ctrlm_config_default.json +++ b/src/ctrlm_config_default.json @@ -291,7 +291,9 @@ "par_voice_eos_method" : 1, "par_voice_eos_timeout" : 2500, "server_hosts" : [], - "telemetry_session_stats" : false + "telemetry_session_stats" : false, + "voice_activity_detection_mode" : "enabled" + }, "device_update" : { "dir_root" : "/srv/device_update/", diff --git a/src/telemetry/ctrlm_telemetry_markers.h b/src/telemetry/ctrlm_telemetry_markers.h index 23c0f775..cb07ec32 100644 --- a/src/telemetry/ctrlm_telemetry_markers.h +++ b/src/telemetry/ctrlm_telemetry_markers.h @@ -93,7 +93,7 @@ // The Voice Session Statistics Marker reports statistics for the voice session(s). The format of the marker is a json array of arrays with each event in the format below: // // [[event1], [event2], [event3], ...] -// [,,,,,,,,,,,,,,,,,,,,] +// [,,,,,,,,,,,,,,,,,,,,,,,,,] // // - Version of the marker format. // - Name of the device that started the session. @@ -111,13 +111,19 @@ // - lost samples. // - decoder failure count. // - sample buffer high watermark. -// - audio stream success/error code. -// - protocol success/error code. -// - server success/error code. +// - audio stream success/error code. +// - session success/error code. +// - server success/error code. // - server message. // - flag to indicate if session was successful. +// - reason why the stream ended (if available). +// - protocol return code. +// - flag to indicate if voice was detected. +// - peak confidence level. +// - peak RMS level. + #define MARKER_VOICE_SESSION_STATS "ctrlm.voice.session.stats" -#define MARKER_VOICE_SESSION_STATS_VERSION "2" +#define MARKER_VOICE_SESSION_STATS_VERSION "3" // End Voice Session Statistics diff --git a/src/voice/ctrlm_voice_obj.cpp b/src/voice/ctrlm_voice_obj.cpp index d8d87159..12402a12 100644 --- a/src/voice/ctrlm_voice_obj.cpp +++ b/src/voice/ctrlm_voice_obj.cpp @@ -186,39 +186,40 @@ ctrlm_voice_t::ctrlm_voice_t() { #ifdef JSON_ARRAY_VAL_STR_VOICE_SERVER_HOSTS_3 this->url_hostname_pattern_add(JSON_ARRAY_VAL_STR_VOICE_SERVER_HOSTS_3); #endif - this->prefs.aspect_ratio = JSON_STR_VALUE_VOICE_ASPECT_RATIO; - this->prefs.guide_language = JSON_STR_VALUE_VOICE_LANGUAGE; - this->prefs.app_id_http = JSON_STR_VALUE_VOICE_APP_ID_HTTP; - this->prefs.app_id_ws = JSON_STR_VALUE_VOICE_APP_ID_WS; - this->prefs.timeout_vrex_connect = JSON_INT_VALUE_VOICE_VREX_REQUEST_TIMEOUT; - this->prefs.timeout_vrex_session = JSON_INT_VALUE_VOICE_VREX_RESPONSE_TIMEOUT; - this->prefs.timeout_stats = JSON_INT_VALUE_VOICE_TIMEOUT_STATS; - this->prefs.timeout_packet_initial = JSON_INT_VALUE_VOICE_TIMEOUT_PACKET_INITIAL; - this->prefs.timeout_packet_subsequent = JSON_INT_VALUE_VOICE_TIMEOUT_PACKET_SUBSEQUENT; - this->prefs.bitrate_minimum = JSON_INT_VALUE_VOICE_BITRATE_MINIMUM; - this->prefs.time_threshold = JSON_INT_VALUE_VOICE_TIME_THRESHOLD; - this->prefs.utterance_save = ctrlm_is_production_build() ? JSON_ARRAY_VAL_BOOL_VOICE_SAVE_LAST_UTTERANCE_0 : JSON_ARRAY_VAL_BOOL_VOICE_SAVE_LAST_UTTERANCE_1; - this->prefs.utterance_use_curtail = JSON_BOOL_VALUE_VOICE_UTTERANCE_USE_CURTAIL; - this->prefs.utterance_file_qty_max = JSON_INT_VALUE_VOICE_UTTERANCE_FILE_QTY_MAX; - this->prefs.utterance_file_size_max = JSON_INT_VALUE_VOICE_UTTERANCE_FILE_SIZE_MAX; - this->prefs.utterance_path = JSON_STR_VALUE_VOICE_UTTERANCE_PATH; - this->prefs.utterance_duration_min = JSON_INT_VALUE_VOICE_MINIMUM_DURATION; - this->prefs.ffv_leading_samples = JSON_INT_VALUE_VOICE_FFV_LEADING_SAMPLES; - this->prefs.force_voice_settings = JSON_BOOL_VALUE_VOICE_FORCE_VOICE_SETTINGS; - this->prefs.vrex_test_flag = JSON_BOOL_VALUE_VOICE_VREX_TEST_FLAG; - this->prefs.vrex_wuw_bypass_success_flag = JSON_BOOL_VALUE_VOICE_VREX_WUW_BYPASS_SUCCESS_FLAG; - this->prefs.vrex_wuw_bypass_failure_flag = JSON_BOOL_VALUE_VOICE_VREX_WUW_BYPASS_FAILURE_FLAG; - this->prefs.force_toggle_fallback = JSON_BOOL_VALUE_VOICE_FORCE_TOGGLE_FALLBACK; - this->prefs.telemetry_session_stats = JSON_BOOL_VALUE_VOICE_TELEMETRY_SESSION_STATS; - this->prefs.par_voice_enabled = false; - this->prefs.par_voice_eos_method = JSON_INT_VALUE_VOICE_PAR_VOICE_EOS_METHOD; - this->prefs.par_voice_eos_timeout = JSON_INT_VALUE_VOICE_PAR_VOICE_EOS_TIMEOUT; + this->prefs.aspect_ratio = JSON_STR_VALUE_VOICE_ASPECT_RATIO; + this->prefs.guide_language = JSON_STR_VALUE_VOICE_LANGUAGE; + this->prefs.app_id_http = JSON_STR_VALUE_VOICE_APP_ID_HTTP; + this->prefs.app_id_ws = JSON_STR_VALUE_VOICE_APP_ID_WS; + this->prefs.timeout_vrex_connect = JSON_INT_VALUE_VOICE_VREX_REQUEST_TIMEOUT; + this->prefs.timeout_vrex_session = JSON_INT_VALUE_VOICE_VREX_RESPONSE_TIMEOUT; + this->prefs.timeout_stats = JSON_INT_VALUE_VOICE_TIMEOUT_STATS; + this->prefs.timeout_packet_initial = JSON_INT_VALUE_VOICE_TIMEOUT_PACKET_INITIAL; + this->prefs.timeout_packet_subsequent = JSON_INT_VALUE_VOICE_TIMEOUT_PACKET_SUBSEQUENT; + this->prefs.bitrate_minimum = JSON_INT_VALUE_VOICE_BITRATE_MINIMUM; + this->prefs.time_threshold = JSON_INT_VALUE_VOICE_TIME_THRESHOLD; + this->prefs.utterance_save = ctrlm_is_production_build() ? JSON_ARRAY_VAL_BOOL_VOICE_SAVE_LAST_UTTERANCE_0 : JSON_ARRAY_VAL_BOOL_VOICE_SAVE_LAST_UTTERANCE_1; + this->prefs.utterance_use_curtail = JSON_BOOL_VALUE_VOICE_UTTERANCE_USE_CURTAIL; + this->prefs.utterance_file_qty_max = JSON_INT_VALUE_VOICE_UTTERANCE_FILE_QTY_MAX; + this->prefs.utterance_file_size_max = JSON_INT_VALUE_VOICE_UTTERANCE_FILE_SIZE_MAX; + this->prefs.utterance_path = JSON_STR_VALUE_VOICE_UTTERANCE_PATH; + this->prefs.utterance_duration_min = JSON_INT_VALUE_VOICE_MINIMUM_DURATION; + this->prefs.ffv_leading_samples = JSON_INT_VALUE_VOICE_FFV_LEADING_SAMPLES; + this->prefs.voice_activity_detection_mode = this->voice_activity_detection_mode_to_xrsr(JSON_STR_VALUE_VOICE_VOICE_ACTIVITY_DETECTION_MODE); + this->prefs.force_voice_settings = JSON_BOOL_VALUE_VOICE_FORCE_VOICE_SETTINGS; + this->prefs.vrex_test_flag = JSON_BOOL_VALUE_VOICE_VREX_TEST_FLAG; + this->prefs.vrex_wuw_bypass_success_flag = JSON_BOOL_VALUE_VOICE_VREX_WUW_BYPASS_SUCCESS_FLAG; + this->prefs.vrex_wuw_bypass_failure_flag = JSON_BOOL_VALUE_VOICE_VREX_WUW_BYPASS_FAILURE_FLAG; + this->prefs.force_toggle_fallback = JSON_BOOL_VALUE_VOICE_FORCE_TOGGLE_FALLBACK; + this->prefs.telemetry_session_stats = JSON_BOOL_VALUE_VOICE_TELEMETRY_SESSION_STATS; + this->prefs.par_voice_enabled = false; + this->prefs.par_voice_eos_method = JSON_INT_VALUE_VOICE_PAR_VOICE_EOS_METHOD; + this->prefs.par_voice_eos_timeout = JSON_INT_VALUE_VOICE_PAR_VOICE_EOS_TIMEOUT; this->voice_params_opus_encoder_default(); - this->xrsr_opened = false; - this->voice_ipc = NULL; - this->packet_loss_threshold = JSON_INT_VALUE_VOICE_PACKET_LOSS_THRESHOLD; - this->vsdk_config = NULL; - this->nsm_voice_session = false; + this->xrsr_opened = false; + this->voice_ipc = NULL; + this->packet_loss_threshold = JSON_INT_VALUE_VOICE_PACKET_LOSS_THRESHOLD; + this->vsdk_config = NULL; + this->nsm_voice_session = false; #ifndef TELEMETRY_SUPPORT XLOGD_WARN("telemetry is not enabled"); @@ -261,6 +262,7 @@ ctrlm_voice_t::ctrlm_voice_t() { this->secure_url_required = JSON_BOOL_VALUE_VOICE_REQUIRE_SECURE_URL; XLOGD_TELEMETRY("require i_SAT <%s> i_MTLS <%s> i_secure_url <%s>", this->sat_token_required ? "YES" : "NO", this->mtls_required ? "YES" : "NO", this->secure_url_required ? "YES" : "NO"); + XLOGD_INFO("voice activity detection mode <%s>", xrsr_stream_voice_activity_mode_str(this->prefs.voice_activity_detection_mode)); errno_t safec_rc = memset_s(this->sat_token, sizeof(this->sat_token), 0, sizeof(this->sat_token)); ERR_CHK(safec_rc); @@ -425,6 +427,7 @@ bool ctrlm_voice_t::voice_configure_config_file_json(json_t *obj_voice, json_t * conf.config_value_get(JSON_STR_NAME_VOICE_URL_SRC_MIC_TAP, this->prefs.server_url_src_mic_tap); conf.config_value_get(JSON_STR_NAME_VOICE_LANGUAGE, this->prefs.guide_language); conf.config_value_get(JSON_INT_NAME_VOICE_MINIMUM_DURATION, this->prefs.utterance_duration_min); + if(conf.config_value_get(JSON_BOOL_NAME_VOICE_ENABLE_SAT, this->sat_token_required)) { ctrlm_sm_voice_sat_enable_write(this->sat_token_required); XLOGD_TELEMETRY("require c_SAT <%s>", this->sat_token_required ? "YES" : "NO"); @@ -432,6 +435,12 @@ bool ctrlm_voice_t::voice_configure_config_file_json(json_t *obj_voice, json_t * conf.config_value_get(JSON_STR_NAME_VOICE_ASPECT_RATIO, this->prefs.aspect_ratio); } + std::string voice_activity_detection_mode; + if(conf.config_value_get(JSON_STR_NAME_VOICE_VOICE_ACTIVITY_DETECTION_MODE, voice_activity_detection_mode)) { + this->prefs.voice_activity_detection_mode = this->voice_activity_detection_mode_to_xrsr(voice_activity_detection_mode); + XLOGD_INFO("voice activity detection mode <%s>", xrsr_stream_voice_activity_mode_str(this->prefs.voice_activity_detection_mode)); + } + std::vector obj_server_hosts; if(conf.config_value_get(JSON_ARRAY_NAME_VOICE_SERVER_HOSTS, obj_server_hosts)) { this->url_hostname_patterns(obj_server_hosts); @@ -1089,6 +1098,17 @@ void ctrlm_voice_t::voice_params_opus_encoder_default(void) { this->voice_params_opus_samples_per_packet_set(); } +xrsr_stream_voice_activity_mode_t ctrlm_voice_t::voice_activity_detection_mode_to_xrsr(const std::string &mode) { + // Configure voice activity detection parameters based on mode + if(mode == "enabled") { // Voice activity detection will be used but not enforced + return(XRSR_STREAM_VOICE_ACTIVITY_MODE_ENABLED); + } else if(mode == "enforced") { // Voice session will only proceed if voice activity is detected + return(XRSR_STREAM_VOICE_ACTIVITY_MODE_ENFORCED); + } + // Voice activity detection is disabled (or invalid mode) + return(XRSR_STREAM_VOICE_ACTIVITY_MODE_DISABLED); +} + void ctrlm_voice_t::voice_params_opus_samples_per_packet_set(void) { guchar fr_dur = (this->prefs.opus_encoder_params[3] >> 4) & 0xF; switch(fr_dur) { @@ -2645,6 +2665,12 @@ void ctrlm_voice_t::voice_session_end_callback(ctrlm_voice_session_end_cb_t *ses end.result = SESSION_END_SHORT_UTTERANCE; end.reason = (int)session->end_reason_rcu; this->voice_ipc->session_end(end); + } else if(stats->session_end_reason == XRSR_SESSION_END_REASON_ERROR_AUDIO_SILENT) { + ctrlm_voice_ipc_event_session_end_t end; + end.common = session->ipc_common_data; + end.result = SESSION_END_SILENT_UTTERANCE; + end.reason = (int)session->end_reason_rcu; + this->voice_ipc->session_end(end); } else { ctrlm_voice_ipc_event_session_end_server_stats_t server_stats; ctrlm_voice_ipc_event_session_end_t end; @@ -2929,9 +2955,20 @@ void ctrlm_voice_t::voice_stream_end_callback(ctrlm_voice_stream_end_cb_t *strea } XLOGD_AUTOMATION_TELEMETRY("src <%s> Packets Lost/Total <%u/%u> %.02f%% duration <%u> ms", ctrlm_voice_device_str(session->voice_device), session->packets_lost, session->packets_lost + session->packets_processed, 100.0 * ((double)session->packets_lost / (double)(session->packets_lost + session->packets_processed)), stream_duration); #ifdef TELEMETRY_SUPPORT + uint32_t packets_total = session->packets_lost + session->packets_processed; + int32_t voice_detected = -1; + uint32_t peak_confidence = 0; + int32_t peak_rms_level = 0; + if(stats->audio_stats.vad_frames_processed > 0) { + voice_detected = (stats->audio_stats.vad_voice_detected) ? 1 : 0; + peak_confidence = (stats->audio_stats.vad_confidence_peak * 100); + peak_rms_level = stats->audio_stats.vad_rms_level_peak; + + XLOGD_INFO("VAD frames <%u> voice detected <%s> confidence peak <%u%%> rms level peak <%d dB>", stats->audio_stats.vad_frames_processed, voice_detected == 1 ? "YES" : "NO", peak_confidence, peak_rms_level); + } + if(this->prefs.telemetry_session_stats) { - uint32_t packets_total = session->packets_lost + session->packets_processed; - session->telemetry_session_stats.update_on_stream_end(stream_duration, packets_total, session->packets_lost, packets_total * samples_per_packet, session->packets_lost * samples_per_packet, decoder_failures, 0); + session->telemetry_session_stats.update_on_stream_end(stream_duration, packets_total, session->packets_lost, packets_total * samples_per_packet, session->packets_lost * samples_per_packet, decoder_failures, 0, voice_detected, peak_confidence, peak_rms_level); } #endif } else if(samples_processed > 0) { @@ -2939,7 +2976,7 @@ void ctrlm_voice_t::voice_stream_end_callback(ctrlm_voice_stream_end_cb_t *strea XLOGD_INFO("src <%s> Samples Lost/Total <%u/%u> %.02f%% buffered max <%u> duration <%u> ms", ctrlm_voice_device_str(session->voice_device), samples_lost, samples_lost + samples_processed, 100.0 * ((double)samples_lost / (double)(samples_lost + samples_processed)), samples_buffered_max, stream_duration); #ifdef TELEMETRY_SUPPORT if(this->prefs.telemetry_session_stats) { - session->telemetry_session_stats.update_on_stream_end(stream_duration, 0, 0, samples_lost + samples_processed, samples_lost, decoder_failures, samples_buffered_max); + session->telemetry_session_stats.update_on_stream_end(stream_duration, 0, 0, samples_lost + samples_processed, samples_lost, decoder_failures, samples_buffered_max, -1, 0, 0); } #endif } @@ -4074,6 +4111,14 @@ void ctrlm_voice_t::voice_rfc_retrieved_handler(const ctrlm_rfc_attr_t& attr) { routing_config_updated |= attr.get_rfc_value(JSON_BOOL_NAME_VOICE_DST_PARAMS_LOW_LATENCY_IPV4_FALLBACK, this->prefs.dst_params_low_latency.ipv4_fallback); routing_config_updated |= attr.get_rfc_value(JSON_INT_NAME_VOICE_DST_PARAMS_LOW_LATENCY_BACKOFF_DELAY, this->prefs.dst_params_low_latency.backoff_delay); + + std::string voice_activity_detection_mode; + if(attr.get_rfc_value(JSON_STR_NAME_VOICE_VOICE_ACTIVITY_DETECTION_MODE, voice_activity_detection_mode)) { + this->prefs.voice_activity_detection_mode = this->voice_activity_detection_mode_to_xrsr(voice_activity_detection_mode); + XLOGD_INFO("voice activity detection mode <%s>", xrsr_stream_voice_activity_mode_str(this->prefs.voice_activity_detection_mode)); + routing_config_updated = true; + } + std::vector obj_server_hosts; if(attr.get_rfc_value(JSON_ARRAY_NAME_VOICE_SERVER_HOSTS, obj_server_hosts)) { this->url_hostname_patterns(obj_server_hosts); diff --git a/src/voice/ctrlm_voice_obj.h b/src/voice/ctrlm_voice_obj.h index 3ec217b2..9c0bc4be 100644 --- a/src/voice/ctrlm_voice_obj.h +++ b/src/voice/ctrlm_voice_obj.h @@ -273,41 +273,42 @@ typedef struct { // End Event Callback Structures typedef struct { - std::string server_url_src_ptt; - std::string server_url_src_ff; - std::string server_url_src_mic_tap; - std::vector server_hosts; - std::string aspect_ratio; - std::string guide_language; - std::string app_id_http; - std::string app_id_ws; - unsigned long timeout_vrex_connect; - unsigned long timeout_vrex_session; - unsigned long timeout_stats; - unsigned long timeout_packet_initial; - unsigned long timeout_packet_subsequent; - guchar bitrate_minimum; - guint16 time_threshold; - bool utterance_save; - bool utterance_use_curtail; - unsigned long utterance_file_qty_max; - unsigned long utterance_file_size_max; - std::string utterance_path; - unsigned long utterance_duration_min; - unsigned long ffv_leading_samples; - bool force_voice_settings; - bool vrex_test_flag; - bool vrex_wuw_bypass_success_flag; - bool vrex_wuw_bypass_failure_flag; - std::string opus_encoder_params_str; - uint8_t opus_encoder_params[CTRLM_RCU_RIB_ATTR_LEN_OPUS_ENCODING_PARAMS]; - bool force_toggle_fallback; - bool telemetry_session_stats; - xrsr_dst_params_t dst_params_standby; - xrsr_dst_params_t dst_params_low_latency; - bool par_voice_enabled; - uint8_t par_voice_eos_method; - uint16_t par_voice_eos_timeout; + std::string server_url_src_ptt; + std::string server_url_src_ff; + std::string server_url_src_mic_tap; + std::vector server_hosts; + std::string aspect_ratio; + std::string guide_language; + std::string app_id_http; + std::string app_id_ws; + unsigned long timeout_vrex_connect; + unsigned long timeout_vrex_session; + unsigned long timeout_stats; + unsigned long timeout_packet_initial; + unsigned long timeout_packet_subsequent; + guchar bitrate_minimum; + guint16 time_threshold; + bool utterance_save; + bool utterance_use_curtail; + unsigned long utterance_file_qty_max; + unsigned long utterance_file_size_max; + std::string utterance_path; + unsigned long utterance_duration_min; + unsigned long ffv_leading_samples; + xrsr_stream_voice_activity_mode_t voice_activity_detection_mode; + bool force_voice_settings; + bool vrex_test_flag; + bool vrex_wuw_bypass_success_flag; + bool vrex_wuw_bypass_failure_flag; + std::string opus_encoder_params_str; + uint8_t opus_encoder_params[CTRLM_RCU_RIB_ATTR_LEN_OPUS_ENCODING_PARAMS]; + bool force_toggle_fallback; + bool telemetry_session_stats; + xrsr_dst_params_t dst_params_standby; + xrsr_dst_params_t dst_params_low_latency; + bool par_voice_enabled; + uint8_t par_voice_eos_method; + uint16_t par_voice_eos_timeout; } voice_session_prefss_t; typedef struct { @@ -637,6 +638,8 @@ class ctrlm_voice_t { bool voice_params_opus_encoder_validate(std::string &opus_encoder_params_str); void voice_params_opus_samples_per_packet_set(void); bool voice_params_hex_str_to_bytes(std::string hex_string, guchar *data, guint32 length); + + xrsr_stream_voice_activity_mode_t voice_activity_detection_mode_to_xrsr(const std::string &mode); bool voice_session_can_request(ctrlm_voice_device_t device); void voice_session_set_active(ctrlm_voice_device_t device); diff --git a/src/voice/ctrlm_voice_obj_generic.cpp b/src/voice/ctrlm_voice_obj_generic.cpp index 4cb35f99..948d6039 100644 --- a/src/voice/ctrlm_voice_obj_generic.cpp +++ b/src/voice/ctrlm_voice_obj_generic.cpp @@ -172,12 +172,17 @@ void ctrlm_voice_generic_t::voice_sdk_update_routes() { xrsr_src_t src = (xrsr_src_t)j; ctrlm_voice_device_t src_device = xrsr_to_voice_device(src); std::string *url = NULL; + + xrsr_stream_voice_activity_mode_t stream_vad_mode = XRSR_STREAM_VOICE_ACTIVITY_MODE_DISABLED; sem_wait(&this->device_status_semaphore); if(this->device_status[src_device] != CTRLM_VOICE_DEVICE_STATUS_DISABLED && this->device_status[src_device] != CTRLM_VOICE_DEVICE_STATUS_NOT_SUPPORTED) { switch(src_device) { case CTRLM_VOICE_DEVICE_PTT: { url = &this->prefs.server_url_src_ptt; + + // For PTT source, use the configured VAD mode which may be disabled, enabled, or enforced + stream_vad_mode = this->prefs.voice_activity_detection_mode; break; } case CTRLM_VOICE_DEVICE_MICROPHONE: @@ -232,15 +237,16 @@ void ctrlm_voice_generic_t::voice_sdk_update_routes() { if(!this->obj_ws_nextgen->get_handlers(&handlers_xrsr)) { XLOGD_ERROR("failed to get handlers ws"); } else { - routes[i].src = src; - routes[i].dst_qty = 1; - routes[i].dsts[0].url = urls_translated[translated_index].c_str(); - routes[i].dsts[0].handlers = handlers_xrsr; - routes[i].dsts[0].formats = XRSR_AUDIO_FORMAT_PCM; - routes[i].dsts[0].stream_time_min = this->prefs.utterance_duration_min; - routes[i].dsts[0].stream_from = stream_from; - routes[i].dsts[0].stream_offset = stream_offset; - routes[i].dsts[0].stream_until = stream_until; + routes[i].src = src; + routes[i].dst_qty = 1; + routes[i].dsts[0].url = urls_translated[translated_index].c_str(); + routes[i].dsts[0].handlers = handlers_xrsr; + routes[i].dsts[0].formats = XRSR_AUDIO_FORMAT_PCM; + routes[i].dsts[0].stream_time_min = this->prefs.utterance_duration_min; + routes[i].dsts[0].stream_vad_mode = stream_vad_mode; + routes[i].dsts[0].stream_from = stream_from; + routes[i].dsts[0].stream_offset = stream_offset; + routes[i].dsts[0].stream_until = stream_until; if(networked_standby_supported && (src == XRSR_SRC_MICROPHONE)) { routes[i].dsts[0].params[XRSR_POWER_MODE_LOW] = &this->prefs.dst_params_standby; } @@ -264,15 +270,16 @@ void ctrlm_voice_generic_t::voice_sdk_update_routes() { if(!this->obj_ws_nsp->get_handlers(&handlers_xrsr)) { XLOGD_ERROR("failed to get handlers ws"); } else { - routes[i].src = src; - routes[i].dst_qty = 1; - routes[i].dsts[0].url = urls_translated[translated_index].c_str(); - routes[i].dsts[0].handlers = handlers_xrsr; - routes[i].dsts[0].formats = XRSR_AUDIO_FORMAT_PCM | XRSR_AUDIO_FORMAT_PCM_32_BIT | XRSR_AUDIO_FORMAT_PCM_32_BIT_MULTI | XRSR_AUDIO_FORMAT_PCM_RAW; - routes[i].dsts[0].stream_time_min = 0; - routes[i].dsts[0].stream_from = XRSR_STREAM_FROM_LIVE; - routes[i].dsts[0].stream_offset = 0; - routes[i].dsts[0].stream_until = XRSR_STREAM_UNTIL_END_OF_STREAM; + routes[i].src = src; + routes[i].dst_qty = 1; + routes[i].dsts[0].url = urls_translated[translated_index].c_str(); + routes[i].dsts[0].handlers = handlers_xrsr; + routes[i].dsts[0].formats = XRSR_AUDIO_FORMAT_PCM | XRSR_AUDIO_FORMAT_PCM_32_BIT | XRSR_AUDIO_FORMAT_PCM_32_BIT_MULTI | XRSR_AUDIO_FORMAT_PCM_RAW; + routes[i].dsts[0].stream_time_min = 0; + routes[i].dsts[0].stream_vad_mode = XRSR_STREAM_VOICE_ACTIVITY_MODE_DISABLED; + routes[i].dsts[0].stream_from = XRSR_STREAM_FROM_LIVE; + routes[i].dsts[0].stream_offset = 0; + routes[i].dsts[0].stream_until = XRSR_STREAM_UNTIL_END_OF_STREAM; if(networked_standby_supported && (src == XRSR_SRC_MICROPHONE)) { routes[i].dsts[0].params[XRSR_POWER_MODE_LOW] = &this->prefs.dst_params_standby; } @@ -305,19 +312,20 @@ void ctrlm_voice_generic_t::voice_sdk_update_routes() { url->append("speech?"); } - routes[i].src = src; - routes[i].dst_qty = 1; - routes[i].dsts[0].url = url->c_str(); - routes[i].dsts[0].handlers = handlers_xrsr; + routes[i].src = src; + routes[i].dst_qty = 1; + routes[i].dsts[0].url = url->c_str(); + routes[i].dsts[0].handlers = handlers_xrsr; #ifdef AUDIO_DECODE - routes[i].dsts[0].formats = XRSR_AUDIO_FORMAT_PCM; + routes[i].dsts[0].formats = XRSR_AUDIO_FORMAT_PCM; #else - routes[i].dsts[0].formats = XRSR_AUDIO_FORMAT_PCM | XRSR_AUDIO_FORMAT_ADPCM; + routes[i].dsts[0].formats = XRSR_AUDIO_FORMAT_PCM | XRSR_AUDIO_FORMAT_ADPCM; #endif - routes[i].dsts[0].stream_time_min = this->prefs.utterance_duration_min; - routes[i].dsts[0].stream_from = stream_from; - routes[i].dsts[0].stream_offset = stream_offset; - routes[i].dsts[0].stream_until = stream_until; + routes[i].dsts[0].stream_time_min = this->prefs.utterance_duration_min; + routes[i].dsts[0].stream_vad_mode = stream_vad_mode; + routes[i].dsts[0].stream_from = stream_from; + routes[i].dsts[0].stream_offset = stream_offset; + routes[i].dsts[0].stream_until = stream_until; if(networked_standby_supported && (src == XRSR_SRC_MICROPHONE)) { routes[i].dsts[0].params[XRSR_POWER_MODE_LOW] = &this->prefs.dst_params_standby; } @@ -334,15 +342,16 @@ void ctrlm_voice_generic_t::voice_sdk_update_routes() { XLOGD_ERROR("failed to get handlers ws"); } else { - routes[i].src = src; - routes[i].dst_qty = 1; - routes[i].dsts[0].url = url->c_str(); - routes[i].dsts[0].handlers = handlers_xrsr; - routes[i].dsts[0].formats = XRSR_AUDIO_FORMAT_PCM; - routes[i].dsts[0].stream_time_min = this->prefs.utterance_duration_min; - routes[i].dsts[0].stream_from = stream_from; - routes[i].dsts[0].stream_offset = stream_offset; - routes[i].dsts[0].stream_until = stream_until; + routes[i].src = src; + routes[i].dst_qty = 1; + routes[i].dsts[0].url = url->c_str(); + routes[i].dsts[0].handlers = handlers_xrsr; + routes[i].dsts[0].formats = XRSR_AUDIO_FORMAT_PCM; + routes[i].dsts[0].stream_time_min = this->prefs.utterance_duration_min; + routes[i].dsts[0].stream_vad_mode = stream_vad_mode; + routes[i].dsts[0].stream_from = stream_from; + routes[i].dsts[0].stream_offset = stream_offset; + routes[i].dsts[0].stream_until = stream_until; if(networked_standby_supported && (src == XRSR_SRC_MICROPHONE)) { routes[i].dsts[0].params[XRSR_POWER_MODE_LOW] = &this->prefs.dst_params_standby; } @@ -357,15 +366,16 @@ void ctrlm_voice_generic_t::voice_sdk_update_routes() { XLOGD_ERROR("failed to get handlers ws"); } else { - routes[i].src = src; - routes[i].dst_qty = 1; - routes[i].dsts[0].url = urls_translated[translated_index].c_str(); - routes[i].dsts[0].handlers = handlers_xrsr; - routes[i].dsts[0].formats = XRSR_AUDIO_FORMAT_PCM; - routes[i].dsts[0].stream_time_min = this->prefs.utterance_duration_min; - routes[i].dsts[0].stream_from = stream_from; - routes[i].dsts[0].stream_offset = stream_offset; - routes[i].dsts[0].stream_until = stream_until; + routes[i].src = src; + routes[i].dst_qty = 1; + routes[i].dsts[0].url = urls_translated[translated_index].c_str(); + routes[i].dsts[0].handlers = handlers_xrsr; + routes[i].dsts[0].formats = XRSR_AUDIO_FORMAT_PCM; + routes[i].dsts[0].stream_time_min = this->prefs.utterance_duration_min; + routes[i].dsts[0].stream_vad_mode = stream_vad_mode; + routes[i].dsts[0].stream_from = stream_from; + routes[i].dsts[0].stream_offset = stream_offset; + routes[i].dsts[0].stream_until = stream_until; if(networked_standby_supported && (src == XRSR_SRC_MICROPHONE)) { routes[i].dsts[0].params[XRSR_POWER_MODE_LOW] = &this->prefs.dst_params_standby; } diff --git a/src/voice/ipc/ctrlm_voice_ipc.h b/src/voice/ipc/ctrlm_voice_ipc.h index 969a8380..db8dc582 100644 --- a/src/voice/ipc/ctrlm_voice_ipc.h +++ b/src/voice/ipc/ctrlm_voice_ipc.h @@ -92,7 +92,8 @@ typedef enum { SESSION_END_SUCCESS, SESSION_END_FAILURE, SESSION_END_ABORT, - SESSION_END_SHORT_UTTERANCE + SESSION_END_SHORT_UTTERANCE, + SESSION_END_SILENT_UTTERANCE } ctrlm_voice_ipc_event_session_end_result_t; typedef struct { diff --git a/src/voice/ipc/ctrlm_voice_ipc_iarm_legacy.cpp b/src/voice/ipc/ctrlm_voice_ipc_iarm_legacy.cpp index 6564ef4c..bdcc85d8 100644 --- a/src/voice/ipc/ctrlm_voice_ipc_iarm_legacy.cpp +++ b/src/voice/ipc/ctrlm_voice_ipc_iarm_legacy.cpp @@ -158,6 +158,18 @@ bool ctrlm_voice_ipc_iarm_legacy_t::session_end(const ctrlm_voice_ipc_event_sess ret = broadcast_iarm_event_legacy(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_SESSION_SHORT, &event, sizeof(event)); break; } + case SESSION_END_SILENT_UTTERANCE: { + ctrlm_voice_iarm_event_session_silent_t event = {0}; + event.api_revision = CTRLM_VOICE_IARM_BUS_API_REVISION; + event.network_id = session_end.common.network_id; + event.network_type = session_end.common.network_type; + event.controller_id = session_end.common.controller_id; + event.session_id = session_end.common.session_id_ctrlm; + event.reason = (ctrlm_voice_session_end_reason_t)session_end.reason; + event.return_code_internal = session_end.return_code_internal; + ret = broadcast_iarm_event_legacy(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_SESSION_SILENT, &event, sizeof(event)); + break; + } } } // Reset state diff --git a/src/voice/ipc/ctrlm_voice_ipc_iarm_thunder.cpp b/src/voice/ipc/ctrlm_voice_ipc_iarm_thunder.cpp index 6b407173..b148dda5 100644 --- a/src/voice/ipc/ctrlm_voice_ipc_iarm_thunder.cpp +++ b/src/voice/ipc/ctrlm_voice_ipc_iarm_thunder.cpp @@ -62,6 +62,7 @@ #define JSON_SESSION_END_RESULT_ERROR "error" #define JSON_SESSION_END_RESULT_ABORT "abort" #define JSON_SESSION_END_RESULT_SHORT "shortUtterance" +#define JSON_SESSION_END_RESULT_SILENT "silentUtterance" #define JSON_SESSION_END_TRANSCRIPTION "transcription" #define JSON_SESSION_END_PROTOCOL_ERROR "protocolErrorCode" #define JSON_SESSION_END_PROTOCOL_LIBRARY_ERROR "protocolLibraryErrorCode" @@ -71,6 +72,7 @@ #define JSON_SESSION_END_ERROR_REASON "reason" #define JSON_SESSION_END_ABORT_REASON "reason" #define JSON_SESSION_END_SHORT_REASON "reason" +#define JSON_SESSION_END_SILENT_REASON "reason" #define JSON_SESSION_END_STB_STATS "stbStats" #define JSON_SESSION_END_STB_STATS_TYPE "type" #define JSON_SESSION_END_STB_STATS_FIRMWARE "firmware" @@ -291,6 +293,20 @@ bool ctrlm_voice_ipc_iarm_thunder_t::session_end(const ctrlm_voice_ipc_event_ses } break; } + case SESSION_END_SILENT_UTTERANCE: { + int rc_silent; + rc |= json_object_set_new_nocheck(event_data, JSON_SESSION_END_RESULT, json_string(JSON_SESSION_END_RESULT_SILENT)); + + // Add Audio Silent Data to result object + rc_silent = json_object_set_new_nocheck(event_result, JSON_SESSION_END_SILENT_REASON, json_integer(session_end.reason)); + if(0 != rc_silent) { + XLOGD_ERROR("Error creating audio silent JSON subobject"); + JSON_DEREFERENCE(event_result); + } else { + rc |= json_object_set_new_nocheck(event_data, JSON_SESSION_END_RESULT_SILENT, event_result); + } + break; + } } if(session_end.stb_stats) { int stats_rc; diff --git a/src/voice/telemetry/ctrlm_voice_telemetry_events.cpp b/src/voice/telemetry/ctrlm_voice_telemetry_events.cpp index d5f6bba3..041d420a 100644 --- a/src/voice/telemetry/ctrlm_voice_telemetry_events.cpp +++ b/src/voice/telemetry/ctrlm_voice_telemetry_events.cpp @@ -212,7 +212,10 @@ bool ctrlm_voice_telemetry_session_t::event() { ss << "\"" << m_server_message << "\","; ss << m_result << ","; ss << m_end_reason_stream << ","; - ss << m_ret_code_protocol << "]]"; + ss << m_ret_code_protocol << ","; + ss << m_voice_detected << ","; + ss << m_peak_confidence << ","; + ss << m_peak_rms_level << "]]"; if(m_event_list.length() + ss.str().length() > m_event_list_max_size) { // Maximum data size exceeded XLOGD_WARN("telemetry event exceeds max size <%s,%s>", val_marker.c_str(), ss.str().c_str()); @@ -267,7 +270,7 @@ void ctrlm_voice_telemetry_session_t::update_on_key_release(int32_t time_start_l m_has_key_release = true; } -void ctrlm_voice_telemetry_session_t::update_on_stream_end(uint32_t time_stream_len_act, uint32_t packets_total, uint32_t packets_lost, uint32_t samples_total, uint32_t samples_lost, uint32_t decoder_failures, uint32_t samples_buffered_max) { +void ctrlm_voice_telemetry_session_t::update_on_stream_end(uint32_t time_stream_len_act, uint32_t packets_total, uint32_t packets_lost, uint32_t samples_total, uint32_t samples_lost, uint32_t decoder_failures, uint32_t samples_buffered_max, int32_t voice_detected, uint32_t peak_confidence, int32_t peak_rms_level) { m_time_stream_len_act = time_stream_len_act; m_packets_total = packets_total; m_packets_lost = packets_lost; @@ -276,6 +279,12 @@ void ctrlm_voice_telemetry_session_t::update_on_stream_end(uint32_t time_stream_ m_decoder_failures = decoder_failures; m_samples_buffered_max = samples_buffered_max; + if(voice_detected >= 0) { + m_voice_detected = voice_detected; + m_peak_confidence = peak_confidence; + m_peak_rms_level = peak_rms_level; + } + if(m_has_key_release) { m_time_stream_delta = m_time_stream_len_act - m_time_stream_len_exp; } @@ -320,6 +329,10 @@ void ctrlm_voice_telemetry_session_t::reset_stats() { m_result = false; m_ret_code_protocol = 0; + m_voice_detected = -1; + m_peak_confidence = 0; + m_peak_rms_level = 0; + m_server_message.clear(); m_device_type.clear(); m_device_version.clear(); diff --git a/src/voice/telemetry/ctrlm_voice_telemetry_events.h b/src/voice/telemetry/ctrlm_voice_telemetry_events.h index adadfde6..18fcab29 100644 --- a/src/voice/telemetry/ctrlm_voice_telemetry_events.h +++ b/src/voice/telemetry/ctrlm_voice_telemetry_events.h @@ -75,7 +75,7 @@ class ctrlm_voice_telemetry_session_t : public ctrlm_telemetry_event_t Date: Wed, 27 May 2026 08:15:56 -0400 Subject: [PATCH 58/81] RDKEMW-12856: throw early error when IRDB provides empty waveforms (#236) --- src/ble/ctrlm_ble_network.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ble/ctrlm_ble_network.cpp b/src/ble/ctrlm_ble_network.cpp index 57cdb6da..ab094c0e 100644 --- a/src/ble/ctrlm_ble_network.cpp +++ b/src/ble/ctrlm_ble_network.cpp @@ -796,9 +796,10 @@ void ctrlm_obj_network_ble_t::req_process_program_ir_codes(void *data, int size) } if (ble_rcu_interface_) { - if (!ble_rcu_interface_->programIrSignalWaveforms(controllers_[controller_id]->ieee_address_get().get_value(), + if (ir_codes.empty()) { + XLOGD_ERROR("Provided IR waveforms are empty!"); + } else if (!ble_rcu_interface_->programIrSignalWaveforms(controllers_[controller_id]->ieee_address_get().get_value(), std::move(ir_codes), dqm->vendor_info.rcu_support_bitmask)) { - XLOGD_ERROR("failed to program IR signal waveforms on remote"); } else { success = true; From a67f6d974ef655fa3b0e58eef798584717d482a2 Mon Sep 17 00:00:00 2001 From: Gene Gallagher <129112619+egalla204@users.noreply.github.com> Date: Sat, 30 May 2026 08:19:56 -0400 Subject: [PATCH 59/81] RDKEMW-16814: reduce ble status prints and events (#235) --- src/attributes/ctrlm_attr_general.cpp | 12 +- src/attributes/ctrlm_attr_voice.cpp | 4 +- src/ble/ctrlm_ble_controller.cpp | 4 +- src/ble/ctrlm_ble_controller_attr_version.cpp | 8 +- src/ble/ctrlm_ble_network.cpp | 252 ++++++++++++------ src/ble/ctrlm_ble_network.h | 7 + src/ble/ctrlm_ble_rcu_interface.cpp | 6 +- .../gatt/gatt_audioservice_rdk.cpp | 4 +- .../bleservices/gatt/gatt_batteryservice.cpp | 2 +- .../gatt/gatt_deviceinfoservice.cpp | 20 +- .../bleservices/gatt/gatt_infraredservice.cpp | 4 +- .../bleservices/gatt/gatt_infraredsignal.cpp | 12 +- .../gatt/gatt_remotecontrolservice.cpp | 20 +- .../hal/blercu/bluez/blegattnotifypipe.cpp | 2 +- src/ctrlm_controller.cpp | 6 +- src/ctrlm_ir_controller.cpp | 2 +- src/ctrlm_network.cpp | 10 +- src/ctrlm_network.h | 3 + src/database/ctrlm_database.cpp | 2 +- src/database/ctrlm_db_types.cpp | 4 +- src/network/ctrlm_ir_rf_db.h | 2 +- src/rf4ce/ctrlm_rf4ce_controller.cpp | 2 +- src/rf4ce/ctrlm_rf4ce_network.cpp | 2 +- 23 files changed, 251 insertions(+), 139 deletions(-) diff --git a/src/attributes/ctrlm_attr_general.cpp b/src/attributes/ctrlm_attr_general.cpp index a533e6fc..80a6edb9 100644 --- a/src/attributes/ctrlm_attr_general.cpp +++ b/src/attributes/ctrlm_attr_general.cpp @@ -76,7 +76,7 @@ bool ctrlm_string_db_attr_t::read_db(ctrlm_db_ctx_t ctx) { if(blob.read_db(ctx)) { this->value = blob.to_string(); ret = true; - XLOGD_INFO("%s read from database: %s", this->get_name().c_str(), this->to_string().c_str()); + XLOGD_DEBUG("%s read from database: %s", this->get_name().c_str(), this->to_string().c_str()); } else { XLOGD_ERROR("failed to read from db <%s>", this->get_name().c_str()); } @@ -90,7 +90,7 @@ bool ctrlm_string_db_attr_t::write_db(ctrlm_db_ctx_t ctx) { if(blob.from_string(this->value)) { if(blob.write_db(ctx)) { ret = true; - XLOGD_INFO("%s written to database: %s", this->get_name().c_str(), this->to_string().c_str()); + XLOGD_DEBUG("%s written to database: %s", this->get_name().c_str(), this->to_string().c_str()); } else { XLOGD_ERROR("failed to write to db <%s>", this->get_name().c_str()); } @@ -157,7 +157,7 @@ bool ctrlm_uint64_db_attr_t::read_db(ctrlm_db_ctx_t ctx) { if(data.read_db(ctx)) { this->set_value(data.get_uint64()); ret = true; - XLOGD_INFO("%s read from database: %s", this->get_name().c_str(), this->to_string().c_str()); + XLOGD_DEBUG("%s read from database: %s", this->get_name().c_str(), this->to_string().c_str()); } else { XLOGD_ERROR("failed to read from db <%s>", this->get_name().c_str()); } @@ -169,7 +169,7 @@ bool ctrlm_uint64_db_attr_t::write_db(ctrlm_db_ctx_t ctx) { ctrlm_db_uint64_t data(this->get_key(), this->get_table(), this->get_value()); if(data.write_db(ctx)) { ret = true; - XLOGD_INFO("%s written to database: %s", this->get_name().c_str(), this->to_string().c_str()); + XLOGD_DEBUG("%s written to database: %s", this->get_name().c_str(), this->to_string().c_str()); } else { XLOGD_ERROR("failed to write to db <%s>", this->get_name().c_str()); } @@ -237,7 +237,7 @@ bool ctrlm_ieee_db_addr_t::read_db(ctrlm_db_ctx_t ctx) { if(data.read_db(ctx)) { this->set_value(data.get_uint64()); ret = true; - XLOGD_INFO("%s read from database: %s", this->get_name().c_str(), this->to_string().c_str()); + XLOGD_DEBUG("%s read from database: %s", this->get_name().c_str(), this->to_string().c_str()); } else { XLOGD_ERROR("failed to read from db <%s>", this->get_name().c_str()); } @@ -249,7 +249,7 @@ bool ctrlm_ieee_db_addr_t::write_db(ctrlm_db_ctx_t ctx) { ctrlm_db_uint64_t data(this->get_key(), this->get_table(), this->get_value()); if(data.write_db(ctx)) { ret = true; - XLOGD_INFO("%s written to database: %s", this->get_name().c_str(), this->to_string().c_str()); + XLOGD_DEBUG("%s written to database: %s", this->get_name().c_str(), this->to_string().c_str()); } else { XLOGD_ERROR("failed to write to db <%s>", this->get_name().c_str()); } diff --git a/src/attributes/ctrlm_attr_voice.cpp b/src/attributes/ctrlm_attr_voice.cpp index 87f1759d..963b3b09 100644 --- a/src/attributes/ctrlm_attr_voice.cpp +++ b/src/attributes/ctrlm_attr_voice.cpp @@ -256,7 +256,7 @@ bool ctrlm_voice_metrics_t::read_db(ctrlm_db_ctx_t ctx) { this->utterances_exceeding_packet_loss_threshold_today = ((buf[39] << 24) | (buf[38] << 16) | (buf[37] << 8) | buf[36]); this->utterances_exceeding_packet_loss_threshold_yesterday = ((buf[43] << 24) | (buf[42] << 16) | (buf[41] << 8) | buf[40]); ret = true; - XLOGD_INFO("%s read from database: %s", this->get_name().c_str(), this->to_string().c_str()); + XLOGD_DEBUG("%s read from database: %s", this->get_name().c_str(), this->to_string().c_str()); } else { XLOGD_ERROR("data from db is too small <%s>", this->get_name().c_str()); } @@ -322,7 +322,7 @@ bool ctrlm_voice_metrics_t::write_db(ctrlm_db_ctx_t ctx) { if(blob.from_buffer(buf, sizeof(buf))) { if(blob.write_db(ctx)) { ret = true; - XLOGD_INFO("%s written to database: %s", this->get_name().c_str(), this->to_string().c_str()); + XLOGD_DEBUG("%s written to database: %s", this->get_name().c_str(), this->to_string().c_str()); } else { XLOGD_ERROR("failed to write to db <%s>", this->get_name().c_str()); } diff --git a/src/ble/ctrlm_ble_controller.cpp b/src/ble/ctrlm_ble_controller.cpp index f1a87c22..c9e996c9 100644 --- a/src/ble/ctrlm_ble_controller.cpp +++ b/src/ble/ctrlm_ble_controller.cpp @@ -58,7 +58,7 @@ ctrlm_obj_controller_ble_t::ctrlm_obj_controller_ble_t(ctrlm_controller_id_t con wakeup_custom_list_(), irdbs_supported_(0) { - XLOGD_INFO("constructor - controller id <%u>", controller_id); + XLOGD_DEBUG("constructor - controller id <%u>", controller_id); voice_metrics_->read_config(); ieee_address_->set_num_bytes(6); @@ -66,7 +66,7 @@ ctrlm_obj_controller_ble_t::ctrlm_obj_controller_ble_t(ctrlm_controller_id_t con } ctrlm_obj_controller_ble_t::ctrlm_obj_controller_ble_t() { - XLOGD_INFO("default constructor"); + XLOGD_DEBUG("default constructor"); } void ctrlm_obj_controller_ble_t::db_create() { diff --git a/src/ble/ctrlm_ble_controller_attr_version.cpp b/src/ble/ctrlm_ble_controller_attr_version.cpp index 0bfd0a41..9ffb9077 100644 --- a/src/ble/ctrlm_ble_controller_attr_version.cpp +++ b/src/ble/ctrlm_ble_controller_attr_version.cpp @@ -40,7 +40,7 @@ bool ctrlm_ble_sw_version_t::read_db(ctrlm_db_ctx_t ctx) { if(blob.read_db(ctx)) { if (this->from_string(blob.to_string())) { ret = true; - XLOGD_INFO("%s read from database: %s", this->get_name().c_str(), this->to_string().c_str()); + XLOGD_DEBUG("%s read from database: %s", this->get_name().c_str(), this->to_string().c_str()); } else { XLOGD_ERROR("%s read from database failed to parse <%s> ", this->get_name().c_str(), blob.to_string().c_str()); } @@ -58,7 +58,7 @@ bool ctrlm_ble_sw_version_t::write_db(ctrlm_db_ctx_t ctx) { if(blob.from_string(ver_str)) { if(blob.write_db(ctx)) { ret = true; - XLOGD_INFO("%s written to database: %s", this->get_name().c_str(), this->to_string().c_str()); + XLOGD_DEBUG("%s written to database: %s", this->get_name().c_str(), this->to_string().c_str()); } else { XLOGD_ERROR("failed to write to db <%s>", this->get_name().c_str()); } @@ -90,7 +90,7 @@ bool ctrlm_ble_hw_version_t::read_db(ctrlm_db_ctx_t ctx) { if(blob.read_db(ctx)) { if (this->from_string(blob.to_string())) { ret = true; - XLOGD_INFO("%s read from database: %s", this->get_name().c_str(), this->to_string().c_str()); + XLOGD_DEBUG("%s read from database: %s", this->get_name().c_str(), this->to_string().c_str()); } else { XLOGD_ERROR("%s read from database failed to parse <%s> ", this->get_name().c_str(), blob.to_string().c_str()); } @@ -108,7 +108,7 @@ bool ctrlm_ble_hw_version_t::write_db(ctrlm_db_ctx_t ctx) { if(blob.from_string(ver_str)) { if(blob.write_db(ctx)) { ret = true; - XLOGD_INFO("%s written to database: %s", this->get_name().c_str(), this->to_string().c_str()); + XLOGD_DEBUG("%s written to database: %s", this->get_name().c_str(), this->to_string().c_str()); } else { XLOGD_ERROR("failed to write to db <%s>", this->get_name().c_str()); } diff --git a/src/ble/ctrlm_ble_network.cpp b/src/ble/ctrlm_ble_network.cpp index ab094c0e..c6bdce72 100644 --- a/src/ble/ctrlm_ble_network.cpp +++ b/src/ble/ctrlm_ble_network.cpp @@ -56,6 +56,11 @@ using namespace std; #define CTRLM_BLE_UPGRADE_CONTINUE_TIMEOUT (MINUTE_IN_MILLISECONDS * 5) // 5 minutes #define CTRLM_BLE_UPGRADE_PAUSE_TIMEOUT (MINUTE_IN_MILLISECONDS * 2) // 2 minutes +#define CTRLM_BLE_PRINT_STATUS_TIMEOUT (1000 * 6) // 6 seconds +#define CTRLM_BLE_EVENT_STATUS_TIMEOUT (1000 * 6) // 6 seconds +#define CTRLM_BLE_PRINT_STATUS_DEFER_MAX (20) +#define CTRLM_BLE_EVENT_STATUS_DEFER_MAX (20) + #define CTRLM_VENDOR_BLE_NETWORK_DISABLE_FILE "/etc/vendor/input/ble_network_disable" #define CTRLM_VENDOR_BLE_REMOTE_WHITELIST_FILE "/etc/vendor/input/ble_remote_whitelist.json" #define CTRLM_VENDOR_BLE_NETWORK_OPTIONS_FILE "/etc/vendor/input/ble_network_options.json" @@ -64,6 +69,8 @@ using namespace std; typedef struct { guint upgrade_controllers_timer_tag; guint upgrade_pause_timer_tag; + guint print_status_timer_tag; + guint event_status_timer_tag; } ctrlm_ble_network_t; static ctrlm_ble_network_t g_ctrlm_ble_network; @@ -77,8 +84,11 @@ static const vector ctrlm_ble_ir_key_names { }; -static gboolean ctrlm_ble_upgrade_controllers(gpointer user_data); -static gboolean ctrlm_ble_upgrade_resume(gpointer user_data); +static gboolean ctrlm_ble_print_status_timer_cb(gpointer user_data); +static gboolean ctrlm_ble_event_status_timer_cb(gpointer user_data); + +static gboolean ctrlm_ble_upgrade_controllers_timer_cb(gpointer user_data); +static gboolean ctrlm_ble_upgrade_resume_timer_cb(gpointer user_data); static bool ctrlm_ble_parse_upgrade_image_info(const std::string &filename, ctrlm_ble_upgrade_image_info_t &image_info); ctrlm_ble_unpair_metrics_t::ctrlm_ble_unpair_metrics_t() @@ -288,6 +298,8 @@ ctrlm_obj_network_ble_t::ctrlm_obj_network_ble_t(ctrlm_network_type_t type, ctrl init_result_ = CTRLM_HAL_RESULT_ERROR; ready_ = false; voice_disabled_ = false; + print_status_defer_count_ = 0; + event_status_defer_count_ = 0; g_ctrlm_ble_network.upgrade_controllers_timer_tag = 0; g_ctrlm_ble_network.upgrade_pause_timer_tag = 0; @@ -325,6 +337,8 @@ ctrlm_obj_network_ble_t::~ctrlm_obj_network_ble_t() { ctrlm_timeout_destroy(&g_ctrlm_ble_network.upgrade_controllers_timer_tag); ctrlm_timeout_destroy(&g_ctrlm_ble_network.upgrade_pause_timer_tag); + ctrlm_timeout_destroy(&g_ctrlm_ble_network.event_status_timer_tag); + ctrlm_timeout_destroy(&g_ctrlm_ble_network.print_status_timer_tag); ctrlm_ble_iarm_terminate(); @@ -414,20 +428,18 @@ void ctrlm_obj_network_ble_t::start(GMainLoop* main_loop) } } - // Print out pairing table - XLOGD_INFO("===================================================================="); - XLOGD_INFO(" %u Bound Controllers", controllers_.size()); - XLOGD_INFO("===================================================================="); + XLOGD_INFO("%u bound BLE controllers", controllers_.size()); for(auto &controller : controllers_) { if (controller.second->is_stale(this->stale_remote_time_threshold_get())) { XLOGD_TELEMETRY("Stale remote suspected: <%s>", controller.second->ieee_address_get().to_string().c_str()); } - controller.second->print_status(); } + schedule_status_print(); + // Read IR RF Database from database ir_rf_database_.load_db(); - XLOGD_INFO("\n%s", this->ir_rf_database_.to_string(true).c_str()); + XLOGD_INFO("\n%s", this->ir_rf_database_.to_string(false).c_str()); } @@ -782,7 +794,8 @@ void ctrlm_obj_network_ble_t::req_process_program_ir_codes(void *data, int size) // First add IR Codes to the IR RF Database (this contains all of the logic for maintaining TV vs AVR codes) ir_rf_database_.add_irdb_codes(dqm->ir_codes); - XLOGD_INFO("\n%s", this->ir_rf_database_.to_string(true).c_str()); + XLOGD_INFO("\n%s", this->ir_rf_database_.to_string(false).c_str()); + XLOGD_DEBUG("\n%s", this->ir_rf_database_.to_string(true).c_str()); // Now get the IR codes for the BLE IR slots for(auto key : ctrlm_ble_ir_key_names) { if(ir_rf_database_.has_entry(key)) { @@ -846,7 +859,7 @@ void ctrlm_obj_network_ble_t::req_process_ir_clear_codes(void *data, int size) { } else { success = true; ir_rf_database_.clear_ir_codes(); - XLOGD_INFO("\n%s", ir_rf_database_.to_string(true).c_str()); + XLOGD_INFO("\n%s", ir_rf_database_.to_string(false).c_str()); controllers_[controller_id]->irdb_entry_id_name_set(CTRLM_IRDB_DEV_TYPE_TV, "0"); controllers_[controller_id]->irdb_entry_id_name_set(CTRLM_IRDB_DEV_TYPE_AVR, "0"); } @@ -1272,7 +1285,7 @@ void ctrlm_obj_network_ble_t::clearUpgradeImages() { upgrade_images_.clear(); } -static gboolean ctrlm_ble_upgrade_controllers(gpointer user_data) { +static gboolean ctrlm_ble_upgrade_controllers_timer_cb(gpointer user_data) { ctrlm_network_id_t* net_id = (ctrlm_network_id_t*) user_data; if (net_id != NULL) { // Allocate a message and send it to Control Manager's queue @@ -1287,7 +1300,7 @@ static gboolean ctrlm_ble_upgrade_controllers(gpointer user_data) { return false; } -static gboolean ctrlm_ble_upgrade_resume(gpointer user_data) { +static gboolean ctrlm_ble_upgrade_resume_timer_cb(gpointer user_data) { ctrlm_network_id_t* net_id = (ctrlm_network_id_t*) user_data; if (net_id != NULL) { // Allocate a message and send it to Control Manager's queue @@ -1371,7 +1384,7 @@ void ctrlm_obj_network_ble_t::req_process_upgrade_controllers(void *data, int si // simply will not take the reboot and the software revision will remain unchanged. XLOGD_DEBUG("Upgrading one remote at a time, setting timer for %d minutes to check if other remotes need upgrades.", CTRLM_BLE_UPGRADE_CONTINUE_TIMEOUT / MINUTE_IN_MILLISECONDS); ctrlm_timeout_destroy(&g_ctrlm_ble_network.upgrade_controllers_timer_tag); - g_ctrlm_ble_network.upgrade_controllers_timer_tag = ctrlm_timeout_create(CTRLM_BLE_UPGRADE_CONTINUE_TIMEOUT, ctrlm_ble_upgrade_controllers, &id_); + g_ctrlm_ble_network.upgrade_controllers_timer_tag = ctrlm_timeout_create(CTRLM_BLE_UPGRADE_CONTINUE_TIMEOUT, ctrlm_ble_upgrade_controllers_timer_cb, &id_); return; } else { XLOGD_INFO("Software upgrade not required for controller %s.", controller.second->ieee_address_get().to_string().c_str()); @@ -1403,7 +1416,7 @@ void ctrlm_obj_network_ble_t::req_process_upgrade_controllers(void *data, int si } else { XLOGD_INFO("Upgrade currently in progress, setting timer for %d minutes to check if other remotes need upgrades.", CTRLM_BLE_UPGRADE_CONTINUE_TIMEOUT / MINUTE_IN_MILLISECONDS); ctrlm_timeout_destroy(&g_ctrlm_ble_network.upgrade_controllers_timer_tag); - g_ctrlm_ble_network.upgrade_controllers_timer_tag = ctrlm_timeout_create(CTRLM_BLE_UPGRADE_CONTINUE_TIMEOUT, ctrlm_ble_upgrade_controllers, &id_); + g_ctrlm_ble_network.upgrade_controllers_timer_tag = ctrlm_timeout_create(CTRLM_BLE_UPGRADE_CONTINUE_TIMEOUT, ctrlm_ble_upgrade_controllers_timer_cb, &id_); } } @@ -1667,10 +1680,7 @@ void ctrlm_obj_network_ble_t::ind_rcu_status(ctrlm_hal_ble_RcuStatusData_t *para } void ctrlm_obj_network_ble_t::ind_process_rcu_status(void *data, int size) { - // XLOGD_DEBUG("Enter..."); THREAD_ID_VALIDATE(); - bool report_status = true; - bool print_status = true; ctrlm_hal_ble_RcuStatusData_t *dqm = (ctrlm_hal_ble_RcuStatusData_t *)data; g_assert(dqm); @@ -1687,19 +1697,25 @@ void ctrlm_obj_network_ble_t::ind_process_rcu_status(void *data, int size) { // These properties are associated with the network, not a specific RCU case CTRLM_HAL_BLE_PROPERTY_IS_PAIRING: // don't send up status event for this since CTRLM_HAL_BLE_PROPERTY_STATE handles all pairing states. - report_status = false; - print_status = false; break; case CTRLM_HAL_BLE_PROPERTY_PAIRING_CODE: - report_status = false; // don't send up status event for this. break; case CTRLM_HAL_BLE_PROPERTY_STATE: XLOGD_TELEMETRY("BLE remote RF pairing state changed to <%s>", ctrlm_rf_pair_state_str(dqm->state)); state_ = dqm->state; + if (state_ == CTRLM_RF_PAIR_STATE_COMPLETE || state_ == CTRLM_RF_PAIR_STATE_IDLE) { + // allow some time for all remote data to be received before sending the event to avoid multiple events + schedule_status_event(); + } else { + // for any other states, send event immediately. + schedule_status_event(true); + } break; case CTRLM_HAL_BLE_PROPERTY_IR_STATE: XLOGD_TELEMETRY("BLE remote IR programming state changed to <%s>", ctrlm_ir_state_str(dqm->ir_state)); ir_state_ = dqm->ir_state; + // send event immediately. + schedule_status_event(true); break; default: { @@ -1708,35 +1724,58 @@ void ctrlm_obj_network_ble_t::ind_process_rcu_status(void *data, int size) { if (false == getControllerId(dqm->rcu_data.ieee_address, &controller_id)) { XLOGD_ERROR("Controller <%s> NOT found in the network!!", ctrlm_convert_mac_long_to_string(dqm->rcu_data.ieee_address).c_str()); - report_status = false; - print_status = false; } else { auto controller = controllers_[controller_id]; switch (dqm->property_updated) { case CTRLM_HAL_BLE_PROPERTY_DEVICE_ID: controller->set_device_minor_id(dqm->rcu_data.device_minor_id); + XLOGD_INFO("Controller <%s> device minor ID changed to <%d>", controller->ieee_address_get().to_string().c_str(), dqm->rcu_data.device_minor_id); + //report this immediately since listeners use this to find the input device path for the remote + schedule_status_event(true); break; case CTRLM_HAL_BLE_PROPERTY_NAME: controller->setName(string(dqm->rcu_data.name), true); + XLOGD_INFO("Controller <%s> name changed to <%s>", controller->ieee_address_get().to_string().c_str(), dqm->rcu_data.name); + schedule_status_print(); + schedule_status_event(); break; case CTRLM_HAL_BLE_PROPERTY_MANUFACTURER: controller->setManufacturer(string(dqm->rcu_data.manufacturer), true); + XLOGD_INFO("Controller <%s> manufacturer changed to <%s>", controller->ieee_address_get().to_string().c_str(), dqm->rcu_data.manufacturer); + schedule_status_print(); + schedule_status_event(); break; case CTRLM_HAL_BLE_PROPERTY_MODEL: controller->setModel(string(dqm->rcu_data.model), true); + XLOGD_INFO("Controller <%s> model changed to <%s>", controller->ieee_address_get().to_string().c_str(), dqm->rcu_data.model); + schedule_status_print(); + schedule_status_event(); break; case CTRLM_HAL_BLE_PROPERTY_SERIAL_NUMBER: controller->setSerialNumber(string(dqm->rcu_data.serial_number), true); + XLOGD_INFO("Controller <%s> serial number changed to <%s>", controller->ieee_address_get().to_string().c_str(), dqm->rcu_data.serial_number); + schedule_status_print(); + schedule_status_event(); break; case CTRLM_HAL_BLE_PROPERTY_HW_REVISION: controller->setHwRevision(string(dqm->rcu_data.hw_revision), true); + XLOGD_INFO("Controller <%s> hardware revision changed to <%s>", controller->ieee_address_get().to_string().c_str(), dqm->rcu_data.hw_revision); + schedule_status_print(); + schedule_status_event(); break; case CTRLM_HAL_BLE_PROPERTY_FW_REVISION: controller->setFwRevision(string(dqm->rcu_data.fw_revision), true); + XLOGD_INFO("Controller <%s> firmware revision changed to <%s>", controller->ieee_address_get().to_string().c_str(), dqm->rcu_data.fw_revision); + schedule_status_print(); + schedule_status_event(); break; case CTRLM_HAL_BLE_PROPERTY_SW_REVISION: { controller->setSwRevision(string(dqm->rcu_data.sw_revision), true); + XLOGD_INFO("Controller <%s> software revision changed to <%s>", controller->ieee_address_get().to_string().c_str(), dqm->rcu_data.sw_revision); + schedule_status_print(); + schedule_status_event(); + // SW Rev updated, make sure xconf config file is updated ctrlm_main_queue_msg_header_t *msg = (ctrlm_main_queue_msg_header_t *)g_malloc(sizeof(ctrlm_main_queue_msg_header_t)); if(msg == NULL) { @@ -1749,26 +1788,33 @@ void ctrlm_obj_network_ble_t::ind_process_rcu_status(void *data, int size) { } case CTRLM_HAL_BLE_PROPERTY_IR_CODE: controller->setIrCode(dqm->rcu_data.ir_code); + XLOGD_INFO("Controller <%s> IR code changed to <%d>", controller->ieee_address_get().to_string().c_str(), dqm->rcu_data.ir_code); break; case CTRLM_HAL_BLE_PROPERTY_TOUCH_MODE: controller->setTouchMode(dqm->rcu_data.touch_mode); - print_status = false; - report_status = false; + XLOGD_INFO("Controller <%s> touch mode changed to <%u>", controller->ieee_address_get().to_string().c_str(), dqm->rcu_data.touch_mode); break; case CTRLM_HAL_BLE_PROPERTY_TOUCH_MODE_SETTABLE: controller->setTouchModeSettable(dqm->rcu_data.touch_mode_settable); - print_status = false; - report_status = false; + XLOGD_INFO("Controller <%s> touch mode settable changed to <%s>", controller->ieee_address_get().to_string().c_str(), dqm->rcu_data.touch_mode_settable ? "TRUE" : "FALSE"); break; case CTRLM_HAL_BLE_PROPERTY_BATTERY_LEVEL: controller->setBatteryPercent(dqm->rcu_data.battery_level, true); - print_status = false; + XLOGD_INFO("Controller <%s> battery level changed to <%u%%>", controller->ieee_address_get().to_string().c_str(), dqm->rcu_data.battery_level); + schedule_status_print(); + schedule_status_event(); break; case CTRLM_HAL_BLE_PROPERTY_CONNECTED: controller->setConnected(dqm->rcu_data.connected); + XLOGD_INFO("Controller <%s> connected changed to <%s>", controller->ieee_address_get().to_string().c_str(), dqm->rcu_data.connected ? "TRUE" : "FALSE"); + + schedule_status_print(); + // send event immediately. + schedule_status_event(true); break; case CTRLM_HAL_BLE_PROPERTY_AUDIO_STREAMING: controller->setAudioStreaming(dqm->rcu_data.audio_streaming); + XLOGD_INFO("Controller <%s> audio streaming changed to <%s>", controller->ieee_address_get().to_string().c_str(), dqm->rcu_data.audio_streaming ? "TRUE" : "FALSE"); if(!dqm->rcu_data.audio_streaming) { // report end of stream stats if (ble_rcu_interface_) { @@ -1797,19 +1843,14 @@ void ctrlm_obj_network_ble_t::ind_process_rcu_status(void *data, int size) { } } } - - report_status = false; - print_status = false; break; case CTRLM_HAL_BLE_PROPERTY_AUDIO_GAIN_LEVEL: controller->setAudioGainLevel(dqm->rcu_data.audio_gain_level); - report_status = false; - print_status = false; + XLOGD_INFO("Controller <%s> audio gain level changed to <%u>", controller->ieee_address_get().to_string().c_str(), dqm->rcu_data.audio_gain_level); break; case CTRLM_HAL_BLE_PROPERTY_AUDIO_CODECS: controller->setAudioCodecs(dqm->rcu_data.audio_codecs); - report_status = false; - print_status = false; + XLOGD_INFO("Controller <%s> audio codecs changed to <0x%X>", controller->ieee_address_get().to_string().c_str(), dqm->rcu_data.audio_codecs); break; case CTRLM_HAL_BLE_PROPERTY_IS_UPGRADING: XLOGD_AUTOMATION_INFO("Controller <%s> firmware upgrading = %s", controller->ieee_address_get().to_string().c_str(), dqm->rcu_data.is_upgrading ? "TRUE" : "FALSE"); @@ -1819,8 +1860,6 @@ void ctrlm_obj_network_ble_t::ind_process_rcu_status(void *data, int size) { // flag to TRUE based on this property. Controller upgrade progress flag should only be set to true if packets are actively being sent controller->setUpgradeInProgress(false); } - report_status = false; - print_status = false; break; case CTRLM_HAL_BLE_PROPERTY_UPGRADE_PROGRESS: XLOGD_AUTOMATION_INFO("Controller <%s> firmware upgrade %d%% complete...", controller->ieee_address_get().to_string().c_str(), dqm->rcu_data.upgrade_progress); @@ -1830,21 +1869,17 @@ void ctrlm_obj_network_ble_t::ind_process_rcu_status(void *data, int size) { controller->set_upgrade_progress(dqm->rcu_data.upgrade_progress); if (controller->is_upgrade_progress_at_increment()) { - iarm_event_rcu_firmware_status(*controller); + iarm_event_rcu_firmware_status(*controller); } - report_status = false; - print_status = false; break; case CTRLM_HAL_BLE_PROPERTY_UPGRADE_ERROR: XLOGD_AUTOMATION_ERROR("Controller <%s> firmware upgrade FAILED with error <%s>.", controller->ieee_address_get().to_string().c_str(), dqm->rcu_data.upgrade_error); - report_status = false; - print_status = false; controller->set_upgrade_error(dqm->rcu_data.upgrade_error); if (controller->retry_ota()) { controller->setUpgradeAttempted(false); XLOGD_WARN("Upgrade failed, setting timer for %d minutes to retry.", CTRLM_BLE_UPGRADE_CONTINUE_TIMEOUT / MINUTE_IN_MILLISECONDS); ctrlm_timeout_destroy(&g_ctrlm_ble_network.upgrade_controllers_timer_tag); - g_ctrlm_ble_network.upgrade_controllers_timer_tag = ctrlm_timeout_create(CTRLM_BLE_UPGRADE_CONTINUE_TIMEOUT, ctrlm_ble_upgrade_controllers, &id_); + g_ctrlm_ble_network.upgrade_controllers_timer_tag = ctrlm_timeout_create(CTRLM_BLE_UPGRADE_CONTINUE_TIMEOUT, ctrlm_ble_upgrade_controllers_timer_cb, &id_); controller->set_upgrade_state(CTRLM_RCU_UPGRADE_STATE_RETRYING); } else { controller->check_upgrade_error(); @@ -1871,8 +1906,6 @@ void ctrlm_obj_network_ble_t::ind_process_rcu_status(void *data, int size) { case CTRLM_HAL_BLE_PROPERTY_UNPAIR_REASON: XLOGD_AUTOMATION_INFO("Controller <%s> notified reason for unpairing = <%s>", controller->ieee_address_get().to_string().c_str(), ctrlm_ble_unpair_reason_str(dqm->rcu_data.unpair_reason)); last_rcu_unpair_metrics_.write_rcu_unpair_event(controller->ieee_address_get().get_value(), string(ctrlm_ble_unpair_reason_str(dqm->rcu_data.unpair_reason))); - report_status = false; - print_status = false; if (this->unpair_on_remote_request_ && (dqm->rcu_data.unpair_reason == CTRLM_BLE_RCU_UNPAIR_REASON_SFM || dqm->rcu_data.unpair_reason == CTRLM_BLE_RCU_UNPAIR_REASON_FACTORY_RESET || @@ -1891,8 +1924,6 @@ void ctrlm_obj_network_ble_t::ind_process_rcu_status(void *data, int size) { dqm->rcu_data.reboot_reason == CTRLM_BLE_RCU_REBOOT_REASON_ASSERT ? dqm->rcu_data.assert_report : "" , dqm->rcu_data.reboot_reason == CTRLM_BLE_RCU_REBOOT_REASON_ASSERT ? "\"" : ""); - report_status = false; - print_status = false; if (dqm->rcu_data.reboot_reason == CTRLM_BLE_RCU_REBOOT_REASON_FW_UPDATE) { controller->ota_clear_all_failure_counters(); @@ -1910,48 +1941,114 @@ void ctrlm_obj_network_ble_t::ind_process_rcu_status(void *data, int size) { XLOGD_INFO("Controller <%s> notified last wakeup key = %u (%s key)", controller->ieee_address_get().to_string().c_str(), dqm->rcu_data.last_wakeup_key, ctrlm_linux_key_code_str(dqm->rcu_data.last_wakeup_key, false)); controller->setLastWakeupKey(dqm->rcu_data.last_wakeup_key); - print_status = false; + + // send event immediately. + schedule_status_event(true); break; case CTRLM_HAL_BLE_PROPERTY_WAKEUP_CONFIG: controller->setWakeupConfig(dqm->rcu_data.wakeup_config); XLOGD_INFO("Controller <%s> notified wakeup config = <%s>", controller->ieee_address_get().to_string().c_str(), ctrlm_rcu_wakeup_config_str(controller->get_wakeup_config())); - if (controller->get_wakeup_config() == CTRLM_RCU_WAKEUP_CONFIG_CUSTOM) { - // Don't report status yet if its a custom config. Do that after we receive the custom list - report_status = false; - print_status = false; - } + schedule_status_print(); + schedule_status_event(); break; case CTRLM_HAL_BLE_PROPERTY_WAKEUP_CUSTOM_LIST: controller->setWakeupCustomList(dqm->rcu_data.wakeup_custom_list, dqm->rcu_data.wakeup_custom_list_size); XLOGD_INFO("Controller <%s> notified wakeup custom list = <%s>", controller->ieee_address_get().to_string().c_str(), controller->wakeupCustomListToString().c_str()); - if (controller->get_wakeup_config() != CTRLM_RCU_WAKEUP_CONFIG_CUSTOM) { - // Only report status if the config is set to custom - report_status = false; - print_status = false; - } + schedule_status_print(); + schedule_status_event(); break; case CTRLM_HAL_BLE_PROPERTY_IRDBS_SUPPORTED: controller->setSupportedIrdbs(dqm->rcu_data.irdbs_supported); - report_status = false; - print_status = false; + schedule_status_print(); break; default: XLOGD_WARN("Unhandled Property: %d !!!!!!!!!!!!!!!!!!!!!!!!", dqm->property_updated); - report_status = false; - print_status = false; break; } } break; } } +} + +void ctrlm_obj_network_ble_t::schedule_status_print(bool immediately) { + XLOGD_DEBUG("immediately = <%s>, print_status_defer_count_ = <%d>", immediately ? "TRUE" : "FALSE", print_status_defer_count_); + THREAD_ID_VALIDATE(); + ctrlm_timeout_destroy(&g_ctrlm_ble_network.print_status_timer_tag); + if (immediately || print_status_defer_count_ > CTRLM_BLE_PRINT_STATUS_DEFER_MAX) { + print_status_defer_count_ = 0; + ctrlm_main_queue_msg_header_t msg; + errno_t safec_rc = memset_s(&msg, sizeof(msg), 0, sizeof(msg)); + ERR_CHK(safec_rc); + ctrlm_main_queue_handler_push(CTRLM_HANDLER_NETWORK, (ctrlm_msg_handler_network_t)&ctrlm_obj_network_t::req_process_print_status, &msg, sizeof(msg), NULL, id_); + } else { + print_status_defer_count_++; + g_ctrlm_ble_network.print_status_timer_tag = ctrlm_timeout_create(CTRLM_BLE_PRINT_STATUS_TIMEOUT, ctrlm_ble_print_status_timer_cb, &id_); + } +} + +void ctrlm_obj_network_ble_t::schedule_status_event(bool immediately) { + XLOGD_DEBUG("immediately = <%s>, event_status_defer_count_ = <%d>", immediately ? "TRUE" : "FALSE", event_status_defer_count_); + THREAD_ID_VALIDATE(); + ctrlm_timeout_destroy(&g_ctrlm_ble_network.event_status_timer_tag); + if (immediately || event_status_defer_count_ > CTRLM_BLE_EVENT_STATUS_DEFER_MAX) { + event_status_defer_count_ = 0; + ctrlm_main_queue_msg_header_t msg; + errno_t safec_rc = memset_s(&msg, sizeof(msg), 0, sizeof(msg)); + ERR_CHK(safec_rc); + ctrlm_main_queue_handler_push(CTRLM_HANDLER_NETWORK, (ctrlm_msg_handler_network_t)&ctrlm_obj_network_t::req_process_event_status, &msg, sizeof(msg), NULL, id_); + } else { + event_status_defer_count_++; + g_ctrlm_ble_network.event_status_timer_tag = ctrlm_timeout_create(CTRLM_BLE_EVENT_STATUS_TIMEOUT, ctrlm_ble_event_status_timer_cb, &id_); + } +} + + +void ctrlm_obj_network_ble_t::req_process_print_status(void *data, int size) { + XLOGD_DEBUG("Enter..."); + THREAD_ID_VALIDATE(); + + print_status_defer_count_ = 0; + printStatus(); +} - if (true == print_status) { - printStatus(); +void ctrlm_obj_network_ble_t::req_process_event_status(void *data, int size) { + XLOGD_DEBUG("Enter..."); + THREAD_ID_VALIDATE(); + + event_status_defer_count_ = 0; + iarm_event_rcu_status(); +} + + +static gboolean ctrlm_ble_print_status_timer_cb(gpointer user_data) { + XLOGD_DEBUG("Enter..."); + ctrlm_network_id_t* net_id = (ctrlm_network_id_t*) user_data; + if (net_id != NULL) { + // Allocate a message and send it to Control Manager's queue + ctrlm_main_queue_msg_header_t msg; + errno_t safec_rc = memset_s(&msg, sizeof(msg), 0, sizeof(msg)); + ERR_CHK(safec_rc); + + ctrlm_main_queue_handler_push(CTRLM_HANDLER_NETWORK, (ctrlm_msg_handler_network_t)&ctrlm_obj_network_t::req_process_print_status, &msg, sizeof(msg), NULL, *net_id); } - if (true == report_status) { - iarm_event_rcu_status(); + g_ctrlm_ble_network.print_status_timer_tag = 0; + return false; +} + +static gboolean ctrlm_ble_event_status_timer_cb(gpointer user_data) { + XLOGD_DEBUG("Enter..."); + ctrlm_network_id_t* net_id = (ctrlm_network_id_t*) user_data; + if (net_id != NULL) { + // Allocate a message and send it to Control Manager's queue + ctrlm_main_queue_msg_header_t msg; + errno_t safec_rc = memset_s(&msg, sizeof(msg), 0, sizeof(msg)); + ERR_CHK(safec_rc); + + ctrlm_main_queue_handler_push(CTRLM_HANDLER_NETWORK, (ctrlm_msg_handler_network_t)&ctrlm_obj_network_t::req_process_event_status, &msg, sizeof(msg), NULL, *net_id); } + g_ctrlm_ble_network.event_status_timer_tag = 0; + return false; } void ctrlm_obj_network_ble_t::populate_rcu_status_message(ctrlm_iarm_RcuStatus_params_t *msg) { @@ -2033,6 +2130,10 @@ ctrlm_controller_id_t ctrlm_obj_network_ble_t::controller_add(ctrlm_hal_ble_rcu_ controller->db_store(); } + + schedule_status_print(); + schedule_status_event(); + return id; } @@ -2060,13 +2161,9 @@ void ctrlm_obj_network_ble_t::ind_process_paired(void *data, int size) { return; } - ctrlm_controller_id_t id = controller_add(dqm->rcu_data); - if (controller_exists(id)) { - controllers_[id]->print_status(); - } + controller_add(dqm->rcu_data); // Sync currently connected devices with the HAL - if (ble_rcu_interface_) { auto devices = ble_rcu_interface_->getManagedDevices(); @@ -2130,9 +2227,9 @@ void ctrlm_obj_network_ble_t::ind_process_unpaired(void *data, int size) { controller_remove(id); controllers_.erase(id); - // report updated controller status to the plugin - printStatus(); - iarm_event_rcu_status(); + + schedule_status_print(); + schedule_status_event(); // Update xconf config file ctrlm_main_queue_msg_header_t *msg = (ctrlm_main_queue_msg_header_t *)g_malloc(sizeof(ctrlm_main_queue_msg_header_t)); @@ -2227,7 +2324,7 @@ void ctrlm_obj_network_ble_t::ind_process_keypress(void *data, int size) { XLOGD_INFO("Upgrade cancelled since remote is being used. Setting timer to resume upgrade in %d minutes.", CTRLM_BLE_UPGRADE_PAUSE_TIMEOUT / MINUTE_IN_MILLISECONDS); //delete existing timer and start again ctrlm_timeout_destroy(&g_ctrlm_ble_network.upgrade_pause_timer_tag); - g_ctrlm_ble_network.upgrade_pause_timer_tag = ctrlm_timeout_create(CTRLM_BLE_UPGRADE_PAUSE_TIMEOUT, ctrlm_ble_upgrade_resume, &id_); + g_ctrlm_ble_network.upgrade_pause_timer_tag = ctrlm_timeout_create(CTRLM_BLE_UPGRADE_PAUSE_TIMEOUT, ctrlm_ble_upgrade_resume_timer_cb, &id_); } else if (controller->getUpgradeStuck() && !upgrade_in_progress_) { @@ -2235,7 +2332,7 @@ void ctrlm_obj_network_ble_t::ind_process_keypress(void *data, int size) { controller->ieee_address_get().to_string().c_str()); //delete existing timer and immediately kick off another upgrade ctrlm_timeout_destroy(&g_ctrlm_ble_network.upgrade_pause_timer_tag); - g_ctrlm_ble_network.upgrade_pause_timer_tag = ctrlm_timeout_create(500, ctrlm_ble_upgrade_resume, &id_); + g_ctrlm_ble_network.upgrade_pause_timer_tag = ctrlm_timeout_create(500, ctrlm_ble_upgrade_resume_timer_cb, &id_); } } else if (key_status == CTRLM_KEY_STATUS_UP) { @@ -2380,8 +2477,7 @@ bool ctrlm_obj_network_ble_t::getControllerId(unsigned long long ieee_address, c } } if ( !found ) { - XLOGD_WARN("Controller matching ieee_address (%s) NOT FOUND.", - ctrlm_convert_mac_long_to_string(ieee_address).c_str()); + XLOGD_DEBUG("Controller matching ieee_address (%s) NOT FOUND.", ctrlm_convert_mac_long_to_string(ieee_address).c_str()); } return found; } @@ -2430,7 +2526,7 @@ ctrlm_controller_id_t ctrlm_obj_network_ble_t::controller_id_assign() { // Get the next available controller id for(ctrlm_controller_id_t index = BLE_RCU_ID_RANGE_MIN; index < BLE_RCU_ID_RANGE_MAX; index++) { if(!controller_exists(index)) { - XLOGD_INFO("controller id %u", index); + XLOGD_DEBUG("controller id %u", index); return(index); } } diff --git a/src/ble/ctrlm_ble_network.h b/src/ble/ctrlm_ble_network.h index 1182889a..90724d94 100644 --- a/src/ble/ctrlm_ble_network.h +++ b/src/ble/ctrlm_ble_network.h @@ -168,6 +168,11 @@ class ctrlm_obj_network_ble_t : public ctrlm_obj_network_t { virtual void req_process_cancel_controller_upgrade(void *data, int size); virtual void req_process_status_controller_upgrade(void *data, int size); + void schedule_status_print(bool immediately = false); + void schedule_status_event(bool immediately = false); + virtual void req_process_print_status(void *data, int size); + virtual void req_process_event_status(void *data, int size); + virtual json_t * xconf_export_controllers(); void addUpgradeImage(const ctrlm_ble_upgrade_image_info_t &image_info); void clearUpgradeImages(); @@ -215,6 +220,8 @@ class ctrlm_obj_network_ble_t : public ctrlm_obj_network_t { bool upgrade_in_progress_ = false; bool unpair_on_remote_request_ = true; ctrlm_ble_unpair_metrics_t last_rcu_unpair_metrics_; + int print_status_defer_count_ = 0; + int event_status_defer_count_ = 0; std::map controllers_; std::map upgrade_images_; diff --git a/src/ble/ctrlm_ble_rcu_interface.cpp b/src/ble/ctrlm_ble_rcu_interface.cpp index f90cdc67..4f3e1635 100644 --- a/src/ble/ctrlm_ble_rcu_interface.cpp +++ b/src/ble/ctrlm_ble_rcu_interface.cpp @@ -1397,7 +1397,7 @@ std::vector ctrlm_ble_rcu_interface_t::getManagedDevices() return ret; } - XLOGD_INFO("Get list of currently managed devices"); + XLOGD_DEBUG("Get list of currently managed devices"); auto devices = m_controller->managedDevices(); for (auto const &device : devices) { @@ -1482,8 +1482,8 @@ static int OpenKeyInputDevice(uint64_t ieee_address) uint64_t evdev_macaddr = ctrlm_convert_mac_string_to_long(libevdev_get_uniq(evdev)); if (evdev_macaddr == ieee_address) { - XLOGD_INFO("Input Dev Node (%s) for device (0x%llX) FOUND, returning file descriptor: <%d>", - keyInputFilename.c_str(), ieee_address, input_fd); + XLOGD_INFO("Input Dev Node (%s) for device: <%s> (0x%llX) FOUND, returning file descriptor: <%d>", + keyInputFilename.c_str(), libevdev_get_name(evdev), ieee_address, input_fd); libevdev_free(evdev); evdev = NULL; diff --git a/src/ble/hal/blercu/bleservices/gatt/gatt_audioservice_rdk.cpp b/src/ble/hal/blercu/bleservices/gatt/gatt_audioservice_rdk.cpp index 265a5d83..80897f10 100644 --- a/src/ble/hal/blercu/bleservices/gatt/gatt_audioservice_rdk.cpp +++ b/src/ble/hal/blercu/bleservices/gatt/gatt_audioservice_rdk.cpp @@ -468,7 +468,7 @@ void GattAudioServiceRdk::requestGainLevel() if (value.size() == 1) { m_gainLevel = value[0]; - XLOGD_INFO("Successfully read from RCU gain level = %u", m_gainLevel); + XLOGD_DEBUG("Successfully read from RCU gain level = %u", m_gainLevel); m_gainLevelChangedSlots.invoke(m_gainLevel); } else { XLOGD_ERROR("gain value received has invalid length (%d bytes)", value.size()); @@ -502,7 +502,7 @@ void GattAudioServiceRdk::requestAudioCodecs() if (value.size() == sizeof(m_audioCodecs)) { memcpy(&m_audioCodecs, value.data(), sizeof(m_audioCodecs)); - XLOGD_INFO("Successfully read from RCU audio codecs bit mask = 0x%X", m_audioCodecs); + XLOGD_DEBUG("Successfully read from RCU audio codecs bit mask = 0x%X", m_audioCodecs); m_audioCodecsChangedSlots.invoke(m_audioCodecs); } else { XLOGD_ERROR("audio codec received has invalid length (%d bytes)", value.size()); diff --git a/src/ble/hal/blercu/bleservices/gatt/gatt_batteryservice.cpp b/src/ble/hal/blercu/bleservices/gatt/gatt_batteryservice.cpp index 0dd84fcf..951674e7 100644 --- a/src/ble/hal/blercu/bleservices/gatt/gatt_batteryservice.cpp +++ b/src/ble/hal/blercu/bleservices/gatt/gatt_batteryservice.cpp @@ -275,7 +275,7 @@ void GattBatteryService::onBatteryLevelChanged(const std::vector &newVa return; } - XLOGD_INFO("battery level changed to %u%%", newValue[0]); + XLOGD_DEBUG("battery level changed to %u%%", newValue[0]); // clamp the reply between 0 and 100 unsigned int level = sanitiseBatteryLevel(newValue[0]); diff --git a/src/ble/hal/blercu/bleservices/gatt/gatt_deviceinfoservice.cpp b/src/ble/hal/blercu/bleservices/gatt/gatt_deviceinfoservice.cpp index f4955dfa..441dda76 100644 --- a/src/ble/hal/blercu/bleservices/gatt/gatt_deviceinfoservice.cpp +++ b/src/ble/hal/blercu/bleservices/gatt/gatt_deviceinfoservice.cpp @@ -239,11 +239,9 @@ void GattDeviceInfoService::onEnteredState(int state) */ void GattDeviceInfoService::onExitedState(int state) { - // on exiting the initialising state we should have all the required - // device info fields, so at this point log a milestone message with all - // the details + // on exiting the initialising state we should have all the required device info fields if (state == InitialisingState) { - XLOGD_INFO("bluetooth rcu device info [ %s / %s / hw:%s / fw:%s / sw:%s ]", + XLOGD_DEBUG("bluetooth rcu device info [ %s / %s / hw:%s / fw:%s / sw:%s ]", m_manufacturerName.c_str(), m_modelNumber.c_str(), m_hardwareRevision.c_str(), m_firmwareVersion.c_str(), m_softwareVersion.c_str()); @@ -380,7 +378,7 @@ void GattDeviceInfoService::setManufacturerName(const std::vector &valu if (name != m_manufacturerName) { m_manufacturerName = name; - XLOGD_INFO("manufacturer name: %s", m_manufacturerName.c_str()); + XLOGD_DEBUG("manufacturer name: %s", m_manufacturerName.c_str()); m_manufacturerNameChangedSlots.invoke(m_manufacturerName); } @@ -401,7 +399,7 @@ void GattDeviceInfoService::setModelNumber(const std::vector &value) if (model != m_modelNumber) { m_modelNumber = model; - XLOGD_INFO("model number: %s", m_modelNumber.c_str()); + XLOGD_DEBUG("model number: %s", m_modelNumber.c_str()); m_modelNumberChangedSlots.invoke(m_modelNumber); } @@ -422,7 +420,7 @@ void GattDeviceInfoService::setSerialNumber(const std::vector &value) if (serial != m_serialNumber) { m_serialNumber = serial; - XLOGD_INFO("serial number: %s", m_serialNumber.c_str()); + XLOGD_DEBUG("serial number: %s", m_serialNumber.c_str()); m_serialNumberChangedSlots.invoke(m_serialNumber); } @@ -443,7 +441,7 @@ void GattDeviceInfoService::setHardwareRevision(const std::vector &valu if (hwVersion != m_hardwareRevision) { m_hardwareRevision = hwVersion; - XLOGD_INFO("hardware revision: %s", m_hardwareRevision.c_str()); + XLOGD_DEBUG("hardware revision: %s", m_hardwareRevision.c_str()); m_hardwareRevisionChangedSlots.invoke(m_hardwareRevision); } @@ -465,7 +463,7 @@ void GattDeviceInfoService::setFirmwareVersion(const std::vector &value if (fwVersion != m_firmwareVersion) { m_firmwareVersion = fwVersion; - XLOGD_INFO("firmware version: %s", m_firmwareVersion.c_str()); + XLOGD_DEBUG("firmware version: %s", m_firmwareVersion.c_str()); m_firmwareVersionChangedSlots.invoke(m_firmwareVersion); } @@ -487,7 +485,7 @@ void GattDeviceInfoService::setSoftwareVersion(const std::vector &value if (swVersion != m_softwareVersion) { m_softwareVersion = swVersion; - XLOGD_INFO("software version: %s", m_softwareVersion.c_str()); + XLOGD_DEBUG("software version: %s", m_softwareVersion.c_str()); m_softwareVersionChangedSlots.invoke(m_softwareVersion); } @@ -518,7 +516,7 @@ void GattDeviceInfoService::setSystemId(const std::vector &value) (((uint64_t)value[6]) << 8) | (((uint64_t)value[7]) << 0); - XLOGD_INFO("system id: 0x%016llx", m_systemId); + XLOGD_DEBUG("system id: 0x%016llx", m_systemId); } // ----------------------------------------------------------------------------- diff --git a/src/ble/hal/blercu/bleservices/gatt/gatt_infraredservice.cpp b/src/ble/hal/blercu/bleservices/gatt/gatt_infraredservice.cpp index 40dff3c6..d7be62e4 100644 --- a/src/ble/hal/blercu/bleservices/gatt/gatt_infraredservice.cpp +++ b/src/ble/hal/blercu/bleservices/gatt/gatt_infraredservice.cpp @@ -449,7 +449,7 @@ void GattInfraredService::requestIrSupport() if (value.size() == 1) { uint8_t irSupport_ = value[0]; - XLOGD_INFO("IR support value = 0x%x", irSupport_); + XLOGD_DEBUG("IR support value = 0x%x", irSupport_); if (irSupport_ != m_irSupport) { m_irSupport = irSupport_; m_irSupportChangedSlots.invoke(m_irSupport); @@ -500,7 +500,7 @@ void GattInfraredService::requestCodeId() (int32_t(value[2]) << 16) | (int32_t(value[3]) << 24); - XLOGD_INFO("IR code ID = %d", codeId_); + XLOGD_DEBUG("IR code ID = %d", codeId_); if (codeId_ != m_codeId) { m_codeId = codeId_; diff --git a/src/ble/hal/blercu/bleservices/gatt/gatt_infraredsignal.cpp b/src/ble/hal/blercu/bleservices/gatt/gatt_infraredsignal.cpp index b5ecc8fb..351e5cb9 100644 --- a/src/ble/hal/blercu/bleservices/gatt/gatt_infraredsignal.cpp +++ b/src/ble/hal/blercu/bleservices/gatt/gatt_infraredsignal.cpp @@ -365,27 +365,27 @@ void GattInfraredSignal::onEnteredInitialisingState() switch (value[0]) { case 0x0C: m_keyCode = Key_PowerPrimary; - XLOGD_INFO("found characteristic for 0x%02hhx (Key_PowerPrimary)", value[0]); + XLOGD_DEBUG("found characteristic for 0x%02hhx (Key_PowerPrimary)", value[0]); break; case 0x0B: m_keyCode = Key_PowerSecondary; - XLOGD_INFO("found characteristic for 0x%02hhx (Key_PowerSecondary)", value[0]); + XLOGD_DEBUG("found characteristic for 0x%02hhx (Key_PowerSecondary)", value[0]); break; case 0x29: m_keyCode = Key_Input; - XLOGD_INFO("found characteristic for 0x%02hhx (Key_Input)", value[0]); + XLOGD_DEBUG("found characteristic for 0x%02hhx (Key_Input)", value[0]); break; case 0x10: m_keyCode = Key_VolUp; - XLOGD_INFO("found characteristic for 0x%02hhx (Key_VolUp)", value[0]); + XLOGD_DEBUG("found characteristic for 0x%02hhx (Key_VolUp)", value[0]); break; case 0x11: m_keyCode = Key_VolDown; - XLOGD_INFO("found characteristic for 0x%02hhx (Key_VolDown)", value[0]); + XLOGD_DEBUG("found characteristic for 0x%02hhx (Key_VolDown)", value[0]); break; case 0x0D: m_keyCode = Key_Mute; - XLOGD_INFO("found characteristic for 0x%02hhx (Key_Mute)", value[0]); + XLOGD_DEBUG("found characteristic for 0x%02hhx (Key_Mute)", value[0]); break; /* diff --git a/src/ble/hal/blercu/bleservices/gatt/gatt_remotecontrolservice.cpp b/src/ble/hal/blercu/bleservices/gatt/gatt_remotecontrolservice.cpp index a6c89198..2ec23b0a 100644 --- a/src/ble/hal/blercu/bleservices/gatt/gatt_remotecontrolservice.cpp +++ b/src/ble/hal/blercu/bleservices/gatt/gatt_remotecontrolservice.cpp @@ -279,7 +279,7 @@ void GattRemoteControlService::requestStartUnpairNotify() m_stateMachine.cancelDelayedEvents(RetryStartNotifyEvent); m_stateMachine.postDelayedEvent(RetryStartNotifyEvent, 2000); } else { - XLOGD_INFO("request to start notifications on Unpair characteristic succeeded"); + XLOGD_DEBUG("request to start notifications on Unpair characteristic succeeded"); } }; @@ -303,7 +303,7 @@ void GattRemoteControlService::requestStartRebootNotify() m_stateMachine.cancelDelayedEvents(RetryStartNotifyEvent); m_stateMachine.postDelayedEvent(RetryStartNotifyEvent, 2000); } else { - XLOGD_INFO("request to start notifications on Reboot Reason characteristic succeeded"); + XLOGD_DEBUG("request to start notifications on Reboot Reason characteristic succeeded"); } }; @@ -332,7 +332,7 @@ void GattRemoteControlService::requestRawBatteryVoltageChangedNotify() m_stateMachine.cancelDelayedEvents(RetryStartNotifyEvent); m_stateMachine.postDelayedEvent(RetryStartNotifyEvent, 2000); } else { - XLOGD_INFO("request to start notifications on Raw Battery Voltage characteristic succeeded"); + XLOGD_DEBUG("request to start notifications on Raw Battery Voltage characteristic succeeded"); } }; @@ -433,7 +433,7 @@ void GattRemoteControlService::requestUnpairReason() if (value.size() == 1) { m_unpairReason = value[0]; - XLOGD_INFO("Initial unpair reason is %u (%s)", m_unpairReason, + XLOGD_DEBUG("Initial unpair reason is %u (%s)", m_unpairReason, ctrlm_ble_unpair_reason_str((ctrlm_ble_RcuUnpairReason_t)m_unpairReason)); } else { XLOGD_ERROR("Unpair reason received has invalid length (%d bytes)", value.size()); @@ -468,7 +468,7 @@ void GattRemoteControlService::requestRebootReason() if (value.size() == 1) { m_rebootReason = value[0]; - XLOGD_INFO("Initial reboot reason is %u (%s)", m_rebootReason, + XLOGD_DEBUG("Initial reboot reason is %u (%s)", m_rebootReason, ctrlm_ble_reboot_reason_str((ctrlm_ble_RcuRebootReason_t)m_rebootReason)); if (m_rebootReason == CTRLM_BLE_RCU_REBOOT_REASON_ASSERT) { @@ -509,7 +509,7 @@ void GattRemoteControlService::requestAssertReport() if (value.size() == CTRLM_RCU_ASSERT_REPORT_MAX_SIZE) { string assertStr(value.begin(), value.end()); - XLOGD_INFO("Initial RCU assert report is <%s>", assertStr.c_str()); + XLOGD_DEBUG("Initial RCU assert report is <%s>", assertStr.c_str()); } else { XLOGD_ERROR("RCU assert report has invalid length (%d bytes)", value.size()); } @@ -545,7 +545,7 @@ void GattRemoteControlService::requestLastKeypress() if (value.size() == 1) { m_lastKeypress = value[0]; - XLOGD_INFO("Successfully read last key press characteristic, value = <0x%X>, emitting signal...", m_lastKeypress); + XLOGD_DEBUG("Successfully read last key press characteristic, value = <0x%X>, emitting signal...", m_lastKeypress); m_lastKeypressChangedSlots.invoke(m_lastKeypress); } else { XLOGD_ERROR("Last key press received has invalid length (%d bytes)", value.size()); @@ -625,7 +625,7 @@ void GattRemoteControlService::requestAdvConfig() if (value.size() == 1) { m_advConfig = value[0]; - XLOGD_INFO("Successfully read advertising config characteristic, value = <0x%X>, emitting signal...", m_advConfig); + XLOGD_DEBUG("Successfully read advertising config characteristic, value = <0x%X>, emitting signal...", m_advConfig); m_advConfigChangedSlots.invoke(m_advConfig); } else { XLOGD_ERROR("Advertising config received has invalid length (%d bytes)", value.size()); @@ -662,7 +662,7 @@ void GattRemoteControlService::requestAdvConfigCustomList() XLOGD_ERROR("Failed to read custom advertising config due to <%s>", reply->errorMessage().c_str()); } else { m_advConfigCustomList = reply->result(); - XLOGD_INFO("Successfully read advertising config custom list characteristic"); + XLOGD_DEBUG("Successfully read advertising config custom list characteristic"); m_advConfigCustomListChangedSlots.invoke(m_advConfigCustomList); } @@ -882,7 +882,7 @@ void GattRemoteControlService::onRebootReasonChanged(const vector &newV XLOGD_ERROR("Reboot reason received has invalid length (%d bytes)", newValue.size()); } else { m_rebootReason = newValue[0]; - XLOGD_INFO("reboot reason changed to %u (%s)", m_rebootReason, + XLOGD_DEBUG("reboot reason changed to %u (%s)", m_rebootReason, ctrlm_ble_reboot_reason_str((ctrlm_ble_RcuRebootReason_t)m_rebootReason)); if (m_rebootReason == CTRLM_BLE_RCU_REBOOT_REASON_ASSERT && m_assertReportCharacteristic) { diff --git a/src/ble/hal/blercu/bluez/blegattnotifypipe.cpp b/src/ble/hal/blercu/bluez/blegattnotifypipe.cpp index 6f54af37..1c9c0afc 100644 --- a/src/ble/hal/blercu/bluez/blegattnotifypipe.cpp +++ b/src/ble/hal/blercu/bluez/blegattnotifypipe.cpp @@ -183,7 +183,7 @@ BleGattNotifyPipe::BleGattNotifyPipe(int notifyPipeFd, uint16_t mtu, BleUuid uui m_notifyThread.name = "ble_notify"; sem_init(&m_notifyThreadSem, 0, 0); - XLOGD_INFO("Launching thread <%s> for %s...", m_notifyThread.name, m_uuid.toString().c_str()); + XLOGD_DEBUG("Launching thread <%s> for %s...", m_notifyThread.name, m_uuid.toString().c_str()); if (false == ThreadCreate(&m_notifyThread, NotifyThread, this)) { sem_destroy(&m_notifyThreadSem); } else { diff --git a/src/ctrlm_controller.cpp b/src/ctrlm_controller.cpp index 60173d47..0e7b175e 100644 --- a/src/ctrlm_controller.cpp +++ b/src/ctrlm_controller.cpp @@ -43,15 +43,15 @@ ctrlm_obj_controller_t::ctrlm_obj_controller_t(ctrlm_controller_id_t controller_ voice_metrics_(std::make_shared(&network, controller_id)), ota_failure_cnt_from_last_success_(std::make_shared("OTA Failure Count From Last Success", 0, &network, controller_id, "ota_failure_cnt_last_success")) { - XLOGD_INFO("constructor - %u", controller_id_); + XLOGD_DEBUG("constructor - %u", controller_id_); } ctrlm_obj_controller_t::ctrlm_obj_controller_t() { - XLOGD_INFO("constructor - default"); + XLOGD_DEBUG("constructor - default"); } ctrlm_obj_controller_t::~ctrlm_obj_controller_t() { - XLOGD_INFO("deconstructor - %u", controller_id_); + XLOGD_DEBUG("destructor - %u", controller_id_); } void ctrlm_obj_controller_t::db_load() { diff --git a/src/ctrlm_ir_controller.cpp b/src/ctrlm_ir_controller.cpp index c42b8eae..d2b16855 100644 --- a/src/ctrlm_ir_controller.cpp +++ b/src/ctrlm_ir_controller.cpp @@ -143,7 +143,7 @@ bool ctrlm_ir_controller_t::read_config() { string substr; getline( ss, substr, ',' ); if (!substr.empty()) { - XLOGD_INFO("Adding IR input device name: <%s>", substr.c_str()); + XLOGD_DEBUG("Adding IR input device name: <%s>", substr.c_str()); input_device_names_.push_back(substr); } } diff --git a/src/ctrlm_network.cpp b/src/ctrlm_network.cpp index 26201231..8715c038 100644 --- a/src/ctrlm_network.cpp +++ b/src/ctrlm_network.cpp @@ -66,7 +66,7 @@ ctrlm_obj_network_t::ctrlm_obj_network_t() { } ctrlm_obj_network_t::~ctrlm_obj_network_t() { - XLOGD_INFO("deconstructor - Type (%u) Id (%u) Name (%s)", type_, id_, name_.c_str()); + XLOGD_INFO("destructor - Type (%u) Id (%u) Name (%s)", type_, id_, name_.c_str()); if(NULL != hal_api_term_) { ctrlm_network_term_hal_t *term_data; @@ -882,6 +882,14 @@ void ctrlm_obj_network_t::req_process_upgrade_controllers(void *data, int size) XLOGD_WARN("not implemented for %s network", name_get()); } +void ctrlm_obj_network_t::req_process_print_status(void *data, int size) { + XLOGD_WARN("not implemented for %s network", name_get()); +} + +void ctrlm_obj_network_t::req_process_event_status(void *data, int size) { + XLOGD_WARN("not implemented for %s network", name_get()); +} + void ctrlm_obj_network_t::req_process_start_controller_upgrade(void *data, int size) { ctrlm_main_queue_msg_start_controller_upgrade_t *dqm = (ctrlm_main_queue_msg_start_controller_upgrade_t *)data; diff --git a/src/ctrlm_network.h b/src/ctrlm_network.h index ca6ad547..592e6e84 100644 --- a/src/ctrlm_network.h +++ b/src/ctrlm_network.h @@ -288,6 +288,9 @@ class ctrlm_obj_network_t virtual void power_state_change(gboolean waking_up); time_t stale_remote_time_threshold_get(); + virtual void req_process_print_status(void *data, int size); + virtual void req_process_event_status(void *data, int size); + virtual void iarm_event_rcu_status(void); virtual void iarm_event_rcu_validation_status(void); virtual void iarm_event_rcu_firmware_status(const ctrlm_obj_controller_t &rcu); diff --git a/src/database/ctrlm_database.cpp b/src/database/ctrlm_database.cpp index dfe2bb21..e28e4432 100644 --- a/src/database/ctrlm_database.cpp +++ b/src/database/ctrlm_database.cpp @@ -2183,7 +2183,7 @@ void ctrlm_db_controller_create(ctrlm_network_id_t network_id, ctrlm_controller_ char table_name_controller_entry[CONTROLLER_TABLE_NAME_MAX_LEN]; char key[3]; - XLOGD_INFO("network id %u controller id %u", network_id, controller_id); + XLOGD_DEBUG("network id %u controller id %u", network_id, controller_id); switch(ctrlm_network_type_get(network_id)) { case CTRLM_NETWORK_TYPE_IP: diff --git a/src/database/ctrlm_db_types.cpp b/src/database/ctrlm_db_types.cpp index 0a464b06..362c9f3c 100644 --- a/src/database/ctrlm_db_types.cpp +++ b/src/database/ctrlm_db_types.cpp @@ -35,7 +35,7 @@ ctrlm_db_obj_t::~ctrlm_db_obj_t() { bool ctrlm_db_obj_t::read_db(ctrlm_db_ctx_t ctx) { bool ret = false; sqlite3 *handle = (sqlite3 *)ctx; - XLOGD_INFO("reading blob %s from table %s", this->key.c_str(), this->table.c_str()); + XLOGD_DEBUG("reading blob %s from table %s", this->key.c_str(), this->table.c_str()); if(handle) { sqlite3_stmt *stmt = NULL; std::string query = "SELECT value FROM " + this->table + " WHERE key='" + this->key + "';"; @@ -63,7 +63,7 @@ bool ctrlm_db_obj_t::read_db(ctrlm_db_ctx_t ctx) { bool ctrlm_db_obj_t::write_db(ctrlm_db_ctx_t ctx) { bool ret = false; sqlite3 *handle = (sqlite3 *)ctx; - XLOGD_INFO("writing blob %s to table %s", this->key.c_str(), this->table.c_str()); + XLOGD_DEBUG("writing blob %s to table %s", this->key.c_str(), this->table.c_str()); if(handle) { sqlite3_stmt *stmt = NULL; std::string query = "INSERT OR REPLACE INTO " + this->table + "(key,value) VALUES (?,?);"; diff --git a/src/network/ctrlm_ir_rf_db.h b/src/network/ctrlm_ir_rf_db.h index c9f489a2..439bf1e0 100644 --- a/src/network/ctrlm_ir_rf_db.h +++ b/src/network/ctrlm_ir_rf_db.h @@ -43,7 +43,7 @@ class ctrlm_ir_rf_db_t { ctrlm_ir_rf_db_t(bool power_toggle_favor_tv = true, bool power_discrete_favor_tv = false); /** - * Default Deconstructor + * Default destructor */ virtual ~ctrlm_ir_rf_db_t(); diff --git a/src/rf4ce/ctrlm_rf4ce_controller.cpp b/src/rf4ce/ctrlm_rf4ce_controller.cpp index 960b3fd2..c298ab9e 100644 --- a/src/rf4ce/ctrlm_rf4ce_controller.cpp +++ b/src/rf4ce/ctrlm_rf4ce_controller.cpp @@ -212,7 +212,7 @@ ctrlm_obj_controller_rf4ce_t::ctrlm_obj_controller_rf4ce_t() { } ctrlm_obj_controller_rf4ce_t::~ctrlm_obj_controller_rf4ce_t() { - XLOGD_INFO("deconstructor"); + XLOGD_INFO("destructor"); if (metrics_tag_ != 0) { XLOGD_WARN("metrics timer destroyed"); diff --git a/src/rf4ce/ctrlm_rf4ce_network.cpp b/src/rf4ce/ctrlm_rf4ce_network.cpp index 2caa75c2..85a3caea 100644 --- a/src/rf4ce/ctrlm_rf4ce_network.cpp +++ b/src/rf4ce/ctrlm_rf4ce_network.cpp @@ -304,7 +304,7 @@ ctrlm_obj_network_rf4ce_t::ctrlm_obj_network_rf4ce_t() { } ctrlm_obj_network_rf4ce_t::~ctrlm_obj_network_rf4ce_t() { - XLOGD_INFO("deconstructor"); + XLOGD_INFO("destructor"); for (auto timeout : bind_validation_failed_timeout_) { ctrlm_timeout_destroy(&timeout->timer_id); if (controller_exists(timeout->controller_id)){ From 6e4a8b551fd1a1d76e685e71bee6f47e97e12046 Mon Sep 17 00:00:00 2001 From: Kelvin Lu <119349872+klu339@users.noreply.github.com> Date: Mon, 1 Jun 2026 09:13:24 -0400 Subject: [PATCH 60/81] RDKEMW-15135: T2 RCU pairing (#189) --- src/ble/ctrlm_ble_network.cpp | 60 ++++++++++ src/ble/ctrlm_ble_network.h | 2 + src/ble/ctrlm_ble_rcu_interface.cpp | 6 + src/ble/ctrlm_ble_rcu_interface.h | 5 + src/ble/hal/blercu/blercuadapter.h | 6 +- src/ble/hal/blercu/blercucontroller.cpp | 23 +++- src/ble/hal/blercu/blercucontroller.h | 18 +++ src/ble/hal/blercu/blercudevice.h | 5 +- .../hal/blercu/blercupairingstatemachine.cpp | 110 +++++++++++++++++- .../hal/blercu/blercupairingstatemachine.h | 42 ++++++- src/ble/hal/blercu/bluez/blercuadapter.cpp | 18 +-- src/ble/hal/blercu/bluez/blercuadapter_p.h | 4 +- src/ble/hal/blercu/bluez/blercudevice.cpp | 10 +- src/ble/hal/blercu/bluez/blercudevice_p.h | 2 +- src/telemetry/ctrlm_telemetry_event.cpp | 12 +- src/telemetry/ctrlm_telemetry_event.h | 2 + src/telemetry/ctrlm_telemetry_markers.h | 24 ++++ .../telemetry/ctrlm_voice_telemetry_events.h | 2 +- 18 files changed, 321 insertions(+), 30 deletions(-) diff --git a/src/ble/ctrlm_ble_network.cpp b/src/ble/ctrlm_ble_network.cpp index c6bdce72..94a9022c 100644 --- a/src/ble/ctrlm_ble_network.cpp +++ b/src/ble/ctrlm_ble_network.cpp @@ -47,6 +47,8 @@ #include #include #include "ctrlm_rcp_ipc_iarm_thunder.h" +#include "ctrlm_telemetry.h" +#include using namespace std; @@ -384,6 +386,9 @@ ctrlm_hal_result_t ctrlm_obj_network_ble_t::hal_init_request(GThread *ctrlm_main ble_rcu_interface_->addRcuKeypressHandler(Slot(is_alive_, std::bind(&ctrlm_obj_network_ble_t::ind_keypress, this, std::placeholders::_1))); + ble_rcu_interface_->addRcuPairingOutcomeHandler(Slot(is_alive_, + std::bind(&ctrlm_obj_network_ble_t::ind_rcu_pairing_outcome, this, std::placeholders::_1))); + ble_rcu_interface_->startKeyMonitorThread(); @@ -1671,6 +1676,61 @@ void ctrlm_obj_network_ble_t::req_process_unpair(void *data, int size) { // BEGIN - Process Indications from HAL to the network in CTRLM Main thread context // ------------------------------------------------------------------------------------------------------------------------------------------------------------------ +void ctrlm_obj_network_ble_t::ind_rcu_pairing_outcome(const BleRcuPairingOutcome &outcome) { + // Queue to the ctrlm main thread for duration computation and telemetry emission + auto copy = std::make_shared(outcome); + ctrlm_main_queue_handler_push_new( + CTRLM_HANDLER_NETWORK, + (ctrlm_msg_handler_network_t)&ctrlm_obj_network_ble_t::ind_process_rcu_pairing_outcome, + copy, + NULL, + id_); +} + +void ctrlm_obj_network_ble_t::ind_process_rcu_pairing_outcome(void *data, int size) { + THREAD_ID_VALIDATE(); + const BleRcuPairingOutcome *outcome = static_cast(data); + if (sizeof(BleRcuPairingOutcome) != size) { + XLOGD_ERROR("Invalid size!"); + return; + } + if (!outcome) { + XLOGD_ERROR("pairing outcome data is NULL"); + return; + } + +#ifdef TELEMETRY_SUPPORT + // Serialize to array for ctrlm.rcu.pairing.attempt_accum T2 marker + std::stringstream ss; + ss << "["; + ss << MARKER_RCU_PAIRING_ATTEMPT_VERSION << ","; + ss << "\"" << name_get() << "\","; + ss << outcome->method << ","; + ss << outcome->result << ","; + ss << outcome->discovered << ","; + ss << "\"" << outcome->name << "\","; + ss << outcome->bluezRetries << ","; + + for (uint8_t i = 0; i < outcome->maxBluezRetries; i++) { + if (i >= outcome->bluezRetries || i >= outcome->bluezError.size()) { + ss << "\"null\""; + } else { + std::string msg = outcome->bluezError.at(i); + auto pos = msg.rfind(": "); + msg = (pos != std::string::npos) ? msg.substr(pos + 2) : msg; + ss << "\"" << msg << "\""; + } + if (i != (outcome->maxBluezRetries-1)) { + ss << ","; + } + } + ss << "]"; + + ctrlm_telemetry_event_t ev(MARKER_RCU_PAIRING_ATTEMPT, ss.str()); + ev.event(); +#endif // TELEMETRY_SUPPORT +} + void ctrlm_obj_network_ble_t::ind_rcu_status(ctrlm_hal_ble_RcuStatusData_t *params) { // push to the main queue and process it synchronously there diff --git a/src/ble/ctrlm_ble_network.h b/src/ble/ctrlm_ble_network.h index 90724d94..73f2c8b9 100644 --- a/src/ble/ctrlm_ble_network.h +++ b/src/ble/ctrlm_ble_network.h @@ -134,11 +134,13 @@ class ctrlm_obj_network_ble_t : public ctrlm_obj_network_t { void ind_rcu_paired(ctrlm_hal_ble_IndPaired_params_t *params); void ind_rcu_unpaired(ctrlm_hal_ble_IndUnPaired_params_t *params); void ind_keypress(ctrlm_hal_ble_IndKeypress_params_t *params); + void ind_rcu_pairing_outcome(const BleRcuPairingOutcome &outcome); void ind_process_rcu_status(void *data, int size); void ind_process_paired(void *data, int size); void ind_process_unpaired(void *data, int size); void ind_process_keypress(void *data, int size); + void ind_process_rcu_pairing_outcome(void *data, int size); virtual void req_process_network_status(void *data, int size); virtual void req_process_controller_status(void *data, int size); diff --git a/src/ble/ctrlm_ble_rcu_interface.cpp b/src/ble/ctrlm_ble_rcu_interface.cpp index 4f3e1635..2fd194b7 100644 --- a/src/ble/ctrlm_ble_rcu_interface.cpp +++ b/src/ble/ctrlm_ble_rcu_interface.cpp @@ -185,6 +185,12 @@ void ctrlm_ble_rcu_interface_t::initialize() m_rcuUnpairedSlots.invoke(¶ms); }; m_controller->addManagedDeviceRemovedSlot(Slot(m_isAlive, deviceRemovedSlot)); + + auto pairingOutcomeSlot = [this](const BleRcuPairingOutcome &outcome) + { + m_rcuPairingOutcomeSlots.invoke(outcome); + }; + m_controller->addPairingOutcomeSlot(Slot(m_isAlive, pairingOutcomeSlot)); } voice_params_par_t params; diff --git a/src/ble/ctrlm_ble_rcu_interface.h b/src/ble/ctrlm_ble_rcu_interface.h index c9209c6f..e29c7fc8 100644 --- a/src/ble/ctrlm_ble_rcu_interface.h +++ b/src/ble/ctrlm_ble_rcu_interface.h @@ -145,12 +145,17 @@ class ctrlm_ble_rcu_interface_t { m_rcuKeypressSlots.addSlot(func); } + inline void addRcuPairingOutcomeHandler(const Slot &func) + { + m_rcuPairingOutcomeSlots.addSlot(func); + } Slots m_rcuStatusChangedSlots; Slots m_rcuPairedSlots; Slots m_rcuUnpairedSlots; Slots m_rcuKeypressSlots; + Slots m_rcuPairingOutcomeSlots; private: std::shared_ptr m_isAlive; diff --git a/src/ble/hal/blercu/blercuadapter.h b/src/ble/hal/blercu/blercuadapter.h index cd9fc9e8..3407c25e 100644 --- a/src/ble/hal/blercu/blercuadapter.h +++ b/src/ble/hal/blercu/blercuadapter.h @@ -72,7 +72,7 @@ class BleRcuAdapter virtual bool isDevicePaired(const BleAddress &address) const = 0; virtual bool isDeviceConnected(const BleAddress &address) const = 0; - virtual bool addDevice(const BleAddress &address) = 0; + virtual bool addDevice(const BleAddress &address, int retries) = 0; virtual bool removeDevice(const BleAddress &address) = 0; virtual bool setConnectionParams(BleAddress address, double minInterval, double maxInterval, @@ -107,7 +107,7 @@ class BleRcuAdapter { m_deviceNameChangedSlots.addSlot(func); } - inline void addDevicePairingErrorSlot(const Slot &func) + inline void addDevicePairingErrorSlot(const Slot &func) { m_devicePairingErrorSlots.addSlot(func); } @@ -135,7 +135,7 @@ class BleRcuAdapter Slots m_deviceFoundSlots; Slots m_deviceRemovedSlots; Slots m_deviceNameChangedSlots; - Slots m_devicePairingErrorSlots; + Slots m_devicePairingErrorSlots; Slots m_devicePairingChangedSlots; Slots m_deviceReadyChangedSlots; diff --git a/src/ble/hal/blercu/blercucontroller.cpp b/src/ble/hal/blercu/blercucontroller.cpp index 9924c9df..fd077d1f 100644 --- a/src/ble/hal/blercu/blercucontroller.cpp +++ b/src/ble/hal/blercu/blercucontroller.cpp @@ -41,7 +41,6 @@ using namespace std; - class BleRcuController_userdata { public: BleRcuController_userdata(shared_ptr isAlive_, BleRcuControllerImpl* controller_) @@ -607,6 +606,17 @@ void BleRcuControllerImpl::onFinishedPairing() m_state = Complete; m_stateChangedSlots.invoke(m_state); + + // emit pairing outcome telemetry + BleRcuPairingOutcome outcome; + outcome.method = m_pairingStateMachine.pairingMethod(); + outcome.result = BleRcuPairingStateMachine::SUCCESS; + outcome.bluezRetries = m_pairingStateMachine.bluezRetries(); + outcome.maxBluezRetries = MAX_PAIRING_RETRIES; + outcome.bluezError = m_pairingStateMachine.bluezError(); + outcome.name = m_pairingStateMachine.pairedName(); + outcome.discovered = m_pairingStateMachine.discoveredDevices(); + m_pairingOutcomeSlots.invoke(outcome); } // ----------------------------------------------------------------------------- @@ -646,6 +656,17 @@ void BleRcuControllerImpl::onFailedPairing() m_state = Failed; m_stateChangedSlots.invoke(m_state); + + // emit pairing outcome telemetry + BleRcuPairingOutcome outcome; + outcome.method = m_pairingStateMachine.pairingMethod(); + outcome.result = m_pairingStateMachine.failureReason(); + outcome.bluezRetries = m_pairingStateMachine.bluezRetries(); + outcome.maxBluezRetries = MAX_PAIRING_RETRIES; + outcome.bluezError = m_pairingStateMachine.bluezError(); + outcome.discovered = m_pairingStateMachine.discoveredDevices(); + outcome.name = ""; + m_pairingOutcomeSlots.invoke(outcome); } diff --git a/src/ble/hal/blercu/blercucontroller.h b/src/ble/hal/blercu/blercucontroller.h index 770d4d07..b4eab730 100644 --- a/src/ble/hal/blercu/blercucontroller.h +++ b/src/ble/hal/blercu/blercucontroller.h @@ -36,10 +36,23 @@ #include #include +#include +#include +#include class BleRcuDevice; +struct BleRcuPairingOutcome +{ + int method; // numeric enum value for PairingMethod + int result; // numeric enum value for FailureReason + int discovered; // number of discovered devices + int bluezRetries; // number of bluez retries attempted + int maxBluezRetries; // max number of retries + std::string name; // empty on failure + std::vector bluezError; // bluez error messages +}; class BleRcuController { @@ -101,12 +114,17 @@ class BleRcuController { m_stateChangedSlots.addSlot(func); } + inline void addPairingOutcomeSlot(const Slot &func) + { + m_pairingOutcomeSlots.addSlot(func); + } protected: Slots m_managedDeviceAddedSlots; Slots m_managedDeviceRemovedSlots; Slots m_pairingStateChangedSlots; Slots m_stateChangedSlots; + Slots m_pairingOutcomeSlots; }; #endif // !defined(BLERCUCONTROLLER_H) diff --git a/src/ble/hal/blercu/blercudevice.h b/src/ble/hal/blercu/blercudevice.h index 8ab7cc44..ef297db7 100644 --- a/src/ble/hal/blercu/blercudevice.h +++ b/src/ble/hal/blercu/blercudevice.h @@ -187,17 +187,18 @@ class BleRcuDevice { m_readyChangedSlots.addSlot(func); } - inline void addPairingErrorSlot(const Slot &func) + inline void addPairingErrorSlot(const Slot &func) { m_pairingErrorSlots.addSlot(func); } + protected: Slots m_connectedChangedSlots; Slots m_pairedChangedSlots; Slots m_nameChangedSlots; Slots m_readyChangedSlots; - Slots m_pairingErrorSlots; + Slots m_pairingErrorSlots; }; diff --git a/src/ble/hal/blercu/blercupairingstatemachine.cpp b/src/ble/hal/blercu/blercupairingstatemachine.cpp index e23c6939..0779fb69 100644 --- a/src/ble/hal/blercu/blercupairingstatemachine.cpp +++ b/src/ble/hal/blercu/blercupairingstatemachine.cpp @@ -52,6 +52,9 @@ BleRcuPairingStateMachine::BleRcuPairingStateMachine(const shared_ptraddPoweredChangedSlot(Slot(m_isAlive, std::bind(&BleRcuPairingStateMachine::onAdapterPoweredChanged, this, std::placeholders::_1))); - m_adapter->addDevicePairingErrorSlot(Slot(m_isAlive, - std::bind(&BleRcuPairingStateMachine::onDevicePairingError, this, std::placeholders::_1, std::placeholders::_2))); + m_adapter->addDevicePairingErrorSlot(Slot(m_isAlive, + std::bind(&BleRcuPairingStateMachine::onDevicePairingError, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4))); } BleRcuPairingStateMachine::~BleRcuPairingStateMachine() @@ -206,6 +209,37 @@ bool BleRcuPairingStateMachine::isScanningForAutoPair() const return isRunning() && m_isAutoPairing && m_stateMachine.inState(DiscoverySuperState); } +BleRcuPairingStateMachine::PairingMethod BleRcuPairingStateMachine::pairingMethod() const +{ + return m_pairingMethod; +} + +BleRcuPairingStateMachine::FailureReason BleRcuPairingStateMachine::failureReason() const +{ + return m_failureReason; +} + +int BleRcuPairingStateMachine::discoveredDevices() const +{ + return m_discoveredDevices.size(); +} + +int BleRcuPairingStateMachine::bluezRetries() const +{ + return m_bluezRetries; +} + +std::string BleRcuPairingStateMachine::pairedName() const +{ + auto it = m_discoveredDevices.find(m_pairedMac); + return (it != m_discoveredDevices.end()) ? it->second : ""; +} + +std::vector BleRcuPairingStateMachine::bluezError() const +{ + return m_bluezErrorMsg; +} + // ----------------------------------------------------------------------------- /*! @@ -239,6 +273,14 @@ void BleRcuPairingStateMachine::startAutoWithTimeout(int timeoutMs) m_targetedPairingNames.push_back(name); } + // reset telemetry tracking state + m_pairingMethod = AUTO_TIMEOUT; + m_failureReason = SUCCESS; + m_discoveredDevices.clear(); + m_bluezRetries = 0; + m_pairedMac.clear(); + m_bluezErrorMsg.clear(); + // start the state machine m_stateMachine.start(); @@ -289,6 +331,14 @@ void BleRcuPairingStateMachine::startWithCode(uint8_t pairingCode) m_targetedPairingNames.push_back(std::regex(nameWithCode, std::regex_constants::ECMAScript)); } + // reset telemetry tracking state + m_pairingMethod = IR_CODE; + m_failureReason = SUCCESS; + m_discoveredDevices.clear(); + m_bluezRetries = 0; + m_pairedMac.clear(); + m_bluezErrorMsg.clear(); + // start the state machine m_stateMachine.start(); @@ -321,6 +371,14 @@ void BleRcuPairingStateMachine::startWithMacList(const std::vector & // set the list of addresses to filter for m_pairingMacList = macList; + // reset telemetry tracking state + m_pairingMethod = MAC_LIST; + m_failureReason = SUCCESS; + m_discoveredDevices.clear(); + m_bluezRetries = 0; + m_pairedMac.clear(); + m_bluezErrorMsg.clear(); + // start the state machine m_stateMachine.start(); @@ -353,6 +411,9 @@ void BleRcuPairingStateMachine::stop() XLOGD_INFO("cancelling pairing"); + // record the cancellation reason before posting the event + m_failureReason = FAIL_CANCELLED; + // post a cancel event and let the state-machine clean up m_stateMachine.postEvent(CancelRequestEvent); } @@ -432,15 +493,21 @@ void BleRcuPairingStateMachine::onStateExit(int state) */ void BleRcuPairingStateMachine::onStateTransition(int oldState, int newState) { + FailureReason newFailureReason = SUCCESS; + if (newState == FinishedState) { if (oldState == UnpairingState) { XLOGD_AUTOMATION_WARN("timed-out in un-pairing phase (failed rcu may be left paired)"); + newFailureReason = FAIL_PAIRING_TIMEOUT; } else if (oldState == StartingDiscoveryState) { XLOGD_AUTOMATION_ERROR("timed-out waiting for discovery started signal"); + newFailureReason = FAIL_DISCOVERY_TIMEOUT; } else if (oldState == DiscoveringState) { XLOGD_AUTOMATION_ERROR("timed-out in discovery phase (didn't find target rcu device to pair to)"); + newFailureReason = FAIL_TARGET_RCU_NOT_FOUND; } else if (oldState == StoppingDiscoveryState) { XLOGD_AUTOMATION_ERROR("timed-out waiting for discovery to stop (suggesting something has gone wrong inside bluez)"); + newFailureReason = FAIL_DISCOVERY_STOP_TIMEOUT; } } else if (newState == UnpairingState) { if (oldState == EnablePairableState || oldState == PairingState) { @@ -449,6 +516,11 @@ void BleRcuPairingStateMachine::onStateTransition(int oldState, int newState) XLOGD_AUTOMATION_WARN("timed-out in setup phase (rcu didn't response to all requests within %dms)", m_setupTimeout); } } + + // Change the failure reason only if it hasn't already been set elsewhere + if (newFailureReason != SUCCESS && m_failureReason == SUCCESS) { + m_failureReason = newFailureReason; + } } void BleRcuPairingStateMachine::onEnteredStoppingDiscoveryStartedExternally() @@ -521,6 +593,9 @@ void BleRcuPairingStateMachine::onDiscoveryChanged(bool discovering) if (discovering) { m_stateMachine.postEvent(DiscoveryStartedEvent); } else { + if (m_stateMachine.inState(DiscoverySuperState)) { + m_failureReason = FAIL_DISCOVERY_STOPPED; + } m_stateMachine.postEvent(DiscoveryStoppedEvent); } } @@ -543,6 +618,7 @@ void BleRcuPairingStateMachine::onEnteredDiscoveringState() map::const_iterator it = deviceNames.begin(); for (; it != deviceNames.end(); ++it) { processDevice(it->first, it->second); + m_discoveredDevices.emplace(it->first, it->second); } } @@ -660,7 +736,7 @@ void BleRcuPairingStateMachine::onEnteredPairingState() m_pairingSlots.invoke(); // request the manager to pair with the device - m_adapter->addDevice(m_targetAddress); + m_adapter->addDevice(m_targetAddress, MAX_PAIRING_RETRIES); } // ----------------------------------------------------------------------------- @@ -714,6 +790,7 @@ void BleRcuPairingStateMachine::onEnteredUnpairingState() // remove (unpair) the target device because we've failed :-( if (m_adapter->removeDevice(m_targetAddress) == false) { + m_failureReason = FAIL_PAIRING_TIMEOUT; m_stateMachine.postEvent(DeviceUnpairedEvent); } } @@ -883,6 +960,7 @@ void BleRcuPairingStateMachine::onDeviceFound(const BleAddress &address, XLOGD_DEBUG("device added %s %s (target %s)", address.toString().c_str(), name.c_str(), m_targetAddress.toString().c_str()); + m_discoveredDevices.emplace(address, name); processDevice(address, name); } @@ -905,6 +983,11 @@ void BleRcuPairingStateMachine::onDeviceRemoved(const BleAddress &address) // check if the device removed is the one we're targeting if (!m_targetAddress.isNull() && (m_targetAddress == address)) { + if (m_stateMachine.inState(UnpairingState)) { + m_failureReason = FAIL_PAIRING_TIMEOUT; + } else { + m_failureReason = FAIL_DEVICE_REMOVED; + } m_stateMachine.postEvent(DeviceRemovedEvent); } } @@ -927,6 +1010,7 @@ void BleRcuPairingStateMachine::onDeviceNameChanged(const BleAddress &address, XLOGD_DEBUG("device name changed %s %s (target %s)", address.toString().c_str(), name.c_str(), m_targetAddress.toString().c_str()); + m_discoveredDevices[address] = name; processDevice(address, name); } @@ -941,12 +1025,23 @@ void BleRcuPairingStateMachine::onDeviceNameChanged(const BleAddress &address, */ void BleRcuPairingStateMachine::onDevicePairingError(const BleAddress &address, - const string &error) + const string &error, + int retryCnt, + bool finalRetry) { if (!m_stateMachine.isRunning()) { return; } + m_failureReason = FAIL_BLUEZ_ERROR; + m_bluezRetries = retryCnt; + m_bluezErrorMsg.push_back(error); + + if (!finalRetry) { + // Still retrying so don't stop pairing and timers yet + return; + } + XLOGD_ERROR("Device (%s) pairing failed, shutting down state machine...", address.toString().c_str()); // stop the pairing and setup timeout timers @@ -979,6 +1074,11 @@ void BleRcuPairingStateMachine::onDevicePairingChanged(const BleAddress &address if (paired) { m_stateMachine.postEvent(DevicePairedEvent); } else { + if (m_stateMachine.inState(UnpairingState)) { + m_failureReason = FAIL_PAIRING_TIMEOUT; + } else { + m_failureReason = FAIL_DEVICE_UNPAIRED; + } m_stateMachine.postEvent(DeviceUnpairedEvent); } } @@ -1006,6 +1106,7 @@ void BleRcuPairingStateMachine::onDeviceReadyChanged(const BleAddress &address, if (ready) { m_pairingSuccesses++; m_pairingSucceeded = true; + m_pairedMac = address; m_stateMachine.postEvent(DeviceReadyEvent); } } @@ -1027,6 +1128,7 @@ void BleRcuPairingStateMachine::onAdapterPoweredChanged(bool powered) } if (!powered) { + m_failureReason = FAIL_ADAPTER_OFF; m_stateMachine.postEvent(AdapterPoweredOffEvent); } } diff --git a/src/ble/hal/blercu/blercupairingstatemachine.h b/src/ble/hal/blercu/blercupairingstatemachine.h index cfb15c31..f3d18178 100644 --- a/src/ble/hal/blercu/blercupairingstatemachine.h +++ b/src/ble/hal/blercu/blercupairingstatemachine.h @@ -39,14 +39,36 @@ #include #include #include - +#include class BleRcuAdapter; class ConfigSettings; +#define MAX_PAIRING_RETRIES 3 class BleRcuPairingStateMachine { +public: + enum PairingMethod { + AUTO_TIMEOUT, + MAC_LIST, + IR_CODE, + }; + + enum FailureReason { + SUCCESS = 0, + FAIL_DISCOVERY_TIMEOUT, + FAIL_DISCOVERY_STOPPED, + FAIL_DISCOVERY_STOP_TIMEOUT, + FAIL_PAIRING_TIMEOUT, + FAIL_TARGET_RCU_NOT_FOUND, + FAIL_BLUEZ_ERROR, + FAIL_ADAPTER_OFF, + FAIL_DEVICE_UNPAIRED, + FAIL_DEVICE_REMOVED, + FAIL_CANCELLED + }; + public: enum State { RunningSuperState, @@ -73,6 +95,14 @@ class BleRcuPairingStateMachine bool isScanningForAutoPair() const; int pairingCode() const; +// Pairing outcome getters (valid after the state machine stops) + PairingMethod pairingMethod() const; + FailureReason failureReason() const; + int discoveredDevices() const; + int bluezRetries() const; + std::string pairedName() const; + std::vector bluezError() const; + // public slots: void startAutoWithTimeout(int timeoutMs); void startWithCode(uint8_t pairingCode); @@ -114,7 +144,7 @@ class BleRcuPairingStateMachine void onDeviceNameChanged(const BleAddress &address, const std::string &name); void onDevicePairingChanged(const BleAddress &address, bool paired); void onDeviceReadyChanged(const BleAddress &address, bool ready); - void onDevicePairingError(const BleAddress &address, const std::string &error); + void onDevicePairingError(const BleAddress &address, const std::string &error, int retryCnt, bool finalRetry); void onAdapterPoweredChanged(bool powered); @@ -172,6 +202,14 @@ class BleRcuPairingStateMachine int m_pairingSuccesses; bool m_pairingSucceeded; + // Pairing outcome tracking + PairingMethod m_pairingMethod; + FailureReason m_failureReason; + std::map m_discoveredDevices; + int m_bluezRetries; + BleAddress m_pairedMac; + std::vector m_bluezErrorMsg; + BtrMgrAdapter m_btrMgrAdapter; bool discoveryStartedExternally = false; BtrMgrAdapter::OperationType lastOperationType = BtrMgrAdapter::unknownOperation; diff --git a/src/ble/hal/blercu/bluez/blercuadapter.cpp b/src/ble/hal/blercu/bluez/blercuadapter.cpp index 56949f40..ea05fbc4 100644 --- a/src/ble/hal/blercu/bluez/blercuadapter.cpp +++ b/src/ble/hal/blercu/bluez/blercuadapter.cpp @@ -1216,10 +1216,10 @@ bool BleRcuAdapterBluez::isDeviceConnected(const BleAddress &address) const // ----------------------------------------------------------------------------- /*! - \fn void BleRcuManager::addDevice(const BleAddress &address) + \fn void BleRcuManager::addDevice(const BleAddress &address, int retries) Sends a request to the bluez daemon to pair the device with the given - \a address. The request is sent even if the device is already paired, + \a address and \a retries. The request is sent even if the device is already paired, this is to handle the case where a pending unpair notification is sitting in the dbus queue but not yet processed. @@ -1227,7 +1227,7 @@ bool BleRcuAdapterBluez::isDeviceConnected(const BleAddress &address) const \sa isDevicePaired(), removeDevice() */ -bool BleRcuAdapterBluez::addDevice(const BleAddress &address) +bool BleRcuAdapterBluez::addDevice(const BleAddress &address, int retries) { if (!m_stateMachine.inState(AdapterPoweredOnState)) { return false; @@ -1245,10 +1245,10 @@ bool BleRcuAdapterBluez::addDevice(const BleAddress &address) XLOGD_INFO("requesting bluez pair %s", device->address().toString().c_str()); - device->addPairingErrorSlot(Slot(m_isAlive, - std::bind(&BleRcuAdapterBluez::onDevicePairingError, this, address, std::placeholders::_1))); + device->addPairingErrorSlot(Slot(m_isAlive, + std::bind(&BleRcuAdapterBluez::onDevicePairingError, this, address, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3))); - device->pair(0); + device->pair(0, retries); return true; } @@ -1688,9 +1688,11 @@ void BleRcuAdapterBluez::onDeviceNameChanged(const BleAddress &address, */ void BleRcuAdapterBluez::onDevicePairingError(const BleAddress &address, - const std::string &error) + const std::string &error, + int retryCnt, + bool finalRetry) { - m_devicePairingErrorSlots.invoke(address, error); + m_devicePairingErrorSlots.invoke(address, error, retryCnt, finalRetry); } // ----------------------------------------------------------------------------- diff --git a/src/ble/hal/blercu/bluez/blercuadapter_p.h b/src/ble/hal/blercu/bluez/blercuadapter_p.h index aeb35f5c..33a2e48d 100644 --- a/src/ble/hal/blercu/bluez/blercuadapter_p.h +++ b/src/ble/hal/blercu/bluez/blercuadapter_p.h @@ -94,7 +94,7 @@ class BleRcuAdapterBluez : public BleRcuAdapter bool isDevicePaired(const BleAddress &address) const override; bool isDeviceConnected(const BleAddress &address) const override; - bool addDevice(const BleAddress &address) override; + bool addDevice(const BleAddress &address, int retries) override; bool removeDevice(const BleAddress &address) override; bool setConnectionParams(BleAddress address, double minInterval, double maxInterval, @@ -113,7 +113,7 @@ class BleRcuAdapterBluez : public BleRcuAdapter const std::vector &interfaces); void onDeviceNameChanged(const BleAddress &address, const std::string &name); - void onDevicePairingError(const BleAddress &address, const std::string &error); + void onDevicePairingError(const BleAddress &address, const std::string &error, int retryCnt, bool finalRetry); void onDevicePairedChanged(const BleAddress &address, bool paired); void onDeviceReadyChanged(const BleAddress &address, bool ready); diff --git a/src/ble/hal/blercu/bluez/blercudevice.cpp b/src/ble/hal/blercu/bluez/blercudevice.cpp index 08aa0287..575c8a5f 100644 --- a/src/ble/hal/blercu/bluez/blercudevice.cpp +++ b/src/ble/hal/blercu/bluez/blercudevice.cpp @@ -98,7 +98,7 @@ BleRcuDeviceBluez::BleRcuDeviceBluez(const BleAddress &bdaddr, , m_lastServicesResolvedState(false) , m_isPairing(false) , m_pairingRetryCnt(0) - , m_maxPairingRetries(3) + , m_maxPairingRetries(0) , m_timeSinceReady(0) , m_recoveryAttempts(0) , m_maxRecoveryAttempts(100) @@ -242,8 +242,9 @@ static gboolean getInitialDeviceProperties(gpointer user_data) request then the \a pairingError signal will be emitted. */ -void BleRcuDeviceBluez::pair(int timeout) +void BleRcuDeviceBluez::pair(int timeout, int retries) { + m_maxPairingRetries = retries; m_deviceProxy->Pair( PendingReply<>(m_isAlive, std::bind(&BleRcuDeviceBluez::onPairRequestReply, this, std::placeholders::_1))); @@ -269,10 +270,11 @@ void BleRcuDeviceBluez::onPairRequestReply(PendingReply<> *reply) if (m_pairingRetryCnt < m_maxPairingRetries) { m_pairingRetryCnt++; XLOGD_INFO("Retrying pairing, attempt %d out of %d ", m_pairingRetryCnt, m_maxPairingRetries); - pair(0); + m_pairingErrorSlots.invoke(reply->errorMessage(), m_pairingRetryCnt, false); + pair(0, m_maxPairingRetries); } else { + m_pairingErrorSlots.invoke(reply->errorMessage(), m_pairingRetryCnt, true); m_pairingRetryCnt = 0; - m_pairingErrorSlots.invoke(reply->errorMessage()); } } else { XLOGD_DEBUG("%s pairing request successful", m_address.toString().c_str()); diff --git a/src/ble/hal/blercu/bluez/blercudevice_p.h b/src/ble/hal/blercu/bluez/blercudevice_p.h index 39ecd86c..0700b227 100644 --- a/src/ble/hal/blercu/bluez/blercudevice_p.h +++ b/src/ble/hal/blercu/bluez/blercudevice_p.h @@ -92,7 +92,7 @@ class BleRcuDeviceBluez : public BleRcuDevice public: std::string bluezObjectPath() const; - void pair(int timeout); + void pair(int timeout, int retries); void cancelPairing(); void connect(); diff --git a/src/telemetry/ctrlm_telemetry_event.cpp b/src/telemetry/ctrlm_telemetry_event.cpp index 6ca82571..f6bda2d1 100644 --- a/src/telemetry/ctrlm_telemetry_event.cpp +++ b/src/telemetry/ctrlm_telemetry_event.cpp @@ -34,6 +34,14 @@ bool ctrlm_telemetry_event_t::event() const { template <> bool ctrlm_telemetry_event_t::event() const { - XLOGD_TELEMETRY("telemetry event <%s, %s>", this->marker.c_str(), this->value.c_str()); - return(t2_event_s((char *)this->marker.c_str(), (char *)this->value.c_str()) == T2ERROR_SUCCESS); + if (value.length() > CTRLM_TELEMETRY_MAX_EVENT_SIZE_BYTES) { + XLOGD_ERROR("telemetry event <%s> dropped: value length <%zu> exceeds maximum <%d> bytes", + this->marker.c_str(), + this->value.length(), + CTRLM_TELEMETRY_MAX_EVENT_SIZE_BYTES); + return false; + } else { + XLOGD_TELEMETRY("telemetry event <%s, %s>", this->marker.c_str(), this->value.c_str()); + return(t2_event_s((char *)this->marker.c_str(), (char *)this->value.c_str()) == T2ERROR_SUCCESS); + } } diff --git a/src/telemetry/ctrlm_telemetry_event.h b/src/telemetry/ctrlm_telemetry_event.h index 1628afb1..b83ca853 100644 --- a/src/telemetry/ctrlm_telemetry_event.h +++ b/src/telemetry/ctrlm_telemetry_event.h @@ -26,6 +26,8 @@ #include #endif +#define CTRLM_TELEMETRY_MAX_EVENT_SIZE_BYTES 4536 // Maximum size of event list in bytes (there are limitations in the T2 implementation that restrict the maximum size of an event string. This value should be within the limits of the T2 implementation) + template class ctrlm_telemetry_event_t { static_assert(std::is_same::value || std::is_same::value || std::is_same::value, "Invalid telemetry event type"); diff --git a/src/telemetry/ctrlm_telemetry_markers.h b/src/telemetry/ctrlm_telemetry_markers.h index cb07ec32..446bec55 100644 --- a/src/telemetry/ctrlm_telemetry_markers.h +++ b/src/telemetry/ctrlm_telemetry_markers.h @@ -131,4 +131,28 @@ // End Voice Markers // +// +// RCU Markers +// + +// BLE RCU Pairing Attempt Marker +// Value format: Array of comma separated integers or string with the fields below. +// [,,,,,,,,,] +// - version of the marker format. +// - type of network the marker is coming from +// - enum representing pairing method (see PairingMethod) +// - enum that represents "success" or failure reason (see FailureReason) +// - number of discovered devices from pairing attempt +// - name of paired remote, empty string on failure +// - number of bluez pair() retries made before success or final error +// - error message 1 from bluez layer or null if no error +// - error message 2 from bluez layer or null if no error +// - error message 3 from bluez layer or null if no error +#define MARKER_RCU_PAIRING_ATTEMPT "ctrlm.rcu.pairing.attempt_accum" +#define MARKER_RCU_PAIRING_ATTEMPT_VERSION 1 + +// +// End RCU Markers +// + #endif diff --git a/src/voice/telemetry/ctrlm_voice_telemetry_events.h b/src/voice/telemetry/ctrlm_voice_telemetry_events.h index 18fcab29..f6f10127 100644 --- a/src/voice/telemetry/ctrlm_voice_telemetry_events.h +++ b/src/voice/telemetry/ctrlm_voice_telemetry_events.h @@ -79,7 +79,7 @@ class ctrlm_voice_telemetry_session_t : public ctrlm_telemetry_event_t Date: Fri, 5 Jun 2026 10:51:24 -0400 Subject: [PATCH 61/81] RDKEMW-4433: local server build option (#57) --- CMakeLists.txt | 1 + src/CMakeLists.txt | 4 + .../bleservices/gatt/gatt_audioservice.cpp | 2 +- src/server/CMakeLists.txt | 54 ++ src/server/ctrlm_server_app.h | 49 ++ src/server/ctrlms_main.c | 135 ++++ src/server/ctrlms_version.c | 57 ++ src/server/ctrlms_version.h | 40 ++ src/server/ctrlms_ws.cpp | 586 ++++++++++++++++++ src/server/ctrlms_ws.h | 37 ++ src/voice/ctrlm_voice_obj.cpp | 14 +- src/voice/ipc/ctrlm_voice_ipc_iarm_legacy.cpp | 1 - 12 files changed, 973 insertions(+), 7 deletions(-) create mode 100644 src/server/CMakeLists.txt create mode 100644 src/server/ctrlm_server_app.h create mode 100644 src/server/ctrlms_main.c create mode 100644 src/server/ctrlms_version.c create mode 100644 src/server/ctrlms_version.h create mode 100644 src/server/ctrlms_ws.cpp create mode 100644 src/server/ctrlms_ws.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 112b3c00..b9cdf593 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,6 +39,7 @@ option(BLE_ENABLED "Enable BLE" ON) option(BLE_SERVICES "Enable BLE Services" OFF) option(BREAKPAD "Enable BREAKPAD" OFF) option(BUILD_CTRLM_FACTORY "Build Control Factory Test" OFF) +option(BUILD_CTRLM_SERVER "Build Control Server Daemon" OFF) option(FDC_ENABLED "Enable FDC" OFF) option(IP_ENABLED "Enable IP" OFF) option(RF4CE_ENABLED "Enable RF4CE" ON) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ab20447c..93f3f745 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -140,6 +140,10 @@ if(BUILD_FACTORY_TEST) add_subdirectory(factory) endif() +if(BUILD_CTRLM_SERVER) + add_subdirectory(server) +endif() + if(USE_IARM_POWER_MANAGER) target_sources(controlMgr PRIVATE ipc/ctrlm_ipc_iarm_powermanager.cpp diff --git a/src/ble/hal/blercu/bleservices/gatt/gatt_audioservice.cpp b/src/ble/hal/blercu/bleservices/gatt/gatt_audioservice.cpp index 4a3e3596..ec9819d1 100644 --- a/src/ble/hal/blercu/bleservices/gatt/gatt_audioservice.cpp +++ b/src/ble/hal/blercu/bleservices/gatt/gatt_audioservice.cpp @@ -620,7 +620,7 @@ void GattAudioService::stopStreaming(uint32_t audioDuration, PendingReply<> &&re } if(m_missedSequences >= frameCountMax) { - XLOGD_ERROR("missed frames greater than frame count max"); + XLOGD_ERROR("missed frames <%u> greater than frame count max <%u>", m_missedSequences, frameCountMax); } else { frameCountMax -= m_missedSequences; // compensate for missed frames diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt new file mode 100644 index 00000000..714a3fdd --- /dev/null +++ b/src/server/CMakeLists.txt @@ -0,0 +1,54 @@ +########################################################################## +# If not stated otherwise in this file or this component's LICENSE +# file the following copyright and licenses apply: +# +# Copyright 2019 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. +########################################################################## + +add_executable(controlServer ctrlms_main.c) + +include_directories( + . + ${CMAKE_SYSROOT}/usr/include/safeclib + ${CMAKE_SYSROOT}/usr/include/libsafec + ${CMAKE_SYSROOT}/usr/include/nopoll + ${CMAKE_SYSROOT}/usr/include +) + +target_sources(controlServer PRIVATE + ctrlms_version.c + ctrlms_ws.cpp +) + +target_compile_options(controlServer PUBLIC -fPIC -rdynamic -Wall -Werror) + +target_link_libraries(controlServer c rdkversion pthread nopoll jansson xr-voice-sdk secure_wrapper systemd ${CMAKE_DL_LIBS}) + +if(AUTH_ENABLED) + target_compile_definitions(controlServer PRIVATE CTRLMS_WSS_ENABLED) + target_link_libraries(controlServer ssl crypto RdkCertSelector rdkconfig secure_wrapper) +endif() + +if(USE_SAFEC) + find_package(PkgConfig) + pkg_check_modules(SAFEC REQUIRED libsafec) + if(SAFEC_FOUND) + target_link_libraries(controlServer ${SAFEC_LIBRARIES}) + endif() +else() + target_compile_definitions(controlServer PUBLIC SAFEC_DUMMY_API) +endif() + +install(TARGETS controlServer DESTINATION bin) diff --git a/src/server/ctrlm_server_app.h b/src/server/ctrlm_server_app.h new file mode 100644 index 00000000..98c308f7 --- /dev/null +++ b/src/server/ctrlm_server_app.h @@ -0,0 +1,49 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2014 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. +*/ +#pragma once + +#include +#include +#include + +class ctrlms_app_interface_t +{ + public: + virtual ~ctrlms_app_interface_t() {}; + + virtual void ws_connected(void); + virtual void ws_disconnected(void); + virtual bool ws_receive_audio(const unsigned char *payload, int payload_size); + virtual bool ws_receive_json(const json_t *json_obj); + void ws_send_json(const json_t *json_obj); + void ws_handle_set(void *handle); + + private: + void *ws_handle = NULL; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +ctrlms_app_interface_t *ctrlms_app_interface_create(void); + +#ifdef __cplusplus +} +#endif diff --git a/src/server/ctrlms_main.c b/src/server/ctrlms_main.c new file mode 100644 index 00000000..91cb89d6 --- /dev/null +++ b/src/server/ctrlms_main.c @@ -0,0 +1,135 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CTRLMS_VERSION "1.0" + +#define CTRLMS_WS_PORT_INT (9881) + +typedef struct { + bool silent; + bool verbose; +} ctrlms_options_t; + +static bool ctrlms_cmdline_args(int argc, char *argv[]); +static error_t ctrlms_parse_opt(int key, char *arg, struct argp_state *state); +static void ctrlms_signal_handler(int signum); + +const char *argp_program_version = "controlServer " CTRLMS_VERSION; +const char *argp_program_bug_address = ""; + +static char doc[] = "controlServer -- a server application"; + +static char args_doc[] = ""; + +static struct argp_option options[] = { + {"verbose", 'v', 0, 0, "Produce verbose output" }, + {"quiet", 'q', 0, 0, "Don't produce any output" }, + { 0 } +}; + +static struct argp argp = { options, ctrlms_parse_opt, args_doc, doc }; + +static ctrlms_options_t g_ctrlms_opts = { .silent = false, + .verbose = false + }; + +void ctrlms_signal_handler(int signum) { + if(signum == SIGTERM) { + ctrlms_ws_term(); + } +} + +int main(int argc, char* argv[]) { + int result = -1; + if(signal(SIGTERM, ctrlms_signal_handler) == SIG_ERR) { + XLOGD_ERROR("ctrlms_main: failed to set SIGTERM handler <%s>", strerror(errno)); + } + + // Parse command line arguments + if(!ctrlms_cmdline_args(argc, argv)) { + return(result); + } + + xlog_level_t level = XLOG_LEVEL_WARN; + if(g_ctrlms_opts.silent) { + level = XLOG_LEVEL_ERROR; + } else if(g_ctrlms_opts.verbose) { + level = XLOG_LEVEL_INFO; + // TODO Add option to allow debug level logging + //} else if() { + // level = XLOG_LEVEL_DEBUG; + } + + if(!ctrlms_init(level)) { + XLOGD_ERROR("ctrlms_main: init failed"); + } else { + // Start listening for connections + if(!ctrlms_ws_init(CTRLMS_WS_PORT_INT, true)) { + XLOGD_ERROR("ctrlms_main: ws init failed"); + } else { + result = 0; + XLOGD_INFO("Notifying systemd of successful initialization"); + sd_notifyf(0, "READY=1\nSTATUS=ctrlm-server has successfully initialized\nMAINPID=%lu", (unsigned long)getpid()); + ctrlms_ws_listen(); + } + XLOGD_INFO("ctrlms_main: main loop ended"); + } + ctrlms_term(); + XLOGD_INFO("ctrlms_main: return"); + + return(result); +} + +error_t ctrlms_parse_opt(int key, char *arg, struct argp_state *state) { + // Get the input argument from argp_parse, which we know is a pointer to our arguments structure. + ctrlms_options_t *arguments = state->input; + + switch(key) { + case 'q': { + arguments->silent = true; + break; + } + case 'v': { + arguments->verbose = true; + break; + } + case ARGP_KEY_ARG: { + argp_usage(state); + return(ARGP_ERR_UNKNOWN); + } + case ARGP_KEY_END: { + break; + } + default: { + return(ARGP_ERR_UNKNOWN); + } + } + + return(0); +} + +bool ctrlms_cmdline_args(int argc, char *argv[]) { + argp_parse(&argp, argc, argv, 0, 0, &g_ctrlms_opts); + + #if 0 + if() { // Nothing to do + printf("Invalid options specified. Try 'controlServer --help' or 'controlServer --usage' for more information.\n"); + return(false); + } + #endif + + XLOGD_INFO("verbose <%s>", g_ctrlms_opts.verbose ? "YES" : "NO"); + XLOGD_INFO("silent <%s>", g_ctrlms_opts.silent ? "YES" : "NO"); + + return(true); +} diff --git a/src/server/ctrlms_version.c b/src/server/ctrlms_version.c new file mode 100644 index 00000000..8077e816 --- /dev/null +++ b/src/server/ctrlms_version.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + bool initialized; + bool is_production; +} ctrlms_global_t; + +ctrlms_global_t g_ctrlms = { + .initialized = false, + .is_production = true +}; + +bool ctrlms_init(xlog_level_t level) { + rdk_version_info_t info; + int ret_val = rdk_version_parse_version(&info); + + if(ret_val != 0) { + XLOGD_ERROR("parse error <%s>\n", info.parse_error == NULL ? "" : info.parse_error); + rdk_version_object_free(&info); + return(false); + } + + g_ctrlms.is_production = info.production_build; + + rdk_version_object_free(&info); + + int rc = xlog_init(XLOG_MODULE_ID, NULL, 0, true, false); + xlog_level_set_all(level); + + if(rc != 0) { + XLOGD_ERROR("failed to init xlog"); + return(false); + } + + g_ctrlms.initialized = true; + return(true); +} + +void ctrlms_term(void) { + g_ctrlms.initialized = false; + xlog_term(); +} + +bool ctrlms_is_initialized(void) { + return(g_ctrlms.initialized); +} + +bool ctrlms_is_production(void) { + return(g_ctrlms.is_production); +} + diff --git a/src/server/ctrlms_version.h b/src/server/ctrlms_version.h new file mode 100644 index 00000000..cede9db4 --- /dev/null +++ b/src/server/ctrlms_version.h @@ -0,0 +1,40 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2014 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. +*/ +#ifndef _CTRLMS_VERSION_H_ +#define _CTRLMS_VERSION_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +bool ctrlms_init(xlog_level_t level); +void ctrlms_term(void); + +bool ctrlms_is_initialized(void); +bool ctrlms_is_production(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/server/ctrlms_ws.cpp b/src/server/ctrlms_ws.cpp new file mode 100644 index 00000000..28b179fd --- /dev/null +++ b/src/server/ctrlms_ws.cpp @@ -0,0 +1,586 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CTRLMS_WSS_ENABLED +#include "rdkcertselector.h" +#include +#include +#define CTRLMS_WS_TLS_CERT_KEY_FILE "/tmp/serverXXXXXX" +#define CTRLMS_WS_CERT_FILENAME_PREFIX "file://" +#endif + +typedef struct { + volatile sig_atomic_t term_requested; + noPollCtx * nopoll_ctx; + noPollConnOpts * opts; + char tmp_cert[32]; + bool tmp_cert_created; + bool cert_valid; + noPollConn * nopoll_conn; + void * app_handle; + ctrlms_app_interface_t *app_interface; +} ctrlms_ws_global_t; + +static bool ctrlms_ws_load_app(ctrlms_ws_global_t *state, bool use_stub, void **handle); + +static nopoll_bool ctrlms_ws_on_accept(noPollCtx *ctx, noPollConn *conn, noPollPtr user_data); +static nopoll_bool ctrlms_ws_on_ready(noPollCtx *ctx, noPollConn *conn, noPollPtr user_data); +static void ctrlms_ws_on_message(noPollCtx *ctx, noPollConn *conn, noPollMsg *msg, noPollPtr user_data); +static void ctrlms_ws_on_ping(noPollCtx *ctx, noPollConn *conn, noPollMsg *msg, noPollPtr user_data); +static void ctrlms_ws_on_close(noPollCtx *ctx, noPollConn *conn, noPollPtr user_data); +static void ctrlms_ws_nopoll_log(noPollCtx * ctx, noPollDebugLevel level, const char * log_msg, noPollPtr user_data); +#ifdef CTRLMS_WSS_ENABLED +static bool ctrlms_ws_cert_config(FILE *cert_key_fp); +static bool ctrlms_ws_add_chain(FILE *cert_key_fp, STACK_OF(X509) *additional_certs); +#endif + +ctrlms_ws_global_t g_ctrlms_ws; + +bool ctrlms_ws_init(uint16_t port, bool log_enable) { + errno_t safec_rc = -1; + + g_ctrlms_ws.term_requested = 0; + g_ctrlms_ws.nopoll_ctx = NULL; + g_ctrlms_ws.opts = NULL; + g_ctrlms_ws.cert_valid = false; + g_ctrlms_ws.tmp_cert_created = false; + memset(g_ctrlms_ws.tmp_cert, 0, sizeof(g_ctrlms_ws.tmp_cert)); + g_ctrlms_ws.app_interface = NULL; + g_ctrlms_ws.app_handle = NULL; + g_ctrlms_ws.nopoll_conn = NULL; + + bool result = false; + do { + if(!ctrlms_ws_load_app(&g_ctrlms_ws, false, &g_ctrlms_ws.app_handle)) { + XLOGD_INFO("exiting due to app load failure"); + break; + } + + g_ctrlms_ws.nopoll_ctx = nopoll_ctx_new(); + if(g_ctrlms_ws.nopoll_ctx == NULL) { + XLOGD_ERROR("nopoll context create"); + break; + } + + #ifdef CTRLMS_WSS_ENABLED + do { + int cert_key_fd = -1; + FILE *cert_key_fp = NULL; + int errsv; + + safec_rc = sprintf_s(g_ctrlms_ws.tmp_cert, sizeof(g_ctrlms_ws.tmp_cert), "%s", CTRLMS_WS_TLS_CERT_KEY_FILE); + if(safec_rc < EOK) { + ERR_CHK(safec_rc); + } + + cert_key_fd = mkstemp(g_ctrlms_ws.tmp_cert); + if(cert_key_fd == -1) { + errsv = errno; + XLOGD_ERROR("mkstemp failed: <%s>", strerror(errsv)); + break; + } + g_ctrlms_ws.tmp_cert_created = true; + + cert_key_fp = fdopen(cert_key_fd, "w"); + if(cert_key_fp == NULL) { + errsv = errno; + XLOGD_ERROR("fdopen failed: <%s>", strerror(errsv)); + if(0 != close(cert_key_fd)) { + errsv = errno; + XLOGD_ERROR("failed to close cert/key file descriptor <%s>", strerror(errsv)); + } + break; + } + + if(!ctrlms_ws_cert_config(cert_key_fp)) { + XLOGD_ERROR("failed to set cert or key"); + fclose(cert_key_fp); + break; + } + fclose(cert_key_fp); + + // Init OpenSSL + SSL_library_init(); + SSL_load_error_strings(); + OpenSSL_add_all_algorithms(); + g_ctrlms_ws.cert_valid = true; + } while(0); + + if(!g_ctrlms_ws.cert_valid) { + XLOGD_ERROR("no valid cert/key available"); + break; + } + #endif + + if(log_enable) { + nopoll_log_enable(g_ctrlms_ws.nopoll_ctx, nopoll_true); + nopoll_log_set_handler(g_ctrlms_ws.nopoll_ctx, ctrlms_ws_nopoll_log, NULL); + } + g_ctrlms_ws.opts = nopoll_conn_opts_new(); + if(g_ctrlms_ws.opts == NULL) { + XLOGD_ERROR("nopoll connection options create"); + nopoll_ctx_unref(g_ctrlms_ws.nopoll_ctx); + g_ctrlms_ws.nopoll_ctx = NULL; + break; + } + + nopoll_ctx_set_on_accept(g_ctrlms_ws.nopoll_ctx, ctrlms_ws_on_accept, &g_ctrlms_ws); + nopoll_ctx_set_on_ready(g_ctrlms_ws.nopoll_ctx, ctrlms_ws_on_ready, &g_ctrlms_ws); + nopoll_ctx_set_on_msg(g_ctrlms_ws.nopoll_ctx, ctrlms_ws_on_message, &g_ctrlms_ws); + + if(g_ctrlms_ws.cert_valid) { + nopoll_conn_opts_set_ssl_protocol(g_ctrlms_ws.opts, NOPOLL_METHOD_TLSV1_2); + nopoll_conn_opts_ssl_host_verify(g_ctrlms_ws.opts, nopoll_false); //localhost will not match host specified in certificate + + if(!nopoll_conn_opts_set_ssl_certs(g_ctrlms_ws.opts, g_ctrlms_ws.tmp_cert, g_ctrlms_ws.tmp_cert, NULL, NULL)) { + XLOGD_ERROR("Failed to add cert/key files to nopoll_conn"); + nopoll_ctx_unref(g_ctrlms_ws.nopoll_ctx); + g_ctrlms_ws.nopoll_ctx = NULL; + nopoll_conn_opts_free(g_ctrlms_ws.opts); + g_ctrlms_ws.opts = NULL; + break; + } + } + + char port_str[6]; + safec_rc = sprintf_s(port_str, sizeof(port_str), "%u", port); + if(safec_rc < EOK) { + ERR_CHK(safec_rc); + } + + // Start loopback-only IPv6 listener + if(g_ctrlms_ws.cert_valid) { + g_ctrlms_ws.nopoll_conn = nopoll_listener_tls_new_opts6(g_ctrlms_ws.nopoll_ctx, g_ctrlms_ws.opts, "::1", port_str); + } else { + g_ctrlms_ws.nopoll_conn = nopoll_listener_new_opts6(g_ctrlms_ws.nopoll_ctx, g_ctrlms_ws.opts, "::1", port_str); + } + if(!nopoll_conn_is_ok(g_ctrlms_ws.nopoll_conn)) { + XLOGD_ERROR("Listener connection IPv6 NOT ok"); + nopoll_ctx_unref(g_ctrlms_ws.nopoll_ctx); + g_ctrlms_ws.nopoll_ctx = NULL; + nopoll_conn_opts_free(g_ctrlms_ws.opts); + g_ctrlms_ws.opts = NULL; + break; + } + + result = true; + } while(0); + + if(!result) { + if(g_ctrlms_ws.tmp_cert_created) { + if(0 != unlink(g_ctrlms_ws.tmp_cert)) { + int errsv = errno; + XLOGD_ERROR("failed to remove temp cert <%s>", strerror(errsv)); + } + } + if(g_ctrlms_ws.app_interface != NULL) { + delete g_ctrlms_ws.app_interface; + g_ctrlms_ws.app_interface = NULL; + } + if(g_ctrlms_ws.app_handle != NULL) { + dlclose(g_ctrlms_ws.app_handle); + g_ctrlms_ws.app_handle = NULL; + } + } + + return(result); +} + +bool ctrlms_ws_listen(void) { + XLOGD_INFO("Enter main loop"); + // Poll with a 100 ms timeout so the loop can observe term_requested, which + // is set exclusively by ctrlms_ws_term() — an async-signal-safe operation. + while(!g_ctrlms_ws.term_requested) { + nopoll_loop_wait(g_ctrlms_ws.nopoll_ctx, 100000); + } + + nopoll_conn_opts_unref(g_ctrlms_ws.opts); + nopoll_conn_unref(g_ctrlms_ws.nopoll_conn); + nopoll_ctx_unref(g_ctrlms_ws.nopoll_ctx); + g_ctrlms_ws.nopoll_ctx = NULL; + + if(g_ctrlms_ws.cert_valid) { + if(0 != unlink(g_ctrlms_ws.tmp_cert)) { + int err_store = errno; + XLOGD_ERROR("failed to remove temp cert <%s>", strerror(err_store)); + } + } + + if(g_ctrlms_ws.app_interface != NULL) { + delete g_ctrlms_ws.app_interface; + g_ctrlms_ws.app_interface = NULL; + } + if(g_ctrlms_ws.app_handle != NULL) { + dlclose(g_ctrlms_ws.app_handle); + g_ctrlms_ws.app_handle = NULL; + } + return(true); +} + +void ctrlms_ws_term(void) { + g_ctrlms_ws.term_requested = 1; +} + +static nopoll_bool ctrlms_ws_on_accept(noPollCtx *ctx, noPollConn *conn, noPollPtr user_data) { + ctrlms_ws_global_t *state = (ctrlms_ws_global_t *)user_data; + + if(state == NULL) { + XLOGD_ERROR("invalid params"); + return(nopoll_false); + } + + // Set ping handler + nopoll_conn_set_on_ping_msg(conn, ctrlms_ws_on_ping, user_data); + + return(nopoll_true); +} + +static nopoll_bool ctrlms_ws_on_ready(noPollCtx *ctx, noPollConn *conn, noPollPtr user_data) { + ctrlms_ws_global_t *state = (ctrlms_ws_global_t *)user_data; + + if(state == NULL) { + XLOGD_ERROR("invalid params"); + return(nopoll_false); + } + + XLOGD_INFO("Connection established"); + state->app_interface->ws_handle_set((void *)conn); + state->app_interface->ws_connected(); + + nopoll_conn_set_on_close(conn, ctrlms_ws_on_close, user_data); + + return(nopoll_true); +} + +static void ctrlms_ws_on_message(noPollCtx *ctx, noPollConn *conn, noPollMsg *msg, noPollPtr user_data) { + ctrlms_ws_global_t *state = (ctrlms_ws_global_t *)user_data; + + if(state == NULL) { + XLOGD_ERROR("invalid params"); + return; + } + + bool close_conn = false; + int payload_size = nopoll_msg_get_payload_size(msg); + const unsigned char *payload = nopoll_msg_get_payload(msg); + + switch(nopoll_msg_opcode(msg)) { + case NOPOLL_TEXT_FRAME: { + XLOGD_DEBUG("NOPOLL_TEXT_FRAME size <%d>", payload_size); + + json_t *json_obj = json_loadb((const char *)payload, payload_size, 0, NULL); + + if(json_obj == NULL) { + XLOGD_ERROR("Failed to parse JSON object"); + break; + } else { + // Pass the incoming payload to the application as a borrowed reference. + // The json_obj pointer is only valid for the duration of this call and + // must not be stored by the callee unless it takes its own reference. + close_conn = state->app_interface->ws_receive_json(json_obj); + json_decref(json_obj); + } + break; + } + case NOPOLL_BINARY_FRAME: { + XLOGD_DEBUG("NOPOLL_BINARY_FRAME size <%d>", payload_size); + + // Pass the incoming payload to the application + close_conn = state->app_interface->ws_receive_audio(payload, payload_size); + break; + } + case NOPOLL_CONTINUATION_FRAME: { + XLOGD_INFO("NOPOLL_CONTINUATION_FRAME"); + break; + } + default: { + XLOGD_INFO("NOPOLL_UNKNOWN"); + break; + } + } + + if(close_conn) { + const char *reason = "app closed"; + nopoll_conn_close_ext(conn, 1000, reason, strlen(reason)); + } +} + +static void ctrlms_ws_on_ping(noPollCtx *ctx, noPollConn *conn, noPollMsg *msg, noPollPtr user_data) { + ctrlms_ws_global_t *state = (ctrlms_ws_global_t *)user_data; + if(state == NULL) { + XLOGD_ERROR("invalid params"); + return; + } + + XLOGD_INFO("Ping received"); + // Do nothing, we don't care about this event +} + +static void ctrlms_ws_on_close(noPollCtx *ctx, noPollConn *conn, noPollPtr user_data) { + ctrlms_ws_global_t *state = (ctrlms_ws_global_t *)user_data; + + if(state == NULL) { + XLOGD_ERROR("invalid params"); + return; + } + XLOGD_INFO(""); + + state->app_interface->ws_disconnected(); + state->app_interface->ws_handle_set(NULL); +} + +#ifdef CTRLMS_WSS_ENABLED +static bool ctrlms_ws_cert_config(FILE* cert_key_fp) { + bool ret = false; + + rdkcertselector_h cert_selector = NULL; + PKCS12 *p12_cert = NULL; + EVP_PKEY *pkey = NULL; + X509 *x509_cert = NULL; + STACK_OF(X509) *additional_certs = NULL; + do { + FILE *device_cert_fp = NULL; + + char *cert_path = NULL; + char *cert_password = NULL; + cert_selector = rdkcertselector_new(NULL, NULL, "FBK_MTLS"); + + if(cert_selector == NULL){ + XLOGD_TELEMETRY("cert selector init failed"); + break; + } + + rdkcertselectorStatus_t cert_status = rdkcertselector_getCert(cert_selector, &cert_path, &cert_password); + + if(cert_status != certselectorOk) { + XLOGD_TELEMETRY("cert selector retrieval failed"); + break; + } + + if(cert_path == NULL || cert_password == NULL) { + XLOGD_TELEMETRY("cert selector get failed"); + break; + } + + char *local_path = cert_path; + if(strncmp(local_path, CTRLMS_WS_CERT_FILENAME_PREFIX, strlen(CTRLMS_WS_CERT_FILENAME_PREFIX)) == 0) { + local_path += strlen(CTRLMS_WS_CERT_FILENAME_PREFIX); + } + + device_cert_fp = fopen(local_path, "rb"); + if(device_cert_fp == NULL) { + XLOGD_ERROR("unable to open P12 certificate"); + break; + } + + d2i_PKCS12_fp(device_cert_fp, &p12_cert); + fclose(device_cert_fp); + device_cert_fp = NULL; + + if(p12_cert == NULL) { + XLOGD_ERROR("unable to read P12 certificate"); + break; + } + + if(1 != PKCS12_parse(p12_cert, cert_password, &pkey, &x509_cert, &additional_certs)) { + XLOGD_ERROR("unable to parse P12 certificate"); + break; + } + + if(1 != PEM_write_X509(cert_key_fp, x509_cert)) { + XLOGD_ERROR("failed to write temp cert"); + break; + } + + if(!ctrlms_ws_add_chain(cert_key_fp, additional_certs)) { + XLOGD_ERROR("failed to add chain certs"); + break; + } + + if(1 != PEM_write_PrivateKey(cert_key_fp, pkey, NULL, (unsigned char*)cert_password, strlen(cert_password), NULL, NULL)) { + XLOGD_ERROR("failed to write temp key"); + break; + } + + ret = true; + }while(0); + + if(cert_selector != NULL) { + rdkcertselector_free(&cert_selector); + } + + if(p12_cert != NULL) { + PKCS12_free(p12_cert); + } + + if(pkey != NULL) { + EVP_PKEY_free(pkey); + } + + if(x509_cert != NULL) { + X509_free(x509_cert); + } + + if(additional_certs != NULL) { + sk_X509_pop_free(additional_certs, X509_free); + } + + return ret; +} + +static bool ctrlms_ws_add_chain(FILE *cert_key_fp, STACK_OF(X509) *additional_certs) { + if(cert_key_fp == NULL) { + XLOGD_ERROR("null file pointer"); + return false; + } + if(additional_certs == NULL) { + XLOGD_WARN("no additional certs"); + return true; + } + + for(int32_t index = 0; index < sk_X509_num(additional_certs); index++) { + X509 *cert = sk_X509_value(additional_certs, index); + if(1 != PEM_write_X509(cert_key_fp, cert)) { + XLOGD_ERROR("failed to write temp cert index %d", index); + return false; + } + } + + return true; +} +#endif + +static void ctrlms_ws_nopoll_log(noPollCtx * ctx, noPollDebugLevel level, const char * log_msg, noPollPtr user_data) { + xlog_args_t args; + args.options = XLOG_OPTS_DEFAULT; + args.color = XLOG_COLOR_NONE; + args.function = XLOG_FUNCTION_NONE; + args.line = XLOG_LINE_NONE; + args.id = XLOG_MODULE_ID; + args.size_max = XLOG_BUF_SIZE_DEFAULT; + switch(level) { + case NOPOLL_LEVEL_DEBUG: { args.level = XLOG_LEVEL_DEBUG; break; } + case NOPOLL_LEVEL_INFO: { args.level = XLOG_LEVEL_INFO; break; } + case NOPOLL_LEVEL_WARNING: { args.level = XLOG_LEVEL_WARN; break; } + case NOPOLL_LEVEL_CRITICAL: { args.level = XLOG_LEVEL_ERROR; break; } + default: { args.level = XLOG_LEVEL_INFO; break; } + } + int errsv = errno; + xlog_printf(&args, "%s", log_msg); + errno = errsv; +} + +typedef ctrlms_app_interface_t *(*ctrlms_app_interface_create_t)(void); + +static bool ctrlms_ws_load_app(ctrlms_ws_global_t *state, bool use_stub, void **handle) { + if(handle == NULL) { + XLOGD_ERROR("invalid params"); + return(false); + } + *handle = dlopen("libctrlm-server-app.so", RTLD_NOW); + if(NULL == *handle) { + XLOGD_WARN("failed to load server app plugin <%s>", dlerror()); + + if(use_stub) { + XLOGD_INFO("Using stub implementation of app interface"); + state->app_interface = new ctrlms_app_interface_t(); + return(true); + } + return(false); + } + + dlerror(); // Clear any existing error + ctrlms_app_interface_create_t app_interface = (ctrlms_app_interface_create_t)dlsym(*handle, "ctrlms_app_interface_create"); + char *error = dlerror(); + + if(error != NULL) { + XLOGD_ERROR("failed to find plugin interface, error <%s>", error); + dlclose(*handle); + *handle = NULL; + + if(use_stub) { + XLOGD_INFO("Using stub implementation of app interface"); + state->app_interface = new ctrlms_app_interface_t(); + return(true); + } + return(false); + } + + XLOGD_INFO("successfully loaded plugin interface"); + state->app_interface = (*app_interface)(); + + if(NULL == state->app_interface) { + XLOGD_ERROR("failed to create plugin app interface"); + dlclose(*handle); + *handle = NULL; + if(use_stub) { + XLOGD_INFO("Using stub implementation of app interface"); + state->app_interface = new ctrlms_app_interface_t(); + return(true); + } + return(false); + } + + return(true); +} + +void ctrlms_app_interface_t::ws_connected(void) { + XLOGD_INFO("STUB: implement ws_connected"); +} + +void ctrlms_app_interface_t::ws_disconnected(void) { + XLOGD_INFO("STUB: implement ws_disconnected"); +} + +// Return true to request that the WebSocket connection be closed. +// Return false to keep the connection open after handling/ignoring the frame. +bool ctrlms_app_interface_t::ws_receive_audio(const unsigned char *payload, int payload_size) { + XLOGD_INFO("STUB: audio received size <%d>", payload_size); + return(false); +}; +bool ctrlms_app_interface_t::ws_receive_json(const json_t *json_obj) { + XLOGD_INFO("STUB: json object received"); + return(false); +} + +void ctrlms_app_interface_t::ws_send_json(const json_t *json_obj) { + if(json_obj == NULL) { + XLOGD_ERROR("json object is NULL"); + return; + } + if(ws_handle == NULL) { + XLOGD_ERROR("ws connection is not established"); + return; + } + char *payload = json_dumps(json_obj, JSON_COMPACT | JSON_ENSURE_ASCII); + if(payload == NULL) { + XLOGD_ERROR("failed to dump JSON object"); + return; + } + + XLOGD_INFO("Sending <%s>", payload); + int rc = nopoll_conn_send_text((noPollConn *)ws_handle, payload, strlen(payload)); + if(rc <= 0) { + XLOGD_ERROR("failed to send message"); + } + free(payload); +} + +void ctrlms_app_interface_t::ws_handle_set(void *handle) { + ws_handle = handle; +} diff --git a/src/server/ctrlms_ws.h b/src/server/ctrlms_ws.h new file mode 100644 index 00000000..68a16a45 --- /dev/null +++ b/src/server/ctrlms_ws.h @@ -0,0 +1,37 @@ +/* + * If not stated otherwise in this file or this component's license file the + * following copyright and licenses apply: + * + * Copyright 2014 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. +*/ +#ifndef _CTRLMS_WS_H_ +#define _CTRLMS_WS_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +bool ctrlms_ws_init(uint16_t port, bool log_enable); +bool ctrlms_ws_listen(void); +void ctrlms_ws_term(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/voice/ctrlm_voice_obj.cpp b/src/voice/ctrlm_voice_obj.cpp index 12402a12..7ddf515f 100644 --- a/src/voice/ctrlm_voice_obj.cpp +++ b/src/voice/ctrlm_voice_obj.cpp @@ -1391,7 +1391,9 @@ ctrlm_voice_session_response_status_t ctrlm_voice_t::voice_session_req(ctrlm_net xrsr_session_request_t request_params; request_params.type = XRSR_SESSION_REQUEST_TYPE_INVALID; - + + uint8_t dst_index = 0; + if(is_session_by_text) { XLOGD_INFO("Requesting the speech router start a text-only session with transcription = <%s>", l_transcription_in); if(session->state_src == CTRLM_VOICE_STATE_SRC_STREAMING || session->state_dst != CTRLM_VOICE_STATE_DST_READY) { @@ -1402,7 +1404,9 @@ ctrlm_voice_session_response_status_t ctrlm_voice_t::voice_session_req(ctrlm_net request_params.value.text.text = l_transcription_in; xrsr_audio_format_t xrsr_format = { .type = XRSR_AUDIO_FORMAT_NONE}; - if (false == xrsr_session_request(voice_device_to_xrsr(device_type), xrsr_format, request_params, uuid, false, false)) { + + + if (false == xrsr_session_request(voice_device_to_xrsr(device_type), dst_index, xrsr_format, request_params, uuid, false, false)) { XLOGD_ERROR("Failed to acquire the text-only session from the speech router."); return VOICE_SESSION_RESPONSE_BUSY; } @@ -1422,7 +1426,7 @@ ctrlm_voice_session_response_status_t ctrlm_voice_t::voice_session_req(ctrlm_net xrsr_format.type = XRSR_AUDIO_FORMAT_PCM; } - if (false == xrsr_session_request(voice_device_to_xrsr(device_type), xrsr_format, request_params, uuid, false, false)) { + if (false == xrsr_session_request(voice_device_to_xrsr(device_type), dst_index, xrsr_format, request_params, uuid, false, false)) { XLOGD_ERROR("Failed to acquire the audio file session from the speech router."); return VOICE_SESSION_RESPONSE_BUSY; } @@ -1439,7 +1443,7 @@ ctrlm_voice_session_response_status_t ctrlm_voice_t::voice_session_req(ctrlm_net request_params.type = XRSR_SESSION_REQUEST_TYPE_AUDIO_MIC; request_params.value.audio_mic.stream_params_required = this->nsm_voice_session; - if(false == xrsr_session_request(voice_device_to_xrsr(device_type), xrsr_format, request_params, uuid, low_latency, low_cpu_util)) { + if(false == xrsr_session_request(voice_device_to_xrsr(device_type), dst_index, xrsr_format, request_params, uuid, low_latency, low_cpu_util)) { XLOGD_ERROR("Failed to acquire the microphone session from the speech router."); return VOICE_SESSION_RESPONSE_BUSY; } @@ -1468,7 +1472,7 @@ ctrlm_voice_session_response_status_t ctrlm_voice_t::voice_session_req(ctrlm_net request_params.value.audio_fd.callback = (create_pipe) ? NULL : ctrlm_voice_data_post_processing_cb; // RF4CE does not use pipe read callback request_params.value.audio_fd.user_data = (create_pipe) ? NULL : (void *)this; - if(false == xrsr_session_request(voice_device_to_xrsr(device_type), voice_format_to_xrsr(format), request_params, uuid, false, false)) { + if(false == xrsr_session_request(voice_device_to_xrsr(device_type), dst_index, voice_format_to_xrsr(format), request_params, uuid, false, false)) { XLOGD_TELEMETRY("Failed to acquire voice session"); this->voice_session_notify_abort(network_id, controller_id, 0, CTRLM_VOICE_SESSION_ABORT_REASON_BUSY); if(create_pipe) { diff --git a/src/voice/ipc/ctrlm_voice_ipc_iarm_legacy.cpp b/src/voice/ipc/ctrlm_voice_ipc_iarm_legacy.cpp index bdcc85d8..25b2c8d6 100644 --- a/src/voice/ipc/ctrlm_voice_ipc_iarm_legacy.cpp +++ b/src/voice/ipc/ctrlm_voice_ipc_iarm_legacy.cpp @@ -178,7 +178,6 @@ bool ctrlm_voice_ipc_iarm_legacy_t::session_end(const ctrlm_voice_ipc_event_sess } bool ctrlm_voice_ipc_iarm_legacy_t::server_message(const char *message, unsigned long size) { - XLOGD_INFO("Not supported"); return(true); } From 3fa9bf79d45327633e90ccbe018f25226788e339 Mon Sep 17 00:00:00 2001 From: Gene Gallagher <129112619+egalla204@users.noreply.github.com> Date: Mon, 8 Jun 2026 13:10:43 -0400 Subject: [PATCH 62/81] RDKEMW-13988: add new buttons for interim remote 2.0 support (#234) --- src/ctrlm_utils.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/ctrlm_utils.cpp b/src/ctrlm_utils.cpp index b77595ac..eb8c7b7e 100644 --- a/src/ctrlm_utils.cpp +++ b/src/ctrlm_utils.cpp @@ -1324,10 +1324,10 @@ static const map> ctrlm_linux_key_name {KEY_BATTERY, {"Battery Low", "Battery Low"}}, {KEY_F16, {"Plus", "Plus"}}, {KEY_F13, {"Option", "Option"}}, - {KEY_F4, {"Netflix App", "Netflix App"}}, // APP key for PLATCO - {KEY_INSERT, {"Peacock App", "Peakcock App"}}, // APP key for PLATCO - {KEY_END, {"Disney+ App", "Disney+ App"}}, // APP key for PLATCO - {KEY_DELETE, {"Prime Video App", "Prime Video App"}}, // APP key for PLATCO + {KEY_F4, {"Netflix App", "Netflix App"}}, + {KEY_INSERT, {"Peacock App", "Peacock App"}}, + {KEY_END, {"Disney+ App", "Disney+ App"}}, + {KEY_DELETE, {"Prime Video App", "Prime Video App"}}, {KEY_PAGEUP, {"Channel+", "Channel+"}}, {KEY_PAGEDOWN, {"Channel-", "Channel-"}}, {KEY_SCROLLUP, {"Page+", "Page+"}}, @@ -1342,9 +1342,9 @@ static const map> ctrlm_linux_key_name {KEY_F6, {"Provider", "Provider"}}, {KEY_KPDOT, {"App A", "App A"}}, // A key for RF4CE remotes (also asterisk key) {KEY_F14, {"Quick Access", "Quick Access"}}, // B key for RF4CE remotes (C and D are not defined yet) - {KEY_KPRIGHTPAREN, {"App 1", "App 1"}}, // APP key for LLAMA - {KEY_KPLEFTPAREN, {"App 2", "App 2"}}, // APP key for LLAMA - {KEY_KPCOMMA, {"App 3", "App 3"}}, // APP key for LLAMA + {KEY_KPRIGHTPAREN, {"App 1", "App 1"}}, + {KEY_KPLEFTPAREN, {"App 2", "App 2"}}, + {KEY_KPCOMMA, {"App 3", "App 3"}}, {KEY_CONNECT, {"US BLE Pairing", "US BLE Pairing"}}, {KEY_BLUETOOTH, {"EU BLE Pairing", "EU BLE Pairing"}}, {KEY_VOLUMEDOWN, {"Vol Down", "Vol Down"}}, @@ -1361,7 +1361,11 @@ static const map> ctrlm_linux_key_name {KEY_PLAYPAUSE, {"Play/Pause", "Play/Pause"}}, {KEY_CONFIG, {"Config", "Config"}}, {KEY_POWER, {"Power", "Power"}}, - {KEY_MUTE, {"Mute", "Mute"}} + {KEY_MUTE, {"Mute", "Mute"}}, + {KEY_EQUAL, {"Sports", "Sports"}}, + {KEY_RIGHTBRACE, {"Playlist/Library", "Playlist/Library"}}, + {KEY_LEFTBRACE, {"Live TV", "Live TV"}}, + {KEY_MINUS, {"Best Of", "Best Of"}} }; From e8a2e89140cf7b044a6934f27ad15bd13a1e11e6 Mon Sep 17 00:00:00 2001 From: Gene Gallagher <129112619+egalla204@users.noreply.github.com> Date: Mon, 8 Jun 2026 14:44:34 -0400 Subject: [PATCH 63/81] RDKEMW-18979: onStatus event to contain RCU data from all networks (#238) --- src/ctrlm.h | 3 + src/ctrlm_main.cpp | 34 ++++ src/ipc/ctrlm_rcp_ipc_event.cpp | 6 +- src/ipc/ctrlm_rcp_ipc_event.h | 6 +- src/ipc/ctrlm_rcp_ipc_iarm_thunder.cpp | 247 +++++++++++++++---------- src/ipc/ctrlm_rcp_ipc_iarm_thunder.h | 7 + 6 files changed, 196 insertions(+), 107 deletions(-) diff --git a/src/ctrlm.h b/src/ctrlm.h index 376608b3..b5c73f0a 100644 --- a/src/ctrlm.h +++ b/src/ctrlm.h @@ -26,6 +26,7 @@ #include #include #include +#include #include "ctrlm_hal.h" #include "ctrlm_hal_rf4ce.h" #include "ctrlm_hal_ble.h" @@ -53,6 +54,7 @@ class ctrlm_voice_endpoint_t; class ctrlm_irdb_interface_t; class ctrlm_auth_t; class ctrlm_telemetry_t; +class ctrlm_rcp_ipc_net_status_t; typedef enum { CTRLM_THREAD_MONITOR_RESPONSE_DEAD = 0, CTRLM_THREAD_MONITOR_RESPONSE_ALIVE = 1 @@ -508,6 +510,7 @@ void ctrlm_update_last_key_info(int controller_id, ctrlm_key_source_t sou ctrlm_irdb_interface_t* ctrlm_main_irdb_get(); ctrlm_auth_t* ctrlm_main_auth_get(); void ctrlm_main_auth_start_poll(); +std::shared_ptr ctrlm_main_all_network_rcu_status_get(); std::string ctrlm_device_id_get(); std::string ctrlm_stb_name_get(); std::string ctrlm_device_mac_get(); diff --git a/src/ctrlm_main.cpp b/src/ctrlm_main.cpp index 902b4331..a4b38fac 100644 --- a/src/ctrlm_main.cpp +++ b/src/ctrlm_main.cpp @@ -85,6 +85,8 @@ #include "ctrlm_voice_obj_generic.h" #include "ctrlm_voice_endpoint.h" #include "ctrlm_irdb_interface.h" +#include "ctrlm_rcp_ipc_event.h" + #ifdef FDC_ENABLED #include "xr_fdc.h" #endif @@ -877,6 +879,38 @@ void ctrlm_main_ir_last_keypress_get(ctrlm_ir_last_keypress_t *last_key_info) { } } +static void ctrlm_main_network_handler_execute_for_all(ctrlm_msg_handler_network_t handler, void *data, int size) { + for (auto const &network_it : g_ctrlm.networks) { + if (network_it.second && network_it.second->is_ready()) { + (network_it.second->*handler)(data, size); + } + } +} + +std::shared_ptr ctrlm_main_all_network_rcu_status_get() { + if (g_ctrlm.main_thread != g_thread_self ()) { + XLOGD_ERROR("not called from ctrlm_main_thread!!!!!"); + if(!ctrlm_is_production_build()) { + g_assert(0); + } + return nullptr; + } + + std::shared_ptr> params = + std::make_shared>(); + + params->set_net_id(CTRLM_MAIN_NETWORK_ID_ALL); + + ctrlm_main_queue_msg_get_rcu_status_t msg = {}; + msg.params = params; + + ctrlm_main_network_handler_execute_for_all((ctrlm_msg_handler_network_t)&ctrlm_obj_network_t::req_process_get_rcu_status, + &msg, + sizeof(msg)); + + return params; +} + void ctrlm_utils_sem_wait(){ sem_wait(&g_ctrlm.ctrlm_utils_sem); } diff --git a/src/ipc/ctrlm_rcp_ipc_event.cpp b/src/ipc/ctrlm_rcp_ipc_event.cpp index 510be650..7ed3d43d 100644 --- a/src/ipc/ctrlm_rcp_ipc_event.cpp +++ b/src/ipc/ctrlm_rcp_ipc_event.cpp @@ -135,17 +135,17 @@ void ctrlm_rcp_ipc_net_status_t::populate_status(const ctrlm_obj_network_t &netw } } -ctrlm_ir_state_t ctrlm_rcp_ipc_net_status_t::get_ir_prog_state(void) +ctrlm_ir_state_t ctrlm_rcp_ipc_net_status_t::get_ir_prog_state(void) const { return irdb_state_; } -ctrlm_rf_pair_state_t ctrlm_rcp_ipc_net_status_t::get_rf_pair_state(void) +ctrlm_rf_pair_state_t ctrlm_rcp_ipc_net_status_t::get_rf_pair_state(void) const { return pair_state_; } -void ctrlm_rcp_ipc_net_status_t::get_controller_status_list(std::vector &list) +void ctrlm_rcp_ipc_net_status_t::get_controller_status_list(std::vector &list) const { for (const auto &status : controller_status_list_) { list.push_back(status); diff --git a/src/ipc/ctrlm_rcp_ipc_event.h b/src/ipc/ctrlm_rcp_ipc_event.h index e2c36e7c..03b29da4 100644 --- a/src/ipc/ctrlm_rcp_ipc_event.h +++ b/src/ipc/ctrlm_rcp_ipc_event.h @@ -120,9 +120,9 @@ class ctrlm_rcp_ipc_net_status_t : public ctrlm_virtual_json_t ctrlm_network_type_t get_type() const { return net_type_; } void populate_status(const ctrlm_obj_network_t &network); - ctrlm_ir_state_t get_ir_prog_state(void); - ctrlm_rf_pair_state_t get_rf_pair_state(void); - void get_controller_status_list(std::vector &list); + ctrlm_ir_state_t get_ir_prog_state(void) const; + ctrlm_rf_pair_state_t get_rf_pair_state(void) const; + void get_controller_status_list(std::vector &list) const; private: uint8_t api_revision_ = 0; diff --git a/src/ipc/ctrlm_rcp_ipc_iarm_thunder.cpp b/src/ipc/ctrlm_rcp_ipc_iarm_thunder.cpp index 5ed63e70..15b267d7 100644 --- a/src/ipc/ctrlm_rcp_ipc_iarm_thunder.cpp +++ b/src/ipc/ctrlm_rcp_ipc_iarm_thunder.cpp @@ -19,6 +19,7 @@ #include "algorithm" #include "ctrlm_rcp_ipc_iarm_thunder.h" +#include "ctrlm.h" #include "ctrlm_network.h" #include "ctrlm_log.h" #include @@ -103,6 +104,42 @@ bool ctrlm_rcp_ipc_iarm_thunder_t::is_thunder_device_update_enabled() const return (thunder_device_update_enabled_); } +json_t *ctrlm_rcp_ipc_iarm_thunder_t::build_rcu_status_json( + const std::map &status_map, + ctrlm_ir_state_t ir_prog_state, + ctrlm_rf_pair_state_t rf_pair_state, + ctrlm_network_type_t type) +{ + json_t *status = json_object(); + json_t *net_type_supported = json_array(); + json_t *remote_array = json_array(); + std::vector remotes; + int err = 0; + + for (auto const &it : ctrlm_network_types_get()) { + err |= json_array_append_new(net_type_supported, json_integer(it)); + } + for (auto &it : status_map) { + it.second.get_controller_status_list(remotes); + } + for (const auto &remote : remotes) { + err |= json_array_append_new(remote_array, remote.to_json()); + } + + err |= json_object_set_new_nocheck(status, REMOTE_DATA, remote_array); + err |= json_object_set_new_nocheck(status, NET_TYPES_SUPPORTED, net_type_supported); + err |= json_object_set_new_nocheck(status, NET_TYPE, json_integer(type)); + err |= json_object_set_new_nocheck(status, IR_PROG_STATE, json_string(ctrlm_ir_state_str(ir_prog_state))); + err |= json_object_set_new_nocheck(status, PAIRING_STATE, json_string(ctrlm_rf_pair_state_str(rf_pair_state))); + + if (err) { + XLOGD_ERROR("JSON object set error"); + json_decref(status); + return nullptr; + } + return status; +} + bool ctrlm_rcp_ipc_iarm_thunder_t::on_status(const ctrlm_rcp_ipc_net_status_t &net_status) const { if (!is_running(atomic_running_)) { @@ -115,11 +152,23 @@ bool ctrlm_rcp_ipc_iarm_thunder_t::on_status(const ctrlm_rcp_ipc_net_status_t &n return(false); } - json_t *ret = json_object(); - int err = 0; + std::shared_ptr ptr = ctrlm_main_all_network_rcu_status_get(); + if (ptr == nullptr) { + XLOGD_ERROR("Failed to get RCU status from main thread"); + return false; + } + std::shared_ptr> params = + std::static_pointer_cast>(ptr); + + const std::map status_map = params->get_reply(); - err |= json_object_set_new_nocheck(ret, STATUS, net_status.to_json()); + json_t *status = build_rcu_status_json(status_map, net_status.get_ir_prog_state(), net_status.get_rf_pair_state(), net_status.get_type()); + if (status == nullptr) { + return(false); + } + json_t *ret = json_object(); + int err = json_object_set_new_nocheck(ret, STATUS, status); if (err) { XLOGD_ERROR("JSON object set error"); json_decref(ret); @@ -129,6 +178,70 @@ bool ctrlm_rcp_ipc_iarm_thunder_t::on_status(const ctrlm_rcp_ipc_net_status_t &n return broadcast_iarm_event(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_RCU_IARM_EVENT_RCU_STATUS, ret); } + +IARM_Result_t ctrlm_rcp_ipc_iarm_thunder_t::get_net_status(void *arg) +{ + XLOGD_INFO(""); + + if (!is_running(atomic_running_)) { + XLOGD_ERROR("IARM Call received when IARM component in stopped/terminated state"); + return(IARM_RESULT_INVALID_STATE); + } + + ctrlm_main_iarm_call_json_t *call_data = static_cast(arg); + + if (!call_data || call_data->api_revision != CTRLM_MAIN_IARM_BUS_API_REVISION) { + XLOGD_ERROR("NULL parameter"); + return(IARM_RESULT_INVALID_PARAM); + } + + std::shared_ptr> params = std::make_shared>(); + params->set_net_id(CTRLM_MAIN_NETWORK_ID_ALL); + + sync_send_netw_handler_to_main_queue_new, + ctrlm_main_queue_msg_get_rcu_status_t> + (params, + (ctrlm_msg_handler_network_t)&ctrlm_obj_network_t::req_process_get_rcu_status); + + + std::map status_map = params->get_reply(); + + + ctrlm_network_type_t type = CTRLM_NETWORK_TYPE_INVALID; + ctrlm_ir_state_t ir_prog_state = CTRLM_IR_STATE_UNKNOWN; + ctrlm_rf_pair_state_t rf_pair_state = CTRLM_RF_PAIR_STATE_UNKNOWN; + + // For now default to RF4CE network reporting if available + for (auto &it : status_map) { + ir_prog_state = it.second.get_ir_prog_state(); + rf_pair_state = it.second.get_rf_pair_state(); + type = it.second.get_type(); + + if (type == CTRLM_NETWORK_TYPE_RF4CE) { + break; + } + } + + json_t *status = build_rcu_status_json(status_map, ir_prog_state, rf_pair_state, type); + if (status == nullptr) { + return(IARM_RESULT_INVALID_STATE); + } + + json_t *ret = json_object(); + + int err = 0; + err |= json_object_set_new_nocheck(ret, STATUS, status); + err |= json_object_set_new_nocheck(ret, SUCCESS, json_boolean(params->get_result())); + + if (err || !ctrlm_json_to_iarm_call_data_result(ret, call_data)) { + XLOGD_ERROR("JSON object set error"); + json_decref(ret); + return(IARM_RESULT_INVALID_STATE); + } + + return(IARM_RESULT_SUCCESS); +} + bool ctrlm_rcp_ipc_iarm_thunder_t::on_validation_status(const ctrlm_rcp_ipc_validation_status_t &validation_status) const { if (!is_running(atomic_running_)) { @@ -223,6 +336,7 @@ IARM_Result_t ctrlm_rcp_ipc_iarm_thunder_t::start_pairing(void *arg) if (!payload || !config.current_object_get()) { XLOGD_ERROR("Bad payload from call data"); + json_decref(payload); return(IARM_RESULT_INVALID_PARAM); } @@ -250,17 +364,20 @@ IARM_Result_t ctrlm_rcp_ipc_iarm_thunder_t::start_pairing(void *arg) json_array_foreach(mac_addr_array, index, value) { if (!json_is_string(value)) { XLOGD_ERROR("An element of the %s array is not a string", MAC_ADDRESS_LIST); + json_decref(payload); return(IARM_RESULT_INVALID_PARAM); } uint64_t mac_addr = ctrlm_convert_mac_string_to_long(json_string_value(value)); if (mac_addr == 0) { XLOGD_ERROR("An invalid mac address was provided <%s>", json_string_value(value)); + json_decref(payload); return(IARM_RESULT_INVALID_PARAM); } mac_addr_list.push_back(mac_addr); } } + json_decref(payload); if(!scanEnable && mac_addr_list.size() > 0) { XLOGD_WARN("scanEnable is false but macAddressList is not empty. Ignoring macAddressList."); @@ -325,6 +442,7 @@ IARM_Result_t ctrlm_rcp_ipc_iarm_thunder_t::stop_pairing(void *arg) if (!payload || !config.current_object_get()) { XLOGD_ERROR("Bad payload from call data"); + json_decref(payload); return(IARM_RESULT_INVALID_PARAM); } @@ -337,6 +455,8 @@ IARM_Result_t ctrlm_rcp_ipc_iarm_thunder_t::stop_pairing(void *arg) if (!config.config_value_get(SCAN_DISABLE, scanDisable)) { XLOGD_INFO("Missing %s parameter - defaulting to %s", SCAN_DISABLE, scanDisable ? "true" : "false"); } + json_decref(payload); + bool result = true; if(!screenBindDisable && !scanDisable) { @@ -373,94 +493,6 @@ IARM_Result_t ctrlm_rcp_ipc_iarm_thunder_t::stop_pairing(void *arg) return(IARM_RESULT_SUCCESS); } -IARM_Result_t ctrlm_rcp_ipc_iarm_thunder_t::get_net_status(void *arg) -{ - XLOGD_INFO(""); - - if (!is_running(atomic_running_)) { - XLOGD_ERROR("IARM Call received when IARM component in stopped/terminated state"); - return(IARM_RESULT_INVALID_STATE); - } - - ctrlm_main_iarm_call_json_t *call_data = static_cast(arg); - - if (!call_data || call_data->api_revision != CTRLM_MAIN_IARM_BUS_API_REVISION) { - XLOGD_ERROR("NULL parameter"); - return(IARM_RESULT_INVALID_PARAM); - } - - json_t *payload = json_loads(call_data->payload, JSON_DECODE_ANY, NULL); - json_config config(payload); - - if (!payload || !config.current_object_get()) { - XLOGD_ERROR("Bad payload from call data"); - return(IARM_RESULT_INVALID_PARAM); - } - - - std::shared_ptr> params = std::make_shared>(); - params->set_net_id(CTRLM_MAIN_NETWORK_ID_ALL); - - sync_send_netw_handler_to_main_queue_new, - ctrlm_main_queue_msg_get_rcu_status_t> - (params, - (ctrlm_msg_handler_network_t)&ctrlm_obj_network_t::req_process_get_rcu_status); - - json_t *ret = json_object(); - json_t *status = json_object(); - json_t *net_type_supported = json_array(); - json_t *remote_array = json_array(); - - std::map status_map = params->get_reply(); - std::vector remotes; - - ctrlm_network_type_t type = CTRLM_NETWORK_TYPE_INVALID; - ctrlm_ir_state_t ir_prog_state = CTRLM_IR_STATE_UNKNOWN; - ctrlm_rf_pair_state_t rf_pair_state = CTRLM_RF_PAIR_STATE_UNKNOWN; - int err = 0; - - for (auto const &it : ctrlm_network_types_get()) { - err |= json_array_append_new(net_type_supported, json_integer(it)); - } - for (auto &it : status_map) { - it.second.get_controller_status_list(remotes); - } - for (const auto &remote : remotes) { - err |= json_array_append_new(remote_array, remote.to_json()); - } - // For now default to RF4CE network reporting if available - for (auto &it : status_map) { - ir_prog_state = it.second.get_ir_prog_state(); - rf_pair_state = it.second.get_rf_pair_state(); - type = it.second.get_type(); - - if (type == CTRLM_NETWORK_TYPE_RF4CE) { - break; - } - } - - err |= json_object_set_new_nocheck(status, REMOTE_DATA, remote_array); - err |= json_object_set_new_nocheck(status, NET_TYPES_SUPPORTED, net_type_supported); - err |= json_object_set_new_nocheck(status, NET_TYPE, json_integer(type)); - err |= json_object_set_new_nocheck(status, IR_PROG_STATE, json_string(ctrlm_ir_state_str(ir_prog_state))); - err |= json_object_set_new_nocheck(status, PAIRING_STATE, json_string(ctrlm_rf_pair_state_str(rf_pair_state))); - - err |= json_object_set_new_nocheck(ret, STATUS, status); - err |= json_object_set_new_nocheck(ret, SUCCESS, json_boolean(params->get_result())); - - if (err) { - XLOGD_ERROR("JSON object set error"); - json_decref(ret); - return(IARM_RESULT_INVALID_STATE); - } - - if (!ctrlm_json_to_iarm_call_data_result(ret, call_data)) { - json_decref(ret); - return(IARM_RESULT_INVALID_STATE); - } - - return(IARM_RESULT_SUCCESS); -} IARM_Result_t ctrlm_rcp_ipc_iarm_thunder_t::get_last_keypress(void *arg) { @@ -478,14 +510,6 @@ IARM_Result_t ctrlm_rcp_ipc_iarm_thunder_t::get_last_keypress(void *arg) return(IARM_RESULT_INVALID_PARAM); } - json_t *payload = json_loads(call_data->payload, JSON_DECODE_ANY, NULL); - json_config config(payload); - - if (!payload || !config.current_object_get()) { - XLOGD_ERROR("Bad payload from call data"); - return(IARM_RESULT_INVALID_PARAM); - } - std::shared_ptr> params = std::make_shared>(); params->set_net_id(CTRLM_MAIN_NETWORK_ID_ALL); @@ -554,14 +578,17 @@ IARM_Result_t ctrlm_rcp_ipc_iarm_thunder_t::find_my_remote(void *arg) if (!payload || !config.current_object_get()) { XLOGD_ERROR("Bad payload from call data"); + json_decref(payload); return(IARM_RESULT_INVALID_PARAM); } std::string level; if(!config.config_value_get(LEVEL, level)) { XLOGD_ERROR("Missing %s parameter", LEVEL); + json_decref(payload); return(IARM_RESULT_INVALID_PARAM); } + json_decref(payload); std::shared_ptr params = std::make_shared(); params->set_net_id(CTRLM_MAIN_NETWORK_ID_ALL); @@ -650,6 +677,7 @@ IARM_Result_t ctrlm_rcp_ipc_iarm_thunder_t::write_rcu_wakeup_config(void *arg) if (!payload || !config.current_object_get()) { XLOGD_ERROR("Bad payload from call data"); + json_decref(payload); return(IARM_RESULT_INVALID_PARAM); } @@ -657,6 +685,7 @@ IARM_Result_t ctrlm_rcp_ipc_iarm_thunder_t::write_rcu_wakeup_config(void *arg) std::string wakeup_config; if(!config.config_value_get(WAKEUP_CONFIG, wakeup_config)) { XLOGD_ERROR("Missing %s parameter", WAKEUP_CONFIG); + json_decref(payload); return(IARM_RESULT_INVALID_PARAM); } @@ -664,9 +693,11 @@ IARM_Result_t ctrlm_rcp_ipc_iarm_thunder_t::write_rcu_wakeup_config(void *arg) if (ctrlm_utils_str_to_wakeup_config(wakeup_config) == CTRLM_RCU_WAKEUP_CONFIG_CUSTOM) { if(!config.config_value_get(CUSTOM_KEYS, custom_keys)) { XLOGD_ERROR("Missing %s parameter", CUSTOM_KEYS); + json_decref(payload); return(IARM_RESULT_INVALID_PARAM); } } + json_decref(payload); ctrlm_iarm_call_WriteRcuWakeupConfig_params_t params = {}; params.network_id = CTRLM_MAIN_NETWORK_ID_ALL; @@ -716,6 +747,7 @@ IARM_Result_t ctrlm_rcp_ipc_iarm_thunder_t::unpair(void *arg) if (!payload || !config.current_object_get()) { XLOGD_ERROR("Bad payload from call data"); + json_decref(payload); return(IARM_RESULT_INVALID_PARAM); } @@ -728,17 +760,20 @@ IARM_Result_t ctrlm_rcp_ipc_iarm_thunder_t::unpair(void *arg) json_array_foreach(mac_addr_array, index, value) { if (!json_is_string(value)) { XLOGD_ERROR("An element of the %s array is not a string", MAC_ADDRESS_LIST); + json_decref(payload); return(IARM_RESULT_INVALID_PARAM); } uint64_t mac_addr = ctrlm_convert_mac_string_to_long(json_string_value(value)); if (mac_addr == 0) { XLOGD_ERROR("An invalid mac address was provided <%s>", json_string_value(value)); + json_decref(payload); return(IARM_RESULT_INVALID_PARAM); } mac_addr_list.push_back(mac_addr); } } + json_decref(payload); std::shared_ptr params = std::make_shared(); params->set_net_id(CTRLM_MAIN_NETWORK_ID_ALL); @@ -794,6 +829,7 @@ IARM_Result_t ctrlm_rcp_ipc_iarm_thunder_t::start_fw_update(void *arg) if (!payload || !config.current_object_get()) { XLOGD_ERROR("Bad payload from call data"); + json_decref(payload); return(IARM_RESULT_INVALID_PARAM); } @@ -808,6 +844,7 @@ IARM_Result_t ctrlm_rcp_ipc_iarm_thunder_t::start_fw_update(void *arg) std::string filename; if (!config.config_value_get(FILENAME, filename)) { XLOGD_ERROR("Missing %s parameter", FILENAME); + json_decref(payload); return(IARM_RESULT_INVALID_PARAM); } @@ -816,20 +853,22 @@ IARM_Result_t ctrlm_rcp_ipc_iarm_thunder_t::start_fw_update(void *arg) XLOGD_INFO("%s parameter was omitted", FILETYPE); } - uint8_t percent_increment = 0; + int percent_increment = 0; if (!config.config_value_get(PERCENT_INCREMENT, percent_increment)) { XLOGD_INFO("%s parameter was omitted", PERCENT_INCREMENT); } else if (percent_increment < 0 || percent_increment > 100) { XLOGD_ERROR("%s parameter out of bounds", PERCENT_INCREMENT); + json_decref(payload); return(IARM_RESULT_INVALID_PARAM); } + json_decref(payload); std::shared_ptr params = std::make_shared(); std::shared_ptr> upgrade_sessions = std::make_shared>(); params->set_net_id(CTRLM_MAIN_NETWORK_ID_ALL); params->ieee_address = ieee_address; - params->percent_increment = percent_increment; + params->percent_increment = (uint8_t)percent_increment; params->filetype = filetype; params->filename = filename; params->upgrade_sessions = upgrade_sessions; @@ -890,14 +929,17 @@ IARM_Result_t ctrlm_rcp_ipc_iarm_thunder_t::cancel_fw_update(void *arg) if (!payload || !config.current_object_get()) { XLOGD_ERROR("Bad payload from call data"); + json_decref(payload); return(IARM_RESULT_INVALID_PARAM); } std::string session_id; if (!config.config_value_get(SESSION_ID, session_id) || !ctrlm_utils_is_valid_uuid(session_id)) { XLOGD_ERROR("Missing or bad %s parameter", SESSION_ID); + json_decref(payload); return(IARM_RESULT_INVALID_PARAM); } + json_decref(payload); std::shared_ptr params = std::make_shared(); params->set_net_id(CTRLM_MAIN_NETWORK_ID_ALL); @@ -953,14 +995,17 @@ IARM_Result_t ctrlm_rcp_ipc_iarm_thunder_t::status_fw_update(void *arg) if (!payload || !config.current_object_get()) { XLOGD_ERROR("Bad payload from call data"); + json_decref(payload); return(IARM_RESULT_INVALID_PARAM); } std::string session_id; if (!config.config_value_get(SESSION_ID, session_id) || !ctrlm_utils_is_valid_uuid(session_id)) { XLOGD_ERROR("Missing or bad %s parameter", SESSION_ID); + json_decref(payload); return(IARM_RESULT_INVALID_PARAM); } + json_decref(payload); std::shared_ptr params = std::make_shared(); params->set_net_id(CTRLM_MAIN_NETWORK_ID_ALL); diff --git a/src/ipc/ctrlm_rcp_ipc_iarm_thunder.h b/src/ipc/ctrlm_rcp_ipc_iarm_thunder.h index 384df5ae..3cda825d 100644 --- a/src/ipc/ctrlm_rcp_ipc_iarm_thunder.h +++ b/src/ipc/ctrlm_rcp_ipc_iarm_thunder.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "ctrlm_ipc_iarm.h" #include "ctrlm_ipc.h" #include "ctrlm_utils.h" @@ -94,6 +95,12 @@ class ctrlm_rcp_ipc_iarm_thunder_t : public ctrlm_ipc_iarm_t static IARM_Result_t status_fw_update(void *arg); static IARM_Result_t unpair(void *arg); + + static json_t *build_rcu_status_json(const std::map &status_map, + ctrlm_ir_state_t ir_prog_state, + ctrlm_rf_pair_state_t rf_pair_state, + ctrlm_network_type_t type); + template static void sync_send_netw_handler_to_main_queue(T1 params, ctrlm_msg_handler_network_t handler) { From f0af08001e9e35b432380ec198f9b2561dd15fef Mon Sep 17 00:00:00 2001 From: Kelvin Lu <119349872+klu339@users.noreply.github.com> Date: Mon, 8 Jun 2026 15:22:21 -0400 Subject: [PATCH 64/81] RDKEMW-16966: T2 Events for IRDB Programming (#239) --- include/ctrlm_hal_ble.h | 1 + src/ble/ctrlm_ble_controller.cpp | 25 +++++- src/ble/ctrlm_ble_network.cpp | 42 ++++++++++ src/ble/ctrlm_ble_rcu_interface.cpp | 22 +++-- src/irdb/ctrlm_irdb_interface.cpp | 84 ++++++++++++++++++- src/irdb/ipc/ctrlm_irdb_ipc_iarm_thunder.cpp | 34 ++++++++ src/telemetry/ctrlm_telemetry_markers.h | 12 +++ .../ctrlm_thunder_plugin_display_settings.cpp | 2 +- 8 files changed, 212 insertions(+), 10 deletions(-) diff --git a/include/ctrlm_hal_ble.h b/include/ctrlm_hal_ble.h index f9cb6a14..0f84fc64 100644 --- a/include/ctrlm_hal_ble.h +++ b/include/ctrlm_hal_ble.h @@ -132,6 +132,7 @@ typedef struct { int pairing_code; ctrlm_hal_ble_RcuProperty_t property_updated; ctrlm_hal_ble_rcu_data_t rcu_data; + char ir_fail_reason[CTRLM_MAX_PARAM_STR_LEN]; } ctrlm_hal_ble_RcuStatusData_t; typedef struct { diff --git a/src/ble/ctrlm_ble_controller.cpp b/src/ble/ctrlm_ble_controller.cpp index c9e996c9..388fabb8 100644 --- a/src/ble/ctrlm_ble_controller.cpp +++ b/src/ble/ctrlm_ble_controller.cpp @@ -31,6 +31,7 @@ #include "ctrlm_controller.h" #include "ctrlm_hal_ip.h" #include "blercu/bleservices/blercuupgradeservice.h" +#include "ctrlm_telemetry_event.h" #include #include @@ -534,19 +535,30 @@ void ctrlm_obj_controller_ble_t::setSupportedIrdbs(uint8_t vendor_support_bitmas if (irdb == NULL) { XLOGD_ERROR("IRDB interface is NULL!!!"); +#ifdef TELEMETRY_SUPPORT + char t2_buf[256]; + snprintf(t2_buf, sizeof(t2_buf), "[0,0x%02X,\"unknown\",0x00,0]", vendor_support_bitmask); + ctrlm_telemetry_event_t ev(MARKER_IRDB_VENDOR_SET, t2_buf); + ev.event(); +#endif return; } ctrlm_irdb_vendor_info_t rcu_vendor_info{}; rcu_vendor_info.rcu_support_bitmask = vendor_support_bitmask; - if (!irdb->set_vendor(rcu_vendor_info)) { + bool set_result = irdb->set_vendor(rcu_vendor_info); + if (!set_result) { XLOGD_ERROR("Failed to set IRDB vendor info for controller <%s> with bitmask <0x%X>.", ieee_address_get().to_string().c_str(), vendor_support_bitmask); } ctrlm_irdb_vendor_info_t vendor_info{}; + vendor_info.name = "unknown"; + vendor_info.rcu_support_bitmask = 0xFF; + bool supported = false; if (irdb->get_vendor_info(vendor_info)) { - if (isSupportedIrdb(vendor_info)) { + supported = isSupportedIrdb(vendor_info); + if (supported) { XLOGD_INFO("Controller <%s> IRDBs supported bitmask = <0x%X>, which DOES support the loaded IRDB plugin vendor <%s>", ieee_address_get().to_string().c_str(), vendor_support_bitmask, vendor_info.name.c_str()); } else { @@ -557,6 +569,15 @@ void ctrlm_obj_controller_ble_t::setSupportedIrdbs(uint8_t vendor_support_bitmas XLOGD_WARN("Controller <%s> IRDBs supported bitmask = <0x%X>, couldn't retrieve IRDB plugin vendor info.", ieee_address_get().to_string().c_str(), vendor_support_bitmask); } +#ifdef TELEMETRY_SUPPORT + char t2_buf[256]; + snprintf(t2_buf, sizeof(t2_buf), "[%d,0x%02X,\"%s\",0x%02X,%d]", + (int)set_result,vendor_support_bitmask, + vendor_info.name.c_str(), vendor_info.rcu_support_bitmask, + (int)supported); + ctrlm_telemetry_event_t ev(MARKER_IRDB_VENDOR_SET, t2_buf); + ev.event(); +#endif } uint8_t ctrlm_obj_controller_ble_t::getSupportedIrdbs() const { diff --git a/src/ble/ctrlm_ble_network.cpp b/src/ble/ctrlm_ble_network.cpp index 94a9022c..480d900a 100644 --- a/src/ble/ctrlm_ble_network.cpp +++ b/src/ble/ctrlm_ble_network.cpp @@ -49,6 +49,7 @@ #include "ctrlm_rcp_ipc_iarm_thunder.h" #include "ctrlm_telemetry.h" #include +#include "ctrlm_telemetry_event.h" using namespace std; @@ -792,6 +793,16 @@ void ctrlm_obj_network_ble_t::req_process_program_ir_codes(void *data, int size) XLOGD_ERROR("Controller doesn't exist!"); } else if (!controllers_[controller_id]->isSupportedIrdb(dqm->vendor_info)) { XLOGD_ERROR("Unsupported IRDB - not continuing with ir code download!"); +#ifdef TELEMETRY_SUPPORT + char t2_buf[256]; + snprintf(t2_buf, sizeof(t2_buf), "[%d,\"unsupported\",0x%02X,\"%s\",0x%02X]", + (int)CTRLM_IR_STATE_FAILED, + controllers_[controller_id]->getSupportedIrdbs(), + dqm->vendor_info.name.c_str(), + dqm->vendor_info.rcu_support_bitmask); + ctrlm_telemetry_event_t ev(MARKER_IRDB_PROGRAM_RESULT, t2_buf); + ev.event(); +#endif } else { if(dqm->ir_codes) { @@ -1776,6 +1787,37 @@ void ctrlm_obj_network_ble_t::ind_process_rcu_status(void *data, int size) { ir_state_ = dqm->ir_state; // send event immediately. schedule_status_event(true); +#ifdef TELEMETRY_SUPPORT + { + ctrlm_irdb_vendor_info_t vendor_info{}; + vendor_info.name = "unknown"; + vendor_info.rcu_support_bitmask = 0xFF; + + ctrlm_irdb_interface_t *irdb = ctrlm_main_irdb_get(); + if (irdb) { irdb->get_vendor_info(vendor_info); } + char t2_buf[256]; + if (dqm->ir_state == CTRLM_IR_STATE_COMPLETE || dqm->ir_state == CTRLM_IR_STATE_FAILED) { + ctrlm_controller_id_t controller_id; + uint8_t rcu_bitmask = 0xFF; + if (false == getControllerId(dqm->rcu_data.ieee_address, &controller_id)) { + XLOGD_ERROR("Controller <%s> NOT found in the network!!", + ctrlm_convert_mac_long_to_string(dqm->rcu_data.ieee_address).c_str()); + } else { + auto controller = controllers_[controller_id]; + rcu_bitmask = controller->getSupportedIrdbs(); + } + + snprintf(t2_buf, sizeof(t2_buf), "[%d,\"%s\",0x%02X,\"%s\",0x%02X]", + (int)dqm->ir_state, + dqm->ir_fail_reason, + rcu_bitmask, + vendor_info.name.c_str(), + vendor_info.rcu_support_bitmask); + ctrlm_telemetry_event_t ev(MARKER_IRDB_PROGRAM_RESULT, t2_buf); + ev.event(); + } + } +#endif break; default: { diff --git a/src/ble/ctrlm_ble_rcu_interface.cpp b/src/ble/ctrlm_ble_rcu_interface.cpp index 2fd194b7..36c9dbaf 100644 --- a/src/ble/ctrlm_ble_rcu_interface.cpp +++ b/src/ble/ctrlm_ble_rcu_interface.cpp @@ -1166,7 +1166,7 @@ bool ctrlm_ble_rcu_interface_t::programIrSignalWaveforms(uint64_t ieee_address, uint8_t vendor) { // lambda invoked when the request returns - auto replyHandler = [this](PendingReply<> *reply) mutable + auto replyHandler = [this, ieee_address](PendingReply<> *reply) mutable { bool success = false; @@ -1179,9 +1179,13 @@ bool ctrlm_ble_rcu_interface_t::programIrSignalWaveforms(uint64_t ieee_address, success = true; } - ctrlm_hal_ble_RcuStatusData_t params; + ctrlm_hal_ble_RcuStatusData_t params = {}; params.property_updated = CTRLM_HAL_BLE_PROPERTY_IR_STATE; params.ir_state = success ? CTRLM_IR_STATE_COMPLETE : CTRLM_IR_STATE_FAILED; + params.rcu_data.ieee_address = ieee_address; + if (!success) { + snprintf(params.ir_fail_reason, CTRLM_MAX_PARAM_STR_LEN, "%s", reply->errorMessage().c_str()); + } m_rcuStatusChangedSlots.invoke(¶ms); }; @@ -1247,9 +1251,10 @@ bool ctrlm_ble_rcu_interface_t::programIrSignalWaveforms(uint64_t ieee_address, success = false; } - ctrlm_hal_ble_RcuStatusData_t params; + ctrlm_hal_ble_RcuStatusData_t params = {}; params.property_updated = CTRLM_HAL_BLE_PROPERTY_IR_STATE; params.ir_state = success ? CTRLM_IR_STATE_WAITING : CTRLM_IR_STATE_FAILED; + params.rcu_data.ieee_address = ieee_address; m_rcuStatusChangedSlots.invoke(¶ms); return success; @@ -1258,7 +1263,7 @@ bool ctrlm_ble_rcu_interface_t::programIrSignalWaveforms(uint64_t ieee_address, bool ctrlm_ble_rcu_interface_t::eraseIrSignals(uint64_t ieee_address) { // lambda invoked when the request returns - auto replyHandler = [this](PendingReply<> *reply) mutable + auto replyHandler = [this, ieee_address](PendingReply<> *reply) mutable { bool success = false; @@ -1271,9 +1276,13 @@ bool ctrlm_ble_rcu_interface_t::eraseIrSignals(uint64_t ieee_address) success = true; } - ctrlm_hal_ble_RcuStatusData_t params; + ctrlm_hal_ble_RcuStatusData_t params = {}; params.property_updated = CTRLM_HAL_BLE_PROPERTY_IR_STATE; params.ir_state = success ? CTRLM_IR_STATE_COMPLETE : CTRLM_IR_STATE_FAILED; + params.rcu_data.ieee_address = ieee_address; + if (!success) { + snprintf(params.ir_fail_reason, CTRLM_MAX_PARAM_STR_LEN, "%s", reply->errorMessage().c_str()); + } m_rcuStatusChangedSlots.invoke(¶ms); }; @@ -1295,9 +1304,10 @@ bool ctrlm_ble_rcu_interface_t::eraseIrSignals(uint64_t ieee_address) success = false; } - ctrlm_hal_ble_RcuStatusData_t params; + ctrlm_hal_ble_RcuStatusData_t params = {}; params.property_updated = CTRLM_HAL_BLE_PROPERTY_IR_STATE; params.ir_state = success ? CTRLM_IR_STATE_WAITING : CTRLM_IR_STATE_FAILED; + params.rcu_data.ieee_address = ieee_address; m_rcuStatusChangedSlots.invoke(¶ms); return success; diff --git a/src/irdb/ctrlm_irdb_interface.cpp b/src/irdb/ctrlm_irdb_interface.cpp index 01fa6588..bab8f9a6 100644 --- a/src/irdb/ctrlm_irdb_interface.cpp +++ b/src/irdb/ctrlm_irdb_interface.cpp @@ -21,6 +21,7 @@ #include "ctrlm_network.h" #include "ctrlm_log.h" #include "ctrlm_irdb_stub.h" +#include "ctrlm_telemetry_event.h" #include "ctrlm_ipc_iarm.h" #include "ctrlm_irdb_ipc_iarm_thunder.h" @@ -41,10 +42,36 @@ #include #include +#include #include +#include using namespace std; +typedef enum { + CTRLM_IRDB_AUTOLOOKUP_SOURCE_EDID = 0, + CTRLM_IRDB_AUTOLOOKUP_SOURCE_CEC, + CTRLM_IRDB_AUTOLOOKUP_SOURCE_INFOFRAME, + CTRLM_IRDB_AUTOLOOKUP_SOURCE_UNKNOWN +} ctrlm_irdb_autolookup_source_t; + +typedef enum { + CTRLM_IRDB_AUTOLOOKUP_RESULT_SUCCESS = 0, + CTRLM_IRDB_AUTOLOOKUP_RESULT_NULL, + CTRLM_IRDB_AUTOLOOKUP_RESULT_NO_SOURCE_DATA, + CTRLM_IRDB_AUTOLOOKUP_RESULT_FAILED, + CTRLM_IRDB_AUTOLOOKUP_RESULT_NO_CODES_FOR_SOURCE, + CTRLM_IRDB_AUTOLOOKUP_RESULT_DEV_TYPE_INVALID, + CTRLM_IRDB_AUTOLOOKUP_RESULT_UNKNOWN, +} ctrlm_irdb_autolookup_result_t; + +class ctrlm_irdb_t2_autolookup_entry_t { +public: + ctrlm_irdb_t2_autolookup_entry_t(int p, ctrlm_irdb_autolookup_source_t s, ctrlm_irdb_autolookup_result_t r): port(p), source(s), result(r) {} + int port = -1; + ctrlm_irdb_autolookup_source_t source = CTRLM_IRDB_AUTOLOOKUP_SOURCE_UNKNOWN; + ctrlm_irdb_autolookup_result_t result = CTRLM_IRDB_AUTOLOOKUP_RESULT_UNKNOWN; +}; static ctrlm_irdb_interface_t *_instance = NULL; @@ -420,6 +447,13 @@ bool comp_autolookup_ranked_list (ctrlm_irdb_autolookup_entry_ranked_t i, ctrlm_ bool ctrlm_irdb_interface_t::get_ir_codes_by_autolookup(ctrlm_autolookup_ranked_list_by_type_t &codes) { std::unique_lock guard(m_mutex); bool ret = false; + std::vector t2_info; + + // Retrieve vendor info now while mutex is held (avoids recursive lock via get_vendor_info()) + ctrlm_irdb_vendor_info_t t2_vendor_info{}; + if (g_irdb.pluginGetVendorInfo) { + (*g_irdb.pluginGetVendorInfo)(t2_vendor_info); + } #if defined(CTRLM_THUNDER) if(m_platform_tv == false) { @@ -436,20 +470,26 @@ bool ctrlm_irdb_interface_t::get_ir_codes_by_autolookup(ctrlm_autolookup_ranked_ if(type != CTRLM_IRDB_DEV_TYPE_INVALID) { codes[type].insert(codes[type].end(), ir_codes.begin(), ir_codes.end()); ret = true; + t2_info.emplace_back(-1, CTRLM_IRDB_AUTOLOOKUP_SOURCE_EDID, CTRLM_IRDB_AUTOLOOKUP_RESULT_SUCCESS); } else { XLOGD_ERROR("edid dev type invalid"); + t2_info.emplace_back(-1, CTRLM_IRDB_AUTOLOOKUP_SOURCE_EDID, CTRLM_IRDB_AUTOLOOKUP_RESULT_DEV_TYPE_INVALID); } } else { XLOGD_ERROR("no codes for edid data"); + t2_info.emplace_back(-1, CTRLM_IRDB_AUTOLOOKUP_SOURCE_EDID, CTRLM_IRDB_AUTOLOOKUP_RESULT_NO_CODES_FOR_SOURCE); } } else { XLOGD_ERROR("Failed getting codes by edid"); + t2_info.emplace_back(-1, CTRLM_IRDB_AUTOLOOKUP_SOURCE_EDID, CTRLM_IRDB_AUTOLOOKUP_RESULT_FAILED); } } else { XLOGD_ERROR("No EDID data"); + t2_info.emplace_back(-1, CTRLM_IRDB_AUTOLOOKUP_SOURCE_EDID, CTRLM_IRDB_AUTOLOOKUP_RESULT_NO_SOURCE_DATA); } } else { XLOGD_ERROR("display_settings is NULL"); + t2_info.emplace_back(-1, CTRLM_IRDB_AUTOLOOKUP_SOURCE_EDID, CTRLM_IRDB_AUTOLOOKUP_RESULT_NULL); } if(g_irdb.cec_source) { // Check CEC data @@ -465,21 +505,27 @@ bool ctrlm_irdb_interface_t::get_ir_codes_by_autolookup(ctrlm_autolookup_ranked_ if(type != CTRLM_IRDB_DEV_TYPE_INVALID) { codes[type].insert(codes[type].end(), ir_codes.begin(), ir_codes.end()); ret = true; + t2_info.emplace_back(itr.port, CTRLM_IRDB_AUTOLOOKUP_SOURCE_CEC, CTRLM_IRDB_AUTOLOOKUP_RESULT_SUCCESS); } else { XLOGD_ERROR("cec dev type invalid"); + t2_info.emplace_back(itr.port, CTRLM_IRDB_AUTOLOOKUP_SOURCE_CEC, CTRLM_IRDB_AUTOLOOKUP_RESULT_DEV_TYPE_INVALID); } } else { XLOGD_WARN("no code for cec device <%s>", itr.osd.c_str()); + t2_info.emplace_back(itr.port, CTRLM_IRDB_AUTOLOOKUP_SOURCE_CEC, CTRLM_IRDB_AUTOLOOKUP_RESULT_NO_CODES_FOR_SOURCE); } } else { XLOGD_WARN("Failed to get codes for cec device <%s>", itr.osd.c_str()); + t2_info.emplace_back(itr.port, CTRLM_IRDB_AUTOLOOKUP_SOURCE_CEC, CTRLM_IRDB_AUTOLOOKUP_RESULT_FAILED); } } } else { XLOGD_ERROR("No CEC device data"); + t2_info.emplace_back(-1, CTRLM_IRDB_AUTOLOOKUP_SOURCE_CEC, CTRLM_IRDB_AUTOLOOKUP_RESULT_NO_SOURCE_DATA); } } else { XLOGD_ERROR("cec is NULL"); + t2_info.emplace_back(-1, CTRLM_IRDB_AUTOLOOKUP_SOURCE_CEC, CTRLM_IRDB_AUTOLOOKUP_RESULT_NULL); } } else { if(g_irdb.av_input) { @@ -495,21 +541,27 @@ bool ctrlm_irdb_interface_t::get_ir_codes_by_autolookup(ctrlm_autolookup_ranked_ if(type != CTRLM_IRDB_DEV_TYPE_INVALID) { codes[type].insert(codes[type].end(), ir_codes.begin(), ir_codes.end()); ret = true; + t2_info.emplace_back(itr.first, CTRLM_IRDB_AUTOLOOKUP_SOURCE_INFOFRAME, CTRLM_IRDB_AUTOLOOKUP_RESULT_SUCCESS); } else { XLOGD_ERROR("port %d infoframe dev type invalid", itr.first); + t2_info.emplace_back(itr.first, CTRLM_IRDB_AUTOLOOKUP_SOURCE_INFOFRAME, CTRLM_IRDB_AUTOLOOKUP_RESULT_DEV_TYPE_INVALID); } } else { XLOGD_WARN("no code for port %d infoframe", itr.first); + t2_info.emplace_back(itr.first, CTRLM_IRDB_AUTOLOOKUP_SOURCE_INFOFRAME, CTRLM_IRDB_AUTOLOOKUP_RESULT_NO_CODES_FOR_SOURCE); } } else { XLOGD_WARN("Failed to get codes for port %d infoframe", itr.first); + t2_info.emplace_back(itr.first, CTRLM_IRDB_AUTOLOOKUP_SOURCE_INFOFRAME, CTRLM_IRDB_AUTOLOOKUP_RESULT_FAILED); } } else { XLOGD_WARN("no infoframe for port %d", itr.first); + t2_info.emplace_back(itr.first, CTRLM_IRDB_AUTOLOOKUP_SOURCE_INFOFRAME, CTRLM_IRDB_AUTOLOOKUP_RESULT_NO_SOURCE_DATA); } } } else { XLOGD_ERROR("hdmi is NULL"); + t2_info.emplace_back(-1, CTRLM_IRDB_AUTOLOOKUP_SOURCE_INFOFRAME, CTRLM_IRDB_AUTOLOOKUP_RESULT_NULL); } if(g_irdb.cec_sink) { // Check CEC data @@ -524,21 +576,27 @@ bool ctrlm_irdb_interface_t::get_ir_codes_by_autolookup(ctrlm_autolookup_ranked_ if(type != CTRLM_IRDB_DEV_TYPE_INVALID) { codes[type].insert(codes[type].end(), ir_codes.begin(), ir_codes.end()); ret = true; + t2_info.emplace_back(itr.port, CTRLM_IRDB_AUTOLOOKUP_SOURCE_CEC, CTRLM_IRDB_AUTOLOOKUP_RESULT_SUCCESS); } else { XLOGD_ERROR("cec dev type invalid"); + t2_info.emplace_back(itr.port, CTRLM_IRDB_AUTOLOOKUP_SOURCE_CEC, CTRLM_IRDB_AUTOLOOKUP_RESULT_DEV_TYPE_INVALID); } } else { XLOGD_WARN("no code for cec device <%s>", itr.osd.c_str()); + t2_info.emplace_back(itr.port, CTRLM_IRDB_AUTOLOOKUP_SOURCE_CEC, CTRLM_IRDB_AUTOLOOKUP_RESULT_NO_CODES_FOR_SOURCE); } } else { XLOGD_WARN("Failed to get codes for cec device <%s>", itr.osd.c_str()); + t2_info.emplace_back(itr.port, CTRLM_IRDB_AUTOLOOKUP_SOURCE_CEC, CTRLM_IRDB_AUTOLOOKUP_RESULT_FAILED); } } } else { XLOGD_ERROR("No CEC device data"); + t2_info.emplace_back(-1, CTRLM_IRDB_AUTOLOOKUP_SOURCE_CEC, CTRLM_IRDB_AUTOLOOKUP_RESULT_NO_SOURCE_DATA); } } else { - XLOGD_ERROR("cec_sink is NULL"); + XLOGD_ERROR("cec is NULL"); + t2_info.emplace_back(-1, CTRLM_IRDB_AUTOLOOKUP_SOURCE_CEC, CTRLM_IRDB_AUTOLOOKUP_RESULT_NULL); } } #endif @@ -557,6 +615,30 @@ bool ctrlm_irdb_interface_t::get_ir_codes_by_autolookup(ctrlm_autolookup_ranked_ codes[CTRLM_IRDB_DEV_TYPE_AVR].erase( unique( codes[CTRLM_IRDB_DEV_TYPE_AVR].begin(), codes[CTRLM_IRDB_DEV_TYPE_AVR].end() ), codes[CTRLM_IRDB_DEV_TYPE_AVR].end() ); } +#ifdef TELEMETRY_SUPPORT + size_t tv_count = codes.count(CTRLM_IRDB_DEV_TYPE_TV) ? codes.at(CTRLM_IRDB_DEV_TYPE_TV).size() : 0; + size_t avr_count = codes.count(CTRLM_IRDB_DEV_TYPE_AVR) ? codes.at(CTRLM_IRDB_DEV_TYPE_AVR).size() : 0; + std::stringstream ss; + bool first = true; + for (const auto &entry : t2_info) { + if (!first) { + ss << ","; + } + ss << entry.port << "," << static_cast(entry.source) << "," << static_cast(entry.result); + first = false; + } + std::string results = ss.str(); + ss.str(""); + ss << "[\"" << t2_vendor_info.name << "\"" + << ",0x" << std::hex << std::setfill('0') << std::setw(2) << (int)t2_vendor_info.rcu_support_bitmask + << "," << std::dec << (int)m_platform_tv + << "," << tv_count + << "," << avr_count + << "," << (results.empty() ? "\"\"" : results) << "]"; + ctrlm_telemetry_event_t ev(MARKER_IRDB_AUTOLOOKUP_RESULT, ss.str()); + ev.event(); +#endif + return(ret); } diff --git a/src/irdb/ipc/ctrlm_irdb_ipc_iarm_thunder.cpp b/src/irdb/ipc/ctrlm_irdb_ipc_iarm_thunder.cpp index 48b7c29a..e58f7a64 100644 --- a/src/irdb/ipc/ctrlm_irdb_ipc_iarm_thunder.cpp +++ b/src/irdb/ipc/ctrlm_irdb_ipc_iarm_thunder.cpp @@ -23,6 +23,7 @@ #include "ctrlm_log.h" #include "json_config.h" #include "ctrlm_utils.h" +#include "ctrlm_telemetry_event.h" namespace { constexpr char const* NET_TYPE = "netType"; @@ -152,6 +153,17 @@ IARM_Result_t ctrlm_irdb_ipc_iarm_thunder_t::get_manufacturers(void *arg) { } } +#ifdef TELEMETRY_SUPPORT + ctrlm_irdb_vendor_info_t vendor_info{}; + if (irdb) { + irdb->get_vendor_info(vendor_info); + } + char t2_buf[128]; + snprintf(t2_buf, sizeof(t2_buf), "[\"%s\",0x%02X,\"%s\",%d]", vendor_info.name.c_str(), vendor_info.rcu_support_bitmask, CTRLM_MAIN_IARM_CALL_IR_MANUFACTURERS, (int)success); + ctrlm_telemetry_event_t ev(MARKER_IRDB_MANUAL_RESULT, t2_buf); + ev.event(); +#endif + // Assemble the return json_object_set_new(ret, SUCCESS, json_boolean(success)); if(success) { @@ -226,6 +238,17 @@ IARM_Result_t ctrlm_irdb_ipc_iarm_thunder_t::get_models(void *arg) { } } +#ifdef TELEMETRY_SUPPORT + ctrlm_irdb_vendor_info_t vendor_info{}; + if(irdb) { + irdb->get_vendor_info(vendor_info); + } + char t2_buf[128]; + snprintf(t2_buf, sizeof(t2_buf), "[\"%s\",0x%02X,\"%s\",%d]", vendor_info.name.c_str(), vendor_info.rcu_support_bitmask, CTRLM_MAIN_IARM_CALL_IR_MODELS, (int)success); + ctrlm_telemetry_event_t ev(MARKER_IRDB_MANUAL_RESULT, t2_buf); + ev.event(); +#endif + // Assemble the return json_object_set_new(ret, SUCCESS, json_boolean(success)); if(success) { @@ -366,6 +389,17 @@ IARM_Result_t ctrlm_irdb_ipc_iarm_thunder_t::get_irdb_entry_ids(void *arg) { } } +#ifdef TELEMETRY_SUPPORT + ctrlm_irdb_vendor_info_t vendor_info{}; + if (irdb) { + irdb->get_vendor_info(vendor_info); + } + char t2_buf[128]; + snprintf(t2_buf, sizeof(t2_buf), "[\"%s\",0x%02X,\"%s\",%d]", vendor_info.name.c_str(), vendor_info.rcu_support_bitmask, CTRLM_MAIN_IARM_CALL_IR_CODES, (int)success); + ctrlm_telemetry_event_t ev(MARKER_IRDB_MANUAL_RESULT, t2_buf); + ev.event(); +#endif + // Assemble the return json_object_set_new(ret, SUCCESS, json_boolean(success)); if(success) { diff --git a/src/telemetry/ctrlm_telemetry_markers.h b/src/telemetry/ctrlm_telemetry_markers.h index 446bec55..e9ba968b 100644 --- a/src/telemetry/ctrlm_telemetry_markers.h +++ b/src/telemetry/ctrlm_telemetry_markers.h @@ -153,6 +153,18 @@ // // End RCU Markers + +// IRDB Markers +// + +// All _accum markers are aggregated by the T2 platform within each reporting window. +#define MARKER_IRDB_AUTOLOOKUP_RESULT "ctrlm.irdb.autolookup.result_accum" // format: ,,,,, +#define MARKER_IRDB_MANUAL_RESULT "ctrlm.irdb.manual.result_accum" // format: ,,, +#define MARKER_IRDB_PROGRAM_RESULT "ctrlm.irdb.program.result_accum" // format: ,,,, +#define MARKER_IRDB_VENDOR_SET "ctrlm.irdb.vendor_set_accum" // format: ,,,, + +// +// End IRDB Markers // #endif diff --git a/src/thunder/plugins/ctrlm_thunder_plugin_display_settings.cpp b/src/thunder/plugins/ctrlm_thunder_plugin_display_settings.cpp index 662af928..b11001e6 100644 --- a/src/thunder/plugins/ctrlm_thunder_plugin_display_settings.cpp +++ b/src/thunder/plugins/ctrlm_thunder_plugin_display_settings.cpp @@ -118,7 +118,7 @@ bool ctrlm_thunder_plugin_display_settings_t::_get_edid() { } } ret = true; - XLOGD_DEBUG("EDID data <%d> bytes: \n<%s>", edid_size, ss.str().c_str()); + XLOGD_INFO("EDID data <%d> bytes: \n<%s>", edid_size, ss.str().c_str()); } else { XLOGD_ERROR("Failed to decode EDID base64!"); } From a449407540eec21e4da8895afeba464c2b40abc2 Mon Sep 17 00:00:00 2001 From: Gene Gallagher <129112619+egalla204@users.noreply.github.com> Date: Mon, 8 Jun 2026 19:31:56 -0400 Subject: [PATCH 65/81] RDKEMW-13898: prevent simultaneous irdb codes from different vendors (#220) --- src/ble/ctrlm_ble_network.cpp | 21 ++++++++++- src/database/ctrlm_database.cpp | 48 +++++++++++++++++++++---- src/database/ctrlm_database.h | 8 ++--- src/network/ctrlm_ir_rf_db.cpp | 62 ++++++++++++++++++++++++++++++--- src/network/ctrlm_ir_rf_db.h | 31 ++++++++++++++++- 5 files changed, 153 insertions(+), 17 deletions(-) diff --git a/src/ble/ctrlm_ble_network.cpp b/src/ble/ctrlm_ble_network.cpp index 480d900a..f5c316b4 100644 --- a/src/ble/ctrlm_ble_network.cpp +++ b/src/ble/ctrlm_ble_network.cpp @@ -806,10 +806,29 @@ void ctrlm_obj_network_ble_t::req_process_program_ir_codes(void *data, int size) } else { if(dqm->ir_codes) { + if (dqm->ir_codes->type == CTRLM_IRDB_DEV_TYPE_TV && (ir_rf_database_.get_avr_ir_vendor_id() != 0 && ir_rf_database_.get_avr_ir_vendor_id() != dqm->vendor_info.rcu_support_bitmask) ) { + // if we are programming TV codes but the previous AVR codes are from a different IRDB vendor, then clear out the AVR codes. + // the remote cannot send different codes from different IRDB vendors at the same time. + XLOGD_INFO("Programming TV codes from vendor %s(0x%X), but currently have AVR codes from %s(0x%X). Clearing AVR codes.", + dqm->vendor_info.name.c_str(), (unsigned int)dqm->vendor_info.rcu_support_bitmask, + ir_rf_database_.get_avr_ir_vendor_name().c_str(), (unsigned int)ir_rf_database_.get_avr_ir_vendor_id()); + + ir_rf_database_.clear_avr_ir_codes(); + + } else if (dqm->ir_codes->type == CTRLM_IRDB_DEV_TYPE_AVR && (ir_rf_database_.get_tv_ir_vendor_id() != 0 && ir_rf_database_.get_tv_ir_vendor_id() != dqm->vendor_info.rcu_support_bitmask) ) { + // if we are programming AVR codes but the previous TV codes are from a different IRDB vendor, then clear out the TV codes. + // the remote cannot send different codes from different IRDB vendors at the same time. + XLOGD_INFO("Programming AVR codes from vendor %s(0x%X), but currently have TV codes from %s(0x%X). Clearing TV codes.", + dqm->vendor_info.name.c_str(), (unsigned int)dqm->vendor_info.rcu_support_bitmask, + ir_rf_database_.get_tv_ir_vendor_name().c_str(), (unsigned int)ir_rf_database_.get_tv_ir_vendor_id()); + + ir_rf_database_.clear_tv_ir_codes(); + } + std::map> ir_codes; // First add IR Codes to the IR RF Database (this contains all of the logic for maintaining TV vs AVR codes) - ir_rf_database_.add_irdb_codes(dqm->ir_codes); + ir_rf_database_.add_irdb_codes(dqm->ir_codes, dqm->vendor_info.rcu_support_bitmask, dqm->vendor_info.name); XLOGD_INFO("\n%s", this->ir_rf_database_.to_string(false).c_str()); XLOGD_DEBUG("\n%s", this->ir_rf_database_.to_string(true).c_str()); // Now get the IR codes for the BLE IR slots diff --git a/src/database/ctrlm_database.cpp b/src/database/ctrlm_database.cpp index e28e4432..2e9e6e5c 100644 --- a/src/database/ctrlm_database.cpp +++ b/src/database/ctrlm_database.cpp @@ -71,7 +71,11 @@ using namespace std; #define CTRLM_DB_IR_COMMAND_REPEATS "ir_command_repeats" #define CTRLM_DB_DEVICE_UPDATE_SESSION_STATE "du_session_state" #define CTRLM_DB_TV_IR_CODE_ID "tv_ir_code_id" +#define CTRLM_DB_TV_IR_VENDOR_ID "tv_ir_vendor_id" +#define CTRLM_DB_TV_IR_VENDOR_NAME "tv_ir_vendor_name" #define CTRLM_DB_AVR_IR_CODE_ID "avr_ir_code_id" +#define CTRLM_DB_AVR_IR_VENDOR_ID "avr_ir_vendor_id" +#define CTRLM_DB_AVR_IR_VENDOR_NAME "avr_ir_vendor_name" #define CTRLM_DB_TABLE_VOICE "ctrlm_voice" @@ -706,11 +710,13 @@ void ctrlm_db_ir_command_repeats_read(guchar **data, guint32 *length) { ctrlm_db_read_blob(CTRLM_DB_TABLE_CTRLMGR, CTRLM_DB_IR_COMMAND_REPEATS, data, length); } -void ctrlm_db_tv_ir_code_id_write(const std::string id) { +void ctrlm_db_tv_ir_code_id_write(const std::string id, unsigned char vendor_id, const std::string vendor_name) { ctrlm_db_write_blob(CTRLM_DB_TABLE_CTRLMGR, CTRLM_DB_TV_IR_CODE_ID, (const guchar*) id.c_str(), id.length()); + ctrlm_db_write_uint64(CTRLM_DB_TABLE_CTRLMGR, CTRLM_DB_TV_IR_VENDOR_ID, vendor_id); + ctrlm_db_write_blob(CTRLM_DB_TABLE_CTRLMGR, CTRLM_DB_TV_IR_VENDOR_NAME, (const guchar*) vendor_name.c_str(), vendor_name.length()); } -void ctrlm_db_tv_ir_code_id_read(std::string &id) { +void ctrlm_db_tv_ir_code_id_read(std::string &id, unsigned char &vendor_id, std::string &vendor_name) { guchar *data = NULL; guint32 length = 0; ctrlm_db_read_blob(CTRLM_DB_TABLE_CTRLMGR, CTRLM_DB_TV_IR_CODE_ID, &data, &length); @@ -718,15 +724,31 @@ void ctrlm_db_tv_ir_code_id_read(std::string &id) { id.assign((char *)data, length); ctrlm_db_free(data); } else { - XLOGD_WARN("Failed to load tv_ir_code_id from db"); + XLOGD_WARN("Failed to load %s from db", CTRLM_DB_TV_IR_CODE_ID); + } + + guint64 vendor_id_64 = 0; + ctrlm_db_read_uint64(CTRLM_DB_TABLE_CTRLMGR, CTRLM_DB_TV_IR_VENDOR_ID, (sqlite_uint64*)&vendor_id_64); + vendor_id = vendor_id_64; + + data = NULL; + length = 0; + ctrlm_db_read_blob(CTRLM_DB_TABLE_CTRLMGR, CTRLM_DB_TV_IR_VENDOR_NAME, &data, &length); + if(NULL != data) { + vendor_name.assign((char *)data, length); + ctrlm_db_free(data); + } else { + XLOGD_WARN("Failed to load %s from db", CTRLM_DB_TV_IR_VENDOR_NAME); } } -void ctrlm_db_avr_ir_code_id_write(const std::string id) { +void ctrlm_db_avr_ir_code_id_write(const std::string id, unsigned char vendor_id, const std::string vendor_name) { ctrlm_db_write_blob(CTRLM_DB_TABLE_CTRLMGR, CTRLM_DB_AVR_IR_CODE_ID, (const guchar*) id.c_str(), id.length()); + ctrlm_db_write_uint64(CTRLM_DB_TABLE_CTRLMGR, CTRLM_DB_AVR_IR_VENDOR_ID, vendor_id); + ctrlm_db_write_blob(CTRLM_DB_TABLE_CTRLMGR, CTRLM_DB_AVR_IR_VENDOR_NAME, (const guchar*) vendor_name.c_str(), vendor_name.length()); } -void ctrlm_db_avr_ir_code_id_read(std::string &id) { +void ctrlm_db_avr_ir_code_id_read(std::string &id, unsigned char &vendor_id, std::string &vendor_name) { guchar *data = NULL; guint32 length = 0; ctrlm_db_read_blob(CTRLM_DB_TABLE_CTRLMGR, CTRLM_DB_AVR_IR_CODE_ID, &data, &length); @@ -734,7 +756,21 @@ void ctrlm_db_avr_ir_code_id_read(std::string &id) { id.assign((char *)data, length); ctrlm_db_free(data); } else { - XLOGD_WARN("Failed to load avr_ir_code_id from db"); + XLOGD_WARN("Failed to load %s from db", CTRLM_DB_AVR_IR_CODE_ID); + } + + guint64 vendor_id_64 = 0; + ctrlm_db_read_uint64(CTRLM_DB_TABLE_CTRLMGR, CTRLM_DB_AVR_IR_VENDOR_ID, (sqlite_uint64*)&vendor_id_64); + vendor_id = vendor_id_64; + + data = NULL; + length = 0; + ctrlm_db_read_blob(CTRLM_DB_TABLE_CTRLMGR, CTRLM_DB_AVR_IR_VENDOR_NAME, &data, &length); + if(NULL != data) { + vendor_name.assign((char *)data, length); + ctrlm_db_free(data); + } else { + XLOGD_WARN("Failed to load %s from db", CTRLM_DB_AVR_IR_VENDOR_NAME); } } diff --git a/src/database/ctrlm_database.h b/src/database/ctrlm_database.h index 4716b075..f842c71f 100644 --- a/src/database/ctrlm_database.h +++ b/src/database/ctrlm_database.h @@ -77,10 +77,10 @@ void ctrlm_db_chime_volume_write(guchar *data, guint32 length); void ctrlm_db_chime_volume_read(guchar **data, guint32 *length); void ctrlm_db_ir_command_repeats_write(guchar *data, guint32 length); void ctrlm_db_ir_command_repeats_read(guchar **data, guint32 *length); -void ctrlm_db_tv_ir_code_id_write(const std::string id); -void ctrlm_db_tv_ir_code_id_read(std::string &id); -void ctrlm_db_avr_ir_code_id_write(const std::string id); -void ctrlm_db_avr_ir_code_id_read(std::string &id); +void ctrlm_db_tv_ir_code_id_write(const std::string id, unsigned char vendor_id, const std::string vendor_name); +void ctrlm_db_tv_ir_code_id_read(std::string &id, unsigned char &vendor_id, std::string &vendor_name); +void ctrlm_db_avr_ir_code_id_write(const std::string id, unsigned char vendor_id, const std::string vendor_name); +void ctrlm_db_avr_ir_code_id_read(std::string &id, unsigned char &vendor_id, std::string &vendor_name); void ctrlm_db_rf4ce_networks_list(std::vector *network_ids); void ctrlm_db_rf4ce_controllers_list(ctrlm_network_id_t network_id, std::vector *controller_ids); diff --git a/src/network/ctrlm_ir_rf_db.cpp b/src/network/ctrlm_ir_rf_db.cpp index 126e57cb..6c821f5a 100644 --- a/src/network/ctrlm_ir_rf_db.cpp +++ b/src/network/ctrlm_ir_rf_db.cpp @@ -42,7 +42,11 @@ ctrlm_ir_rf_db_t::ctrlm_ir_rf_db_t(bool power_toggle_favor_tv, bool power_discre this->power_toggle_favor_tv = power_toggle_favor_tv; this->power_discrete_favor_tv = power_discrete_favor_tv; this->tv_ir_code_id_ = "0"; + this->tv_ir_vendor_id_ = 0; + this->tv_ir_vendor_name_ = "INVALID"; this->avr_ir_code_id_ = "0"; + this->avr_ir_vendor_id_ = 0; + this->avr_ir_vendor_name_ = "INVALID"; } ctrlm_ir_rf_db_t::~ctrlm_ir_rf_db_t() { @@ -174,17 +178,21 @@ ctrlm_key_code_t to_ctrlm_keycode(ctrlm_irdb_key_code_t irdb_code) { } } -bool ctrlm_ir_rf_db_t::add_irdb_codes(ctrlm_irdb_ir_code_set_t *ir_codes) { +bool ctrlm_ir_rf_db_t::add_irdb_codes(ctrlm_irdb_ir_code_set_t *ir_codes, unsigned char ir_vendor_id, const std::string &ir_vendor_name) { bool ret = false; if(ir_codes) { ctrlm_ir_rf_db_dev_type_t type = ctrlm_ir_rf_db_entry_t::type_from_irdb(ir_codes->type); switch(type) { case CTRLM_IR_RF_DB_DEV_TV: { this->tv_ir_code_id_ = ir_codes->id; + this->tv_ir_vendor_id_ = ir_vendor_id; + this->tv_ir_vendor_name_ = ir_vendor_name; break; } case CTRLM_IR_RF_DB_DEV_AVR: { this->avr_ir_code_id_ = ir_codes->id; + this->avr_ir_vendor_id_ = ir_vendor_id; + this->avr_ir_vendor_name_ = ir_vendor_name; break; } default: { @@ -205,52 +213,75 @@ bool ctrlm_ir_rf_db_t::add_irdb_codes(ctrlm_irdb_ir_code_set_t *ir_codes) { } void ctrlm_ir_rf_db_t::clear_tv_ir_codes() { + ctrlm_db_ir_rf_database_delete(CTRLM_KEY_CODE_TV_POWER_ON); this->remove_entry(CTRLM_KEY_CODE_TV_POWER_ON); + + ctrlm_db_ir_rf_database_delete(CTRLM_KEY_CODE_TV_POWER_OFF); this->remove_entry(CTRLM_KEY_CODE_TV_POWER_OFF); + + ctrlm_db_ir_rf_database_delete(CTRLM_KEY_CODE_TV_POWER); this->remove_entry(CTRLM_KEY_CODE_TV_POWER); + if(this->has_entry(CTRLM_KEY_CODE_VOL_UP)) { if(this->ir_rf_db[CTRLM_KEY_CODE_VOL_UP]->get_type() == CTRLM_IR_RF_DB_DEV_TV) { + ctrlm_db_ir_rf_database_delete(CTRLM_KEY_CODE_VOL_UP); this->remove_entry(CTRLM_KEY_CODE_VOL_UP); } } if(this->has_entry(CTRLM_KEY_CODE_VOL_DOWN)) { if(this->ir_rf_db[CTRLM_KEY_CODE_VOL_DOWN]->get_type() == CTRLM_IR_RF_DB_DEV_TV) { + ctrlm_db_ir_rf_database_delete(CTRLM_KEY_CODE_VOL_DOWN); this->remove_entry(CTRLM_KEY_CODE_VOL_DOWN); } } if(this->has_entry(CTRLM_KEY_CODE_MUTE)) { if(this->ir_rf_db[CTRLM_KEY_CODE_MUTE]->get_type() == CTRLM_IR_RF_DB_DEV_TV) { + ctrlm_db_ir_rf_database_delete(CTRLM_KEY_CODE_MUTE); this->remove_entry(CTRLM_KEY_CODE_MUTE); } } + ctrlm_db_ir_rf_database_delete(CTRLM_KEY_CODE_INPUT_SELECT); this->remove_entry(CTRLM_KEY_CODE_INPUT_SELECT); this->fix_common_slots_and_ir_flags(); this->tv_ir_code_id_ = "0"; + this->tv_ir_vendor_id_ = 0; + this->tv_ir_vendor_name_ = "INVALID"; } void ctrlm_ir_rf_db_t::clear_avr_ir_codes() { + ctrlm_db_ir_rf_database_delete(CTRLM_KEY_CODE_AVR_POWER_ON); this->remove_entry(CTRLM_KEY_CODE_AVR_POWER_ON); + + ctrlm_db_ir_rf_database_delete(CTRLM_KEY_CODE_AVR_POWER_OFF); this->remove_entry(CTRLM_KEY_CODE_AVR_POWER_OFF); + + ctrlm_db_ir_rf_database_delete(CTRLM_KEY_CODE_AVR_POWER_TOGGLE); this->remove_entry(CTRLM_KEY_CODE_AVR_POWER_TOGGLE); + if(this->has_entry(CTRLM_KEY_CODE_VOL_UP)) { if(this->ir_rf_db[CTRLM_KEY_CODE_VOL_UP]->get_type() == CTRLM_IR_RF_DB_DEV_AVR) { + ctrlm_db_ir_rf_database_delete(CTRLM_KEY_CODE_VOL_UP); this->remove_entry(CTRLM_KEY_CODE_VOL_UP); } } if(this->has_entry(CTRLM_KEY_CODE_VOL_DOWN)) { if(this->ir_rf_db[CTRLM_KEY_CODE_VOL_DOWN]->get_type() == CTRLM_IR_RF_DB_DEV_AVR) { + ctrlm_db_ir_rf_database_delete(CTRLM_KEY_CODE_VOL_DOWN); this->remove_entry(CTRLM_KEY_CODE_VOL_DOWN); } } if(this->has_entry(CTRLM_KEY_CODE_MUTE)) { if(this->ir_rf_db[CTRLM_KEY_CODE_MUTE]->get_type() == CTRLM_IR_RF_DB_DEV_AVR) { + ctrlm_db_ir_rf_database_delete(CTRLM_KEY_CODE_MUTE); this->remove_entry(CTRLM_KEY_CODE_MUTE); } } this->fix_common_slots_and_ir_flags(); this->avr_ir_code_id_ = "0"; + this->avr_ir_vendor_id_ = 0; + this->avr_ir_vendor_name_ = "INVALID"; } void ctrlm_ir_rf_db_t::clear_ir_codes() { @@ -259,7 +290,11 @@ void ctrlm_ir_rf_db_t::clear_ir_codes() { this->remove_entry(itr->first); } this->tv_ir_code_id_ = "0"; + this->tv_ir_vendor_id_ = 0; + this->tv_ir_vendor_name_ = "INVALID"; this->avr_ir_code_id_ = "0"; + this->avr_ir_vendor_id_ = 0; + this->avr_ir_vendor_name_ = "INVALID"; } ctrlm_ir_rf_db_entry_t *ctrlm_ir_rf_db_t::get_ir_code(ctrlm_key_code_t key) { @@ -274,7 +309,9 @@ std::string ctrlm_ir_rf_db_t::to_string(bool debug) const { std::stringstream ss; ss << "IR RF Database: "<< std::endl; ss << "\tTV IR Code ID <" << tv_ir_code_id_ << ">" << std::endl; + ss << "\tTV IR Vendor Info <" << tv_ir_vendor_name_ << ": " << (unsigned int)tv_ir_vendor_id_ << ">" << std::endl; ss << "\tAVR IR Code ID <" << avr_ir_code_id_ << ">" << std::endl; + ss << "\tAVR IR Vendor Info <" << avr_ir_vendor_name_ << ": " << (unsigned int)avr_ir_vendor_id_ << ">" << std::endl; for(auto itr = this->ir_rf_db.begin(); itr != this->ir_rf_db.end(); itr++) { if(itr->second != NULL) { ss << "\tKeySlot <" << ctrlm_key_code_str(itr->first) << ">, " << itr->second->to_string(debug) << std::endl; @@ -373,16 +410,16 @@ void ctrlm_ir_rf_db_t::load_db() { this->replace_entry(itr->first, entry); } } - ctrlm_db_tv_ir_code_id_read(tv_ir_code_id_); - ctrlm_db_avr_ir_code_id_read(avr_ir_code_id_); + ctrlm_db_tv_ir_code_id_read(tv_ir_code_id_, tv_ir_vendor_id_, tv_ir_vendor_name_); + ctrlm_db_avr_ir_code_id_read(avr_ir_code_id_, avr_ir_vendor_id_, avr_ir_vendor_name_); } bool ctrlm_ir_rf_db_t::store_db() { for(auto itr = this->ir_rf_db.begin(); itr != this->ir_rf_db.end(); itr++) { this->store_entry(itr->first); } - ctrlm_db_tv_ir_code_id_write(tv_ir_code_id_); - ctrlm_db_avr_ir_code_id_write(avr_ir_code_id_); + ctrlm_db_tv_ir_code_id_write(tv_ir_code_id_, tv_ir_vendor_id_, tv_ir_vendor_name_); + ctrlm_db_avr_ir_code_id_write(avr_ir_code_id_, avr_ir_vendor_id_, avr_ir_vendor_name_); return(true); // TODO, maybe change to void } @@ -449,7 +486,22 @@ std::string ctrlm_ir_rf_db_t::get_tv_ir_code_id() { return tv_ir_code_id_; } +unsigned char ctrlm_ir_rf_db_t::get_tv_ir_vendor_id() { + return tv_ir_vendor_id_; +} + +std::string ctrlm_ir_rf_db_t::get_tv_ir_vendor_name() { + return tv_ir_vendor_name_; +} + std::string ctrlm_ir_rf_db_t::get_avr_ir_code_id() { return avr_ir_code_id_; } +unsigned char ctrlm_ir_rf_db_t::get_avr_ir_vendor_id() { + return avr_ir_vendor_id_; +} + +std::string ctrlm_ir_rf_db_t::get_avr_ir_vendor_name() { + return avr_ir_vendor_name_; +} diff --git a/src/network/ctrlm_ir_rf_db.h b/src/network/ctrlm_ir_rf_db.h index 439bf1e0..d383e3d5 100644 --- a/src/network/ctrlm_ir_rf_db.h +++ b/src/network/ctrlm_ir_rf_db.h @@ -60,7 +60,7 @@ class ctrlm_ir_rf_db_t { * @param ir_codes A keymap supplied from the CTRLM IRDB component * @reutrn True if the entries were added to the IRRF Database, False otherwise. */ - bool add_irdb_codes(ctrlm_irdb_ir_code_set_t *ir_codes); + bool add_irdb_codes(ctrlm_irdb_ir_code_set_t *ir_codes, unsigned char ir_vendor_id = 0, const std::string &ir_vendor_name = ""); /** * Function to clear all TV IR codes stored in the IR RF Database @@ -120,11 +120,36 @@ class ctrlm_ir_rf_db_t { */ std::string get_tv_ir_code_id(); + /** + * Function used to get the TV IR vendor ID in the ControlMgr Database. + * @return the TV IR vendor ID as unsigned char + */ + unsigned char get_tv_ir_vendor_id(); + + /** + * Function used to get the TV IR vendor name in the ControlMgr Database. + * @return the TV IR vendor name in string form. + */ + std::string get_tv_ir_vendor_name(); + /** * Function used to get the AVR IR code ID in the ControlMgr Database. * @return the AVR IR code ID in string form. */ std::string get_avr_ir_code_id(); + + /** + * Function used to get the AVR IR vendor ID in the ControlMgr Database. + * @return the AVR IR vendor ID as unsigned char + */ + unsigned char get_avr_ir_vendor_id(); + + /** + * Function used to get the AVR IR vendor name in the ControlMgr Database. + * @return the AVR IR vendor name in string form. + */ + std::string get_avr_ir_vendor_name(); + private: /** @@ -157,7 +182,11 @@ class ctrlm_ir_rf_db_t { bool power_toggle_favor_tv; bool power_discrete_favor_tv; std::string tv_ir_code_id_; + unsigned char tv_ir_vendor_id_; + std::string tv_ir_vendor_name_; std::string avr_ir_code_id_; + unsigned char avr_ir_vendor_id_; + std::string avr_ir_vendor_name_; }; From 9667bf74d230cf610f5fa453820aef45ec894d38 Mon Sep 17 00:00:00 2001 From: Gene Gallagher Date: Mon, 8 Jun 2026 20:02:33 -0400 Subject: [PATCH 66/81] 1.1.17 release changelog updates --- CHANGELOG.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 27ed797d..7b2b696b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,23 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [1.1.17](https://github.com/rdkcentral/control/compare/1.1.16...1.1.17) + +> 8 June 2026 + +- RDKEMW-13898: prevent simultaneous irdb codes from different vendors [`#220`](https://github.com/rdkcentral/control/pull/220) +- RDKEMW-16966: T2 Events for IRDB Programming [`#239`](https://github.com/rdkcentral/control/pull/239) +- RDKEMW-18979: onStatus event to contain RCU data from all networks [`#238`](https://github.com/rdkcentral/control/pull/238) +- RDKEMW-13988: add new buttons for interim remote 2.0 support [`#234`](https://github.com/rdkcentral/control/pull/234) +- RDKEMW-4433: local server build option [`#57`](https://github.com/rdkcentral/control/pull/57) +- RDKEMW-15135: T2 RCU pairing [`#189`](https://github.com/rdkcentral/control/pull/189) +- RDKEMW-16814: reduce ble status prints and events [`#235`](https://github.com/rdkcentral/control/pull/235) +- RDKEMW-12856: throw early error when IRDB provides empty waveforms [`#236`](https://github.com/rdkcentral/control/pull/236) +- RDKEMW-14906 : VAD detector in Control Manager/Voice SDK [`#186`](https://github.com/rdkcentral/control/pull/186) +- RDKEMW-17620 : ctrlm rfc value groups not updating [`#219`](https://github.com/rdkcentral/control/pull/219) +- RDKEMW-18299 : only register SIGQUIT when process is interactive [`#229`](https://github.com/rdkcentral/control/pull/229) + + #### [1.1.16](https://github.com/rdkcentral/control/compare/1.1.15...1.1.16) > 8 May 2026 From 577091351e263fd8fcc67aeaf096714cbb6078bd Mon Sep 17 00:00:00 2001 From: Gene Gallagher <129112619+egalla204@users.noreply.github.com> Date: Tue, 16 Jun 2026 16:03:52 -0400 Subject: [PATCH 67/81] Revert "RDKEMW-14906 : VAD detector in Control Manager/Voice SDK (#186)" (#245) This reverts commit 5a6dbfbf88cdb7d62128a93b3990bdb595bc0141. --- include/ctrlm_ipc.h | 3 +- include/ctrlm_ipc_voice.h | 11 -- src/ctrlm_config_default.json | 4 +- src/telemetry/ctrlm_telemetry_markers.h | 16 +-- src/voice/ctrlm_voice_obj.cpp | 115 ++++++------------ src/voice/ctrlm_voice_obj.h | 73 ++++++----- src/voice/ctrlm_voice_obj_generic.cpp | 102 +++++++--------- src/voice/ipc/ctrlm_voice_ipc.h | 3 +- src/voice/ipc/ctrlm_voice_ipc_iarm_legacy.cpp | 12 -- .../ipc/ctrlm_voice_ipc_iarm_thunder.cpp | 16 --- .../ctrlm_voice_telemetry_events.cpp | 17 +-- .../telemetry/ctrlm_voice_telemetry_events.h | 6 +- 12 files changed, 127 insertions(+), 251 deletions(-) diff --git a/include/ctrlm_ipc.h b/include/ctrlm_ipc.h index 7d87d12c..32d0dea1 100644 --- a/include/ctrlm_ipc.h +++ b/include/ctrlm_ipc.h @@ -302,8 +302,7 @@ typedef enum { CTRLM_RCU_IARM_EVENT_RF4CE_PAIRING_WINDOW_TIMEOUT = 35, ///< Indicates that a battery milestone event occured CTRLM_RCU_IARM_EVENT_FIRMWARE_UPDATE_PROGRESS = 36, ///< Generated when an milestone is reached for remote firmware upgrade CTRLM_RCU_IARM_EVENT_VALIDATION_STATUS = 37, ///< Generated when the validation status changes - CTRLM_VOICE_IARM_EVENT_SESSION_SILENT = 38, ///< Voice session was silent (no speech detected) - CTRLM_MAIN_IARM_EVENT_MAX = 39 ///< Placeholder for the last event (used in registration) + CTRLM_MAIN_IARM_EVENT_MAX = 38 ///< Placeholder for the last event (used in registration) } ctrlm_main_iarm_event_t; /// @brief Remote Control Key Status diff --git a/include/ctrlm_ipc_voice.h b/include/ctrlm_ipc_voice.h index 4a912cad..ed96c951 100644 --- a/include/ctrlm_ipc_voice.h +++ b/include/ctrlm_ipc_voice.h @@ -281,16 +281,6 @@ typedef struct { long return_code_internal; ///< Internally generated return code } ctrlm_voice_iarm_event_session_short_t; -typedef struct { - unsigned char api_revision; ///< The revision of this API. - ctrlm_network_id_t network_id; ///< Identifier of network on which the controller is bound - ctrlm_network_type_t network_type; ///< Type of network on which the controller is bound - ctrlm_controller_id_t controller_id; ///< A unique identifier of the remote - unsigned long session_id; ///< A unique id for the voice session. - ctrlm_voice_session_end_reason_t reason; ///< The reason that the voice session was silent - long return_code_internal; ///< Internally generated return code -} ctrlm_voice_iarm_event_session_silent_t; - typedef struct { unsigned char api_revision; ///< The revision of this API char media_service_url[2083]; ///< The url for the media service (null terminated string) @@ -386,7 +376,6 @@ typedef struct { /// | CTRLM_MAIN_IARM_BUS_NAME | CTRLM_VOICE_IARM_EVENT_SESSION_STATS | ctrlm_voice_iarm_event_session_stats_t * | Generated when the statistics of the voice session are available | /// | CTRLM_MAIN_IARM_BUS_NAME | CTRLM_VOICE_IARM_EVENT_SESSION_ABORT | ctrlm_voice_iarm_event_session_abort_t * | Generated when a voice session is aborted (denied) | /// | CTRLM_MAIN_IARM_BUS_NAME | CTRLM_VOICE_IARM_EVENT_SESSION_SHORT | ctrlm_voice_iarm_event_session_short_t * | Generated when a short voice session is detected | -/// | CTRLM_MAIN_IARM_BUS_NAME | CTRLM_VOICE_IARM_EVENT_SESSION_SILENT | ctrlm_voice_iarm_event_session_silent_t * | Generated when a silent voice session is detected | /// | CTRLM_MAIN_IARM_BUS_NAME | CTRLM_VOICE_IARM_EVENT_MEDIA_SERVICE | ctrlm_voice_iarm_event_media_service_t * | Generated when a media service response is received | /// /// IARM events are available on a subscription basis. In order to receive an event, a client must explicitly register to receive the event by calling diff --git a/src/ctrlm_config_default.json b/src/ctrlm_config_default.json index 21aa49c6..af65c196 100755 --- a/src/ctrlm_config_default.json +++ b/src/ctrlm_config_default.json @@ -291,9 +291,7 @@ "par_voice_eos_method" : 1, "par_voice_eos_timeout" : 2500, "server_hosts" : [], - "telemetry_session_stats" : false, - "voice_activity_detection_mode" : "enabled" - + "telemetry_session_stats" : false }, "device_update" : { "dir_root" : "/srv/device_update/", diff --git a/src/telemetry/ctrlm_telemetry_markers.h b/src/telemetry/ctrlm_telemetry_markers.h index e9ba968b..f1314e0f 100644 --- a/src/telemetry/ctrlm_telemetry_markers.h +++ b/src/telemetry/ctrlm_telemetry_markers.h @@ -93,7 +93,7 @@ // The Voice Session Statistics Marker reports statistics for the voice session(s). The format of the marker is a json array of arrays with each event in the format below: // // [[event1], [event2], [event3], ...] -// [,,,,,,,,,,,,,,,,,,,,,,,,,] +// [,,,,,,,,,,,,,,,,,,,,] // // - Version of the marker format. // - Name of the device that started the session. @@ -111,19 +111,13 @@ // - lost samples. // - decoder failure count. // - sample buffer high watermark. -// - audio stream success/error code. -// - session success/error code. -// - server success/error code. +// - audio stream success/error code. +// - protocol success/error code. +// - server success/error code. // - server message. // - flag to indicate if session was successful. -// - reason why the stream ended (if available). -// - protocol return code. -// - flag to indicate if voice was detected. -// - peak confidence level. -// - peak RMS level. - #define MARKER_VOICE_SESSION_STATS "ctrlm.voice.session.stats" -#define MARKER_VOICE_SESSION_STATS_VERSION "3" +#define MARKER_VOICE_SESSION_STATS_VERSION "2" // End Voice Session Statistics diff --git a/src/voice/ctrlm_voice_obj.cpp b/src/voice/ctrlm_voice_obj.cpp index 7ddf515f..c81a629a 100644 --- a/src/voice/ctrlm_voice_obj.cpp +++ b/src/voice/ctrlm_voice_obj.cpp @@ -186,40 +186,39 @@ ctrlm_voice_t::ctrlm_voice_t() { #ifdef JSON_ARRAY_VAL_STR_VOICE_SERVER_HOSTS_3 this->url_hostname_pattern_add(JSON_ARRAY_VAL_STR_VOICE_SERVER_HOSTS_3); #endif - this->prefs.aspect_ratio = JSON_STR_VALUE_VOICE_ASPECT_RATIO; - this->prefs.guide_language = JSON_STR_VALUE_VOICE_LANGUAGE; - this->prefs.app_id_http = JSON_STR_VALUE_VOICE_APP_ID_HTTP; - this->prefs.app_id_ws = JSON_STR_VALUE_VOICE_APP_ID_WS; - this->prefs.timeout_vrex_connect = JSON_INT_VALUE_VOICE_VREX_REQUEST_TIMEOUT; - this->prefs.timeout_vrex_session = JSON_INT_VALUE_VOICE_VREX_RESPONSE_TIMEOUT; - this->prefs.timeout_stats = JSON_INT_VALUE_VOICE_TIMEOUT_STATS; - this->prefs.timeout_packet_initial = JSON_INT_VALUE_VOICE_TIMEOUT_PACKET_INITIAL; - this->prefs.timeout_packet_subsequent = JSON_INT_VALUE_VOICE_TIMEOUT_PACKET_SUBSEQUENT; - this->prefs.bitrate_minimum = JSON_INT_VALUE_VOICE_BITRATE_MINIMUM; - this->prefs.time_threshold = JSON_INT_VALUE_VOICE_TIME_THRESHOLD; - this->prefs.utterance_save = ctrlm_is_production_build() ? JSON_ARRAY_VAL_BOOL_VOICE_SAVE_LAST_UTTERANCE_0 : JSON_ARRAY_VAL_BOOL_VOICE_SAVE_LAST_UTTERANCE_1; - this->prefs.utterance_use_curtail = JSON_BOOL_VALUE_VOICE_UTTERANCE_USE_CURTAIL; - this->prefs.utterance_file_qty_max = JSON_INT_VALUE_VOICE_UTTERANCE_FILE_QTY_MAX; - this->prefs.utterance_file_size_max = JSON_INT_VALUE_VOICE_UTTERANCE_FILE_SIZE_MAX; - this->prefs.utterance_path = JSON_STR_VALUE_VOICE_UTTERANCE_PATH; - this->prefs.utterance_duration_min = JSON_INT_VALUE_VOICE_MINIMUM_DURATION; - this->prefs.ffv_leading_samples = JSON_INT_VALUE_VOICE_FFV_LEADING_SAMPLES; - this->prefs.voice_activity_detection_mode = this->voice_activity_detection_mode_to_xrsr(JSON_STR_VALUE_VOICE_VOICE_ACTIVITY_DETECTION_MODE); - this->prefs.force_voice_settings = JSON_BOOL_VALUE_VOICE_FORCE_VOICE_SETTINGS; - this->prefs.vrex_test_flag = JSON_BOOL_VALUE_VOICE_VREX_TEST_FLAG; - this->prefs.vrex_wuw_bypass_success_flag = JSON_BOOL_VALUE_VOICE_VREX_WUW_BYPASS_SUCCESS_FLAG; - this->prefs.vrex_wuw_bypass_failure_flag = JSON_BOOL_VALUE_VOICE_VREX_WUW_BYPASS_FAILURE_FLAG; - this->prefs.force_toggle_fallback = JSON_BOOL_VALUE_VOICE_FORCE_TOGGLE_FALLBACK; - this->prefs.telemetry_session_stats = JSON_BOOL_VALUE_VOICE_TELEMETRY_SESSION_STATS; - this->prefs.par_voice_enabled = false; - this->prefs.par_voice_eos_method = JSON_INT_VALUE_VOICE_PAR_VOICE_EOS_METHOD; - this->prefs.par_voice_eos_timeout = JSON_INT_VALUE_VOICE_PAR_VOICE_EOS_TIMEOUT; + this->prefs.aspect_ratio = JSON_STR_VALUE_VOICE_ASPECT_RATIO; + this->prefs.guide_language = JSON_STR_VALUE_VOICE_LANGUAGE; + this->prefs.app_id_http = JSON_STR_VALUE_VOICE_APP_ID_HTTP; + this->prefs.app_id_ws = JSON_STR_VALUE_VOICE_APP_ID_WS; + this->prefs.timeout_vrex_connect = JSON_INT_VALUE_VOICE_VREX_REQUEST_TIMEOUT; + this->prefs.timeout_vrex_session = JSON_INT_VALUE_VOICE_VREX_RESPONSE_TIMEOUT; + this->prefs.timeout_stats = JSON_INT_VALUE_VOICE_TIMEOUT_STATS; + this->prefs.timeout_packet_initial = JSON_INT_VALUE_VOICE_TIMEOUT_PACKET_INITIAL; + this->prefs.timeout_packet_subsequent = JSON_INT_VALUE_VOICE_TIMEOUT_PACKET_SUBSEQUENT; + this->prefs.bitrate_minimum = JSON_INT_VALUE_VOICE_BITRATE_MINIMUM; + this->prefs.time_threshold = JSON_INT_VALUE_VOICE_TIME_THRESHOLD; + this->prefs.utterance_save = ctrlm_is_production_build() ? JSON_ARRAY_VAL_BOOL_VOICE_SAVE_LAST_UTTERANCE_0 : JSON_ARRAY_VAL_BOOL_VOICE_SAVE_LAST_UTTERANCE_1; + this->prefs.utterance_use_curtail = JSON_BOOL_VALUE_VOICE_UTTERANCE_USE_CURTAIL; + this->prefs.utterance_file_qty_max = JSON_INT_VALUE_VOICE_UTTERANCE_FILE_QTY_MAX; + this->prefs.utterance_file_size_max = JSON_INT_VALUE_VOICE_UTTERANCE_FILE_SIZE_MAX; + this->prefs.utterance_path = JSON_STR_VALUE_VOICE_UTTERANCE_PATH; + this->prefs.utterance_duration_min = JSON_INT_VALUE_VOICE_MINIMUM_DURATION; + this->prefs.ffv_leading_samples = JSON_INT_VALUE_VOICE_FFV_LEADING_SAMPLES; + this->prefs.force_voice_settings = JSON_BOOL_VALUE_VOICE_FORCE_VOICE_SETTINGS; + this->prefs.vrex_test_flag = JSON_BOOL_VALUE_VOICE_VREX_TEST_FLAG; + this->prefs.vrex_wuw_bypass_success_flag = JSON_BOOL_VALUE_VOICE_VREX_WUW_BYPASS_SUCCESS_FLAG; + this->prefs.vrex_wuw_bypass_failure_flag = JSON_BOOL_VALUE_VOICE_VREX_WUW_BYPASS_FAILURE_FLAG; + this->prefs.force_toggle_fallback = JSON_BOOL_VALUE_VOICE_FORCE_TOGGLE_FALLBACK; + this->prefs.telemetry_session_stats = JSON_BOOL_VALUE_VOICE_TELEMETRY_SESSION_STATS; + this->prefs.par_voice_enabled = false; + this->prefs.par_voice_eos_method = JSON_INT_VALUE_VOICE_PAR_VOICE_EOS_METHOD; + this->prefs.par_voice_eos_timeout = JSON_INT_VALUE_VOICE_PAR_VOICE_EOS_TIMEOUT; this->voice_params_opus_encoder_default(); - this->xrsr_opened = false; - this->voice_ipc = NULL; - this->packet_loss_threshold = JSON_INT_VALUE_VOICE_PACKET_LOSS_THRESHOLD; - this->vsdk_config = NULL; - this->nsm_voice_session = false; + this->xrsr_opened = false; + this->voice_ipc = NULL; + this->packet_loss_threshold = JSON_INT_VALUE_VOICE_PACKET_LOSS_THRESHOLD; + this->vsdk_config = NULL; + this->nsm_voice_session = false; #ifndef TELEMETRY_SUPPORT XLOGD_WARN("telemetry is not enabled"); @@ -262,7 +261,6 @@ ctrlm_voice_t::ctrlm_voice_t() { this->secure_url_required = JSON_BOOL_VALUE_VOICE_REQUIRE_SECURE_URL; XLOGD_TELEMETRY("require i_SAT <%s> i_MTLS <%s> i_secure_url <%s>", this->sat_token_required ? "YES" : "NO", this->mtls_required ? "YES" : "NO", this->secure_url_required ? "YES" : "NO"); - XLOGD_INFO("voice activity detection mode <%s>", xrsr_stream_voice_activity_mode_str(this->prefs.voice_activity_detection_mode)); errno_t safec_rc = memset_s(this->sat_token, sizeof(this->sat_token), 0, sizeof(this->sat_token)); ERR_CHK(safec_rc); @@ -427,7 +425,6 @@ bool ctrlm_voice_t::voice_configure_config_file_json(json_t *obj_voice, json_t * conf.config_value_get(JSON_STR_NAME_VOICE_URL_SRC_MIC_TAP, this->prefs.server_url_src_mic_tap); conf.config_value_get(JSON_STR_NAME_VOICE_LANGUAGE, this->prefs.guide_language); conf.config_value_get(JSON_INT_NAME_VOICE_MINIMUM_DURATION, this->prefs.utterance_duration_min); - if(conf.config_value_get(JSON_BOOL_NAME_VOICE_ENABLE_SAT, this->sat_token_required)) { ctrlm_sm_voice_sat_enable_write(this->sat_token_required); XLOGD_TELEMETRY("require c_SAT <%s>", this->sat_token_required ? "YES" : "NO"); @@ -435,12 +432,6 @@ bool ctrlm_voice_t::voice_configure_config_file_json(json_t *obj_voice, json_t * conf.config_value_get(JSON_STR_NAME_VOICE_ASPECT_RATIO, this->prefs.aspect_ratio); } - std::string voice_activity_detection_mode; - if(conf.config_value_get(JSON_STR_NAME_VOICE_VOICE_ACTIVITY_DETECTION_MODE, voice_activity_detection_mode)) { - this->prefs.voice_activity_detection_mode = this->voice_activity_detection_mode_to_xrsr(voice_activity_detection_mode); - XLOGD_INFO("voice activity detection mode <%s>", xrsr_stream_voice_activity_mode_str(this->prefs.voice_activity_detection_mode)); - } - std::vector obj_server_hosts; if(conf.config_value_get(JSON_ARRAY_NAME_VOICE_SERVER_HOSTS, obj_server_hosts)) { this->url_hostname_patterns(obj_server_hosts); @@ -1098,17 +1089,6 @@ void ctrlm_voice_t::voice_params_opus_encoder_default(void) { this->voice_params_opus_samples_per_packet_set(); } -xrsr_stream_voice_activity_mode_t ctrlm_voice_t::voice_activity_detection_mode_to_xrsr(const std::string &mode) { - // Configure voice activity detection parameters based on mode - if(mode == "enabled") { // Voice activity detection will be used but not enforced - return(XRSR_STREAM_VOICE_ACTIVITY_MODE_ENABLED); - } else if(mode == "enforced") { // Voice session will only proceed if voice activity is detected - return(XRSR_STREAM_VOICE_ACTIVITY_MODE_ENFORCED); - } - // Voice activity detection is disabled (or invalid mode) - return(XRSR_STREAM_VOICE_ACTIVITY_MODE_DISABLED); -} - void ctrlm_voice_t::voice_params_opus_samples_per_packet_set(void) { guchar fr_dur = (this->prefs.opus_encoder_params[3] >> 4) & 0xF; switch(fr_dur) { @@ -2669,12 +2649,6 @@ void ctrlm_voice_t::voice_session_end_callback(ctrlm_voice_session_end_cb_t *ses end.result = SESSION_END_SHORT_UTTERANCE; end.reason = (int)session->end_reason_rcu; this->voice_ipc->session_end(end); - } else if(stats->session_end_reason == XRSR_SESSION_END_REASON_ERROR_AUDIO_SILENT) { - ctrlm_voice_ipc_event_session_end_t end; - end.common = session->ipc_common_data; - end.result = SESSION_END_SILENT_UTTERANCE; - end.reason = (int)session->end_reason_rcu; - this->voice_ipc->session_end(end); } else { ctrlm_voice_ipc_event_session_end_server_stats_t server_stats; ctrlm_voice_ipc_event_session_end_t end; @@ -2959,20 +2933,9 @@ void ctrlm_voice_t::voice_stream_end_callback(ctrlm_voice_stream_end_cb_t *strea } XLOGD_AUTOMATION_TELEMETRY("src <%s> Packets Lost/Total <%u/%u> %.02f%% duration <%u> ms", ctrlm_voice_device_str(session->voice_device), session->packets_lost, session->packets_lost + session->packets_processed, 100.0 * ((double)session->packets_lost / (double)(session->packets_lost + session->packets_processed)), stream_duration); #ifdef TELEMETRY_SUPPORT - uint32_t packets_total = session->packets_lost + session->packets_processed; - int32_t voice_detected = -1; - uint32_t peak_confidence = 0; - int32_t peak_rms_level = 0; - if(stats->audio_stats.vad_frames_processed > 0) { - voice_detected = (stats->audio_stats.vad_voice_detected) ? 1 : 0; - peak_confidence = (stats->audio_stats.vad_confidence_peak * 100); - peak_rms_level = stats->audio_stats.vad_rms_level_peak; - - XLOGD_INFO("VAD frames <%u> voice detected <%s> confidence peak <%u%%> rms level peak <%d dB>", stats->audio_stats.vad_frames_processed, voice_detected == 1 ? "YES" : "NO", peak_confidence, peak_rms_level); - } - if(this->prefs.telemetry_session_stats) { - session->telemetry_session_stats.update_on_stream_end(stream_duration, packets_total, session->packets_lost, packets_total * samples_per_packet, session->packets_lost * samples_per_packet, decoder_failures, 0, voice_detected, peak_confidence, peak_rms_level); + uint32_t packets_total = session->packets_lost + session->packets_processed; + session->telemetry_session_stats.update_on_stream_end(stream_duration, packets_total, session->packets_lost, packets_total * samples_per_packet, session->packets_lost * samples_per_packet, decoder_failures, 0); } #endif } else if(samples_processed > 0) { @@ -2980,7 +2943,7 @@ void ctrlm_voice_t::voice_stream_end_callback(ctrlm_voice_stream_end_cb_t *strea XLOGD_INFO("src <%s> Samples Lost/Total <%u/%u> %.02f%% buffered max <%u> duration <%u> ms", ctrlm_voice_device_str(session->voice_device), samples_lost, samples_lost + samples_processed, 100.0 * ((double)samples_lost / (double)(samples_lost + samples_processed)), samples_buffered_max, stream_duration); #ifdef TELEMETRY_SUPPORT if(this->prefs.telemetry_session_stats) { - session->telemetry_session_stats.update_on_stream_end(stream_duration, 0, 0, samples_lost + samples_processed, samples_lost, decoder_failures, samples_buffered_max, -1, 0, 0); + session->telemetry_session_stats.update_on_stream_end(stream_duration, 0, 0, samples_lost + samples_processed, samples_lost, decoder_failures, samples_buffered_max); } #endif } @@ -4115,14 +4078,6 @@ void ctrlm_voice_t::voice_rfc_retrieved_handler(const ctrlm_rfc_attr_t& attr) { routing_config_updated |= attr.get_rfc_value(JSON_BOOL_NAME_VOICE_DST_PARAMS_LOW_LATENCY_IPV4_FALLBACK, this->prefs.dst_params_low_latency.ipv4_fallback); routing_config_updated |= attr.get_rfc_value(JSON_INT_NAME_VOICE_DST_PARAMS_LOW_LATENCY_BACKOFF_DELAY, this->prefs.dst_params_low_latency.backoff_delay); - - std::string voice_activity_detection_mode; - if(attr.get_rfc_value(JSON_STR_NAME_VOICE_VOICE_ACTIVITY_DETECTION_MODE, voice_activity_detection_mode)) { - this->prefs.voice_activity_detection_mode = this->voice_activity_detection_mode_to_xrsr(voice_activity_detection_mode); - XLOGD_INFO("voice activity detection mode <%s>", xrsr_stream_voice_activity_mode_str(this->prefs.voice_activity_detection_mode)); - routing_config_updated = true; - } - std::vector obj_server_hosts; if(attr.get_rfc_value(JSON_ARRAY_NAME_VOICE_SERVER_HOSTS, obj_server_hosts)) { this->url_hostname_patterns(obj_server_hosts); diff --git a/src/voice/ctrlm_voice_obj.h b/src/voice/ctrlm_voice_obj.h index 9c0bc4be..3ec217b2 100644 --- a/src/voice/ctrlm_voice_obj.h +++ b/src/voice/ctrlm_voice_obj.h @@ -273,42 +273,41 @@ typedef struct { // End Event Callback Structures typedef struct { - std::string server_url_src_ptt; - std::string server_url_src_ff; - std::string server_url_src_mic_tap; - std::vector server_hosts; - std::string aspect_ratio; - std::string guide_language; - std::string app_id_http; - std::string app_id_ws; - unsigned long timeout_vrex_connect; - unsigned long timeout_vrex_session; - unsigned long timeout_stats; - unsigned long timeout_packet_initial; - unsigned long timeout_packet_subsequent; - guchar bitrate_minimum; - guint16 time_threshold; - bool utterance_save; - bool utterance_use_curtail; - unsigned long utterance_file_qty_max; - unsigned long utterance_file_size_max; - std::string utterance_path; - unsigned long utterance_duration_min; - unsigned long ffv_leading_samples; - xrsr_stream_voice_activity_mode_t voice_activity_detection_mode; - bool force_voice_settings; - bool vrex_test_flag; - bool vrex_wuw_bypass_success_flag; - bool vrex_wuw_bypass_failure_flag; - std::string opus_encoder_params_str; - uint8_t opus_encoder_params[CTRLM_RCU_RIB_ATTR_LEN_OPUS_ENCODING_PARAMS]; - bool force_toggle_fallback; - bool telemetry_session_stats; - xrsr_dst_params_t dst_params_standby; - xrsr_dst_params_t dst_params_low_latency; - bool par_voice_enabled; - uint8_t par_voice_eos_method; - uint16_t par_voice_eos_timeout; + std::string server_url_src_ptt; + std::string server_url_src_ff; + std::string server_url_src_mic_tap; + std::vector server_hosts; + std::string aspect_ratio; + std::string guide_language; + std::string app_id_http; + std::string app_id_ws; + unsigned long timeout_vrex_connect; + unsigned long timeout_vrex_session; + unsigned long timeout_stats; + unsigned long timeout_packet_initial; + unsigned long timeout_packet_subsequent; + guchar bitrate_minimum; + guint16 time_threshold; + bool utterance_save; + bool utterance_use_curtail; + unsigned long utterance_file_qty_max; + unsigned long utterance_file_size_max; + std::string utterance_path; + unsigned long utterance_duration_min; + unsigned long ffv_leading_samples; + bool force_voice_settings; + bool vrex_test_flag; + bool vrex_wuw_bypass_success_flag; + bool vrex_wuw_bypass_failure_flag; + std::string opus_encoder_params_str; + uint8_t opus_encoder_params[CTRLM_RCU_RIB_ATTR_LEN_OPUS_ENCODING_PARAMS]; + bool force_toggle_fallback; + bool telemetry_session_stats; + xrsr_dst_params_t dst_params_standby; + xrsr_dst_params_t dst_params_low_latency; + bool par_voice_enabled; + uint8_t par_voice_eos_method; + uint16_t par_voice_eos_timeout; } voice_session_prefss_t; typedef struct { @@ -638,8 +637,6 @@ class ctrlm_voice_t { bool voice_params_opus_encoder_validate(std::string &opus_encoder_params_str); void voice_params_opus_samples_per_packet_set(void); bool voice_params_hex_str_to_bytes(std::string hex_string, guchar *data, guint32 length); - - xrsr_stream_voice_activity_mode_t voice_activity_detection_mode_to_xrsr(const std::string &mode); bool voice_session_can_request(ctrlm_voice_device_t device); void voice_session_set_active(ctrlm_voice_device_t device); diff --git a/src/voice/ctrlm_voice_obj_generic.cpp b/src/voice/ctrlm_voice_obj_generic.cpp index 948d6039..4cb35f99 100644 --- a/src/voice/ctrlm_voice_obj_generic.cpp +++ b/src/voice/ctrlm_voice_obj_generic.cpp @@ -172,17 +172,12 @@ void ctrlm_voice_generic_t::voice_sdk_update_routes() { xrsr_src_t src = (xrsr_src_t)j; ctrlm_voice_device_t src_device = xrsr_to_voice_device(src); std::string *url = NULL; - - xrsr_stream_voice_activity_mode_t stream_vad_mode = XRSR_STREAM_VOICE_ACTIVITY_MODE_DISABLED; sem_wait(&this->device_status_semaphore); if(this->device_status[src_device] != CTRLM_VOICE_DEVICE_STATUS_DISABLED && this->device_status[src_device] != CTRLM_VOICE_DEVICE_STATUS_NOT_SUPPORTED) { switch(src_device) { case CTRLM_VOICE_DEVICE_PTT: { url = &this->prefs.server_url_src_ptt; - - // For PTT source, use the configured VAD mode which may be disabled, enabled, or enforced - stream_vad_mode = this->prefs.voice_activity_detection_mode; break; } case CTRLM_VOICE_DEVICE_MICROPHONE: @@ -237,16 +232,15 @@ void ctrlm_voice_generic_t::voice_sdk_update_routes() { if(!this->obj_ws_nextgen->get_handlers(&handlers_xrsr)) { XLOGD_ERROR("failed to get handlers ws"); } else { - routes[i].src = src; - routes[i].dst_qty = 1; - routes[i].dsts[0].url = urls_translated[translated_index].c_str(); - routes[i].dsts[0].handlers = handlers_xrsr; - routes[i].dsts[0].formats = XRSR_AUDIO_FORMAT_PCM; - routes[i].dsts[0].stream_time_min = this->prefs.utterance_duration_min; - routes[i].dsts[0].stream_vad_mode = stream_vad_mode; - routes[i].dsts[0].stream_from = stream_from; - routes[i].dsts[0].stream_offset = stream_offset; - routes[i].dsts[0].stream_until = stream_until; + routes[i].src = src; + routes[i].dst_qty = 1; + routes[i].dsts[0].url = urls_translated[translated_index].c_str(); + routes[i].dsts[0].handlers = handlers_xrsr; + routes[i].dsts[0].formats = XRSR_AUDIO_FORMAT_PCM; + routes[i].dsts[0].stream_time_min = this->prefs.utterance_duration_min; + routes[i].dsts[0].stream_from = stream_from; + routes[i].dsts[0].stream_offset = stream_offset; + routes[i].dsts[0].stream_until = stream_until; if(networked_standby_supported && (src == XRSR_SRC_MICROPHONE)) { routes[i].dsts[0].params[XRSR_POWER_MODE_LOW] = &this->prefs.dst_params_standby; } @@ -270,16 +264,15 @@ void ctrlm_voice_generic_t::voice_sdk_update_routes() { if(!this->obj_ws_nsp->get_handlers(&handlers_xrsr)) { XLOGD_ERROR("failed to get handlers ws"); } else { - routes[i].src = src; - routes[i].dst_qty = 1; - routes[i].dsts[0].url = urls_translated[translated_index].c_str(); - routes[i].dsts[0].handlers = handlers_xrsr; - routes[i].dsts[0].formats = XRSR_AUDIO_FORMAT_PCM | XRSR_AUDIO_FORMAT_PCM_32_BIT | XRSR_AUDIO_FORMAT_PCM_32_BIT_MULTI | XRSR_AUDIO_FORMAT_PCM_RAW; - routes[i].dsts[0].stream_time_min = 0; - routes[i].dsts[0].stream_vad_mode = XRSR_STREAM_VOICE_ACTIVITY_MODE_DISABLED; - routes[i].dsts[0].stream_from = XRSR_STREAM_FROM_LIVE; - routes[i].dsts[0].stream_offset = 0; - routes[i].dsts[0].stream_until = XRSR_STREAM_UNTIL_END_OF_STREAM; + routes[i].src = src; + routes[i].dst_qty = 1; + routes[i].dsts[0].url = urls_translated[translated_index].c_str(); + routes[i].dsts[0].handlers = handlers_xrsr; + routes[i].dsts[0].formats = XRSR_AUDIO_FORMAT_PCM | XRSR_AUDIO_FORMAT_PCM_32_BIT | XRSR_AUDIO_FORMAT_PCM_32_BIT_MULTI | XRSR_AUDIO_FORMAT_PCM_RAW; + routes[i].dsts[0].stream_time_min = 0; + routes[i].dsts[0].stream_from = XRSR_STREAM_FROM_LIVE; + routes[i].dsts[0].stream_offset = 0; + routes[i].dsts[0].stream_until = XRSR_STREAM_UNTIL_END_OF_STREAM; if(networked_standby_supported && (src == XRSR_SRC_MICROPHONE)) { routes[i].dsts[0].params[XRSR_POWER_MODE_LOW] = &this->prefs.dst_params_standby; } @@ -312,20 +305,19 @@ void ctrlm_voice_generic_t::voice_sdk_update_routes() { url->append("speech?"); } - routes[i].src = src; - routes[i].dst_qty = 1; - routes[i].dsts[0].url = url->c_str(); - routes[i].dsts[0].handlers = handlers_xrsr; + routes[i].src = src; + routes[i].dst_qty = 1; + routes[i].dsts[0].url = url->c_str(); + routes[i].dsts[0].handlers = handlers_xrsr; #ifdef AUDIO_DECODE - routes[i].dsts[0].formats = XRSR_AUDIO_FORMAT_PCM; + routes[i].dsts[0].formats = XRSR_AUDIO_FORMAT_PCM; #else - routes[i].dsts[0].formats = XRSR_AUDIO_FORMAT_PCM | XRSR_AUDIO_FORMAT_ADPCM; + routes[i].dsts[0].formats = XRSR_AUDIO_FORMAT_PCM | XRSR_AUDIO_FORMAT_ADPCM; #endif - routes[i].dsts[0].stream_time_min = this->prefs.utterance_duration_min; - routes[i].dsts[0].stream_vad_mode = stream_vad_mode; - routes[i].dsts[0].stream_from = stream_from; - routes[i].dsts[0].stream_offset = stream_offset; - routes[i].dsts[0].stream_until = stream_until; + routes[i].dsts[0].stream_time_min = this->prefs.utterance_duration_min; + routes[i].dsts[0].stream_from = stream_from; + routes[i].dsts[0].stream_offset = stream_offset; + routes[i].dsts[0].stream_until = stream_until; if(networked_standby_supported && (src == XRSR_SRC_MICROPHONE)) { routes[i].dsts[0].params[XRSR_POWER_MODE_LOW] = &this->prefs.dst_params_standby; } @@ -342,16 +334,15 @@ void ctrlm_voice_generic_t::voice_sdk_update_routes() { XLOGD_ERROR("failed to get handlers ws"); } else { - routes[i].src = src; - routes[i].dst_qty = 1; - routes[i].dsts[0].url = url->c_str(); - routes[i].dsts[0].handlers = handlers_xrsr; - routes[i].dsts[0].formats = XRSR_AUDIO_FORMAT_PCM; - routes[i].dsts[0].stream_time_min = this->prefs.utterance_duration_min; - routes[i].dsts[0].stream_vad_mode = stream_vad_mode; - routes[i].dsts[0].stream_from = stream_from; - routes[i].dsts[0].stream_offset = stream_offset; - routes[i].dsts[0].stream_until = stream_until; + routes[i].src = src; + routes[i].dst_qty = 1; + routes[i].dsts[0].url = url->c_str(); + routes[i].dsts[0].handlers = handlers_xrsr; + routes[i].dsts[0].formats = XRSR_AUDIO_FORMAT_PCM; + routes[i].dsts[0].stream_time_min = this->prefs.utterance_duration_min; + routes[i].dsts[0].stream_from = stream_from; + routes[i].dsts[0].stream_offset = stream_offset; + routes[i].dsts[0].stream_until = stream_until; if(networked_standby_supported && (src == XRSR_SRC_MICROPHONE)) { routes[i].dsts[0].params[XRSR_POWER_MODE_LOW] = &this->prefs.dst_params_standby; } @@ -366,16 +357,15 @@ void ctrlm_voice_generic_t::voice_sdk_update_routes() { XLOGD_ERROR("failed to get handlers ws"); } else { - routes[i].src = src; - routes[i].dst_qty = 1; - routes[i].dsts[0].url = urls_translated[translated_index].c_str(); - routes[i].dsts[0].handlers = handlers_xrsr; - routes[i].dsts[0].formats = XRSR_AUDIO_FORMAT_PCM; - routes[i].dsts[0].stream_time_min = this->prefs.utterance_duration_min; - routes[i].dsts[0].stream_vad_mode = stream_vad_mode; - routes[i].dsts[0].stream_from = stream_from; - routes[i].dsts[0].stream_offset = stream_offset; - routes[i].dsts[0].stream_until = stream_until; + routes[i].src = src; + routes[i].dst_qty = 1; + routes[i].dsts[0].url = urls_translated[translated_index].c_str(); + routes[i].dsts[0].handlers = handlers_xrsr; + routes[i].dsts[0].formats = XRSR_AUDIO_FORMAT_PCM; + routes[i].dsts[0].stream_time_min = this->prefs.utterance_duration_min; + routes[i].dsts[0].stream_from = stream_from; + routes[i].dsts[0].stream_offset = stream_offset; + routes[i].dsts[0].stream_until = stream_until; if(networked_standby_supported && (src == XRSR_SRC_MICROPHONE)) { routes[i].dsts[0].params[XRSR_POWER_MODE_LOW] = &this->prefs.dst_params_standby; } diff --git a/src/voice/ipc/ctrlm_voice_ipc.h b/src/voice/ipc/ctrlm_voice_ipc.h index db8dc582..969a8380 100644 --- a/src/voice/ipc/ctrlm_voice_ipc.h +++ b/src/voice/ipc/ctrlm_voice_ipc.h @@ -92,8 +92,7 @@ typedef enum { SESSION_END_SUCCESS, SESSION_END_FAILURE, SESSION_END_ABORT, - SESSION_END_SHORT_UTTERANCE, - SESSION_END_SILENT_UTTERANCE + SESSION_END_SHORT_UTTERANCE } ctrlm_voice_ipc_event_session_end_result_t; typedef struct { diff --git a/src/voice/ipc/ctrlm_voice_ipc_iarm_legacy.cpp b/src/voice/ipc/ctrlm_voice_ipc_iarm_legacy.cpp index 25b2c8d6..88fbd3b0 100644 --- a/src/voice/ipc/ctrlm_voice_ipc_iarm_legacy.cpp +++ b/src/voice/ipc/ctrlm_voice_ipc_iarm_legacy.cpp @@ -158,18 +158,6 @@ bool ctrlm_voice_ipc_iarm_legacy_t::session_end(const ctrlm_voice_ipc_event_sess ret = broadcast_iarm_event_legacy(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_SESSION_SHORT, &event, sizeof(event)); break; } - case SESSION_END_SILENT_UTTERANCE: { - ctrlm_voice_iarm_event_session_silent_t event = {0}; - event.api_revision = CTRLM_VOICE_IARM_BUS_API_REVISION; - event.network_id = session_end.common.network_id; - event.network_type = session_end.common.network_type; - event.controller_id = session_end.common.controller_id; - event.session_id = session_end.common.session_id_ctrlm; - event.reason = (ctrlm_voice_session_end_reason_t)session_end.reason; - event.return_code_internal = session_end.return_code_internal; - ret = broadcast_iarm_event_legacy(CTRLM_MAIN_IARM_BUS_NAME, CTRLM_VOICE_IARM_EVENT_SESSION_SILENT, &event, sizeof(event)); - break; - } } } // Reset state diff --git a/src/voice/ipc/ctrlm_voice_ipc_iarm_thunder.cpp b/src/voice/ipc/ctrlm_voice_ipc_iarm_thunder.cpp index b148dda5..6b407173 100644 --- a/src/voice/ipc/ctrlm_voice_ipc_iarm_thunder.cpp +++ b/src/voice/ipc/ctrlm_voice_ipc_iarm_thunder.cpp @@ -62,7 +62,6 @@ #define JSON_SESSION_END_RESULT_ERROR "error" #define JSON_SESSION_END_RESULT_ABORT "abort" #define JSON_SESSION_END_RESULT_SHORT "shortUtterance" -#define JSON_SESSION_END_RESULT_SILENT "silentUtterance" #define JSON_SESSION_END_TRANSCRIPTION "transcription" #define JSON_SESSION_END_PROTOCOL_ERROR "protocolErrorCode" #define JSON_SESSION_END_PROTOCOL_LIBRARY_ERROR "protocolLibraryErrorCode" @@ -72,7 +71,6 @@ #define JSON_SESSION_END_ERROR_REASON "reason" #define JSON_SESSION_END_ABORT_REASON "reason" #define JSON_SESSION_END_SHORT_REASON "reason" -#define JSON_SESSION_END_SILENT_REASON "reason" #define JSON_SESSION_END_STB_STATS "stbStats" #define JSON_SESSION_END_STB_STATS_TYPE "type" #define JSON_SESSION_END_STB_STATS_FIRMWARE "firmware" @@ -293,20 +291,6 @@ bool ctrlm_voice_ipc_iarm_thunder_t::session_end(const ctrlm_voice_ipc_event_ses } break; } - case SESSION_END_SILENT_UTTERANCE: { - int rc_silent; - rc |= json_object_set_new_nocheck(event_data, JSON_SESSION_END_RESULT, json_string(JSON_SESSION_END_RESULT_SILENT)); - - // Add Audio Silent Data to result object - rc_silent = json_object_set_new_nocheck(event_result, JSON_SESSION_END_SILENT_REASON, json_integer(session_end.reason)); - if(0 != rc_silent) { - XLOGD_ERROR("Error creating audio silent JSON subobject"); - JSON_DEREFERENCE(event_result); - } else { - rc |= json_object_set_new_nocheck(event_data, JSON_SESSION_END_RESULT_SILENT, event_result); - } - break; - } } if(session_end.stb_stats) { int stats_rc; diff --git a/src/voice/telemetry/ctrlm_voice_telemetry_events.cpp b/src/voice/telemetry/ctrlm_voice_telemetry_events.cpp index 041d420a..d5f6bba3 100644 --- a/src/voice/telemetry/ctrlm_voice_telemetry_events.cpp +++ b/src/voice/telemetry/ctrlm_voice_telemetry_events.cpp @@ -212,10 +212,7 @@ bool ctrlm_voice_telemetry_session_t::event() { ss << "\"" << m_server_message << "\","; ss << m_result << ","; ss << m_end_reason_stream << ","; - ss << m_ret_code_protocol << ","; - ss << m_voice_detected << ","; - ss << m_peak_confidence << ","; - ss << m_peak_rms_level << "]]"; + ss << m_ret_code_protocol << "]]"; if(m_event_list.length() + ss.str().length() > m_event_list_max_size) { // Maximum data size exceeded XLOGD_WARN("telemetry event exceeds max size <%s,%s>", val_marker.c_str(), ss.str().c_str()); @@ -270,7 +267,7 @@ void ctrlm_voice_telemetry_session_t::update_on_key_release(int32_t time_start_l m_has_key_release = true; } -void ctrlm_voice_telemetry_session_t::update_on_stream_end(uint32_t time_stream_len_act, uint32_t packets_total, uint32_t packets_lost, uint32_t samples_total, uint32_t samples_lost, uint32_t decoder_failures, uint32_t samples_buffered_max, int32_t voice_detected, uint32_t peak_confidence, int32_t peak_rms_level) { +void ctrlm_voice_telemetry_session_t::update_on_stream_end(uint32_t time_stream_len_act, uint32_t packets_total, uint32_t packets_lost, uint32_t samples_total, uint32_t samples_lost, uint32_t decoder_failures, uint32_t samples_buffered_max) { m_time_stream_len_act = time_stream_len_act; m_packets_total = packets_total; m_packets_lost = packets_lost; @@ -279,12 +276,6 @@ void ctrlm_voice_telemetry_session_t::update_on_stream_end(uint32_t time_stream_ m_decoder_failures = decoder_failures; m_samples_buffered_max = samples_buffered_max; - if(voice_detected >= 0) { - m_voice_detected = voice_detected; - m_peak_confidence = peak_confidence; - m_peak_rms_level = peak_rms_level; - } - if(m_has_key_release) { m_time_stream_delta = m_time_stream_len_act - m_time_stream_len_exp; } @@ -329,10 +320,6 @@ void ctrlm_voice_telemetry_session_t::reset_stats() { m_result = false; m_ret_code_protocol = 0; - m_voice_detected = -1; - m_peak_confidence = 0; - m_peak_rms_level = 0; - m_server_message.clear(); m_device_type.clear(); m_device_version.clear(); diff --git a/src/voice/telemetry/ctrlm_voice_telemetry_events.h b/src/voice/telemetry/ctrlm_voice_telemetry_events.h index f6f10127..93badb20 100644 --- a/src/voice/telemetry/ctrlm_voice_telemetry_events.h +++ b/src/voice/telemetry/ctrlm_voice_telemetry_events.h @@ -75,7 +75,7 @@ class ctrlm_voice_telemetry_session_t : public ctrlm_telemetry_event_t Date: Wed, 17 Jun 2026 09:27:52 -0400 Subject: [PATCH 68/81] 1.1.18 release changelog updates --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b2b696b..b1103259 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,13 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [1.1.18](https://github.com/rdkcentral/control/compare/1.1.17...1.1.18) + +> 17 June 2026 + +- Revert "RDKEMW-14906 : VAD detector in Control Manager/Voice SDK (#186)" [`#245`](https://github.com/rdkcentral/control/pull/245) + + #### [1.1.17](https://github.com/rdkcentral/control/compare/1.1.16...1.1.17) > 8 June 2026 From 61a6d570ac661084114864676294e07afb40ded4 Mon Sep 17 00:00:00 2001 From: dwolaver <44593664+dwolaver@users.noreply.github.com> Date: Thu, 25 Jun 2026 10:59:00 -0400 Subject: [PATCH 69/81] RDKEMW-20361 : ctrlm branch name print in logs not correct (#248) --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b9cdf593..00266a6f 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -264,7 +264,7 @@ install(FILES ${CMAKE_BINARY_DIR}/ctrlm_config.json DESTINATION ${CMAKE_INSTALL_ # GENERATED FILES add_custom_command( OUTPUT ctrlm_version_build.h COMMAND echo -n "#define CTRLM_MAIN_BRANCH \"" >> ctrlm_version_build.h - COMMAND git -C ${CMAKE_CURRENT_SOURCE_DIR} branch --all --contains | sed -n -e "s/^\\s*remotes\\/origin\\///" -e "2p" | tr -d "\\n" >> ctrlm_version_build.h + COMMAND sh -c "src=\"${CMAKE_CURRENT_SOURCE_DIR}\"; ref=$(git -C \"$src\" describe --tags --exact-match 2>/dev/null || git -C \"$src\" branch -a --format='%(refname:short)' --contains HEAD 2>/dev/null | sed -n '2{p;q}'); echo -n \"$ref\" >> ctrlm_version_build.h" COMMAND echo "\"" >> ctrlm_version_build.h COMMAND echo -n "#define CTRLM_MAIN_COMMIT_ID " >> ctrlm_version_build.h COMMAND git -C ${CMAKE_CURRENT_SOURCE_DIR} log --format=\"%H\" -n 1 >> ctrlm_version_build.h From 75504292c04665875720f282d8798ab3337bbab4 Mon Sep 17 00:00:00 2001 From: dwolaver <44593664+dwolaver@users.noreply.github.com> Date: Wed, 8 Jul 2026 14:48:10 -0400 Subject: [PATCH 70/81] RDKEMW-17935 : remove ctrlm build flags - USE_DEPRECATED_HDMI_INPUT_PLUGIN (#250) --- CMakeLists.txt | 5 - src/CMakeLists.txt | 1 - src/irdb/ctrlm_irdb_interface.cpp | 12 - .../ctrlm_thunder_plugin_hdmi_input.cpp | 242 ------------------ .../plugins/ctrlm_thunder_plugin_hdmi_input.h | 99 ------- 5 files changed, 359 deletions(-) delete mode 100644 src/thunder/plugins/ctrlm_thunder_plugin_hdmi_input.cpp delete mode 100644 src/thunder/plugins/ctrlm_thunder_plugin_hdmi_input.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 00266a6f..55d597d8 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,7 +52,6 @@ option(XRSR_HTTP "Enable XRSR_HTTP" OFF) option(XRSR_SDT "Enable XRSR_SDT" OFF) option(ENABLE_ASYNC_SRVR_MSG "Enable Asynchronous Server Messaging Feature" OFF) option(ENABLE_AVS_WITH_SDT "Enable SDT Based AVS Support" OFF) -option(USE_DEPRECATED_HDMI_INPUT_PLUGIN "Use deprecated HDMI Input plugin instead of AV Input plugin" OFF) # BUILD SYSTEM set(STAGING_BINDIR_NATIVE, "invalid" CACHE PATH "staging bin dir native") @@ -253,10 +252,6 @@ else() add_compile_definitions(SAFEC_DUMMY_API) endif() -if(USE_DEPRECATED_HDMI_INPUT_PLUGIN) - add_compile_definitions(USE_DEPRECATED_HDMI_INPUT_PLUGIN) -endif() - install(TARGETS controlMgr RUNTIME DESTINATION bin) install(FILES ${CMAKE_BINARY_DIR}/ctrlm_config.json DESTINATION ${CMAKE_INSTALL_SYSCONFDIR} COMPONENT config ) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 93f3f745..99916598 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -198,7 +198,6 @@ if(THUNDER) thunder/plugins/ctrlm_thunder_plugin_display_settings.cpp thunder/plugins/ctrlm_thunder_plugin_device_info.cpp thunder/plugins/ctrlm_thunder_plugin_av_input.cpp - thunder/plugins/ctrlm_thunder_plugin_hdmi_input.cpp thunder/plugins/ctrlm_thunder_plugin_system.cpp ipc/ctrlm_rcp_ipc_iarm_thunder.cpp voice/ipc/ctrlm_voice_ipc_iarm_thunder.cpp diff --git a/src/irdb/ctrlm_irdb_interface.cpp b/src/irdb/ctrlm_irdb_interface.cpp index bab8f9a6..e9b5395e 100644 --- a/src/irdb/ctrlm_irdb_interface.cpp +++ b/src/irdb/ctrlm_irdb_interface.cpp @@ -32,11 +32,7 @@ #include "ctrlm_thunder_plugin_display_settings.h" #include "ctrlm_thunder_plugin_cec_source.h" // TV Platforms -#ifdef USE_DEPRECATED_HDMI_INPUT_PLUGIN -#include "ctrlm_thunder_plugin_hdmi_input.h" -#else #include "ctrlm_thunder_plugin_av_input.h" -#endif #include "ctrlm_thunder_plugin_cec_sink.h" #endif @@ -111,11 +107,7 @@ typedef struct { Thunder::DisplaySettings::ctrlm_thunder_plugin_display_settings_t *display_settings; Thunder::CEC::ctrlm_thunder_plugin_cec_source_t *cec_source; Thunder::CECSink::ctrlm_thunder_plugin_cec_sink_t *cec_sink; - #ifdef USE_DEPRECATED_HDMI_INPUT_PLUGIN - Thunder::HDMIInput::ctrlm_thunder_plugin_hdmi_input_t *av_input; - #else Thunder::AVInput::ctrlm_thunder_plugin_av_input_t *av_input; - #endif #endif } ctrlm_irdb_global_t; @@ -383,11 +375,7 @@ void ctrlm_irdb_interface_t::on_thunder_ready() { } } } else { - #ifdef USE_DEPRECATED_HDMI_INPUT_PLUGIN - g_irdb.av_input = Thunder::HDMIInput::ctrlm_thunder_plugin_hdmi_input_t::getInstance(); - #else g_irdb.av_input = Thunder::AVInput::ctrlm_thunder_plugin_av_input_t::getInstance(); - #endif g_irdb.cec_sink = Thunder::CECSink::ctrlm_thunder_plugin_cec_sink_t::getInstance(); } #endif diff --git a/src/thunder/plugins/ctrlm_thunder_plugin_hdmi_input.cpp b/src/thunder/plugins/ctrlm_thunder_plugin_hdmi_input.cpp deleted file mode 100644 index ed9f2a1e..00000000 --- a/src/thunder/plugins/ctrlm_thunder_plugin_hdmi_input.cpp +++ /dev/null @@ -1,242 +0,0 @@ -/* - * If not stated otherwise in this file or this component's license file the - * following copyright and licenses apply: - * - * Copyright 2015 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. -*/ -#include "ctrlm_thunder_plugin_hdmi_input.h" -#include "ctrlm_log.h" -#include -#include -#include -#include - -using namespace Thunder; -using namespace HDMIInput; -using namespace WPEFramework; - -static int _on_hotplug_thread(void *data) { - auto params = (std::pair *)data; - if(params) { - if(params->first) { - params->first->check_device_list((void *)¶ms->second); - } else { - XLOGD_ERROR("Plugin NULL"); - } - delete params; - } else { - XLOGD_ERROR("Params NULL"); - } - return(0); -} - -static void _on_hotplug(ctrlm_thunder_plugin_hdmi_input_t *plugin, JsonObject params) { - g_idle_add(_on_hotplug_thread, new std::pair(plugin, params)); -} - -static int _on_device_status_change_thread(void *data) { - auto params = (std::pair *)data; - if(params) { - if(params->first) { - if(params->second.HasLabel("id") && params->second.HasLabel("status")) { - params->first->on_device_status_change(params->second["id"].Number(), params->second["status"].String() == "started"); - } else { - std::string response_str; - params->second.ToString(response_str); - XLOGD_ERROR("HDMIInput device status changemalformed: <%s>", response_str.c_str()); - } - } else { - XLOGD_ERROR("Plugin NULL"); - } - delete params; - } else { - XLOGD_ERROR("Params NULL"); - } - return(0); -} - -static void _on_device_status_change(ctrlm_thunder_plugin_hdmi_input_t *plugin, JsonObject params) { - g_idle_add(_on_device_status_change_thread, new std::pair(plugin, params)); -} - -ctrlm_thunder_plugin_hdmi_input_t::ctrlm_thunder_plugin_hdmi_input_t() : ctrlm_thunder_plugin_t("HdmiInput", "org.rdk.HdmiInput", 2) { - sem_init(&this->semaphore, 0, 1); - this->registered_events = false; -} - -ctrlm_thunder_plugin_hdmi_input_t::~ctrlm_thunder_plugin_hdmi_input_t() { - -} - -ctrlm_thunder_plugin_hdmi_input_t *ctrlm_thunder_plugin_hdmi_input_t::getInstance() { - XLOGD_INFO("HDMI Input Plugin"); - static ctrlm_thunder_plugin_hdmi_input_t instance; - return &instance; -} - -void ctrlm_thunder_plugin_hdmi_input_t::get_infoframes(std::map > &infoframes) { - // Lock sempahore as we are touching infoframe cache - sem_wait(&this->semaphore); - infoframes = this->infoframes; - // Unlock semaphore as we are done touching the infoframe cache - sem_post(&this->semaphore); -} - -bool ctrlm_thunder_plugin_hdmi_input_t::_get_infoframe(int port) { - bool ret = false; - JsonObject params, response; - - XLOGD_INFO("Calling HDMIInput for infoframe data for port %d", port); - - params["portId"] = port; - // Lock sempahore as we are touching infoframe cache - sem_wait(&this->semaphore); - this->infoframes[port].clear(); - - if(this->call_plugin("getRawHDMISPD", (void *)¶ms, (void *)&response)) { - if(response.HasLabel("HDMISPD")) { - std::string infoframe_str = response["HDMISPD"].String(); - if(!infoframe_str.empty()) { - uint8_t *infoframe_buf = NULL; - size_t infoframe_size = 0; - - // Base64 decode the string - infoframe_buf = g_base64_decode(infoframe_str.c_str(), &infoframe_size); - if(infoframe_buf && infoframe_size > 0) { - for(size_t i = 0; i < infoframe_size; i++) { - this->infoframes[port].push_back(infoframe_buf[i]); // This checksum byte is not part of the HDMI spec, not sure why dsMgr/TvServer adds it within the infoframe - } -#define REMOVE_RSD_BYTE -#ifdef REMOVE_RSD_BYTE - this->infoframes[port].erase(this->infoframes[port].begin() + 3); -#endif - if(this->infoframes[port].size() < 29) { - XLOGD_INFO("Padding infoframe to complete 29 bytes"); - for(size_t i = this->infoframes[port].size(); i < 29; i++) { - this->infoframes[port].push_back(0x00); - } - } else if(this->infoframes[port].size() > 29) { - XLOGD_INFO("Removing padding from infoframe to 29 bytes"); - for(size_t i = this->infoframes[port].size(); i > 29; i--) { - this->infoframes[port].pop_back(); - } - } - ret = true; - } else { - XLOGD_ERROR("Failed to decode Infoframe base64!"); - } - g_free(infoframe_buf); - } else { - XLOGD_ERROR("Infoframe string is empty!"); - } - } else { - std::string response_str; - response.ToString(response_str); - XLOGD_ERROR("HDMIInput readINFOFRAME response malformed: <%s>", response_str.c_str()); - } - } else { - XLOGD_ERROR("HDMIInput readINFOFRAME call failed!"); - } - - // Unlock semaphore as we are done touching the infoframe cache - sem_post(&this->semaphore); - return(ret); -} - -void ctrlm_thunder_plugin_hdmi_input_t::_clear_infoframe(int port) { - XLOGD_INFO("Clearing infoframe data from cache for port %d", port); - // Lock sempahore as we are touching infoframe cache - sem_wait(&this->semaphore); - this->infoframes[port].clear(); - // Unlock semaphore as we are done touching the infoframe cache - sem_post(&this->semaphore); -} - -void ctrlm_thunder_plugin_hdmi_input_t::on_device_status_change(int port, bool active) { - XLOGD_INFO("Device status changed <%s>", (active ? "STARTED" : "STOPPED")); - if(active) { - XLOGD_INFO("Acquiring new infoframe data"); - this->_get_infoframe(port); - } else { - XLOGD_INFO("Purposely doing nothing when status is stopped"); - } -} - -bool ctrlm_thunder_plugin_hdmi_input_t::register_events() { - bool ret = this->registered_events; - if(ret == false) { - auto clientObject = (JSONRPC::LinkType*)this->plugin_client; - if(clientObject) { - ret = true; - uint32_t thunderRet = clientObject->Subscribe(CALL_TIMEOUT, _T("onDevicesChanged"), &_on_hotplug, this); - if(thunderRet != Core::ERROR_NONE) { - XLOGD_ERROR("Thunder subscribe failed "); - ret = false; - } - thunderRet = clientObject->Subscribe(CALL_TIMEOUT, _T("onInputStatusChanged"), &_on_device_status_change, this); - if(thunderRet != Core::ERROR_NONE) { - XLOGD_ERROR("Thunder subscribe failed "); - ret = false; - } - if(ret) { - this->registered_events = true; - } - } - } - Thunder::Plugin::ctrlm_thunder_plugin_t::register_events(); - return(ret); -} - -void ctrlm_thunder_plugin_hdmi_input_t::on_initial_activation() { - // Get initial INFOFRAME info - JsonObject params, response; - if(this->call_plugin("getHDMIInputDevices", (void *)¶ms, (void *)&response)) { - this->check_device_list((void *)&response); - } - - Thunder::Plugin::ctrlm_thunder_plugin_t::on_initial_activation(); -} - -void ctrlm_thunder_plugin_hdmi_input_t::check_device_list(void *params) { - JsonObject *root = (JsonObject *)params; - if(root) { - std::string response_st; - root->ToString(response_st); - XLOGD_INFO("%s", response_st.c_str()); - if(root->HasLabel("devices")) { - JsonArray devices = (*root)["devices"].Array(); - for(int i = 0; i < devices.Length(); i++) { - JsonObject device = devices[i].Object(); - if(device.HasLabel("id") && device.HasLabel("connected")) { - if(device["connected"].String() == "true") { - this->_get_infoframe(device["id"].Number()); - } else { - this->_clear_infoframe(device["id"].Number()); - } - } else { - std::string response_str; - device.ToString(response_str); - XLOGD_WARN("Malformed device object <%s>", response_str.c_str()); - } - } - } else { - std::string response_str; - root->ToString(response_str); - XLOGD_WARN("Missing device list! <%s>", response_str.c_str()); - } - } else { - XLOGD_WARN("JsonObject is NULL"); - } -} diff --git a/src/thunder/plugins/ctrlm_thunder_plugin_hdmi_input.h b/src/thunder/plugins/ctrlm_thunder_plugin_hdmi_input.h deleted file mode 100644 index 0a858186..00000000 --- a/src/thunder/plugins/ctrlm_thunder_plugin_hdmi_input.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * If not stated otherwise in this file or this component's license file the - * following copyright and licenses apply: - * - * Copyright 2014 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. -*/ -#ifndef __CTRLM_THUNDER_PLUGIN_HDMI_INPUT_H__ -#define __CTRLM_THUNDER_PLUGIN_HDMI_INPUT_H__ -#include "ctrlm_thunder_plugin.h" -#include -#include - -namespace Thunder { -namespace HDMIInput { - -/** - * This class is used within ControlMgr to interact with the HDMIInput Thunder Plugin. - */ -class ctrlm_thunder_plugin_hdmi_input_t : public Thunder::Plugin::ctrlm_thunder_plugin_t { -public: - /** - * This function is used to get the Thunder HDMI Input instance, as it is a Singleton. - * @return The instance of the Thunder HDMI Input, or NULL on error. - */ - static ctrlm_thunder_plugin_hdmi_input_t *getInstance(); - - /** - * HDMIInput Thunder Plugin Destructor - */ - virtual ~ctrlm_thunder_plugin_hdmi_input_t(); - - /** - * This function is used to get the HDMI Infoframe data from cache. - * @param infoframe The vector that the resulting Infoframe data will be placed. - */ - void get_infoframes(std::map > &infoframes); - -public: - /** - * This function is technically used internally but from static function. This is used to handle device status events. - * @param port The HDMI port of the input device which has changed status. - * @param active The boolean that states whether the source is active or not. - */ - void on_device_status_change(int port, bool active); - - /** - * This function is technically used internally but from static function. This function is used to parse device list from HdmiInput calls/events - */ - void check_device_list(void *params); - -protected: - /** - * HDMIInput Thunder Plugin Default Constructor - */ - ctrlm_thunder_plugin_hdmi_input_t(); - - /** - * This function is called when registering for Thunder events. - * @return True if the events were registered for successfully otherwise False. - */ - virtual bool register_events(); - - /** - * This function is called when the initial activation of the plugin occurs. - */ - virtual void on_initial_activation(); - - /** - * This function actually calls the HDMI Input Thunder Plugin to get the Infoframe data. - * @return True if the call was successful and there is data available, otherwise False. - */ - bool _get_infoframe(int port); - - /** - * This function clears the current infoframe cache. - */ - void _clear_infoframe(int port); - -private: - std::map > infoframes; - sem_t semaphore; - bool registered_events; - -}; -}; -}; -#endif From 8c8118740728284656c185ccf1c6b19d83724f61 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Wed, 8 Jul 2026 15:42:49 -0400 Subject: [PATCH 71/81] RDKEMW-18082: ctrlm coverity cleanup (#225) --- ci/build_dependencies.sh | 103 ++++++++++++++++++---------- ci/cov_build.sh | 6 -- ci/mocks/devicesettings_ctrlm.patch | 40 ----------- ci/mocks/safec_lib.h | 44 ------------ ci/mocks/testframework_overrides.h | 48 ------------- ci/mocks/xlog_ci_compat.h | 42 ------------ src/ctrlm_utils.cpp | 6 ++ src/voice/ctrlm_voice_obj.cpp | 4 ++ 8 files changed, 75 insertions(+), 218 deletions(-) delete mode 100644 ci/mocks/devicesettings_ctrlm.patch delete mode 100644 ci/mocks/safec_lib.h delete mode 100644 ci/mocks/testframework_overrides.h delete mode 100644 ci/mocks/xlog_ci_compat.h diff --git a/ci/build_dependencies.sh b/ci/build_dependencies.sh index 9abff1c9..5d5bb7a9 100644 --- a/ci/build_dependencies.sh +++ b/ci/build_dependencies.sh @@ -43,22 +43,21 @@ apt install -y \ uuid-dev \ libevdev-dev \ libdrm-dev \ - libsafec-dev \ + libbsd-dev \ + autoconf \ + automake \ + libtool \ + make \ + gperf \ python3-pip python3 -m pip install jsonref ########################################### # 2. Clone the required repositories -XRSDK_REF="1.0.13" -git clone --depth 1 --filter=blob:none --branch "${XRSDK_REF}" https://github.com/rdkcentral/xr-voice-sdk.git +git clone --depth 1 --filter=blob:none --branch develop https://github.com/rdkcentral/xr-voice-sdk.git -git clone --depth 1 --filter=blob:none --branch develop https://github.com/rdkcentral/entservices-testframework.git - -# Patch the upstream testframework devicesettings.h with ctrlm-specific -# additions (ducking types, setAudioDucking, Manager::IsInitialized). -# We can remove this if added to upstream testframework -git -C entservices-testframework apply "$GITHUB_WORKSPACE/ci/mocks/devicesettings_ctrlm.patch" +git clone --depth 1 --filter=blob:none https://github.com/rdkcentral/entservices-testframework.git git clone --depth 1 --filter=blob:none --sparse --branch develop https://github.com/rdkcentral/iarmmgrs.git git -C iarmmgrs sparse-checkout set hal @@ -72,10 +71,22 @@ git -C rdk-halif-power_manager sparse-checkout set include git clone --depth 1 --filter=blob:none --sparse --branch develop https://github.com/rdkcentral/rdkversion.git git -C rdkversion sparse-checkout set src +git clone --depth 1 --filter=blob:none --sparse https://github.com/rdkcentral/meta-rdk-oss-reference.git +git -C meta-rdk-oss-reference sparse-checkout set recipes-common/safec-common-wrapper/files + +# Build and install nopoll for xr-voice-sdk WS-enabled native CI build. +git clone --depth 1 https://github.com/ASPLes/nopoll.git +cd nopoll +./autogen.sh --prefix=/usr +make -j$(nproc) +make install +cd "${GITHUB_WORKSPACE}" + IARMMGRS_DIR="$GITHUB_WORKSPACE/iarmmgrs" DEEPSLEEP_HAL_DIR="$GITHUB_WORKSPACE/rdk-halif-deepsleep_manager" POWER_HAL_DIR="$GITHUB_WORKSPACE/rdk-halif-power_manager" RDKVERSION_DIR="$GITHUB_WORKSPACE/rdkversion" +SAFEC_WRAPPER_DIR="$GITHUB_WORKSPACE/meta-rdk-oss-reference/recipes-common/safec-common-wrapper/files" ############################ # 3. Create stub/empty headers for external dependencies @@ -83,30 +94,49 @@ echo "========================================================================== echo "Creating stub headers" HEADERS_DIR="$GITHUB_WORKSPACE/ci/headers" -XRSDK_HEADERS_DIR="$HEADERS_DIR/xr-voice-sdk" mkdir -p "${HEADERS_DIR}" mkdir -p "${HEADERS_DIR}/rdk/iarmbus" mkdir -p "${HEADERS_DIR}/rdk/ds" mkdir -p "${HEADERS_DIR}/rdk/iarmmgrs-hal" -mkdir -p "${XRSDK_HEADERS_DIR}" - -# Copy real xr-voice-sdk headers. -# xr_fdc.h is NOT copied: only needed when FDC_ENABLED=ON -cp "$GITHUB_WORKSPACE/xr-voice-sdk/src/xr-speech-vrex/xrsv.h" "${XRSDK_HEADERS_DIR}/" -cp "$GITHUB_WORKSPACE/xr-voice-sdk/src/xr-speech-router/xrsr.h" "${XRSDK_HEADERS_DIR}/" -cp "$GITHUB_WORKSPACE/xr-voice-sdk/src/xr-mq/xr_mq.h" "${XRSDK_HEADERS_DIR}/" -cp "$GITHUB_WORKSPACE/xr-voice-sdk/src/xr-speech-vrex/xrsv_http/xrsv_http.h" "${XRSDK_HEADERS_DIR}/" -cp "$GITHUB_WORKSPACE/xr-voice-sdk/src/xr-speech-vrex/xrsv_ws_nextgen/xrsv_ws_nextgen.h" "${XRSDK_HEADERS_DIR}/" -cp "$GITHUB_WORKSPACE/xr-voice-sdk/src/xr-timestamp/xr_timestamp.h" "${XRSDK_HEADERS_DIR}/" - -# Generate rdkx_logger_modules.h from xr-voice-sdk's module configuration, -# then copy the real rdkx_logger and xr_voice_sdk headers. -# This replaces the hand-written ci/mocks/control/ stubs. -python3 "$GITHUB_WORKSPACE/xr-voice-sdk/scripts/rdkx_logger_modules_to_c.py" \ - "$GITHUB_WORKSPACE/xr-voice-sdk/src/xr-logger/rdkv/rdkx_logger_modules.json" \ - "${XRSDK_HEADERS_DIR}/rdkx_logger_modules" "mw" -cp "$GITHUB_WORKSPACE/xr-voice-sdk/src/xr-logger/rdkx_logger_mw.h" "${XRSDK_HEADERS_DIR}/rdkx_logger.h" -cp "$GITHUB_WORKSPACE/xr-voice-sdk/src/xr_voice_sdk.h" "${XRSDK_HEADERS_DIR}/xr_voice_sdk.h" + +# Use the Yocto safec_lib.h sysroot header for CI builds without libsafec. +# Add include guards because the upstream header does not provide them. +cp "$SAFEC_WRAPPER_DIR/safec_lib.h" "$HEADERS_DIR/safec_lib.h" +sed -i '1s/^/#ifndef CTRLM_CI_SAFEC_LIB_H\n#define CTRLM_CI_SAFEC_LIB_H\n/' "$HEADERS_DIR/safec_lib.h" +printf '\n#endif /* CTRLM_CI_SAFEC_LIB_H */\n' >> "$HEADERS_DIR/safec_lib.h" +# patching parseFormat to avoid -Wmaybe-uninitialized warnings in ctrlm_database.cpp from the safec wrapper's dummy implementation +sed -i 's/static inline int parseFormat(const char \*dst,/static inline int parseFormat(char *dst,/' "$HEADERS_DIR/safec_lib.h" +# patching strcpy_s to avoid Coverity's array-vs-NULL warning on string literals while +# preserving the dummy wrapper's null and bounds checks in CI builds. +perl -0pi -e 's{#define strcpy_s\(dst,max,src\) \(src != NULL\)\?\(\(max > strlen\(src\)\)\?EOK:ESLEMAX\):ESNULLP; \\\n if\(\(src != NULL\) && \(max > strlen\(src\)\)\) strcpy\(dst,src\);}{#define strcpy_s(dst,max,src) ({ const char *ctrlm_ci_src__ = (src); ctrlm_ci_src__ != NULL ? (((max) > strlen(ctrlm_ci_src__)) ? (strcpy((dst), ctrlm_ci_src__), EOK) : ESLEMAX) : ESNULLP; })}s or die "failed to patch strcpy_s in safec_lib.h\n"' "$HEADERS_DIR/safec_lib.h" +# patching strncpy_s to avoid the wrapper's raw strncpy expansion, which triggers +# -Wstringop-truncation in CI even though ctrlm manually terminates the destination buffer. +perl -0pi -e 's{#define strncpy_s\(dst,max,src,len\) \(src != NULL\)\?\(\(len <= max\)\?EOK:ESLEMAX\):ESNULLP; \\\n if\(\(src != NULL\) && \(len <= max\)\) strncpy\(dst,src,len\);}{#define strncpy_s(dst,max,src,len) (src != NULL)?((len <= max)?EOK:ESLEMAX):ESNULLP; \\\n if((src != NULL) && (len <= max)) { size_t copy_len = strnlen(src, len); memcpy(dst, src, copy_len); if(copy_len < (size_t)(max)) memset((char *)(dst) + copy_len, 0, (size_t)(max) - copy_len); }}s or die "failed to patch strncpy_s in safec_lib.h\n"' "$HEADERS_DIR/safec_lib.h" + +# Stage rdkversion.h before building xr-voice-sdk. +cp "$RDKVERSION_DIR/src/rdkversion.h" "$HEADERS_DIR/rdkversion.h" + +# Build xr-voice-sdk and install its headers under ${HEADERS_DIR}/xr-voice-sdk/. +# Version doesn't matter here, but we try to get the latest tag for good measure since it's included in the generated headers and may be used by downstream code. +XRSDK_REF=$(git ls-remote --tags https://github.com/rdkcentral/xr-voice-sdk.git \ + | grep -oP '\d+\.\d+\.\d+$' | sort -V | tail -1) +echo "Building xr-voice-sdk at ref ${XRSDK_REF}" +cmake -G Ninja \ + -S "$GITHUB_WORKSPACE/xr-voice-sdk" \ + -B "$GITHUB_WORKSPACE/build/xr-voice-sdk" \ + -DCMAKE_INSTALL_PREFIX="${HEADERS_DIR}" \ + -DCMAKE_INSTALL_INCLUDEDIR="xr-voice-sdk" \ + -DCMAKE_INSTALL_SYSCONFDIR="${HEADERS_DIR}/etc" \ + -DCMAKE_C_FLAGS="-I${HEADERS_DIR} -DSAFEC_DUMMY_API" \ + -DSTAGING_BINDIR_NATIVE="/usr/bin" \ + -DCMAKE_PROJECT_VERSION="${XRSDK_REF}" \ + -DWS_ENABLED=ON \ + -DWS_NOPOLL_PATCHES=OFF \ + -DINSTALL_INTERNAL_HEADERS=ON + +cmake --build "$GITHUB_WORKSPACE/build/xr-voice-sdk" +cmake --install "$GITHUB_WORKSPACE/build/xr-voice-sdk" --component headers +cmake --install "$GITHUB_WORKSPACE/build/xr-voice-sdk" --component internal-headers cd "${HEADERS_DIR}" @@ -160,16 +190,11 @@ find "$IARMMGRS_DIR" -name comcastIrKeyCodes.h -print -quit | xargs -r -I{} cp " [ -f comcastIrKeyCodes.h ] # rdkversion.h (used by ctrlm_main.cpp) -cp "$RDKVERSION_DIR/src/rdkversion.h" rdkversion.h [ -f rdkversion.h ] # secure_wrapper (types provided via empty stub — no v_secure_* calls in core) touch secure_wrapper.h -# safec compatibility header - committed in ci/mocks, copied here so it is -# resolved on the generated-headers include path. -cp "$GITHUB_WORKSPACE/ci/mocks/safec_lib.h" safec_lib.h - echo "Stub headers created successfully" cd "${GITHUB_WORKSPACE}" @@ -190,13 +215,15 @@ cat > /tmp/stub.c << 'STUB_EOF' void __stub_placeholder(void) {} STUB_EOF -# Build stub .so for each missing library -# nopoll and dshalcli are unused (factory-only) but unconditionally linked by CMakeLists.txt -# We can remove them from the link list in the future if desired, but for now just provide stubs to satisfy the linker. -for lib in xr-voice-sdk rdkversion IARMBus ds nopoll dshalcli rfcapi secure_wrapper evdev; do +# Build stub .so files for libraries still linked in CI. +# nopoll and dshalcli are factory-only but still linked unconditionally. +for lib in rdkversion IARMBus ds nopoll dshalcli rfcapi secure_wrapper evdev; do gcc -shared -fPIC -o "${STUB_LIB_DIR}/lib${lib}.so" /tmp/stub.c done +# Copy the real xr-voice-sdk .so alongside the stubs. +cp "$GITHUB_WORKSPACE/build/xr-voice-sdk/src/libxr-voice-sdk.so" "${STUB_LIB_DIR}/libxr-voice-sdk.so" + rm /tmp/stub.c echo "Stub libraries created in ${STUB_LIB_DIR}" diff --git a/ci/cov_build.sh b/ci/cov_build.sh index 3a51b921..5b48686b 100644 --- a/ci/cov_build.sh +++ b/ci/cov_build.sh @@ -28,9 +28,7 @@ ls -la "${GITHUB_WORKSPACE}" echo "building control (ctrlm-main)" XRSDK_REAL_HEADERS="$GITHUB_WORKSPACE/ci/headers/xr-voice-sdk" -XLOG_COMPAT="$GITHUB_WORKSPACE/ci/mocks/xlog_ci_compat.h" MOCK_DIR="$GITHUB_WORKSPACE/entservices-testframework/Tests/mocks" -MOCK_OVERRIDES="$GITHUB_WORKSPACE/ci/mocks/testframework_overrides.h" HEADERS_DIR="$GITHUB_WORKSPACE/ci/headers" EMPTY_JSON="$GITHUB_WORKSPACE/install/usr/include/ctrlm_config_empty.json" GLIB_CFLAGS="$(pkg-config --cflags glib-2.0)" @@ -77,13 +75,10 @@ cmake -G Ninja -S "$GITHUB_WORKSPACE" -B build/control \ -I ${GITHUB_WORKSPACE}/install/usr/include \ -I /usr/include/libdrm \ ${GLIB_CFLAGS} \ --include ${XLOG_COMPAT} \ -include ${MOCK_DIR}/Iarm.h \ --include ${MOCK_OVERRIDES} \ -include ${MOCK_DIR}/devicesettings.h \ -include ${MOCK_DIR}/Rfc.h \ -Wall -Wno-error \ --DSAFEC_DUMMY_API \ -DDISABLE_SECURITY_TOKEN" \ -DCMAKE_C_FLAGS=" \ -I ${XRSDK_REAL_HEADERS} \ @@ -96,7 +91,6 @@ ${GLIB_CFLAGS} \ -I /usr/include/libdrm \ ${GLIB_CFLAGS} \ -Wall -Wno-error \ --DSAFEC_DUMMY_API \ -DDISABLE_SECURITY_TOKEN" \ -DCMAKE_EXE_LINKER_FLAGS="-L${GITHUB_WORKSPACE}/install/usr/lib -Wl,--unresolved-symbols=ignore-all" diff --git a/ci/mocks/devicesettings_ctrlm.patch b/ci/mocks/devicesettings_ctrlm.patch deleted file mode 100644 index d2faf8a8..00000000 --- a/ci/mocks/devicesettings_ctrlm.patch +++ /dev/null @@ -1,40 +0,0 @@ ---- a/Tests/mocks/devicesettings.h 2026-04-21 19:12:58.154981897 +0000 -+++ b/Tests/mocks/devicesettings.h 2026-04-21 19:13:50.591192520 +0000 -@@ -72,6 +72,16 @@ - dsAUDIOPORT_TYPE_MAX /**< Maximum index for audio port type. */ - } dsAudioPortType_t; - -+typedef enum _dsAudioDuckingAction_t { -+ dsAUDIO_DUCKINGACTION_START = 0, -+ dsAUDIO_DUCKINGACTION_STOP = 1 -+} dsAudioDuckingAction_t; -+ -+typedef enum _dsAudioDuckingType_t { -+ dsAUDIO_DUCKINGTYPE_ABSOLUTE = 0, -+ dsAUDIO_DUCKINGTYPE_RELATIVE = 1 -+} dsAudioDuckingType_t; -+ - typedef enum _dsVideoPortType_t { - dsVIDEOPORT_TYPE_RF = 0, ///< RF modulator (channel 3/4) video output - dsVIDEOPORT_TYPE_BB, ///< Baseband (composite, RCA) video output -@@ -934,6 +944,11 @@ - void enableARC(dsAudioARCTypes_t type, bool enable); - uint32_t getDolbyVolumeMode() const; - void setStereoMode(const std::string &mode, bool persist); -+ void setAudioDucking(dsAudioDuckingAction_t action, dsAudioDuckingType_t type, float level) { -+ (void)action; -+ (void)type; -+ (void)level; -+ } - - - -@@ -1420,6 +1435,8 @@ - static ManagerImpl* impl; - - public: -+ static bool IsInitialized; -+ - Manager(); - - static void setImpl(ManagerImpl* newImpl); diff --git a/ci/mocks/safec_lib.h b/ci/mocks/safec_lib.h deleted file mode 100644 index 37d75748..00000000 --- a/ci/mocks/safec_lib.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * If not stated otherwise in this file or this component's license file the - * following copyright and licenses apply: - * - * Copyright 2026 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. - */ - -/* - * Compatibility header: maps ctrlm's local include name to the real libsafec - * package headers (libsafec-dev / safec-common-wrapper in production). - * - * In CI this file is copied from ci/mocks/ into ci/headers/ by - * build_dependencies.sh so it is resolved on the generated-headers include - * path used by cov_build.sh. - * - * This exists because ctrlm includes safec_lib.h directly, while the native CI - * environment provides the underlying libsafec package headers instead of that - * project-local wrapper. - */ - -#ifndef CTRLM_CI_SAFEC_LIB_H_ -#define CTRLM_CI_SAFEC_LIB_H_ - -#include -#include -#include - -#ifndef ERR_CHK -#define ERR_CHK(rc) do { (void)(rc); } while(0) -#endif - -#endif /* CTRLM_CI_SAFEC_LIB_H_ */ diff --git a/ci/mocks/testframework_overrides.h b/ci/mocks/testframework_overrides.h deleted file mode 100644 index 22b8a0a2..00000000 --- a/ci/mocks/testframework_overrides.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * If not stated otherwise in this file or this component's license file the - * following copyright and licenses apply: - * - * Copyright 2026 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. - */ -/* - * CI patch layer for gaps in the entservices-testframework mock headers. - * - * ctrlm needs a few IARM declarations that are missing from the testframework - * headers used by this reduced build. This file adds only those missing pieces - * and can be removed once they exist upstream. - */ -#ifndef CTRLM_CI_TESTFRAMEWORK_OVERRIDES_H_ -#define CTRLM_CI_TESTFRAMEWORK_OVERRIDES_H_ - -/* Pinned testframework Iarm.h stops at UNKNOWN; ctrlm also references MAX. */ -#ifndef DEEPSLEEP_WAKEUPREASON_MAX -#define DEEPSLEEP_WAKEUPREASON_MAX (DEEPSLEEP_WAKEUPREASON_UNKNOWN + 1) -#endif - -/* IARM common API string not present in the pinned testframework mock */ -#ifndef IARM_BUS_COMMON_API_PowerPreChange -#define IARM_BUS_COMMON_API_PowerPreChange "PowerPreChange" -#endif - -/* Struct not present in the pinned testframework mock */ -#ifndef CTRLM_IARM_BUS_COMMON_API_POWERPRECHANGE_PARAM_T_DEFINED -#define CTRLM_IARM_BUS_COMMON_API_POWERPRECHANGE_PARAM_T_DEFINED -typedef struct { - IARM_Bus_PWRMgr_PowerState_t newState; - IARM_Bus_PWRMgr_PowerState_t curState; -} IARM_Bus_CommonAPI_PowerPreChange_Param_t; -#endif - -#endif /* CTRLM_CI_TESTFRAMEWORK_OVERRIDES_H_ */ diff --git a/ci/mocks/xlog_ci_compat.h b/ci/mocks/xlog_ci_compat.h deleted file mode 100644 index 43836b73..00000000 --- a/ci/mocks/xlog_ci_compat.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * If not stated otherwise in this file or this component's license file the - * following copyright and licenses apply: - * - * Copyright 2026 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. - */ - -/* - * CI compatibility shim. - * - * The production rdkx_logger.h is included transitively everywhere via - * ctrlm_log.h. In the Yocto build the SDK headers pull several std:: names - * into the global namespace. A handful of ctrlm TUs (e.g. ctrlm_utils.cpp) - * rely on those names being globally visible. This tiny header replicates - * that behaviour for the CI native build. - */ -#ifndef CTRLM_CI_XLOG_COMPAT_H_ -#define CTRLM_CI_XLOG_COMPAT_H_ - -#ifdef __cplusplus -#include -#include -#include -using std::get; -using std::map; -using std::string; -using std::tuple; -#endif - -#endif /* CTRLM_CI_XLOG_COMPAT_H_ */ diff --git a/src/ctrlm_utils.cpp b/src/ctrlm_utils.cpp index eb8c7b7e..6be8556a 100644 --- a/src/ctrlm_utils.cpp +++ b/src/ctrlm_utils.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include "ctrlm.h" #include "ctrlm_utils.h" #include @@ -47,6 +48,11 @@ #include // end dsMgr includes +using std::get; +using std::map; +using std::string; +using std::tuple; + #define BLOCK_SIZE (1024 * 4 * 10) /* bytes */ #define MAX_RECURSE_DEPTH 20 diff --git a/src/voice/ctrlm_voice_obj.cpp b/src/voice/ctrlm_voice_obj.cpp index c81a629a..e6e8636d 100644 --- a/src/voice/ctrlm_voice_obj.cpp +++ b/src/voice/ctrlm_voice_obj.cpp @@ -2925,11 +2925,15 @@ void ctrlm_voice_t::voice_stream_end_callback(ctrlm_voice_stream_end_cb_t *strea if(session->packets_processed > 0) { uint32_t stream_duration = session->packets_processed * 20; // assume 20 ms per packet + #ifdef TELEMETRY_SUPPORT uint32_t samples_per_packet = 320; // 16 kHz samples at 20 ms per packet + #endif if(session->format.type == CTRLM_VOICE_FORMAT_ADPCM_FRAME) { uint32_t frame_duration_us = (session->format.value.adpcm_frame.size_packet - session->format.value.adpcm_frame.size_header) * 125; // 125 us per byte for ADPCM at 16 kHz stream_duration = (session->packets_processed * frame_duration_us) / 1000; + #ifdef TELEMETRY_SUPPORT samples_per_packet = (session->format.value.adpcm_frame.size_packet - session->format.value.adpcm_frame.size_header) * 2; // 2 samples per byte for ADPCM + #endif } XLOGD_AUTOMATION_TELEMETRY("src <%s> Packets Lost/Total <%u/%u> %.02f%% duration <%u> ms", ctrlm_voice_device_str(session->voice_device), session->packets_lost, session->packets_lost + session->packets_processed, 100.0 * ((double)session->packets_lost / (double)(session->packets_lost + session->packets_processed)), stream_duration); #ifdef TELEMETRY_SUPPORT From 87b09d95fdb25e6cc481f0f9f98fd4ccdc6363c8 Mon Sep 17 00:00:00 2001 From: dwolaver <44593664+dwolaver@users.noreply.github.com> Date: Thu, 9 Jul 2026 14:44:34 -0400 Subject: [PATCH 72/81] RDKEMW-7310 : remove ctrlm build flags - USE_DEPRECATED_IRMGR (#254) --- src/ctrlm.h | 1 - src/ctrlm_main.cpp | 392 +--------------------------------------- src/ctrlm_main_iarm.cpp | 9 - 3 files changed, 2 insertions(+), 400 deletions(-) diff --git a/src/ctrlm.h b/src/ctrlm.h index b5c73f0a..e4a9b518 100644 --- a/src/ctrlm.h +++ b/src/ctrlm.h @@ -469,7 +469,6 @@ gboolean ctrlm_pairing_window_active_get(void); void ctrlm_pairing_window_bind_status_set(ctrlm_bind_status_t bind_status); void ctrlm_discovery_remote_type_set(const char *remote_type_str); ctrlm_pairing_restrict_by_remote_t restrict_pairing_by_remote_get(); -void ctrlm_event_handler_ir(const char *owner, IARM_EventId_t event_id, void *data, size_t len); void ctrlm_quit_main_loop(); gboolean ctrlm_power_state_change(ctrlm_power_state_t power_state); diff --git a/src/ctrlm_main.cpp b/src/ctrlm_main.cpp index a4b38fac..daf0977b 100644 --- a/src/ctrlm_main.cpp +++ b/src/ctrlm_main.cpp @@ -36,10 +36,6 @@ #include #include "jansson.h" #include "libIBus.h" -#ifdef USE_DEPRECATED_IRMGR -#include "irMgr.h" -#include "plat_ir.h" -#endif #include "sysMgr.h" #ifdef BREAKPAD_SUPPORT #include "client/linux/handler/exception_handler.h" @@ -369,11 +365,10 @@ static void ctrlm_stop_one_touch_autobind_(ctrlm_network_id_t network_id); static void ctrlm_close_pairing_window_(ctrlm_network_id_t network_id, ctrlm_close_pairing_window_reason reason); static void ctrlm_pairing_window_bind_status_set_(ctrlm_bind_status_t bind_status); static void ctrlm_discovery_remote_type_set_(const char* remote_type_str); -static void ctrlm_controller_product_name_get(ctrlm_controller_id_t controller_id, char *source_name) __attribute__((unused)); //USE_DEPRECATED_IRMGR static void ctrlm_global_rfc_values_retrieved(const ctrlm_rfc_attr_t &attr); -static gboolean ctrlm_timeout_line_of_sight(gpointer user_data) __attribute__((unused)); //USE_DEPRECATED_IRMGR -static gboolean ctrlm_timeout_autobind(gpointer user_data) __attribute__((unused)); //USE_DEPRECATED_IRMGR +static gboolean ctrlm_timeout_line_of_sight(gpointer user_data); +static gboolean ctrlm_timeout_autobind(gpointer user_data); static gboolean ctrlm_timeout_binding_button(gpointer user_data); static gboolean ctrlm_timeout_screen_bind(gpointer user_data); static gboolean ctrlm_timeout_one_touch_autobind(gpointer user_data); @@ -392,9 +387,6 @@ static void ctrlm_property_write_shutdown_time(void); static guchar ctrlm_property_write_shutdown_time(guchar *data, guchar length); static void ctrlm_property_read_shutdown_time(void); static void control_service_values_read_from_db(); -#ifdef USE_DEPRECATED_IRMGR -static void ctrlm_check_for_key_tag(int key_tag) __attribute__((unused)); //USE_DEPRECATED_IRMGR -#endif #if CTRLM_HAL_RF4CE_API_VERSION >= 9 static void ctrlm_crash_recovery_check(); @@ -4226,351 +4218,6 @@ gboolean ctrlm_main_iarm_call_chip_status_get(ctrlm_main_iarm_call_chip_status_t return(true); } -#ifdef USE_DEPRECATED_IRMGR -void ctrlm_event_handler_ir(const char *owner, IARM_EventId_t event_id, void *data, size_t len) -{ - IARM_Bus_IRMgr_EventData_t *ir_event = (IARM_Bus_IRMgr_EventData_t *)data; - - switch(ir_event->data.irkey.keySrc) { - case IARM_BUS_IRMGR_KEYSRC_IR: { - int key_code = ir_event->data.irkey.keyCode; - int key_type = ir_event->data.irkey.keyType; - if(key_code == KED_SETUP && key_type == KET_KEYDOWN) { // Received IR Line of sight code - XLOGD_INFO("Setup IR code received."); - // Cancel active line of sight timer (if active) - ctrlm_timeout_destroy(&g_ctrlm.line_of_sight_timeout_tag); - - if(!g_ctrlm.line_of_sight) { - ctrlm_main_iarm_event_binding_line_of_sight(TRUE); - } - // Set line of sight as active - g_ctrlm.line_of_sight = TRUE; - - // Set a timer to clear the line of sight after a period of time - g_ctrlm.line_of_sight_timeout_tag = ctrlm_timeout_create(g_ctrlm.line_of_sight_timeout_val, ctrlm_timeout_line_of_sight, NULL); - return; - } else if(key_code == KED_RF_PAIR_GHOST && key_type == KET_KEYDOWN) { // Received IR autobinding ghost code - XLOGD_INFO("Autobind ghost code received."); - // Cancel active autobind timer (if active) - ctrlm_timeout_destroy(&g_ctrlm.autobind_timeout_tag); - - if(!g_ctrlm.autobind) { - ctrlm_main_iarm_event_autobind_line_of_sight(TRUE); - } - // Set autobind as active - g_ctrlm.autobind = TRUE; - - // Set a timer to clear the autobind after a period of time - g_ctrlm.autobind_timeout_tag = ctrlm_timeout_create(g_ctrlm.autobind_timeout_val, ctrlm_timeout_autobind, NULL); - return; - } - break; - } - case IARM_BUS_IRMGR_KEYSRC_FP: { - if(0) { // TODO Pairing button was pressed - // Cancel active line of sight timer (if active) - ctrlm_timeout_destroy(&g_ctrlm.binding_button_timeout_tag); - - if(!g_ctrlm.binding_button) { - ctrlm_main_iarm_event_binding_button(TRUE); - } - // Set button binding as active - g_ctrlm.binding_button = TRUE; - - // Set a timer to clear the line of sight after a period of time - g_ctrlm.binding_button_timeout_tag = ctrlm_timeout_create(g_ctrlm.binding_button_timeout_val, ctrlm_timeout_binding_button, NULL); - } - return; - } - case IARM_BUS_IRMGR_KEYSRC_RF: { - XLOGD_DEBUG("RF key source received."); - break; - } - default: { - XLOGD_WARN("Other key source received. 0x%08x", ir_event->data.irkey.keySrc); - break; - } - } - - //Listen for control events - if(event_id == IARM_BUS_IRMGR_EVENT_CONTROL) - { - IARM_Bus_IRMgr_EventData_t *ir_event_data = (IARM_Bus_IRMgr_EventData_t*)data; - int key_code = ir_event_data->data.irkey.keyCode; - int key_src = ir_event_data->data.irkey.keySrc; - int key_tag = ir_event_data->data.irkey.keyTag; - int controller_id = ir_event_data->data.irkey.keySourceId; - bool need_to_update_db = false; - bool need_to_update_last_key_info = false; - bool send_on_control_event = false; - ctrlm_ir_remote_type old_remote_type = g_ctrlm.last_key_info.last_ir_remote_type; - ctrlm_remote_keypad_config old_remote_keypad_config = g_ctrlm.last_key_info.remote_keypad_config; - ctrlm_key_source_t last_source_type = g_ctrlm.last_key_info.source_type; - gboolean write_last_key_info = false; - char last_source_name[CTRLM_RCU_RIB_ATTR_LEN_PRODUCT_NAME]; - char source_name[CTRLM_RCU_RIB_ATTR_LEN_PRODUCT_NAME]; - ctrlm_remote_keypad_config remote_keypad_config; - string type; - string str_data; - errno_t safec_rc = -1; - int ind = -1; - - safec_rc = strcpy_s(last_source_name, sizeof(last_source_name), g_ctrlm.last_key_info.source_name); - ERR_CHK(safec_rc); - - if ((key_src != IARM_BUS_IRMGR_KEYSRC_IR) && (key_src != IARM_BUS_IRMGR_KEYSRC_RF)) { - // NOTE: For now, we are explicitly ignoring keypresses from IP or FP sources! - return; - } - - //Check for day change - need_to_update_db = ctrlm_main_handle_day_change_ir_remote_usage(); - - if (len != sizeof(IARM_Bus_IRMgr_EventData_t)) { - XLOGD_ERROR("ERROR - Got IARM_BUS_IRMGR_EVENT_CONTROL event with bad data length <%u>, should be <%u>!!", len, sizeof(IARM_Bus_IRMgr_EventData_t)); - return; - } - - switch(key_code) { - case KED_XR2V3: - case KED_XR5V2: - case KED_XR11V1: - case KED_XR11V2: { - g_ctrlm.last_key_info.last_ir_remote_type = CTRLM_IR_REMOTE_TYPE_XR11V2; - g_ctrlm.last_key_info.remote_keypad_config = CTRLM_REMOTE_KEYPAD_CONFIG_HAS_SETUP_KEY_WITH_NUMBER_KEYS; - g_ctrlm.last_key_info.source_type = IARM_BUS_IRMGR_KEYSRC_IR; - g_ctrlm.last_key_info.is_screen_bind_mode = false; - type = "irRemote"; - str_data = std::to_string(g_ctrlm.last_key_info.remote_keypad_config); - send_on_control_event = true; - need_to_update_last_key_info = true; - safec_rc = strncpy_s(source_name, sizeof(source_name), ctrlm_rcu_ir_remote_types_str(g_ctrlm.last_key_info.last_ir_remote_type), CTRLM_RCU_RIB_ATTR_LEN_PRODUCT_NAME - 1); - ERR_CHK(safec_rc); - source_name[CTRLM_RCU_RIB_ATTR_LEN_PRODUCT_NAME - 1] = '\0'; - switch(key_code) { - case KED_XR2V3: - if(!g_ctrlm.ir_remote_usage_today.has_ir_xr2) { - g_ctrlm.ir_remote_usage_today.has_ir_xr2 = true; - need_to_update_db = true; - } - break; - case KED_XR5V2: - if(!g_ctrlm.ir_remote_usage_today.has_ir_xr5) { - g_ctrlm.ir_remote_usage_today.has_ir_xr5 = true; - need_to_update_db = true; - } - break; - case KED_XR11V1: - case KED_XR11V2: - if(!g_ctrlm.ir_remote_usage_today.has_ir_xr11) { - g_ctrlm.ir_remote_usage_today.has_ir_xr11 = true; - need_to_update_db = true; - } - break; - } - break; - } - - case KED_XR11_NOTIFY: - g_ctrlm.last_key_info.last_ir_remote_type = CTRLM_IR_REMOTE_TYPE_XR11V2; - g_ctrlm.last_key_info.remote_keypad_config = CTRLM_REMOTE_KEYPAD_CONFIG_HAS_SETUP_KEY_WITH_NUMBER_KEYS; - g_ctrlm.last_key_info.source_type = IARM_BUS_IRMGR_KEYSRC_IR; - g_ctrlm.last_key_info.is_screen_bind_mode = false; - XLOGD_INFO("Received KED_XR11_NOTIFY"); - if((!g_ctrlm.ir_remote_usage_today.has_ir_remote) || (old_remote_type != g_ctrlm.last_key_info.last_ir_remote_type) || (old_remote_keypad_config != g_ctrlm.last_key_info.remote_keypad_config)) { - //Don't use has_ir_xr11 because this could be XR2 or XR5. Use has_ir_remote. - g_ctrlm.ir_remote_usage_today.has_ir_remote = true; - need_to_update_db = true; - } - break; - case KED_XR15V1_NOTIFY: - g_ctrlm.last_key_info.last_ir_remote_type = CTRLM_IR_REMOTE_TYPE_XR15V1; - g_ctrlm.last_key_info.remote_keypad_config = CTRLM_REMOTE_KEYPAD_CONFIG_HAS_NO_SETUP_KEY_WITH_NUMBER_KEYS; - g_ctrlm.last_key_info.source_type = IARM_BUS_IRMGR_KEYSRC_IR; - XLOGD_INFO("Received KED_XR15V1_NOTIFY"); - if((!g_ctrlm.ir_remote_usage_today.has_ir_xr15) || (old_remote_type != g_ctrlm.last_key_info.last_ir_remote_type) || (old_remote_keypad_config != g_ctrlm.last_key_info.remote_keypad_config)) { - g_ctrlm.ir_remote_usage_today.has_ir_xr15 = true; - need_to_update_db = true; - } - break; - case KED_XR16V1_NOTIFY: - g_ctrlm.last_key_info.last_ir_remote_type = CTRLM_IR_REMOTE_TYPE_NA; - g_ctrlm.last_key_info.remote_keypad_config = CTRLM_REMOTE_KEYPAD_CONFIG_HAS_NO_SETUP_KEY_WITH_NO_NUMBER_KEYS; - g_ctrlm.last_key_info.source_type = IARM_BUS_IRMGR_KEYSRC_IR; - XLOGD_INFO("Received KED_XR16V1_NOTIFY"); - if((!g_ctrlm.ir_remote_usage_today.has_ir_remote) || (old_remote_type != g_ctrlm.last_key_info.last_ir_remote_type) || (old_remote_keypad_config != g_ctrlm.last_key_info.remote_keypad_config)) { - g_ctrlm.ir_remote_usage_today.has_ir_remote = true; - need_to_update_db = true; - } - break; - case KED_SCREEN_BIND_NOTIFY: - g_ctrlm.last_key_info.is_screen_bind_mode = true; - XLOGD_INFO("Received KED_SCREEN_BIND_NOTIFY"); - break; - case KED_VOLUMEUP: - case KED_VOLUMEDOWN: - case KED_MUTE: - case KED_INPUTKEY: - case KED_POWER: - case KED_TVPOWER: - case KED_RF_POWER: - case KED_DISCRETE_POWER_ON: - case KED_DISCRETE_POWER_STANDBY: { - send_on_control_event = true; - need_to_update_last_key_info = true; - type = "TV"; - break; - } - case KED_PUSH_TO_TALK: - send_on_control_event = true; - need_to_update_last_key_info = true; - type = "mic"; - break; - default: - break; - } - - if(key_src == IARM_BUS_IRMGR_KEYSRC_RF) { - ctrlm_controller_product_name_get(controller_id, source_name); - remote_keypad_config = ctrlm_get_remote_keypad_config(source_name); - } else { - remote_keypad_config = g_ctrlm.last_key_info.remote_keypad_config; - controller_id = -1; - //Check to see if the tag was included. If so, use it. - ctrlm_check_for_key_tag(key_tag); - safec_rc = strcpy_s(source_name, sizeof(source_name), ctrlm_rcu_ir_remote_types_str(g_ctrlm.last_key_info.last_ir_remote_type)); - ERR_CHK(safec_rc); - } - - XLOGD_INFO("Got IARM_BUS_IRMGR_EVENT_CONTROL event, controller_id <%d>, controlCode <0x%02X>, src <%d>.", controller_id, (unsigned int)key_code, key_src); - - //Only save the last key info to the db if the source type (IR or RF) or the source name (XR11, XR15) have changed - //It's not worth the writes to the db for every key. It is important to know if we are IR/RF and XR11/XR15 - bool isValid = false; - (last_source_type != key_src) ? isValid = true : (safec_rc = strcmp_s(last_source_name, sizeof(last_source_name), source_name, &ind)); - if((isValid) || ((safec_rc == EOK) && (ind != 0))) { - write_last_key_info = true; - } else if(safec_rc != EOK) { - ERR_CHK(safec_rc); - } - - if(send_on_control_event) { - str_data = std::to_string(remote_keypad_config); - ctrlm_rcu_iarm_event_control(controller_id, key_source_names[key_src], type.c_str(), str_data.c_str(), key_code, 0); - } - - if(need_to_update_last_key_info) { - ctrlm_update_last_key_info(controller_id, key_src, key_code, source_name, g_ctrlm.last_key_info.is_screen_bind_mode, write_last_key_info); - } - - if(need_to_update_db) { - ctrlm_property_write_ir_remote_usage(); - } - } - //Listen for key events to keep track of last key info - else if (event_id == IARM_BUS_IRMGR_EVENT_IRKEY) - { - IARM_Bus_IRMgr_EventData_t *ir_event_data = (IARM_Bus_IRMgr_EventData_t*)data; - int key_code = ir_event_data->data.irkey.keyCode; - int key_src = ir_event_data->data.irkey.keySrc; - int key_tag = ir_event_data->data.irkey.keyTag; - int controller_id = ir_event_data->data.irkey.keySourceId; - guchar last_source_type = g_ctrlm.last_key_info.source_type; - gboolean write_last_key_info = false; - char last_source_name[CTRLM_RCU_RIB_ATTR_LEN_PRODUCT_NAME]; - char source_name[CTRLM_RCU_RIB_ATTR_LEN_PRODUCT_NAME]; - - errno_t safec_rc = -1; - int ind = -1; - - safec_rc = strcpy_s(last_source_name, sizeof(last_source_name), g_ctrlm.last_key_info.source_name); - ERR_CHK(safec_rc); - - if ((ir_event_data->data.irkey.keyType == KET_KEYUP) || (ir_event_data->data.irkey.keyType == KET_KEYREPEAT)) { - // Don't remember keyup or repeat events - only use keydown. - return; - } - - if ((key_src != IARM_BUS_IRMGR_KEYSRC_IR) && (key_src != IARM_BUS_IRMGR_KEYSRC_RF)) { - // NOTE: For now, we are explicitly ignoring keypresses from IP or FP sources! - return; - } - - if (key_src != IARM_BUS_IRMGR_KEYSRC_RF) { - controller_id = -1; - } - - if(key_src == IARM_BUS_IRMGR_KEYSRC_RF) { - ctrlm_controller_product_name_get(controller_id, source_name); - } else { - controller_id = -1; - //Check to see if the tag was included. If so, use it. - ctrlm_check_for_key_tag(key_tag); - safec_rc = strcpy_s(source_name, sizeof(source_name), ctrlm_rcu_ir_remote_types_str(g_ctrlm.last_key_info.last_ir_remote_type)); - ERR_CHK(safec_rc); - } - - if (len != sizeof(IARM_Bus_IRMgr_EventData_t)) { - XLOGD_ERROR("ERROR - Got IARM_BUS_IRMGR_EVENT_IRKEY event with bad data length <%u>, should be <%u>!!", len, sizeof(IARM_Bus_IRMgr_EventData_t)); - return; - } - - //Only save the last key info to the db if the source type (IR or RF) or the source name (XR11, XR15) have changed - //It's not worth the writes to the db for every key. It is important to know if we are IR/RF and XR11/XR15 - bool isValid = false; - (last_source_type != key_src) ? isValid = true : (safec_rc = strcmp_s(last_source_name, sizeof(last_source_name), source_name, &ind)); - if((isValid) || ((safec_rc == EOK) && (ind != 0))) { - write_last_key_info = true; - } else if(safec_rc != EOK) { - ERR_CHK(safec_rc); - } - - ctrlm_update_last_key_info(controller_id, key_src, key_code, source_name, g_ctrlm.last_key_info.is_screen_bind_mode, write_last_key_info); - } -} - -void ctrlm_check_for_key_tag(int key_tag) { - switch(key_tag) { - case XMP_TAG_PLATCO: { - g_ctrlm.last_key_info.last_ir_remote_type = CTRLM_IR_REMOTE_TYPE_PLATCO; - break; - } - case XMP_TAG_XR11V2: { - g_ctrlm.last_key_info.last_ir_remote_type = CTRLM_IR_REMOTE_TYPE_XR11V2; - break; - } - case XMP_TAG_XR15V1: { - g_ctrlm.last_key_info.last_ir_remote_type = CTRLM_IR_REMOTE_TYPE_XR15V1; - break; - } - case XMP_TAG_XR15V2: { - g_ctrlm.last_key_info.last_ir_remote_type = CTRLM_IR_REMOTE_TYPE_XR15V2; - break; - } - case XMP_TAG_XR16V1: { - g_ctrlm.last_key_info.last_ir_remote_type = CTRLM_IR_REMOTE_TYPE_XR16V1; - break; - } - case XMP_TAG_XRAV1: { - g_ctrlm.last_key_info.last_ir_remote_type = CTRLM_IR_REMOTE_TYPE_XRAV1; - break; - } - case XMP_TAG_XR20V1: { - g_ctrlm.last_key_info.last_ir_remote_type = CTRLM_IR_REMOTE_TYPE_XR20V1; - break; - } - case XMP_TAG_COMCAST: - case XMP_TAG_UNDEFINED: - default: { - break; - } - } - if(key_tag != XMP_TAG_COMCAST) { - XLOGD_DEBUG("key_tag <%s>", ctrlm_rcu_ir_remote_types_str(g_ctrlm.last_key_info.last_ir_remote_type)); - } -} -#endif // USE_DEPRECATED_IRMGR - gboolean ctrlm_timeout_line_of_sight(gpointer user_data) { XLOGD_INFO("Timeout - Line of sight."); // Allocate a message and send it to Control Manager's queue @@ -5891,35 +5538,6 @@ ctrlm_controller_id_t ctrlm_last_used_controller_get(ctrlm_network_type_t networ return CTRLM_MAIN_CONTROLLER_ID_INVALID; } -void ctrlm_controller_product_name_get(ctrlm_controller_id_t controller_id, char *source_name) { - // Signal completion of the operation - sem_t semaphore; - ctrlm_main_status_cmd_result_t cmd_result = CTRLM_MAIN_STATUS_REQUEST_PENDING; - - // Allocate a message and send it to Control Manager's queue - ctrlm_main_queue_msg_product_name_t msg; - errno_t safec_rc = memset_s(&msg, sizeof(msg), 0, sizeof(msg)); - ERR_CHK(safec_rc); - - sem_init(&semaphore, 0, 0); - msg.controller_id = controller_id; - msg.product_name = source_name; - msg.semaphore = &semaphore; - msg.cmd_result = &cmd_result; - - ctrlm_main_queue_handler_push(CTRLM_HANDLER_NETWORK, (ctrlm_msg_handler_network_t)&ctrlm_obj_network_t::req_process_controller_product_name, &msg, sizeof(msg), NULL, 1); // TODO: Hack, using default RF4CE network ID. - - // Wait for the result semaphore to be signaled - XLOGD_DEBUG("Waiting for main thread to process CONTROLLER_TYPE request"); - sem_wait(&semaphore); - sem_destroy(&semaphore); - - if(cmd_result != CTRLM_MAIN_STATUS_REQUEST_SUCCESS) { - XLOGD_ERROR("ERROR getting product name!!"); - return; - } -} - void control_service_values_read_from_db() { guchar *data = NULL; guint32 length; @@ -6064,12 +5682,6 @@ gboolean ctrlm_start_iarm(gpointer user_data) { // Register iarm calls and events XLOGD_INFO(": Register iarm calls and events"); -#ifdef USE_DEPRECATED_IRMGR - // IARM Events that we are listening to from other processes - IARM_Bus_RegisterEventHandler(IARM_BUS_IRMGR_NAME, IARM_BUS_IRMGR_EVENT_IRKEY, ctrlm_event_handler_ir); - IARM_Bus_RegisterEventHandler(IARM_BUS_IRMGR_NAME, IARM_BUS_IRMGR_EVENT_CONTROL, ctrlm_event_handler_ir); -#endif - ctrlm_main_iarm_init(); XLOGD_INFO("Notifying systemd of successful initialization"); diff --git a/src/ctrlm_main_iarm.cpp b/src/ctrlm_main_iarm.cpp index db124af4..a51cdd1f 100644 --- a/src/ctrlm_main_iarm.cpp +++ b/src/ctrlm_main_iarm.cpp @@ -22,9 +22,6 @@ #include #include "libIBus.h" #include "libIBusDaemon.h" -#ifdef USE_DEPRECATED_IRMGR -#include "irMgr.h" -#endif #include "sysMgr.h" #include "comcastIrKeyCodes.h" #include "ctrlm.h" @@ -129,12 +126,6 @@ void ctrlm_main_iarm_terminate(void) { // Change to stopped or terminated state, so we do not accept new calls g_atomic_int_set(&running, 0); -#ifdef USE_DEPRECATED_IRMGR - // IARM Events that we are listening to from other processes - IARM_Bus_RemoveEventHandler(IARM_BUS_IRMGR_NAME, IARM_BUS_IRMGR_EVENT_IRKEY, ctrlm_event_handler_ir); - IARM_Bus_RemoveEventHandler(IARM_BUS_IRMGR_NAME, IARM_BUS_IRMGR_EVENT_CONTROL, ctrlm_event_handler_ir); -#endif - // Unregister calls that can be invoked by IARM bus clients //for(index = 0; index < sizeof(ctrlm_iarm_calls)/sizeof(ctrlm_iarm_call_t); index++) { // result = IARM_Bus_UnRegisterCall(ctrlm_iarm_calls[index].name, ctrlm_iarm_calls[index].handler); From c2483a9572613d81b853a2c2b80bd52497bfec5d Mon Sep 17 00:00:00 2001 From: Kelvin Lu <119349872+klu339@users.noreply.github.com> Date: Mon, 13 Jul 2026 10:48:21 -0400 Subject: [PATCH 73/81] RDKEMW-20543: Send IR Prog State RF4CE Network (#252) --- src/rf4ce/ctrlm_rf4ce_network.cpp | 11 +++++++++++ src/rf4ce/ctrlm_rf4ce_network.h | 1 + 2 files changed, 12 insertions(+) diff --git a/src/rf4ce/ctrlm_rf4ce_network.cpp b/src/rf4ce/ctrlm_rf4ce_network.cpp index 85a3caea..91df3fb5 100644 --- a/src/rf4ce/ctrlm_rf4ce_network.cpp +++ b/src/rf4ce/ctrlm_rf4ce_network.cpp @@ -2620,6 +2620,13 @@ guchar ctrlm_obj_network_rf4ce_t::target_irdb_status_flags_get() { return(target_irdb_status_.flags); } +void ctrlm_obj_network_rf4ce_t::ir_prog_state_set(ctrlm_ir_state_t state) { + THREAD_ID_VALIDATE(); + XLOGD_INFO("RF4CE remote IR programming state changed to <%s>", ctrlm_ir_state_str(state)); + ir_state_ = state; + iarm_event_rcu_status(); +} + ctrlm_rf4ce_controller_irdb_status_t ctrlm_obj_network_rf4ce_t::most_recent_controller_irdb_status_get(void) { THREAD_ID_VALIDATE(); ctrlm_rf4ce_controller_irdb_status_t most_recent_controller_irdb_status; @@ -4452,6 +4459,8 @@ void ctrlm_obj_network_rf4ce_t::req_process_program_ir_codes(void *data, int siz XLOGD_ERROR("Controller %u doesn't exist", dqm->controller_id); } + ir_prog_state_set(success ? CTRLM_IR_STATE_COMPLETE : CTRLM_IR_STATE_FAILED); + if(dqm->success) dqm->success->push_back(success); // post the semaphore if(dqm->semaphore) { @@ -4482,6 +4491,8 @@ void ctrlm_obj_network_rf4ce_t::req_process_ir_clear_codes(void *data, int size) XLOGD_ERROR("Controller %u doesn't exist", dqm->controller_id); } + ir_prog_state_set(success ? CTRLM_IR_STATE_COMPLETE : CTRLM_IR_STATE_FAILED); + if(dqm->success) dqm->success->push_back(success); // post the semaphore if(dqm->semaphore) { diff --git a/src/rf4ce/ctrlm_rf4ce_network.h b/src/rf4ce/ctrlm_rf4ce_network.h index 10cc771a..44dd2570 100644 --- a/src/rf4ce/ctrlm_rf4ce_network.h +++ b/src/rf4ce/ctrlm_rf4ce_network.h @@ -386,6 +386,7 @@ class ctrlm_obj_network_rf4ce_t : public ctrlm_obj_network_t gboolean target_irdb_status_read_from_db(); void target_irdb_status_set(ctrlm_rf4ce_controller_irdb_status_t controller_irdb_status); guchar target_irdb_status_flags_get(); + void ir_prog_state_set(ctrlm_ir_state_t state); ctrlm_rf4ce_controller_irdb_status_t most_recent_controller_irdb_status_get(); virtual void disable_hal_calls(); From 51f7a1e453b0ac7cbe65c3fe1611bd32bdd23575 Mon Sep 17 00:00:00 2001 From: dwolaver <44593664+dwolaver@users.noreply.github.com> Date: Mon, 13 Jul 2026 15:08:00 -0400 Subject: [PATCH 74/81] RDKEMW-17936 : remove ctrlm build flags - USE_IARM_POWER_MANAGER (#251) --- CMakeLists.txt | 5 - ci/cov_build.sh | 1 - src/CMakeLists.txt | 13 +-- src/ctrlm_main.cpp | 8 +- src/ctrlm_main_iarm.cpp | 9 -- src/ctrlm_powermanager_factory.cpp | 19 ++-- src/ctrlm_utils.cpp | 27 ----- src/ctrlm_utils.h | 6 -- src/factory/CMakeLists.txt | 2 +- src/factory/ctrlmf_main.c | 2 + src/factory/ctrlmf_version.c | 26 ++++- src/ipc/ctrlm_ipc_iarm_powermanager.cpp | 126 ------------------------ src/ipc/ctrlm_ipc_iarm_powermanager.h | 40 -------- src/voice/ctrlm_voice_obj.cpp | 16 +++ 14 files changed, 57 insertions(+), 243 deletions(-) delete mode 100755 src/ipc/ctrlm_ipc_iarm_powermanager.cpp delete mode 100755 src/ipc/ctrlm_ipc_iarm_powermanager.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 55d597d8..b7d58266 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,7 +47,6 @@ option(TELEMETRY_SUPPORT "Enable TELEMETRY_SUPPORT" OFF) option(THUNDER "Enable THUNDER" ON) option(THUNDER_SECURITY "Enable THUNDER_SECURITY" OFF) option(USE_SAFEC "Use safec" OFF) -option(USE_IARM_POWER_MANAGER "Use IARM Power Manager" OFF) option(XRSR_HTTP "Enable XRSR_HTTP" OFF) option(XRSR_SDT "Enable XRSR_SDT" OFF) option(ENABLE_ASYNC_SRVR_MSG "Enable Asynchronous Server Messaging Feature" OFF) @@ -238,10 +237,6 @@ if(THUNDER) endif() endif() -if(USE_IARM_POWER_MANAGER) - add_compile_definitions(USE_IARM_POWER_MANAGER) -endif() - if(USE_SAFEC) find_package(PkgConfig) pkg_check_modules(SAFEC REQUIRED libsafec) diff --git a/ci/cov_build.sh b/ci/cov_build.sh index 5b48686b..c89df5b4 100644 --- a/ci/cov_build.sh +++ b/ci/cov_build.sh @@ -51,7 +51,6 @@ cmake -G Ninja -S "$GITHUB_WORKSPACE" -B build/control \ -DBUILD_CTRLM_FACTORY=OFF \ -DBUILD_FACTORY_TEST=OFF \ -DUSE_SAFEC=OFF \ --DUSE_IARM_POWER_MANAGER=ON \ -DBREAKPAD=OFF \ -DFDC_ENABLED=OFF \ -DENABLE_ASYNC_SRVR_MSG=OFF \ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 99916598..6cc4dd7a 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -144,17 +144,6 @@ if(BUILD_CTRLM_SERVER) add_subdirectory(server) endif() -if(USE_IARM_POWER_MANAGER) - target_sources(controlMgr PRIVATE - ipc/ctrlm_ipc_iarm_powermanager.cpp - ) -else() - target_sources(controlMgr PRIVATE - thunder/ctrlm_thunder_powermanager.cpp - thunder/ctrlm_thunder_plugin_powermanager.cpp - ) -endif() - if(RF4CE_ENABLED) target_sources(controlMgr PRIVATE rf4ce/controller/attributes/ctrlm_rf4ce_controller_attr_battery.cpp @@ -192,6 +181,8 @@ if(THUNDER) thunder/ctrlm_thunder_controller.cpp thunder/ctrlm_thunder_plugin.cpp thunder/ctrlm_thunder_plugin_system_audio_player.cpp + thunder/ctrlm_thunder_powermanager.cpp + thunder/ctrlm_thunder_plugin_powermanager.cpp thunder/helpers/ctrlm_thunder_helpers.cpp thunder/plugins/ctrlm_thunder_plugin_cec_sink.cpp thunder/plugins/ctrlm_thunder_plugin_cec_source.cpp diff --git a/src/ctrlm_main.cpp b/src/ctrlm_main.cpp index daf0977b..2d5348bf 100644 --- a/src/ctrlm_main.cpp +++ b/src/ctrlm_main.cpp @@ -2713,7 +2713,7 @@ gpointer ctrlm_main_thread(gpointer param) { g_ctrlm.wake_with_voice_allowed = false; - if((wake_with_voice_allowed == true) && (g_ctrlm.power_manager->get_wakeup_reason_voice())) { + if((wake_with_voice_allowed == true) && (g_ctrlm.power_manager != NULL) && (g_ctrlm.power_manager->get_wakeup_reason_voice())) { if( g_ctrlm.voice_session->nsm_voice_session == true ) { XLOGD_INFO("Handling NSM voice session, ignore ON"); } else { @@ -5523,7 +5523,11 @@ gboolean ctrlm_main_get_networked_standby_mode(void) { bool networked_standby_mode = false; if(g_ctrlm.networked_standby_supported && (g_ctrlm.power_state == CTRLM_POWER_STATE_DEEP_SLEEP)) { - networked_standby_mode = g_ctrlm.power_manager->get_networked_standby_mode(); + if(g_ctrlm.power_manager == NULL) { + XLOGD_ERROR("power_manager is invalid, defaulting to OFF"); + } else { + networked_standby_mode = g_ctrlm.power_manager->get_networked_standby_mode(); + } } return networked_standby_mode ? true : false; diff --git a/src/ctrlm_main_iarm.cpp b/src/ctrlm_main_iarm.cpp index a51cdd1f..a967f46f 100644 --- a/src/ctrlm_main_iarm.cpp +++ b/src/ctrlm_main_iarm.cpp @@ -27,7 +27,6 @@ #include "ctrlm.h" #include "ctrlm_log.h" #include "ctrlm_ipc.h" -#include "ctrlm_ipc_iarm_powermanager.h" #include "ctrlm_network.h" #include "ctrlm_tr181.h" #include "ctrlm_utils.h" @@ -56,9 +55,6 @@ static IARM_Result_t ctrlm_main_iarm_call_start_pair_with_code(void *arg); static IARM_Result_t ctrlm_main_iarm_call_chip_status_get(void *arg); static IARM_Result_t ctrlm_main_iarm_call_audio_capture_start(void *arg); static IARM_Result_t ctrlm_main_iarm_call_audio_capture_stop(void *arg); -#if CTRLM_HAL_RF4CE_API_VERSION >= 10 && !defined(CTRLM_DPI_CONTROL_NOT_SUPPORTED) -extern IARM_Result_t ctrlm_iarm_powermanager_event_handler_power_pre_change(void* pArgs); -#endif typedef struct { const char * name; @@ -92,11 +88,6 @@ ctrlm_iarm_call_t ctrlm_iarm_calls[] = { {CTRLM_MAIN_IARM_CALL_CHIP_STATUS_GET, ctrlm_main_iarm_call_chip_status_get }, {CTRLM_MAIN_IARM_CALL_AUDIO_CAPTURE_START, ctrlm_main_iarm_call_audio_capture_start }, {CTRLM_MAIN_IARM_CALL_AUDIO_CAPTURE_STOP, ctrlm_main_iarm_call_audio_capture_stop }, - #if USE_IARM_POWER_MANAGER - #if CTRLM_HAL_RF4CE_API_VERSION >= 10 && !defined(CTRLM_DPI_CONTROL_NOT_SUPPORTED) - {IARM_BUS_COMMON_API_PowerPreChange, ctrlm_iarm_powermanager_event_handler_power_pre_change }, - #endif - #endif }; diff --git a/src/ctrlm_powermanager_factory.cpp b/src/ctrlm_powermanager_factory.cpp index 7048c028..bd4eeae8 100755 --- a/src/ctrlm_powermanager_factory.cpp +++ b/src/ctrlm_powermanager_factory.cpp @@ -18,32 +18,31 @@ */ #include #include "ctrlm_powermanager.h" -#ifdef USE_IARM_POWER_MANAGER -#include "ctrlm_ipc_iarm_powermanager.h" -#else #include "ctrlm_thunder_powermanager.h" -#endif +#ifdef CTRLM_THUNDER static ctrlm_powermanager_t *instance = NULL; +#endif ctrlm_powermanager_t* ctrlm_powermanager_t::get_instance() { + #ifdef CTRLM_THUNDER if(instance == NULL) { - #ifdef USE_IARM_POWER_MANAGER - instance = new ctrlm_ipc_iarm_powermanager_t(); - #else instance = new ctrlm_thunder_powermanager_t(); - #endif } - + return(instance); + #else + return(NULL); + #endif } void ctrlm_powermanager_t::destroy_instance() { - + #ifdef CTRLM_THUNDER if(instance != NULL) { delete instance; instance = NULL; } + #endif } ctrlm_powermanager_t::~ctrlm_powermanager_t() { diff --git a/src/ctrlm_utils.cpp b/src/ctrlm_utils.cpp index 6be8556a..d2a87311 100644 --- a/src/ctrlm_utils.cpp +++ b/src/ctrlm_utils.cpp @@ -1383,33 +1383,6 @@ const char *ctrlm_linux_key_code_str(uint16_t code, bool mask) { } } -#ifdef USE_IARM_POWER_MANAGER -const char *ctrlm_wakeup_reason_str(DeepSleep_WakeupReason_t wakeup_reason) { - switch(wakeup_reason) { - case DEEPSLEEP_WAKEUPREASON_IR: return("IR"); - case DEEPSLEEP_WAKEUPREASON_RCU_BT: return("RCU_BT"); - case DEEPSLEEP_WAKEUPREASON_RCU_RF4CE: return("RCU_RF4CE"); - case DEEPSLEEP_WAKEUPREASON_GPIO: return("GPIO"); - case DEEPSLEEP_WAKEUPREASON_LAN: return("LAN"); - case DEEPSLEEP_WAKEUPREASON_WLAN: return("WLAN"); - case DEEPSLEEP_WAKEUPREASON_TIMER: return("TIMER"); - case DEEPSLEEP_WAKEUPREASON_FRONT_PANEL: return("FRONT_PANEL"); - case DEEPSLEEP_WAKEUPREASON_WATCHDOG: return("WATCHDOG"); - case DEEPSLEEP_WAKEUPREASON_SOFTWARE_RESET: return("SOFTWARE_RESET"); - case DEEPSLEEP_WAKEUPREASON_THERMAL_RESET: return("THERMAL_RESET"); - case DEEPSLEEP_WAKEUPREASON_WARM_RESET: return("WARM_RESET"); - case DEEPSLEEP_WAKEUPREASON_COLDBOOT: return("COLDBOOT"); - case DEEPSLEEP_WAKEUPREASON_STR_AUTH_FAILURE: return("STR_AUTH_FAILURE"); - case DEEPSLEEP_WAKEUPREASON_CEC: return("CEC"); - case DEEPSLEEP_WAKEUPREASON_PRESENCE: return("PRESENCE"); - case DEEPSLEEP_WAKEUPREASON_VOICE: return("VOICE"); - case DEEPSLEEP_WAKEUPREASON_UNKNOWN: return("UNKNOWN"); - case DEEPSLEEP_WAKEUPREASON_MAX: return("MAX"); - } - return(ctrlm_invalid_return(wakeup_reason)); -} -#endif - bool ctrlm_file_copy(const char* src, const char* dst, bool overwrite, bool follow_dst_symbolic_link) { bool ret = FALSE; GFile *g_src = g_file_new_for_path(src); diff --git a/src/ctrlm_utils.h b/src/ctrlm_utils.h index baed40e7..098131be 100644 --- a/src/ctrlm_utils.h +++ b/src/ctrlm_utils.h @@ -36,9 +36,6 @@ #include "libIBus.h" #include "libIBusDaemon.h" #include -#ifdef USE_IARM_POWER_MANAGER -#include "deepSleepMgr.h" -#endif #ifdef TELEMETRY_SUPPORT #include #endif @@ -205,9 +202,6 @@ const char *ctrlm_ir_state_str(ctrlm_ir_state_t state); const char *ctrlm_power_state_str(ctrlm_power_state_t state); const char *ctrlm_device_type_str(ctrlm_device_type_t device_type); -#ifdef USE_IARM_POWER_MANAGER -const char *ctrlm_wakeup_reason_str(DeepSleep_WakeupReason_t wakeup_reason); -#endif const char *ctrlm_rcu_wakeup_config_str(ctrlm_rcu_wakeup_config_t config); #ifdef TELEMETRY_SUPPORT diff --git a/src/factory/CMakeLists.txt b/src/factory/CMakeLists.txt index 530cbf5b..610e05c8 100644 --- a/src/factory/CMakeLists.txt +++ b/src/factory/CMakeLists.txt @@ -40,7 +40,6 @@ target_sources(ctrlm-fta PRIVATE ctrlmf_utils.c ctrlmf_audio_capture.cpp ctrlmf_audio_control.cpp - ctrlmf_audio_playback.cpp ctrlmf_mic_test.cpp ctrlmf_ws.c iarm/ctrlmf_iarm_client.cpp @@ -58,6 +57,7 @@ endif() if(THUNDER) add_compile_definitions(PRIVATE CTRLMF_THUNDER) target_sources(ctrlm-fta PRIVATE + ctrlmf_audio_playback.cpp thunder/ctrlmf_thunder_controller.cpp thunder/ctrlmf_thunder_plugin.cpp thunder/ctrlmf_thunder_plugin_system_audio_player.cpp diff --git a/src/factory/ctrlmf_main.c b/src/factory/ctrlmf_main.c index e70337d9..11e07039 100644 --- a/src/factory/ctrlmf_main.c +++ b/src/factory/ctrlmf_main.c @@ -116,7 +116,9 @@ int main(int argc, char* argv[]) { XLOGD_INFO("ctrlmf_main: test result <%s>", test_result.pass ? "PASS" : "FAIL"); } } else if(g_ctrlmf_opts.audio_file_path != NULL) { + #ifdef CTRLMF_THUNDER ctrlmf_audio_playback_start(g_ctrlmf_opts.audio_file_path); + #endif } if(g_ctrlmf_opts.mute_main_audio) { ctrlmf_audio_control_mute(false); diff --git a/src/factory/ctrlmf_version.c b/src/factory/ctrlmf_version.c index 7d52efc0..bf148401 100644 --- a/src/factory/ctrlmf_version.c +++ b/src/factory/ctrlmf_version.c @@ -7,7 +7,9 @@ #include #include #include +#ifdef CTRLMF_THUNDER #include +#endif #include #include @@ -56,12 +58,24 @@ bool ctrlmf_init(xlog_level_t level, bool requires_audio_playback, bool requires return(false); } - if(requires_audio_playback && !ctrlmf_audio_playback_init()) { - XLOGD_ERROR("failed to init audio playback"); - if(requires_audio_control) { - ctrlmf_audio_control_term(); + if(requires_audio_playback) { + #ifdef CTRLMF_THUNDER + bool audio_playback_available = true; + if(!ctrlmf_audio_playback_init()) { + XLOGD_ERROR("failed to init audio playback"); + audio_playback_available = false; + } + #else + bool audio_playback_available = false; + XLOGD_ERROR("audio playback is disabled"); + #endif + + if(!audio_playback_available) { + if(requires_audio_control) { + ctrlmf_audio_control_term(); + } + return(false); } - return(false); } g_ctrlmf.handle_audio_analysis = ctrlmf_load_plugin_audio_analysis(audio_analyze_func); @@ -74,7 +88,9 @@ bool ctrlmf_init(xlog_level_t level, bool requires_audio_playback, bool requires void ctrlmf_term(void) { if(g_ctrlmf.audio_playback_init) { + #ifdef CTRLMF_THUNDER ctrlmf_audio_playback_term(); + #endif } if(g_ctrlmf.audio_control_init) { diff --git a/src/ipc/ctrlm_ipc_iarm_powermanager.cpp b/src/ipc/ctrlm_ipc_iarm_powermanager.cpp deleted file mode 100755 index 24897391..00000000 --- a/src/ipc/ctrlm_ipc_iarm_powermanager.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/* - * If not stated otherwise in this file or this component's license file the - * following copyright and licenses apply: - * - * Copyright 2015 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. -*/ -#include "ctrlm.h" -#include "ctrlm_ipc.h" -#include "ctrlm_ipc_iarm_powermanager.h" -#include "ctrlm_log.h" -#include "ctrlm_utils.h" -#include "pwrMgr.h" -#include "ctrlm_tr181.h" - -static ctrlm_power_state_t ctrlm_iarm_power_state_map(IARM_Bus_PowerState_t iarm_power_state); - -ctrlm_ipc_iarm_powermanager_t::ctrlm_ipc_iarm_powermanager_t() { - XLOGD_INFO("IARM PowerManager Implementation"); -} - -ctrlm_ipc_iarm_powermanager_t::~ctrlm_ipc_iarm_powermanager_t() { -} - -ctrlm_power_state_t ctrlm_ipc_iarm_powermanager_t::get_power_state() { - IARM_Bus_PWRMgr_GetPowerState_Param_t param; - ctrlm_power_state_t power_state = CTRLM_POWER_STATE_ON; - - if(IARM_RESULT_SUCCESS != IARM_Bus_Call(IARM_BUS_PWRMGR_NAME, IARM_BUS_PWRMGR_API_GetPowerState, (void *)¶m, sizeof(param))) { - XLOGD_WARN("IARM bus failed to read power state, defaulting to <%s>", ctrlm_power_state_str(power_state)); - } else { - power_state = ctrlm_iarm_power_state_map(param.curState); - //If ctrlm restarts with system STANDBY state, set to ON, will receive a DEEP_SLEEP or ON message shortly - if(ctrlm_is_networked_standby_supported() && (power_state == CTRLM_POWER_STATE_STANDBY)) { - power_state = CTRLM_POWER_STATE_ON; - } - XLOGD_DEBUG("power state <%s>", ctrlm_power_state_str(power_state)); - } - - return power_state; -} - -bool ctrlm_ipc_iarm_powermanager_t::get_networked_standby_mode() { - IARM_Bus_PWRMgr_NetworkStandbyMode_Param_t param = {0}; - IARM_Result_t res = IARM_Bus_Call(IARM_BUS_PWRMGR_NAME, IARM_BUS_PWRMGR_API_GetNetworkStandbyMode, (void *)¶m, sizeof(param)); - - if (res != IARM_RESULT_SUCCESS) { - XLOGD_ERROR("IARM query for network standby mode failed, default to NO"); - return false; - } - - return param.bStandbyMode ? true : false; - -} - -bool ctrlm_ipc_iarm_powermanager_t::get_wakeup_reason_voice() { - DeepSleep_WakeupReason_t wakeup_reason; - IARM_Result_t res; - bool wakeup_reason_voice = false; - bool pwrmgr2 = false; - - if(CTRLM_TR181_RESULT_SUCCESS != ctrlm_tr181_bool_get(CTRLM_RT181_POWER_RFC_PWRMGR2, &pwrmgr2)) { - XLOGD_INFO("failed to determine Power Manager revision, defaulting to 1"); - } - - res = IARM_Bus_Call(pwrmgr2 ? IARM_BUS_PWRMGR_NAME : IARM_BUS_DEEPSLEEPMGR_NAME, IARM_BUS_DEEPSLEEPMGR_API_GetLastWakeupReason, (void*)&wakeup_reason, sizeof(wakeup_reason)); - if(res != IARM_RESULT_SUCCESS) { - XLOGD_ERROR("IARM query for wakeup reason failed, returning false!"); - return false; - } - - XLOGD_AUTOMATION_INFO("wakeup_reason <%s>", ctrlm_wakeup_reason_str(wakeup_reason)); - - wakeup_reason_voice = (wakeup_reason == DEEPSLEEP_WAKEUPREASON_VOICE) ? true: false; - - return wakeup_reason_voice; -} - -#if CTRLM_HAL_RF4CE_API_VERSION >= 10 && !defined(CTRLM_DPI_CONTROL_NOT_SUPPORTED) -IARM_Result_t ctrlm_iarm_powermanager_event_handler_power_pre_change(void* pArgs) -{ - const IARM_Bus_CommonAPI_PowerPreChange_Param_t* pParams = (const IARM_Bus_CommonAPI_PowerPreChange_Param_t*) pArgs; - - if(pArgs == NULL) { - XLOGD_ERROR("Invalid argument"); - return IARM_RESULT_INVALID_PARAM; - } - - ctrlm_main_queue_power_state_change_t *msg = (ctrlm_main_queue_power_state_change_t *)g_malloc(sizeof(ctrlm_main_queue_power_state_change_t)); - if(NULL == msg) { - XLOGD_FATAL("Out of memory"); - g_assert(0); - return IARM_RESULT_OOM; - } - - msg->header.type = CTRLM_MAIN_QUEUE_MSG_TYPE_POWER_STATE_CHANGE; - msg->new_state = ctrlm_iarm_power_state_map(pParams->newState); - XLOGD_DEBUG("Power State mapped to <%s>", ctrlm_power_state_str(msg->new_state)); - ctrlm_main_queue_msg_push(msg); - - return IARM_RESULT_SUCCESS; -} -#endif - -ctrlm_power_state_t ctrlm_iarm_power_state_map(IARM_Bus_PowerState_t iarm_power_state) { - - switch(iarm_power_state) { - case IARM_BUS_PWRMGR_POWERSTATE_ON: return CTRLM_POWER_STATE_ON; - case IARM_BUS_PWRMGR_POWERSTATE_STANDBY: - case IARM_BUS_PWRMGR_POWERSTATE_STANDBY_LIGHT_SLEEP: return CTRLM_POWER_STATE_STANDBY; - case IARM_BUS_PWRMGR_POWERSTATE_STANDBY_DEEP_SLEEP: - case IARM_BUS_PWRMGR_POWERSTATE_OFF: return CTRLM_POWER_STATE_DEEP_SLEEP; - default: return CTRLM_POWER_STATE_ON; - } -} diff --git a/src/ipc/ctrlm_ipc_iarm_powermanager.h b/src/ipc/ctrlm_ipc_iarm_powermanager.h deleted file mode 100755 index 4944340a..00000000 --- a/src/ipc/ctrlm_ipc_iarm_powermanager.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * If not stated otherwise in this file or this component's license file the - * following copyright and licenses apply: - * - * Copyright 2015 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. -*/ -#include "ctrlm_ipc.h" -#include "ctrlm_powermanager.h" -#include - -class ctrlm_ipc_iarm_powermanager_t : public ctrlm_powermanager_t { -public: - ctrlm_ipc_iarm_powermanager_t(); - ~ctrlm_ipc_iarm_powermanager_t(); - - ctrlm_power_state_t get_power_state(); - bool get_networked_standby_mode(); - bool get_wakeup_reason_voice(); - - -private: - sem_t semaphore; -}; - -#if CTRLM_HAL_RF4CE_API_VERSION >= 10 && !defined(CTRLM_DPI_CONTROL_NOT_SUPPORTED) -IARM_Result_t ctrlm_iarm_powermanager_event_handler_power_pre_change(void* pArgs); -#endif -IARM_Result_t ctrlm_iarm_powermanager_call_power_state_change(void *arg); diff --git a/src/voice/ctrlm_voice_obj.cpp b/src/voice/ctrlm_voice_obj.cpp index e6e8636d..43f28c05 100644 --- a/src/voice/ctrlm_voice_obj.cpp +++ b/src/voice/ctrlm_voice_obj.cpp @@ -67,7 +67,9 @@ static void ctrlm_voice_data_post_processing_cb(int bytes_sent, void *user_data) static ctrlm_voice_session_group_t voice_device_to_session_group(ctrlm_voice_device_t device_type); +#ifdef CTRLM_THUNDER static void ctrlm_voice_system_audio_player_event_handler(system_audio_player_event_t event, void *user_data); +#endif static xrsr_power_mode_t voice_xrsr_power_map(ctrlm_power_state_t ctrlm_power_state); @@ -268,12 +270,20 @@ ctrlm_voice_t::ctrlm_voice_t() { sem_init(&this->vsr_semaphore, 0, 0); if(this->beep_on_kwd_supported) { + #ifdef CTRLM_THUNDER this->obj_sap = Thunder::SystemAudioPlayer::ctrlm_thunder_plugin_system_audio_player_t::getInstance(); this->obj_sap->add_event_handler(ctrlm_voice_system_audio_player_event_handler, this); this->sap_opened = this->obj_sap->open(SYSTEM_AUDIO_PLAYER_AUDIO_TYPE_WAV, SYSTEM_AUDIO_PLAYER_SOURCE_TYPE_FILE, SYSTEM_AUDIO_PLAYER_PLAY_MODE_SYSTEM); if(!this->sap_opened) { XLOGD_WARN("unable to open system audio player"); } + #else + this->obj_sap = NULL; + this->sap_opened = false; + this->beep_on_kwd_supported = false; + this->beep_on_kwd_file = NULL; + XLOGD_WARN("beep on keyword is not supported without Thunder"); + #endif } // Set audio mode to default @@ -313,12 +323,14 @@ ctrlm_voice_t::~ctrlm_voice_t() { } } + #ifdef CTRLM_THUNDER if(this->beep_on_kwd_supported && this->sap_opened) { if(!this->obj_sap->close()) { XLOGD_WARN("unable to close system audio player"); } this->sap_opened = false; } + #endif /* Close Voice SDK */ @@ -3031,6 +3043,7 @@ void ctrlm_voice_t::voice_action_keyword_verification_callback(const uuid_t uuid } void ctrlm_voice_t::voice_keyword_verified_action(void) { + #ifdef CTRLM_THUNDER if(this->beep_on_kwd_supported && (this->beep_on_kwd_file != NULL) && this->audio_ducking_beep_enabled) { // play beep audio before ducking audio if(this->audio_ducking_beep_in_progress) { XLOGD_WARN("audio ducking beep already in progress!"); @@ -3072,6 +3085,7 @@ void ctrlm_voice_t::voice_keyword_verified_action(void) { } while(retry >= 0); } this->audio_state_set(true); + #endif } void ctrlm_voice_t::voice_keyword_beep_completed_normal(void *data, int size) { @@ -3865,6 +3879,7 @@ void ctrlm_voice_t::voice_device_disable(ctrlm_voice_device_t device, bool db_wr sem_post(&this->device_status_semaphore); } +#ifdef CTRLM_THUNDER void ctrlm_voice_system_audio_player_event_handler(system_audio_player_event_t event, void *user_data) { if(user_data == NULL) { return; @@ -3904,6 +3919,7 @@ void ctrlm_voice_system_audio_player_event_handler(system_audio_player_event_t e } } } +#endif void ctrlm_voice_t::voice_nsm_session_request(void) { ctrlm_network_id_t network_id = CTRLM_MAIN_NETWORK_ID_DSP; From c650ac273504981086eb5b33fabbc3fb0d3e6f3d Mon Sep 17 00:00:00 2001 From: Kelvin Lu <119349872+klu339@users.noreply.github.com> Date: Mon, 13 Jul 2026 15:21:08 -0400 Subject: [PATCH 75/81] RDKEMW-20544: Add timestamp to T2 accum markers (#261) --- src/ble/ctrlm_ble_controller.cpp | 37 ++++++----- src/ble/ctrlm_ble_controller.h | 2 + src/ble/ctrlm_ble_network.cpp | 67 ++++++++++---------- src/ble/ctrlm_ble_network.h | 1 + src/ctrlm_utils.cpp | 8 +++ src/ctrlm_utils.h | 3 + src/irdb/ctrlm_irdb_interface.cpp | 7 +- src/irdb/ipc/ctrlm_irdb_ipc_iarm_thunder.cpp | 54 +++++++--------- src/telemetry/ctrlm_telemetry_markers.h | 17 +++-- 9 files changed, 109 insertions(+), 87 deletions(-) diff --git a/src/ble/ctrlm_ble_controller.cpp b/src/ble/ctrlm_ble_controller.cpp index 388fabb8..f91b99c7 100644 --- a/src/ble/ctrlm_ble_controller.cpp +++ b/src/ble/ctrlm_ble_controller.cpp @@ -34,6 +34,7 @@ #include "ctrlm_telemetry_event.h" #include +#include #include #include #include @@ -528,6 +529,24 @@ ctrlm_timestamp_t ctrlm_obj_controller_ble_t::getVoiceStartTimeLocal() const { return(voice_start_time_local_); } +void ctrlm_obj_controller_ble_t::emit_irdb_vendor_set( + int set_result, uint8_t rcu_bitmask, + const std::string &vendor_name, uint8_t vendor_bitmask, int supported) +{ +#ifdef TELEMETRY_SUPPORT + std::ostringstream ss; + ss << "[" << MARKER_IRDB_VENDOR_SET_VERSION + << "," << set_result + << ",0x" << std::hex << std::setfill('0') << std::setw(2) << (int)rcu_bitmask + << ",\"" << vendor_name << "\"" + << ",0x" << std::setw(2) << (int)vendor_bitmask << std::dec + << "," << supported + << "," << ctrlm_timestamp_get_ms() << "]"; + ctrlm_telemetry_event_t ev(MARKER_IRDB_VENDOR_SET, ss.str()); + ev.event(); +#endif +} + void ctrlm_obj_controller_ble_t::setSupportedIrdbs(uint8_t vendor_support_bitmask) { this->irdbs_supported_ = vendor_support_bitmask; @@ -535,12 +554,7 @@ void ctrlm_obj_controller_ble_t::setSupportedIrdbs(uint8_t vendor_support_bitmas if (irdb == NULL) { XLOGD_ERROR("IRDB interface is NULL!!!"); -#ifdef TELEMETRY_SUPPORT - char t2_buf[256]; - snprintf(t2_buf, sizeof(t2_buf), "[0,0x%02X,\"unknown\",0x00,0]", vendor_support_bitmask); - ctrlm_telemetry_event_t ev(MARKER_IRDB_VENDOR_SET, t2_buf); - ev.event(); -#endif + emit_irdb_vendor_set(0, vendor_support_bitmask, "unknown", 0x00, 0); return; } @@ -569,15 +583,8 @@ void ctrlm_obj_controller_ble_t::setSupportedIrdbs(uint8_t vendor_support_bitmas XLOGD_WARN("Controller <%s> IRDBs supported bitmask = <0x%X>, couldn't retrieve IRDB plugin vendor info.", ieee_address_get().to_string().c_str(), vendor_support_bitmask); } -#ifdef TELEMETRY_SUPPORT - char t2_buf[256]; - snprintf(t2_buf, sizeof(t2_buf), "[%d,0x%02X,\"%s\",0x%02X,%d]", - (int)set_result,vendor_support_bitmask, - vendor_info.name.c_str(), vendor_info.rcu_support_bitmask, - (int)supported); - ctrlm_telemetry_event_t ev(MARKER_IRDB_VENDOR_SET, t2_buf); - ev.event(); -#endif + emit_irdb_vendor_set((int)set_result, vendor_support_bitmask, + vendor_info.name, vendor_info.rcu_support_bitmask, (int)supported); } uint8_t ctrlm_obj_controller_ble_t::getSupportedIrdbs() const { diff --git a/src/ble/ctrlm_ble_controller.h b/src/ble/ctrlm_ble_controller.h index 432f5c76..5e1bc5ce 100644 --- a/src/ble/ctrlm_ble_controller.h +++ b/src/ble/ctrlm_ble_controller.h @@ -150,6 +150,8 @@ class ctrlm_obj_controller_ble_t : public ctrlm_obj_controller_t { void update_controller_id_and_db_entry(std::string name, ctrlm_network_id_t network_id, ctrlm_controller_id_t new_id); private: + void emit_irdb_vendor_set(int set_result, uint8_t rcu_bitmask, const std::string &vendor_name, uint8_t vendor_bitmask, int supported); + ctrlm_obj_network_ble_t *obj_network_ble_ = NULL; bool connected_ = false; diff --git a/src/ble/ctrlm_ble_network.cpp b/src/ble/ctrlm_ble_network.cpp index f5c316b4..64ec4984 100644 --- a/src/ble/ctrlm_ble_network.cpp +++ b/src/ble/ctrlm_ble_network.cpp @@ -49,6 +49,7 @@ #include "ctrlm_rcp_ipc_iarm_thunder.h" #include "ctrlm_telemetry.h" #include +#include #include "ctrlm_telemetry_event.h" using namespace std; @@ -773,6 +774,23 @@ void ctrlm_obj_network_ble_t::req_process_pair_with_code(void *data, int size) { } } +void ctrlm_obj_network_ble_t::emit_irdb_program_result(int ir_state, const std::string &fail_reason, + uint8_t rcu_bitmask, + const std::string &vendor_name, uint8_t vendor_bitmask) +{ +#ifdef TELEMETRY_SUPPORT + std::ostringstream ss; + ss << "[" << MARKER_IRDB_PROGRAM_RESULT_VERSION + << "," << ir_state + << ",\"" << fail_reason << "\"" + << ",0x" << std::hex << std::setfill('0') << std::setw(2) << (int)rcu_bitmask + << ",\"" << vendor_name << "\"" + << ",0x" << std::setw(2) << (int)vendor_bitmask << std::dec + << "," << ctrlm_timestamp_get_ms() << "]"; + ctrlm_telemetry_event_t ev(MARKER_IRDB_PROGRAM_RESULT, ss.str()); + ev.event(); +#endif +} void ctrlm_obj_network_ble_t::req_process_program_ir_codes(void *data, int size) { XLOGD_DEBUG("Enter..."); @@ -793,16 +811,9 @@ void ctrlm_obj_network_ble_t::req_process_program_ir_codes(void *data, int size) XLOGD_ERROR("Controller doesn't exist!"); } else if (!controllers_[controller_id]->isSupportedIrdb(dqm->vendor_info)) { XLOGD_ERROR("Unsupported IRDB - not continuing with ir code download!"); -#ifdef TELEMETRY_SUPPORT - char t2_buf[256]; - snprintf(t2_buf, sizeof(t2_buf), "[%d,\"unsupported\",0x%02X,\"%s\",0x%02X]", - (int)CTRLM_IR_STATE_FAILED, - controllers_[controller_id]->getSupportedIrdbs(), - dqm->vendor_info.name.c_str(), - dqm->vendor_info.rcu_support_bitmask); - ctrlm_telemetry_event_t ev(MARKER_IRDB_PROGRAM_RESULT, t2_buf); - ev.event(); -#endif + emit_irdb_program_result((int)CTRLM_IR_STATE_FAILED, "unsupported", + controllers_[controller_id]->getSupportedIrdbs(), + dqm->vendor_info.name, dqm->vendor_info.rcu_support_bitmask); } else { if(dqm->ir_codes) { @@ -1754,6 +1765,7 @@ void ctrlm_obj_network_ble_t::ind_process_rcu_pairing_outcome(void *data, int si ss << ","; } } + ss << "," << ctrlm_timestamp_get_ms(); ss << "]"; ctrlm_telemetry_event_t ev(MARKER_RCU_PAIRING_ATTEMPT, ss.str()); @@ -1806,37 +1818,24 @@ void ctrlm_obj_network_ble_t::ind_process_rcu_status(void *data, int size) { ir_state_ = dqm->ir_state; // send event immediately. schedule_status_event(true); -#ifdef TELEMETRY_SUPPORT - { + if (dqm->ir_state == CTRLM_IR_STATE_COMPLETE || dqm->ir_state == CTRLM_IR_STATE_FAILED) { ctrlm_irdb_vendor_info_t vendor_info{}; vendor_info.name = "unknown"; vendor_info.rcu_support_bitmask = 0xFF; - ctrlm_irdb_interface_t *irdb = ctrlm_main_irdb_get(); if (irdb) { irdb->get_vendor_info(vendor_info); } - char t2_buf[256]; - if (dqm->ir_state == CTRLM_IR_STATE_COMPLETE || dqm->ir_state == CTRLM_IR_STATE_FAILED) { - ctrlm_controller_id_t controller_id; - uint8_t rcu_bitmask = 0xFF; - if (false == getControllerId(dqm->rcu_data.ieee_address, &controller_id)) { - XLOGD_ERROR("Controller <%s> NOT found in the network!!", - ctrlm_convert_mac_long_to_string(dqm->rcu_data.ieee_address).c_str()); - } else { - auto controller = controllers_[controller_id]; - rcu_bitmask = controller->getSupportedIrdbs(); - } - - snprintf(t2_buf, sizeof(t2_buf), "[%d,\"%s\",0x%02X,\"%s\",0x%02X]", - (int)dqm->ir_state, - dqm->ir_fail_reason, - rcu_bitmask, - vendor_info.name.c_str(), - vendor_info.rcu_support_bitmask); - ctrlm_telemetry_event_t ev(MARKER_IRDB_PROGRAM_RESULT, t2_buf); - ev.event(); + + ctrlm_controller_id_t controller_id; + uint8_t rcu_bitmask = 0xFF; + if (false == getControllerId(dqm->rcu_data.ieee_address, &controller_id)) { + XLOGD_ERROR("Controller <%s> NOT found in the network!!", + ctrlm_convert_mac_long_to_string(dqm->rcu_data.ieee_address).c_str()); + } else { + rcu_bitmask = controllers_[controller_id]->getSupportedIrdbs(); } + emit_irdb_program_result((int)dqm->ir_state, dqm->ir_fail_reason, + rcu_bitmask, vendor_info.name, vendor_info.rcu_support_bitmask); } -#endif break; default: { diff --git a/src/ble/ctrlm_ble_network.h b/src/ble/ctrlm_ble_network.h index 73f2c8b9..62201e5f 100644 --- a/src/ble/ctrlm_ble_network.h +++ b/src/ble/ctrlm_ble_network.h @@ -216,6 +216,7 @@ class ctrlm_obj_network_ble_t : public ctrlm_obj_network_t { ctrlm_controller_id_t get_last_used_controller(void); bool end_voice_session_for_controller(uint64_t ieee_address, ctrlm_voice_session_end_reason_t reason, int32_t audioDuration = -1, int32_t startLag = -1, rdkx_timestamp_t *keyDownTime = NULL, rdkx_timestamp_t *keyUpTime = NULL); ctrlm_controller_id_t find_controller_from_upgrade_session_uuid(const std::string &uuid); + void emit_irdb_program_result(int ir_state, const std::string &fail_reason, uint8_t rcu_bitmask, const std::string &vendor_name, uint8_t vendor_bitmask); json_t * json_config_ = NULL; bool voice_disabled_ = false; diff --git a/src/ctrlm_utils.cpp b/src/ctrlm_utils.cpp index d2a87311..83dfba02 100644 --- a/src/ctrlm_utils.cpp +++ b/src/ctrlm_utils.cpp @@ -134,6 +134,14 @@ void ctrlm_timestamp_get_monotonic(ctrlm_timestamp_t *timestamp) { } } +uint64_t ctrlm_timestamp_get_ms(void) { + struct timespec ts; + if(clock_gettime(CLOCK_REALTIME, &ts) != 0) { + return 0; + } + return ((uint64_t)ts.tv_sec * 1000ULL) + ((uint64_t)ts.tv_nsec / 1000000ULL); +} + // 1 : one is greater than two // 0 : one and two are equal // -1 : one is less than two diff --git a/src/ctrlm_utils.h b/src/ctrlm_utils.h index 098131be..9623c31d 100644 --- a/src/ctrlm_utils.h +++ b/src/ctrlm_utils.h @@ -259,6 +259,9 @@ void ctrlm_utils_message_queue_close(int *msgq); bool ctrlm_utils_queue_msg_push(int msgq, const char *msg, size_t msg_len); std::string ctrlm_utils_time_as_string(time_t time); +// Returns the current wall-clock time in epoch milliseconds. +uint64_t ctrlm_timestamp_get_ms(void); + ctrlm_fmr_alarm_level_t ctrlm_utils_str_to_fmr_level(const std::string &level); ctrlm_rcu_wakeup_config_t ctrlm_utils_str_to_wakeup_config(const std::string &wakeup_config); int ctrlm_utils_custom_key_str_to_array(const std::string &custom_keys, int *custom_list); diff --git a/src/irdb/ctrlm_irdb_interface.cpp b/src/irdb/ctrlm_irdb_interface.cpp index e9b5395e..ad847489 100644 --- a/src/irdb/ctrlm_irdb_interface.cpp +++ b/src/irdb/ctrlm_irdb_interface.cpp @@ -20,6 +20,7 @@ #include "ctrlm_irdb_interface.h" #include "ctrlm_network.h" #include "ctrlm_log.h" +#include "ctrlm_utils.h" #include "ctrlm_irdb_stub.h" #include "ctrlm_telemetry_event.h" @@ -617,12 +618,14 @@ bool ctrlm_irdb_interface_t::get_ir_codes_by_autolookup(ctrlm_autolookup_ranked_ } std::string results = ss.str(); ss.str(""); - ss << "[\"" << t2_vendor_info.name << "\"" + ss << "[" << MARKER_IRDB_AUTOLOOKUP_RESULT_VERSION + << ",\"" << t2_vendor_info.name << "\"" << ",0x" << std::hex << std::setfill('0') << std::setw(2) << (int)t2_vendor_info.rcu_support_bitmask << "," << std::dec << (int)m_platform_tv << "," << tv_count << "," << avr_count - << "," << (results.empty() ? "\"\"" : results) << "]"; + << "," << (results.empty() ? "\"\"" : results) + << "," << ctrlm_timestamp_get_ms() << "]"; ctrlm_telemetry_event_t ev(MARKER_IRDB_AUTOLOOKUP_RESULT, ss.str()); ev.event(); #endif diff --git a/src/irdb/ipc/ctrlm_irdb_ipc_iarm_thunder.cpp b/src/irdb/ipc/ctrlm_irdb_ipc_iarm_thunder.cpp index e58f7a64..0afede14 100644 --- a/src/irdb/ipc/ctrlm_irdb_ipc_iarm_thunder.cpp +++ b/src/irdb/ipc/ctrlm_irdb_ipc_iarm_thunder.cpp @@ -18,6 +18,8 @@ */ #include +#include +#include #include "ctrlm_irdb_ipc_iarm_thunder.h" #include "ctrlm.h" #include "ctrlm_log.h" @@ -38,6 +40,25 @@ namespace { constexpr char const* SUCCESS = "success"; constexpr char const* TV = "TV"; constexpr char const* AMP = "AMP"; + + void emit_irdb_manual_result(ctrlm_irdb_interface_t *irdb, const char *method, bool success) + { +#ifdef TELEMETRY_SUPPORT + ctrlm_irdb_vendor_info_t vendor_info{}; + if (irdb) { + irdb->get_vendor_info(vendor_info); + } + std::ostringstream ss; + ss << "[" << MARKER_IRDB_MANUAL_RESULT_VERSION + << ",\"" << vendor_info.name << "\"" + << ",0x" << std::hex << std::setfill('0') << std::setw(2) << (int)vendor_info.rcu_support_bitmask << std::dec + << ",\"" << method << "\"" + << "," << (int)success + << "," << ctrlm_timestamp_get_ms() << "]"; + ctrlm_telemetry_event_t ev(MARKER_IRDB_MANUAL_RESULT, ss.str()); + ev.event(); +#endif + } } ctrlm_irdb_ipc_iarm_thunder_t::ctrlm_irdb_ipc_iarm_thunder_t() : ctrlm_ipc_iarm_t() { @@ -153,16 +174,7 @@ IARM_Result_t ctrlm_irdb_ipc_iarm_thunder_t::get_manufacturers(void *arg) { } } -#ifdef TELEMETRY_SUPPORT - ctrlm_irdb_vendor_info_t vendor_info{}; - if (irdb) { - irdb->get_vendor_info(vendor_info); - } - char t2_buf[128]; - snprintf(t2_buf, sizeof(t2_buf), "[\"%s\",0x%02X,\"%s\",%d]", vendor_info.name.c_str(), vendor_info.rcu_support_bitmask, CTRLM_MAIN_IARM_CALL_IR_MANUFACTURERS, (int)success); - ctrlm_telemetry_event_t ev(MARKER_IRDB_MANUAL_RESULT, t2_buf); - ev.event(); -#endif + emit_irdb_manual_result(irdb, CTRLM_MAIN_IARM_CALL_IR_MANUFACTURERS, success); // Assemble the return json_object_set_new(ret, SUCCESS, json_boolean(success)); @@ -238,16 +250,7 @@ IARM_Result_t ctrlm_irdb_ipc_iarm_thunder_t::get_models(void *arg) { } } -#ifdef TELEMETRY_SUPPORT - ctrlm_irdb_vendor_info_t vendor_info{}; - if(irdb) { - irdb->get_vendor_info(vendor_info); - } - char t2_buf[128]; - snprintf(t2_buf, sizeof(t2_buf), "[\"%s\",0x%02X,\"%s\",%d]", vendor_info.name.c_str(), vendor_info.rcu_support_bitmask, CTRLM_MAIN_IARM_CALL_IR_MODELS, (int)success); - ctrlm_telemetry_event_t ev(MARKER_IRDB_MANUAL_RESULT, t2_buf); - ev.event(); -#endif + emit_irdb_manual_result(irdb, CTRLM_MAIN_IARM_CALL_IR_MODELS, success); // Assemble the return json_object_set_new(ret, SUCCESS, json_boolean(success)); @@ -389,16 +392,7 @@ IARM_Result_t ctrlm_irdb_ipc_iarm_thunder_t::get_irdb_entry_ids(void *arg) { } } -#ifdef TELEMETRY_SUPPORT - ctrlm_irdb_vendor_info_t vendor_info{}; - if (irdb) { - irdb->get_vendor_info(vendor_info); - } - char t2_buf[128]; - snprintf(t2_buf, sizeof(t2_buf), "[\"%s\",0x%02X,\"%s\",%d]", vendor_info.name.c_str(), vendor_info.rcu_support_bitmask, CTRLM_MAIN_IARM_CALL_IR_CODES, (int)success); - ctrlm_telemetry_event_t ev(MARKER_IRDB_MANUAL_RESULT, t2_buf); - ev.event(); -#endif + emit_irdb_manual_result(irdb, CTRLM_MAIN_IARM_CALL_IR_CODES, success); // Assemble the return json_object_set_new(ret, SUCCESS, json_boolean(success)); diff --git a/src/telemetry/ctrlm_telemetry_markers.h b/src/telemetry/ctrlm_telemetry_markers.h index f1314e0f..55baa379 100644 --- a/src/telemetry/ctrlm_telemetry_markers.h +++ b/src/telemetry/ctrlm_telemetry_markers.h @@ -131,7 +131,7 @@ // BLE RCU Pairing Attempt Marker // Value format: Array of comma separated integers or string with the fields below. -// [,,,,,,,,,] +// [,,,,,,,,,,] // - version of the marker format. // - type of network the marker is coming from // - enum representing pairing method (see PairingMethod) @@ -142,8 +142,9 @@ // - error message 1 from bluez layer or null if no error // - error message 2 from bluez layer or null if no error // - error message 3 from bluez layer or null if no error +// - wall-clock time the marker was generated, in epoch milliseconds (makes each marker value unique) #define MARKER_RCU_PAIRING_ATTEMPT "ctrlm.rcu.pairing.attempt_accum" -#define MARKER_RCU_PAIRING_ATTEMPT_VERSION 1 +#define MARKER_RCU_PAIRING_ATTEMPT_VERSION 2 // // End RCU Markers @@ -152,10 +153,14 @@ // // All _accum markers are aggregated by the T2 platform within each reporting window. -#define MARKER_IRDB_AUTOLOOKUP_RESULT "ctrlm.irdb.autolookup.result_accum" // format: ,,,,, -#define MARKER_IRDB_MANUAL_RESULT "ctrlm.irdb.manual.result_accum" // format: ,,, -#define MARKER_IRDB_PROGRAM_RESULT "ctrlm.irdb.program.result_accum" // format: ,,,, -#define MARKER_IRDB_VENDOR_SET "ctrlm.irdb.vendor_set_accum" // format: ,,,, +#define MARKER_IRDB_AUTOLOOKUP_RESULT "ctrlm.irdb.autolookup.result_accum" // format: ,,,,,,, +#define MARKER_IRDB_AUTOLOOKUP_RESULT_VERSION 1 +#define MARKER_IRDB_MANUAL_RESULT "ctrlm.irdb.manual.result_accum" // format: ,,,,, +#define MARKER_IRDB_MANUAL_RESULT_VERSION 1 +#define MARKER_IRDB_PROGRAM_RESULT "ctrlm.irdb.program.result_accum" // format: ,,,,,, +#define MARKER_IRDB_PROGRAM_RESULT_VERSION 1 +#define MARKER_IRDB_VENDOR_SET "ctrlm.irdb.vendor_set_accum" // format: ,,,,,, +#define MARKER_IRDB_VENDOR_SET_VERSION 1 // // End IRDB Markers From 4fa7429a071fa6ab0490a238007e808759259cbe Mon Sep 17 00:00:00 2001 From: dwolaver <44593664+dwolaver@users.noreply.github.com> Date: Tue, 14 Jul 2026 20:49:34 -0400 Subject: [PATCH 76/81] RDKEMW-19785 : control manager - remove deprecated RFCs (#243) --- src/ctrlm_main.cpp | 6 - src/ctrlm_tr181.h | 36 +--- src/rf4ce/ctrlm_rf4ce_network.cpp | 192 +----------------- src/rf4ce/ctrlm_rf4ce_network.h | 4 - .../ctrlm_rf4ce_network_attr_config.cpp | 45 ---- .../ctrlm_rf4ce_network_attr_config.h | 1 - src/voice/ctrlm_voice_obj.cpp | 114 +---------- src/voice/ctrlm_voice_obj.h | 1 - 8 files changed, 3 insertions(+), 396 deletions(-) diff --git a/src/ctrlm_main.cpp b/src/ctrlm_main.cpp index 2d5348bf..0603fd64 100644 --- a/src/ctrlm_main.cpp +++ b/src/ctrlm_main.cpp @@ -964,12 +964,6 @@ void ctrlm_thread_monitor_init(void) { g_ctrlm.monitor_threads.shrink_to_fit(); - if(CTRLM_TR181_RESULT_SUCCESS != ctrlm_tr181_bool_get(CTRLM_RF4CE_TR181_THREAD_MONITOR_MINIDUMP_ENABLE, &g_ctrlm.thread_monitor_minidump)) { - XLOGD_INFO("Thread Monitor Minidump is <%s> (TR181 not present)", (g_ctrlm.thread_monitor_minidump ? "ENABLED" : "DISABLED")); - } else { - XLOGD_INFO("Thread Monitor Minidump is <%s>", (g_ctrlm.thread_monitor_minidump ? "ENABLED" : "DISABLED")); - } - // Run once to kick off the first poll ctrlm_thread_monitor(NULL); } diff --git a/src/ctrlm_tr181.h b/src/ctrlm_tr181.h index 8fdb0b34..b1eb19a5 100644 --- a/src/ctrlm_tr181.h +++ b/src/ctrlm_tr181.h @@ -24,46 +24,12 @@ #include "rfcapi.h" #define CTRLM_RFC_MAX_PARAM_LEN MAX_PARAM_LEN //from rfcapi.h is 2048 -#define CTRLM_RF4CE_TR181_POLLING_CONFIGURATION_PREFIX "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.XRPollingConfiguration." -#define CTRLM_RF4CE_TR181_POLLING_CONFIGURATION_ENABLED CTRLM_RF4CE_TR181_POLLING_CONFIGURATION_PREFIX "Enable" -#define CTRLM_RF4CE_TR181_POLLING_CONFIGURATION_DEFAULT CTRLM_RF4CE_TR181_POLLING_CONFIGURATION_PREFIX "Default" -#define CTRLM_RF4CE_TR181_POLLING_CONFIGURATION_XR11V2 CTRLM_RF4CE_TR181_POLLING_CONFIGURATION_PREFIX "XR11v2" -#define CTRLM_RF4CE_TR181_POLLING_CONFIGURATION_XR15V1 CTRLM_RF4CE_TR181_POLLING_CONFIGURATION_PREFIX "XR15v1" -#define CTRLM_RF4CE_TR181_POLLING_CONFIGURATION_XR15V2 CTRLM_RF4CE_TR181_POLLING_CONFIGURATION_PREFIX "XR15v2" -#define CTRLM_RF4CE_TR181_POLLING_CONFIGURATION_XR16V1 CTRLM_RF4CE_TR181_POLLING_CONFIGURATION_PREFIX "XR16v1" -#define CTRLM_RF4CE_TR181_POLLING_CONFIGURATION_XR19V1 CTRLM_RF4CE_TR181_POLLING_CONFIGURATION_PREFIX "XR19v1" -#define CTRLM_RF4CE_TR181_POLLING_CONFIGURATION_XRAV1 CTRLM_RF4CE_TR181_POLLING_CONFIGURATION_PREFIX "XRAv1" -#define CTRLM_RF4CE_TR181_PRESS_AND_RELEASE_EOS_TIMEOUT "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.PressAndRelease.EOSTimeout" -#define CTRLM_RF4CE_TR181_PRESS_AND_RELEASE_EOS_METHOD "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.PressAndRelease.EOSMethod" -#define CTRLM_RF4CE_TR181_MAC_POLLING_CONFIGURATION_ENABLE "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.XRmacPolling.Enable" -#define CTRLM_RF4CE_TR181_MAC_POLLING_CONFIGURATION_INTERVAL "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.XRmacPolling.macPollingInterval" -#define CTRLM_RF4CE_TR181_ASB_ENABLED "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.XRPairing.ASBEnable" -#define CTRLM_RF4CE_TR181_ASB_DERIVATION_METHOD "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.XRPairing.ASBDerivationMethod" -#define CTRLM_RF4CE_TR181_ASB_FAIL_THRESHOLD "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.XRPairing.ASBFailThreshold" -#define CTRLM_RF4CE_TR181_THREAD_MONITOR_MINIDUMP_ENABLE "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.ThreadMonitorMinidump.Enable" -#define CTRLM_RF4CE_TR181_XR19_DSP_CONFIGURATION "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.XRDsp.XR19.Configuration" -#define CTRLM_RF4CE_TR181_RF4CE_AUDIO_PROFILE_TARGET "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.RF4CE.AudioProfileTarget" -#define CTRLM_RF4CE_TR181_RF4CE_OPUS_ENCODER_PARAMS "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.RF4CE.OpusEncoderParams" -#define CTRLM_RF4CE_TR181_RF4CE_RSP_IDLE_FF "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.RF4CE.FF.RspIdle" -#define CTRLM_RF4CE_TR181_RF4CE_VOICE_ENCRYPTION "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.RF4CE.VoiceEncryption.Enable" -#define CTRLM_RF4CE_TR181_RF4CE_HOST_PACKET_DECRYPTION "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.RF4CE.HostPacketDecryption.Enable" -#define CTRLM_RF4CE_TR181_RSP_TIME_PREFIX "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.RF4CE.RspTime." -#define CTRLM_RF4CE_TR181_RSP_TIME_XRC CTRLM_RF4CE_TR181_RSP_TIME_PREFIX "XRC" -#define CTRLM_RF4CE_TR181_RSP_TIME_XVP CTRLM_RF4CE_TR181_RSP_TIME_PREFIX "XVP" -#define CTRLM_RF4CE_TR181_RSP_TIME_XDIU CTRLM_RF4CE_TR181_RSP_TIME_PREFIX "XDIU" -#define CTRLM_TR181_VOICE_PARAMS_AUDIO_MODE "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.Voice.AudioMode" -#define CTRLM_TR181_VOICE_PARAMS_AUDIO_TIMING "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.Voice.AudioTiming" -#define CTRLM_TR181_VOICE_PARAMS_AUDIO_CONFIDENCE_THRESHOLD "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.Voice.AudioConfidenceThreshold" -#define CTRLM_TR181_VOICE_PARAMS_AUDIO_DUCKING_TYPE "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.Voice.AudioDuckingType" -#define CTRLM_TR181_VOICE_PARAMS_AUDIO_DUCKING_LEVEL "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.Voice.AudioDuckingLevel" -#define CTRLM_TR181_VOICE_PARAMS_VSDK_CONFIGURATION "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.Voice.VSDKConfiguration" -#define CTRLM_TR181_VOICE_PARAMS_KEYWORD_SENSITIVITY "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.Voice.KeywordSensitivity" #define CTRLM_TR181_TELEMETRY_REPORT_GLOBAL "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.ctrlm.telemetry_report.global" #define CTRLM_TR181_TELEMETRY_REPORT_RF4CE "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.ctrlm.telemetry_report.rf4ce" #define CTRLM_TR181_TELEMETRY_REPORT_BLE "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.ctrlm.telemetry_report.ble" #define CTRLM_TR181_TELEMETRY_REPORT_IP "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.ctrlm.telemetry_report.ip" #define CTRLM_TR181_TELEMETRY_REPORT_VOICE "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.ctrlm.telemetry_report.voice" -#define CTRLM_RT181_POWER_RFC_PWRMGR2 "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.Power.PwrMgr2.Enable" +#define CTRLM_TR181_POWER_RFC_PWRMGR2 "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.Power.PwrMgr2.Enable" typedef enum { diff --git a/src/rf4ce/ctrlm_rf4ce_network.cpp b/src/rf4ce/ctrlm_rf4ce_network.cpp index 91df3fb5..db7a2302 100644 --- a/src/rf4ce/ctrlm_rf4ce_network.cpp +++ b/src/rf4ce/ctrlm_rf4ce_network.cpp @@ -726,9 +726,6 @@ gboolean ctrlm_obj_network_rf4ce_t::load_config(json_t *json_obj_net_rf4ce) { sub_conf.config_value_get(JSON_INT_NAME_NETWORK_RF4CE_DSP_IC_DETECT, dsp_configuration_.ic_config_detect, 0x00, 0xFF); } } - //Read tr181 values here. tr181 values will override any config file values. - polling_config_tr181_read(); - process_xconf(); XLOGD_INFO("User String <%s>", user_string_.c_str()); XLOGD_INFO("Timeout Key Release %u ms", timeout_key_release_); @@ -2934,110 +2931,6 @@ void ctrlm_obj_network_rf4ce_t::default_polling_configuration() { } } -void ctrlm_obj_network_rf4ce_t::polling_config_tr181_read() { - guint8 default_polling_methods = 0; - ctrlm_rf4ce_polling_configuration_t default_polling_config_hb = {0}; - - ctrlm_rf4ce_polling_configuration_t default_polling_config_mac; - errno_t safec_rc = memset_s(&default_polling_config_mac, sizeof(ctrlm_rf4ce_polling_configuration_t), 0, sizeof(ctrlm_rf4ce_polling_configuration_t)); - ERR_CHK(safec_rc); - default_polling_config_mac.trigger = POLLING_TRIGGER_FLAG_TIME; - default_polling_config_mac.time_interval = JSON_INT_VALUE_NETWORK_RF4CE_POLLING_DEFAULT_MAC_TIME_INTERVAL; - - bool b_has_default_config = false; - - char tr181_buf[1024] = {0}; - if(CTRLM_TR181_RESULT_SUCCESS == ctrlm_tr181_string_get(CTRLM_RF4CE_TR181_POLLING_CONFIGURATION_DEFAULT, tr181_buf, sizeof(tr181_buf))) { - if(4 == sscanf(tr181_buf, "%hhu:%hu:%hhu:%u:", &default_polling_methods, &default_polling_config_hb.trigger, &default_polling_config_hb.kp_counter, &default_polling_config_hb.time_interval)) { - XLOGD_INFO("Default HB Polling Configuration from TR181"); - b_has_default_config = true; - } - } - - bool b_has_default_mac_config = false; - - bool mac_polling_enabled = false; - if(CTRLM_TR181_RESULT_SUCCESS == ctrlm_tr181_bool_get(CTRLM_RF4CE_TR181_MAC_POLLING_CONFIGURATION_ENABLE, &mac_polling_enabled)) { - XLOGD_INFO("Default Mac Polling Configuration from TR181"); - b_has_default_mac_config = mac_polling_enabled; - ctrlm_tr181_int_get(CTRLM_RF4CE_TR181_MAC_POLLING_CONFIGURATION_INTERVAL, (int*)&default_polling_config_mac.time_interval, 1000, 60000); - - if(mac_polling_enabled) { - polling_methods_ |= POLLING_METHODS_FLAG_MAC; - } else { - polling_methods_ &= ~POLLING_METHODS_FLAG_MAC; - } - - } - for(int i = 0; i < RF4CE_CONTROLLER_TYPE_INVALID; i++) { - XLOGD_INFO("Polling Configuration Remote Type <%s>", ctrlm_rf4ce_controller_type_str((ctrlm_rf4ce_controller_type_t)i)); - const char *controller_tr181_str = 0; - - switch((ctrlm_rf4ce_controller_type_t)i) { - case RF4CE_CONTROLLER_TYPE_XR11: { - controller_tr181_str = CTRLM_RF4CE_TR181_POLLING_CONFIGURATION_XR11V2; - break; - } - case RF4CE_CONTROLLER_TYPE_XR15: { - controller_tr181_str = CTRLM_RF4CE_TR181_POLLING_CONFIGURATION_XR15V1; - break; - } - case RF4CE_CONTROLLER_TYPE_XR15V2: { - controller_tr181_str = CTRLM_RF4CE_TR181_POLLING_CONFIGURATION_XR15V2; - break; - } - case RF4CE_CONTROLLER_TYPE_XR16: { - controller_tr181_str = CTRLM_RF4CE_TR181_POLLING_CONFIGURATION_XR16V1; - break; - } - case RF4CE_CONTROLLER_TYPE_XR19: { - controller_tr181_str = CTRLM_RF4CE_TR181_POLLING_CONFIGURATION_XR19V1; - break; - } - case RF4CE_CONTROLLER_TYPE_XRA: { - controller_tr181_str = CTRLM_RF4CE_TR181_POLLING_CONFIGURATION_XRAV1; - break; - } - default: { - break; - } - } - - if (b_has_default_mac_config) { - controller_polling_configuration_mac_[i] = default_polling_config_mac; - } - - if(controller_tr181_str) { - if (b_has_default_config) { - controller_polling_methods_[i] = default_polling_methods; - controller_polling_configuration_heartbeat_[i] = default_polling_config_hb; - } - safec_rc = memset_s(tr181_buf, sizeof(tr181_buf), 0, sizeof(tr181_buf)); - ERR_CHK(safec_rc); - ctrlm_rf4ce_polling_configuration_t controller_polling_configuration; - if(CTRLM_TR181_RESULT_SUCCESS == ctrlm_tr181_string_get(controller_tr181_str, tr181_buf, sizeof(tr181_buf))) { - if(4 == sscanf(tr181_buf, "%hhu:%hu:%hhu:%u:", &controller_polling_methods_[i], - &controller_polling_configuration.trigger, - &controller_polling_configuration.kp_counter, - &controller_polling_configuration.time_interval)) { - //If MAC polling bit is set, save the mac config - if(controller_polling_methods_[i] & POLLING_METHODS_FLAG_MAC) { - controller_polling_configuration_mac_[i].trigger = controller_polling_configuration.trigger; - controller_polling_configuration_mac_[i].kp_counter = controller_polling_configuration.kp_counter; - // The MAC polling period has been set above when MAC was enabled - } - //If Heartbeat polling bit is set, save the heartbeat config - if(controller_polling_methods_[i] & POLLING_METHODS_FLAG_HEARTBEAT) { - controller_polling_configuration_heartbeat_[i] = controller_polling_configuration; - } - XLOGD_INFO("Controller Polling Configuration Read from TR181 <%s><%s>", ctrlm_rf4ce_controller_type_str((ctrlm_rf4ce_controller_type_t)i),ctrlm_rf4ce_controller_polling_methods_str(controller_polling_methods_[i])); - } - } - } - controller_polling_methods_[i] &= polling_methods_; // The controller polling_methods should only contain methods currently supported by target - } -} - void ctrlm_obj_network_rf4ce_t::polling_config_read(json_config *conf) { if(NULL == conf) { XLOGD_ERROR("json config is NULL!"); @@ -3412,42 +3305,6 @@ void ctrlm_obj_network_rf4ce_t::polling_action_push(void *data, int size) { } } -void ctrlm_obj_network_rf4ce_t::process_xconf() { - int result; - int value = 0; - bool b_value = true; - result = ctrlm_tr181_int_get(CTRLM_RF4CE_TR181_RF4CE_AUDIO_PROFILE_TARGET, &value, 1, 7); - if(result != CTRLM_TR181_RESULT_SUCCESS) { - XLOGD_INFO("audio profile target not present"); - } else { - audio_profiles_targ_ = value; - XLOGD_INFO("audio profile target 0x%04X", audio_profiles_targ_); - } - - result = ctrlm_tr181_int_get(CTRLM_RF4CE_TR181_RF4CE_RSP_IDLE_FF, &value, 0, 1000); - if(result != CTRLM_TR181_RESULT_SUCCESS) { - XLOGD_INFO("FF Rsp Idle time not present"); - } else { - response_idle_time_ff_ = value; - XLOGD_INFO("FF Rsp Idle time %u", response_idle_time_ff_); - } - - if(CTRLM_TR181_RESULT_SUCCESS != ctrlm_tr181_bool_get(CTRLM_RF4CE_TR181_RF4CE_VOICE_ENCRYPTION, &b_value)) { - XLOGD_INFO("TR181 RF4CE Voice Encryption not present"); - } else { - XLOGD_TELEMETRY("TR181 RF4CE Voice Encryption set to %s", (b_value ? "TRUE" : "FALSE")); - voice_command_encryption_ = (b_value ? VOICE_COMMAND_ENCRYPTION_ENABLED : VOICE_COMMAND_ENCRYPTION_DISABLED); - } - - if(CTRLM_TR181_RESULT_SUCCESS != ctrlm_tr181_bool_get(CTRLM_RF4CE_TR181_RF4CE_HOST_PACKET_DECRYPTION, &host_decryption_)) { - XLOGD_INFO("TR181 RF4CE Host Packet Decryption not present"); - } else { - XLOGD_INFO("TR181 RF4CE Host Packet Decryption set to %s", (host_decryption_ ? "TRUE" : "FALSE")); - } - - rsp_time_.legacy_rfc(); -} - // ASB Functions bool ctrlm_obj_network_rf4ce_t::rf4ce_asb_init(void *data, int size) { @@ -3525,8 +3382,6 @@ void ctrlm_obj_network_rf4ce_t::asb_link_key_derivation_perform(void *data, int } void ctrlm_obj_network_rf4ce_t::asb_configuration(json_config *conf) { - int temp_i; - bool temp_b; // Get JSON configuration first if(NULL != conf) { conf->config_value_get(JSON_BOOL_NAME_NETWORK_RF4CE_ASB_ENABLE, asb_enabled_); @@ -3534,23 +3389,6 @@ void ctrlm_obj_network_rf4ce_t::asb_configuration(json_config *conf) { conf->config_value_get(JSON_INT_NAME_NETWORK_RF4CE_ASB_FALLBACK_THRESHOLD, asb_fallback_count_threshold_, 0x01, 0xFF); conf->config_value_get(JSON_BOOL_NAME_NETWORK_RF4CE_ASB_FORCE_SETTINGS, asb_force_settings_); } - - // Now check TR181 - if(CTRLM_TR181_RESULT_SUCCESS == ctrlm_tr181_bool_get(CTRLM_RF4CE_TR181_ASB_ENABLED, &temp_b)) { - asb_enabled_ = temp_b; - XLOGD_INFO("TR181 ASB Enable set to %s", (asb_enabled_ ? "TRUE" : "FALSE")); - } - if(asb_enabled_) { - if(CTRLM_TR181_RESULT_SUCCESS == ctrlm_tr181_int_get(CTRLM_RF4CE_TR181_ASB_DERIVATION_METHOD, &temp_i, 0x01, 0xFF)) { - asb_key_derivation_methods_ = temp_i; - XLOGD_INFO("TR181 ASB Key Derivation Method set to %d", asb_key_derivation_methods_); - } - if(CTRLM_TR181_RESULT_SUCCESS == ctrlm_tr181_int_get(CTRLM_RF4CE_TR181_ASB_FAIL_THRESHOLD, &temp_i, 0x01, 0xFF)) { - asb_fallback_count_threshold_ = temp_i; - XLOGD_INFO("TR181 ASB Fallback Threshold set to %d", asb_fallback_count_threshold_); - } - } - } void ctrlm_obj_network_rf4ce_t::rf4ce_asb_destroy(void *data, int size) { @@ -3990,9 +3828,7 @@ void ctrlm_obj_network_rf4ce_t::set_timers() { } void ctrlm_obj_network_rf4ce_t::xconf_configuration() { - if(FALSE == force_dsp_configuration_) { - dsp_configuration_xconf(); - } else { + if(FALSE != force_dsp_configuration_) { XLOGD_WARN("force dsp configuration is true, tell device(s) to read it"); update_far_field_configuration(RF4CE_POLLING_ACTION_DSP_CONFIGURATION); } @@ -4127,32 +3963,6 @@ void ctrlm_obj_network_rf4ce_t::update_far_field_configuration(ctrlm_rf4ce_polli } } -void ctrlm_obj_network_rf4ce_t::dsp_configuration_xconf() { - char rfc_val[100] = {'\0'}; - unsigned char *decoded_buf = NULL; - size_t decoded_buf_len = 0; - if(force_dsp_configuration_) { - XLOGD_WARN("not going to xconf for DSP configuration"); - return; - } - if(CTRLM_TR181_RESULT_SUCCESS == ctrlm_tr181_string_get(CTRLM_RF4CE_TR181_XR19_DSP_CONFIGURATION, rfc_val, sizeof(rfc_val))) { - decoded_buf = g_base64_decode(rfc_val, &decoded_buf_len); - if(decoded_buf) { - if(decoded_buf_len == CTRLM_RF4CE_RIB_ATTR_LEN_DSP_CONFIGURATION) { - XLOGD_INFO("DSP configuration taken from XCONF"); - property_write_dsp_configuration(decoded_buf, (uint8_t)decoded_buf_len); - } else { - XLOGD_WARN("incorrect length"); - } - free(decoded_buf); - } else { - XLOGD_WARN("failed to decode base64"); - } - } else { - XLOGD_INFO("no rfc value"); - } -} - void ctrlm_obj_network_rf4ce_t::attributes_from_db() { // So far just getting the DSP configuration if(!force_dsp_configuration_) { diff --git a/src/rf4ce/ctrlm_rf4ce_network.h b/src/rf4ce/ctrlm_rf4ce_network.h index 44dd2570..2c48c962 100644 --- a/src/rf4ce/ctrlm_rf4ce_network.h +++ b/src/rf4ce/ctrlm_rf4ce_network.h @@ -636,10 +636,6 @@ class ctrlm_obj_network_rf4ce_t : public ctrlm_obj_network_t static gboolean binding_in_progress_timeout(gpointer user_data); void default_polling_configuration(); void polling_config_read(json_config *conf); - void polling_config_tr181_read(); - void process_xconf(); - - void dsp_configuration_xconf(); gboolean is_asb_active(ctrlm_hal_rf4ce_ieee_address_t ieee_address); static gboolean asb_link_validation_timeout(gpointer user_data); diff --git a/src/rf4ce/network/attributes/ctrlm_rf4ce_network_attr_config.cpp b/src/rf4ce/network/attributes/ctrlm_rf4ce_network_attr_config.cpp index f4898cac..4988b397 100644 --- a/src/rf4ce/network/attributes/ctrlm_rf4ce_network_attr_config.cpp +++ b/src/rf4ce/network/attributes/ctrlm_rf4ce_network_attr_config.cpp @@ -62,51 +62,6 @@ unsigned int ctrlm_rf4ce_rsp_time_t::get_us(uint8_t profile_id) const { return(1000 * this->get_ms(profile_id)); } -// TODO: remove once generic RFC is approved for use -void ctrlm_rf4ce_rsp_time_t::legacy_rfc() { - unsigned int value = 0; - bool changed = false; - int rsp_time_min = (ctrlm_is_production_build() ? RESPONSE_TIME_MIN : RESPONSE_TIME_CONFIG_VBN_MIN); - int rsp_time_max = (ctrlm_is_production_build() ? RESPONSE_TIME_MAX : RESPONSE_TIME_CONFIG_VBN_MAX); - ctrlm_tr181_result_t result = ctrlm_tr181_int_get(CTRLM_RF4CE_TR181_RSP_TIME_XRC, &value, rsp_time_min, rsp_time_max); - if(result != CTRLM_TR181_RESULT_SUCCESS) { - XLOGD_INFO("XRC Response Time not present"); - } else { - if(value != this->rsp_times[RESPONSE_TIME_PROFILE_XRC]) { - changed = true; - } - this->rsp_times[RESPONSE_TIME_PROFILE_XRC] = value; - XLOGD_INFO("XRC Response Time %ums", this->rsp_times[RESPONSE_TIME_PROFILE_XRC]); - } - - result = ctrlm_tr181_int_get(CTRLM_RF4CE_TR181_RSP_TIME_XVP, &value, rsp_time_min, rsp_time_max); - if(result != CTRLM_TR181_RESULT_SUCCESS) { - XLOGD_INFO("XVP Response Time not present"); - } else { - if(value != this->rsp_times[RESPONSE_TIME_PROFILE_XVP]) { - changed = true; - } - this->rsp_times[RESPONSE_TIME_PROFILE_XVP] = value; - XLOGD_INFO("XVP Response Time %ums", this->rsp_times[RESPONSE_TIME_PROFILE_XVP]); - } - - result = ctrlm_tr181_int_get(CTRLM_RF4CE_TR181_RSP_TIME_XDIU, &value, rsp_time_min, rsp_time_max); - if(result != CTRLM_TR181_RESULT_SUCCESS) { - XLOGD_INFO("XDIU Response Time not present"); - } else { - if(value != this->rsp_times[RESPONSE_TIME_PROFILE_XDIU]) { - changed = true; - } - this->rsp_times[RESPONSE_TIME_PROFILE_XDIU] = value; - XLOGD_INFO("XDIU Response Time %ums", this->rsp_times[RESPONSE_TIME_PROFILE_XDIU]); - } - - if(changed && this->updated_listener) { - XLOGD_INFO("calling updated listener for %s", this->get_name().c_str()); - this->updated_listener(*this); - } -} - std::string ctrlm_rf4ce_rsp_time_t::to_string() const { std::stringstream ss; ss << "XRC <" << this->rsp_times.at(RESPONSE_TIME_PROFILE_XRC) << "ms> "; diff --git a/src/rf4ce/network/attributes/ctrlm_rf4ce_network_attr_config.h b/src/rf4ce/network/attributes/ctrlm_rf4ce_network_attr_config.h index 44a6a646..cdabf815 100644 --- a/src/rf4ce/network/attributes/ctrlm_rf4ce_network_attr_config.h +++ b/src/rf4ce/network/attributes/ctrlm_rf4ce_network_attr_config.h @@ -54,7 +54,6 @@ class ctrlm_rf4ce_rsp_time_t : public ctrlm_attr_t, public ctrlm_rf4ce_rib_attr_ public: unsigned int get_ms(uint8_t profile_id) const; unsigned int get_us(uint8_t profile_id) const; - void legacy_rfc(); public: /** diff --git a/src/voice/ctrlm_voice_obj.cpp b/src/voice/ctrlm_voice_obj.cpp index 43f28c05..808c0f87 100644 --- a/src/voice/ctrlm_voice_obj.cpp +++ b/src/voice/ctrlm_voice_obj.cpp @@ -417,6 +417,7 @@ bool ctrlm_voice_t::voice_configure_config_file_json(json_t *obj_voice, json_t * ctrlm_voice_iarm_call_settings_t *voice_settings = NULL; uint32_t voice_settings_len = 0; std::string init; + (void)local_conf; XLOGD_INFO("Configuring voice"); ctrlm_voice_audio_settings_t audio_settings = {this->audio_mode, this->audio_timing, this->audio_confidence_threshold, this->audio_ducking_type, this->audio_ducking_level, this->audio_ducking_beep_enabled}; @@ -578,7 +579,6 @@ bool ctrlm_voice_t::voice_configure_config_file_json(json_t *obj_voice, json_t * } this->set_audio_mode(&audio_settings); - this->process_xconf(&json_obj_vsdk, local_conf); // Disable muting/ducking to recover in case ctrlm restarts while muted/ducked. this->audio_state_set(false); @@ -949,118 +949,6 @@ bool ctrlm_voice_t::voice_init_set(const char *init, bool db_write) { return(ret); } -void ctrlm_voice_t::process_xconf(json_t **json_obj_vsdk, bool local_conf) { - XLOGD_INFO("Voice XCONF Settings"); - int result; - - char vsdk_config_str[CTRLM_RFC_MAX_PARAM_LEN] = {0}; //MAX_PARAM_LEN from rfcapi.h is 2048 - - if(ctrlm_is_rf4ce_enabled()) { - char encoder_params_str[CTRLM_RCU_RIB_ATTR_LEN_OPUS_ENCODING_PARAMS * 2 + 1] = {0}; - - result = ctrlm_tr181_string_get(CTRLM_RF4CE_TR181_RF4CE_OPUS_ENCODER_PARAMS, encoder_params_str, sizeof(encoder_params_str)); - if(result == CTRLM_TR181_RESULT_SUCCESS) { - std::string opus_encoder_params_str = encoder_params_str; - this->voice_params_opus_encoder_validate(opus_encoder_params_str); - - XLOGD_INFO("opus encoder params <%s>", this->prefs.opus_encoder_params_str.c_str()); - } - } - - ctrlm_voice_audio_settings_t audio_settings = {this->audio_mode, this->audio_timing, this->audio_confidence_threshold, this->audio_ducking_type, this->audio_ducking_level, this->audio_ducking_beep_enabled}; - bool changed = false; - - result = ctrlm_tr181_int_get(CTRLM_TR181_VOICE_PARAMS_AUDIO_MODE, (int*)&audio_settings.mode); - if(result == CTRLM_TR181_RESULT_SUCCESS) { - changed = true; - } - result = ctrlm_tr181_int_get(CTRLM_TR181_VOICE_PARAMS_AUDIO_TIMING, (int *)&audio_settings.timing); - if(result == CTRLM_TR181_RESULT_SUCCESS) { - changed = true; - } - result = ctrlm_tr181_real_get(CTRLM_TR181_VOICE_PARAMS_AUDIO_CONFIDENCE_THRESHOLD, &audio_settings.confidence_threshold); - if(result == CTRLM_TR181_RESULT_SUCCESS) { - changed = true; - } - result = ctrlm_tr181_int_get(CTRLM_TR181_VOICE_PARAMS_AUDIO_DUCKING_TYPE, (int *)&audio_settings.ducking_type); - if(result == CTRLM_TR181_RESULT_SUCCESS) { - changed = true; - } - result = ctrlm_tr181_real_get(CTRLM_TR181_VOICE_PARAMS_AUDIO_DUCKING_LEVEL, &audio_settings.ducking_level); - if(result == CTRLM_TR181_RESULT_SUCCESS) { - changed = true; - } - - // CTRLM_TR181_VOICE_PARAMS_AUDIO_DUCKING_BEEP doesn't exist because this is a user configurable setting via configureVoice thunder api - - result = ctrlm_tr181_string_get(CTRLM_TR181_VOICE_PARAMS_VSDK_CONFIGURATION, &vsdk_config_str[0], CTRLM_RFC_MAX_PARAM_LEN); - if(result == CTRLM_TR181_RESULT_SUCCESS) { - json_error_t jerror; - json_t *jvsdk; - char *decoded_buf = NULL; - size_t decoded_buf_len = 0; - - decoded_buf = (char *)g_base64_decode((const gchar*)vsdk_config_str, &decoded_buf_len); - if(decoded_buf) { - if(decoded_buf_len > 0 && decoded_buf_len < CTRLM_RFC_MAX_PARAM_LEN) { - XLOGD_INFO("VSDK configuration taken from XCONF"); - XLOGD_INFO("%s", decoded_buf); - - jvsdk = json_loads(&decoded_buf[0], 0, &jerror); - do { - if(NULL == jvsdk) { - XLOGD_ERROR("XCONF has VSDK params but json_loads() failed, line %d: %s ", jerror.line, jerror.text ); - break; - } - if(!json_is_object(jvsdk)) - { - XLOGD_ERROR("found VSDK in text but invalid object"); - break; - } - - //If execution reaches here we have XCONF settings to use. If developer has used local conf settings, keep them. - if(local_conf) { - if(!json_object_update(jvsdk, *json_obj_vsdk)) { - XLOGD_ERROR("failed to update json_obj_vsdk"); - break; - } - } - - *json_obj_vsdk = json_deep_copy(jvsdk); - if(NULL == *json_obj_vsdk) - { - XLOGD_ERROR("found VSDK object but failed to copy. We have lost any /opt file VSDK parameters"); - /* Nothing to do about this unlikely error. If I copy to a temp pointer to protect the input, - * then I have to copy from temp to real, and check that copy for failure. Where would it end? - */ - break; - } - }while(0); - } else { - XLOGD_WARN("incorrect length"); - } - free(decoded_buf); - } else { - XLOGD_WARN("failed to decode base64"); - } - } - - int value = 0; - result = ctrlm_tr181_int_get(CTRLM_RF4CE_TR181_PRESS_AND_RELEASE_EOS_TIMEOUT, &value, 0, UINT16_MAX); - if(result == CTRLM_TR181_RESULT_SUCCESS) { - this->prefs.par_voice_eos_timeout = value; - } - - result = ctrlm_tr181_int_get(CTRLM_RF4CE_TR181_PRESS_AND_RELEASE_EOS_METHOD, &value, 0, UINT8_MAX); - if(result == CTRLM_TR181_RESULT_SUCCESS) { - this->prefs.par_voice_eos_method = value; - } - - if(changed) { - this->set_audio_mode(&audio_settings); - } -} - void ctrlm_voice_t::query_strings_updated() { // N/A } diff --git a/src/voice/ctrlm_voice_obj.h b/src/voice/ctrlm_voice_obj.h index 3ec217b2..b7368631 100644 --- a/src/voice/ctrlm_voice_obj.h +++ b/src/voice/ctrlm_voice_obj.h @@ -554,7 +554,6 @@ class ctrlm_voice_t { void voice_params_qos_get(voice_params_qos_t *params); void voice_params_opus_encoder_get(voice_params_opus_encoder_t *params); void voice_params_par_get(voice_params_par_t *params); - virtual void process_xconf(json_t **json_obj_vsdk, bool local_conf); virtual void query_strings_updated(); int packet_loss_threshold_get() const; From 1fdb0b1964e2193d10835bff6821694dc5ca04ff Mon Sep 17 00:00:00 2001 From: dwolaver <44593664+dwolaver@users.noreply.github.com> Date: Thu, 16 Jul 2026 13:07:43 -0400 Subject: [PATCH 77/81] RDKEMW-4056 : RFC overrides for BLE network config (#52) --- src/ble/ctrlm_ble_network.cpp | 28 ++++++++++++- .../hal/blercu/blercupairingstatemachine.cpp | 28 ++++++------- .../hal/blercu/blercupairingstatemachine.h | 6 +-- src/ble/hal/configsettings/configsettings.cpp | 39 +++++++++++++++++++ src/ble/hal/configsettings/configsettings.h | 6 +-- 5 files changed, 86 insertions(+), 21 deletions(-) diff --git a/src/ble/ctrlm_ble_network.cpp b/src/ble/ctrlm_ble_network.cpp index 64ec4984..a0f37652 100644 --- a/src/ble/ctrlm_ble_network.cpp +++ b/src/ble/ctrlm_ble_network.cpp @@ -2797,7 +2797,33 @@ void ctrlm_obj_network_ble_t::power_state_change(gboolean waking_up) { } void ctrlm_obj_network_ble_t::rfc_retrieved_handler(const ctrlm_rfc_attr_t &attr) { - // TODO - No RFC parameters as of now + XLOGD_INFO("process BLE RFC values"); + + // Process options object + bool disable_voice = false; + if(attr.get_rfc_value(JSON_OBJ_NAME_NETWORK_BLE_OPTIONS JSON_PATH_SEPERATOR JSON_BOOL_NAME_NETWORK_BLE_OPTIONS_DISABLE_VOICE, disable_voice)) { + voice_disabled_ = disable_voice; + XLOGD_INFO("BLE voice support is %s by config", voice_disabled_ ? "disabled" : "enabled"); + } + + auto config = getConfigSettings(); + if (config == nullptr) { + XLOGD_ERROR("config not available"); + return; + } + + json_t *obj = nullptr; + if(!attr.get_rfc_json_value(&obj)) { + XLOGD_ERROR("failed to get RFC json object"); + return; + } + + // Update config settings from RFC json object + bool updated = config->updateFromJson(obj); + if(!updated) { + XLOGD_WARN("no BLE config updates found in RFC"); + } + json_decref(obj); } std::vector ctrlm_obj_network_ble_t::get_controller_obj_list() const { diff --git a/src/ble/hal/blercu/blercupairingstatemachine.cpp b/src/ble/hal/blercu/blercupairingstatemachine.cpp index 0779fb69..8fa38aa5 100644 --- a/src/ble/hal/blercu/blercupairingstatemachine.cpp +++ b/src/ble/hal/blercu/blercupairingstatemachine.cpp @@ -44,11 +44,8 @@ BleRcuPairingStateMachine::BleRcuPairingStateMachine(const shared_ptrdiscoveryTimeout()) - , m_discoveryTimeoutDefault(config->discoveryTimeout()) - , m_pairingTimeout(config->pairingTimeout()) - , m_setupTimeout(config->setupTimeout()) - , m_unpairingTimeout(config->upairingTimeout()) , m_pairingAttempts(0) , m_pairingSuccesses(0) , m_pairingSucceeded(false) @@ -287,6 +284,7 @@ void BleRcuPairingStateMachine::startAutoWithTimeout(int timeoutMs) m_pairingAttempts++; m_pairingSucceeded = false; XLOGD_INFO("Started auto pairing procedure"); + XLOGD_DEBUG("timeouts - discovery <%d ms> pairing <%d ms> setup <%d ms> unpairing <%d ms>", m_discoveryTimeout, m_config->pairingTimeout(), m_config->setupTimeout(), m_config->upairingTimeout()); } @@ -304,7 +302,7 @@ void BleRcuPairingStateMachine::startWithCode(uint8_t pairingCode) return; } - m_discoveryTimeout = m_discoveryTimeoutDefault; + m_discoveryTimeout = m_config->discoveryTimeout(); // use the default discovery timeout for this pairing method m_isAutoPairing = false; // clear the target device @@ -345,6 +343,7 @@ void BleRcuPairingStateMachine::startWithCode(uint8_t pairingCode) m_pairingAttempts++; m_pairingSucceeded = false; XLOGD_INFO("started pairing, searching for device with prefix code %03d or MAC hash 0x%02X", m_pairingCode, m_pairingMacHash); + XLOGD_DEBUG("timeouts - discovery <%d ms> pairing <%d ms> setup <%d ms> unpairing <%d ms>", m_discoveryTimeout, m_config->pairingTimeout(), m_config->setupTimeout(), m_config->upairingTimeout()); } // ----------------------------------------------------------------------------- @@ -360,6 +359,8 @@ void BleRcuPairingStateMachine::startWithMacList(const std::vector & return; } + m_discoveryTimeout = m_config->discoveryTimeout(); // use the default discovery timeout for this pairing method + // clear the target device m_targetAddress.clear(); @@ -389,7 +390,7 @@ void BleRcuPairingStateMachine::startWithMacList(const std::vector & for (const auto &address : macList) { XLOGD_INFO("<%s>", address.toString().c_str()); } - + XLOGD_DEBUG("timeouts - discovery <%d ms> pairing <%d ms> setup <%d ms> unpairing <%d ms>", m_discoveryTimeout, m_config->pairingTimeout(), m_config->setupTimeout(), m_config->upairingTimeout()); } @@ -511,9 +512,9 @@ void BleRcuPairingStateMachine::onStateTransition(int oldState, int newState) } } else if (newState == UnpairingState) { if (oldState == EnablePairableState || oldState == PairingState) { - XLOGD_AUTOMATION_WARN("timed-out in pairing phase (rcu device didn't pair within %dms)", m_pairingTimeout); + XLOGD_AUTOMATION_WARN("timed-out in pairing phase (rcu device didn't pair within %dms)", m_config->pairingTimeout()); } else if (oldState == SetupState) { - XLOGD_AUTOMATION_WARN("timed-out in setup phase (rcu didn't response to all requests within %dms)", m_setupTimeout); + XLOGD_AUTOMATION_WARN("timed-out in setup phase (rcu didn't response to all requests within %dms)", m_config->setupTimeout()); } } @@ -643,7 +644,7 @@ void BleRcuPairingStateMachine::onExitedDiscoverySuperState() void BleRcuPairingStateMachine::onEnteredStoppingDiscoveryState() { // start the pairing timeout timer - m_stateMachine.postDelayedEvent(PairingTimeoutEvent, m_pairingTimeout); + m_stateMachine.postDelayedEvent(PairingTimeoutEvent, m_config->pairingTimeout()); // if we've got to this state it means we have a target device if (m_targetAddress.isNull()) { @@ -708,7 +709,7 @@ void BleRcuPairingStateMachine::onEnteredEnablePairableState() // in pairable mode because we don't know if the previous timeout is long enough for our purposes. // The timeout is set to 5 seconds past the overall time we've given the state machine // to pair with the rcu. - m_adapter->enablePairable(m_pairingTimeout + 5000); + m_adapter->enablePairable(m_config->pairingTimeout() + 5000); if (m_adapter->isPairable()) { // is already pairable so just post the 'enabled' event @@ -748,8 +749,9 @@ void BleRcuPairingStateMachine::onEnteredPairingState() void BleRcuPairingStateMachine::onEnteredSetupState() { // start the setup timeout timer - m_stateMachine.postDelayedEvent(SetupTimeoutEvent, m_setupTimeout); - XLOGD_DEBUG("starting setup timeout timer for %dms", m_setupTimeout); + int timeout = m_config->setupTimeout(); + m_stateMachine.postDelayedEvent(SetupTimeoutEvent, timeout); + XLOGD_DEBUG("starting setup timeout timer for %dms", timeout); } // ----------------------------------------------------------------------------- @@ -781,7 +783,7 @@ void BleRcuPairingStateMachine::onExitedPairingSuperState() void BleRcuPairingStateMachine::onEnteredUnpairingState() { // start the unpairing timeout timer - m_stateMachine.postDelayedEvent(UnpairingTimeoutEvent, m_unpairingTimeout); + m_stateMachine.postDelayedEvent(UnpairingTimeoutEvent, m_config->upairingTimeout()); // if we've got to this state it means we have a target device if (m_targetAddress.isNull()) { diff --git a/src/ble/hal/blercu/blercupairingstatemachine.h b/src/ble/hal/blercu/blercupairingstatemachine.h index f3d18178..2988f198 100644 --- a/src/ble/hal/blercu/blercupairingstatemachine.h +++ b/src/ble/hal/blercu/blercupairingstatemachine.h @@ -192,11 +192,9 @@ class BleRcuPairingStateMachine StateMachine m_stateMachine; + const std::shared_ptr m_config; + int m_discoveryTimeout; - int m_discoveryTimeoutDefault; - int m_pairingTimeout; - int m_setupTimeout; - int m_unpairingTimeout; int m_pairingAttempts; int m_pairingSuccesses; diff --git a/src/ble/hal/configsettings/configsettings.cpp b/src/ble/hal/configsettings/configsettings.cpp index ce8cc3a7..29539642 100644 --- a/src/ble/hal/configsettings/configsettings.cpp +++ b/src/ble/hal/configsettings/configsettings.cpp @@ -200,6 +200,37 @@ std::shared_ptr ConfigSettings::parseJson(json_t *jsonConfig) return std::make_shared(timeouts, std::move(models)); } +// ----------------------------------------------------------------------------- +/*! + Parses a json config file and updates the existing object. Any unrecognized fields are ignored. + + \see defaults() + */ +bool ConfigSettings::updateJson(json_t *jsonConfig) +{ + bool updated = false; + + if (jsonConfig == nullptr || !json_is_object(jsonConfig)) { + XLOGD_WARN("invalid json config"); + return(updated); + } + + // find the timeout params + json_t *timeoutsObj = json_object_get(jsonConfig, "timeouts"); + if (timeoutsObj && json_is_object(timeoutsObj)) { + m_timeOuts = parseTimeouts(timeoutsObj); + updated = true; + } + + // find the model details array + json_t *modelArray = json_object_get(jsonConfig, "models"); + if (modelArray && json_is_array(modelArray)) { + XLOGD_WARN("models cannot be updated"); + } + + return(updated); +} + // ----------------------------------------------------------------------------- /*! Parses a json config file and returns a \l{std::shared_ptr} to a @@ -378,3 +409,11 @@ int ConfigSettings::hidrawWaitLimitTimeout() const return m_timeOuts.hidrawWaitLimitMSecs; } +// ----------------------------------------------------------------------------- +/*! + Returns true if any of the config fields are updated. Otherwise, returns false. + */ +bool ConfigSettings::updateFromJson(json_t *jsonConfig) +{ + return updateJson(jsonConfig); +} diff --git a/src/ble/hal/configsettings/configsettings.h b/src/ble/hal/configsettings/configsettings.h index 5a4d5e9b..c51c9491 100644 --- a/src/ble/hal/configsettings/configsettings.h +++ b/src/ble/hal/configsettings/configsettings.h @@ -48,6 +48,7 @@ class ConfigSettings static std::shared_ptr fromJsonFile(const std::string &filePath); static std::shared_ptr fromJsonBuffer(const char *jsonBuffer); static std::shared_ptr parseJson(json_t *jsonConfig); + bool updateJson(json_t *jsonConfig); struct TimeOuts { int discoveryMSecs; @@ -65,6 +66,7 @@ class ConfigSettings std::vector &&modelDetails); public: + bool updateFromJson(json_t *jsonConfig); int discoveryTimeout() const; int pairingTimeout() const; int setupTimeout() const; @@ -80,11 +82,9 @@ class ConfigSettings static TimeOuts parseTimeouts(json_t *json); private: - const TimeOuts m_timeOuts; + TimeOuts m_timeOuts; const std::vector m_modelDetails; }; -// QDebug operator<<(QDebug dbg, const ConfigSettings &settings); - #endif // !defined(CONFIGSETTINGS_H) From 8e1c5e70001f7467792d918ec244129bf512cd2b Mon Sep 17 00:00:00 2001 From: dwolaver <44593664+dwolaver@users.noreply.github.com> Date: Mon, 20 Jul 2026 12:32:40 -0400 Subject: [PATCH 78/81] RDKEMW-21599 : Control manager crashed on executing tr181 command (#262) --- src/rfc/ctrlm_rfc_attr.cpp | 6 +++--- src/voice/ctrlm_voice_obj.cpp | 12 ++++++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/rfc/ctrlm_rfc_attr.cpp b/src/rfc/ctrlm_rfc_attr.cpp index f9e996bb..0e52ee19 100644 --- a/src/rfc/ctrlm_rfc_attr.cpp +++ b/src/rfc/ctrlm_rfc_attr.cpp @@ -70,7 +70,9 @@ void ctrlm_rfc_attr_t::set_rfc_value(const std::string &value) { // Convert to JSON json_t *temp = this->value_json; json_error_t json_error; - this->value_json = json_loads((const char *)decoded_buf, JSON_REJECT_DUPLICATES, &json_error); + this->value_json = json_loadb((const char *)decoded_buf, decoded_buf_len, JSON_REJECT_DUPLICATES, &json_error); + free(decoded_buf); + decoded_buf = NULL; if(this->value_json) { XLOGD_INFO("successfully got JSON from encoded string, alert the listeners"); json_decref(temp); @@ -80,8 +82,6 @@ void ctrlm_rfc_attr_t::set_rfc_value(const std::string &value) { this->value_json = temp; return; // return here, we don't want to call listeners on invalid data } - free(decoded_buf); - decoded_buf = NULL; } else { XLOGD_ERROR("failed to decode base64"); return; // return here, we don't want to call listeners on invalid data diff --git a/src/voice/ctrlm_voice_obj.cpp b/src/voice/ctrlm_voice_obj.cpp index 808c0f87..2bc56102 100644 --- a/src/voice/ctrlm_voice_obj.cpp +++ b/src/voice/ctrlm_voice_obj.cpp @@ -3870,8 +3870,6 @@ xrsr_power_mode_t voice_xrsr_power_map(ctrlm_power_state_t ctrlm_power_state) { } void ctrlm_voice_t::voice_rfc_retrieved_handler(const ctrlm_rfc_attr_t& attr) { - bool enabled = true; - XLOGD_INFO("processing RFC values"); attr.get_rfc_value(JSON_INT_NAME_VOICE_VREX_REQUEST_TIMEOUT, this->prefs.timeout_vrex_connect,0); @@ -3992,6 +3990,7 @@ void ctrlm_voice_t::voice_rfc_retrieved_handler(const ctrlm_rfc_attr_t& attr) { } if(attr.get_rfc_value(JSON_BOOL_NAME_VOICE_FORCE_VOICE_SETTINGS, this->prefs.force_voice_settings) && this->prefs.force_voice_settings) { + bool enabled = true; attr.get_rfc_value(JSON_BOOL_NAME_VOICE_ENABLE, enabled); attr.get_rfc_value(JSON_STR_NAME_VOICE_URL_SRC_PTT, this->prefs.server_url_src_ptt); attr.get_rfc_value(JSON_STR_NAME_VOICE_URL_SRC_FF, this->prefs.server_url_src_ff); @@ -4013,6 +4012,7 @@ void ctrlm_voice_t::voice_rfc_retrieved_handler(const ctrlm_rfc_attr_t& attr) { } void ctrlm_voice_t::vsdk_rfc_retrieved_handler(const ctrlm_rfc_attr_t& attr) { + XLOGD_INFO("processing RFC values"); json_t *obj_vsdk = NULL; if(attr.get_rfc_json_value(&obj_vsdk) && obj_vsdk) { XLOGD_INFO("VSDK values from XCONF, reopening xrsr.."); @@ -4021,7 +4021,12 @@ void ctrlm_voice_t::vsdk_rfc_retrieved_handler(const ctrlm_rfc_attr_t& attr) { } // This is temporary until the VSDK supports receiving a config on the fly this->voice_sdk_close(); - this->voice_sdk_open(obj_vsdk); + if(this->vsdk_config) { + json_decref(this->vsdk_config); + this->vsdk_config = NULL; + } + this->vsdk_config = obj_vsdk; // Transfer ownership + this->voice_sdk_open(this->vsdk_config); this->voice_sdk_update_routes(); // Set init message if read from shared memory @@ -4038,7 +4043,6 @@ void ctrlm_voice_t::vsdk_rfc_retrieved_handler(const ctrlm_rfc_attr_t& attr) { } else { this->voice_init_set(init.c_str(), false); } - json_decref(obj_vsdk); } } From e0a75fdc35092b0f004676a0d4bc68aa677a5bc2 Mon Sep 17 00:00:00 2001 From: dwolaver <44593664+dwolaver@users.noreply.github.com> Date: Wed, 22 Jul 2026 17:27:50 -0400 Subject: [PATCH 79/81] RDKEMW-20831 : remove ctrlm unused IARM calls/events (#258) --- doxygen/build_docs.py | 203 -- doxygen/ctrlm_api_all | 2310 ---------------- doxygen/ctrlm_api_hal | 2315 ---------------- doxygen/ctrlm_api_hal_rf4ce | 2317 ----------------- doxygen/ctrlm_api_ipc | 2314 ---------------- doxygen/ctrlm_api_ipc_device_update | 2316 ---------------- doxygen/ctrlm_api_ipc_rcu | 2316 ---------------- doxygen/ctrlm_api_ipc_voice | 2316 ---------------- doxygen/ctrlm_dox_hal.h | 0 doxygen/ctrlm_dox_hal_btle.h | 0 doxygen/ctrlm_dox_hal_ip.h | 0 doxygen/ctrlm_dox_hal_rf4ce.h | 69 - doxygen/ctrlm_dox_ipc.h | 64 - doxygen/ctrlm_dox_ipc_device_update.h | 68 - doxygen/ctrlm_dox_ipc_rcu.h | 68 - doxygen/ctrlm_dox_ipc_voice.h | 68 - doxygen/iarm/libIARM.h | 112 - doxygen/iarm/libIBus.h | 319 --- include/ctrlm_ipc.h | 362 +-- include/ctrlm_ipc_ble.h | 23 - include/ctrlm_ipc_device_update.h | 270 -- include/ctrlm_ipc_key_codes.h | 4 - include/ctrlm_ipc_rcu.h | 414 --- include/ctrlm_ipc_voice.h | 251 -- src/ctrlm.h | 61 +- src/ctrlm_device_update.cpp | 113 +- src/ctrlm_device_update.h | 7 - src/ctrlm_device_update_iarm.cpp | 236 -- src/ctrlm_main.cpp | 975 +------ src/ctrlm_main_iarm.cpp | 259 +- src/ctrlm_network.cpp | 15 - src/ctrlm_network.h | 1 - src/ctrlm_rcu.cpp | 84 - src/ctrlm_rcu.h | 2 - src/ctrlm_rcu_iarm.cpp | 15 - src/ctrlm_utils.cpp | 37 - src/ctrlm_utils.h | 3 - src/database/ctrlm_database.cpp | 4 - src/database/ctrlm_database.h | 1 - src/rf4ce/ctrlm_rf4ce_network.cpp | 55 +- src/rf4ce/ctrlm_rf4ce_network.h | 1 - src/voice/ctrlm_voice_obj.cpp | 4 +- src/voice/ipc/ctrlm_voice_ipc_iarm_legacy.cpp | 180 +- 43 files changed, 115 insertions(+), 20437 deletions(-) delete mode 100755 doxygen/build_docs.py delete mode 100644 doxygen/ctrlm_api_all delete mode 100644 doxygen/ctrlm_api_hal delete mode 100644 doxygen/ctrlm_api_hal_rf4ce delete mode 100644 doxygen/ctrlm_api_ipc delete mode 100644 doxygen/ctrlm_api_ipc_device_update delete mode 100644 doxygen/ctrlm_api_ipc_rcu delete mode 100644 doxygen/ctrlm_api_ipc_voice delete mode 100644 doxygen/ctrlm_dox_hal.h delete mode 100644 doxygen/ctrlm_dox_hal_btle.h delete mode 100644 doxygen/ctrlm_dox_hal_ip.h delete mode 100644 doxygen/ctrlm_dox_hal_rf4ce.h delete mode 100644 doxygen/ctrlm_dox_ipc.h delete mode 100644 doxygen/ctrlm_dox_ipc_device_update.h delete mode 100644 doxygen/ctrlm_dox_ipc_rcu.h delete mode 100644 doxygen/ctrlm_dox_ipc_voice.h delete mode 100644 doxygen/iarm/libIARM.h delete mode 100644 doxygen/iarm/libIBus.h diff --git a/doxygen/build_docs.py b/doxygen/build_docs.py deleted file mode 100755 index 0e48adbe..00000000 --- a/doxygen/build_docs.py +++ /dev/null @@ -1,203 +0,0 @@ -#!/usr/bin/python -########################################################################## -# If not stated otherwise in this file or this component's LICENSE -# file the following copyright and licenses apply: -# -# Copyright 2020 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. -########################################################################## - -import os, sys, shutil, tarfile -from subprocess import call -import re - -dir_out = "./output/" - -def docs_gen_all(build_release=False): - release_version = '1' - release_name = 'ctrlm_all_release_' + release_version - header_files = ['ctrlm_hal.h', 'ctrlm_hal_rf4ce.h', 'ctrlm_hal_btle.h', 'ctrlm_hal_ip.h', 'ctrlm_ipc.h', 'ctrlm_ipc_rcu.h', 'ctrlm_ipc_voice.h', 'ctrlm_ipc_key_codes.h', 'ctrlm_ipc_device_update.h'] - cmd = ["doxygen", "ctrlm_api_all"] - ret = call(cmd) - if build_release: - build_pdf() - package_release(release_name, header_files) - else: - launch_html() - -def docs_gen_hal(build_release=False): - release_version = '1' - release_name = 'ctrlm_hal_release_' + release_version - header_files = ['ctrlm_hal.h', 'ctrlm_hal_rf4ce.h', 'ctrlm_hal_btle.h', 'ctrlm_hal_ip.h'] - cmd = ["doxygen", "ctrlm_api_hal", "ctrlm_hal_rf4ce.h", "ctrlm_hal_btle.h", "ctrlm_hal_ip.h" ] - ret = call(cmd) - if build_release: - build_pdf() - package_release(release_name, header_files) - else: - launch_html() - -def docs_gen_hal_rf4ce(build_release=False): - release_version = release_version_get('ctrlm_hal_rf4ce.h', 'CTRLM_HAL_RF4CE_API_VERSION') - release_name = 'ctrlm_hal_rf4ce_release_' + release_version - header_files = ['ctrlm_hal.h', 'ctrlm_hal_rf4ce.h'] - cmd = ["doxygen", "ctrlm_api_hal_rf4ce" ] - ret = call(cmd) - if build_release: - build_pdf() - package_release(release_name, header_files) - else: - launch_html() - -def docs_gen_hal_btle(build_release=False): - release_version = '1' - release_name = 'ctrlm_hal_btle_release_' + release_version - header_files = ['ctrlm_hal.h', 'ctrlm_hal_btle.h'] - cmd = ["doxygen", "ctrlm_api_hal_btle" ] - ret = call(cmd) - if build_release: - build_pdf() - package_release(release_name, header_files) - else: - launch_html() - -def docs_gen_hal_ip(build_release=False): - release_version = '1' - release_name = 'ctrlm_hal_ip_release_' + release_version - header_files = ['ctrlm_hal.h', 'ctrlm_hal_ip.h'] - cmd = ["doxygen", "ctrlm_api_hal_ip" ] - ret = call(cmd) - if build_release: - build_pdf() - package_release(release_name, header_files) - else: - launch_html() - -def docs_gen_ipc(build_release=False): - release_version = '3' - release_name = 'ctrlm_ipc_release_' + release_version - header_files = ['ctrlm_ipc.h', 'ctrlm_ipc_rcu.h', 'ctrlm_ipc_voice.h', 'ctrlm_ipc_key_codes.h', 'ctrlm_ipc_device_update.h'] - cmd = ["doxygen", "ctrlm_api_ipc" ] - ret = call(cmd) - if build_release: - build_pdf() - package_release(release_name, header_files) - else: - launch_html() - -def docs_gen_ipc_device_update(build_release=False): - release_version = '1' - release_name = 'ctrlm_ipc_device_update_release_' + release_version - header_files = ['ctrlm_ipc.h', 'ctrlm_ipc_device_update.h'] - cmd = ["doxygen", "ctrlm_api_ipc_device_update" ] - ret = call(cmd) - if build_release: - build_pdf() - package_release(release_name, header_files) - else: - launch_html() - -def docs_gen_ipc_voice(build_release=False): - release_version = '1' - release_name = 'ctrlm_ipc_voice_release_' + release_version - header_files = ['ctrlm_ipc.h', 'ctrlm_ipc_voice.h'] - cmd = ["doxygen", "ctrlm_api_ipc_voice" ] - ret = call(cmd) - if build_release: - build_pdf() - package_release(release_name, header_files) - else: - launch_html() - -def docs_gen_ipc_rcu(build_release=False): - release_version = '1' - release_name = 'ctrlm_ipc_rcu_release_' + release_version - header_files = ['ctrlm_ipc.h', 'ctrlm_ipc_rcu.h', 'ctrlm_ipc_key_codes.h'] - cmd = ["doxygen", "ctrlm_api_ipc_rcu" ] - ret = call(cmd) - if build_release: - build_pdf() - package_release(release_name, header_files) - else: - launch_html() - -def launch_html(): - dir_html = os.path.join(dir_out, 'html') - file_html = os.path.join(dir_html, 'index.html') - cmd = ["firefox", file_html ] - ret = call(cmd) - -def build_pdf(): - os.chdir("./output/latex") - cmd = ["pdflatex", "refman.tex" ] - ret = call(cmd) - os.chdir("../..") - -def package_release(release_name, header_files): - dir_html = os.path.join(dir_out, 'html') - dir_latex = os.path.join(dir_out, 'latex') - dir_rel = os.path.join(dir_out, release_name) - dir_rel_html = os.path.join(dir_rel, 'html') - file_pdf = os.path.join(dir_latex, 'refman.pdf') - file_rel_pdf = os.path.join(dir_rel, 'hal_api.pdf') - file_rel_html = os.path.join(dir_rel, 'hal_api.html') - file_rel_tar = os.path.join(dir_out, release_name + '.tar.gz') - - if os.path.isdir(dir_rel): - shutil.rmtree(dir_rel) - - # Create release directory - os.mkdir(dir_rel) - # Copy html files - shutil.copytree(dir_html, dir_rel_html) - - # Create html shortcut - fh = open(file_rel_html, 'w') - fh.write('') - fh.close() - - # Copy pdf file - shutil.copy2(file_pdf, file_rel_pdf) - - # Copy header files - for file in header_files: - shutil.copy2(os.path.join('../include', file), dir_rel) - - # tar up the release - tar = tarfile.open(file_rel_tar, "w:gz") - tar.add(dir_rel, arcname=release_name) - tar.close() - - # Remove the release directory - shutil.rmtree(dir_rel) - -def release_version_get(filename, key): - fh = open(os.path.join('../include', filename), 'r') - contents = fh.read() - fh.close() - - m = re.search('.*' + key + '\s*\((.*)\)', contents) - - return m.group(1) - - -#docs_gen_all() -#docs_gen_hal() -docs_gen_hal_rf4ce(True) -#docs_gen_hal_btle() -#docs_gen_hal_ip() -#docs_gen_ipc() -#docs_gen_ipc_device_update(False) -#docs_gen_ipc_voice() -#docs_gen_ipc_rcu() diff --git a/doxygen/ctrlm_api_all b/doxygen/ctrlm_api_all deleted file mode 100644 index 56797131..00000000 --- a/doxygen/ctrlm_api_all +++ /dev/null @@ -1,2310 +0,0 @@ -# Doxyfile 1.8.6 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project. -# -# All text after a double hash (##) is considered a comment and is placed in -# front of the TAG it is preceding. -# -# All text after a single hash (#) is considered a comment and will be ignored. -# The format is: -# TAG = value [value, ...] -# For lists, items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (\" \"). - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all text -# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv -# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv -# for the list of possible encodings. -# The default value is: UTF-8. - -DOXYFILE_ENCODING = UTF-8 - -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by -# double-quotes, unless you are using Doxywizard) that should identify the -# project for which the documentation is generated. This name is used in the -# title of most generated pages and in a few other places. -# The default value is: My Project. - -PROJECT_NAME = "Control Manager" - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. This -# could be handy for archiving the generated documentation or if some version -# control system is used. - -PROJECT_NUMBER = - -# Using the PROJECT_BRIEF tag one can provide an optional one line description -# for a project that appears at the top of each page and should give viewer a -# quick idea about the purpose of the project. Keep the description short. - -PROJECT_BRIEF = - -# With the PROJECT_LOGO tag one can specify an logo or icon that is included in -# the documentation. The maximum height of the logo should not exceed 55 pixels -# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo -# to the output directory. - -PROJECT_LOGO = - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path -# into which the generated documentation will be written. If a relative path is -# entered, it will be relative to the location where doxygen was started. If -# left blank the current directory will be used. - -OUTPUT_DIRECTORY = ./output/ - -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- -# directories (in 2 levels) under the output directory of each output format and -# will distribute the generated files over these directories. Enabling this -# option can be useful when feeding doxygen a huge amount of source files, where -# putting all generated files in the same directory would otherwise causes -# performance problems for the file system. -# The default value is: NO. - -CREATE_SUBDIRS = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, -# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), -# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, -# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), -# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, -# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, -# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, -# Ukrainian and Vietnamese. -# The default value is: English. - -OUTPUT_LANGUAGE = English - -# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member -# descriptions after the members that are listed in the file and class -# documentation (similar to Javadoc). Set to NO to disable this. -# The default value is: YES. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief -# description of a member or function before the detailed description -# -# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. -# The default value is: YES. - -REPEAT_BRIEF = NO - -# This tag implements a quasi-intelligent brief description abbreviator that is -# used to form the text in various listings. Each string in this list, if found -# as the leading text of the brief description, will be stripped from the text -# and the result, after processing the whole list, is used as the annotated -# text. Otherwise, the brief description is used as-is. If left blank, the -# following values are used ($name is automatically replaced with the name of -# the entity):The $name class, The $name widget, The $name file, is, provides, -# specifies, contains, represents, a, an and the. - -ABBREVIATE_BRIEF = - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# doxygen will generate a detailed section even if there is only a brief -# description. -# The default value is: NO. - -ALWAYS_DETAILED_SEC = NO - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. -# The default value is: NO. - -INLINE_INHERITED_MEMB = NO - -# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path -# before files name in the file list and in the header files. If set to NO the -# shortest path that makes the file name unique will be used -# The default value is: YES. - -FULL_PATH_NAMES = YES - -# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. -# Stripping is only done if one of the specified strings matches the left-hand -# part of the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the path to -# strip. -# -# Note that you can specify absolute paths here, but also relative paths, which -# will be relative from the directory where doxygen is started. -# This tag requires that the tag FULL_PATH_NAMES is set to YES. - -STRIP_FROM_PATH = - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the -# path mentioned in the documentation of a class, which tells the reader which -# header file to include in order to use a class. If left blank only the name of -# the header file containing the class definition is used. Otherwise one should -# specify the list of include paths that are normally passed to the compiler -# using the -I flag. - -STRIP_FROM_INC_PATH = - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but -# less readable) file names. This can be useful is your file systems doesn't -# support long names like on DOS, Mac, or CD-ROM. -# The default value is: NO. - -SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the -# first line (until the first dot) of a Javadoc-style comment as the brief -# description. If set to NO, the Javadoc-style will behave just like regular Qt- -# style comments (thus requiring an explicit @brief command for a brief -# description.) -# The default value is: NO. - -JAVADOC_AUTOBRIEF = NO - -# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first -# line (until the first dot) of a Qt-style comment as the brief description. If -# set to NO, the Qt-style will behave just like regular Qt-style comments (thus -# requiring an explicit \brief command for a brief description.) -# The default value is: NO. - -QT_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a -# multi-line C++ special comment block (i.e. a block of //! or /// comments) as -# a brief description. This used to be the default behavior. The new default is -# to treat a multi-line C++ comment block as a detailed description. Set this -# tag to YES if you prefer the old behavior instead. -# -# Note that setting this tag to YES also means that rational rose comments are -# not recognized any more. -# The default value is: NO. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the -# documentation from any documented member that it re-implements. -# The default value is: YES. - -INHERIT_DOCS = YES - -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a -# new page for each member. If set to NO, the documentation of a member will be -# part of the file/class/namespace that contains it. -# The default value is: NO. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen -# uses this value to replace tabs by spaces in code fragments. -# Minimum value: 1, maximum value: 16, default value: 4. - -TAB_SIZE = 4 - -# This tag can be used to specify a number of aliases that act as commands in -# the documentation. An alias has the form: -# name=value -# For example adding -# "sideeffect=@par Side Effects:\n" -# will allow you to put the command \sideeffect (or @sideeffect) in the -# documentation, which will result in a user-defined paragraph with heading -# "Side Effects:". You can put \n's in the value part of an alias to insert -# newlines. - -ALIASES = - -# This tag can be used to specify a number of word-keyword mappings (TCL only). -# A mapping has the form "name=value". For example adding "class=itcl::class" -# will allow you to use the command class in the itcl::class meaning. - -TCL_SUBST = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources -# only. Doxygen will then generate output that is more tailored for C. For -# instance, some of the names that are used will be different. The list of all -# members will be omitted, etc. -# The default value is: NO. - -OPTIMIZE_OUTPUT_FOR_C = YES - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or -# Python sources only. Doxygen will then generate output that is more tailored -# for that language. For instance, namespaces will be presented as packages, -# qualified scopes will look different, etc. -# The default value is: NO. - -OPTIMIZE_OUTPUT_JAVA = NO - -# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -# sources. Doxygen will then generate output that is tailored for Fortran. -# The default value is: NO. - -OPTIMIZE_FOR_FORTRAN = NO - -# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -# sources. Doxygen will then generate output that is tailored for VHDL. -# The default value is: NO. - -OPTIMIZE_OUTPUT_VHDL = NO - -# Doxygen selects the parser to use depending on the extension of the files it -# parses. With this tag you can assign which parser to use for a given -# extension. Doxygen has a built-in mapping, but you can override or extend it -# using this tag. The format is ext=language, where ext is a file extension, and -# language is one of the parsers supported by doxygen: IDL, Java, Javascript, -# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make -# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C -# (default is Fortran), use: inc=Fortran f=C. -# -# Note For files without extension you can use no_extension as a placeholder. -# -# Note that for custom extensions you also need to set FILE_PATTERNS otherwise -# the files are not read by doxygen. - -EXTENSION_MAPPING = - -# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments -# according to the Markdown format, which allows for more readable -# documentation. See http://daringfireball.net/projects/markdown/ for details. -# The output of markdown processing is further processed by doxygen, so you can -# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in -# case of backward compatibilities issues. -# The default value is: YES. - -MARKDOWN_SUPPORT = YES - -# When enabled doxygen tries to link words that correspond to documented -# classes, or namespaces to their corresponding documentation. Such a link can -# be prevented in individual cases by by putting a % sign in front of the word -# or globally by setting AUTOLINK_SUPPORT to NO. -# The default value is: YES. - -AUTOLINK_SUPPORT = YES - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want -# to include (a tag file for) the STL sources as input, then you should set this -# tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); -# versus func(std::string) {}). This also make the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. -# The default value is: NO. - -BUILTIN_STL_SUPPORT = NO - -# If you use Microsoft's C++/CLI language, you should set this option to YES to -# enable parsing support. -# The default value is: NO. - -CPP_CLI_SUPPORT = NO - -# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: -# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen -# will parse them like normal C++ but will assume all classes use public instead -# of private inheritance when no explicit protection keyword is present. -# The default value is: NO. - -SIP_SUPPORT = NO - -# For Microsoft's IDL there are propget and propput attributes to indicate -# getter and setter methods for a property. Setting this option to YES will make -# doxygen to replace the get and set methods by a property in the documentation. -# This will only work if the methods are indeed getting or setting a simple -# type. If this is not the case, or you want to show the methods anyway, you -# should set this option to NO. -# The default value is: YES. - -IDL_PROPERTY_SUPPORT = YES - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. -# The default value is: NO. - -DISTRIBUTE_GROUP_DOC = NO - -# Set the SUBGROUPING tag to YES to allow class member groups of the same type -# (for instance a group of public functions) to be put as a subgroup of that -# type (e.g. under the Public Functions section). Set it to NO to prevent -# subgrouping. Alternatively, this can be done per class using the -# \nosubgrouping command. -# The default value is: YES. - -SUBGROUPING = YES - -# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions -# are shown inside the group in which they are included (e.g. using \ingroup) -# instead of on a separate page (for HTML and Man pages) or section (for LaTeX -# and RTF). -# -# Note that this feature does not work in combination with -# SEPARATE_MEMBER_PAGES. -# The default value is: NO. - -INLINE_GROUPED_CLASSES = NO - -# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions -# with only public data fields or simple typedef fields will be shown inline in -# the documentation of the scope in which they are defined (i.e. file, -# namespace, or group documentation), provided this scope is documented. If set -# to NO, structs, classes, and unions are shown on a separate page (for HTML and -# Man pages) or section (for LaTeX and RTF). -# The default value is: NO. - -INLINE_SIMPLE_STRUCTS = NO - -# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or -# enum is documented as struct, union, or enum with the name of the typedef. So -# typedef struct TypeS {} TypeT, will appear in the documentation as a struct -# with name TypeT. When disabled the typedef will appear as a member of a file, -# namespace, or class. And the struct will be named TypeS. This can typically be -# useful for C code in case the coding convention dictates that all compound -# types are typedef'ed and only the typedef is referenced, never the tag name. -# The default value is: NO. - -TYPEDEF_HIDES_STRUCT = NO - -# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This -# cache is used to resolve symbols given their name and scope. Since this can be -# an expensive process and often the same symbol appears multiple times in the -# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small -# doxygen will become slower. If the cache is too large, memory is wasted. The -# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range -# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 -# symbols. At the end of a run doxygen will report the cache usage and suggest -# the optimal cache size from a speed point of view. -# Minimum value: 0, maximum value: 9, default value: 0. - -LOOKUP_CACHE_SIZE = 0 - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. Private -# class members and static file members will be hidden unless the -# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. -# Note: This will also disable the warnings about undocumented members that are -# normally produced when WARNINGS is set to YES. -# The default value is: NO. - -EXTRACT_ALL = NO - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will -# be included in the documentation. -# The default value is: NO. - -EXTRACT_PRIVATE = NO - -# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal -# scope will be included in the documentation. -# The default value is: NO. - -EXTRACT_PACKAGE = NO - -# If the EXTRACT_STATIC tag is set to YES all static members of a file will be -# included in the documentation. -# The default value is: NO. - -EXTRACT_STATIC = NO - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined -# locally in source files will be included in the documentation. If set to NO -# only classes defined in header files are included. Does not have any effect -# for Java sources. -# The default value is: YES. - -EXTRACT_LOCAL_CLASSES = YES - -# This flag is only useful for Objective-C code. When set to YES local methods, -# which are defined in the implementation section but not in the interface are -# included in the documentation. If set to NO only methods in the interface are -# included. -# The default value is: NO. - -EXTRACT_LOCAL_METHODS = NO - -# If this flag is set to YES, the members of anonymous namespaces will be -# extracted and appear in the documentation as a namespace called -# 'anonymous_namespace{file}', where file will be replaced with the base name of -# the file that contains the anonymous namespace. By default anonymous namespace -# are hidden. -# The default value is: NO. - -EXTRACT_ANON_NSPACES = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all -# undocumented members inside documented classes or files. If set to NO these -# members will be included in the various overviews, but no documentation -# section is generated. This option has no effect if EXTRACT_ALL is enabled. -# The default value is: NO. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. If set -# to NO these classes will be included in the various overviews. This option has -# no effect if EXTRACT_ALL is enabled. -# The default value is: NO. - -HIDE_UNDOC_CLASSES = NO - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend -# (class|struct|union) declarations. If set to NO these declarations will be -# included in the documentation. -# The default value is: NO. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any -# documentation blocks found inside the body of a function. If set to NO these -# blocks will be appended to the function's detailed documentation block. -# The default value is: NO. - -HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation that is typed after a -# \internal command is included. If the tag is set to NO then the documentation -# will be excluded. Set it to YES to include the internal documentation. -# The default value is: NO. - -INTERNAL_DOCS = NO - -# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file -# names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. -# The default value is: system dependent. - -CASE_SENSE_NAMES = YES - -# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with -# their full class and namespace scopes in the documentation. If set to YES the -# scope will be hidden. -# The default value is: NO. - -HIDE_SCOPE_NAMES = NO - -# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of -# the files that are included by a file in the documentation of that file. -# The default value is: YES. - -SHOW_INCLUDE_FILES = YES - -# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each -# grouped member an include statement to the documentation, telling the reader -# which file to include in order to use the member. -# The default value is: NO. - -SHOW_GROUPED_MEMB_INC = NO - -# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include -# files with double quotes in the documentation rather than with sharp brackets. -# The default value is: NO. - -FORCE_LOCAL_INCLUDES = NO - -# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the -# documentation for inline members. -# The default value is: YES. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the -# (detailed) documentation of file and class members alphabetically by member -# name. If set to NO the members will appear in declaration order. -# The default value is: YES. - -SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief -# descriptions of file, namespace and class members alphabetically by member -# name. If set to NO the members will appear in declaration order. Note that -# this will also influence the order of the classes in the class list. -# The default value is: NO. - -SORT_BRIEF_DOCS = NO - -# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the -# (brief and detailed) documentation of class members so that constructors and -# destructors are listed first. If set to NO the constructors will appear in the -# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. -# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief -# member documentation. -# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting -# detailed member documentation. -# The default value is: NO. - -SORT_MEMBERS_CTORS_1ST = NO - -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy -# of group names into alphabetical order. If set to NO the group names will -# appear in their defined order. -# The default value is: NO. - -SORT_GROUP_NAMES = NO - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by -# fully-qualified names, including namespaces. If set to NO, the class list will -# be sorted only by class name, not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the alphabetical -# list. -# The default value is: NO. - -SORT_BY_SCOPE_NAME = NO - -# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper -# type resolution of all parameters of a function it will reject a match between -# the prototype and the implementation of a member function even if there is -# only one candidate or it is obvious which candidate to choose by doing a -# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still -# accept a match between prototype and implementation in such cases. -# The default value is: NO. - -STRICT_PROTO_MATCHING = NO - -# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the -# todo list. This list is created by putting \todo commands in the -# documentation. -# The default value is: YES. - -GENERATE_TODOLIST = YES - -# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the -# test list. This list is created by putting \test commands in the -# documentation. -# The default value is: YES. - -GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug -# list. This list is created by putting \bug commands in the documentation. -# The default value is: YES. - -GENERATE_BUGLIST = YES - -# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) -# the deprecated list. This list is created by putting \deprecated commands in -# the documentation. -# The default value is: YES. - -GENERATE_DEPRECATEDLIST= YES - -# The ENABLED_SECTIONS tag can be used to enable conditional documentation -# sections, marked by \if ... \endif and \cond -# ... \endcond blocks. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the -# initial value of a variable or macro / define can have for it to appear in the -# documentation. If the initializer consists of more lines than specified here -# it will be hidden. Use a value of 0 to hide initializers completely. The -# appearance of the value of individual variables and macros / defines can be -# controlled using \showinitializer or \hideinitializer command in the -# documentation regardless of this setting. -# Minimum value: 0, maximum value: 10000, default value: 30. - -MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at -# the bottom of the documentation of classes and structs. If set to YES the list -# will mention the files that were used to generate the documentation. -# The default value is: YES. - -SHOW_USED_FILES = YES - -# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This -# will remove the Files entry from the Quick Index and from the Folder Tree View -# (if specified). -# The default value is: YES. - -SHOW_FILES = YES - -# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces -# page. This will remove the Namespaces entry from the Quick Index and from the -# Folder Tree View (if specified). -# The default value is: YES. - -SHOW_NAMESPACES = YES - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from -# the version control system). Doxygen will invoke the program by executing (via -# popen()) the command command input-file, where command is the value of the -# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided -# by doxygen. Whatever the program writes to standard output is used as the file -# version. For an example see the documentation. - -FILE_VERSION_FILTER = - -# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed -# by doxygen. The layout file controls the global structure of the generated -# output files in an output format independent way. To create the layout file -# that represents doxygen's defaults, run doxygen with the -l option. You can -# optionally specify a file name after the option, if omitted DoxygenLayout.xml -# will be used as the name of the layout file. -# -# Note that if you run doxygen from a directory containing a file called -# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE -# tag is left empty. - -LAYOUT_FILE = - -# The CITE_BIB_FILES tag can be used to specify one or more bib files containing -# the reference definitions. This must be a list of .bib files. The .bib -# extension is automatically appended if omitted. This requires the bibtex tool -# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. -# For LaTeX the style of the bibliography can be controlled using -# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the -# search path. Do not use file names with spaces, bibtex cannot handle them. See -# also \cite for info how to create references. - -CITE_BIB_FILES = - -#--------------------------------------------------------------------------- -# Configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated to -# standard output by doxygen. If QUIET is set to YES this implies that the -# messages are off. -# The default value is: NO. - -QUIET = NO - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES -# this implies that the warnings are on. -# -# Tip: Turn warnings on while writing the documentation. -# The default value is: YES. - -WARNINGS = YES - -# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate -# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag -# will automatically be disabled. -# The default value is: YES. - -WARN_IF_UNDOCUMENTED = YES - -# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some parameters -# in a documented function, or documenting parameters that don't exist or using -# markup commands wrongly. -# The default value is: YES. - -WARN_IF_DOC_ERROR = YES - -# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that -# are documented, but have no documentation for their parameters or return -# value. If set to NO doxygen will only warn about wrong or incomplete parameter -# documentation, but not about the absence of documentation. -# The default value is: NO. - -WARN_NO_PARAMDOC = NO - -# The WARN_FORMAT tag determines the format of the warning messages that doxygen -# can produce. The string should contain the $file, $line, and $text tags, which -# will be replaced by the file and line number from which the warning originated -# and the warning text. Optionally the format may contain $version, which will -# be replaced by the version of the file (if it could be obtained via -# FILE_VERSION_FILTER) -# The default value is: $file:$line: $text. - -WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning and error -# messages should be written. If left blank the output is written to standard -# error (stderr). - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# Configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag is used to specify the files and/or directories that contain -# documented source files. You may enter file names like myfile.cpp or -# directories like /usr/src/myproject. Separate the files or directories with -# spaces. -# Note: If this tag is empty the current directory is searched. - -INPUT = . ../include - -# This tag can be used to specify the character encoding of the source files -# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses -# libiconv (or the iconv built into libc) for the transcoding. See the libiconv -# documentation (see: http://www.gnu.org/software/libiconv) for the list of -# possible encodings. -# The default value is: UTF-8. - -INPUT_ENCODING = UTF-8 - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and -# *.h) to filter out the source-files in the directories. If left blank the -# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, -# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, -# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, -# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, -# *.qsf, *.as and *.js. - -FILE_PATTERNS = - -# The RECURSIVE tag can be used to specify whether or not subdirectories should -# be searched for input files as well. -# The default value is: NO. - -RECURSIVE = NO - -# The EXCLUDE tag can be used to specify files and/or directories that should be -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. -# -# Note that relative paths are relative to the directory from which doxygen is -# run. - -EXCLUDE = - -# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or -# directories that are symbolic links (a Unix file system feature) are excluded -# from the input. -# The default value is: NO. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. -# -# Note that the wildcards are matched against the file with absolute path, so to -# exclude all test directories for example use the pattern */test/* - -EXCLUDE_PATTERNS = ctrlm_dox_ipc.h \ - ctrlm_dox_ipc_rcu.h \ - ctrlm_dox_ipc_voice.h \ - ctrlm_dox_ipc_device_update.h \ - ctrlm_dox_hal.h \ - ctrlm_dox_hal_rf4ce.h \ - ctrlm_dox_hal_ip.h \ - ctrlm_dox_hal_btle.h - -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the -# output. The symbol name can be a fully qualified name, a word, or if the -# wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test -# -# Note that the wildcards are matched against the file with absolute path, so to -# exclude all test directories use the pattern */test/* - -EXCLUDE_SYMBOLS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or directories -# that contain example code fragments that are included (see the \include -# command). - -EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and -# *.h) to filter out the source-files in the directories. If left blank all -# files are included. - -EXAMPLE_PATTERNS = - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude commands -# irrespective of the value of the RECURSIVE tag. -# The default value is: NO. - -EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or directories -# that contain images that are to be included in the documentation (see the -# \image command). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command: -# -# -# -# where is the value of the INPUT_FILTER tag, and is the -# name of an input file. Doxygen will then use the output that the filter -# program writes to standard output. If FILTER_PATTERNS is specified, this tag -# will be ignored. -# -# Note that the filter must not add or remove lines; it is applied before the -# code is scanned, but not when the output code is generated. If lines are added -# or removed, the anchors will not be placed correctly. - -INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. The filters are a list of the form: pattern=filter -# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how -# filters are used. If the FILTER_PATTERNS tag is empty or if none of the -# patterns match the file name, INPUT_FILTER is applied. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER ) will also be used to filter the input files that are used for -# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). -# The default value is: NO. - -FILTER_SOURCE_FILES = NO - -# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file -# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and -# it is also possible to disable source filtering for a specific pattern using -# *.ext= (so without naming a filter). -# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. - -FILTER_SOURCE_PATTERNS = - -# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that -# is part of the input, its contents will be placed on the main page -# (index.html). This can be useful if you have a project on for instance GitHub -# and want to reuse the introduction page also for the doxygen output. - -USE_MDFILE_AS_MAINPAGE = - -#--------------------------------------------------------------------------- -# Configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will be -# generated. Documented entities will be cross-referenced with these sources. -# -# Note: To get rid of all source code in the generated output, make sure that -# also VERBATIM_HEADERS is set to NO. -# The default value is: NO. - -SOURCE_BROWSER = NO - -# Setting the INLINE_SOURCES tag to YES will include the body of functions, -# classes and enums directly into the documentation. -# The default value is: NO. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any -# special comment blocks from generated source code fragments. Normal C, C++ and -# Fortran comments will always remain visible. -# The default value is: YES. - -STRIP_CODE_COMMENTS = YES - -# If the REFERENCED_BY_RELATION tag is set to YES then for each documented -# function all documented functions referencing it will be listed. -# The default value is: NO. - -REFERENCED_BY_RELATION = NO - -# If the REFERENCES_RELATION tag is set to YES then for each documented function -# all documented entities called/used by that function will be listed. -# The default value is: NO. - -REFERENCES_RELATION = NO - -# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set -# to YES, then the hyperlinks from functions in REFERENCES_RELATION and -# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will -# link to the documentation. -# The default value is: YES. - -REFERENCES_LINK_SOURCE = YES - -# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the -# source code will show a tooltip with additional information such as prototype, -# brief description and links to the definition and documentation. Since this -# will make the HTML file larger and loading of large files a bit slower, you -# can opt to disable this feature. -# The default value is: YES. -# This tag requires that the tag SOURCE_BROWSER is set to YES. - -SOURCE_TOOLTIPS = YES - -# If the USE_HTAGS tag is set to YES then the references to source code will -# point to the HTML generated by the htags(1) tool instead of doxygen built-in -# source browser. The htags tool is part of GNU's global source tagging system -# (see http://www.gnu.org/software/global/global.html). You will need version -# 4.8.6 or higher. -# -# To use it do the following: -# - Install the latest version of global -# - Enable SOURCE_BROWSER and USE_HTAGS in the config file -# - Make sure the INPUT points to the root of the source tree -# - Run doxygen as normal -# -# Doxygen will invoke htags (and that will in turn invoke gtags), so these -# tools must be available from the command line (i.e. in the search path). -# -# The result: instead of the source browser generated by doxygen, the links to -# source code will now point to the output of htags. -# The default value is: NO. -# This tag requires that the tag SOURCE_BROWSER is set to YES. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a -# verbatim copy of the header file for each class for which an include is -# specified. Set to NO to disable this. -# See also: Section \class. -# The default value is: YES. - -VERBATIM_HEADERS = YES - -#--------------------------------------------------------------------------- -# Configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all -# compounds will be generated. Enable this if the project contains a lot of -# classes, structs, unions or interfaces. -# The default value is: YES. - -ALPHABETICAL_INDEX = YES - -# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in -# which the alphabetical index list will be split. -# Minimum value: 1, maximum value: 20, default value: 5. -# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. - -COLS_IN_ALPHA_INDEX = 5 - -# In case all classes in a project start with a common prefix, all classes will -# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag -# can be used to specify a prefix (or a list of prefixes) that should be ignored -# while generating the index headers. -# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output -# The default value is: YES. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a -# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of -# it. -# The default directory is: html. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_OUTPUT = html - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each -# generated HTML page (for example: .htm, .php, .asp). -# The default value is: .html. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a user-defined HTML header file for -# each generated HTML page. If the tag is left blank doxygen will generate a -# standard header. -# -# To get valid HTML the header file that includes any scripts and style sheets -# that doxygen needs, which is dependent on the configuration options used (e.g. -# the setting GENERATE_TREEVIEW). It is highly recommended to start with a -# default header using -# doxygen -w html new_header.html new_footer.html new_stylesheet.css -# YourConfigFile -# and then modify the file new_header.html. See also section "Doxygen usage" -# for information on how to generate the default header that doxygen normally -# uses. -# Note: The header is subject to change so you typically have to regenerate the -# default header when upgrading to a newer version of doxygen. For a description -# of the possible markers and block names see the documentation. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each -# generated HTML page. If the tag is left blank doxygen will generate a standard -# footer. See HTML_HEADER for more information on how to generate a default -# footer and what special commands can be used inside the footer. See also -# section "Doxygen usage" for information on how to generate the default footer -# that doxygen normally uses. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style -# sheet that is used by each HTML page. It can be used to fine-tune the look of -# the HTML output. If left blank doxygen will generate a default style sheet. -# See also section "Doxygen usage" for information on how to generate the style -# sheet that doxygen normally uses. -# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as -# it is more robust and this tag (HTML_STYLESHEET) will in the future become -# obsolete. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_STYLESHEET = - -# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user- -# defined cascading style sheet that is included after the standard style sheets -# created by doxygen. Using this option one can overrule certain style aspects. -# This is preferred over using HTML_STYLESHEET since it does not replace the -# standard style sheet and is therefor more robust against future updates. -# Doxygen will copy the style sheet file to the output directory. For an example -# see the documentation. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_EXTRA_STYLESHEET = - -# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or -# other source files which should be copied to the HTML output directory. Note -# that these files will be copied to the base HTML output directory. Use the -# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these -# files. In the HTML_STYLESHEET file, use the file name only. Also note that the -# files will be copied as-is; there are no commands or markers available. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_EXTRA_FILES = - -# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen -# will adjust the colors in the stylesheet and background images according to -# this color. Hue is specified as an angle on a colorwheel, see -# http://en.wikipedia.org/wiki/Hue for more information. For instance the value -# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 -# purple, and 360 is red again. -# Minimum value: 0, maximum value: 359, default value: 220. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_COLORSTYLE_HUE = 220 - -# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors -# in the HTML output. For a value of 0 the output will use grayscales only. A -# value of 255 will produce the most vivid colors. -# Minimum value: 0, maximum value: 255, default value: 100. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_COLORSTYLE_SAT = 100 - -# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the -# luminance component of the colors in the HTML output. Values below 100 -# gradually make the output lighter, whereas values above 100 make the output -# darker. The value divided by 100 is the actual gamma applied, so 80 represents -# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not -# change the gamma. -# Minimum value: 40, maximum value: 240, default value: 80. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_COLORSTYLE_GAMMA = 80 - -# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting this -# to NO can help when comparing the output of multiple runs. -# The default value is: YES. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_TIMESTAMP = YES - -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_DYNAMIC_SECTIONS = NO - -# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries -# shown in the various tree structured indices initially; the user can expand -# and collapse entries dynamically later on. Doxygen will expand the tree to -# such a level that at most the specified number of entries are visible (unless -# a fully collapsed tree already exceeds this amount). So setting the number of -# entries 1 will produce a full collapsed tree by default. 0 is a special value -# representing an infinite number of entries and will result in a full expanded -# tree by default. -# Minimum value: 0, maximum value: 9999, default value: 100. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_INDEX_NUM_ENTRIES = 100 - -# If the GENERATE_DOCSET tag is set to YES, additional index files will be -# generated that can be used as input for Apple's Xcode 3 integrated development -# environment (see: http://developer.apple.com/tools/xcode/), introduced with -# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a -# Makefile in the HTML output directory. Running make will produce the docset in -# that directory and running make install will install the docset in -# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at -# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html -# for more information. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_DOCSET = NO - -# This tag determines the name of the docset feed. A documentation feed provides -# an umbrella under which multiple documentation sets from a single provider -# (such as a company or product suite) can be grouped. -# The default value is: Doxygen generated docs. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_FEEDNAME = "Doxygen generated docs" - -# This tag specifies a string that should uniquely identify the documentation -# set bundle. This should be a reverse domain-name style string, e.g. -# com.mycompany.MyDocSet. Doxygen will append .docset to the name. -# The default value is: org.doxygen.Project. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_BUNDLE_ID = org.doxygen.Project - -# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify -# the documentation publisher. This should be a reverse domain-name style -# string, e.g. com.mycompany.MyDocSet.documentation. -# The default value is: org.doxygen.Publisher. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_PUBLISHER_ID = org.doxygen.Publisher - -# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. -# The default value is: Publisher. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_PUBLISHER_NAME = Publisher - -# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three -# additional HTML index files: index.hhp, index.hhc, and index.hhk. The -# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on -# Windows. -# -# The HTML Help Workshop contains a compiler that can convert all HTML output -# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML -# files are now used as the Windows 98 help format, and will replace the old -# Windows help format (.hlp) on all Windows platforms in the future. Compressed -# HTML files also contain an index, a table of contents, and you can search for -# words in the documentation. The HTML workshop also contains a viewer for -# compressed HTML files. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_HTMLHELP = NO - -# The CHM_FILE tag can be used to specify the file name of the resulting .chm -# file. You can add a path in front of the file if the result should not be -# written to the html output directory. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -CHM_FILE = - -# The HHC_LOCATION tag can be used to specify the location (absolute path -# including file name) of the HTML help compiler ( hhc.exe). If non-empty -# doxygen will try to run the HTML help compiler on the generated index.hhp. -# The file has to be specified with full path. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -HHC_LOCATION = - -# The GENERATE_CHI flag controls if a separate .chi index file is generated ( -# YES) or that it should be included in the master .chm file ( NO). -# The default value is: NO. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -GENERATE_CHI = NO - -# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) -# and project file content. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -CHM_INDEX_ENCODING = - -# The BINARY_TOC flag controls whether a binary table of contents is generated ( -# YES) or a normal table of contents ( NO) in the .chm file. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members to -# the table of contents of the HTML help documentation and to the tree view. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -TOC_EXPAND = NO - -# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and -# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that -# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help -# (.qch) of the generated HTML documentation. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_QHP = NO - -# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify -# the file name of the resulting .qch file. The path specified is relative to -# the HTML output folder. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QCH_FILE = - -# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help -# Project output. For more information please see Qt Help Project / Namespace -# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). -# The default value is: org.doxygen.Project. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_NAMESPACE = org.doxygen.Project - -# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt -# Help Project output. For more information please see Qt Help Project / Virtual -# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- -# folders). -# The default value is: doc. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_VIRTUAL_FOLDER = doc - -# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom -# filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- -# filters). -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_CUST_FILTER_NAME = - -# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the -# custom filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- -# filters). -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_CUST_FILTER_ATTRS = - -# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this -# project's filter section matches. Qt Help Project / Filter Attributes (see: -# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_SECT_FILTER_ATTRS = - -# The QHG_LOCATION tag can be used to specify the location of Qt's -# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the -# generated .qhp file. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHG_LOCATION = - -# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be -# generated, together with the HTML files, they form an Eclipse help plugin. To -# install this plugin and make it available under the help contents menu in -# Eclipse, the contents of the directory containing the HTML and XML files needs -# to be copied into the plugins directory of eclipse. The name of the directory -# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. -# After copying Eclipse needs to be restarted before the help appears. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_ECLIPSEHELP = NO - -# A unique identifier for the Eclipse help plugin. When installing the plugin -# the directory name containing the HTML and XML files should also have this -# name. Each documentation set should have its own identifier. -# The default value is: org.doxygen.Project. -# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. - -ECLIPSE_DOC_ID = org.doxygen.Project - -# If you want full control over the layout of the generated HTML pages it might -# be necessary to disable the index and replace it with your own. The -# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top -# of each HTML page. A value of NO enables the index and the value YES disables -# it. Since the tabs in the index contain the same information as the navigation -# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -DISABLE_INDEX = NO - -# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index -# structure should be generated to display hierarchical information. If the tag -# value is set to YES, a side panel will be generated containing a tree-like -# index structure (just like the one that is generated for HTML Help). For this -# to work a browser that supports JavaScript, DHTML, CSS and frames is required -# (i.e. any modern browser). Windows users are probably better off using the -# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can -# further fine-tune the look of the index. As an example, the default style -# sheet generated by doxygen has an example that shows how to put an image at -# the root of the tree instead of the PROJECT_NAME. Since the tree basically has -# the same information as the tab index, you could consider setting -# DISABLE_INDEX to YES when enabling this option. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_TREEVIEW = NO - -# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that -# doxygen will group on one line in the generated HTML documentation. -# -# Note that a value of 0 will completely suppress the enum values from appearing -# in the overview section. -# Minimum value: 0, maximum value: 20, default value: 4. -# This tag requires that the tag GENERATE_HTML is set to YES. - -ENUM_VALUES_PER_LINE = 1 - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used -# to set the initial width (in pixels) of the frame in which the tree is shown. -# Minimum value: 0, maximum value: 1500, default value: 250. -# This tag requires that the tag GENERATE_HTML is set to YES. - -TREEVIEW_WIDTH = 250 - -# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to -# external symbols imported via tag files in a separate window. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -EXT_LINKS_IN_WINDOW = NO - -# Use this tag to change the font size of LaTeX formulas included as images in -# the HTML documentation. When you change the font size after a successful -# doxygen run you need to manually remove any form_*.png images from the HTML -# output directory to force them to be regenerated. -# Minimum value: 8, maximum value: 50, default value: 10. -# This tag requires that the tag GENERATE_HTML is set to YES. - -FORMULA_FONTSIZE = 10 - -# Use the FORMULA_TRANPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are not -# supported properly for IE 6.0, but are supported on all modern browsers. -# -# Note that when changing this option you need to delete any form_*.png files in -# the HTML output directory before the changes have effect. -# The default value is: YES. -# This tag requires that the tag GENERATE_HTML is set to YES. - -FORMULA_TRANSPARENT = YES - -# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see -# http://www.mathjax.org) which uses client side Javascript for the rendering -# instead of using prerendered bitmaps. Use this if you do not have LaTeX -# installed or if you want to formulas look prettier in the HTML output. When -# enabled you may also need to install MathJax separately and configure the path -# to it using the MATHJAX_RELPATH option. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -USE_MATHJAX = NO - -# When MathJax is enabled you can set the default output format to be used for -# the MathJax output. See the MathJax site (see: -# http://docs.mathjax.org/en/latest/output.html) for more details. -# Possible values are: HTML-CSS (which is slower, but has the best -# compatibility), NativeMML (i.e. MathML) and SVG. -# The default value is: HTML-CSS. -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_FORMAT = HTML-CSS - -# When MathJax is enabled you need to specify the location relative to the HTML -# output directory using the MATHJAX_RELPATH option. The destination directory -# should contain the MathJax.js script. For instance, if the mathjax directory -# is located at the same level as the HTML output directory, then -# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax -# Content Delivery Network so you can quickly see the result without installing -# MathJax. However, it is strongly recommended to install a local copy of -# MathJax from http://www.mathjax.org before deployment. -# The default value is: http://cdn.mathjax.org/mathjax/latest. -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest - -# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax -# extension names that should be enabled during MathJax rendering. For example -# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_EXTENSIONS = - -# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces -# of code that will be used on startup of the MathJax code. See the MathJax site -# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an -# example see the documentation. -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_CODEFILE = - -# When the SEARCHENGINE tag is enabled doxygen will generate a search box for -# the HTML output. The underlying search engine uses javascript and DHTML and -# should work on any modern browser. Note that when using HTML help -# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) -# there is already a search function so this one should typically be disabled. -# For large projects the javascript based search engine can be slow, then -# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to -# search using the keyboard; to jump to the search box use + S -# (what the is depends on the OS and browser, but it is typically -# , /