GCC Code Coverage Report


Directory: lib/fprime-samd/fprime-samd/Drv/RtcDriver/
File: RtcDriver.cpp
Date: 2026-10-20 16:49:00
Exec Total Coverage
Lines: 67 71 94.4%
Functions: 7 7 100.0%
Branches: 33 41 80.5%

Line Branch Exec Source
1 // ======================================================================
2 // \title RtcDriver.cpp
3 // \author tumbar
4 // \brief cpp file for RtcDriver component implementation class
5 // ======================================================================
6
7 #include "fprime-samd/Drv/RtcDriver/RtcDriver.hpp"
8 #include "Fw/Types/Assert.hpp"
9 #include "Os/RawTime.hpp"
10 #include "config/FwAssertArgTypeAliasAc.h"
11 #include "fprime-samd/Drv/RtcDriver/RawTime.hpp"
12 #include "fprime-samd/Drv/RtcDriver/RtcDriverHardware.hpp"
13 #include "samd-config/RtcDriverConfig.hpp"
14
15 namespace Os {
16 namespace Samd21 {
17
18 9 Os::Samd21::Samd21RawTimeHandle timeNow() {
19 9 Os::Samd21::Samd21RawTimeHandle time;
20
21
1/1
✓ Branch 1 taken 9 times.
9 ::Samd21::RtcHardware::RtcState& state = ::Samd21::RtcHardware::getRtcState();
22
23
3/4
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 1 times.
9 if (state.configured) {
24
1/2
✗ Branch 4 not taken.
✓ Branch 5 taken 8 times.
8 U32 seconds_offset = state.n_ticks / static_cast<U32>(state.rate_hz);
25
1/2
✗ Branch 4 not taken.
✓ Branch 5 taken 8 times.
8 U32 subsecond_ticks = state.n_ticks % static_cast<U32>(state.rate_hz);
26
27 8 constexpr U32 USEC_PER_SEC = 1000000;
28
1/1
✓ Branch 1 taken 8 times.
8 U32 subtick_counter = ::Samd21::RtcHardware::RtcHal::readRtcCounter();
29
30 // Use 64-bit arithmetic to avoid overflow, then cast result back to U32
31 // Maximum intermediate value: 32768 * 1000000 = 32,768,000,000 (fits in U64)
32 U32 usecond_offset =
33
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
8 static_cast<U32>((static_cast<U64>(subsecond_ticks) * USEC_PER_SEC) / static_cast<U32>(state.rate_hz));
34 U32 useconds_counter =
35
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
8 static_cast<U32>((static_cast<U64>(subtick_counter) * USEC_PER_SEC) / state.clock_rate_hz);
36
37 // Compute the final time
38 8 U32 useconds = usecond_offset + useconds_counter;
39 8 U32 seconds = seconds_offset + (useconds / USEC_PER_SEC);
40 8 useconds %= USEC_PER_SEC;
41
42 8 time.m_seconds = seconds;
43 8 time.m_micros = useconds;
44 } else {
45 // RTC is not configured, we have no way of determining the processor time
46 1 time.m_seconds = 0;
47 1 time.m_micros = 0;
48 }
49
50 9 return time;
51 }
52
53 5 Fw::TimeInterval timeInterval(const Samd21RawTimeHandle& a, const Samd21RawTimeHandle& b) {
54
6/6
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 1 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 2 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 1 times.
5 const bool a_is_newer = (a.m_seconds > b.m_seconds) || ((a.m_seconds == b.m_seconds) && (a.m_micros > b.m_micros));
55
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
5 const Samd21RawTimeHandle& newer = a_is_newer ? a : b;
56
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
5 const Samd21RawTimeHandle& older = a_is_newer ? b : a;
57
58
2/2
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 4 times.
5 if (newer.m_micros < older.m_micros) {
59 1 return Fw::TimeInterval(newer.m_seconds - older.m_seconds - 1, 1000000 + newer.m_micros - older.m_micros);
60 }
61 4 return Fw::TimeInterval(newer.m_seconds - older.m_seconds, newer.m_micros - older.m_micros);
62 }
63
64 } // namespace Samd21
65 } // namespace Os
66
67 namespace Samd21 {
68
69 // ----------------------------------------------------------------------
70 // Component construction and destruction
71 // ----------------------------------------------------------------------
72
73 15 RtcDriver ::RtcDriver(const char* const compName) : RtcDriverComponentBase(compName) {}
74
75 34 void RtcDriver ::configure(ClockSource clk_source, TickRate rate) {
76 34 RtcHardware::RtcState& state = RtcHardware::getRtcState();
77 34 FW_ASSERT(!state.configured);
78
79 // Validate the rate is one of our predefined rates
80
1/2
✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
34 switch (rate) {
81 34 case TickRate::TICK_1_HZ:
82 case TickRate::TICK_2_HZ:
83 case TickRate::TICK_4_HZ:
84 case TickRate::TICK_8_HZ:
85 case TickRate::TICK_16_HZ:
86 case TickRate::TICK_32_HZ:
87 case TickRate::TICK_64_HZ:
88 case TickRate::TICK_128_HZ:
89 34 break;
90 ✗ default:
91 ✗ FW_ASSERT(0, static_cast<FwAssertArgType>(rate));
92 break;
93 }
94
95 // Select the clock source
96
3/4
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
34 switch (clk_source) {
97 18 case RtcDriver::ClockSource::InternalOscillator:
98 18 state.clock_rate_hz = RtcDriver::INTERNAL_CLOCK_FREQ_HZ;
99 18 break;
100 8 case RtcDriver::ClockSource::ExternalOscillator:
101 8 state.clock_rate_hz = ::Samd21::RtcDriverConfig::EXTERNAL_CLOCK_FREQ_HZ;
102 8 break;
103 8 case RtcDriver::ClockSource::UltraLowPowerOscillator:
104 8 state.clock_rate_hz = RtcDriver::INTERNAL_CLOCK_FREQ_HZ;
105 8 break;
106 ✗ default:
107 ✗ FW_ASSERT(0, static_cast<FwAssertArgType>(clk_source));
108 break;
109 }
110
111 // Configure GCLK and get the clock rate
112 34 RtcHardware::RtcHal::configureGclk(clk_source);
113
114 // Configure RTC peripheral
115 34 RtcHardware::RtcHal::configureRtc(state.clock_rate_hz, rate);
116
117 // Initialize state
118 34 state.n_ticks = 0;
119 34 state.rate_hz = rate;
120 34 state.configured = true;
121 34 }
122
123 9 void RtcDriver ::enable() {
124 9 RtcHardware::RtcState& state = RtcHardware::getRtcState();
125 9 FW_ASSERT(state.configured);
126
127 // Enable the RTC peripheral
128 9 RtcHardware::RtcHal::enableRtc();
129 9 }
130
131 11 bool RtcDriver ::activeIn_handler(FwIndexType portNum, U32 context) {
132 // Acknowledge the ISR on every cycle
133 11 RtcHardware::RtcState& state = RtcHardware::getRtcState();
134 11 state.deadline_reached = true;
135
136
3/4
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 1 times.
11 if (state.wakeup_interrupt) {
137 // Acknowledge the interrupt
138 10 state.wakeup_interrupt = false;
139
140 // The RTC woke us up, emit the signal
141
1/1
✓ Branch 2 taken 10 times.
10 Os::RawTime cycle_start;
142
1/1
✓ Branch 2 taken 10 times.
10 auto status = cycle_start.now();
143 10 FW_ASSERT(status == Os::RawTimeInterface::Status::OP_OK, status);
144
145
2/2
✓ Branch 6 taken 10 times.
✓ Branch 11 taken 10 times.
10 this->tlmWrite_CycleOverrun(state.deadline_exceeded);
146
1/1
✓ Branch 5 taken 10 times.
10 this->CycleOut_out(0, cycle_start);
147
148 // A cycle was emitted this tick, so work was done
149 10 return true;
150 10 }
151
152 // No pending wakeup interrupt: nothing to do this tick
153 1 return false;
154 }
155
156 30 RtcDriver ::~RtcDriver() {}
157
158 } // namespace Samd21
159