GCC Code Coverage Report


Directory: lib/fprime-samd/fprime-samd/Drv/RtcDriver/
File: RtcDriver.cpp
Date: 2026-09-26 00:05:16
Exec Total Coverage
Lines: 59 64 92.2%
Functions: 6 6 100.0%
Branches: 20 29 69.0%

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 11 Os::Samd21::Samd21RawTimeHandle timeNow() {
19 11 Os::Samd21::Samd21RawTimeHandle time;
20
21
1/1
✓ Branch 1 taken 11 times.
11 ::Samd21::RtcHardware::RtcState& state = ::Samd21::RtcHardware::getRtcState();
22
23
3/4
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 1 times.
11 if (state.configured) {
24
1/2
✗ Branch 4 not taken.
✓ Branch 5 taken 10 times.
10 U32 seconds_offset = state.n_ticks / static_cast<U32>(state.rate_hz);
25
1/2
✗ Branch 4 not taken.
✓ Branch 5 taken 10 times.
10 U32 subsecond_ticks = state.n_ticks % static_cast<U32>(state.rate_hz);
26
27 10 constexpr U32 USEC_PER_SEC = 1000000;
28
1/1
✓ Branch 1 taken 10 times.
10 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 10 times.
10 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 10 times.
10 static_cast<U32>((static_cast<U64>(subtick_counter) * USEC_PER_SEC) / state.clock_rate_hz);
36
37 // Compute the final time
38 10 U32 useconds = usecond_offset + useconds_counter;
39 10 U32 seconds = seconds_offset + (useconds / USEC_PER_SEC);
40 10 useconds %= USEC_PER_SEC;
41
42 10 time.m_seconds = seconds;
43 10 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 11 return time;
51 }
52
53 } // namespace Samd21
54 } // namespace Os
55
56 namespace Samd21 {
57
58 // ----------------------------------------------------------------------
59 // Component construction and destruction
60 // ----------------------------------------------------------------------
61
62 10 RtcDriver ::RtcDriver(const char* const compName) : RtcDriverComponentBase(compName) {}
63
64 33 void RtcDriver ::configure(ClockSource clk_source, TickRate rate) {
65 33 RtcHardware::RtcState& state = RtcHardware::getRtcState();
66 33 FW_ASSERT(!state.configured);
67
68 // Validate the rate is one of our predefined rates
69
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 switch (rate) {
70 33 case TickRate::TICK_1_HZ:
71 case TickRate::TICK_2_HZ:
72 case TickRate::TICK_4_HZ:
73 case TickRate::TICK_8_HZ:
74 case TickRate::TICK_16_HZ:
75 case TickRate::TICK_32_HZ:
76 case TickRate::TICK_64_HZ:
77 case TickRate::TICK_128_HZ:
78 33 break;
79 ✗ default:
80 ✗ FW_ASSERT(0, static_cast<FwAssertArgType>(rate));
81 break;
82 }
83
84 // Select the clock source
85
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
33 switch (clk_source) {
86 17 case RtcDriver::ClockSource::InternalOscillator:
87 17 state.clock_rate_hz = RtcDriver::INTERNAL_CLOCK_FREQ_HZ;
88 17 break;
89 8 case RtcDriver::ClockSource::ExternalOscillator:
90 8 state.clock_rate_hz = ::Samd21::RtcDriverConfig::EXTERNAL_CLOCK_FREQ_HZ;
91 8 break;
92 8 case RtcDriver::ClockSource::UltraLowPowerOscillator:
93 8 state.clock_rate_hz = RtcDriver::INTERNAL_CLOCK_FREQ_HZ;
94 8 break;
95 ✗ default:
96 ✗ FW_ASSERT(0, static_cast<FwAssertArgType>(clk_source));
97 break;
98 }
99
100 // Configure GCLK and get the clock rate
101 33 RtcHardware::RtcHal::configureGclk(clk_source);
102
103 // Configure RTC peripheral
104 33 RtcHardware::RtcHal::configureRtc(state.clock_rate_hz, rate);
105
106 // Initialize state
107 33 state.n_ticks = 0;
108 33 state.rate_hz = rate;
109 33 state.configured = true;
110 33 }
111
112 9 void RtcDriver ::enable() {
113 9 RtcHardware::RtcState& state = RtcHardware::getRtcState();
114 9 FW_ASSERT(state.configured);
115
116 // Enable the RTC peripheral
117 9 RtcHardware::RtcHal::enableRtc();
118 9 }
119
120 7 bool RtcDriver ::activeIn_handler(FwIndexType portNum, U32 context) {
121 // Acknowledge the ISR on every cycle
122 7 RtcHardware::RtcState& state = RtcHardware::getRtcState();
123 7 state.deadline_reached = true;
124
125
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
7 if (state.wakeup_interrupt) {
126 // Acknowledge the interrupt
127 7 state.wakeup_interrupt = false;
128
129 // The RTC woke us up, emit the signal
130
1/1
✓ Branch 2 taken 7 times.
7 Os::RawTime cycle_start;
131
1/1
✓ Branch 2 taken 7 times.
7 auto status = cycle_start.now();
132 7 FW_ASSERT(status == Os::RawTimeInterface::Status::OP_OK, status);
133
134
2/2
✓ Branch 6 taken 7 times.
✓ Branch 11 taken 7 times.
7 this->tlmWrite_CycleOverrun(state.deadline_exceeded);
135
1/1
✓ Branch 5 taken 7 times.
7 this->CycleOut_out(0, cycle_start);
136
137 // A cycle was emitted this tick, so work was done
138 7 return true;
139 7 }
140
141 // No pending wakeup interrupt: nothing to do this tick
142 ✗ return false;
143 }
144
145 20 RtcDriver ::~RtcDriver() {}
146
147 } // namespace Samd21
148