GCC Code Coverage Report


Directory: lib/fprime-samd/fprime-samd/
File: Drv/RtcDriver/RtcDriver.cpp
Date: 2026-09-26 00:05:09
Exec Total Coverage
Lines: 0 64 0.0%
Functions: 0 6 0.0%
Branches: 0 46 0.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 ✗ Os::Samd21::Samd21RawTimeHandle timeNow() {
19 ✗ Os::Samd21::Samd21RawTimeHandle time;
20
21 ✗ ::Samd21::RtcHardware::RtcState& state = ::Samd21::RtcHardware::getRtcState();
22
23 ✗ if (state.configured) {
24 ✗ U32 seconds_offset = state.n_ticks / static_cast<U32>(state.rate_hz);
25 ✗ U32 subsecond_ticks = state.n_ticks % static_cast<U32>(state.rate_hz);
26
27 ✗ constexpr U32 USEC_PER_SEC = 1000000;
28 ✗ 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 ✗ static_cast<U32>((static_cast<U64>(subsecond_ticks) * USEC_PER_SEC) / static_cast<U32>(state.rate_hz));
34 U32 useconds_counter =
35 ✗ static_cast<U32>((static_cast<U64>(subtick_counter) * USEC_PER_SEC) / state.clock_rate_hz);
36
37 // Compute the final time
38 ✗ U32 useconds = usecond_offset + useconds_counter;
39 ✗ U32 seconds = seconds_offset + (useconds / USEC_PER_SEC);
40 ✗ useconds %= USEC_PER_SEC;
41
42 ✗ time.m_seconds = seconds;
43 ✗ time.m_micros = useconds;
44 } else {
45 // RTC is not configured, we have no way of determining the processor time
46 ✗ time.m_seconds = 0;
47 ✗ time.m_micros = 0;
48 }
49
50 ✗ return time;
51 }
52
53 } // namespace Samd21
54 } // namespace Os
55
56 namespace Samd21 {
57
58 // ----------------------------------------------------------------------
59 // Component construction and destruction
60 // ----------------------------------------------------------------------
61
62 ✗ RtcDriver ::RtcDriver(const char* const compName) : RtcDriverComponentBase(compName) {}
63
64 ✗ void RtcDriver ::configure(ClockSource clk_source, TickRate rate) {
65 ✗ RtcHardware::RtcState& state = RtcHardware::getRtcState();
66 ✗ FW_ASSERT(!state.configured);
67
68 // Validate the rate is one of our predefined rates
69 ✗ switch (rate) {
70 ✗ 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 ✗ break;
79 ✗ default:
80 ✗ FW_ASSERT(0, static_cast<FwAssertArgType>(rate));
81 break;
82 }
83
84 // Select the clock source
85 ✗ switch (clk_source) {
86 ✗ case RtcDriver::ClockSource::InternalOscillator:
87 ✗ state.clock_rate_hz = RtcDriver::INTERNAL_CLOCK_FREQ_HZ;
88 ✗ break;
89 ✗ case RtcDriver::ClockSource::ExternalOscillator:
90 ✗ state.clock_rate_hz = ::Samd21::RtcDriverConfig::EXTERNAL_CLOCK_FREQ_HZ;
91 ✗ break;
92 ✗ case RtcDriver::ClockSource::UltraLowPowerOscillator:
93 ✗ state.clock_rate_hz = RtcDriver::INTERNAL_CLOCK_FREQ_HZ;
94 ✗ 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 ✗ RtcHardware::RtcHal::configureGclk(clk_source);
102
103 // Configure RTC peripheral
104 ✗ RtcHardware::RtcHal::configureRtc(state.clock_rate_hz, rate);
105
106 // Initialize state
107 ✗ state.n_ticks = 0;
108 ✗ state.rate_hz = rate;
109 ✗ state.configured = true;
110 ✗ }
111
112 ✗ void RtcDriver ::enable() {
113 ✗ RtcHardware::RtcState& state = RtcHardware::getRtcState();
114 ✗ FW_ASSERT(state.configured);
115
116 // Enable the RTC peripheral
117 ✗ RtcHardware::RtcHal::enableRtc();
118 ✗ }
119
120 ✗ bool RtcDriver ::activeIn_handler(FwIndexType portNum, U32 context) {
121 // Acknowledge the ISR on every cycle
122 ✗ RtcHardware::RtcState& state = RtcHardware::getRtcState();
123 ✗ state.deadline_reached = true;
124
125 ✗ if (state.wakeup_interrupt) {
126 // Acknowledge the interrupt
127 ✗ state.wakeup_interrupt = false;
128
129 // The RTC woke us up, emit the signal
130 ✗ Os::RawTime cycle_start;
131 ✗ auto status = cycle_start.now();
132 ✗ FW_ASSERT(status == Os::RawTimeInterface::Status::OP_OK, status);
133
134 ✗ this->tlmWrite_CycleOverrun(state.deadline_exceeded);
135 ✗ this->CycleOut_out(0, cycle_start);
136
137 // A cycle was emitted this tick, so work was done
138 ✗ return true;
139 ✗ }
140
141 // No pending wakeup interrupt: nothing to do this tick
142 ✗ return false;
143 }
144
145 ✗ RtcDriver ::~RtcDriver() {}
146
147 } // namespace Samd21
148