Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
75cfa31
changed rtc tests to assert
collinc04 May 25, 2026
f385b3a
updated rtc tests to use assert
collinc04 May 25, 2026
94a06e5
Merge branch 'main' into RTC_test_fix
collinc04 May 25, 2026
bfc9356
Updated code
collinc04 May 25, 2026
51904cf
Merge branch 'main' into RTC_test_fix
Mikefly123 May 28, 2026
4d14cf5
Revert Zephyr to What's on Main
Mikefly123 May 29, 2026
435ce42
Change order of TMP112 to Run Last
Mikefly123 May 29, 2026
9302e89
Merge branch 'main' of https://github.com/Open-Source-Space-Foundatio…
collinc04 Jul 20, 2026
a10dd96
fix test #6
collinc04 Jul 20, 2026
9a031e7
Submodule branch switch
collinc04 Jul 20, 2026
4e04d63
Merge branch 'main' of https://github.com/Open-Source-Space-Foundatio…
collinc04 Jul 20, 2026
d6000b1
Merge branch 'main' into RTC_test_fix
collinc04 Jul 20, 2026
12478c0
test bug fix
collinc04 Jul 20, 2026
7aaf430
bug test fixed
collinc04 Jul 20, 2026
0d02d0b
cleanup
collinc04 Aug 2, 2026
3cd67a9
fixed sub
collinc04 Aug 2, 2026
746e24f
Merge branch 'main' of github.com:open-source-space-foundation/proves…
nateinaction Aug 2, 2026
16468ad
Replace usages of start=NOW
nateinaction Aug 2, 2026
6803ab7
Eliminate test 6 race condition
collinc04 Aug 3, 2026
6c9a181
mark uart
collinc04 Aug 3, 2026
6243eaa
increased buffer time
collinc04 Aug 3, 2026
ae116fc
big buffer
collinc04 Aug 3, 2026
fe0dc47
RTC time assured
collinc04 Aug 4, 2026
02a605a
blocking added for 497
collinc04 Aug 4, 2026
081d2b0
updated tests
collinc04 Aug 5, 2026
0ac06b0
functionality
collinc04 Aug 5, 2026
43b16df
Merge branch 'main' into RTC_conflict_fix
collinc04 Aug 13, 2026
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
Original file line number Diff line number Diff line change
Expand Up @@ -185,12 +185,28 @@ void RtcManager ::parameterUpdated(FwPrmIdType id) {
this->cancelSequences_out(i);
}

// Cancel pending alarm, as switching the timebase causes undefined behavior
uint16_t mask = 0;
int rc = rtc_alarm_set_time(this->m_dev, 0, mask, &this->m_alarm_time);
if (rc != 0) {
// log failure
this->log_WARNING_HI_AlarmHardwareError(0, rc);
}

this->log_ACTIVITY_HI_TimeBaseChanged(timeBase);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

