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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions FprimeZephyrReference/Components/Drv/RtcManager/RtcManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,19 @@ void RtcManager ::TIME_SET_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, Drv::Time
// Store current time for logging
Fw::Time time_before_set = this->getTime();

// Cancel any running sequences BEFORE setting time
// This prevents premature execution of time-based commands after time change
// Port index 0 = cmdSeq, port index 1 = payloadSeq, port index 2 = safeModeSeq
if (this->isConnected_cancelSequences_OutputPort(0)) {
this->cancelSequences_out(0);
}
if (this->isConnected_cancelSequences_OutputPort(1)) {
this->cancelSequences_out(1);
}
if (this->isConnected_cancelSequences_OutputPort(2)) {
this->cancelSequences_out(2);
}
Comment on lines +101 to +112
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm good spot for a loop...


// Populate rtc_time structure from TimeData
const struct rtc_time time_rtc = {
.tm_sec = static_cast<int>(t.get_Second()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ module Drv {
second: U32 @< The invalid second
) severity warning high id 10 format "Provided second is invalid should be in [0, 59]: {}"

###############################################################################
# Port for canceling sequences on time change #
###############################################################################
@ Port for canceling running sequences when RTC time is set
@ Connected to seqCancelIn ports of Command, Payload, and SafeMode sequencers
output port cancelSequences: [3] Svc.CmdSeqCancel

###############################################################################
# Standard AC Ports: Required for Channels, Events, Commands, and Parameters #
###############################################################################
Expand Down
5 changes: 5 additions & 0 deletions FprimeZephyrReference/ReferenceDeployment/Top/topology.fpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,11 @@ module ReferenceDeployment {
modeManager.runSequence -> safeModeSeq.seqRunIn
safeModeSeq.seqDone -> modeManager.completeSequence

# RTC time change cancels running sequences
rtcManager.cancelSequences[0] -> cmdSeq.seqCancelIn
rtcManager.cancelSequences[1] -> payloadSeq.seqCancelIn
rtcManager.cancelSequences[2] -> safeModeSeq.seqCancelIn


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't forget to also add a connection to the safe mode sequencer!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added connection to safeModeSeq.seqCancelIn. All three sequencers (cmdSeq, payloadSeq, safeModeSeq) are now connected. Commit: badd953

}

Expand Down
68 changes: 68 additions & 0 deletions FprimeZephyrReference/test/int/rtc_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
resetManager = "ReferenceDeployment.resetManager"
rtcManager = "ReferenceDeployment.rtcManager"
ina219SysManager = "ReferenceDeployment.ina219SysManager"
cmdSeq = "ReferenceDeployment.cmdSeq"
payloadSeq = "ReferenceDeployment.payloadSeq"
safeModeSeq = "ReferenceDeployment.safeModeSeq"


@pytest.fixture(autouse=True)
Expand Down Expand Up @@ -156,3 +159,68 @@ def test_03_time_not_set_event(fprime_test_api: IntegrationTestAPI, start_gds):
fprime_test_api.send_and_assert_event(
f"{rtcManager}.TIME_SET", [time_data_str], events, timeout=10
)


def test_04_sequence_cancellation_on_time_set(
fprime_test_api: IntegrationTestAPI, start_gds
):
"""Test that running sequences are canceled when RTC time is set

This test verifies the behavior described in issue #282:
- Start dummy sequences on cmdSeq and payloadSeq
- Set the RTC time
- Assert that CS_SequenceCanceled events are emitted for both sequencers
"""

# Clear histories to start fresh
fprime_test_api.clear_histories()

# Start test sequences on cmdSeq and payloadSeq
# These sequences have delays so they'll be running when we set the time
print("Starting test sequence on cmdSeq...")
fprime_test_api.send_and_assert_command(
f"{cmdSeq}.CS_RUN", ["/seq/test_rtc_cancel.bin", "NO_BLOCK"], timeout=5
)

print("Starting test sequence on payloadSeq...")
fprime_test_api.send_and_assert_command(
f"{payloadSeq}.CS_RUN", ["/seq/test_rtc_cancel.bin", "NO_BLOCK"], timeout=5
)

# Wait a moment to ensure sequences are running
time.sleep(0.5)
Comment on lines +190 to +191
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check for an event rather than sleeping.


# Clear histories before setting time so we can check for cancel events
fprime_test_api.clear_histories()

# Set the RTC time - this should trigger sequence cancellation
print("Setting RTC time (should cancel sequences)...")
curiosity_landing = datetime(2012, 8, 6, 5, 17, 57, tzinfo=timezone.utc)
set_time(fprime_test_api, curiosity_landing)

# Assert that we see CS_SequenceCanceled or CS_NoSequenceActive events
# The sequences should be canceled before the time is actually set
print("Checking for sequence cancellation events...")

# Get all events after the TIME_SET command
events = fprime_test_api.get_event_test_history()

# Look for CS_SequenceCanceled events from cmdSeq or payloadSeq
# Or CS_NoSequenceActive if the sequence already completed (which is also valid)
cancel_events = [
e
for e in events
if "CS_SequenceCanceled" in str(e.get_template().get_name())
or "CS_NoSequenceActive" in str(e.get_template().get_name())
]

# We should see at least one cancellation event (could be 2 if both sequences were running)
# or NoSequenceActive events if sequences completed before cancellation
assert len(cancel_events) >= 1, (
f"Expected to see CS_SequenceCanceled or CS_NoSequenceActive events, "
f"but got: {[str(e.get_template().get_name()) for e in events]}"
)

print(f"Found {len(cancel_events)} sequence cancellation/status events")
for event in cancel_events:
print(f" - {event.get_template().get_name()}")
3 changes: 3 additions & 0 deletions sequences/test_rtc_cancel.seq
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we automate uploading this sequence?

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
; Test sequence for RTC cancellation test
; This sequence has a long delay to occupy the sequencer when RTC time is set
R00:01:00 CdhCore.cmdDisp.CMD_NO_OP_STRING, "Hello World!"