Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions FprimeZephyrReference/Components/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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/")
Expand Down
Original file line number Diff line number Diff line change
@@ -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
# )
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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

}
}
Original file line number Diff line number Diff line change
@@ -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 <zephyr/device.h>

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
95 changes: 95 additions & 0 deletions FprimeZephyrReference/Components/GenericDeviceMonitor/docs/sdd.md
Original file line number Diff line number Diff line change
@@ -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 {
<<Auto-generated>>
}
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 |
21 changes: 21 additions & 0 deletions FprimeZephyrReference/ReferenceDeployment/Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 **//
Expand All @@ -27,13 +36,25 @@ 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;
inputs.uartDevice = serial;
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading
Loading