void RtcManager ::ALARM_SET_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, Drv::TimeData t) {
// retrieve info about current alarm
// Check the TimeBase parameter to ensure that we are using RTC time
Fw::ParamValid valid;
const Rtc::TimeBase timeBase = this->paramGet_TIMEBASE(valid);
if (timeBase == Rtc::TimeBase::TB_PROC_TIME) {
this->log_WARNING_HI_AlarmNotSet(t, EINVAL);
this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
return;
}

// retrieve info about current alarm
uint16_t mask = this->m_curr_mask;
int rc = rtc_alarm_get_time(this->m_dev, 0, &mask, &this->m_alarm_time);

Expand Down
176 changes: 158 additions & 18 deletions PROVESFlightControllerReference/test/int/rtc_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,12 @@ def test_04_sequence_cancellation_on_time_set(
def test_05_rtc_alarm_set_and_trigger(fprime_test_api: IntegrationTestAPI, start_gds):
"""Test that we can set an RTC alarm and that it triggers at the correct time"""

# Ensure that we are not using proc time
proves_send_and_assert_command(
fprime_test_api, f"{rtcManager}.TIMEBASE_PRM_SET", ["TB_SC_TIME"]
)
fprime_test_api.await_event(f"{rtcManager}.TimeBaseChanged", timeout=10)

# Clear histories
fprime_test_api.clear_histories()

Expand All @@ -302,17 +308,22 @@ def test_05_rtc_alarm_set_and_trigger(fprime_test_api: IntegrationTestAPI, start
Second=alarm_time.second,
)
alarm_time_data_str = json.dumps(alarm_time_data)
start: TimeType = TimeType().set_datetime(
datetime.now(), time_base=TimeType.TimeBase("TB_DONT_CARE")
)
Comment on lines +311 to +313

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -C 2 'set_datetime\(' PROVESFlightControllerReference/test/int
rg -n -C 2 'datetime\.now\(timezone\.utc\)' PROVESFlightControllerReference/test/int

Repository: Open-Source-Space-Foundation/proves-core-reference

Length of output: 15158


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== rtc_test.py imports and nearby helper =="
sed -n '1,80p;255,515p' PROVESFlightControllerReference/test/int/rtc_test.py

echo
echo "== locate TimeType definition/usages =="
rg -n "class TimeType|def set_datetime|TimeBase|TB_DONT_CARE|TB_UTC|TB_" .

Repository: Open-Source-Space-Foundation/proves-core-reference

Length of output: 24805


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== TimeType source in installed package =="
python3 - <<'PY'
import inspect
from fprime_gds.common.models.serialize.time_type import TimeType
print("module:", TimeType.__module__)
print(inspect.getsourcefile(TimeType))
print("\nset_datetime source:")
try:
    print(inspect.getsource(TimeType.set_datetime))
except Exception as e:
    print(type(e).__name__, e)
print("\nTimeBase source:")
try:
    print(inspect.getsource(TimeType.TimeBase))
except Exception as e:
    print(type(e).__name__, e)
print("\nTimeBase values:")
print(list(TimeType.TimeBase))
for val in TimeType.TimeBase:
    print(val, val.value, val.name)
PY

echo
echo "== related await_event predicate behavior =="
rg -n -C 3 'def await_event|time_base|TimeBase|TB_' fprime-gds-common-proves-core-reference fprime_gds 2>/dev/null || true

Repository: Open-Source-Space-Foundation/proves-core-reference

Length of output: 354


🌐 Web query:

fprime_gds common models serialize time_type TimeType set_datetime TimeBase TB_DONT_CARE TB_UTC

💡 Result:

In the F' (F Prime) architecture, TimeType is a serializable class located in fprime_gds.common.models.serialize.time_type used to parse, store, and format timestamp information for telemetry and events [1][2]. Regarding your query on TimeType and time base values: 1. TimeType and set_datetime: The TimeType class provides methods to manage timestamp data [1]. While standard Python datetime conversion is often handled through getters like get_datetime [1], the internal values (seconds and microseconds) are typically managed during object initialization or via internal helpers [1]. Users primarily interact with TimeType through arithmetic operations and comparison operators supported by the GDS Integration Test API [2]. 2. TimeBase Enumerations (TB_DONT_CARE, TB_UTC): The TimeBase enumeration defines the source or clock system for a timestamp [3][4]. - TB_DONT_CARE: Defined as 0xFFFF (or 65535), this value is used primarily in sequences to indicate that the sequence should execute regardless of the current flight software time base [3][4][5]. - TB_UTC: Note that standard F' TimeBase configurations typically include values like TB_NONE, TB_PROC_TIME, TB_WORKSTATION_TIME, and TB_SC_TIME [4][6][5]. While specific project implementations may extend or map time bases differently, TB_UTC is not a standard, built-in member of the default TimeBase enumeration in the core F' framework [4][5]. If you are looking to set a specific time base, you would typically provide the desired TimeBase enum value during the construction of a TimeType object [1]. The system uses these bases to ensure synchronization between ground-side sequences and flight software state [3].

Citations:


🌐 Web query:

github NASA fprime gds TimeType set_datetime TB_UTC source

💡 Result:

In the NASA F Prime (F´) Ground Data System (GDS), the TimeType class is used to store and manage timestamps for telemetry and events [1][2]. While you referenced "TB_UTC," the F Prime GDS implementation typically uses defined TimeBase constants to categorize time sources [1]. The set_datetime method is a member function of the TimeType class used to initialize or update a timestamp from a Python datetime object [1][3]. Example usage found in the F Prime GDS source code [3]: cmd_data.time.set_datetime(datetime.datetime.now, TimeType.TimeBase("TB_WORKSTATION_TIME")) Key details regarding TimeType and set_datetime: 1. Functionality: The set_datetime method allows developers to convert a standard Python datetime object into an F Prime TimeType instance, requiring a specified TimeBase [1]. 2. TimeBase: TimeBase constants (such as TB_WORKSTATION_TIME or others defined in the system) indicate the source or domain of the time [1][3]. 3. Location: The source code for the TimeType class is located in the fprime-gds repository, typically under fprime_gds/common/models/serialize/time_type.py [1][4]. Please note that results referencing TB_UTC often appear in other software projects (like libzypp) unrelated to NASA's F Prime [5][6]. Within F Prime, ensure you are using the specific TimeBase constants defined in your F Prime deployment's configuration or GDS headers [1][4].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== inspect fprime-gds package/source if present =="
python3 - <<'PY'
import shutil, urllib.request, sys
urls = [
    "https://raw.githubusercontent.com/nasa/fprime-gds/devel/src/fprime_gds/common/models/serialize/time_type.py",
]
for url in urls:
    try:
        data = urllib.request.urlopen(url, timeout=20).read().decode("utf-8", "replace")
    except Exception as e:
        print(f"FETCH_FAILED {url}: {type(e).__name__}: {e}")
        continue
    lines = data.splitlines()
    print(f"--- {url} ({len(lines)} lines) ---")
    for i, line in enumerate(lines, 1):
        if "class TimeBase" in line or "TB_UTC" in line or "TB_DONT_CARE" in line or "TB_SC_TIME" in line or "TB_PROC_TIME" in line or "def set_datetime" in line:
            start=max(1,i-8); end=min(len(lines),i+16)
            for j in range(start,end+1):
                print(f"{j:4}: {lines[j-1]}")
            print()
PY

echo
echo "== list installed fprime-gds location without importing =="
python3 - <<'PY'
import sys, os, zipimport
print("sys.path:")
for p in sys.path[:10]:
    print(" ", p)
for spec in pkg_resources_pkgutil := []:
    pass
try:
    import pkg_resources
    for p in pkg_resources.working_set.by_key["fprime-gds"].metadata.resource_listdir("fprime_gds/common/models/serialize") if "fprime-gds" in {k.lower(): True for k in []} and "pkg_resources" in dir() else []:
        if "time_type" in p:
            print(p)
except Exception as e:
    print("pkg_resources check skipped:", type(e).__name__, e)

try:
    import fprime_gds
    print("fprime_gds imported from", fprime_gds.__file__)
except Exception as e:
    print("fprime_gds import failed:", type(e).__name__, e)
PY

Repository: Open-Source-Space-Foundation/proves-core-reference

Length of output: 704


🌐 Web query:

site:nasa.github.io/fprime UsersGuide dev testAPI time_type TimeType set_datetime TB_DONT_CARE

💡 Result:

In the F Prime (F´) framework, TB_DONT_CARE is a member of the TimeBase enumeration, defined with a value of 0xFFFF [1][2]. It is used primarily in sequencing to indicate that a sequence can be executed regardless of the current flight software time base [1]. Regarding the context of your query: 1. TimeType and Test API: The TimeType class is a serializable object used for storing and comparing timestamps (seconds and microseconds) within F Prime [3][4]. While TimeType handles time data, the TB_DONT_CARE constant belongs specifically to the TimeBase enumeration used by the system to manage time synchronization and sequencing [1][2]. 2. Functionality: When a sequence specifies TB_DONT_CARE as its time base, the system bypasses time base validation checks that would otherwise prevent the sequence from running if the flight software time base did not match the expected source [1][5]. 3. Configuration: The constant is defined in the F Prime configuration (typically in FpConfig.h) alongside other time base types like TB_PROC_TIME and TB_WORKSTATION_TIME [2][6][7]. It is distinct from FW_CONTEXT_DONT_CARE, which serves a similar "don't care" purpose for time contexts in sequences [5][8][6]. There is no standard method named set_datetime that takes TB_DONT_CARE as an argument in the public IntegrationTestAPI or TimeType class [3][9]. Time management in the Test API is generally handled through TimeType instances or helper methods like get_latest_time [4][9]. If you are encountering a set_datetime method, it may be a custom implementation or specific to a localized test script [3].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== fetch source with insecure SSL (remote docs/source unavailable to command, use deterministic local evidence instead) =="
curl -kL -sS --max-time 20 "https://raw.githubusercontent.com/nasa/fprime-gds/devel/src/fprime_gds/common/models/serialize/time_type.py" | sed -n '1,180p' || true

echo
echo "== repository ruff/python lint config for timezone warnings =="
rg -n "DTZ005|use-datetime-default|datetime-default|flake8-datetimez|ruff|lint" -g 'pyproject.toml' -g 'Makefile' -g '*.ini' . || true

Repository: Open-Source-Space-Foundation/proves-core-reference

Length of output: 6419


🌐 Web query:

github nasa fprime-gds time_type.py TimeBase TB_UTC set_datetime

💡 Result:

In the F Prime (F´) GDS, the TimeType class (found in fprime_gds.common.models.serialize.time_type) is used to handle timestamping data [1]. There is no method named set_datetime in the TimeType class [1]. The TimeType object is initialized using the constructor init(time_base=0, time_context=0, seconds=0, useconds=0) [1]. While the class includes a method called get_datetime(tz=None) to convert a TimeType object into a Python datetime object [1], it does not have a corresponding setter to update the TimeType instance from a datetime object. Regarding TimeBase and TB_UTC: 1. TimeBase: This is an enumeration defining the clocks in the F´ system (e.g., TB_NONE, TB_PROC_TIME, TB_WORKSTATION_TIME, TB_SC_TIME, TB_DONT_CARE) [2][3]. 2. TB_UTC: This is generally not a standard TimeBase enum value in the base F´ framework [2][3]. Time bases are typically defined by the project in FpConfig.fpp [3]. For time manipulation within the GDS test API, the TimeType class supports basic arithmetic (addition, subtraction) and comparisons directly with other TimeType objects or floating-point numbers [4]. If you need to construct a TimeType object, you generally provide the seconds and microseconds directly during instantiation [1]. [1][4][2]

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate TimeType definitions across repo =="
rg -n "class TimeType|def set_datetime|TB_UTC|TB_DONT_CARE" . --glob '!**/.git/**' || true

echo
echo "== all TimeType constructors/assignments =="
rg -n "TimeType\(|\.set_datetime\(" . --glob '!**/.git/**' || true

echo
echo "== check whether TB_UTC is defined in git-tracked files =="
rg -n "TB_UTC" $(git ls-files) 2>/dev/null || true

echo
echo "== inspect repository pyproject for DTZ005, if present =="
python3 - <<'PY'
from pathlib import Path
for p in [Path("pyproject.toml"), Path("ruff.toml"), Path(".ruff.toml")]:
    if p.exists():
        print(f"--- {p} ---")
        txt = p.read_text()
        for i, line in enumerate(txt.splitlines(), 1):
            if "DTZ005" in line or "use-datetime-default" in line or "timedeltas-only-conversion" in line or "datetime-default" in line:
                print(f"{i}: {line}")
PY

Repository: Open-Source-Space-Foundation/proves-core-reference

Length of output: 5142


🌐 Web query:

github nasa fprime-gds src/fprime_gds/common/models/serialize/time_type.py TB_UTC

💡 Result:

In the F Prime (F´) framework, TB_UTC is not a standard member of the fprime_gds.common.models.serialize.time_type.TimeType class or the core Fw::Time system. The F Prime time system primarily utilizes time bases such as TB_NONE, TB_WORKSTATION_TIME, and TB_PROC_TIME [1][2]. The confusion regarding TB_UTC often arises from its presence in other unrelated software projects, such as the libzypp library, which uses an enumeration containing TB_UTC for date and time formatting [3][4][5]. Within the F Prime GDS Python codebase, time is managed using the TimeType class [6]. While developers might occasionally define custom time bases or work with external time formats, TB_UTC is not a built-in F Prime constant. If you encounter TB_UTC in an F Prime context, it is likely a custom extension or an error resulting from a misidentification of external library constants. For standard F Prime operations, time bases are typically set using the defined enumerations in the Fw::Time component, and the GDS handles these via the serialization logic in fprime_gds.common.models.serialize.time_type [6][2].

Citations:


Use timezone-aware UTC timestamps for event windows.

These test timestamps are used after UTC-based RTC alarm setup, but datetime.now() is host-local and naive. Use datetime.now(timezone.utc) before constructing the TimeType event window. Run make fmt after the update.

🧰 Tools
🪛 Ruff (0.16.1)

[warning] 312-312: datetime.datetime.now() called without a tz argument

(DTZ005)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@PROVESFlightControllerReference/test/int/rtc_test.py` around lines 311 - 313,
Update the event-window timestamp initialization using TimeType.set_datetime to
call datetime.now(timezone.utc) instead of the host-local naive datetime.now().
Ensure the timezone import is available, then run make fmt.

Sources: Coding guidelines, Linters/SAST tools

fprime_test_api.send_command(f"{rtcManager}.ALARM_SET", [alarm_time_data_str])

# Assert that we receive an AlarmTriggered event within 10 seconds
fprime_test_api.await_event(f"{rtcManager}.AlarmTriggered", timeout=10)
fprime_test_api.assert_event(
f"{rtcManager}.AlarmTriggered", start=start, timeout=10

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why are you using assert event everywhere instead of await event? await allows us to be more flexible with waiting for commands to come back from my understanding, but is the timing importtant in this case?

)

# make sure the alarm is gone
fprime_test_api.send_command(f"{rtcManager}.ALARM_LIST")
fprime_test_api.await_event(f"{rtcManager}.AlarmNotSet", timeout=10)
fprime_test_api.assert_event(f"{rtcManager}.AlarmNotSet", start=start, timeout=10)


# cancellation test
# Cancellation test
@pytest.mark.uart_only(
reason="This test sets the RTC time which triggers the #402 / #404 bugs on PROVES Core Reference"
)
Expand All @@ -323,7 +334,7 @@ def test_06_rtc_alarm_cancellation(fprime_test_api: IntegrationTestAPI, start_gd
fprime_test_api.clear_histories()

# Set an alarm for 5 seconds in the future
alarm_time = datetime.now(timezone.utc) + timedelta(seconds=5)
alarm_time = datetime.now(timezone.utc) + timedelta(seconds=60)
alarm_time_data = dict(
Year=alarm_time.year,
Month=alarm_time.month,
Expand All @@ -333,12 +344,45 @@ def test_06_rtc_alarm_cancellation(fprime_test_api: IntegrationTestAPI, start_gd
Second=alarm_time.second,
)
alarm_time_data_str = json.dumps(alarm_time_data)

start: TimeType = TimeType().set_datetime(
datetime.now(), time_base=TimeType.TimeBase("TB_DONT_CARE")
)

# Send ALARM_SET and await AlarmSet to get the concrete alarm ID
fprime_test_api.send_command(f"{rtcManager}.ALARM_SET", [alarm_time_data_str])
alarm_set_evt: EventData = fprime_test_api.assert_event(
f"{rtcManager}.AlarmSet", start=start, timeout=5
)

# Cancel the alarm immediately
fprime_test_api.send_command(f"{rtcManager}.ALARM_CANCEL")
# Extract the alarm id from the AlarmSet event (first arg assumed to be the ID)
alarm_id = None
if alarm_set_evt and len(alarm_set_evt.args) > 0:
alarm_id = alarm_set_evt.args[0].val

assert alarm_id is not None, "Failed to obtain alarm id from AlarmSet event"

# Cancel the alarm by ID
fprime_test_api.send_command(f"{rtcManager}.ALARM_CANCEL", [alarm_id])

# Assert AlarmCanceled references the same ID
alarm_canceled_evt: EventData = fprime_test_api.assert_event(
f"{rtcManager}.AlarmCanceled", start=start, timeout=5
)
assert alarm_canceled_evt.args and alarm_canceled_evt.args[0].val == alarm_id, (
f"AlarmCanceled id {alarm_canceled_evt.args[0].val} did not match expected {alarm_id}"
)
Comment on lines +372 to +374

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Do not index an unchecked event argument list.

If AlarmCanceled has no arguments, the assertion message evaluates alarm_canceled_evt.args[0] and raises IndexError. Split the presence check from the ID comparison.

Proposed fix
-    assert alarm_canceled_evt.args and alarm_canceled_evt.args[0].val == alarm_id, (
-        f"AlarmCanceled id {alarm_canceled_evt.args[0].val} did not match expected {alarm_id}"
-    )
+    assert alarm_canceled_evt.args, "AlarmCanceled did not include an alarm ID"
+    assert alarm_canceled_evt.args[0].val == alarm_id, (
+        f"AlarmCanceled id {alarm_canceled_evt.args[0].val} did not match expected {alarm_id}"
+    )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
assert alarm_canceled_evt.args and alarm_canceled_evt.args[0].val == alarm_id, (
f"AlarmCanceled id {alarm_canceled_evt.args[0].val} did not match expected {alarm_id}"
)
assert alarm_canceled_evt.args, "AlarmCanceled did not include an alarm ID"
assert alarm_canceled_evt.args[0].val == alarm_id, (
f"AlarmCanceled id {alarm_canceled_evt.args[0].val} did not match expected {alarm_id}"
)
🧰 Tools
🪛 Ruff (0.16.1)

[warning] 372-374: Assertion should be broken down into multiple parts

(PT018)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@PROVESFlightControllerReference/test/int/rtc_test.py` around lines 372 - 374,
Update the AlarmCanceled assertion in the RTC test to separate validation of
alarm_canceled_evt.args from the ID comparison, ensuring the error message never
indexes args[0] unless an argument exists. Preserve the expected alarm_id
equality check after confirming the argument list is non-empty.

Source: Linters/SAST tools


# Wait until after the scheduled alarm time to ensure it would have fired if not canceled
remaining = (alarm_time - datetime.now(timezone.utc)).total_seconds()
if remaining > 0:
time.sleep(remaining + 1)

fprime_test_api.await_event(f"{rtcManager}.AlarmTriggered", timeout=10)
# Verify no AlarmTriggered for this alarm id (assert that assert_event times out)
with pytest.raises(AssertionError):
fprime_test_api.assert_event(
f"{rtcManager}.AlarmTriggered", start=start, timeout=3
)


# validation test
Expand All @@ -354,8 +398,13 @@ def test_07_rtc_alarm_cancel_no_alarm_set(
fprime_test_api.clear_histories()

# validate that cancel doesn't work without an alarm being present
start: TimeType = TimeType().set_datetime(
datetime.now(), time_base=TimeType.TimeBase("TB_DONT_CARE")
)
fprime_test_api.send_command(f"{rtcManager}.ALARM_CANCEL", [0])
fprime_test_api.await_event(f"{rtcManager}.AlarmNotCanceled", timeout=10)
fprime_test_api.assert_event(
f"{rtcManager}.AlarmNotCanceled", start=start, timeout=10
)


# list test
Expand All @@ -368,8 +417,11 @@ def test_08_rtc_alarm_list(fprime_test_api: IntegrationTestAPI, start_gds):
# Clear histories
fprime_test_api.clear_histories()

start: TimeType = TimeType().set_datetime(
datetime.now(), time_base=TimeType.TimeBase("TB_DONT_CARE")
)
fprime_test_api.send_command(f"{rtcManager}.ALARM_LIST")
fprime_test_api.await_event(f"{rtcManager}.AlarmNotSet", timeout=10)
fprime_test_api.assert_event(f"{rtcManager}.AlarmNotSet", start=start, timeout=10)

# Set an alarm for 5 seconds in the future
alarm_time = datetime.now(timezone.utc) + timedelta(seconds=5)
Expand All @@ -384,8 +436,11 @@ def test_08_rtc_alarm_list(fprime_test_api: IntegrationTestAPI, start_gds):
alarm_time_data_str = json.dumps(alarm_time_data)
fprime_test_api.send_command(f"{rtcManager}.ALARM_SET", [alarm_time_data_str])

start = TimeType().set_datetime(
datetime.now(), time_base=TimeType.TimeBase("TB_DONT_CARE")
)
fprime_test_api.send_command(f"{rtcManager}.ALARM_LIST")
fprime_test_api.await_event(f"{rtcManager}.AlarmSet", timeout=10)
fprime_test_api.assert_event(f"{rtcManager}.AlarmSet", start=start, timeout=10)


@pytest.mark.uart_only(
Expand All @@ -404,19 +459,22 @@ def test_09_set_alarm_in_past(fprime_test_api: IntegrationTestAPI, start_gds):
Second=alarm_time.second,
)
alarm_time_data_str = json.dumps(alarm_time_data)
start: TimeType = TimeType().set_datetime(
datetime.now(), time_base=TimeType.TimeBase("TB_DONT_CARE")
)
fprime_test_api.send_command(f"{rtcManager}.ALARM_SET", [alarm_time_data_str])

# Assert that we receive an AlarmNotSet event within 10 seconds
fprime_test_api.await_event(f"{rtcManager}.AlarmNotSet", timeout=10)
fprime_test_api.assert_event(f"{rtcManager}.AlarmNotSet", start=start, timeout=10)


@pytest.mark.uart_only(
reason="This test sets the RTC time which triggers the #402 / #404 bugs on PROVES Core Reference"
)
def test_10_double_set_test(fprime_test_api: IntegrationTestAPI, start_gds):
"""Ensure that double setting an alarm will result in a rejection from the system"""
# Set an alarm for 5 seconds in the future
alarm_time = datetime.now(timezone.utc) + timedelta(seconds=5)
# Set an alarm for 60 seconds in the future
alarm_time = datetime.now(timezone.utc) + timedelta(seconds=60)
alarm_time_data = dict(
Year=alarm_time.year,
Month=alarm_time.month,
Expand All @@ -426,32 +484,114 @@ def test_10_double_set_test(fprime_test_api: IntegrationTestAPI, start_gds):
Second=alarm_time.second,
)
alarm_time_data_str = json.dumps(alarm_time_data)
start: TimeType = TimeType().set_datetime(
datetime.now(), time_base=TimeType.TimeBase("TB_DONT_CARE")
)
fprime_test_api.send_command(f"{rtcManager}.ALARM_SET", [alarm_time_data_str])
# Assert that we receive an AlarmSet event within 10 seconds
fprime_test_api.await_event(f"{rtcManager}.AlarmSet", timeout=10)
fprime_test_api.assert_event(f"{rtcManager}.AlarmSet", start=start, timeout=10)

# Double set the alarm
alarm_time = datetime.now(timezone.utc) + timedelta(seconds=5)
alarm_time = datetime.now(timezone.utc) + timedelta(seconds=60)
alarm_time_data = dict(
Year=alarm_time.year,
Month=alarm_time.month,
Day=alarm_time.day,
Hour=alarm_time.hour,
Minute=alarm_time.minute,
Second=alarm_time.second,
)
Comment on lines +496 to +503

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use a dictionary literal.

Ruff C408 flags this redundant dict(...) call. Replace it with a dictionary literal and run make fmt. As per coding guidelines, Python code must use Ruff through make fmt.

🧰 Tools
🪛 ast-grep (0.45.0)

[info] 503-503: use jsonify instead of json.dumps for JSON output
Context: json.dumps(alarm_time_data)
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)

🪛 Ruff (0.16.1)

[warning] 496-503: Unnecessary dict() call (rewrite as a literal)

Rewrite as a literal

(C408)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@PROVESFlightControllerReference/test/int/rtc_test.py` around lines 496 - 503,
Replace the dict(...) constructor assigned to alarm_time_data with an equivalent
dictionary literal containing the existing Year, Month, Day, Hour, Minute, and
Second entries. Run make fmt to apply the required Ruff formatting.

Sources: Coding guidelines, Linters/SAST tools

alarm_time_data_str = json.dumps(alarm_time_data)
start = TimeType().set_datetime(
datetime.now(), time_base=TimeType.TimeBase("TB_DONT_CARE")
)
fprime_test_api.send_command(f"{rtcManager}.ALARM_SET", [alarm_time_data_str])
# Assert that we receive an AlarmNotSet event within 10 seconds
fprime_test_api.await_event(f"{rtcManager}.AlarmNotSet", timeout=10)
fprime_test_api.assert_event(f"{rtcManager}.AlarmNotSet", start=start, timeout=10)

# Clean up: cancel the alarm
fprime_test_api.send_command(f"{rtcManager}.ALARM_CANCEL")
Comment on lines +512 to +513

@coderabbitai coderabbitai Bot Aug 4, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Pass the required alarm ID during cleanup.

ALARM_CANCEL_cmdHandler requires a U16 ID. Line 513 sends no argument. The command can fail before it cancels the retained first alarm, which leaks state into later tests.

Pass the configured alarm ID (0) or capture the first AlarmSet event ID and use it here.

Proposed fix
     # Clean up: cancel the alarm
-    fprime_test_api.send_command(f"{rtcManager}.ALARM_CANCEL")
+    fprime_test_api.send_command(f"{rtcManager}.ALARM_CANCEL", [0])
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Clean up: cancel the alarm
fprime_test_api.send_command(f"{rtcManager}.ALARM_CANCEL")
# Clean up: cancel the alarm
fprime_test_api.send_command(f"{rtcManager}.ALARM_CANCEL", [0])
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@PROVESFlightControllerReference/test/int/rtc_test.py` around lines 512 - 513,
Update the cleanup call to ALARM_CANCEL in rtc test teardown to pass the
required U16 alarm ID, using the configured ID 0 or the ID captured from the
initial AlarmSet event, so the retained alarm is reliably cancelled before later
tests run.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks like coderabbit is right about the U16, is this passing without its paramaer?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -C 4 '\bALARM_CANCEL\b|ALARM_CANCEL_cmdHandler\b' .

Length of output: 19125


@ineskhou, the test can pass without the parameter, but the cleanup command is not valid.

ALARM_CANCEL requires ID: U16 in RtcManager.fpp. The handler also requires U16 ID.

Line 513 only calls send_command. It does not assert the command response or AlarmCanceled. Therefore, the test can finish even if command deserialization or dispatch rejects the empty argument list. In that case, the first alarm remains configured.

Use [0] here. The component sets its alarm with ID 0, and the existing tests already use that ID. An additional AlarmCanceled assertion would verify the cleanup.


🧬 Code Graph Analysis Results

PROVESFlightControllerReference/test/int/common.py:56-109

proves_send_and_assert_command accepts args with a default of [], then passes that list to fprime_test_api.send_and_assert_command. Commands invoked without parameters therefore execute with an empty argument list.

PROVESFlightControllerReference/test/int/rtc_test.py:55-75

set_time constructs a JSON time payload and calls TIME_SET with one argument: [time_data_str].

PROVESFlightControllerReference/test/int/rtc_test.py:78-109

uplink_sequence_and_await_completion generates a sequence using generateSequence(..., 0xFFFF, cont=True), where 0xFFFF is passed as the sequence generator parameter.

You are interacting with an AI system.



@pytest.mark.uart_only(reason="Test functionality of the timebase parameter")
def test_11_proc_toggle(fprime_test_api: IntegrationTestAPI, start_gds):
"""Test for events emitted by the timebase parameter"""

start: TimeType = TimeType().set_datetime(
datetime.now(), time_base=TimeType.TimeBase("TB_DONT_CARE")
)

try:
# Test that we can set timebase to proc time
proves_send_and_assert_command(
fprime_test_api, f"{rtcManager}.TIMEBASE_PRM_SET", ["TB_PROC_TIME"]
)
# Assert that we receive a TimeBaseChanged event within 10 seconds
fprime_test_api.await_event(f"{rtcManager}.TimeBaseChanged", timeout=10)
fprime_test_api.assert_event(
f"{rtcManager}.TimeBaseChanged", start=start, timeout=10
)
finally:
# Restore spacecraft time so subsequent tests see RTC-backed timestamps
proves_send_and_assert_command(
fprime_test_api, f"{rtcManager}.TIMEBASE_PRM_SET", ["TB_SC_TIME"]
)
fprime_test_api.await_event(f"{rtcManager}.TimeBaseChanged", timeout=10)
fprime_test_api.assert_event(
f"{rtcManager}.TimeBaseChanged", start=start, timeout=10
)


@pytest.mark.uart_only(reason="Test functionality of the timebase parameter")
def test_12_param_update_conflict_check(fprime_test_api: IntegrationTestAPI, start_gds):
"""Test for that RTC alarms no longer conflict with parameter updates and function properly"""

start: TimeType = TimeType().set_datetime(
datetime.now(), time_base=TimeType.TimeBase("TB_DONT_CARE")
)

# Ensure that we are not using proc time
proves_send_and_assert_command(
fprime_test_api, f"{rtcManager}.TIMEBASE_PRM_SET", ["TB_SC_TIME"]
)
fprime_test_api.assert_event(
f"{rtcManager}.TimeBaseChanged", start=start, timeout=10
)

# Set an alarm for 60 seconds in the future
alarm_time = datetime.now(timezone.utc) + timedelta(seconds=60)
alarm_time_data = dict(
Year=alarm_time.year,
Month=alarm_time.month,
Day=alarm_time.day,
Hour=alarm_time.hour,
Minute=alarm_time.minute,
Second=alarm_time.second,
)
alarm_time_data_str = json.dumps(alarm_time_data)
start: TimeType = TimeType().set_datetime(
datetime.now(), time_base=TimeType.TimeBase("TB_DONT_CARE")
)

# Set an alarm
fprime_test_api.send_command(f"{rtcManager}.ALARM_SET", [alarm_time_data_str])
fprime_test_api.assert_event(f"{rtcManager}.AlarmSet", start=start, timeout=10)
Comment on lines +573 to +576

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Capture a new event-window timestamp for each command.

start is captured before ALARM_SET and reused by later TimeBaseChanged and AlarmNotSet assertions. If assert_event matches any event after start, the final assertion at Lines 595-597 can match the earlier transition at Lines 579-581 instead of the restoration command. Capture start immediately before each command with a corresponding event assertion.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@PROVESFlightControllerReference/test/int/rtc_test.py` around lines 573 - 576,
Update the RTC test command/assertion sequences around ALARM_SET,
TimeBaseChanged, and AlarmNotSet so each command captures a fresh event-window
timestamp immediately before sending it. Use the matching timestamp for each
subsequent assert_event call, including the final restoration assertion, instead
of reusing the initial start value.


# Switch to proc time to make sure it is canceled
proves_send_and_assert_command(
fprime_test_api, f"{rtcManager}.TIMEBASE_PRM_SET", ["TB_SC_TIME"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Based on the comment should we swap to TB_PROC_TIME instead of TB_SC_TIME?

)

# make sure that it is gone
fprime_test_api.send_command(f"{rtcManager}.ALARM_LIST")
fprime_test_api.assert_event(f"{rtcManager}.AlarmNotSet", start=start, timeout=10)

# Make sure we cannot set while in proc time
fprime_test_api.send_command(f"{rtcManager}.ALARM_SET", [alarm_time_data_str])
fprime_test_api.assert_event(f"{rtcManager}.AlarmNotSet", start=start, timeout=10)

# Set time back to RTC to avoid ruining other tests
proves_send_and_assert_command(
fprime_test_api, f"{rtcManager}.TIMEBASE_PRM_SET", ["TB_SC_TIME"]
)
fprime_test_api.assert_event(
f"{rtcManager}.TimeBaseChanged", start=start, timeout=10
)
Comment on lines +575 to +597

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Establish the conflict state before asserting its result.

Line 573 does not confirm that ALARM_SET created an alarm. A rejected or unprocessed command leaves no alarm, so Line 582 can pass without testing cleanup.

Line 577 selects TB_SC_TIME, not TB_PROC_TIME. The test therefore does not execute the processor-time conflict path.

After selecting processor time, assert TimeBaseChanged. Wrap the conflict checks in try/finally and move the existing spacecraft-time restoration into finally. A failed assertion must not leave shared hardware in processor time.

Proposed fix
     fprime_test_api.send_command(f"{rtcManager}.ALARM_SET", [alarm_time_data_str])
+    fprime_test_api.assert_event(
+        f"{rtcManager}.AlarmSet", start=start, timeout=10
+    )

-        fprime_test_api, f"{rtcManager}.TIMEBASE_PRM_SET", ["TB_SC_TIME"]
+        fprime_test_api, f"{rtcManager}.TIMEBASE_PRM_SET", ["TB_PROC_TIME"]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@PROVESFlightControllerReference/test/int/rtc_test.py` around lines 573 - 594,
Update the alarm conflict test around ALARM_SET and TIMEBASE_PRM_SET to first
assert that the initial ALARM_SET successfully created the alarm, then select
TB_PROC_TIME and assert TimeBaseChanged before checking cancellation and
rejection behavior. Wrap the processor-time conflict assertions in try/finally,
and move the existing restoration to TB_SC_TIME into finally so cleanup occurs
even when an assertion fails.

Loading