diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 458d52eb..516d6c99 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1,6 +1,7 @@ # Proves Core Reference Project - Copilot Instructions ## Project Overview + This is a reference software implementation for the [Proves Kit](https://docs.proveskit.space/en/latest/), combining F Prime (NASA's flight software framework) with Zephyr RTOS to create firmware for embedded flight control boards. The project targets ARM Cortex-M microcontrollers, specifically RP2350 (Raspberry Pi Pico 2) and STM32 boards. **Repository Size**: ~450MB (primarily from Zephyr workspace and F Prime submodules) @@ -11,20 +12,25 @@ This is a reference software implementation for the [Proves Kit](https://docs.pr ## Critical Build Prerequisites ### System Dependencies + Before any build steps, ensure you have: + - Python 3.13+ (specified in `.python-version`) - F Prime system requirements: https://fprime.jpl.nasa.gov/latest/docs/getting-started/installing-fprime/#system-requirements - Zephyr dependencies: https://docs.zephyrproject.org/latest/develop/getting_started/index.html#install-dependencies - **NOTE**: Only install dependencies; do NOT run Zephyr's full setup (handled by Makefile) ### Build Tool: UV Package Manager + This project uses **UV** (v0.8.13) for Python environment management. It is automatically downloaded by the Makefile. + - Do NOT use `pip` or `python -m venv` directly - Always use `make` targets which invoke UV internally ## Build & Test Workflow ### First-Time Setup (Complete Sequence) + Run these commands **in order** from the repository root. The entire setup takes ~5-10 minutes: ```bash @@ -47,6 +53,7 @@ make build **IMPORTANT**: The `make` command (default target) runs all of the above automatically. **Alternative Zephyr Setup**: The new Makefile structure provides more granular Zephyr control: + ```bash # Complete Zephyr setup (equivalent to zephyr-setup) make zephyr @@ -62,24 +69,28 @@ make zephyr-sdk # Install SDK ### Development Workflow **After making code changes**: + ```bash # Always run build (it calls generate-if-needed automatically) make build ``` **When to run generate explicitly**: + - After modifying `.fpp` files (F Prime component definitions) - After changing CMakeLists.txt files - After modifying core F Prime package files - Command: `make generate` ### Linting & Formatting + ```bash # Run all pre-commit checks (REQUIRED before committing) make fmt ``` This runs: + - `clang-format` (C/C++ formatting) - `cpplint` (C++ style checking using `cpplint.cfg`) - `ruff` (Python linting and formatting) @@ -107,6 +118,7 @@ make test-integration ``` **Test Framework Details**: + - **Location**: `FprimeZephyrReference/test/int/` - **Framework**: pytest with fprime-gds testing API - **Test Files**: @@ -117,12 +129,14 @@ make test-integration - **Communication**: Tests communicate with the board via GDS over UART **Test Prerequisites**: + 1. Board must be connected via USB (appears as CDC ACM device) 2. Firmware must be flashed and running 3. GDS must be running and connected to the board 4. Board must be in operational state (not in bootloader mode) **Test Examples**: + - **Watchdog Tests**: Start/stop watchdog, verify transition counting - **IMU Tests**: Send telemetry packets, verify acceleration data - **RTC Tests**: Set/get time, verify time synchronization @@ -130,6 +144,7 @@ make test-integration ## Project Structure ### Repository Root Files + ``` CMakeLists.txt # Top-level CMake configuration CMakePresets.json # CMake presets for Zephyr build @@ -144,13 +159,14 @@ requirements.txt # Python dependencies ``` ### Directory Structure + ``` FprimeZephyrReference/ ├── Components/ # Custom F Prime components │ ├── BootloaderTrigger/ │ ├── Drv/ # Driver components (IMU, RTC, sensor managers) │ ├── FatalHandler/ -│ ├── ImuManager/ +│ ├── DetumbleManager/ │ └── Watchdog/ ├── ReferenceDeployment/ │ ├── Main.cpp # Application entry point @@ -181,6 +197,7 @@ docs/ ### Key Architecture Points **F Prime + Zephyr Integration**: + - F Prime components defined in `.fpp` files (autocoded to C++) - Zephyr handles RTOS, drivers, and hardware abstraction - Main entry point: `FprimeZephyrReference/ReferenceDeployment/Main.cpp` @@ -191,9 +208,11 @@ docs/ ## Board Variations & Hardware Configuration ### Available Board Versions + The project supports multiple variants of the PROVES Flight Control Board, all based on the RP2350 (Raspberry Pi Pico 2) microcontroller: **Base Board (`proves_flight_control_board_v5`)**: + - Common hardware definition shared by all variants - Defines sensors: LSM6DSO (IMU), LIS2MDL (magnetometer), INA219 (current sensor) - LoRa radio: SX1276 with SPI interface @@ -202,12 +221,14 @@ The project supports multiple variants of the PROVES Flight Control Board, all b - Watchdog LED on GPIO 23 (base configuration) **Variant C (`proves_flight_control_board_v5c`)**: + - **Key Difference**: Watchdog LED moved to GPIO 24 - LoRa DIO pins: GPIO 13 and GPIO 12 (different from base) - USB Product ID: "PROVES Flight Control Board v5c" - As we develop, probably other differences will be noticed **Variant D (`proves_flight_control_board_v5d`)**: + - **Key Difference**: Uses base board configuration (LED on GPIO 23) - LoRa DIO pins: GPIO 14 and GPIO 13 (base configuration) - USB Product ID: "PROVES Flight Control Board v5d" @@ -215,12 +236,14 @@ The project supports multiple variants of the PROVES Flight Control Board, all b - **Default Board**: This is the default in `settings.ini` ### Board Selection + - **Default**: Set in `settings.ini` (`BOARD=proves_flight_control_board_v5d/rp2350a/m33`) - **Override**: Use CMake option `-DBOARD=//` - **Available SOCs**: `rp2350a` (Raspberry Pi Pico 2) - **Available Cores**: `m33` (ARM Cortex-M33) **Component Types**: + - `.fpp` files: F Prime component definitions (autocoded) - `.cpp/.hpp` files: Implementation code - `CMakeLists.txt` in each component: Build registration @@ -228,6 +251,7 @@ The project supports multiple variants of the PROVES Flight Control Board, all b ## Build System Details ### Generated Artifacts Location + ``` build-fprime-automatic-zephyr/ # F Prime + Zephyr build cache build-artifacts/ @@ -237,6 +261,7 @@ build-artifacts/ ``` ### CMake Configuration + - **Toolchain**: `lib/fprime-zephyr/cmake/toolchain/zephyr.cmake` - **Build Type**: Release - **Board Root**: Repository root (custom board definitions in `boards/`) @@ -245,6 +270,7 @@ build-artifacts/ - `FPRIME_ENABLE_AUTOCODER_UTS=OFF` (no autocoder unit tests) ### Makefile Targets Reference + ```bash make help # Show all available targets make submodules # Initialize git submodules @@ -266,6 +292,7 @@ make minimize-uv-cache # Minimize UV cache (CI optimization) ``` **Zephyr-Specific Targets** (from `lib/makelib/zephyr.mk`): + ```bash make zephyr # Complete Zephyr setup (config + workspace + export + deps + SDK) make zephyr-config # Configure west @@ -283,6 +310,7 @@ make clean-zephyr-sdk # Remove Zephyr SDK ### CI/CD Pipeline (`.github/workflows/ci.yaml`) **Jobs**: + 1. **Lint**: Runs `make fmt` (pre-commit checks) 2. **Build**: Full build with caching - Caches: bin tools, submodules, Python venv, Zephyr workspace @@ -290,6 +318,7 @@ make clean-zephyr-sdk # Remove Zephyr SDK - Uploads: `build-artifacts/zephyr.uf2` and dictionary JSON **Critical for CI Success**: + - Always run `make fmt` before pushing - Ensure code builds with `make build` locally - Integration tests are NOT run in CI (require hardware) @@ -297,29 +326,39 @@ make clean-zephyr-sdk # Remove Zephyr SDK ## Common Issues & Workarounds ### Issue: Build Fails with "west not found" + **Solution**: Run `make zephyr-setup` to install west and Zephyr SDK. ### Issue: "No such file or directory: fprime-util" + **Solution**: Run `make fprime-venv` to create virtual environment with dependencies. ### Issue: CMake cache errors after changing board configuration + **Solution**: Run `make clean` followed by `make generate build`. ### Issue: USB device not detected on board + **Workaround**: The board may need to be put into bootloader mode. Use the new bootloader target: + ```bash make bootloader ``` + This automatically detects if the board is already in bootloader mode and triggers it if needed. See board-specific guides in `docs/additional-resources/board-list.md`. ### Issue: Integration tests fail to connect + **Solution**: Ensure GDS is running (`make gds`) and board is connected. Check serial port in GDS output. ### Issue: Build times out (>2 minutes) + **Solution**: First build takes 3-5 minutes. Subsequent builds are faster (~30 seconds). Use `timeout: 300` for initial builds. ### Issue: Flashing firmware to board + **Different boards require different methods**: + - **RP2040/RP2350**: Copy `.uf2` file to board's USB mass storage ```bash cp build-artifacts/zephyr.uf2 /Volumes/RPI-RP2 # macOS @@ -334,6 +373,7 @@ This automatically detects if the board is already in bootloader mode and trigge ## File Modification Guidelines ### When modifying F Prime components: + 1. Edit `.fpp` files for interface changes (ports, commands, telemetry, events) 2. Edit `.cpp/.hpp` files for implementation 3. Run `make generate` to regenerate autocoded files @@ -346,6 +386,7 @@ This automatically detects if the board is already in bootloader mode and trigge The `ReferenceDeploymentTopology` is the central coordination point for the F Prime application: **Key Files**: + - `FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentTopology.cpp` - Main topology implementation - `FprimeZephyrReference/ReferenceDeployment/Top/topology.fpp` - FPP topology definition - `FprimeZephyrReference/ReferenceDeployment/Top/instances.fpp` - Component instances @@ -359,12 +400,14 @@ static const struct gpio_dt_spec ledGpio = GPIO_DT_SPEC_GET(DT_NODELABEL(led0), ``` **DT_NODE Explanation**: + - `DT_NODELABEL(led0)` - References the `led0` node from device tree - `GPIO_DT_SPEC_GET()` - Extracts GPIO specification (port, pin, flags) - Device tree defines hardware mapping: `led0: led0 { gpios = <&gpio0 23 GPIO_ACTIVE_HIGH>; }` - Board variants override these mappings (e.g., v5c uses GPIO 24, v5d uses GPIO 23) **Topology Initialization Sequence**: + 1. `initComponents()` - Initialize all F Prime components 2. `setBaseIds()` - Set component ID offsets 3. `connectComponents()` - Wire component ports together @@ -374,16 +417,19 @@ static const struct gpio_dt_spec ledGpio = GPIO_DT_SPEC_GET(DT_NODELABEL(led0), 7. `startTasks()` - Start active component tasks **Hardware Integration**: + - Topology bridges F Prime components with Zephyr device drivers - Uses device tree nodes to access sensors, GPIO, UART, etc. - Board-specific configurations handled through device tree overlays ### When modifying topology: + 1. Edit `FprimeZephyrReference/ReferenceDeployment/Top/instances.fpp` for new component instances 2. Edit `FprimeZephyrReference/ReferenceDeployment/Top/topology.fpp` for connections 3. Run `make generate build` ### When adding new components: + 1. Create component directory under `FprimeZephyrReference/Components/` 2. Add `CMakeLists.txt` with `register_fprime_library()` or `register_fprime_module()` 3. Add component to parent `CMakeLists.txt` with `add_fprime_subdirectory()` @@ -395,24 +441,28 @@ static const struct gpio_dt_spec ledGpio = GPIO_DT_SPEC_GET(DT_NODELABEL(led0), The `ReferenceDeploymentTopology` serves as the central coordinator that bridges F Prime components with Zephyr hardware drivers through Device Tree nodes. **Key Topology Files**: + - `FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentTopology.cpp` - Main implementation - `FprimeZephyrReference/ReferenceDeployment/Top/topology.fpp` - FPP topology definition - `FprimeZephyrReference/ReferenceDeployment/Top/instances.fpp` - Component instances - `FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentTopologyDefs.hpp` - Type definitions **DT_NODE Usage Pattern**: + ```cpp // Example from ReferenceDeploymentTopology.cpp static const struct gpio_dt_spec ledGpio = GPIO_DT_SPEC_GET(DT_NODELABEL(led0), gpios); ``` **How DT_NODE Works**: + 1. **Device Tree Definition**: Hardware is defined in `.dts` files (e.g., `led0: led0 { gpios = <&gpio0 23 GPIO_ACTIVE_HIGH>; }`) 2. **DT_NODELABEL**: References the device tree node by label (`led0`) 3. **GPIO_DT_SPEC_GET**: Extracts GPIO specification (port, pin, flags) at compile time 4. **Board Variants**: Different boards override these mappings (v5c uses GPIO 24, v5d uses GPIO 23) **Topology Initialization Sequence**: + ```cpp void setupTopology(const TopologyState& state) { initComponents(state); // 1. Initialize F Prime components @@ -426,6 +476,7 @@ void setupTopology(const TopologyState& state) { ``` **Hardware Integration Points**: + - **GPIO Access**: `GPIO_DT_SPEC_GET(DT_NODELABEL(led0), gpios)` for LED control - **UART Communication**: Device tree defines CDC ACM UART for console/GDS - **Sensor Access**: I2C/SPI devices defined in device tree (LSM6DSO, LIS2MDL, etc.) @@ -433,12 +484,14 @@ void setupTopology(const TopologyState& state) { **Adding Hardware-Accessing Components**: When creating components that need hardware access: + 1. Define device tree nodes in board `.dts` files 2. Use `DT_NODELABEL()` and `GPIO_DT_SPEC_GET()` in component code 3. Add component to topology in `instances.fpp` and `topology.fpp` 4. Configure hardware access in `ReferenceDeploymentTopology.cpp` ### When modifying board configuration: + 1. Edit `settings.ini` to change default board 2. Or use CMake option: `cmake -DBOARD=` 3. Board definitions are in `boards/bronco_space/` @@ -447,13 +500,16 @@ When creating components that need hardware access: ## Additional Repository Information ### Build Artifacts & Outputs + - **Firmware Binary**: `build-artifacts/zephyr.uf2` (for RP2040/RP2350 boards) - **Firmware Hex**: `build-artifacts/zephyr.hex` (for STM32 boards) - **Dictionary**: `build-artifacts/zephyr/fprime-zephyr-deployment/dict/ReferenceDeploymentTopologyDictionary.json` - **Build Cache**: `build-fprime-automatic-zephyr/` (F Prime + Zephyr build directory) ### Component Architecture + The project includes several custom F Prime components: + - **Watchdog**: Hardware watchdog management with LED indication - **IMU Manager**: LSM6DSO 6-axis IMU sensor management - **LIS2MDL Manager**: 3-axis magnetometer management @@ -462,6 +518,7 @@ The project includes several custom F Prime components: - **Fatal Handler**: System error handling and recovery ### Development Environment + - **Python Version**: 3.13+ (specified in `.python-version`) - **Package Manager**: UV v0.8.13 (automatically downloaded) - **Virtual Environment**: `fprime-venv/` (created by Makefile) @@ -469,12 +526,15 @@ The project includes several custom F Prime components: - **West Workspace**: `.west/` (Zephyr workspace configuration) ### Git Submodules + The repository uses three main submodules: + - `lib/fprime/` - F Prime framework (NASA's flight software framework) - `lib/fprime-zephyr/` - F Prime-Zephyr integration layer - `lib/zephyr-workspace/` - Zephyr RTOS workspace ### Configuration Files + - `settings.ini` - F Prime project settings and default board - `prj.conf` - Zephyr project configuration (USB, I2C, SPI, sensors) - `CMakePresets.json` - CMake presets for different build configurations @@ -485,6 +545,7 @@ The repository uses three main submodules: ## Trust These Instructions These instructions are comprehensive and validated. **Only search for additional information if**: + - Instructions are incomplete for your specific task - You encounter errors not covered in "Common Issues" - You need board-specific flashing instructions (see docs/) diff --git a/FprimeZephyrReference/Components/CMakeLists.txt b/FprimeZephyrReference/Components/CMakeLists.txt index 9b9cab94..519151d7 100644 --- a/FprimeZephyrReference/Components/CMakeLists.txt +++ b/FprimeZephyrReference/Components/CMakeLists.txt @@ -6,8 +6,9 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Burnwire/") 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}/DetumbleManager/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FsSpace/") -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}/LoadSwitch/") diff --git a/FprimeZephyrReference/Components/DetumbleManager/CMakeLists.txt b/FprimeZephyrReference/Components/DetumbleManager/CMakeLists.txt new file mode 100644 index 00000000..bf6c13b9 --- /dev/null +++ b/FprimeZephyrReference/Components/DetumbleManager/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}/DetumbleManager.fpp" + SOURCES + "${CMAKE_CURRENT_LIST_DIR}/DetumbleManager.cpp" +# DEPENDS +# MyPackage_MyOtherModule +) + +### Unit Tests ### +# register_fprime_ut( +# AUTOCODER_INPUTS +# "${CMAKE_CURRENT_LIST_DIR}/DetumbleManager.fpp" +# SOURCES +# "${CMAKE_CURRENT_LIST_DIR}/test/ut/DetumbleManagerTestMain.cpp" +# "${CMAKE_CURRENT_LIST_DIR}/test/ut/DetumbleManagerTester.cpp" +# DEPENDS +# STest # For rules-based testing +# UT_AUTO_HELPERS +# ) diff --git a/FprimeZephyrReference/Components/DetumbleManager/DetumbleManager.cpp b/FprimeZephyrReference/Components/DetumbleManager/DetumbleManager.cpp new file mode 100644 index 00000000..fe31268d --- /dev/null +++ b/FprimeZephyrReference/Components/DetumbleManager/DetumbleManager.cpp @@ -0,0 +1,117 @@ +// ====================================================================== +// \title DetumbleManager.cpp +// \brief cpp file for DetumbleManager component implementation class +// ====================================================================== + +#include "FprimeZephyrReference/Components/DetumbleManager/DetumbleManager.hpp" + +#include +#include +#include + +namespace Components { + +// ---------------------------------------------------------------------- +// Component construction and destruction +// ---------------------------------------------------------------------- + +DetumbleManager ::DetumbleManager(const char* const compName) : DetumbleManagerComponentBase(compName) {} + +DetumbleManager ::~DetumbleManager() {} + +// ---------------------------------------------------------------------- +// Handler implementations for typed input ports +// ---------------------------------------------------------------------- + +void DetumbleManager ::run_handler(FwIndexType portNum, U32 context) { + U32 currTime = this->getTime().getSeconds(); + + // I'm not checking the value of isValid for paramGet calls since all of the parameters have a + // default value, but maybe there should still be specific logging for if the default parameter + // was used and retrieval failed. + Fw::ParamValid isValid; + + if (this->detumbleRunning) { + // Check if we've hit the max time detumble can run + U32 maxTime = this->paramGet_MAX_TIME(isValid); + if (currTime - this->startTime <= maxTime) { + bool res = this->executeControlStep(); + if (!res) { + // Log some error + } + + this->iterations++; + + // Every 10 iterations (every second), check if the rotation per second is less than 12 degrees + if (this->iterations % 10 == 0) { + Drv::AngularVelocity angVel = this->angularVelocityGet_out(0); + F64 rotationRate = this->getAngularVelocityMagnitude(angVel); + + F64 threshold = this->paramGet_ROTATIONAL_THRESHOLD(isValid); + if (rotationRate < threshold) { + // Rotation is below threshold - can stop detumbling + this->detumbleRunning = false; + this->lastCompleted = currTime; + } + } + } else { + // Max time reached, disable detumble for now + this->detumbleRunning = false; + this->lastCompleted = currTime; + } + } else { + // Check if the cooldown has ended, and start if so. + if (currTime - this->lastCompleted >= this->paramGet_COOLDOWN(isValid)) { + this->detumbleRunning = true; + this->startTime = currTime; + } + } +} + +bool DetumbleManager::executeControlStep() { + Drv::MagneticField mgField = this->magneticFieldGet_out(0); + if (this->prevMgField == this->EMPTY_MG_FIELD) { + this->prevMgField = mgField; + } + + Drv::DipoleMoment dpMoment = this->dipoleMomentGet_out(0, mgField, this->prevMgField); + if (dpMoment == this->EMPTY_DP_MOMENT) { + // Log some kinda error + return false; + } + + this->prevMgField = mgField; + this->setDipoleMoment(dpMoment); + + return true; +} +void DetumbleManager::setDipoleMoment(Drv::DipoleMoment dpMoment) { + // Convert dipole moment to (unlimited) current + F64 unlimited_x = dpMoment.get_x() / (this->COIL_NUM_TURNS_X_Y * this->COIL_AREA_X_Y); + F64 unlimited_y = dpMoment.get_y() / (this->COIL_NUM_TURNS_X_Y * this->COIL_AREA_X_Y); + F64 unlimited_z = dpMoment.get_z() / (this->COIL_NUM_TURNS_Z * this->COIL_AREA_Z); + + // Limit current for each axis to max coil current + F64 limited_x = std::fmin(std::fabs(unlimited_x), this->COIL_MAX_CURRENT_X_Y) * (unlimited_x >= 0 ? 1.0 : -1.0); + F64 limited_y = std::fmin(std::fabs(unlimited_y), this->COIL_MAX_CURRENT_X_Y) * (unlimited_y >= 0 ? 1.0 : -1.0); + F64 limited_z = std::fmin(std::fabs(unlimited_z), this->COIL_MAX_CURRENT_Z) * (unlimited_z >= 0 ? 1.0 : -1.0); + + F64 x1 = limited_x; + F64 x2 = -limited_x; + F64 y1 = limited_y; + F64 y2 = -limited_y; + F64 z1 = limited_z; + + this->magnetorquersSet_out(0, {x1, x2, y1, y2, z1}); +} + +F64 DetumbleManager::getAngularVelocityMagnitude(const Drv::AngularVelocity& angVel) { + // Calculate magnitude in rad/s + F64 magRadPerSec = + std::sqrt(angVel.get_x() * angVel.get_x() + angVel.get_y() * angVel.get_y() + angVel.get_z() * angVel.get_z()); + + // Convert rad/s to deg/s + return magRadPerSec * 180.0 / this->PI; +} + +} // namespace Components diff --git a/FprimeZephyrReference/Components/DetumbleManager/DetumbleManager.fpp b/FprimeZephyrReference/Components/DetumbleManager/DetumbleManager.fpp new file mode 100644 index 00000000..77a751a9 --- /dev/null +++ b/FprimeZephyrReference/Components/DetumbleManager/DetumbleManager.fpp @@ -0,0 +1,62 @@ +module Components { + @ Detumble Manager Component for F Prime FSW framework. + passive component DetumbleManager { + + @ Parameter for storing the rotational threshold for detumble to be enabled (default 12 deg/s) + param ROTATIONAL_THRESHOLD: F32 default 12.0 \ + id 1 + + @ Parameter for storing the max amount of time an iteration can run + param MAX_TIME: U32 default 10800 \ + id 2 + + @ Parameter for storing the cooldown after a detumble run finishes (in seconds) + param COOLDOWN: U32 default 600 \ + id 3 + + @ Run loop + sync input port run: Svc.Sched + + @ Port for sending accelerationGet calls to the LSM6DSO Driver + output port accelerationGet: Drv.AccelerationGet + + @ Port for sending angularVelocityGet calls to the LSM6DSO Driver + output port angularVelocityGet: Drv.AngularVelocityGet + + @ Port for sending magneticFieldGet calls to the LIS2MDL Manager + output port magneticFieldGet: Drv.MagneticFieldGet + + @ Port for sending temperatureGet calls to the LSM6DSO Driver + output port temperatureGet: Drv.TemperatureGet + + @ Port for sending dipoleMomentGet calls to the BDotDetumble Component + output port dipoleMomentGet: Drv.DipoleMomentGet + + @ Port for sending SetMagnetorquers calls to the MagnetorquerManager Component + output port magnetorquersSet: Drv.SetMagnetorquers + + ############################################################################### + # Standard AC Ports: Required for Channels, Events, Commands, and Parameters # + ############################################################################### + @ Port for requesting the current time + time get port timeCaller + + @ Port for getting parameters + param get port prmGetOut + + @ Port for setting parameters + param set port prmSetOut + + @ 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 + + + + } +} diff --git a/FprimeZephyrReference/Components/DetumbleManager/DetumbleManager.hpp b/FprimeZephyrReference/Components/DetumbleManager/DetumbleManager.hpp new file mode 100644 index 00000000..692398c8 --- /dev/null +++ b/FprimeZephyrReference/Components/DetumbleManager/DetumbleManager.hpp @@ -0,0 +1,71 @@ +// ====================================================================== +// \title DetumbleManager.hpp +// \brief hpp file for DetumbleManager component implementation class +// ====================================================================== + +#ifndef Components_DetumbleManager_HPP +#define Components_DetumbleManager_HPP + +#include + +#include "FprimeZephyrReference/Components/DetumbleManager/DetumbleManagerComponentAc.hpp" + +namespace Components { + +class DetumbleManager final : public DetumbleManagerComponentBase { + public: + // ---------------------------------------------------------------------- + // Component construction and destruction + // ---------------------------------------------------------------------- + + //! Construct DetumbleManager object + DetumbleManager(const char* const compName); + + //! Destroy DetumbleManager object + ~DetumbleManager(); + + private: + // ---------------------------------------------------------------------- + // Handler implementations for typed input ports + // ---------------------------------------------------------------------- + + //! Handler implementation + void run_handler(FwIndexType portNum, //!< The port number + U32 context //!< The call order + ) override; + + // Constants + Drv::MagneticField EMPTY_MG_FIELD = Drv::MagneticField(0.0, 0.0, 0.0, -1); + Drv::DipoleMoment EMPTY_DP_MOMENT = Drv::DipoleMoment(0.0, 0.0, 0.0); + const double PI = 3.14159265358979323846; + + // Proves V3 Magnetorquer Information + F64 COIL_VOLTAGE = 3.3; + F64 COIL_NUM_TURNS_X_Y = 48; + F64 COIL_LENGTH_X_Y = 0.053; + F64 COIL_WIDTH_X_Y = 0.045; + F64 COIL_AREA_X_Y = this->COIL_LENGTH_X_Y * this->COIL_WIDTH_X_Y; + F64 COIL_RESISTANCE_X_Y = 57.2; + F64 COIL_MAX_CURRENT_X_Y = this->COIL_VOLTAGE / this->COIL_RESISTANCE_X_Y; + I64 COIL_NUM_TURNS_Z = 153; + F64 COIL_DIAMETER_Z = 0.05755; + F64 COIL_AREA_Z = this->PI * pow(this->COIL_DIAMETER_Z / 2, 2.0); + F64 COIL_RESISTANCE_Z = 248.8; + F64 COIL_MAX_CURRENT_Z = this->COIL_VOLTAGE / this->COIL_RESISTANCE_Z; + + // Variables + Drv::MagneticField prevMgField = Drv::MagneticField(0.0, 0.0, 0.0, -1); + int iterations = 0; + U32 startTime = 0; + U32 lastCompleted = 0; + bool detumbleRunning = true; + + // Functions + bool executeControlStep(); + void setDipoleMoment(Drv::DipoleMoment dpMoment); + F64 getAngularVelocityMagnitude(const Drv::AngularVelocity& angVel); +}; + +} // namespace Components + +#endif diff --git a/FprimeZephyrReference/Components/DetumbleManager/docs/sdd.md b/FprimeZephyrReference/Components/DetumbleManager/docs/sdd.md new file mode 100644 index 00000000..56d94e4a --- /dev/null +++ b/FprimeZephyrReference/Components/DetumbleManager/docs/sdd.md @@ -0,0 +1,73 @@ +# Components::DetumbleManager + +The IMU Manager (Inertial Measurement Unit) component provides sensor data related to motion and orientation of the craft. It interfaces with two drivers: the LIS2MDL Manager and the LSM6DSO Driver which provide acceleration, angular velocity, magnetic field, and temperature measurements. + +## Usage Examples + +The IMU Manager component is designed to be scheduled periodically to trigger collection of sensor data and telemetering. It operates as a passive component that responds to scheduler calls. + +### Typical Usage + +1. The component is instantiated and initialized during system startup +2. The scheduler calls the `run` port at regular intervals +3. On each run call, the component: + - Fetches sensor data from both the LIS2MDL Manager and LSM6DSO Driver + - Outputs telemetry for acceleration, angular velocity, magnetic field, and temperature + +## Class Diagram + +```mermaid +classDiagram + namespace Components { + class DetumbleManagerComponentBase { + <> + } + class DetumbleManager { + + DetumbleManager(const char* compName) + + ~DetumbleManager() + - run_handler(FwIndexType portNum, U32 context): void + } + } + DetumbleManagerComponentBase <|-- DetumbleManager : inherits +``` + +## Port Descriptions + +| Name | Type | Description | +| ------------------ | ---------- | ---------------------------------------------------------- | +| run | sync input | Scheduler port that triggers sensor data collection | +| accelerationGet | output | Port for calling accelerationGet on the LSM6DSO Manager | +| angularVelocityGet | output | Port for calling angularVelocityGet on the LSM6DSO Manager | +| magneticFieldGet | output | Port for calling magneticFieldGet on the LIS2MDL Manager | +| temperatureGet | output | Port for calling temperatureGet on the LSM6DSO Manager | +| timeCaller | time get | Port for requesting current system time | + +## Sequence Diagrams + +```mermaid +sequenceDiagram + participant Scheduler + participant IMU Manager + participant LIS2MDL Manager + participant LSM6DSO Manager + + Scheduler-->>IMU Manager: run + IMU Manager->>LSM6DSO Manager: AccelerationGet + IMU Manager->>LSM6DSO Manager: AngularVelocityGet + IMU Manager->>LSM6DSO Manager: TemperatureGet + IMU Manager->>LIS2MDL Manager: MagneticFieldGet +``` + +## Requirements + +| Name | Description | Validation | +| ---------------------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------ | +| Sensor Data Collection | The component shall trigger data collection from both LSM6DSO and LIS2MDL sensors when run is called | Verify all sensor manager output ports are called | +| Periodic Operation | The component shall operate as a scheduled component responding to scheduler calls | Verify component responds correctly to scheduler input | + +## Change Log + +| Date | Description | +| --------- | --------------------------------------------------------------------- | +| 2025-9-9 | Initial IMU Manager component | +| 2025-9-18 | Extracted Zephyr calls to discrete LIS2MDL Manager and LSM6DSO Driver | diff --git a/FprimeZephyrReference/Components/Drv/BDotDetumble/BDotDetumble.cpp b/FprimeZephyrReference/Components/Drv/BDotDetumble/BDotDetumble.cpp new file mode 100644 index 00000000..6d21d750 --- /dev/null +++ b/FprimeZephyrReference/Components/Drv/BDotDetumble/BDotDetumble.cpp @@ -0,0 +1,70 @@ +// ====================================================================== +// \title BDotDetumble.cpp +// \author aychar +// \brief cpp file for BDotDetumble component implementation class +// ====================================================================== + +#include "FprimeZephyrReference/Components/Drv/BDotDetumble/BDotDetumble.hpp" + +#include + +namespace Drv { + +// ---------------------------------------------------------------------- +// Component construction and destruction +// ---------------------------------------------------------------------- + +BDotDetumble ::BDotDetumble(const char* const compName) : BDotDetumbleComponentBase(compName) {} + +BDotDetumble ::~BDotDetumble() {} + +Drv::DipoleMoment BDotDetumble::dipoleMomentGet_handler(const FwIndexType portNum, + const Drv::MagneticField& currMagField, + const Drv::MagneticField& prevMagField) { + F64 magnitude = this->getMagnitude(currMagField); + if (magnitude < 1e-6) { + return Drv::DipoleMoment(); + } + + if (currMagField.get_timestamp() <= prevMagField.get_timestamp()) { + return Drv::DipoleMoment(); + } + + F64* dB_dtArr = this->dB_dt(currMagField, prevMagField); + if (dB_dtArr == nullptr) { + return Drv::DipoleMoment(); + } + + F64 moment_x = this->gain * dB_dtArr[0] / magnitude; + F64 moment_y = this->gain * dB_dtArr[1] / magnitude; + F64 moment_z = this->gain * dB_dtArr[2] / magnitude; + + delete[] dB_dtArr; + + return Drv::DipoleMoment(moment_x, moment_y, moment_z); +} + +F64 BDotDetumble::getMagnitude(const Drv::MagneticField magField) { + return sqrt((magField.get_x() * magField.get_x()) + (magField.get_y() * magField.get_y()) + + (magField.get_z() * magField.get_z())); +} + +F64* BDotDetumble::dB_dt(const Drv::MagneticField currMagField, const Drv::MagneticField prevMagField) { + I64 dt = currMagField.get_timestamp() - prevMagField.get_timestamp(); + if (dt < 1e-6) { + return nullptr; + } + + F64 dBx_dt = (currMagField.get_x() - prevMagField.get_x()) / dt; + F64 dBy_dt = (currMagField.get_y() - prevMagField.get_y()) / dt; + F64 dBz_dt = (currMagField.get_z() - prevMagField.get_z()) / dt; + + F64* arr = new F64[3]; + arr[0] = dBx_dt; + arr[1] = dBy_dt; + arr[2] = dBz_dt; + + return arr; +} + +} // namespace Drv diff --git a/FprimeZephyrReference/Components/Drv/BDotDetumble/BDotDetumble.fpp b/FprimeZephyrReference/Components/Drv/BDotDetumble/BDotDetumble.fpp new file mode 100644 index 00000000..275bca0f --- /dev/null +++ b/FprimeZephyrReference/Components/Drv/BDotDetumble/BDotDetumble.fpp @@ -0,0 +1,38 @@ +module Drv { + port DipoleMomentGet( + currMagField: MagneticField + prevMagField: MagneticField + ) -> DipoleMoment +} + +module Drv { + @ Component for F Prime FSW framework. + passive component BDotDetumble { + + sync input port dipoleMomentGet: DipoleMomentGet + + telemetry DipoleMoment: DipoleMoment + + ############################################################################### + # 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 + + @ 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/Drv/BDotDetumble/BDotDetumble.hpp b/FprimeZephyrReference/Components/Drv/BDotDetumble/BDotDetumble.hpp new file mode 100644 index 00000000..a00745e0 --- /dev/null +++ b/FprimeZephyrReference/Components/Drv/BDotDetumble/BDotDetumble.hpp @@ -0,0 +1,42 @@ +// ====================================================================== +// \title BDotDetumble.hpp +// \author aychar +// \brief hpp file for BDotDetumble component implementation class +// ====================================================================== + +#ifndef Drv_BDotDetumble_HPP +#define Drv_BDotDetumble_HPP + +#include "FprimeZephyrReference/Components/Drv/BDotDetumble/BDotDetumbleComponentAc.hpp" + +namespace Drv { + +class BDotDetumble final : public BDotDetumbleComponentBase { + public: + // ---------------------------------------------------------------------- + // Component construction and destruction + // ---------------------------------------------------------------------- + + //! Construct BDotDetumble object + BDotDetumble(const char* const compName //!< The component name + ); + + //! Destroy BDotDetumble object + ~BDotDetumble(); + + // Get the current dipole moment + Drv::DipoleMoment dipoleMomentGet_handler(const FwIndexType portNum, + const Drv::MagneticField& currMagField, + const Drv::MagneticField& prevMagField) override; + + private: + F64 gain = 1.0; + + // Get magnitude + F64 getMagnitude(Drv::MagneticField magField); + + // Get the time derivative of the magnetic field + F64* dB_dt(Drv::MagneticField currMagField, Drv::MagneticField prevMagField); +}; +} // namespace Drv +#endif diff --git a/FprimeZephyrReference/Components/Drv/BDotDetumble/CMakeLists.txt b/FprimeZephyrReference/Components/Drv/BDotDetumble/CMakeLists.txt new file mode 100644 index 00000000..fe05923c --- /dev/null +++ b/FprimeZephyrReference/Components/Drv/BDotDetumble/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}/BDotDetumble.fpp" + SOURCES + "${CMAKE_CURRENT_LIST_DIR}/BDotDetumble.cpp" +# DEPENDS +# MyPackage_MyOtherModule +) + +### Unit Tests ### +# register_fprime_ut( +# AUTOCODER_INPUTS +# "${CMAKE_CURRENT_LIST_DIR}/BDotDetumble.fpp" +# SOURCES +# "${CMAKE_CURRENT_LIST_DIR}/test/ut/BDotDetumbleTestMain.cpp" +# "${CMAKE_CURRENT_LIST_DIR}/test/ut/BDotDetumbleTester.cpp" +# DEPENDS +# STest # For rules-based testing +# UT_AUTO_HELPERS +# ) diff --git a/FprimeZephyrReference/Components/Drv/BDotDetumble/docs/sdd.md b/FprimeZephyrReference/Components/Drv/BDotDetumble/docs/sdd.md new file mode 100644 index 00000000..528b8114 --- /dev/null +++ b/FprimeZephyrReference/Components/Drv/BDotDetumble/docs/sdd.md @@ -0,0 +1,66 @@ +# Drv::BDotDetumble + +Component for F Prime FSW framework. + +## 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 | +|---|---| +|---|---| + +## Component States +Add component states in the chart below +| Name | Description | +|---|---| +|---|---| + +## Sequence Diagrams +Add sequence diagrams here + +## Parameters +| Name | Description | +|---|---| +|---|---| + +## Commands +| Name | Description | +|---|---| +|---|---| + +## Events +| Name | Description | +|---|---| +|---|---| + +## Telemetry +| Name | Description | +|---|---| +|---|---| + +## Unit Tests +Add unit test descriptions in the chart below +| Name | Description | Output | Coverage | +|---|---|---|---| +|---|---|---|---| + +## Requirements +Add requirements in the chart below +| Name | Description | Validation | +|---|---|---| +|---|---|---| + +## Change Log +| Date | Description | +|---|---| +|---| Initial Draft | diff --git a/FprimeZephyrReference/Components/Drv/CMakeLists.txt b/FprimeZephyrReference/Components/Drv/CMakeLists.txt index efcd2f90..77baa7cc 100644 --- a/FprimeZephyrReference/Components/Drv/CMakeLists.txt +++ b/FprimeZephyrReference/Components/Drv/CMakeLists.txt @@ -3,3 +3,5 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Lis2mdlManager/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Lsm6dsoManager/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/RtcManager") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Types/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/BDotDetumble/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/MagnetorquerManager/") diff --git a/FprimeZephyrReference/Components/Drv/Lis2mdlManager/Lis2mdlManager.cpp b/FprimeZephyrReference/Components/Drv/Lis2mdlManager/Lis2mdlManager.cpp index 23484e46..f66e9470 100644 --- a/FprimeZephyrReference/Components/Drv/Lis2mdlManager/Lis2mdlManager.cpp +++ b/FprimeZephyrReference/Components/Drv/Lis2mdlManager/Lis2mdlManager.cpp @@ -7,6 +7,8 @@ #include +#include + namespace Drv { // ---------------------------------------------------------------------- @@ -32,7 +34,7 @@ void Lis2mdlManager ::configure(const struct device* dev) { Drv::MagneticField Lis2mdlManager ::magneticFieldGet_handler(FwIndexType portNum) { if (!device_is_ready(this->m_dev)) { this->log_WARNING_HI_DeviceNotReady(); - return Drv::MagneticField(0.0, 0.0, 0.0); + return Drv::MagneticField(0.0, 0.0, 0.0, -1); } this->log_WARNING_HI_DeviceNotReady_ThrottleClear(); @@ -46,8 +48,8 @@ Drv::MagneticField Lis2mdlManager ::magneticFieldGet_handler(FwIndexType portNum sensor_channel_get(this->m_dev, SENSOR_CHAN_MAGN_Y, &y); sensor_channel_get(this->m_dev, SENSOR_CHAN_MAGN_Z, &z); - Drv::MagneticField magnetic_readings = - Drv::MagneticField(sensor_value_to_double(&x), sensor_value_to_double(&y), sensor_value_to_double(&z)); + Drv::MagneticField magnetic_readings = Drv::MagneticField(sensor_value_to_double(&x), sensor_value_to_double(&y), + sensor_value_to_double(&z), k_uptime_get()); this->tlmWrite_MagneticField(magnetic_readings); diff --git a/FprimeZephyrReference/Components/Drv/MagnetorquerManager/CMakeLists.txt b/FprimeZephyrReference/Components/Drv/MagnetorquerManager/CMakeLists.txt new file mode 100644 index 00000000..92da00df --- /dev/null +++ b/FprimeZephyrReference/Components/Drv/MagnetorquerManager/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}/MagnetorquerManager.fpp" + SOURCES + "${CMAKE_CURRENT_LIST_DIR}/MagnetorquerManager.cpp" +# DEPENDS +# MyPackage_MyOtherModule +) + +### Unit Tests ### +# register_fprime_ut( +# AUTOCODER_INPUTS +# "${CMAKE_CURRENT_LIST_DIR}/MagnetorquerManager.fpp" +# SOURCES +# "${CMAKE_CURRENT_LIST_DIR}/test/ut/MagnetorquerManagerTestMain.cpp" +# "${CMAKE_CURRENT_LIST_DIR}/test/ut/MagnetorquerManagerTester.cpp" +# DEPENDS +# STest # For rules-based testing +# UT_AUTO_HELPERS +# ) diff --git a/FprimeZephyrReference/Components/Drv/MagnetorquerManager/MagnetorquerManager.cpp b/FprimeZephyrReference/Components/Drv/MagnetorquerManager/MagnetorquerManager.cpp new file mode 100644 index 00000000..fe720b16 --- /dev/null +++ b/FprimeZephyrReference/Components/Drv/MagnetorquerManager/MagnetorquerManager.cpp @@ -0,0 +1,71 @@ +// ====================================================================== +// \title MagnetorquerManager.cpp +// \author aychar +// \brief cpp file for MagnetorquerManager component implementation class +// ====================================================================== + +#include "FprimeZephyrReference/Components/Drv/MagnetorquerManager/MagnetorquerManager.hpp" + +#include +#include + +namespace Drv { + +// ---------------------------------------------------------------------- +// Component construction and destruction +// ---------------------------------------------------------------------- + +MagnetorquerManager ::MagnetorquerManager(const char* const compName) : MagnetorquerManagerComponentBase(compName) {} + +MagnetorquerManager ::~MagnetorquerManager() {} + +// ---------------------------------------------------------------------- +// Helper methods +// ---------------------------------------------------------------------- + +void MagnetorquerManager ::configure(const struct device* const devices[5]) { + for (int i = 0; i < 5; ++i) { + this->m_devices[i] = devices[i]; + } +} + +void MagnetorquerManager ::START_PLAYBACK_TEST_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, U8 faceIdx) { + // Validate face index (0..4) + if (faceIdx >= 5) { + this->log_WARNING_LO_InvalidFaceIndex(); + return; + } + + const struct device* dev = this->m_devices[faceIdx]; + if (!device_is_ready(dev)) { + this->log_WARNING_HI_DeviceNotReady(); + return; + } + + drv2605_haptic_config(dev, DRV2605_HAPTICS_SOURCE_ROM, (union drv2605_config_data*)&this->rom); +} + +void MagnetorquerManager ::START_PLAYBACK_TEST2_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, U8 faceIdx) { + // Validate face index (0..4) + if (faceIdx >= 5) { + this->log_WARNING_LO_InvalidFaceIndex(); + return; + } + + const struct device* dev = this->m_devices[faceIdx]; + if (!device_is_ready(dev)) { + this->log_WARNING_HI_DeviceNotReady(); + return; + } + + struct drv2605_rom_data rom2 = {.library = DRV2605_LIBRARY_TS2200_A, .seq_regs = {50, 0, 0, 0, 0, 0, 0, 0}}; + drv2605_haptic_config(dev, DRV2605_HAPTICS_SOURCE_ROM, (union drv2605_config_data*)&rom2); +} + +void MagnetorquerManager ::SetMagnetorquers_handler(const FwIndexType portNum, const Drv::InputArray& value) { + // TODO(hrfarmer): Once its possible to properly interact with the DRV2605, I'll figure out how to + // determine how the passed in amps should translate to a specific pattern(s) that should be ran. + return; +} + +} // namespace Drv diff --git a/FprimeZephyrReference/Components/Drv/MagnetorquerManager/MagnetorquerManager.fpp b/FprimeZephyrReference/Components/Drv/MagnetorquerManager/MagnetorquerManager.fpp new file mode 100644 index 00000000..39811975 --- /dev/null +++ b/FprimeZephyrReference/Components/Drv/MagnetorquerManager/MagnetorquerManager.fpp @@ -0,0 +1,60 @@ +module Drv { + array InputArray = [5] I32; + port SetMagnetorquers( + value: InputArray @< Amp value for each face in the order x1, x2, y1, y2, z1 + ) +} + +module Drv { + @ Component for F Prime FSW framework. + passive component MagnetorquerManager { + + @ Event for reporting DRV2605 not ready error + event DeviceNotReady() severity warning high format "DRV2605 device not ready" throttle 5 + + @ Event to report an invalid face index passed in + event InvalidFaceIndex() severity warning low format "The faceIdx should be between 0-4" + + @ Start DRV2605 playback on a device with effect #47 on a specific face + @ faceIdx: index of the face to actuate (valid range: 0..4) + sync command START_PLAYBACK_TEST(faceIdx: U8) + + @ Start DRV2605 playback on a device with effect #50 on a specific face + @ faceIdx: index of the face to actuate (valid range: 0..4) + sync command START_PLAYBACK_TEST2(faceIdx: U8) + + @ Input port to set magnetorquer values + sync input port SetMagnetorquers: SetMagnetorquers + + ############################################################################### + # 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/Drv/MagnetorquerManager/MagnetorquerManager.hpp b/FprimeZephyrReference/Components/Drv/MagnetorquerManager/MagnetorquerManager.hpp new file mode 100644 index 00000000..ce81ad90 --- /dev/null +++ b/FprimeZephyrReference/Components/Drv/MagnetorquerManager/MagnetorquerManager.hpp @@ -0,0 +1,50 @@ +// ====================================================================== +// \title MagnetorquerManager.hpp +// \author aychar +// \brief hpp file for MagnetorquerManager component implementation class +// ====================================================================== + +#ifndef Drv_MagnetorquerManager_HPP +#define Drv_MagnetorquerManager_HPP + +#include "FprimeZephyrReference/Components/Drv/MagnetorquerManager/MagnetorquerManagerComponentAc.hpp" +#include +#include +#include +#include + +namespace Drv { + +class MagnetorquerManager final : public MagnetorquerManagerComponentBase { + public: + // ---------------------------------------------------------------------- + // Component construction and destruction + // ---------------------------------------------------------------------- + + //! Construct MagnetorquerManager object + MagnetorquerManager(const char* const compName //!< The component name + ); + + //! Destroy MagnetorquerManager object + ~MagnetorquerManager(); + + //! Configure the DRV2605 device + // Accept an array of six pointers to const device objects. The pointers themselves are const + // to match callers that provide const device* const* types. + void configure(const struct device* const devices[5]); + + private: + //! Zephyr device to store initialized DRV2605 devices + const struct device* m_devices[5]; + struct drv2605_rom_data rom = {.library = DRV2605_LIBRARY_TS2200_A, .seq_regs = {47, 0, 0, 0, 0, 0, 0, 0}}; + + // Command handlers updated to accept a face index (0..5) + void START_PLAYBACK_TEST_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, U8 faceIdx) override; + void START_PLAYBACK_TEST2_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, U8 faceIdx) override; + + void SetMagnetorquers_handler(const FwIndexType portNum, const Drv::InputArray& value) override; +}; + +} // namespace Drv + +#endif diff --git a/FprimeZephyrReference/Components/Drv/MagnetorquerManager/docs/sdd.md b/FprimeZephyrReference/Components/Drv/MagnetorquerManager/docs/sdd.md new file mode 100644 index 00000000..52138636 --- /dev/null +++ b/FprimeZephyrReference/Components/Drv/MagnetorquerManager/docs/sdd.md @@ -0,0 +1,134 @@ +# Drv::MagnetorquerManager + +The Magnetorquer Manager component interfaces with the five DRV2605 devices on a PROVES CubeSat to control the current of the magnetorquers. + +## Usage Examples + +This component is designed to be used by the detumble service to be able to detumble the cubesat when launched. + +### Diagrams + +```mermaid +graph LR + A[Detumble Service] -->|SetMagnetorquers| B[MagnetorquerManager] + B -->|Configure| C[DRV2605 Device 0
X1 Face] + B -->|Configure| D[DRV2605 Device 1
X2 Face] + B -->|Configure| E[DRV2605 Device 2
Y1 Face] + B -->|Configure| F[DRV2605 Device 3
Y2 Face] + B -->|Configure| G[DRV2605 Device 4
Z1 Face] +``` + +### Typical Usage + +1. The component is instantiated and initialized during system startup +2. The detumble service calls the `SetMagnetorquers` input port. +3. On each call, the component: + - Takes in an `InputArray` parameter of 5 I32 for the amps for each face. + - Translates the passed in values to a sequence value from the DRV2605 library. + - Runs the sequence for each device. + +## Class Diagram + +```mermaid +classDiagram + class MagnetorquerManager { + -device* m_devices[5] + +configure(devices[5]) + +SetMagnetorquers_handler(portNum, value) + +START_PLAYBACK_TEST_cmdHandler(opCode, cmdSeq, faceIdx) + +START_PLAYBACK_TEST2_cmdHandler(opCode, cmdSeq, faceIdx) + } + + class MagnetorquerManagerComponentBase { + <> + } + + class DRV2605 { + <> + +device_is_ready() + +drv2605_haptic_config() + } + + MagnetorquerManager --|> MagnetorquerManagerComponentBase + MagnetorquerManager --> DRV2605 : uses (5 devices) +``` + +## Port Descriptions + +| Name | Description | +| ---------------- | ------------------------------------------------------------------------------------------- | +| SetMagnetorquers | Input port that takes in an array (I32[5]) and applies each value to the corresponding face | + +## Sequence Diagrams + +### SetMagnetorquers Operation + +```mermaid +sequenceDiagram + participant DS as Detumble Service + participant MM as MagnetorquerManager + participant DRV as DRV2605 Devices + + DS->>MM: SetMagnetorquers([x1, x2, y1, y2, z1]) + Note over MM: Validate input array + Note over MM: Translate amps to sequences + loop For each face (0-4) + MM->>DRV: Check device_is_ready() + alt Device Ready + MM->>DRV: drv2605_haptic_config(sequence) + else Device Not Ready + MM->>MM: log_WARNING_HI_DeviceNotReady() + end + end + MM-->>DS: Return +``` + +### Test Command Operation + +```mermaid +sequenceDiagram + participant GS as Ground Station + participant MM as MagnetorquerManager + participant DRV as DRV2605 Device + + GS->>MM: START_PLAYBACK_TEST(faceIdx) + MM->>MM: Validate faceIdx (0-4) + alt Invalid faceIdx + MM->>MM: log_WARNING_LO_InvalidFaceIndex() + else Valid faceIdx + MM->>DRV: device_is_ready() + alt Device Ready + MM->>DRV: drv2605_haptic_config(effect #47) + else Device Not Ready + MM->>MM: log_WARNING_HI_DeviceNotReady() + end + end + MM-->>GS: Command Response +``` + +## Commands + +| Name | Description | +| -------------------- | ------------------------------------------------------------------------------------------------ | +| START_PLAYBACK_TEST | Start DRV2605 playback on a device with effect #47 on a specific face (faceIdx: 0-4). Test only. | +| START_PLAYBACK_TEST2 | Start DRV2605 playback on a device with effect #50 on a specific face (faceIdx: 0-4). Test only. | + +## Events + +| Name | Description | +| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | +| DeviceNotReady | Output whenever a magnetorquer is attempted to be used while it is not initialized. | +| InvalidFaceIndex | Output whenever one of the manual test comamands are ran with an invalid face index (will be removed if/when the test commands are removed) | + +## Requirements + +Add requirements in the chart below +| Name | Description | Validation | +|---|---|---| +|---|---|---| + +## Change Log + +| Date | Description | +| ---------- | ------------- | +| 11/11/2025 | Initial Draft | diff --git a/FprimeZephyrReference/Components/Drv/Types/Types.fpp b/FprimeZephyrReference/Components/Drv/Types/Types.fpp index e129beea..bb032758 100644 --- a/FprimeZephyrReference/Components/Drv/Types/Types.fpp +++ b/FprimeZephyrReference/Components/Drv/Types/Types.fpp @@ -19,5 +19,13 @@ module Drv { x: F64 @< Magnetic field in gauss in the X direction. y: F64 @< Magnetic field in gauss in the Y direction. z: F64 @< Magnetic field in gauss in the Z direction. + timestamp: I64 @< Time the magnetic field struct was created. Used for dB_dt calculation. + } + + @ Calculated dipole moment from the B-Dot algorithm. + struct DipoleMoment { + x: F64 + y: F64 + z: F64 } } diff --git a/FprimeZephyrReference/Components/ImuManager/ImuManager.cpp b/FprimeZephyrReference/Components/ImuManager/ImuManager.cpp deleted file mode 100644 index 24e520a7..00000000 --- a/FprimeZephyrReference/Components/ImuManager/ImuManager.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// ====================================================================== -// \title ImuManager.cpp -// \brief cpp file for ImuManager component implementation class -// ====================================================================== - -#include "FprimeZephyrReference/Components/ImuManager/ImuManager.hpp" - -#include - -namespace Components { - -// ---------------------------------------------------------------------- -// Component construction and destruction -// ---------------------------------------------------------------------- - -ImuManager ::ImuManager(const char* const compName) : ImuManagerComponentBase(compName) {} - -ImuManager ::~ImuManager() {} - -// ---------------------------------------------------------------------- -// Handler implementations for typed input ports -// ---------------------------------------------------------------------- - -void ImuManager ::run_handler(FwIndexType portNum, U32 context) { - // Read from Lsm6dsoManager - this->accelerationGet_out(0); - this->angularVelocityGet_out(0); - this->temperatureGet_out(0); - - // Read from Lis2mdlManager - this->magneticFieldGet_out(0); -} -} // namespace Components diff --git a/FprimeZephyrReference/Components/ImuManager/ImuManager.fpp b/FprimeZephyrReference/Components/ImuManager/ImuManager.fpp deleted file mode 100644 index ae6973c2..00000000 --- a/FprimeZephyrReference/Components/ImuManager/ImuManager.fpp +++ /dev/null @@ -1,24 +0,0 @@ -module Components { - @ IMU Manager Component for F Prime FSW framework. - passive component ImuManager { - sync input port run: Svc.Sched - - @ Port for sending accelerationGet calls to the LSM6DSO Driver - output port accelerationGet: Drv.AccelerationGet - - @ Port for sending angularVelocityGet calls to the LSM6DSO Driver - output port angularVelocityGet: Drv.AngularVelocityGet - - @ Port for sending magneticFieldGet calls to the LIS2MDL Manager - output port magneticFieldGet: Drv.MagneticFieldGet - - @ Port for sending temperatureGet calls to the LSM6DSO Driver - output port temperatureGet: Drv.TemperatureGet - - ############################################################################### - # Standard AC Ports: Required for Channels, Events, Commands, and Parameters # - ############################################################################### - @ Port for requesting the current time - time get port timeCaller - } -} diff --git a/FprimeZephyrReference/Components/ImuManager/ImuManager.hpp b/FprimeZephyrReference/Components/ImuManager/ImuManager.hpp deleted file mode 100644 index 14bec238..00000000 --- a/FprimeZephyrReference/Components/ImuManager/ImuManager.hpp +++ /dev/null @@ -1,38 +0,0 @@ -// ====================================================================== -// \title ImuManager.hpp -// \brief hpp file for ImuManager component implementation class -// ====================================================================== - -#ifndef Components_ImuManager_HPP -#define Components_ImuManager_HPP - -#include "FprimeZephyrReference/Components/ImuManager/ImuManagerComponentAc.hpp" - -namespace Components { - -class ImuManager final : public ImuManagerComponentBase { - public: - // ---------------------------------------------------------------------- - // Component construction and destruction - // ---------------------------------------------------------------------- - - //! Construct ImuManager object - ImuManager(const char* const compName); - - //! Destroy ImuManager object - ~ImuManager(); - - private: - // ---------------------------------------------------------------------- - // Handler implementations for typed input ports - // ---------------------------------------------------------------------- - - //! Handler implementation - void run_handler(FwIndexType portNum, //!< The port number - U32 context //!< The call order - ) override; -}; - -} // namespace Components - -#endif diff --git a/FprimeZephyrReference/Components/ImuManager/docs/sdd.md b/FprimeZephyrReference/Components/ImuManager/docs/sdd.md deleted file mode 100644 index db12b255..00000000 --- a/FprimeZephyrReference/Components/ImuManager/docs/sdd.md +++ /dev/null @@ -1,69 +0,0 @@ -# Components::ImuManager - -The IMU Manager (Inertial Measurement Unit) component provides sensor data related to motion and orientation of the craft. It interfaces with two drivers: the LIS2MDL Manager and the LSM6DSO Driver which provide acceleration, angular velocity, magnetic field, and temperature measurements. - -## Usage Examples - -The IMU Manager component is designed to be scheduled periodically to trigger collection of sensor data and telemetering. It operates as a passive component that responds to scheduler calls. - -### Typical Usage - -1. The component is instantiated and initialized during system startup -2. The scheduler calls the `run` port at regular intervals -3. On each run call, the component: - - Fetches sensor data from both the LIS2MDL Manager and LSM6DSO Driver - - Outputs telemetry for acceleration, angular velocity, magnetic field, and temperature - -## Class Diagram - -```mermaid -classDiagram - namespace Components { - class ImuManagerComponentBase { - <> - } - class ImuManager { - + ImuManager(const char* compName) - + ~ImuManager() - - run_handler(FwIndexType portNum, U32 context): void - } - } - ImuManagerComponentBase <|-- ImuManager : inherits -``` - -## Port Descriptions -| Name | Type | Description | -|---|---|---| -| run | sync input | Scheduler port that triggers sensor data collection | -| accelerationGet | output | Port for calling accelerationGet on the LSM6DSO Manager | -| angularVelocityGet | output | Port for calling angularVelocityGet on the LSM6DSO Manager | -| magneticFieldGet | output | Port for calling magneticFieldGet on the LIS2MDL Manager | -| temperatureGet | output | Port for calling temperatureGet on the LSM6DSO Manager | -| timeCaller | time get | Port for requesting current system time | - -## Sequence Diagrams -```mermaid -sequenceDiagram - participant Scheduler - participant IMU Manager - participant LIS2MDL Manager - participant LSM6DSO Manager - - Scheduler-->>IMU Manager: run - IMU Manager->>LSM6DSO Manager: AccelerationGet - IMU Manager->>LSM6DSO Manager: AngularVelocityGet - IMU Manager->>LSM6DSO Manager: TemperatureGet - IMU Manager->>LIS2MDL Manager: MagneticFieldGet -``` - -## Requirements -| Name | Description | Validation | -|---|---|---| -| Sensor Data Collection | The component shall trigger data collection from both LSM6DSO and LIS2MDL sensors when run is called | Verify all sensor manager output ports are called | -| Periodic Operation | The component shall operate as a scheduled component responding to scheduler calls | Verify component responds correctly to scheduler input | - -## Change Log -| Date | Description | -|---|---| -| 2025-9-9 | Initial IMU Manager component | -| 2025-9-18 | Extracted Zephyr calls to discrete LIS2MDL Manager and LSM6DSO Driver | diff --git a/FprimeZephyrReference/Components/ImuManager/CMakeLists.txt b/FprimeZephyrReference/Components/LoadSwitch/CMakeLists.txt similarity index 74% rename from FprimeZephyrReference/Components/ImuManager/CMakeLists.txt rename to FprimeZephyrReference/Components/LoadSwitch/CMakeLists.txt index 19006128..5be47b2d 100644 --- a/FprimeZephyrReference/Components/ImuManager/CMakeLists.txt +++ b/FprimeZephyrReference/Components/LoadSwitch/CMakeLists.txt @@ -16,9 +16,9 @@ register_fprime_library( AUTOCODER_INPUTS - "${CMAKE_CURRENT_LIST_DIR}/ImuManager.fpp" + "${CMAKE_CURRENT_LIST_DIR}/LoadSwitch.fpp" SOURCES - "${CMAKE_CURRENT_LIST_DIR}/ImuManager.cpp" + "${CMAKE_CURRENT_LIST_DIR}/LoadSwitch.cpp" # DEPENDS # MyPackage_MyOtherModule ) @@ -26,10 +26,10 @@ register_fprime_library( ### Unit Tests ### # register_fprime_ut( # AUTOCODER_INPUTS -# "${CMAKE_CURRENT_LIST_DIR}/ImuManager.fpp" +# "${CMAKE_CURRENT_LIST_DIR}/LoadSwitch.fpp" # SOURCES -# "${CMAKE_CURRENT_LIST_DIR}/test/ut/ImuManagerTestMain.cpp" -# "${CMAKE_CURRENT_LIST_DIR}/test/ut/ImuManagerTester.cpp" +# "${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..5dbca3e3 --- /dev/null +++ b/FprimeZephyrReference/Components/LoadSwitch/LoadSwitch.cpp @@ -0,0 +1,57 @@ +// ====================================================================== +// \title LoadSwitch.cpp +// \author sarah +// \brief cpp file for LoadSwitch component implementation class +// ====================================================================== + +#include "FprimeZephyrReference/Components/LoadSwitch/LoadSwitch.hpp" + +#include + +namespace Components { + +const struct device* LoadSwitch::m_device = nullptr; +// ---------------------------------------------------------------------- +// 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) { + gpio_pin_set(m_device, m_pinNum, 0); + k_sleep(K_MSEC(100)); + gpio_pin_set(m_device, m_pinNum, 1); +} + +// ---------------------------------------------------------------------- +// Handler implementations for commands +// ---------------------------------------------------------------------- + +void LoadSwitch ::TURN_ON_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) { + gpio_pin_set(m_device, m_pinNum, 1); + this->log_ACTIVITY_HI_StatusChanged(Fw::On::ON); + // I think some code needed to send this status to the port as well + this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); +} + +void LoadSwitch ::TURN_OFF_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) { + gpio_pin_set(m_device, m_pinNum, 0); + this->log_ACTIVITY_HI_StatusChanged(Fw::On::OFF); + // I think some code needed to send this status to the port as well + this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); +} + +// This is meant to be used in Topology.cpp to configure the pin and device +void LoadSwitch ::pin_configuration(const struct device* device, uint8_t pinNum) { + this->m_pinNum = pinNum; + this->m_device = device; + gpio_pin_configure(m_device, m_pinNum, GPIO_OUTPUT_INACTIVE); +} + +} // namespace Components diff --git a/FprimeZephyrReference/Components/LoadSwitch/LoadSwitch.fpp b/FprimeZephyrReference/Components/LoadSwitch/LoadSwitch.fpp new file mode 100644 index 00000000..4d52e08a --- /dev/null +++ b/FprimeZephyrReference/Components/LoadSwitch/LoadSwitch.fpp @@ -0,0 +1,72 @@ +module Components { + @ A generic load switch for controlling power to components + active 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) + async command TURN_ON() + async 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 + + + # Input that will be used by other components if they want to force a reset + # (off and on again) of the load switch + async 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..d8d917d2 --- /dev/null +++ b/FprimeZephyrReference/Components/LoadSwitch/LoadSwitch.hpp @@ -0,0 +1,70 @@ +// ====================================================================== +// \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(); + + // ---------------------------------------------------------------------- + // Configuration Meant to be used in ***Topology.cpp + // ---------------------------------------------------------------------- + + void pin_configuration(const struct device* device, uint8_t pinNum); + + 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; + + // ---------------------------------------------------------------------- + // Member variables + // ---------------------------------------------------------------------- + + uint8_t m_pinNum; + static const struct device* m_device; +}; + +} // namespace Components + +#endif diff --git a/FprimeZephyrReference/Components/LoadSwitch/docs/sdd.md b/FprimeZephyrReference/Components/LoadSwitch/docs/sdd.md new file mode 100644 index 00000000..c1bbcfe8 --- /dev/null +++ b/FprimeZephyrReference/Components/LoadSwitch/docs/sdd.md @@ -0,0 +1,66 @@ +# Components::LoadSwitch + +A generic load switch for controlling power to components + +## Usage Examples +Add usage examples here + +### Diagrams +Add diagrams here + +### Typical Usage +The load switch would be used whenever a sensor is to be turned on or off. + +## Class Diagram +Add a class diagram here + +## Port Descriptions +| Name | Description | +|---|---| +| Status | Boolean value displaying whether the load switch is on or not. | + +## Component States +| Name | Description | +|-------|--------------------------------------| +| Off | No power to the component | +| On | Power supplied to the component | +| Error | An error occurred in the load switch | + +## Sequence Diagrams +Add sequence diagrams here + +## Parameters +| Name | Description | +|---|---| +|---|---| + +## Commands +| Name | Description | +|---|---| +| On | Turn on power to the component | +| Off | Turn off power to the component | + +## Events +| Name | Description | +|---|---| +| StatusChanged | Emits event whenever the status of the load switch changes | + +## Telemetry +| Name | Description | +|---|---| +| IsOn | Returns whether the load switch is supplying power to the component or not | + +## Unit Tests +| Name | Description | Output | Coverage | +|---|---|---|---| +|---|---|---|---| + +## Requirements +| Name | Description | Validation | +|---|---|---| +|---|---|---| + +## Change Log +| Date | Description | +|---|---| +| 10-22-2025 | Sarah, Kevin, and MoMata's first commit | diff --git a/FprimeZephyrReference/ReferenceDeployment/Main.cpp b/FprimeZephyrReference/ReferenceDeployment/Main.cpp index 6b5187a8..2cd31ae6 100644 --- a/FprimeZephyrReference/ReferenceDeployment/Main.cpp +++ b/FprimeZephyrReference/ReferenceDeployment/Main.cpp @@ -17,6 +17,13 @@ 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)); +// Magnetorquer devices +const struct device* face0_drv2605 = DEVICE_DT_GET(DT_NODELABEL(face0_drv2605)); +const struct device* face1_drv2605 = DEVICE_DT_GET(DT_NODELABEL(face1_drv2605)); +const struct device* face2_drv2605 = DEVICE_DT_GET(DT_NODELABEL(face2_drv2605)); +const struct device* face3_drv2605 = DEVICE_DT_GET(DT_NODELABEL(face3_drv2605)); +const struct device* face4_drv2605 = DEVICE_DT_GET(DT_NODELABEL(face4_drv2605)); + int main(int argc, char* argv[]) { // ** DO NOT REMOVE **// // @@ -32,6 +39,11 @@ int main(int argc, char* argv[]) { inputs.uartDevice = serial; inputs.lsm6dsoDevice = lsm6dso; inputs.lis2mdlDevice = lis2mdl; + inputs.drv2605Devices[0] = face0_drv2605; + inputs.drv2605Devices[1] = face1_drv2605; + inputs.drv2605Devices[2] = face2_drv2605; + inputs.drv2605Devices[3] = face3_drv2605; + inputs.drv2605Devices[4] = face4_drv2605; inputs.baudRate = 115200; // Setup, cycle, and teardown topology diff --git a/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentPackets.fppi b/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentPackets.fppi index e8e74ee4..7c0bd5b1 100644 --- a/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentPackets.fppi +++ b/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentPackets.fppi @@ -61,7 +61,18 @@ telemetry packets ReferenceDeploymentPackets { ReferenceDeployment.antennaDeployer.LastDistance } - packet PowerMonitor id 9 group 4 { + packet LoadSwitches id 9 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 + } + + packet PowerMonitor id 10 group 4 { ReferenceDeployment.ina219SysManager.Voltage ReferenceDeployment.ina219SysManager.Current ReferenceDeployment.ina219SysManager.Power diff --git a/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentTopology.cpp b/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentTopology.cpp index 0580479a..6571a0e5 100644 --- a/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentTopology.cpp +++ b/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentTopology.cpp @@ -16,6 +16,7 @@ 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 device* mcp23017_dev = DEVICE_DT_GET(DT_NODELABEL(mcp23017)); // Allows easy reference to objects in FPP/autocoder required namespaces using namespace ReferenceDeployment; @@ -60,6 +61,14 @@ void configureTopology() { gpioDriver.open(ledGpio, Zephyr::ZephyrGpioDriver::GpioConfiguration::OUT); gpioBurnwire0.open(burnwire0Gpio, Zephyr::ZephyrGpioDriver::GpioConfiguration::OUT); gpioBurnwire1.open(burnwire1Gpio, Zephyr::ZephyrGpioDriver::GpioConfiguration::OUT); + face4LoadSwitch.pin_configuration(mcp23017_dev, 8); + face0LoadSwitch.pin_configuration(mcp23017_dev, 9); + face1LoadSwitch.pin_configuration(mcp23017_dev, 10); + face2LoadSwitch.pin_configuration(mcp23017_dev, 11); + face3LoadSwitch.pin_configuration(mcp23017_dev, 12); + face5LoadSwitch.pin_configuration(mcp23017_dev, 13); + payloadPowerLoadSwitch.pin_configuration(mcp23017_dev, 1); + payloadBatteryLoadSwitch.pin_configuration(mcp23017_dev, 3); } // Public functions for use in main program are namespaced with deployment name ReferenceDeployment @@ -92,6 +101,7 @@ void setupTopology(const TopologyState& state) { lis2mdlManager.configure(state.lis2mdlDevice); ina219SysManager.configure(state.ina219SysDevice); ina219SolManager.configure(state.ina219SolDevice); + magnetorquerManager.configure(state.drv2605Devices); } void startRateGroups() { diff --git a/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentTopologyDefs.hpp b/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentTopologyDefs.hpp index 63b8ccd6..9550b770 100644 --- a/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentTopologyDefs.hpp +++ b/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentTopologyDefs.hpp @@ -74,6 +74,7 @@ struct TopologyState { const device* loraDevice; //!< LoRa device path for communication const device* lsm6dsoDevice; //!< LSM6DSO device path for accelerometer/gyroscope const device* lis2mdlDevice; //!< LIS2MDL device path for magnetometer + const device* drv2605Devices[5]; //!< Array of DRV2605 devices (5) U32 baudRate; //!< Baud rate for UART communication CdhCore::SubtopologyState cdhCore; //!< Subtopology state for CdhCore ComCcsds::SubtopologyState comCcsds; //!< Subtopology state for ComCcsds diff --git a/FprimeZephyrReference/ReferenceDeployment/Top/instances.fpp b/FprimeZephyrReference/ReferenceDeployment/Top/instances.fpp index 4cf1dbf9..485b8ddf 100644 --- a/FprimeZephyrReference/ReferenceDeployment/Top/instances.fpp +++ b/FprimeZephyrReference/ReferenceDeployment/Top/instances.fpp @@ -37,7 +37,47 @@ module ReferenceDeployment { stack size Default.STACK_SIZE \ priority 4 - instance prmDb: Svc.PrmDb base id 0x10003000 \ + instance face4LoadSwitch: Components.LoadSwitch base id 0x10003000 \ + queue size Default.QUEUE_SIZE \ + stack size Default.STACK_SIZE \ + priority 5 + + instance face0LoadSwitch: Components.LoadSwitch base id 0x10004000 \ + queue size Default.QUEUE_SIZE \ + stack size Default.STACK_SIZE \ + priority 5 + + instance face1LoadSwitch: Components.LoadSwitch base id 0x10005000 \ + queue size Default.QUEUE_SIZE \ + stack size Default.STACK_SIZE \ + priority 5 + + instance face2LoadSwitch: Components.LoadSwitch base id 0x10006000 \ + queue size Default.QUEUE_SIZE \ + stack size Default.STACK_SIZE \ + priority 5 + + instance face3LoadSwitch: Components.LoadSwitch base id 0x10007000 \ + queue size Default.QUEUE_SIZE \ + stack size Default.STACK_SIZE \ + priority 5 + + instance face5LoadSwitch: Components.LoadSwitch base id 0x10008000 \ + queue size Default.QUEUE_SIZE \ + stack size Default.STACK_SIZE \ + priority 5 + + instance payloadPowerLoadSwitch: Components.LoadSwitch base id 0x10009000 \ + queue size Default.QUEUE_SIZE \ + stack size Default.STACK_SIZE \ + priority 5 + + instance payloadBatteryLoadSwitch: Components.LoadSwitch base id 0x1000A000 \ + queue size Default.QUEUE_SIZE \ + stack size Default.STACK_SIZE \ + priority 5 + + instance prmDb: Svc.PrmDb base id 0x1000B000 \ queue size Default.QUEUE_SIZE \ stack size Default.STACK_SIZE \ priority 5 @@ -64,7 +104,7 @@ module ReferenceDeployment { instance rtcManager: Drv.RtcManager base id 0x10016000 - instance imuManager: Components.ImuManager base id 0x10017000 + instance DetumbleManager: Components.DetumbleManager base id 0x10017000 instance lis2mdlManager: Drv.Lis2mdlManager base id 0x10018000 @@ -95,4 +135,6 @@ module ReferenceDeployment { instance ina219SysManager: Drv.Ina219Manager base id 0x10032000 instance ina219SolManager: Drv.Ina219Manager base id 0x10033000 + + instance magnetorquerManager: Drv.MagnetorquerManager base id 0x10034000 } diff --git a/FprimeZephyrReference/ReferenceDeployment/Top/topology.fpp b/FprimeZephyrReference/ReferenceDeployment/Top/topology.fpp index 79169a2e..02a4ea14 100644 --- a/FprimeZephyrReference/ReferenceDeployment/Top/topology.fpp +++ b/FprimeZephyrReference/ReferenceDeployment/Top/topology.fpp @@ -32,7 +32,7 @@ module ReferenceDeployment { instance watchdog instance prmDb instance rtcManager - instance imuManager + instance DetumbleManager instance lis2mdlManager instance lsm6dsoManager instance bootloaderTrigger @@ -43,10 +43,20 @@ 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 magnetorquerManager # ---------------------------------------------------------------------- @@ -127,6 +137,7 @@ module ReferenceDeployment { rateGroup10Hz.RateGroupMemberOut[0] -> comDriver.schedIn rateGroup10Hz.RateGroupMemberOut[1] -> ComCcsdsUart.aggregator.timeout rateGroup10Hz.RateGroupMemberOut[2] -> ComCcsds.aggregator.timeout + rateGroup10Hz.RateGroupMemberOut[3] -> DetumbleManager.run # Slow rate (1Hz) rate group rateGroupDriver.CycleOut[Ports_RateGroups.rateGroup1Hz] -> rateGroup1Hz.CycleIn @@ -135,7 +146,6 @@ module ReferenceDeployment { rateGroup1Hz.RateGroupMemberOut[2] -> ComCcsds.commsBufferManager.schedIn rateGroup1Hz.RateGroupMemberOut[3] -> CdhCore.tlmSend.Run rateGroup1Hz.RateGroupMemberOut[4] -> watchdog.run - rateGroup1Hz.RateGroupMemberOut[5] -> imuManager.run rateGroup1Hz.RateGroupMemberOut[6] -> comDelay.run rateGroup1Hz.RateGroupMemberOut[7] -> burnwire.schedIn rateGroup1Hz.RateGroupMemberOut[8] -> antennaDeployer.schedIn @@ -159,11 +169,12 @@ module ReferenceDeployment { antennaDeployer.burnStop -> burnwire.burnStop } - connections imuManager { - imuManager.accelerationGet -> lsm6dsoManager.accelerationGet - imuManager.angularVelocityGet -> lsm6dsoManager.angularVelocityGet - imuManager.magneticFieldGet -> lis2mdlManager.magneticFieldGet - imuManager.temperatureGet -> lsm6dsoManager.temperatureGet + connections DetumbleManager { + DetumbleManager.accelerationGet -> lsm6dsoManager.accelerationGet + DetumbleManager.angularVelocityGet -> lsm6dsoManager.angularVelocityGet + DetumbleManager.magneticFieldGet -> lis2mdlManager.magneticFieldGet + DetumbleManager.temperatureGet -> lsm6dsoManager.temperatureGet + DetumbleManager.magnetorquersSet -> magnetorquerManager.SetMagnetorquers } connections sysPowerMonitor { 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/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..21672f1f 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,180 @@ 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>; + + i2c_mux@0 { + compatible = "ti,tca9548a-channel"; + label = "face0_i2c"; + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + face0_temp_sens: tmp112@72 { + compatible = "ti,tmp112"; + reg = <0x72>; + }; + + 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_temp_sens: tmp112@72 { + compatible = "ti,tmp112"; + reg = <0x72>; + }; + + 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_temp_sens: tmp112@72 { + compatible = "ti,tmp112"; + reg = <0x72>; + }; + + 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_temp_sens: tmp112@72 { + compatible = "ti,tmp112"; + reg = <0x72>; + }; + + 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@72 { + compatible = "ti,tmp112"; + reg = <0x72>; + }; + batt_cell2_temp_sens: tmp112@73 { + compatible = "ti,tmp112"; + reg = <0x73>; + }; + batt_cell3_temp_sens: tmp112@74 { + compatible = "ti,tmp112"; + reg = <0x74>; + }; + batt_cell4_temp_sens: tmp112@75 { + compatible = "ti,tmp112"; + reg = <0x75>; + }; + }; + + i2c_mux@5 { + compatible = "ti,tca9548a-channel"; + label = "face4_i2c"; + reg = <5>; + #address-cells = <1>; + #size-cells = <0>; + face4_temp_sens: tmp112@72 { + compatible = "ti,tmp112"; + reg = <0x72>; + }; + + 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_temp_sens: tmp112@72 { + compatible = "ti,tmp112"; + reg = <0x72>; + }; + }; + + i2c_mux@7 { + compatible = "ti,tca9548a-channel"; + label = "top_i2c"; + reg = <7>; + #address-cells = <1>; + #size-cells = <0>; + top_temp_sens: tmp112@72 { + compatible = "ti,tmp112"; + reg = <0x72>; + }; + }; + }; }; @@ -190,4 +364,137 @@ 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 for traceability + gpio-line-names = "FACE4_ENABLE", "FACE0_ENABLE", "FACE1_ENABLE", "FACE2_ENABLE", + "FACE3_ENABLE", "FACE5_ENABLE", "READONLY", "CHARGE", + "ENABLE_Heater", "PAYLOAD_PWR_ENABLE", "FIRE_DEPLOY2_B", "PAYLOAD_BATT_ENABLE", + "RF2_IO2", "RF2_IO1", "RF2_IO0", "RF2_IO3"; + + 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..72461cee 100644 --- a/prj.conf +++ b/prj.conf @@ -28,6 +28,9 @@ CONFIG_GPIO=y CONFIG_LED=y CONFIG_PWM=n CONFIG_I2C=y +# I2C multiplexer (TCA9548A) priority configuration +CONFIG_I2C_TCA954X_ROOT_INIT_PRIO=70 +CONFIG_I2C_TCA954X_CHANNEL_INIT_PRIO=71 CONFIG_SPI=y CONFIG_PINCTRL=y CONFIG_ASSERT=y @@ -36,7 +39,7 @@ CONFIG_DYNAMIC_THREAD=y CONFIG_KERNEL_MEM_POOL=y CONFIG_DYNAMIC_THREAD_ALLOC=n CONFIG_DYNAMIC_THREAD_PREFER_POOL=y -CONFIG_DYNAMIC_THREAD_POOL_SIZE=15 +CONFIG_DYNAMIC_THREAD_POOL_SIZE=24 # 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' @@ -65,3 +68,6 @@ CONFIG_FAT_FILESYSTEM_ELM=y CONFIG_FS_FATFS_EXFAT=y CONFIG_FS_FATFS_MOUNT_MKFS=y CONFIG_FS_FATFS_FSTAB_AUTOMOUNT=y + +CONFIG_HAPTICS=y +CONFIG_HAPTICS_DRV2605=y