From 8daace1a7dec6e7c78ae31a1eac96586648a5d8f Mon Sep 17 00:00:00 2001 From: Nate Gay Date: Wed, 26 Nov 2025 22:23:42 -0600 Subject: [PATCH 1/9] Add faces to device tree --- .../proves_flight_control_board_v5.dtsi | 241 ++++++++++++++++++ ...ht_control_board_v5c_rp2350a_m33_defconfig | 3 + ...ht_control_board_v5d_rp2350a_m33_defconfig | 3 + prj.conf | 12 +- 4 files changed, 258 insertions(+), 1 deletion(-) diff --git a/boards/bronco_space/proves_flight_control_board_v5/proves_flight_control_board_v5.dtsi b/boards/bronco_space/proves_flight_control_board_v5/proves_flight_control_board_v5.dtsi index 78eb6a54..d8d39c61 100644 --- a/boards/bronco_space/proves_flight_control_board_v5/proves_flight_control_board_v5.dtsi +++ b/boards/bronco_space/proves_flight_control_board_v5/proves_flight_control_board_v5.dtsi @@ -136,6 +136,247 @@ zephyr_udc0: &usbd { lsb-microamp = <61>; label = "INA219 sol"; }; + + tca9548a: tca9548a@77 { + compatible = "ti,tca9548a"; + status = "okay"; + reg = <0x77>; + #address-cells = <1>; + #size-cells = <0>; + label = "TCA9548A"; + reset-gpios = <&gpio0 26 GPIO_ACTIVE_LOW>; + + mux_channel_0: i2c_mux@0 { + compatible = "ti,tca9548a-channel"; + label = "mux_channel_0"; + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + face0_temp_sens: tmp112@48 { + compatible = "ti,tmp112"; + reg = <0x48>; + status = "okay"; + label = "FACE0_TMP112"; + zephyr,deferred-init; + }; + + face0_light_sens: light@29 { + compatible = "vishay,veml6031"; + reg = <0x29>; + status = "okay"; + label = "FACE0_VEML6031"; + zephyr,deferred-init; + }; + + face0_drv2605: drv2605@5a { + compatible = "ti,drv2605"; + status = "okay"; + reg = <0x5a>; + label = "FACE0_DRV2605"; + zephyr,deferred-init; + + actuator-mode = "LRA"; + loop-gain = "HIGH"; + feedback-brake-factor = "2X"; + }; + + }; + + mux_channel_1: i2c_mux@1 { + compatible = "ti,tca9548a-channel"; + label = "mux_channel_1"; + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + face1_temp_sens: tmp112@48 { + compatible = "ti,tmp112"; + reg = <0x48>; + status = "okay"; + label = "FACE1_TMP112"; + zephyr,deferred-init; + }; + + face1_light_sens: light@29 { + compatible = "vishay,veml6031"; + reg = <0x29>; + status = "okay"; + label = "FACE1_VEML6031"; + zephyr,deferred-init; + }; + + face1_drv2605: drv2605@5a { + compatible = "ti,drv2605"; + status = "okay"; + reg = <0x5a>; + label = "FACE1_DRV2605"; + zephyr,deferred-init; + + actuator-mode = "LRA"; + loop-gain = "HIGH"; + feedback-brake-factor = "2X"; + }; + + }; + + mux_channel_2: i2c_mux@2 { + compatible = "ti,tca9548a-channel"; + label = "mux_channel_2"; + reg = <2>; + #address-cells = <1>; + #size-cells = <0>; + + face2_temp_sens: tmp112@48 { + compatible = "ti,tmp112"; + reg = <0x48>; + status = "okay"; + label = "FACE2_TMP112"; + zephyr,deferred-init; + }; + + face2_light_sens: light@29 { + compatible = "vishay,veml6031"; + reg = <0x29>; + status = "okay"; + label = "FACE2_VEML6031"; + zephyr,deferred-init; + }; + + face2_drv2605: drv2605@5a { + compatible = "ti,drv2605"; + status = "okay"; + reg = <0x5a>; + label = "FACE2_DRV2605"; + zephyr,deferred-init; + + actuator-mode = "LRA"; + loop-gain = "HIGH"; + feedback-brake-factor = "2X"; + }; + + }; + + mux_channel_3: i2c_mux@3 { + compatible = "ti,tca9548a-channel"; + label = "mux_channel_3"; + reg = <3>; + #address-cells = <1>; + #size-cells = <0>; + + face3_temp_sens: tmp112@48 { + compatible = "ti,tmp112"; + reg = <0x48>; + status = "okay"; + label = "FACE3_TMP112"; + zephyr,deferred-init; + }; + + face3_light_sens: light@29 { + compatible = "vishay,veml6031"; + reg = <0x29>; + status = "okay"; + label = "FACE3_VEML6031"; + zephyr,deferred-init; + }; + + face3_drv2605: drv2605@5a { + compatible = "ti,drv2605"; + status = "okay"; + reg = <0x5a>; + label = "FACE3_DRV2605"; + zephyr,deferred-init; + + actuator-mode = "LRA"; + loop-gain = "HIGH"; + feedback-brake-factor = "2X"; + }; + + }; + + // Battery + mux_channel_4: i2c_mux@4 { + compatible = "ti,tca9548a-channel"; + label = "mux_channel_4"; + reg = <7>; + #address-cells = <1>; + #size-cells = <0>; + batt_cell1_temp_sens: tmp112@48 { + compatible = "ti,tmp112"; + reg = <0x48>; + status = "okay"; + }; + batt_cell2_temp_sens: tmp112@49 { + compatible = "ti,tmp112"; + reg = <0x49>; + status = "okay"; + }; + batt_cell3_temp_sens: tmp112@4a { + compatible = "ti,tmp112"; + reg = <0x4a>; + status = "okay"; + }; + batt_cell4_temp_sens: tmp112@4b { + compatible = "ti,tmp112"; + reg = <0x4b>; + status = "okay"; + }; + }; + + // Z- Face + mux_channel_5: i2c_mux@5 { + compatible = "ti,tca9548a-channel"; + label = "mux_channel_5"; + reg = <4>; + #address-cells = <1>; + #size-cells = <0>; + + face5_temp_sens: tmp112@48 { + compatible = "ti,tmp112"; + reg = <0x48>; + status = "okay"; + label = "FACE5_TMP112"; + zephyr,deferred-init; + }; + + face5_light_sens: light@29 { + compatible = "vishay,veml6031"; + reg = <0x29>; + status = "okay"; + label = "FACE5_VEML6031"; + zephyr,deferred-init; + }; + + face5_drv2605: drv2605@5a { + compatible = "ti,drv2605"; + status = "okay"; + reg = <0x5a>; + label = "FACE5_DRV2605"; + zephyr,deferred-init; + + actuator-mode = "LRA"; + loop-gain = "HIGH"; + feedback-brake-factor = "2X"; + }; + + }; + + // Top is always powered so no deferred init needed + mux_channel_7: i2c_mux@7 { + compatible = "ti,tca9548a-channel"; + label = "mux_channel_7"; + reg = <7>; + #address-cells = <1>; + #size-cells = <0>; + // TODO add top cap temp sensor (it's not a TMP112) + face7_light_sens: light@29 { + compatible = "vishay,veml6031"; + reg = <0x29>; + status = "okay"; + label = "FACE7_VEML6031"; + }; + }; + }; }; diff --git a/boards/bronco_space/proves_flight_control_board_v5c/proves_flight_control_board_v5c_rp2350a_m33_defconfig b/boards/bronco_space/proves_flight_control_board_v5c/proves_flight_control_board_v5c_rp2350a_m33_defconfig index 176cb4e4..2b429e95 100644 --- a/boards/bronco_space/proves_flight_control_board_v5c/proves_flight_control_board_v5c_rp2350a_m33_defconfig +++ b/boards/bronco_space/proves_flight_control_board_v5c/proves_flight_control_board_v5c_rp2350a_m33_defconfig @@ -18,11 +18,14 @@ CONFIG_CDC_ACM_SERIAL_PID=0x000F CONFIG_CDC_ACM_SERIAL_VID=0x0028 CONFIG_CDC_ACM_SERIAL_PRODUCT_STRING="PROVES Flight Control Board v5c" +CONFIG_I2C_TCA954X=y + # Sensors CONFIG_LSM6DSO=y CONFIG_LSM6DSO_ENABLE_TEMP=y CONFIG_LIS2MDL=y CONFIG_INA219=y +CONFIG_TMP112=y # Radio CONFIG_LORA=y diff --git a/boards/bronco_space/proves_flight_control_board_v5d/proves_flight_control_board_v5d_rp2350a_m33_defconfig b/boards/bronco_space/proves_flight_control_board_v5d/proves_flight_control_board_v5d_rp2350a_m33_defconfig index 12f07e11..818e1062 100644 --- a/boards/bronco_space/proves_flight_control_board_v5d/proves_flight_control_board_v5d_rp2350a_m33_defconfig +++ b/boards/bronco_space/proves_flight_control_board_v5d/proves_flight_control_board_v5d_rp2350a_m33_defconfig @@ -18,11 +18,14 @@ CONFIG_CDC_ACM_SERIAL_PID=0x000F CONFIG_CDC_ACM_SERIAL_VID=0x0028 CONFIG_CDC_ACM_SERIAL_PRODUCT_STRING="PROVES Flight Control Board v5d" +CONFIG_I2C_TCA954X=y + # Sensors CONFIG_LSM6DSO=y CONFIG_LSM6DSO_ENABLE_TEMP=y CONFIG_LIS2MDL=y CONFIG_INA219=y +CONFIG_TMP112=y # Radio CONFIG_LORA=y diff --git a/prj.conf b/prj.conf index 1829a68f..9c463cec 100644 --- a/prj.conf +++ b/prj.conf @@ -28,6 +28,13 @@ CONFIG_SPI=y CONFIG_PINCTRL=y CONFIG_ASSERT=y +#### I2C Multiplexer Configuration #### +CONFIG_I2C_TCA954X=y +# Priority order: I2C Bus (16) < GPIO (11) < Mux Root (70) < Mux Channels (71) < Load Switches (75) < Sensors (90) +# Mux must initialize AFTER I2C bus (16) and GPIO (11) but BEFORE sensors (90) +CONFIG_I2C_TCA954X_ROOT_INIT_PRIO=70 +CONFIG_I2C_TCA954X_CHANNEL_INIT_PRIO=71 + CONFIG_DYNAMIC_THREAD=y CONFIG_KERNEL_MEM_POOL=y CONFIG_DYNAMIC_THREAD_ALLOC=n @@ -46,8 +53,11 @@ CONFIG_COMMON_LIBC_MALLOC=y CONFIG_SENSOR=y -CONFIG_LOG=n +# Enable detailed logging for I2C and sensor debugging +CONFIG_LOG=y CONFIG_LOG_DEFAULT_LEVEL=3 +CONFIG_I2C_LOG_LEVEL_DBG=y +CONFIG_SENSOR_LOG_LEVEL_DBG=y CONFIG_CBPRINTF_FP_SUPPORT=y From fd98e597cf5d871028a1be1abd1499f546d67b24 Mon Sep 17 00:00:00 2001 From: Nate Gay Date: Thu, 27 Nov 2025 21:40:14 -0600 Subject: [PATCH 2/9] Update boards/bronco_space/proves_flight_control_board_v5c/proves_flight_control_board_v5c_rp2350a_m33_defconfig Co-authored-by: Michael Pham <61564344+Mikefly123@users.noreply.github.com> --- .../proves_flight_control_board_v5c_rp2350a_m33_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/boards/bronco_space/proves_flight_control_board_v5c/proves_flight_control_board_v5c_rp2350a_m33_defconfig b/boards/bronco_space/proves_flight_control_board_v5c/proves_flight_control_board_v5c_rp2350a_m33_defconfig index 2b429e95..7a5b0c34 100644 --- a/boards/bronco_space/proves_flight_control_board_v5c/proves_flight_control_board_v5c_rp2350a_m33_defconfig +++ b/boards/bronco_space/proves_flight_control_board_v5c/proves_flight_control_board_v5c_rp2350a_m33_defconfig @@ -26,6 +26,7 @@ CONFIG_LSM6DSO_ENABLE_TEMP=y CONFIG_LIS2MDL=y CONFIG_INA219=y CONFIG_TMP112=y +CONFIG_VEML6031=y # Radio CONFIG_LORA=y From d918a4837bd5aa9faeae7deda0e5692baa8f34a1 Mon Sep 17 00:00:00 2001 From: Nate Gay Date: Thu, 27 Nov 2025 21:40:19 -0600 Subject: [PATCH 3/9] Update boards/bronco_space/proves_flight_control_board_v5d/proves_flight_control_board_v5d_rp2350a_m33_defconfig Co-authored-by: Michael Pham <61564344+Mikefly123@users.noreply.github.com> --- .../proves_flight_control_board_v5d_rp2350a_m33_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/boards/bronco_space/proves_flight_control_board_v5d/proves_flight_control_board_v5d_rp2350a_m33_defconfig b/boards/bronco_space/proves_flight_control_board_v5d/proves_flight_control_board_v5d_rp2350a_m33_defconfig index 818e1062..daaf56bd 100644 --- a/boards/bronco_space/proves_flight_control_board_v5d/proves_flight_control_board_v5d_rp2350a_m33_defconfig +++ b/boards/bronco_space/proves_flight_control_board_v5d/proves_flight_control_board_v5d_rp2350a_m33_defconfig @@ -26,6 +26,7 @@ CONFIG_LSM6DSO_ENABLE_TEMP=y CONFIG_LIS2MDL=y CONFIG_INA219=y CONFIG_TMP112=y +CONFIG_VEML6031=y # Radio CONFIG_LORA=y From c6aa4d6b32dd88401088f79192314ba0ae7e13fc Mon Sep 17 00:00:00 2001 From: Michael Pham <61564344+Mikefly123@users.noreply.github.com> Date: Fri, 28 Nov 2025 22:00:33 -0800 Subject: [PATCH 4/9] Updated dtsi to Match Temp-Sensor Branch --- .../proves_flight_control_board_v5.dtsi | 44 +++++++++++++++++-- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/boards/bronco_space/proves_flight_control_board_v5/proves_flight_control_board_v5.dtsi b/boards/bronco_space/proves_flight_control_board_v5/proves_flight_control_board_v5.dtsi index d8d39c61..cb5bbdad 100644 --- a/boards/bronco_space/proves_flight_control_board_v5/proves_flight_control_board_v5.dtsi +++ b/boards/bronco_space/proves_flight_control_board_v5/proves_flight_control_board_v5.dtsi @@ -298,7 +298,7 @@ zephyr_udc0: &usbd { mux_channel_4: i2c_mux@4 { compatible = "ti,tca9548a-channel"; label = "mux_channel_4"; - reg = <7>; + reg = <4>; #address-cells = <1>; #size-cells = <0>; batt_cell1_temp_sens: tmp112@48 { @@ -323,11 +323,11 @@ zephyr_udc0: &usbd { }; }; - // Z- Face + // Z- Face x1 mux_channel_5: i2c_mux@5 { compatible = "ti,tca9548a-channel"; label = "mux_channel_5"; - reg = <4>; + reg = <5>; #address-cells = <1>; #size-cells = <0>; @@ -361,6 +361,44 @@ zephyr_udc0: &usbd { }; + // Z- Face x2 + mux_channel_6: i2c_mux@6 { + compatible = "ti,tca9548a-channel"; + label = "mux_channel_6"; + reg = <6>; + #address-cells = <1>; + #size-cells = <0>; + + face6_temp_sens: tmp112@48 { + compatible = "ti,tmp112"; + reg = <0x48>; + status = "okay"; + label = "FACE5_TMP112"; + zephyr,deferred-init; + }; + + face6_light_sens: light@29 { + compatible = "vishay,veml6031"; + reg = <0x29>; + status = "okay"; + label = "FACE5_VEML6031"; + zephyr,deferred-init; + }; + + face6_drv2605: drv2605@5a { + compatible = "ti,drv2605"; + status = "okay"; + reg = <0x5a>; + label = "FACE5_DRV2605"; + zephyr,deferred-init; + + actuator-mode = "LRA"; + loop-gain = "HIGH"; + feedback-brake-factor = "2X"; + }; + + }; + // Top is always powered so no deferred init needed mux_channel_7: i2c_mux@7 { compatible = "ti,tca9548a-channel"; From 622202d6a065106e665123cf3f95c5718946beb2 Mon Sep 17 00:00:00 2001 From: Nate Gay Date: Sat, 29 Nov 2025 14:13:02 -0600 Subject: [PATCH 5/9] Update face definitions --- .../proves_flight_control_board_v5.dtsi | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/boards/bronco_space/proves_flight_control_board_v5/proves_flight_control_board_v5.dtsi b/boards/bronco_space/proves_flight_control_board_v5/proves_flight_control_board_v5.dtsi index cb5bbdad..4a3b310a 100644 --- a/boards/bronco_space/proves_flight_control_board_v5/proves_flight_control_board_v5.dtsi +++ b/boards/bronco_space/proves_flight_control_board_v5/proves_flight_control_board_v5.dtsi @@ -466,19 +466,19 @@ zephyr_udc0: &usbd { * 5: RF2_IO1 (GPA5) * 6: RF2_IO0 (GPA6) * 7: RF2_IO3 (GPA7) - * 8: FACE4_ENABLE (GPB0) + * 8: FACE5_ENABLE (GPB5) * 9: FACE0_ENABLE (GPB1) * 10: FACE1_ENABLE (GPB2) * 11: FACE2_ENABLE (GPB3) * 12: FACE3_ENABLE (GPB4) - * 13: FACE5_ENABLE (GPB5) + * 13: FACE4_ENABLE (GPB0) * 14: READONLY (GPB6) * 15: CHARGE (GPB7) */ gpio-line-names = "ENABLE_HEATER", "PAYLOAD_PWR_ENABLE", "FIRE_DEPLOY2_B", "PAYLOAD_BATT_ENABLE", "RF2_IO2", "RF2_IO1", "RF2_IO0", "RF2_IO3", - "FACE4_ENABLE", "FACE0_ENABLE", "FACE1_ENABLE", "FACE2_ENABLE", - "FACE3_ENABLE", "FACE5_ENABLE", "READONLY", "CHARGE"; + "FACE5_ENABLE", "FACE0_ENABLE", "FACE1_ENABLE", "FACE2_ENABLE", + "FACE3_ENABLE", "FACE4_ENABLE", "READONLY", "CHARGE"; reset-gpios = <&gpio0 20 GPIO_ACTIVE_LOW>; @@ -493,10 +493,10 @@ zephyr_udc0: &usbd { gpio_outputs { compatible = "gpio-leds"; // Using gpio-leds as a convenient container - face4_enable: face4-enable { + face5_enable: face5-enable { - gpios = <&mcp23017 8 GPIO_ACTIVE_HIGH>; // GPB0 - label = "FACE4_ENABLE"; + gpios = <&mcp23017 8 GPIO_ACTIVE_HIGH>; // GPB5 + label = "FACE5_ENABLE"; }; face0_enable: face0-enable { @@ -523,10 +523,10 @@ zephyr_udc0: &usbd { label = "FACE3_ENABLE"; }; - face5_enable: face5-enable { + face4_enable: face4-enable { - gpios = <&mcp23017 13 GPIO_ACTIVE_HIGH>; // GPB5 - label = "FACE5_ENABLE"; + gpios = <&mcp23017 13 GPIO_ACTIVE_HIGH>; // GPB0 + label = "FACE4_ENABLE"; }; enable_heater: enable-heater { From b693cc31cdd44732ae39c42cf157b6c0e2af8192 Mon Sep 17 00:00:00 2001 From: Nate Gay Date: Sat, 29 Nov 2025 14:16:22 -0600 Subject: [PATCH 6/9] Add uart to device tree --- ...roves_flight_control_board_v5-pinctrl.dtsi | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/boards/bronco_space/proves_flight_control_board_v5/proves_flight_control_board_v5-pinctrl.dtsi b/boards/bronco_space/proves_flight_control_board_v5/proves_flight_control_board_v5-pinctrl.dtsi index 48167dd4..ce52e817 100644 --- a/boards/bronco_space/proves_flight_control_board_v5/proves_flight_control_board_v5-pinctrl.dtsi +++ b/boards/bronco_space/proves_flight_control_board_v5/proves_flight_control_board_v5-pinctrl.dtsi @@ -11,6 +11,26 @@ input-enable; }; }; + uart0_default: uart0_default { + group1 { + pinmux = ; + }; + + group2 { + pinmux = ; + input-enable; + }; + }; + uart1_default: uart1_default { + group1 { + pinmux = ; + }; + + group2 { + pinmux = ; + input-enable; + }; + }; spi1_default: spi1_default { group1 { pinmux = , ; From 4b5180800c0a4b62e623540fdbd18283bb1cc847 Mon Sep 17 00:00:00 2001 From: Nate Gay Date: Sat, 29 Nov 2025 15:34:03 -0600 Subject: [PATCH 7/9] Remove I2C debug lines from prj.conf --- prj.conf | 2 -- 1 file changed, 2 deletions(-) diff --git a/prj.conf b/prj.conf index 9c463cec..d54b91ee 100644 --- a/prj.conf +++ b/prj.conf @@ -56,8 +56,6 @@ CONFIG_SENSOR=y # Enable detailed logging for I2C and sensor debugging CONFIG_LOG=y CONFIG_LOG_DEFAULT_LEVEL=3 -CONFIG_I2C_LOG_LEVEL_DBG=y -CONFIG_SENSOR_LOG_LEVEL_DBG=y CONFIG_CBPRINTF_FP_SUPPORT=y From 0cb9b91f691607b79ba6d5805531096203459b63 Mon Sep 17 00:00:00 2001 From: Nate Gay Date: Sun, 30 Nov 2025 15:59:03 -0600 Subject: [PATCH 8/9] Add TCA and Mux Health components --- .../Components/CMakeLists.txt | 1 + .../GenericDeviceMonitor/CMakeLists.txt | 36 +++++++ .../GenericDeviceMonitor.cpp | 45 +++++++++ .../GenericDeviceMonitor.fpp | 38 ++++++++ .../GenericDeviceMonitor.hpp | 65 +++++++++++++ .../GenericDeviceMonitor/docs/sdd.md | 95 +++++++++++++++++++ .../ReferenceDeployment/Main.cpp | 21 ++++ .../Top/ReferenceDeploymentPackets.fppi | 11 +++ .../Top/ReferenceDeploymentTopology.cpp | 8 ++ .../Top/ReferenceDeploymentTopologyDefs.hpp | 9 ++ .../ReferenceDeployment/Top/instances.fpp | 18 ++++ .../ReferenceDeployment/Top/topology.fpp | 17 ++++ .../project/config/AcConstants.fpp | 2 +- 13 files changed, 365 insertions(+), 1 deletion(-) create mode 100644 FprimeZephyrReference/Components/GenericDeviceMonitor/CMakeLists.txt create mode 100644 FprimeZephyrReference/Components/GenericDeviceMonitor/GenericDeviceMonitor.cpp create mode 100644 FprimeZephyrReference/Components/GenericDeviceMonitor/GenericDeviceMonitor.fpp create mode 100644 FprimeZephyrReference/Components/GenericDeviceMonitor/GenericDeviceMonitor.hpp create mode 100644 FprimeZephyrReference/Components/GenericDeviceMonitor/docs/sdd.md diff --git a/FprimeZephyrReference/Components/CMakeLists.txt b/FprimeZephyrReference/Components/CMakeLists.txt index b4f276ad..c320c369 100644 --- a/FprimeZephyrReference/Components/CMakeLists.txt +++ b/FprimeZephyrReference/Components/CMakeLists.txt @@ -8,6 +8,7 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ComDelay/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Drv/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FatalHandler") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FsSpace/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/GenericDeviceMonitor/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ImuManager/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/LoadSwitch/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ModeManager/") diff --git a/FprimeZephyrReference/Components/GenericDeviceMonitor/CMakeLists.txt b/FprimeZephyrReference/Components/GenericDeviceMonitor/CMakeLists.txt new file mode 100644 index 00000000..731a72e3 --- /dev/null +++ b/FprimeZephyrReference/Components/GenericDeviceMonitor/CMakeLists.txt @@ -0,0 +1,36 @@ +#### +# F Prime CMakeLists.txt: +# +# SOURCES: list of source files (to be compiled) +# AUTOCODER_INPUTS: list of files to be passed to the autocoders +# DEPENDS: list of libraries that this module depends on +# +# More information in the F´ CMake API documentation: +# https://fprime.jpl.nasa.gov/latest/docs/reference/api/cmake/API/ +# +#### + +# Module names are derived from the path from the nearest project/library/framework +# root when not specifically overridden by the developer. i.e. The module defined by +# `Ref/SignalGen/CMakeLists.txt` will be named `Ref_SignalGen`. + +register_fprime_library( + AUTOCODER_INPUTS + "${CMAKE_CURRENT_LIST_DIR}/GenericDeviceMonitor.fpp" + SOURCES + "${CMAKE_CURRENT_LIST_DIR}/GenericDeviceMonitor.cpp" +# DEPENDS +# MyPackage_MyOtherModule +) + +### Unit Tests ### +# register_fprime_ut( +# AUTOCODER_INPUTS +# "${CMAKE_CURRENT_LIST_DIR}/GenericDeviceMonitor.fpp" +# SOURCES +# "${CMAKE_CURRENT_LIST_DIR}/test/ut/GenericDeviceMonitorTestMain.cpp" +# "${CMAKE_CURRENT_LIST_DIR}/test/ut/GenericDeviceMonitorTester.cpp" +# DEPENDS +# STest # For rules-based testing +# UT_AUTO_HELPERS +# ) diff --git a/FprimeZephyrReference/Components/GenericDeviceMonitor/GenericDeviceMonitor.cpp b/FprimeZephyrReference/Components/GenericDeviceMonitor/GenericDeviceMonitor.cpp new file mode 100644 index 00000000..17bca66e --- /dev/null +++ b/FprimeZephyrReference/Components/GenericDeviceMonitor/GenericDeviceMonitor.cpp @@ -0,0 +1,45 @@ +// ====================================================================== +// \title GenericDeviceMonitor.cpp +// \author nate +// \brief cpp file for GenericDeviceMonitor component implementation class +// ====================================================================== + +#include "FprimeZephyrReference/Components/GenericDeviceMonitor/GenericDeviceMonitor.hpp" + +namespace Components { + +// ---------------------------------------------------------------------- +// Component construction and destruction +// ---------------------------------------------------------------------- + +GenericDeviceMonitor ::GenericDeviceMonitor(const char* const compName) : GenericDeviceMonitorComponentBase(compName) {} + +GenericDeviceMonitor ::~GenericDeviceMonitor() {} + +// ---------------------------------------------------------------------- +// Helper methods +// ---------------------------------------------------------------------- + +void GenericDeviceMonitor::configure(const struct device* dev) { + this->m_dev = dev; +} + +// ---------------------------------------------------------------------- +// Handler implementations for typed input ports +// ---------------------------------------------------------------------- + +Fw::Health GenericDeviceMonitor ::healthGet_handler(FwIndexType portNum) { + return device_is_ready(this->m_dev) ? Fw::Health::HEALTHY : Fw::Health::FAILED; +} + +void GenericDeviceMonitor ::run_handler(FwIndexType portNum, U32 context) { + if (!device_is_ready(this->m_dev)) { + this->tlmWrite_Healthy(Fw::Health::FAILED); + this->log_WARNING_LO_DeviceNotReady(); + return; + } + + this->tlmWrite_Healthy(Fw::Health::HEALTHY); +} + +} // namespace Components diff --git a/FprimeZephyrReference/Components/GenericDeviceMonitor/GenericDeviceMonitor.fpp b/FprimeZephyrReference/Components/GenericDeviceMonitor/GenericDeviceMonitor.fpp new file mode 100644 index 00000000..e5da4abc --- /dev/null +++ b/FprimeZephyrReference/Components/GenericDeviceMonitor/GenericDeviceMonitor.fpp @@ -0,0 +1,38 @@ +module Components { + port HealthGet -> Fw.Health +} + +module Components { + @ Generic Device Health Reporter + @ Use for devices which only need to report simple health status and have no interactivity + passive component GenericDeviceMonitor { + + @ Port receiving calls from the rate group + sync input port run: Svc.Sched + + @ Port receiving calls to request device health + sync input port healthGet: HealthGet + + @ Telemetry showing device health + telemetry Healthy: Fw.Health + + @ Event indicating device not ready + event DeviceNotReady() severity warning low id 0 format "Device not ready" throttle 5 + + ############################################################################### + # Standard AC Ports: Required for Channels, Events, Commands, and Parameters # + ############################################################################### + @ Port for requesting the current time + time get port timeCaller + + @ Port for sending textual representation of events + text event port logTextOut + + @ Port for sending events to downlink + event port logOut + + @ Port for sending telemetry channels to downlink + telemetry port tlmOut + + } +} diff --git a/FprimeZephyrReference/Components/GenericDeviceMonitor/GenericDeviceMonitor.hpp b/FprimeZephyrReference/Components/GenericDeviceMonitor/GenericDeviceMonitor.hpp new file mode 100644 index 00000000..ea0d741f --- /dev/null +++ b/FprimeZephyrReference/Components/GenericDeviceMonitor/GenericDeviceMonitor.hpp @@ -0,0 +1,65 @@ +// ====================================================================== +// \title GenericDeviceMonitor.hpp +// \author nate +// \brief hpp file for GenericDeviceMonitor component implementation class +// ====================================================================== + +#ifndef Components_GenericDeviceMonitor_HPP +#define Components_GenericDeviceMonitor_HPP + +#include "FprimeZephyrReference/Components/GenericDeviceMonitor/GenericDeviceMonitorComponentAc.hpp" +#include + +namespace Components { + +class GenericDeviceMonitor final : public GenericDeviceMonitorComponentBase { + public: + // ---------------------------------------------------------------------- + // Component construction and destruction + // ---------------------------------------------------------------------- + + //! Construct GenericDeviceMonitor object + GenericDeviceMonitor(const char* const compName //!< The component name + ); + + //! Destroy GenericDeviceMonitor object + ~GenericDeviceMonitor(); + + public: + // ---------------------------------------------------------------------- + // Public helper methods + // ---------------------------------------------------------------------- + + //! Configure the zephyr mux channel device + void configure(const struct device* dev); + + private: + // ---------------------------------------------------------------------- + // Handler implementations for typed input ports + // ---------------------------------------------------------------------- + + //! Handler implementation for healthGet + //! + //! Port receiving calls to request device health + Fw::Health healthGet_handler(FwIndexType portNum //!< The port number + ) override; + + //! Handler implementation for run + //! + //! Port receiving calls from the rate group + void run_handler(FwIndexType portNum, //!< The port number + U32 context //!< The call order + ) override; + + private: + // ---------------------------------------------------------------------- + // Private member variables + // ---------------------------------------------------------------------- + + //! Zephyr device stores the initialized mux channel + const struct device* m_dev; +}; + +} // namespace Components + +#endif diff --git a/FprimeZephyrReference/Components/GenericDeviceMonitor/docs/sdd.md b/FprimeZephyrReference/Components/GenericDeviceMonitor/docs/sdd.md new file mode 100644 index 00000000..7caaa23f --- /dev/null +++ b/FprimeZephyrReference/Components/GenericDeviceMonitor/docs/sdd.md @@ -0,0 +1,95 @@ +# Components::GenericDeviceMonitor + +Generic Device Health Reporter + +## Usage Examples + +The GenericDeviceMonitor component is designed to monitor and report the health status of simple devices that do not require complex interactivity. It can be scheduled to periodically check or report status, and it provides a port for external components to query its health. + +### Typical Usage + +1. The component is instantiated and connected to a rate group and/or a health monitoring service. +2. The scheduler calls the `run` port. +3. External components can call the `healthGet` port to retrieve the current health status. +4. The component emits telemetry indicating its health status (`Healthy`). +5. If the device is not ready, it emits a `DeviceNotReady` event. + +## Class Diagram + +```mermaid +classDiagram + namespace Components { + class GenericDeviceMonitorComponentBase { + <> + } + class GenericDeviceMonitor { + + GenericDeviceMonitor(const char* compName) + + ~GenericDeviceMonitor() + - run_handler(FwIndexType portNum, U32 context): void + - healthGet_handler(FwIndexType portNum, Fw::Health& health): void + } + } + GenericDeviceMonitorComponentBase <|-- GenericDeviceMonitor : inherits +``` + +## Port Descriptions +| Name | Type | Description | +|---|---|---| +| run | sync input | Port receiving calls from the rate group | +| healthGet | sync input | Port receiving calls to request device health | +| timeCaller | time get | Port for requesting the current time | +| logTextOut | text event | Port for sending textual representation of events | +| logOut | event | Port for sending events to downlink | +| tlmOut | telemetry | Port for sending telemetry channels to downlink | + +## Component States +The component is stateless in terms of FSM, but tracks the health status of the monitored device. + +## Sequence Diagrams + +```mermaid +sequenceDiagram + participant Scheduler + participant GenericDeviceMonitor + participant ExternalRequester + + Scheduler->>GenericDeviceMonitor: run + GenericDeviceMonitor-->>GenericDeviceMonitor: Check Status (Internal) + GenericDeviceMonitor->>Telemetry: Healthy + + ExternalRequester->>GenericDeviceMonitor: healthGet + GenericDeviceMonitor-->>ExternalRequester: return Health Status +``` + +## Parameters +None + +## Commands +None + +## Events +| Name | Description | +|---|---| +| DeviceNotReady | Event indicating device not ready | + +## Telemetry +| Name | Description | +|---|---| +| Healthy | Telemetry showing device health | + +## Unit Tests +| Name | Description | +|---|---| +| TestHealthReporting | Verify health status reporting via telemetry | + +## Requirements +| Name | Description | Validation | +|---|---|---| +| Health Reporting | The component shall report the health status of the monitored device via telemetry | Verify `Healthy` telemetry channel | +| Health Query | The component shall respond to health queries via the `healthGet` port | Verify `healthGet` port return value | +| Error Reporting | The component shall emit an event if the device is not ready | Verify `DeviceNotReady` event | + +## Change Log +| Date | Description | +|---|---| +| 2025-11-30 | Initial Draft | diff --git a/FprimeZephyrReference/ReferenceDeployment/Main.cpp b/FprimeZephyrReference/ReferenceDeployment/Main.cpp index c4d250c5..d40792b8 100644 --- a/FprimeZephyrReference/ReferenceDeployment/Main.cpp +++ b/FprimeZephyrReference/ReferenceDeployment/Main.cpp @@ -17,6 +17,15 @@ const struct device* lora = DEVICE_DT_GET(DT_NODELABEL(lora0)); const struct device* lsm6dso = DEVICE_DT_GET(DT_NODELABEL(lsm6dso0)); const struct device* lis2mdl = DEVICE_DT_GET(DT_NODELABEL(lis2mdl0)); const struct device* rtc = DEVICE_DT_GET(DT_NODELABEL(rtc0)); +const struct device* tca9548a = DEVICE_DT_GET(DT_NODELABEL(tca9548a)); +const struct device* mux_channel_0 = DEVICE_DT_GET(DT_NODELABEL(mux_channel_0)); +const struct device* mux_channel_1 = DEVICE_DT_GET(DT_NODELABEL(mux_channel_1)); +const struct device* mux_channel_2 = DEVICE_DT_GET(DT_NODELABEL(mux_channel_2)); +const struct device* mux_channel_3 = DEVICE_DT_GET(DT_NODELABEL(mux_channel_3)); +const struct device* mux_channel_4 = DEVICE_DT_GET(DT_NODELABEL(mux_channel_4)); +const struct device* mux_channel_5 = DEVICE_DT_GET(DT_NODELABEL(mux_channel_5)); +const struct device* mux_channel_6 = DEVICE_DT_GET(DT_NODELABEL(mux_channel_6)); +const struct device* mux_channel_7 = DEVICE_DT_GET(DT_NODELABEL(mux_channel_7)); int main(int argc, char* argv[]) { // ** DO NOT REMOVE **// @@ -27,6 +36,8 @@ int main(int argc, char* argv[]) { Os::init(); // Object for communicating state to the topology ReferenceDeployment::TopologyState inputs; + + // Flight Control Board device bindings inputs.ina219SysDevice = ina219Sys; inputs.ina219SolDevice = ina219Sol; inputs.loraDevice = lora; @@ -34,6 +45,16 @@ int main(int argc, char* argv[]) { inputs.lsm6dsoDevice = lsm6dso; inputs.lis2mdlDevice = lis2mdl; inputs.rtcDevice = rtc; + inputs.tca9548aDevice = tca9548a; + inputs.muxChannel0Device = mux_channel_0; + inputs.muxChannel1Device = mux_channel_1; + inputs.muxChannel2Device = mux_channel_2; + inputs.muxChannel3Device = mux_channel_3; + inputs.muxChannel4Device = mux_channel_4; + inputs.muxChannel5Device = mux_channel_5; + inputs.muxChannel6Device = mux_channel_6; + inputs.muxChannel7Device = mux_channel_7; + inputs.baudRate = 115200; // Setup, cycle, and teardown topology diff --git a/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentPackets.fppi b/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentPackets.fppi index 6055131c..df328712 100644 --- a/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentPackets.fppi +++ b/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentPackets.fppi @@ -91,7 +91,18 @@ telemetry packets ReferenceDeploymentPackets { ComCcsdsUart.authenticate.AuthenticatedPacketsCount ComCcsdsUart.authenticate.RejectedPacketsCount ComCcsdsUart.authenticate.CurrentSequenceNumber + } + packet TcaMonitor id 12 group 4 { + ReferenceDeployment.tcaMonitor.Healthy + ReferenceDeployment.muxChannel0Monitor.Healthy + ReferenceDeployment.muxChannel1Monitor.Healthy + ReferenceDeployment.muxChannel2Monitor.Healthy + ReferenceDeployment.muxChannel3Monitor.Healthy + ReferenceDeployment.muxChannel4Monitor.Healthy + ReferenceDeployment.muxChannel5Monitor.Healthy + ReferenceDeployment.muxChannel6Monitor.Healthy + ReferenceDeployment.muxChannel7Monitor.Healthy } } omit { diff --git a/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentTopology.cpp b/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentTopology.cpp index af8e02a4..13004e7f 100644 --- a/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentTopology.cpp +++ b/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentTopology.cpp @@ -115,6 +115,14 @@ void setupTopology(const TopologyState& state) { lis2mdlManager.configure(state.lis2mdlDevice); ina219SysManager.configure(state.ina219SysDevice); ina219SolManager.configure(state.ina219SolDevice); + tcaMonitor.configure(state.tca9548aDevice); + muxChannel0Monitor.configure(state.muxChannel0Device); + muxChannel1Monitor.configure(state.muxChannel1Device); + muxChannel2Monitor.configure(state.muxChannel2Device); + muxChannel3Monitor.configure(state.muxChannel3Device); + muxChannel4Monitor.configure(state.muxChannel4Device); + muxChannel5Monitor.configure(state.muxChannel5Device); + muxChannel7Monitor.configure(state.muxChannel7Device); } void startRateGroups() { diff --git a/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentTopologyDefs.hpp b/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentTopologyDefs.hpp index 00b11005..cf7aee2f 100644 --- a/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentTopologyDefs.hpp +++ b/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentTopologyDefs.hpp @@ -80,6 +80,15 @@ struct TopologyState { const device* lsm6dsoDevice; //!< LSM6DSO device path for accelerometer/gyroscope const device* lis2mdlDevice; //!< LIS2MDL device path for magnetometer const device* rtcDevice; //!< RTC device path + const device* tca9548aDevice; //!< TCA9548A I2C multiplexer device + const device* muxChannel0Device; //!< Multiplexer channel 0 device + const device* muxChannel1Device; //!< Multiplexer channel 1 device + const device* muxChannel2Device; //!< Multiplexer channel 2 device + const device* muxChannel3Device; //!< Multiplexer channel 3 device + const device* muxChannel4Device; //!< Multiplexer channel 4 device + const device* muxChannel5Device; //!< Multiplexer channel 5 device + const device* muxChannel6Device; //!< Multiplexer channel 5 device + const device* muxChannel7Device; //!< Multiplexer channel 7 device }; namespace PingEntries = ::PingEntries; diff --git a/FprimeZephyrReference/ReferenceDeployment/Top/instances.fpp b/FprimeZephyrReference/ReferenceDeployment/Top/instances.fpp index a2cd9211..430025d3 100644 --- a/FprimeZephyrReference/ReferenceDeployment/Top/instances.fpp +++ b/FprimeZephyrReference/ReferenceDeployment/Top/instances.fpp @@ -142,4 +142,22 @@ module ReferenceDeployment { instance startupManager: Components.StartupManager base id 0x1003F000 + instance tcaMonitor: Components.GenericDeviceMonitor base id 0x10041000 + + instance muxChannel0Monitor: Components.GenericDeviceMonitor base id 0x10042000 + + instance muxChannel1Monitor: Components.GenericDeviceMonitor base id 0x10043000 + + instance muxChannel2Monitor: Components.GenericDeviceMonitor base id 0x10044000 + + instance muxChannel3Monitor: Components.GenericDeviceMonitor base id 0x10045000 + + instance muxChannel4Monitor: Components.GenericDeviceMonitor base id 0x10046000 + + instance muxChannel5Monitor: Components.GenericDeviceMonitor base id 0x10047000 + + instance muxChannel6Monitor: Components.GenericDeviceMonitor base id 0x10048000 + + instance muxChannel7Monitor: Components.GenericDeviceMonitor base id 0x10049000 + } diff --git a/FprimeZephyrReference/ReferenceDeployment/Top/topology.fpp b/FprimeZephyrReference/ReferenceDeployment/Top/topology.fpp index 0390534e..58855540 100644 --- a/FprimeZephyrReference/ReferenceDeployment/Top/topology.fpp +++ b/FprimeZephyrReference/ReferenceDeployment/Top/topology.fpp @@ -68,6 +68,15 @@ module ReferenceDeployment { instance ina219SolManager instance resetManager instance modeManager + instance tcaMonitor + instance muxChannel0Monitor + instance muxChannel1Monitor + instance muxChannel2Monitor + instance muxChannel3Monitor + instance muxChannel4Monitor + instance muxChannel5Monitor + instance muxChannel6Monitor + instance muxChannel7Monitor # ---------------------------------------------------------------------- @@ -173,6 +182,14 @@ module ReferenceDeployment { rateGroup1Hz.RateGroupMemberOut[11] -> startupManager.run rateGroup1Hz.RateGroupMemberOut[12] -> powerMonitor.run rateGroup1Hz.RateGroupMemberOut[13] -> modeManager.run + rateGroup1Hz.RateGroupMemberOut[14] -> tcaMonitor.run + rateGroup1Hz.RateGroupMemberOut[15] -> muxChannel0Monitor.run + rateGroup1Hz.RateGroupMemberOut[16] -> muxChannel1Monitor.run + rateGroup1Hz.RateGroupMemberOut[17] -> muxChannel2Monitor.run + rateGroup1Hz.RateGroupMemberOut[18] -> muxChannel3Monitor.run + rateGroup1Hz.RateGroupMemberOut[19] -> muxChannel4Monitor.run + rateGroup1Hz.RateGroupMemberOut[20] -> muxChannel5Monitor.run + rateGroup1Hz.RateGroupMemberOut[21] -> muxChannel7Monitor.run } diff --git a/FprimeZephyrReference/project/config/AcConstants.fpp b/FprimeZephyrReference/project/config/AcConstants.fpp index 8eeefb4b..50398f38 100644 --- a/FprimeZephyrReference/project/config/AcConstants.fpp +++ b/FprimeZephyrReference/project/config/AcConstants.fpp @@ -4,7 +4,7 @@ # ====================================================================== @ Number of rate group member output ports for ActiveRateGroup -constant ActiveRateGroupOutputPorts = 15 +constant ActiveRateGroupOutputPorts = 22 @ Number of rate group member output ports for PassiveRateGroup constant PassiveRateGroupOutputPorts = 10 From 59972a7b2bce34f0dd5b32454612b182802538e6 Mon Sep 17 00:00:00 2001 From: Nate Gay Date: Sun, 30 Nov 2025 16:02:17 -0600 Subject: [PATCH 9/9] Add test --- .../test/int/generic_device_monitor_test.py | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 FprimeZephyrReference/test/int/generic_device_monitor_test.py diff --git a/FprimeZephyrReference/test/int/generic_device_monitor_test.py b/FprimeZephyrReference/test/int/generic_device_monitor_test.py new file mode 100644 index 00000000..e64f6b7c --- /dev/null +++ b/FprimeZephyrReference/test/int/generic_device_monitor_test.py @@ -0,0 +1,24 @@ +""" +generic_device_monitor_test.py: + +Integration tests for the Generic Device Monitor component. +""" + +from fprime_gds.common.data_types.ch_data import ChData +from fprime_gds.common.testing_fw.api import IntegrationTestAPI + +# We use the tcaMonitor instance to test the GenericDeviceMonitor component +tcaMonitor = "ReferenceDeployment.tcaMonitor" + + +def test_01_generic_device_monitor_healthy( + fprime_test_api: IntegrationTestAPI, start_gds +): + """Test that the Generic Device Monitor reports Healthy""" + result: ChData = fprime_test_api.assert_telemetry( + f"{tcaMonitor}.Healthy", start="NOW", timeout=5 + ) + + assert str(result.get_val()) == "Healthy", ( + f"Generic Device Monitor should be Healthy, got {result.get_val()}" + )