diff --git a/FprimeZephyrReference/Components/Burnwire/Burnwire.cpp b/FprimeZephyrReference/Components/Burnwire/Burnwire.cpp new file mode 100644 index 00000000..a4536519 --- /dev/null +++ b/FprimeZephyrReference/Components/Burnwire/Burnwire.cpp @@ -0,0 +1,84 @@ +// ====================================================================== +// \title Burnwire.cpp +// \brief cpp file for Burnwire component implementation class +// ====================================================================== + +#include "FprimeZephyrReference/Components/Burnwire/Burnwire.hpp" + +namespace Components { + +// ---------------------------------------------------------------------- +// Component construction and destruction +// ---------------------------------------------------------------------- + +Burnwire ::Burnwire(const char* const compName) : BurnwireComponentBase(compName) { + this->m_safetyCounter = 0; + this->m_state = Fw::On::OFF; +} + +Burnwire ::~Burnwire() {} + +// ---------------------------------------------------------------------- +// Handler implementations for typed input ports +// ---------------------------------------------------------------------- +void Burnwire ::burnStart_handler(FwIndexType portNum) { + this->startBurn(); +} + +void Burnwire ::burnStop_handler(FwIndexType portNum) { + this->stopBurn(); +} + +void Burnwire::startBurn() { + this->log_ACTIVITY_HI_SetBurnwireState(Fw::On::ON); + this->m_safetyCounter = 0; + this->m_state = Fw::On::ON; + + Fw::ParamValid valid; + U32 timeout = this->paramGet_SAFETY_TIMER(valid); + this->log_ACTIVITY_HI_SafetyTimerState(timeout); +} + +void Burnwire::stopBurn() { + this->log_ACTIVITY_HI_SetBurnwireState(Fw::On::OFF); + this->gpioSet_out(0, Fw::Logic::LOW); + this->gpioSet_out(1, Fw::Logic::LOW); + + this->m_state = Fw::On::OFF; + this->log_ACTIVITY_LO_BurnwireEndCount(m_safetyCounter); +} + +void Burnwire ::schedIn_handler(FwIndexType portNum, U32 context) { + Fw::ParamValid valid; + U32 timeout = this->paramGet_SAFETY_TIMER(valid); + + if (this->m_state == Fw::On::ON) { + this->m_safetyCounter++; + if (this->m_safetyCounter == 1) { + this->gpioSet_out(0, Fw::Logic::HIGH); + this->gpioSet_out(1, Fw::Logic::HIGH); + this->log_ACTIVITY_HI_SafetyTimerStatus(Fw::On::ON); + } + + if (this->m_safetyCounter >= timeout) { + stopBurn(); + this->log_ACTIVITY_HI_SafetyTimerStatus(Fw::On::OFF); + } + } +} + +// ---------------------------------------------------------------------- +// Handler implementations for commands +// ---------------------------------------------------------------------- + +void Burnwire ::START_BURNWIRE_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) { + this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); + this->startBurn(); +} + +void Burnwire ::STOP_BURNWIRE_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) { + this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); + this->stopBurn(); +} + +} // namespace Components diff --git a/FprimeZephyrReference/Components/Burnwire/Burnwire.fpp b/FprimeZephyrReference/Components/Burnwire/Burnwire.fpp new file mode 100644 index 00000000..4f529e54 --- /dev/null +++ b/FprimeZephyrReference/Components/Burnwire/Burnwire.fpp @@ -0,0 +1,75 @@ +module Components { + @ Turns Burnwire on and off + passive component Burnwire { + + @ START_BURNWIRE turns on the burnwire + sync command START_BURNWIRE( + ) + + @ STOP_BURNWIRE turns on the burnwire + sync command STOP_BURNWIRE( + ) + + event SetBurnwireState(burnwire_state: Fw.On) \ + severity activity high \ + format "Burnwire State: {}" + + event SafetyTimerStatus(burnwire_state: Fw.On) \ + severity activity high\ + format "Safety Timer State: {} " + + event SafetyTimerState(burnwire_status: U32) \ + severity activity high\ + format "Safety Timer Will Burn For: {} Seconds" + + event BurnwireEndCount(end_count: U32) \ + severity activity low \ + format "Burnwire Burned for {} Seconds" + + @ Port getting start signal + sync input port burnStart: Fw.Signal + + @ Port getting stop signal + sync input port burnStop: Fw.Signal + + @ Input Port to get the rate group + sync input port schedIn: Svc.Sched + + @ Port sending calls to the GPIO driver to stop and start the burnwire + output port gpioSet: [2] Drv.GpioWrite + + # @ SAFETY_TIMER parameter is the maximum time that the burn component will run + param SAFETY_TIMER: U32 default 10 + + ############################################################################### + # 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/Burnwire/Burnwire.hpp b/FprimeZephyrReference/Components/Burnwire/Burnwire.hpp new file mode 100644 index 00000000..4f41d832 --- /dev/null +++ b/FprimeZephyrReference/Components/Burnwire/Burnwire.hpp @@ -0,0 +1,70 @@ +// ====================================================================== +// \title Burnwire.hpp +// \brief hpp file for Burnwire component implementation class +// ====================================================================== + +#ifndef Components_Burnwire_HPP +#define Components_Burnwire_HPP + +#include +#include "FprimeZephyrReference/Components/Burnwire/BurnwireComponentAc.hpp" + +namespace Components { + +class Burnwire final : public BurnwireComponentBase { + public: + // ---------------------------------------------------------------------- + // Component construction and destruction + // ---------------------------------------------------------------------- + + //! Construct Burnwire object + Burnwire(const char* const compName //!< The component name + ); + + //! Destroy Burnwire object + ~Burnwire(); + + private: + // ---------------------------------------------------------------------- + // Handler implementations for typed input ports + // ---------------------------------------------------------------------- + + //! Handler implementation for burnStart + //! + //! Port getting start signal + void burnStart_handler(FwIndexType portNum //!< The port number + ) override; + + //! Handler implementation for burnStop + //! + //! Port getting stop signal + void burnStop_handler(FwIndexType portNum //!< The port number + ) override; + + void schedIn_handler(FwIndexType portNum, //!< The port number + U32 context //!< The call order + ) override; + + void startBurn(); + + void stopBurn(); + + private: + // ---------------------------------------------------------------------- + // Handler implementations for commands + // ---------------------------------------------------------------------- + + //! Handler implementation for command START_BURNWIRE + void START_BURNWIRE_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) override; + + //! Handler implementation for command STOP_BURNWIRE + void STOP_BURNWIRE_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) override; + + Fw::On m_state = Fw::On::OFF; // keeps track if burnwire is on or off + std::atomic m_safetyCounter; // makes this an atomic variable (so its set only in one command), + // you read and write half the value bc a corrupted read could be dangerouts +}; + +} // namespace Components + +#endif diff --git a/FprimeZephyrReference/Components/Burnwire/CMakeLists.txt b/FprimeZephyrReference/Components/Burnwire/CMakeLists.txt new file mode 100644 index 00000000..5e68dc91 --- /dev/null +++ b/FprimeZephyrReference/Components/Burnwire/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}/Burnwire.fpp" + SOURCES + "${CMAKE_CURRENT_LIST_DIR}/Burnwire.cpp" +# DEPENDS +# MyPackage_MyOtherModule +) + +### Unit Tests ### +# register_fprime_ut( +# AUTOCODER_INPUTS +# "${CMAKE_CURRENT_LIST_DIR}/Burnwire.fpp" +# SOURCES +# "${CMAKE_CURRENT_LIST_DIR}/test/ut/BurnwireTestMain.cpp" +# "${CMAKE_CURRENT_LIST_DIR}/test/ut/BurnwireTester.cpp" +# DEPENDS +# STest # For rules-based testing +# UT_AUTO_HELPERS +# ) diff --git a/FprimeZephyrReference/Components/Burnwire/docs/sdd.md b/FprimeZephyrReference/Components/Burnwire/docs/sdd.md new file mode 100644 index 00000000..62d5f959 --- /dev/null +++ b/FprimeZephyrReference/Components/Burnwire/docs/sdd.md @@ -0,0 +1,62 @@ +# Components::Burnwire + +Driving the Burnwire on and off. This component activates the two pins that are required to heat the burnwire resisitor. The burnwire deployment will be handled by the Antenna Deployment, that will call the ports in the burnwire deployment. For testing, the commands to directly call the burnwire have been left in. + +Burnwire is agnostic to the ideal safety count, it simply sets it to be whatever the port or command passes onto + +## Sequence Diagrams +Add sequence diagrams here + +## Requirements +Add requirements in the chart below +| Name | Description | Validation | +| ---- | ----------- | ------ | +|BW-001|The burnwire shall turn on and off in response to a port calls (TBR for antenna deployer component) |Hardware Test| +|BW-002|The burnwire shall turn on and off in response to commands (TBR for testing for now) |Hardware Test| +|BW-003|The burnwire component shall provide an event when it is turned on and off |Integration Test| +|BW-004|The burnwire component shall activate by turning both the GPIO pins that activate the burnwire | Hardware Test| +|BW-005|The burnwire component shall be controlled by a safety timeout attached to a 1Hz rate group |Integration Test| +|BW-006|The safety timeout shall emit an event when it is changes | Integration test| +|BW-007|The burnwire safety time shall emit an event when it starts and stops |Integration Test| + +## Port Descriptions +Name | Type | Description | +|----|---|---| +|burnStop|`Fw::Signal`|Receive stop signal to stop the burnwire| +|burnStart|`Fw::Signal`|Receive start signal to start burnwire| +|gpioSet|`Drv::GpioWrite`|Control GPIO state to driver| +|schedIn|[`Svc::Sched`]| run | Input | Synchronous | Receive periodic calls from rate group| + + +## Commands +| Name | Description | +| ---- | ----------- | +|START_BURNWIRE|Starts the Burn| +|STOP_BURNWIRE|Stops the Burn| + +## Events +| Name | Description | +|---|---| +|SetBurnwireState| Emits burnwire state when the burnwire turns on or off| +|SafetyTimerStatus| Emits safety timer state when the Safety Time has stopped or started| +|SafetyTimerState| Emits the amount of time the safety time will run for when it starts| +| BurnwireEndCount| How long the burnwire actually burned for | + +## Component States +Add component states in the chart below +| Name | Description | +|----|---| +|m_state|Keeps track if the burnwire is on or off| + +## Tests +Add unit test descriptions in the chart below +| Name | Description | Output | Coverage | +|------|-------------|--------|----------| +|TestSafety|Tests Burnwire turns off after SAFETY_TIMER seconds|Integration|---| +|TestSafety|Tests Burnwire emits correct events after start and stop|Integration|---| + + +## Parameter +| Name | Description | +| -----|-------------| +| SAFETY_TIMER | By Default set in fpp (currently 10) is the max time the burnwire should ever run| diff --git a/FprimeZephyrReference/Components/CMakeLists.txt b/FprimeZephyrReference/Components/CMakeLists.txt index 08ac562c..fcd50b7c 100644 --- a/FprimeZephyrReference/Components/CMakeLists.txt +++ b/FprimeZephyrReference/Components/CMakeLists.txt @@ -4,4 +4,5 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Drv/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FatalHandler") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ImuManager/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Watchdog") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Burnwire/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/BootloaderTrigger/") diff --git a/FprimeZephyrReference/Components/Watchdog/Watchdog.cpp b/FprimeZephyrReference/Components/Watchdog/Watchdog.cpp index 91c8e102..da205821 100644 --- a/FprimeZephyrReference/Components/Watchdog/Watchdog.cpp +++ b/FprimeZephyrReference/Components/Watchdog/Watchdog.cpp @@ -54,19 +54,21 @@ void Watchdog ::stop_handler(FwIndexType portNum) { // ---------------------------------------------------------------------- void Watchdog ::START_WATCHDOG_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) { + this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); + // call start handler this->start_handler(0); // Provide command response - this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); } void Watchdog ::STOP_WATCHDOG_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) { + this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); + // call stop handler this->stop_handler(0); // Provide command response - this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); } } // namespace Components diff --git a/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentTopology.cpp b/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentTopology.cpp index 4e3bb311..d06583fa 100644 --- a/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentTopology.cpp +++ b/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentTopology.cpp @@ -14,6 +14,8 @@ #include 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); // Allows easy reference to objects in FPP/autocoder required namespaces using namespace ReferenceDeployment; @@ -55,6 +57,8 @@ void configureTopology() { rateGroup1Hz.configure(rateGroup1HzContext, FW_NUM_ARRAY_ELEMENTS(rateGroup1HzContext)); gpioDriver.open(ledGpio, Zephyr::ZephyrGpioDriver::GpioConfiguration::OUT); + gpioBurnwire0.open(burnwire0Gpio, Zephyr::ZephyrGpioDriver::GpioConfiguration::OUT); + gpioBurnwire1.open(burnwire1Gpio, Zephyr::ZephyrGpioDriver::GpioConfiguration::OUT); } // Public functions for use in main program are namespaced with deployment name ReferenceDeployment diff --git a/FprimeZephyrReference/ReferenceDeployment/Top/instances.fpp b/FprimeZephyrReference/ReferenceDeployment/Top/instances.fpp index 1dff4a28..7bda4baf 100644 --- a/FprimeZephyrReference/ReferenceDeployment/Top/instances.fpp +++ b/FprimeZephyrReference/ReferenceDeployment/Top/instances.fpp @@ -70,4 +70,10 @@ module ReferenceDeployment { instance lsm6dsoManager: Drv.Lsm6dsoManager base id 0x10019000 instance bootloaderTrigger: Components.BootloaderTrigger base id 0x10020000 + + instance burnwire: Components.Burnwire base id 0x10021000 + + instance gpioBurnwire0: Zephyr.ZephyrGpioDriver base id 0x10022000 + + instance gpioBurnwire1: Zephyr.ZephyrGpioDriver base id 0x10023000 } diff --git a/FprimeZephyrReference/ReferenceDeployment/Top/topology.fpp b/FprimeZephyrReference/ReferenceDeployment/Top/topology.fpp index 4f42fd3b..5c58f643 100644 --- a/FprimeZephyrReference/ReferenceDeployment/Top/topology.fpp +++ b/FprimeZephyrReference/ReferenceDeployment/Top/topology.fpp @@ -26,6 +26,8 @@ module ReferenceDeployment { instance timer instance comDriver instance gpioDriver + instance gpioBurnwire0 + instance gpioBurnwire1 instance watchdog instance prmDb instance rtcManager @@ -33,6 +35,8 @@ module ReferenceDeployment { instance lis2mdlManager instance lsm6dsoManager instance bootloaderTrigger + instance burnwire + # ---------------------------------------------------------------------- # Pattern graph specifiers # ---------------------------------------------------------------------- @@ -96,19 +100,24 @@ module ReferenceDeployment { rateGroup1Hz.RateGroupMemberOut[3] -> CdhCore.tlmSend.Run rateGroup1Hz.RateGroupMemberOut[4] -> watchdog.run rateGroup1Hz.RateGroupMemberOut[5] -> imuManager.run + rateGroup1Hz.RateGroupMemberOut[6] -> burnwire.schedIn + } connections Watchdog { watchdog.gpioSet -> gpioDriver.gpioWrite } + connections BurnwireGpio { + burnwire.gpioSet[0] -> gpioBurnwire0.gpioWrite + burnwire.gpioSet[1] -> gpioBurnwire1.gpioWrite + } + connections imuManager { imuManager.accelerationGet -> lsm6dsoManager.accelerationGet imuManager.angularVelocityGet -> lsm6dsoManager.angularVelocityGet imuManager.magneticFieldGet -> lis2mdlManager.magneticFieldGet imuManager.temperatureGet -> lsm6dsoManager.temperatureGet } - } - } diff --git a/FprimeZephyrReference/project/config/CommandDispatcherImplCfg.hpp b/FprimeZephyrReference/project/config/CommandDispatcherImplCfg.hpp index a0257cff..ab88a46b 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 = 21, // !< The size of the table holding opcodes to dispatch + CMD_DISPATCHER_DISPATCH_TABLE_SIZE = 50, // !< 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/test/int/burnwire_test.py b/FprimeZephyrReference/test/int/burnwire_test.py new file mode 100644 index 00000000..882124b7 --- /dev/null +++ b/FprimeZephyrReference/test/int/burnwire_test.py @@ -0,0 +1,93 @@ +# """ +# burnwire_test.py: + +# Integration tests for the Burnwire component. +# """ + +import pytest +from fprime_gds.common.testing_fw.api import IntegrationTestAPI + +# Constants + + +@pytest.fixture(autouse=True) +def reset_burnwire(fprime_test_api: IntegrationTestAPI): + """Fixture to stop burnwire and clear histories before/after each test""" + # Stop burnwire and clear before test + fprime_test_api.clear_histories() + stop_burnwire(fprime_test_api) + yield + # Clear again after test to prevent residue + fprime_test_api.clear_histories() + stop_burnwire(fprime_test_api) + + +def stop_burnwire(fprime_test_api: IntegrationTestAPI): + fprime_test_api.send_and_assert_command( + "ReferenceDeployment.burnwire.STOP_BURNWIRE" + ) + + fprime_test_api.assert_event( + "ReferenceDeployment.burnwire.SetBurnwireState", "OFF", timeout=10 + ) + + fprime_test_api.assert_event( + "ReferenceDeployment.burnwire.BurnwireEndCount", timeout=2 + ) + + received_events = fprime_test_api.get_event_subhistory() + print(f"Received events: {received_events}") + + +def test_01_start_and_stop_burnwire(fprime_test_api: IntegrationTestAPI, start_gds): + """Test that burnwire starts and stops as expected""" + + # Start burnwire + fprime_test_api.send_and_assert_command( + "ReferenceDeployment.burnwire.START_BURNWIRE" + ) + + # Wait for SetBurnwireState = ON + fprime_test_api.assert_event( + "ReferenceDeployment.burnwire.SetBurnwireState", "ON", timeout=2 + ) + + fprime_test_api.assert_event( + "ReferenceDeployment.burnwire.SafetyTimerState", timeout=2 + ) + + fprime_test_api.assert_event( + "ReferenceDeployment.burnwire.SetBurnwireState", "OFF", timeout=10 + ) + + fprime_test_api.assert_event( + "ReferenceDeployment.burnwire.BurnwireEndCount", timeout=2 + ) + + +def test_02_manual_stop_before_timeout(fprime_test_api: IntegrationTestAPI, start_gds): + """Test that burnwire stops manually before the safety timer expires""" + + # Start burnwire + fprime_test_api.send_and_assert_command( + "ReferenceDeployment.burnwire.START_BURNWIRE" + ) + + # Confirm Burnwire turned ON + fprime_test_api.assert_event( + "ReferenceDeployment.burnwire.SetBurnwireState", "ON", timeout=2 + ) + + # # Stop burnwire before safety timer triggers + fprime_test_api.send_and_assert_command( + "ReferenceDeployment.burnwire.STOP_BURNWIRE" + ) + + # Confirm Burnwire turned OFF + fprime_test_api.assert_event( + "ReferenceDeployment.burnwire.SetBurnwireState", "OFF", timeout=2 + ) + + fprime_test_api.assert_event( + "ReferenceDeployment.burnwire.BurnwireEndCount", timeout=2 + ) 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 e93b7426..397708c7 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 @@ -24,6 +24,14 @@ gpios = <&gpio0 23 GPIO_ACTIVE_HIGH>; label = "Watchdog LED"; }; + burnwire0: burnwire0{ + gpios = <&gpio0 28 GPIO_ACTIVE_HIGH>; + label = "burnwire 0"; + }; + burnwire1: burnwire1{ + gpios = <&gpio0 29 GPIO_ACTIVE_HIGH>; + label = "burnwire 1"; + }; }; };