diff --git a/FprimeZephyrReference/Components/CMakeLists.txt b/FprimeZephyrReference/Components/CMakeLists.txt index 9b9cab94..e1cf1f98 100644 --- a/FprimeZephyrReference/Components/CMakeLists.txt +++ b/FprimeZephyrReference/Components/CMakeLists.txt @@ -11,3 +11,5 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ImuManager/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/NullPrmDb/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/PowerMonitor/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Watchdog") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/LightSensor/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/LoadSwitch/") diff --git a/FprimeZephyrReference/Components/LightSensor/CMakeLists.txt b/FprimeZephyrReference/Components/LightSensor/CMakeLists.txt new file mode 100644 index 00000000..c4170acd --- /dev/null +++ b/FprimeZephyrReference/Components/LightSensor/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}/LightSensor.fpp" + SOURCES + "${CMAKE_CURRENT_LIST_DIR}/LightSensor.cpp" +# DEPENDS +# MyPackage_MyOtherModule +) + +### Unit Tests ### +# register_fprime_ut( +# AUTOCODER_INPUTS +# "${CMAKE_CURRENT_LIST_DIR}/LightSensor.fpp" +# SOURCES +# "${CMAKE_CURRENT_LIST_DIR}/test/ut/LightSensorTestMain.cpp" +# "${CMAKE_CURRENT_LIST_DIR}/test/ut/LightSensorTester.cpp" +# DEPENDS +# STest # For rules-based testing +# UT_AUTO_HELPERS +# ) diff --git a/FprimeZephyrReference/Components/LightSensor/LightSensor.cpp b/FprimeZephyrReference/Components/LightSensor/LightSensor.cpp new file mode 100644 index 00000000..7fd0bf43 --- /dev/null +++ b/FprimeZephyrReference/Components/LightSensor/LightSensor.cpp @@ -0,0 +1,164 @@ +// ====================================================================== +// \title LightSensor.cpp +// \author robertpendergrast +// \brief cpp file for LightSensor component implementation class +// ====================================================================== + + + +#include "FprimeZephyrReference/Components/LightSensor/LightSensor.hpp" +#include +#include +#include +#include + +namespace Components { + +// ---------------------------------------------------------------------- +// Component construction and destruction +// ---------------------------------------------------------------------- + +LightSensor ::LightSensor(const char* const compName) : LightSensorComponentBase(compName) {} + +LightSensor ::~LightSensor() {} + +void LightSensor ::configure(const struct device* dev) { + return; +} + +void LightSensor ::ReadData() { // const struct device *dev, + // Return integer + int ret; + + // Sensor value structs for reading data + struct sensor_value light; + struct sensor_value als_raw; + struct sensor_value ir_raw; + struct sensor_value sen; + + sen.val2 = 0; + + Fw::ParamValid valid; + sen.val1 = 5; // pass in saying that the parameter is valid + + // Setting the integration time attribute for the light sensor + + if (! (this->m_attributes_set)){ + ret = sensor_attr_set(this->m_dev, SENSOR_CHAN_LIGHT, (enum sensor_attribute)SENSOR_ATTR_VEML6031_IT, &sen); + if (ret) { + Fw::LogStringArg errMsg("Failed to set it attribute"); + this->log_WARNING_HI_LightSensorError(errMsg); + } + + // Set the sensor attribute for div4 + sen.val1 = paramGet_DIV4(valid); + + ret = sensor_attr_set(this->m_dev, SENSOR_CHAN_LIGHT, (enum sensor_attribute)SENSOR_ATTR_VEML6031_DIV4, &sen); + if (ret) { + Fw::LogStringArg errMsg("Failed to set div4 attribute"); + this->log_WARNING_HI_LightSensorError(errMsg); + } + + // Set the sensor attribute for the gain + sen.val1 = 0; + ret = sensor_attr_set(this->m_dev, SENSOR_CHAN_LIGHT, (enum sensor_attribute)SENSOR_ATTR_VEML6031_GAIN, &sen); + if (ret) { + Fw::LogStringArg errMsg("Failed to set gain attribute ret"); + this->log_WARNING_HI_LightSensorError(errMsg); + } + + this->m_attributes_set = true; + } + + // Get the rate + ret = sensor_sample_fetch(this->m_dev); + if ((ret < 0) && (ret != -E2BIG)) { + Fw::LogStringArg errMsg("sample update error"); + this->log_WARNING_HI_LightSensorError(errMsg); + this->log_WARNING_HI_LightSensorErrorInt(ret); + } + + // Get the light data + sensor_channel_get(this->m_dev, (enum sensor_channel)SENSOR_CHAN_LIGHT, &light); + + // Get the raw ALS + sensor_channel_get(this->m_dev, (enum sensor_channel)SENSOR_CHAN_VEML6031_ALS_RAW_COUNTS, &als_raw); + + // Get the raw IR + sensor_channel_get(this->m_dev, (enum sensor_channel)SENSOR_CHAN_VEML6031_IR_RAW_COUNTS, &ir_raw); + + this->m_RawLightData = sensor_value_to_double(&light); + this->m_ALSLightData = sensor_value_to_double(&als_raw); + this->m_IRLightData = sensor_value_to_double(&ir_raw); +} + +// ---------------------------------------------------------------------- +// Handler implementations for typed input ports +// ---------------------------------------------------------------------- + +void LightSensor ::run_handler(FwIndexType portNum, U32 context) { + Fw::Logic state; + this->gpioRead_out(portNum, state); + if (state == Fw::Logic::HIGH){ // port call to the gpio driver, pass in a specific pin # + this->ReadData(); + this->tlmWrite_RawLightData(this->m_RawLightData); + this->tlmWrite_IRLightData(this->m_IRLightData); + this->tlmWrite_ALSLightData(this->m_ALSLightData); + } else { + if (this->m_device_init == true) { + this->m_device_init = false; + } + if(state == Fw::Logic::LOW && this->m_attributes_set == true){ + this->m_attributes_set = false; + } + } + +} + +void LightSensor::init_handler(FwIndexType portNum) { + + const struct device *mux = DEVICE_DT_GET(DT_NODELABEL(tca9548a)); + const struct device *channel = DEVICE_DT_GET(DT_NODELABEL(face0_i2c)); + const struct device *sensor = DEVICE_DT_GET(DT_NODELABEL(face0_light_sens)); + + if (!mux || !channel || !sensor) { + this->log_WARNING_HI_LightSensorError(Fw::LogStringArg("Device DT_NODELABEL missing")); + return; + } + + int ret = device_init(mux); + if (ret < 0) { + this->log_WARNING_HI_LightSensorError(Fw::LogStringArg("TCA9548A init failed")); + return; + } + k_sleep(K_MSEC(30)); + + ret = device_init(channel); + if (ret < 0) { + this->log_WARNING_HI_LightSensorError(Fw::LogStringArg("Mux channel init failed")); + return; + } + k_sleep(K_MSEC(30)); + + ret = device_init(sensor); + if (ret < 0) { + this->log_WARNING_HI_LightSensorError(Fw::LogStringArg("Light sensor init failed")); + // Continue anyway - might still work + } + k_sleep(K_MSEC(50)); + + if (!device_is_ready(sensor)) { + this->log_WARNING_HI_LightSensorError(Fw::LogStringArg("Light sensor not ready after timeout")); + } + + this->m_dev = sensor; + this->m_device_init = true; + + this->log_ACTIVITY_LO_LightSensorConfigured(); +} + + + + + +} // namespace Components diff --git a/FprimeZephyrReference/Components/LightSensor/LightSensor.fpp b/FprimeZephyrReference/Components/LightSensor/LightSensor.fpp new file mode 100644 index 00000000..6fb531b5 --- /dev/null +++ b/FprimeZephyrReference/Components/LightSensor/LightSensor.fpp @@ -0,0 +1,103 @@ +module Components { + @ Component for reading light sensor data + port InitPort + + passive component LightSensor { + + #### Parameters #### + @ Parameter for setting the gain of the light senors + param GAIN: U32 default 1 + + @ Parameter for setting the integration time of the light sensors + param INTEGRATION_TIME: U32 default 100 + + @ Paremeter for setting the div4 mode of the light sensors + param DIV4: U32 default 0 + + #### Telemetry #### + @ Telemetry for the raw light sensor data + telemetry RawLightData: F32 + + @ Telemetry for the IR light sensor data + telemetry IRLightData: F32 + + @ Telemetry for the ALS light sensor data + telemetry ALSLightData: F32 + + #### Ports #### + + @ Port for polling the light sensor data - called by rate group + sync input port run: Svc.Sched + + @ Port for reading gpio status + output port gpioRead: Drv.GpioRead + + @ Port to tell us when to init the device + sync input port init: InitPort + + #### Events #### + + @ Event for light sensor errors + event LightSensorError(log: string) severity warning high format "Light Sensor Error: {}" + + event LightSensorErrorInt(log: U32) severity warning high format "Light Sensor Error: {}" + + @ Event for light sensor configuration + event LightSensorConfigured() severity activity low format "Light Sensor Configured" + + event LightSensorRead() severity activity low format "Values Read from the Light Sensor" + + + + + ############################################################################## + #### Uncomment the following examples to start customizing your component #### + ############################################################################## + + # @ Example async command + # async command COMMAND_NAME(param_name: U32) + + # @ Example telemetry counter + # telemetry ExampleCounter: U64 + + # @ Example event + # event ExampleStateEvent(example_state: Fw.On) severity activity high id 0 format "State set to {}" + + # @ Example port: receiving calls from the rate group + # sync input port run: Svc.Sched + + # @ Example parameter + # param PARAMETER_NAME: U32 + + ############################################################################### + # Standard AC Ports: Required for Channels, Events, Commands, and Parameters # + ############################################################################### + @ Port for requesting the current time + time get port timeCaller + + @ Port for sending command registrations + command reg port cmdRegOut + + @ Port for receiving commands + command recv port cmdIn + + @ Port for sending command responses + command resp port cmdResponseOut + + @ 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 + + @ Port to return the value of a parameter + param get port prmGetOut + + @Port to set the value of a parameter + param set port prmSetOut + + } +} \ No newline at end of file diff --git a/FprimeZephyrReference/Components/LightSensor/LightSensor.hpp b/FprimeZephyrReference/Components/LightSensor/LightSensor.hpp new file mode 100644 index 00000000..a0742129 --- /dev/null +++ b/FprimeZephyrReference/Components/LightSensor/LightSensor.hpp @@ -0,0 +1,77 @@ +// ====================================================================== +// \title LightSensor.hpp +// \author robertpendergrast +// \brief hpp file for LightSensor component implementation class +// ====================================================================== + +#ifndef Components_LightSensor_HPP +#define Components_LightSensor_HPP + +#include "FprimeZephyrReference/Components/LightSensor/LightSensorComponentAc.hpp" + +#include + +#include +#include +#include + +#include +#include +#include + +#include + +namespace Components { + +class LightSensor final : public LightSensorComponentBase { + public: + // ---------------------------------------------------------------------- + // Component construction and destruction + // ---------------------------------------------------------------------- + + //! Construct LightSensor object + LightSensor(const char* const compName //!< The component name + ); + + //! Destroy LightSensor object + ~LightSensor(); + + + void ReadData(); + + void configure(const struct device* dev); + + private: + // ---------------------------------------------------------------------- + // Handler implementations for typed input ports + // ---------------------------------------------------------------------- + + //! Handler implementation for run + //! + //! Port for polling the light sensor data - called by rate group + void run_handler(FwIndexType portNum, //!< The port number + U32 context //!< The call order + ) override; + + void init_handler(FwIndexType portNum); + + F32 m_RawLightData; + + F32 m_IRLightData; + + F32 m_ALSLightData; + + bool m_configured = false; + + bool m_attributes_set = false; + + bool m_device_init = false; + + const struct device* m_dev; +}; + + + +} // namespace Components + +#endif diff --git a/FprimeZephyrReference/Components/LightSensor/docs/sdd.md b/FprimeZephyrReference/Components/LightSensor/docs/sdd.md new file mode 100644 index 00000000..96f846b9 --- /dev/null +++ b/FprimeZephyrReference/Components/LightSensor/docs/sdd.md @@ -0,0 +1,86 @@ +# Components::LightSensorManager + +Component emitting telemetry read from a VEML 6031 light sensor. This component communicates with the VEML 6031 sensor using a Zephyr driver and provides illuminance data. + +## Usage Examples +Add usage examples here + +### Diagrams +Add diagrams here + +### Typical Usage +And the typical usage of the component here + +## Class Diagram +Add a class diagram here + +## Port Descriptions +| Name | Description | +|------------|---------------------------------------------------------------------------------| +| loadSwitch | Input port for receiving signal from load switch to activate the light sensor | +| run | Input port for receiving ticks from rate group to read sensor data periodically | + +## Component States +| Name | Description | +|------|-------------------| +| RESET | State where sensor encounters an error and resets (turns off and back on to running) | +| OFF | The sensor is off | +| ON | The sensor is on | + +## Sequence Diagrams +Add sequence diagrams here + +## Parameters +| Name | Description | +|---|---| +|GAIN|Controls the sensor’s sensitivity to light| +|INTEGRATION_TIME|Determines how long the sensor collects line for before taking a measurement| +|DET_THRESHOLD|Threshold to decide if light is detected| +|READ_INTERVAL|How many rate group ticks it takes to read the light sensor once| + +## Commands +| Name | Description | +|-------|-------------------------| +| RESET | Turns sensor off and on | + +## Events +| Name | Description | +|----------------------|------------------------------------------------------| +| LightDetected | Emitted when light is detected | +| LightSensorTurnedOn | Emitted when light sensor is turned on | +| LightSensorReset | Emitted when light sensor resets | +| LightSensorTurnedOff | Emitted when light sensor is turned off | +| LightSensorError | Emitted when light sensor transitions to error state | + +## Telemetry +| Name | Description | +|---------|----------------------------------------------------------------| +| Reading | VEML6031 sensor data containing ALS and IR sensor values (raw) | +| Status | Boolean whether data is valid or not | + +## Unit Tests +| Name | Description | Output | Coverage | +|----------------------------|----------------------------------------------------|--------------------------------------------|-------------------------------| +| TestInitialState | Verify component starts in OFF state | Component initializes properly | LightSensor initialization(?) | +| TestSensorReading | Verify ALS and IR readings | accurate sensor values | (?) | +| TestZephyrCommunication | Verify Zephyr operations(?) | Successful sensor application | Zephyr driver | +| TestReadIntervalValidation | Verify read interval is less than integration time | Correct read interval and integration time | Sensor parameters | +| TestThreshold | | | | +| TestStateTransitions | Verify proper state machine transitions | Correct state progression | State machine logic | + + +## Requirements +Add requirements in the chart below +| Name | Description | Validation | +|------|-------------|-------------| +| VEML6031-001 | The LightSensorManager shall emit ALS (ambient light sensor) and IR (infrared) sensor values in units of lx (lux) | Unit-Test | +| VEML6031-002 | The LightSensorManager shall communicate with the VEML6031 using its Zephyr driver | Unit-Test | +| VEML6031-003 | The LightSensorManager shall validate lux readings | Unit-Test | +| VEML6031-004 | The LightSensorManager shall report if light is detected above a provided threshold | Unit-Test | +| VEML6031-005 | The LightSensorManager shall reset | Unit-Test | +| VEML6031-006 | The LightSensormanager shall check if READ_INTERVAL is less than INTEGRATION_TIME | Unit-Test | + +## Change Log +| Date | Description | +|---|---| +|---| Initial Draft | diff --git a/FprimeZephyrReference/Components/LoadSwitch/CMakeLists.txt b/FprimeZephyrReference/Components/LoadSwitch/CMakeLists.txt new file mode 100644 index 00000000..5be47b2d --- /dev/null +++ b/FprimeZephyrReference/Components/LoadSwitch/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}/LoadSwitch.fpp" + SOURCES + "${CMAKE_CURRENT_LIST_DIR}/LoadSwitch.cpp" +# DEPENDS +# MyPackage_MyOtherModule +) + +### Unit Tests ### +# register_fprime_ut( +# AUTOCODER_INPUTS +# "${CMAKE_CURRENT_LIST_DIR}/LoadSwitch.fpp" +# SOURCES +# "${CMAKE_CURRENT_LIST_DIR}/test/ut/LoadSwitchTestMain.cpp" +# "${CMAKE_CURRENT_LIST_DIR}/test/ut/LoadSwitchTester.cpp" +# DEPENDS +# STest # For rules-based testing +# UT_AUTO_HELPERS +# ) diff --git a/FprimeZephyrReference/Components/LoadSwitch/LoadSwitch.cpp b/FprimeZephyrReference/Components/LoadSwitch/LoadSwitch.cpp new file mode 100644 index 00000000..757d8735 --- /dev/null +++ b/FprimeZephyrReference/Components/LoadSwitch/LoadSwitch.cpp @@ -0,0 +1,54 @@ +// ====================================================================== +// \title LoadSwitch.cpp +// \author sarah +// \brief cpp file for LoadSwitch component implementation class +// ====================================================================== + +#include "FprimeZephyrReference/Components/LoadSwitch/LoadSwitch.hpp" +#include + +namespace Components { + +// ---------------------------------------------------------------------- +// Component construction and destruction +// ---------------------------------------------------------------------- + +LoadSwitch ::LoadSwitch(const char* const compName) : LoadSwitchComponentBase(compName) {} + +LoadSwitch ::~LoadSwitch() {} + +// ---------------------------------------------------------------------- +// Handler implementations for typed input ports +// ---------------------------------------------------------------------- + +void LoadSwitch ::Reset_handler(FwIndexType portNum) { + this->gpioSet_out(0, Fw::Logic::LOW); + this->log_ACTIVITY_HI_StatusChanged(Fw::On::OFF); + this->tlmWrite_IsOn(Fw::On::OFF); + k_sleep(K_MSEC(100)); + this->gpioSet_out(0, Fw::Logic::HIGH); + this->log_ACTIVITY_HI_StatusChanged(Fw::On::ON); + this->tlmWrite_IsOn(Fw::On::ON); +} + +// ---------------------------------------------------------------------- +// Handler implementations for commands +// ---------------------------------------------------------------------- + +void LoadSwitch ::TURN_ON_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) { + this->gpioSet_out(0, Fw::Logic::HIGH); + this->log_ACTIVITY_HI_StatusChanged(Fw::On::ON); + this->tlmWrite_IsOn(Fw::On::ON); + this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); + + this->init_out(0); +} + +void LoadSwitch ::TURN_OFF_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) { + this->gpioSet_out(0, Fw::Logic::LOW); + this->log_ACTIVITY_HI_StatusChanged(Fw::On::OFF); + this->tlmWrite_IsOn(Fw::On::OFF); + this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); +} + +} // namespace Components diff --git a/FprimeZephyrReference/Components/LoadSwitch/LoadSwitch.fpp b/FprimeZephyrReference/Components/LoadSwitch/LoadSwitch.fpp new file mode 100644 index 00000000..16b33d3f --- /dev/null +++ b/FprimeZephyrReference/Components/LoadSwitch/LoadSwitch.fpp @@ -0,0 +1,75 @@ +module Components { + @ A generic load switch for controlling power to components + passive component LoadSwitch { + + # One async command/port is required for active components + # This should be overridden by the developers with a useful command/port + + ############################################################################## + #### Uncomment the following examples to start customizing your component #### + ############################################################################## + + # @ Example async command + # async command COMMAND_NAME(param_name: U32) + sync command TURN_ON() + sync command TURN_OFF() + + # @ Example telemetry counter + # telemetry ExampleCounter: U64 + telemetry IsOn: Fw.On + + # @ Example event + # event ExampleStateEvent(example_state: Fw.On) severity activity high id 0 format "State set to {}" + event StatusChanged($state: Fw.On) severity activity high id 1 format "Load switch state changed to {}" + + # @ Example port: receiving calls from the rate group + # sync input port run: Svc.Sched + #output port Status: Drv.GpioRead + #We will not be putting a Drv.GpioRead port here, we are using the Gpio Driver component which has this already! + + @ Port sending calls to the GPIO driver + output port gpioSet: Drv.GpioWrite + + @ Port for telling the light sensor to init + output port init: InitPort + + + # Input that will be used by other components if they want to force a reset + # (off and on again) of the load switch + sync input port Reset: Fw.Signal + + # @ Example parameter + # param PARAMETER_NAME: U32 + + ############################################################################### + # Standard AC Ports: Required for Channels, Events, Commands, and Parameters # + ############################################################################### + @ Port for requesting the current time + time get port timeCaller + + @ Port for sending command registrations + command reg port cmdRegOut + + @ Port for receiving commands + command recv port cmdIn + + @ Port for sending command responses + command resp port cmdResponseOut + + @ 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 + + @ Port to return the value of a parameter + param get port prmGetOut + + @Port to set the value of a parameter + param set port prmSetOut + + } +} diff --git a/FprimeZephyrReference/Components/LoadSwitch/LoadSwitch.hpp b/FprimeZephyrReference/Components/LoadSwitch/LoadSwitch.hpp new file mode 100644 index 00000000..e3a5cf92 --- /dev/null +++ b/FprimeZephyrReference/Components/LoadSwitch/LoadSwitch.hpp @@ -0,0 +1,58 @@ +// ====================================================================== +// \title LoadSwitch.hpp +// \author sarah +// \brief hpp file for LoadSwitch component implementation class +// ====================================================================== + +#ifndef Components_LoadSwitch_HPP +#define Components_LoadSwitch_HPP + +#include "FprimeZephyrReference/Components/LoadSwitch/LoadSwitchComponentAc.hpp" +#include + +// Forward declare Zephyr types to avoid header conflicts +struct device; + +namespace Components { + +class LoadSwitch final : public LoadSwitchComponentBase { + public: + // ---------------------------------------------------------------------- + // Component construction and destruction + // ---------------------------------------------------------------------- + + //! Construct LoadSwitch object + LoadSwitch(const char* const compName //!< The component name + ); + + //! Destroy LoadSwitch object + ~LoadSwitch(); + + private: + // ---------------------------------------------------------------------- + // Handler implementations for commands + // ---------------------------------------------------------------------- + + //! Handler implementation for command TURN_ON + void TURN_ON_cmdHandler(FwOpcodeType opCode, //!< The opcode + U32 cmdSeq //!< The command sequence number + ) override; + + //! Handler implementation for command TURN_OFF + void TURN_OFF_cmdHandler(FwOpcodeType opCode, //!< The opcode + U32 cmdSeq //!< The command sequence number + ) override; + + // ---------------------------------------------------------------------- + // Handler implementations for typed input ports + // ---------------------------------------------------------------------- + + //! Handler implementation for Reset + void Reset_handler(FwIndexType portNum //!< The port number + ) override; + +}; + +} // namespace Components + +#endif diff --git a/FprimeZephyrReference/Components/LoadSwitch/docs/LoadSwitch.svg b/FprimeZephyrReference/Components/LoadSwitch/docs/LoadSwitch.svg new file mode 100644 index 00000000..6bd701fe --- /dev/null +++ b/FprimeZephyrReference/Components/LoadSwitch/docs/LoadSwitch.svg @@ -0,0 +1 @@ +LoadSwitchResettimeCallercmdRegOutcmdIncmdResponseOutlogTextOutlogOuttlmOutprmGetOutprmSetOutgpioSet \ No newline at end of file diff --git a/FprimeZephyrReference/Components/LoadSwitch/docs/sdd.md b/FprimeZephyrReference/Components/LoadSwitch/docs/sdd.md new file mode 100644 index 00000000..51d9dec6 --- /dev/null +++ b/FprimeZephyrReference/Components/LoadSwitch/docs/sdd.md @@ -0,0 +1,53 @@ +# Components::LoadSwitch + +![LoadSwitch](LoadSwitch.svg) + +## Overview + +The `LoadSwitch` component is an active F' component that controls a single load switch output +through the `gpioSet` output port (connected to the platform's GPIO driver). It exposes two +async commands to turn the switch on and off, telemetry reporting the current state, and an +async `Reset` input which toggles the switch (off, short delay, on). + +## Responsibility + +- Control the power rail for a connected peripheral by asserting/deasserting a GPIO. +- Report state changes via an event and telemetry channel. + +## External interface + +### Commands + +| Name | Description | Implementation notes | +|---|---|---| +| TURN_ON | Turn on the associated power rail | `TURN_ON_cmdHandler` sets the gpio via `gpioSet_out(0, Fw::Logic::HIGH)`, emits `StatusChanged` (ON), updates `IsOn` telemetry, replies OK. | +| TURN_OFF | Turn off the associated power rail | `TURN_OFF_cmdHandler` sets the gpio via `gpioSet_out(0, Fw::Logic::LOW)`, emits `StatusChanged` (OFF), updates `IsOn` telemetry, replies OK. | + +### Telemetry + +| Name | Type | Description | +|---|---:|---| +| IsOn | Fw.On | Current power state; written after commands and on Reset handling. | + +### Events + +| Name | Severity | ID | Format | +|---|---|---:|---| +| StatusChanged | activity high | 1 | "Load switch state changed to {}" | + +The component logs the `StatusChanged` event whenever the switch transitions due to a command or a Reset. + +### Ports + +| Port name | Direction | Port type | Notes | +|---|---|---|---| +| gpioSet | output | Drv.GpioWrite | Used to write the physical GPIO. Implementation always uses index 0 (`gpioSet_out(0, ...)`). | +| Reset | input (async) | Fw.Signal | Causes the component to perform a hardware reset sequence: LOW -> wait 100ms -> HIGH. | + + +## Change Log + +| Date | Description | +|---|---| +| 10-22-2025 | Sarah, Kevin, and MoMata's first commit | +| 11-07-2025 | Updated SDD to match implementation in `LoadSwitch.cpp/.hpp/.fpp` (commands, telemetry, event, ports, reset behavior). | diff --git a/FprimeZephyrReference/ReferenceDeployment/Main.cpp b/FprimeZephyrReference/ReferenceDeployment/Main.cpp index 6b5187a8..cc9bc4dd 100644 --- a/FprimeZephyrReference/ReferenceDeployment/Main.cpp +++ b/FprimeZephyrReference/ReferenceDeployment/Main.cpp @@ -16,6 +16,8 @@ const struct device* serial = DEVICE_DT_GET(DT_NODELABEL(cdc_acm_uart0)); 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* lightsensor0 = DEVICE_DT_GET(DT_NODELABEL(face0_light_sens)); +const struct device* lightsensor1 = DEVICE_DT_GET(DT_NODELABEL(face1_light_sens)); int main(int argc, char* argv[]) { // ** DO NOT REMOVE **// @@ -33,6 +35,9 @@ int main(int argc, char* argv[]) { inputs.lsm6dsoDevice = lsm6dso; inputs.lis2mdlDevice = lis2mdl; inputs.baudRate = 115200; + inputs.lightsensor0 = lightsensor0; + inputs.lightsensor1 = lightsensor1; + // Setup, cycle, and teardown topology ReferenceDeployment::setupTopology(inputs); diff --git a/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentPackets.fppi b/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentPackets.fppi index e8e74ee4..d07f5be6 100644 --- a/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentPackets.fppi +++ b/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentPackets.fppi @@ -70,6 +70,27 @@ telemetry packets ReferenceDeploymentPackets { ReferenceDeployment.ina219SolManager.Power } + packet LightSensor id 10 group 4 { + ReferenceDeployment.lightSensor0.ALSLightData + ReferenceDeployment.lightSensor0.RawLightData + ReferenceDeployment.lightSensor0.IRLightData + + ReferenceDeployment.lightSensor1.ALSLightData + ReferenceDeployment.lightSensor1.RawLightData + ReferenceDeployment.lightSensor1.IRLightData + } + + packet LoadSwitches id 11 group 4 { + ReferenceDeployment.face4LoadSwitch.IsOn + ReferenceDeployment.face0LoadSwitch.IsOn + ReferenceDeployment.face1LoadSwitch.IsOn + ReferenceDeployment.face2LoadSwitch.IsOn + ReferenceDeployment.face3LoadSwitch.IsOn + ReferenceDeployment.face5LoadSwitch.IsOn + ReferenceDeployment.payloadPowerLoadSwitch.IsOn + ReferenceDeployment.payloadBatteryLoadSwitch.IsOn + } + } omit { CdhCore.cmdDisp.CommandErrors # Only has one library, no custom versions diff --git a/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentTopology.cpp b/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentTopology.cpp index 0580479a..0d2e41e6 100644 --- a/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentTopology.cpp +++ b/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentTopology.cpp @@ -16,6 +16,14 @@ static const struct gpio_dt_spec ledGpio = GPIO_DT_SPEC_GET(DT_NODELABEL(led0), gpios); static const struct gpio_dt_spec burnwire0Gpio = GPIO_DT_SPEC_GET(DT_NODELABEL(burnwire0), gpios); static const struct gpio_dt_spec burnwire1Gpio = GPIO_DT_SPEC_GET(DT_NODELABEL(burnwire1), gpios); +static const struct gpio_dt_spec face0LoadSwitchGpio = GPIO_DT_SPEC_GET(DT_NODELABEL(face0_enable), gpios); +static const struct gpio_dt_spec face1LoadSwitchGpio = GPIO_DT_SPEC_GET(DT_NODELABEL(face1_enable), gpios); +static const struct gpio_dt_spec face2LoadSwitchGpio = GPIO_DT_SPEC_GET(DT_NODELABEL(face2_enable), gpios); +static const struct gpio_dt_spec face3LoadSwitchGpio = GPIO_DT_SPEC_GET(DT_NODELABEL(face3_enable), gpios); +static const struct gpio_dt_spec face4LoadSwitchGpio = GPIO_DT_SPEC_GET(DT_NODELABEL(face4_enable), gpios); +static const struct gpio_dt_spec face5LoadSwitchGpio = GPIO_DT_SPEC_GET(DT_NODELABEL(face5_enable), gpios); +static const struct gpio_dt_spec payloadPowerLoadSwitchGpio = GPIO_DT_SPEC_GET(DT_NODELABEL(payload_pwr_enable), gpios); +static const struct gpio_dt_spec payloadBatteryLoadSwitchGpio = GPIO_DT_SPEC_GET(DT_NODELABEL(payload_batt_enable), gpios); // Allows easy reference to objects in FPP/autocoder required namespaces using namespace ReferenceDeployment; @@ -57,9 +65,17 @@ void configureTopology() { rateGroup10Hz.configure(rateGroup10HzContext, FW_NUM_ARRAY_ELEMENTS(rateGroup10HzContext)); rateGroup1Hz.configure(rateGroup1HzContext, FW_NUM_ARRAY_ELEMENTS(rateGroup1HzContext)); - gpioDriver.open(ledGpio, Zephyr::ZephyrGpioDriver::GpioConfiguration::OUT); + gpioWatchdog.open(ledGpio, Zephyr::ZephyrGpioDriver::GpioConfiguration::OUT); gpioBurnwire0.open(burnwire0Gpio, Zephyr::ZephyrGpioDriver::GpioConfiguration::OUT); gpioBurnwire1.open(burnwire1Gpio, Zephyr::ZephyrGpioDriver::GpioConfiguration::OUT); + gpioface4LS.open(face4LoadSwitchGpio, Zephyr::ZephyrGpioDriver::GpioConfiguration::OUT); + gpioface0LS.open(face0LoadSwitchGpio, Zephyr::ZephyrGpioDriver::GpioConfiguration::OUT); + gpioface1LS.open(face1LoadSwitchGpio, Zephyr::ZephyrGpioDriver::GpioConfiguration::OUT); + gpioface2LS.open(face2LoadSwitchGpio, Zephyr::ZephyrGpioDriver::GpioConfiguration::OUT); + gpioface3LS.open(face3LoadSwitchGpio, Zephyr::ZephyrGpioDriver::GpioConfiguration::OUT); + gpioface5LS.open(face5LoadSwitchGpio, Zephyr::ZephyrGpioDriver::GpioConfiguration::OUT); + gpioPayloadPowerLS.open(payloadPowerLoadSwitchGpio, Zephyr::ZephyrGpioDriver::GpioConfiguration::OUT); + gpioPayloadBatteryLS.open(payloadBatteryLoadSwitchGpio, Zephyr::ZephyrGpioDriver::GpioConfiguration::OUT); } // Public functions for use in main program are namespaced with deployment name ReferenceDeployment @@ -92,6 +108,8 @@ void setupTopology(const TopologyState& state) { lis2mdlManager.configure(state.lis2mdlDevice); ina219SysManager.configure(state.ina219SysDevice); ina219SolManager.configure(state.ina219SolDevice); + lightSensor0.configure(state.lightsensor0); + lightSensor1.configure(state.lightsensor1); } void startRateGroups() { diff --git a/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentTopologyDefs.hpp b/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentTopologyDefs.hpp index fc9fe0ce..0ae24a71 100644 --- a/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentTopologyDefs.hpp +++ b/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentTopologyDefs.hpp @@ -78,6 +78,9 @@ struct TopologyState { U32 baudRate; //!< Baud rate for UART communication CdhCore::SubtopologyState cdhCore; //!< Subtopology state for CdhCore ComCcsds::SubtopologyState comCcsds; //!< Subtopology state for ComCcsds + const device* lightsensor0; //!< device path for the light sensor + const device* lightsensor1; //!< device path for the light sensor + }; namespace PingEntries = ::PingEntries; diff --git a/FprimeZephyrReference/ReferenceDeployment/Top/instances.fpp b/FprimeZephyrReference/ReferenceDeployment/Top/instances.fpp index 4cf1dbf9..83c3e539 100644 --- a/FprimeZephyrReference/ReferenceDeployment/Top/instances.fpp +++ b/FprimeZephyrReference/ReferenceDeployment/Top/instances.fpp @@ -37,7 +37,8 @@ module ReferenceDeployment { stack size Default.STACK_SIZE \ priority 4 - instance prmDb: Svc.PrmDb base id 0x10003000 \ + + instance prmDb: Svc.PrmDb base id 0x1000B000 \ queue size Default.QUEUE_SIZE \ stack size Default.STACK_SIZE \ priority 5 @@ -58,7 +59,7 @@ module ReferenceDeployment { instance comDriver: Zephyr.ZephyrUartDriver base id 0x10013000 - instance gpioDriver: Zephyr.ZephyrGpioDriver base id 0x10014000 + instance gpioWatchdog: Zephyr.ZephyrGpioDriver base id 0x10014000 instance watchdog: Components.Watchdog base id 0x10015000 @@ -88,11 +89,46 @@ module ReferenceDeployment { instance antennaDeployer: Components.AntennaDeployer base id 0x10029000 - instance fsSpace: Components.FsSpace base id 0x10030000 + instance gpioface4LS: Zephyr.ZephyrGpioDriver base id 0x1002A000 + + instance gpioface0LS: Zephyr.ZephyrGpioDriver base id 0x1002B000 + + instance gpioface1LS: Zephyr.ZephyrGpioDriver base id 0x1002C000 + + instance gpioface2LS: Zephyr.ZephyrGpioDriver base id 0x1002D000 + + instance gpioface3LS: Zephyr.ZephyrGpioDriver base id 0x1002E000 + + instance gpioface5LS: Zephyr.ZephyrGpioDriver base id 0x1002F000 + + instance gpioPayloadPowerLS: Zephyr.ZephyrGpioDriver base id 0x10030000 + + instance gpioPayloadBatteryLS: Zephyr.ZephyrGpioDriver base id 0x10031000 + + instance fsSpace: Components.FsSpace base id 0x10032000 + + instance face4LoadSwitch: Components.LoadSwitch base id 0x10033000 + + instance face0LoadSwitch: Components.LoadSwitch base id 0x10034000 + + instance face1LoadSwitch: Components.LoadSwitch base id 0x10035000 + + instance face2LoadSwitch: Components.LoadSwitch base id 0x10036000 + + instance face3LoadSwitch: Components.LoadSwitch base id 0x10037000 + + instance face5LoadSwitch: Components.LoadSwitch base id 0x10038000 + + instance payloadPowerLoadSwitch: Components.LoadSwitch base id 0x10039000 + + instance payloadBatteryLoadSwitch: Components.LoadSwitch base id 0x1003A000 + + instance powerMonitor: Components.PowerMonitor base id 0x10041000 - instance powerMonitor: Components.PowerMonitor base id 0x10031000 + instance ina219SysManager: Drv.Ina219Manager base id 0x10042000 - instance ina219SysManager: Drv.Ina219Manager base id 0x10032000 + instance ina219SolManager: Drv.Ina219Manager base id 0x10043000 - instance ina219SolManager: Drv.Ina219Manager base id 0x10033000 + instance lightSensor0: Components.LightSensor base id 0x10044000 + instance lightSensor1: Components.LightSensor base id 0x10045000 } diff --git a/FprimeZephyrReference/ReferenceDeployment/Top/topology.fpp b/FprimeZephyrReference/ReferenceDeployment/Top/topology.fpp index 79169a2e..0c60eee4 100644 --- a/FprimeZephyrReference/ReferenceDeployment/Top/topology.fpp +++ b/FprimeZephyrReference/ReferenceDeployment/Top/topology.fpp @@ -26,9 +26,17 @@ module ReferenceDeployment { instance rateGroupDriver instance timer instance lora - instance gpioDriver + instance gpioWatchdog instance gpioBurnwire0 instance gpioBurnwire1 + instance gpioface0LS + instance gpioface1LS + instance gpioface2LS + instance gpioface3LS + instance gpioface4LS + instance gpioface5LS + instance gpioPayloadPowerLS + instance gpioPayloadBatteryLS instance watchdog instance prmDb instance rtcManager @@ -43,10 +51,21 @@ module ReferenceDeployment { instance comSplitterTelemetry # For UART sideband communication instance comDriver + + instance face4LoadSwitch + instance face0LoadSwitch + instance face1LoadSwitch + instance face2LoadSwitch + instance face3LoadSwitch + instance face5LoadSwitch + instance payloadPowerLoadSwitch + instance payloadBatteryLoadSwitch instance fsSpace instance powerMonitor instance ina219SysManager instance ina219SolManager + instance lightSensor0 + instance lightSensor1 # ---------------------------------------------------------------------- @@ -141,12 +160,24 @@ module ReferenceDeployment { rateGroup1Hz.RateGroupMemberOut[8] -> antennaDeployer.schedIn rateGroup1Hz.RateGroupMemberOut[9] -> fsSpace.run rateGroup1Hz.RateGroupMemberOut[10] -> powerMonitor.run - + rateGroup1Hz.RateGroupMemberOut[11] -> lightSensor0.run + rateGroup1Hz.RateGroupMemberOut[12] -> lightSensor1.run } connections Watchdog { - watchdog.gpioSet -> gpioDriver.gpioWrite + watchdog.gpioSet -> gpioWatchdog.gpioWrite + } + + connections LoadSwitches { + face4LoadSwitch.gpioSet -> gpioface4LS.gpioWrite + face0LoadSwitch.gpioSet -> gpioface0LS.gpioWrite + face1LoadSwitch.gpioSet -> gpioface1LS.gpioWrite + face2LoadSwitch.gpioSet -> gpioface2LS.gpioWrite + face3LoadSwitch.gpioSet -> gpioface3LS.gpioWrite + face5LoadSwitch.gpioSet -> gpioface5LS.gpioWrite + payloadPowerLoadSwitch.gpioSet -> gpioPayloadPowerLS.gpioWrite + payloadBatteryLoadSwitch.gpioSet -> gpioPayloadBatteryLS.gpioWrite } connections BurnwireGpio { @@ -175,5 +206,13 @@ module ReferenceDeployment { powerMonitor.solPowerGet -> ina219SolManager.powerGet } + connections lightSensor { + lightSensor0.gpioRead -> gpioface0LS.gpioRead + lightSensor1.gpioRead -> gpioface1LS.gpioRead + + face0LoadSwitch.init -> lightSensor0.init + face1LoadSwitch.init -> lightSensor1.init + } + } } diff --git a/FprimeZephyrReference/project/config/CdhCoreConfig.fpp b/FprimeZephyrReference/project/config/CdhCoreConfig.fpp index 40ad28a8..9e2e2df2 100644 --- a/FprimeZephyrReference/project/config/CdhCoreConfig.fpp +++ b/FprimeZephyrReference/project/config/CdhCoreConfig.fpp @@ -3,7 +3,7 @@ module CdhCoreConfig { constant BASE_ID = 0x01000000 module QueueSizes { - constant cmdDisp = 10 + constant cmdDisp = 20 constant events = 25 constant tlmSend = 5 constant $health = 10 diff --git a/FprimeZephyrReference/project/config/CommandDispatcherImplCfg.hpp b/FprimeZephyrReference/project/config/CommandDispatcherImplCfg.hpp index ab88a46b..350367d4 100644 --- a/FprimeZephyrReference/project/config/CommandDispatcherImplCfg.hpp +++ b/FprimeZephyrReference/project/config/CommandDispatcherImplCfg.hpp @@ -11,7 +11,7 @@ // Define configuration values for dispatcher enum { - CMD_DISPATCHER_DISPATCH_TABLE_SIZE = 50, // !< The size of the table holding opcodes to dispatch + CMD_DISPATCHER_DISPATCH_TABLE_SIZE = 100, // !< The size of the table holding opcodes to dispatch CMD_DISPATCHER_SEQUENCER_TABLE_SIZE = 10, // !< The size of the table holding commands in progress }; diff --git a/FprimeZephyrReference/project/config/TlmPacketizerCfg.hpp b/FprimeZephyrReference/project/config/TlmPacketizerCfg.hpp index 9bbbda05..a8ab8e8d 100644 --- a/FprimeZephyrReference/project/config/TlmPacketizerCfg.hpp +++ b/FprimeZephyrReference/project/config/TlmPacketizerCfg.hpp @@ -16,7 +16,7 @@ #include namespace Svc { -static const FwChanIdType MAX_PACKETIZER_PACKETS = 10; +static const FwChanIdType MAX_PACKETIZER_PACKETS = 11; static const FwChanIdType TLMPACKETIZER_NUM_TLM_HASH_SLOTS = 15; // !< Number of slots in the hash table. // Works best when set to about twice the number of components producing telemetry diff --git a/FprimeZephyrReference/test/int/load_switch_test.py b/FprimeZephyrReference/test/int/load_switch_test.py new file mode 100644 index 00000000..e1f7a651 --- /dev/null +++ b/FprimeZephyrReference/test/int/load_switch_test.py @@ -0,0 +1,82 @@ +""" +load_switch_test.py: + +Integration tests for the Load-Switch component. +""" + +import time + +import pytest +from common import proves_send_and_assert_command +from fprime_gds.common.data_types.ch_data import ChData +from fprime_gds.common.testing_fw.api import IntegrationTestAPI + +loadswitch = "ReferenceDeployment.loadswitch" + +@pytest.fixture(autouse=True) +def ensure_loadswitch_off(fprime_test_api: IntegrationTestAPI, start_gds): + """Ensure LoadSwitch starts in OFF state""" + turn_off(fprime_test_api) + yield + turn_off(fprime_test_api) + +def turn_on(fprime_test_api: IntegrationTestAPI): + """Helper function to turn on the loadswitch""" + proves_send_and_assert_command( + fprime_test_api, + f"{loadswitch}.TURN_ON", + ) + +def turn_off(fprime_test_api: IntegrationTestAPI): + """Helper function to turn off the loadswitch""" + proves_send_and_assert_command( + fprime_test_api, + f"{loadswitch}.TURN_OFF" + ) + +def get_is_on(fprime_test_api: IntegrationTestAPI) -> int: + """Helper function to request packet and get fresh IsOn telemetry""" + proves_send_and_assert_command( + fprime_test_api, + "CdhCore.tlmSend.SEND_PKT", + ["9"], + ) + result: ChData = fprime_test_api.assert_telemetry( + f"{loadswitch}.IsOn", start="NOW", timeout=3 + ) + return result.get_val() + +def test_01_loadswitch_telemetry_basic(fprime_test_api: IntegrationTestAPI, start_gds): + """Test that we can read IsOn telemetry""" + value = get_is_on(fprime_test_api) + assert value in (0, 1), f"IsOn should be 0 or 1, got {value}" + +def test_02_turn_on_sets_high(fprime_test_api: IntegrationTestAPI, start_gds): + """ + Test TURN_ON command sets GPIO high, emits ON event, and updates telemetry + """ + + # Send turn_on command + turn_on(fprime_test_api) + + # Confirm Load-Switch turned ON + fprime_test_api.assert_event(f"{loadswitch}.StatusChanged", args=[1], timeout=2) + + # Confirm telemetry IsOn is 1 + value = get_is_on(fprime_test_api) + assert value == 1, f"Expected IsOn = 1 after TURN_ON, got {value}" + +def test_03_turn_off_sets_low(fprime_test_api: IntegrationTestAPI, start_gds): + """ + Test TURN_OFF command sets GPIO low, emits OFF event, and updates telemetry + """ + + # Send turn_on command + turn_off(fprime_test_api) + + # Confirm Load-Switch turned OFF + fprime_test_api.assert_event(f"{loadswitch}.StatusChanged", args=[0], timeout=2) + + # Confirm telemetry IsOn is 0 + value = get_is_on(fprime_test_api) + assert value == 0, f"Expected IsOn = 0 after TURN_OFF, got {value}" \ No newline at end of file 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 363ac07c..78a999de 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 @@ -163,6 +163,209 @@ zephyr_udc0: &usbd { lsb-microamp = <61>; label = "INA219 sol"; }; + + tca9548a: tca9548a@77 { + compatible = "ti,tca9548a"; + status = "okay"; + zephyr,deferred-init; + reg = <0x77>; + #address-cells = <1>; + #size-cells = <0>; + label = "TCA9548A"; + reset-gpios = <&gpio0 26 GPIO_ACTIVE_LOW>; + + face0_i2c: i2c_mux@0 { + compatible = "ti,tca9548a-channel"; + label = "face0_i2c"; + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + zephyr,deferred-init; + + face0_light_sens: light@29 { + compatible = "vishay,veml6031"; + reg = <0x29>; + status = "okay"; + zephyr,deferred-init; + }; + + face0_drv2605: drv2605@5a { + compatible = "ti,drv2605"; + status = "okay"; + reg = <0x5a>; + label = "FACE0_DRV2605"; + + actuator-mode = "LRA"; + loop-gain = "HIGH"; + feedback-brake-factor = "2X"; + }; + }; + + i2c_mux@1 { + compatible = "ti,tca9548a-channel"; + label = "face1_i2c"; + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + face1_light_sens: light@29 { + compatible = "vishay,veml6031"; + reg = <0x29>; + status = "okay"; + zephyr,deferred-init; + }; + + face1_drv2605: drv2605@5a { + compatible = "ti,drv2605"; + status = "okay"; + reg = <0x5a>; + label = "FACE1_DRV2605"; + + actuator-mode = "LRA"; + loop-gain = "HIGH"; + feedback-brake-factor = "2X"; + }; + }; + + i2c_mux@2 { + compatible = "ti,tca9548a-channel"; + label = "face2_i2c"; + reg = <2>; + #address-cells = <1>; + #size-cells = <0>; + face2_light_sens: light@29 { + compatible = "vishay,veml6031"; + reg = <0x29>; + status = "okay"; + }; + + face2_drv2605: drv2605@5a { + compatible = "ti,drv2605"; + status = "okay"; + reg = <0x5a>; + label = "FACE2_DRV2605"; + + actuator-mode = "LRA"; + loop-gain = "HIGH"; + feedback-brake-factor = "2X"; + }; + }; + + i2c_mux@3 { + compatible = "ti,tca9548a-channel"; + label = "face3_i2c"; + reg = <3>; + #address-cells = <1>; + #size-cells = <0>; + face3_light_sens: light@29 { + compatible = "vishay,veml6031"; + reg = <0x29>; + status = "okay"; + }; + + face3_drv2605: drv2605@5a { + compatible = "ti,drv2605"; + status = "okay"; + reg = <0x5a>; + label = "FACE3_DRV2605"; + + actuator-mode = "LRA"; + loop-gain = "HIGH"; + feedback-brake-factor = "2X"; + }; + }; + + i2c_mux@4 { + compatible = "ti,tca9548a-channel"; + label = "battery_i2c"; + reg = <4>; + #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"; + }; + }; + + i2c_mux@5 { + compatible = "ti,tca9548a-channel"; + label = "face4_i2c"; + reg = <5>; + #address-cells = <1>; + #size-cells = <0>; + face4_light_sens: light@29 { + compatible = "vishay,veml6031"; + reg = <0x29>; + status = "okay"; + }; + + face4_drv2605: drv2605@5a { + compatible = "ti,drv2605"; + status = "okay"; + reg = <0x5a>; + label = "FACE4_DRV2605"; + + actuator-mode = "LRA"; + loop-gain = "HIGH"; + feedback-brake-factor = "2X"; + }; + }; + + i2c_mux@6 { + compatible = "ti,tca9548a-channel"; + label = "face5_i2c"; + reg = <6>; + #address-cells = <1>; + #size-cells = <0>; + face5_light_sens: light@29 { + compatible = "vishay,veml6031"; + reg = <0x29>; + status = "okay"; + }; + + face5_drv2605: drv2605@5a { + compatible = "ti,drv2605"; + status = "okay"; + reg = <0x5a>; + label = "FACE5_DRV2605"; + + actuator-mode = "LRA"; + loop-gain = "HIGH"; + feedback-brake-factor = "2X"; + }; + }; + + i2c_mux@7 { + compatible = "ti,tca9548a-channel"; + label = "top_i2c"; + reg = <7>; + #address-cells = <1>; + #size-cells = <0>; + top_temp_sens: tmp112@48 { + compatible = "ti,tmp112"; + reg = <0x48>; + status = "okay"; + }; + }; + + + }; }; @@ -190,4 +393,155 @@ zephyr_udc0: &usbd { backup-switch-mode = "direct"; label = "RV3028"; }; + ina219: ina219@40 { + compatible = "ti,ina219"; + reg = <0x40>; + shunt-milliohm = <2>; + lsb-microamp = <100>; + label = "INA219"; + }; + mcp23017: mcp23017@20 { + compatible = "microchip,mcp23017"; + reg = <0x20>; + gpio-controller; + #gpio-cells = <2>; + + /* gpio-line-names must match the numeric indexes used below. The + * topology and gpio nodes expect the following mapping (index : name): + * 0: ENABLE_HEATER (GPA0) + * 1: PAYLOAD_PWR_ENABLE (GPA1) + * 2: FIRE_DEPLOY2_B (GPA2) + * 3: PAYLOAD_BATT_ENABLE (GPA3) + * 4: RF2_IO2 (GPA4) + * 5: RF2_IO1 (GPA5) + * 6: RF2_IO0 (GPA6) + * 7: RF2_IO3 (GPA7) + * 8: FACE4_ENABLE (GPB0) + * 9: FACE0_ENABLE (GPB1) + * 10: FACE1_ENABLE (GPB2) + * 11: FACE2_ENABLE (GPB3) + * 12: FACE3_ENABLE (GPB4) + * 13: FACE5_ENABLE (GPB5) + * 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"; + + reset-gpios = <&gpio0 20 GPIO_ACTIVE_LOW>; + + ngpios = <16>; + }; +}; + +// GPIO Expander IO +/ { + + // Define the GPIO outputs based on your schematic + gpio_outputs { + compatible = "gpio-leds"; // Using gpio-leds as a convenient container + + face4_enable: face4-enable { + + gpios = <&mcp23017 8 GPIO_ACTIVE_HIGH>; // GPB0 + label = "FACE4_ENABLE"; + }; + + face0_enable: face0-enable { + + gpios = <&mcp23017 9 GPIO_ACTIVE_HIGH>; // GPB1 + label = "FACE0_ENABLE"; + }; + + face1_enable: face1-enable { + + gpios = <&mcp23017 10 GPIO_ACTIVE_HIGH>; // GPB2 + label = "FACE1_ENABLE"; + }; + + face2_enable: face2-enable { + + gpios = <&mcp23017 11 GPIO_ACTIVE_HIGH>; // GPB3 + label = "FACE2_ENABLE"; + }; + + face3_enable: face3-enable { + + gpios = <&mcp23017 12 GPIO_ACTIVE_HIGH>; // GPB4 + label = "FACE3_ENABLE"; + }; + + face5_enable: face5-enable { + + gpios = <&mcp23017 13 GPIO_ACTIVE_HIGH>; // GPB5 + label = "FACE5_ENABLE"; + }; + + enable_heater: enable-heater { + + gpios = <&mcp23017 0 GPIO_ACTIVE_HIGH>; // GPA0 + label = "ENABLE_Heater"; + }; + + payload_pwr_enable: payload-pwr-enable { + + gpios = <&mcp23017 1 GPIO_ACTIVE_HIGH>; // GPA1 + label = "PAYLOAD_PWR_ENABLE"; + }; + + fire_deploy2_b: fire-deploy2-b { + + gpios = <&mcp23017 2 GPIO_ACTIVE_HIGH>; // GPA2 + label = "FIRE_DEPLOY2_B"; + }; + + payload_batt_enable: payload-batt-enable { + + gpios = <&mcp23017 3 GPIO_ACTIVE_HIGH>; // GPA3 + label = "PAYLOAD_BATT_ENABLE"; + }; + }; + + // Define GPIO inputs + gpio_inputs { + compatible = "gpio-keys"; + + charge: charge { + + gpios = <&mcp23017 16 GPIO_ACTIVE_HIGH>; // GPB7 + label = "CHARGE"; + }; + + readonly: readonly { + + gpios = <&mcp23017 15 GPIO_ACTIVE_HIGH>; // GPB6 + label = "READONLY"; + }; + + rf2_io2: rf2-io2 { + + gpios = <&mcp23017 4 GPIO_ACTIVE_HIGH>; // GPA4 + label = "RF2_IO2"; + }; + + rf2_io1: rf2-io1 { + + gpios = <&mcp23017 5 GPIO_ACTIVE_HIGH>; // GPA5 + label = "RF2_IO1"; + }; + + rf2_io0: rf2-io0 { + + gpios = <&mcp23017 6 GPIO_ACTIVE_HIGH>; // GPA6 + label = "RF2_IO0"; + }; + + rf2_io3: rf2-io3 { + + gpios = <&mcp23017 7 GPIO_ACTIVE_HIGH>; // GPA7 + label = "RF2_IO3"; + }; + }; }; diff --git a/prj.conf b/prj.conf index b1e35675..897c86b2 100644 --- a/prj.conf +++ b/prj.conf @@ -32,6 +32,12 @@ CONFIG_SPI=y CONFIG_PINCTRL=y CONFIG_ASSERT=y +#### I2C Multiplexer Configuration #### +CONFIG_I2C_TCA954X=y +CONFIG_I2C_TCA954X_ROOT_INIT_PRIO=50 +CONFIG_I2C_TCA954X_CHANNEL_INIT_PRIO=51 +CONFIG_VEML6031=y + CONFIG_DYNAMIC_THREAD=y CONFIG_KERNEL_MEM_POOL=y CONFIG_DYNAMIC_THREAD_ALLOC=n @@ -39,6 +45,7 @@ CONFIG_DYNAMIC_THREAD_PREFER_POOL=y CONFIG_DYNAMIC_THREAD_POOL_SIZE=15 # Num threads in the thread pool CONFIG_DYNAMIC_THREAD_STACK_SIZE=8192 + # Size of thread stack in thread pool, must be >= Thread Pool size in F' CONFIG_THREAD_STACK_INFO=y