Skip to content

Commit 1885213

Browse files
ineskhounateinactionSamuelGomezGasiemsen
authored
Introduce RtcManager & Rv3028Driver Components (#18)
* Use custom board definition * Remove commented config * Moving prj.conf sensors to board definition * Add d board * Try referencing c definitions in d board * Making a common v5 board definition * Fix readme * checkpoint rtc working * Pushing what I have * poke * replaced chronotime with zepyhry time * use direct power for rtc backup * This builds and runs but Fprime still does not know the time * super working rtc component * Set fprime-zephyr submodule to latest main * Split rtc manager/driver, confirmed working * Working on sdds * Update the RV3028 sdd * Update SDDs * Revert submodule change * Rename driver to `Rv3028Manager` Co-authored-by: Nate Gay <[email protected]> * Rename references from Rv3028Driver to Rv3028Manager Co-authored-by: Nate Gay <[email protected]> * Remove assertion in constructor Co-authored-by: Nate Gay <[email protected]> * Change logging to use `Fw::Logger` * Most feedback covered * appease linter * Add integration tests * Add typehinting * Comment fix * Test for previous time output when setting time * Stop using EventData.get_dict() * Now with microseconds! Co-authored-by: Samuel Gómez Guio <[email protected]> * Fix FPrime microsecond range expectation * Simplify RTC Manager * Add command failure test * Remove commented code * Stop overwriting getTime * Use fprime getTime() to get the time * Send command failure response if dev not ready * Add input validation Co-authored-by: Aaron Siemsen <[email protected]> --------- Co-authored-by: Nate Gay <[email protected]> Co-authored-by: Nate Gay <[email protected]> Co-authored-by: SamuelGomezG <[email protected]> Co-authored-by: Aaron Siemsen <[email protected]>
1 parent b0fd33e commit 1885213

File tree

11 files changed

+724
-20
lines changed

11 files changed

+724
-20
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
# Include project-wide components here
21
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Helpers/")
32
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Lis2mdlManager/")
43
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Lsm6dsoManager/")
4+
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/RtcManager")
55
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Types/")
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
####
2+
# F Prime CMakeLists.txt:
3+
#
4+
# SOURCES: list of source files (to be compiled)
5+
# AUTOCODER_INPUTS: list of files to be passed to the autocoders
6+
# DEPENDS: list of libraries that this module depends on
7+
#
8+
# More information in the F´ CMake API documentation:
9+
# https://fprime.jpl.nasa.gov/latest/docs/reference/api/cmake/API/
10+
#
11+
####
12+
13+
# Module names are derived from the path from the nearest project/library/framework
14+
# root when not specifically overridden by the developer. i.e. The module defined by
15+
# `Ref/SignalGen/CMakeLists.txt` will be named `Ref_SignalGen`.
16+
17+
register_fprime_library(
18+
AUTOCODER_INPUTS
19+
"${CMAKE_CURRENT_LIST_DIR}/RtcManager.fpp"
20+
SOURCES
21+
"${CMAKE_CURRENT_LIST_DIR}/RtcManager.cpp"
22+
# DEPENDS
23+
# MyPackage_MyOtherModule
24+
)
25+
26+
### Unit Tests ###
27+
# register_fprime_ut(
28+
# AUTOCODER_INPUTS
29+
# "${CMAKE_CURRENT_LIST_DIR}/RtcManager.fpp"
30+
# SOURCES
31+
# "${CMAKE_CURRENT_LIST_DIR}/test/ut/RtcManagerTestMain.cpp"
32+
# "${CMAKE_CURRENT_LIST_DIR}/test/ut/RtcManagerTester.cpp"
33+
# DEPENDS
34+
# STest # For rules-based testing
35+
# UT_AUTO_HELPERS
36+
# )
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
// ======================================================================
2+
// \title RtcManager.cpp
3+
// \brief cpp file for RtcManager component implementation class
4+
// ======================================================================
5+
6+
#include "FprimeZephyrReference/Components/Drv/RtcManager/RtcManager.hpp"
7+
8+
namespace Drv {
9+
10+
// ----------------------------------------------------------------------
11+
// Component construction and destruction
12+
// ----------------------------------------------------------------------
13+
14+
RtcManager ::RtcManager(const char* const compName) : RtcManagerComponentBase(compName) {
15+
// Initialize device
16+
this->dev = device_get_binding("RV3028");
17+
}
18+
19+
RtcManager ::~RtcManager() {}
20+
21+
// ----------------------------------------------------------------------
22+
// Handler implementations for typed input ports
23+
// ----------------------------------------------------------------------
24+
25+
void RtcManager ::timeGetPort_handler(FwIndexType portNum, Fw::Time& time) {
26+
// Check device readiness
27+
if (!device_is_ready(this->dev)) {
28+
// Use logger instead of events since this fn is in a critical path for FPrime
29+
// to get time. Events require time, if this method fails an event will fail.
30+
Fw::Logger::log("RTC not ready");
31+
return;
32+
}
33+
34+
// Get time from RTC
35+
struct rtc_time time_rtc = {};
36+
rtc_get_time(this->dev, &time_rtc);
37+
38+
// Convert to generic tm struct
39+
struct tm* time_tm = rtc_time_to_tm(&time_rtc);
40+
41+
// Convert to time_t (seconds since epoch)
42+
errno = 0;
43+
time_t seconds = timeutil_timegm(time_tm);
44+
if (errno == ERANGE) {
45+
Fw::Logger::log("RTC returned invalid time");
46+
return;
47+
}
48+
49+
// Get microseconds from system clock cycles
50+
// Note: RV3028 does not provide sub-second precision, so this is
51+
// just an approximation based on system cycles.
52+
// FPrime expects microseconds in the range [0, 999999]
53+
uint32_t useconds = k_cyc_to_us_near32(k_cycle_get_32()) % 1000000;
54+
55+
// Set FPrime time object
56+
time.set(TimeBase::TB_WORKSTATION_TIME, 0, static_cast<U32>(seconds), static_cast<U32>(useconds));
57+
}
58+
59+
// ----------------------------------------------------------------------
60+
// Handler implementations for commands
61+
// ----------------------------------------------------------------------
62+
63+
void RtcManager ::TIME_SET_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, Drv::TimeData t) {
64+
// Check device readiness
65+
if (!device_is_ready(this->dev)) {
66+
// Emit device not ready event
67+
this->log_WARNING_HI_DeviceNotReady();
68+
69+
// Send command response
70+
this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
71+
return;
72+
}
73+
this->log_WARNING_HI_DeviceNotReady_ThrottleClear();
74+
75+
// Validate time data
76+
if (!this->timeDataIsValid(t)) {
77+
// Emit time not set event
78+
this->log_WARNING_HI_TimeNotSet();
79+
80+
// Send command response
81+
this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
82+
return;
83+
}
84+
85+
// Store current time for logging
86+
Fw::Time time_before_set = this->getTime();
87+
88+
// Populate rtc_time structure from TimeData
89+
const struct rtc_time time_rtc = {
90+
.tm_sec = static_cast<int>(t.get_Second()),
91+
.tm_min = static_cast<int>(t.get_Minute()),
92+
.tm_hour = static_cast<int>(t.get_Hour()),
93+
.tm_mday = static_cast<int>(t.get_Day()),
94+
.tm_mon = static_cast<int>(t.get_Month() - 1), // month [0-11]
95+
.tm_year = static_cast<int>(t.get_Year() - 1900), // year since 1900
96+
.tm_wday = 0,
97+
.tm_yday = 0,
98+
.tm_isdst = 0,
99+
};
100+
101+
// Set time on RTC
102+
const int status = rtc_set_time(this->dev, &time_rtc);
103+
104+
if (status != 0) {
105+
// Emit time not set event
106+
this->log_WARNING_HI_TimeNotSet();
107+
108+
// Send command response
109+
this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
110+
return;
111+
}
112+
113+
// Emit time set event, include previous time for reference
114+
this->log_ACTIVITY_HI_TimeSet(time_before_set.getSeconds(), time_before_set.getUSeconds());
115+
116+
// Send command response
117+
this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
118+
}
119+
120+
bool RtcManager ::timeDataIsValid(Drv::TimeData t) {
121+
bool valid = true;
122+
123+
if (t.get_Year() < 1900) {
124+
this->log_WARNING_HI_YearValidationFailed(t.get_Year());
125+
valid = false;
126+
}
127+
128+
if (t.get_Month() < 1 || t.get_Month() > 12) {
129+
this->log_WARNING_HI_MonthValidationFailed(t.get_Month());
130+
valid = false;
131+
}
132+
133+
if (t.get_Day() < 1 || t.get_Day() > 31) {
134+
this->log_WARNING_HI_DayValidationFailed(t.get_Day());
135+
valid = false;
136+
}
137+
138+
if (t.get_Hour() > 23) {
139+
this->log_WARNING_HI_HourValidationFailed(t.get_Hour());
140+
valid = false;
141+
}
142+
143+
if (t.get_Minute() > 59) {
144+
this->log_WARNING_HI_MinuteValidationFailed(t.get_Minute());
145+
valid = false;
146+
}
147+
148+
if (t.get_Second() > 59) {
149+
this->log_WARNING_HI_SecondValidationFailed(t.get_Second());
150+
valid = false;
151+
}
152+
153+
return valid;
154+
}
155+
156+
} // namespace Drv
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# Type definition
2+
module Drv {
3+
struct TimeData {
4+
Year: U32 @< Year value.
5+
Month: U32 @< Month value.
6+
Day: U32 @< Day value.
7+
Hour: U32 @< Hour value.
8+
Minute: U32 @< Minute value.
9+
Second: U32 @< Second value.
10+
}
11+
}
12+
13+
# Port definition
14+
module Drv {
15+
port TimeSet(t: TimeData)
16+
port TimeGet -> U32
17+
}
18+
19+
module Drv {
20+
@ Manages the real time clock
21+
passive component RtcManager {
22+
import Svc.Time
23+
24+
@ TIME_SET command to set the time on the RTC
25+
sync command TIME_SET(
26+
t: Drv.TimeData @< Set the time
27+
) opcode 0
28+
29+
##############################################################################
30+
#### Uncomment the following examples to start customizing your component ####
31+
##############################################################################
32+
33+
@ DeviceNotReady event indicates that the RTC is not ready
34+
event DeviceNotReady() severity warning high id 0 format "RTC not ready" throttle 5
35+
36+
@ TimeSet event indicates that the time was set successfully
37+
event TimeSet(
38+
seconds: U32 @< Seconds since epoch
39+
useconds: U32 @< Microseconds
40+
) severity activity high id 3 format "Time set on RTC, previous time: {}.{}"
41+
42+
@ TimeNotSet event indicates that the time was not set successfully
43+
event TimeNotSet() severity warning high id 4 format "Time not set on RTC"
44+
45+
@ YearValidationFailed event indicates that the provided year is invalid
46+
event YearValidationFailed(
47+
year: U32 @< The invalid year
48+
) severity warning high id 5 format "Provided year is invalid should be >= 1900: {}"
49+
50+
@ MonthValidationFailed event indicates that the provided month is invalid
51+
event MonthValidationFailed(
52+
month: U32 @< The invalid month
53+
) severity warning high id 6 format "Provided month is invalid should be in [1, 12]: {}"
54+
55+
@ DayValidationFailed event indicates that the provided day is invalid
56+
event DayValidationFailed(
57+
day: U32 @< The invalid day
58+
) severity warning high id 7 format "Provided day is invalid should be in [1, 31]: {}"
59+
60+
@ HourValidationFailed event indicates that the provided hour is invalid
61+
event HourValidationFailed(
62+
hour: U32 @< The invalid hour
63+
) severity warning high id 8 format "Provided hour is invalid should be in [0, 23]: {}"
64+
65+
@ MinuteValidationFailed event indicates that the provided minute is invalid
66+
event MinuteValidationFailed(
67+
minute: U32 @< The invalid minute
68+
) severity warning high id 9 format "Provided minute is invalid should be in [0, 59]: {}"
69+
70+
@ SecondValidationFailed event indicates that the provided second is invalid
71+
event SecondValidationFailed(
72+
second: U32 @< The invalid second
73+
) severity warning high id 10 format "Provided second is invalid should be in [0, 59]: {}"
74+
75+
###############################################################################
76+
# Standard AC Ports: Required for Channels, Events, Commands, and Parameters #
77+
###############################################################################
78+
@ Port for requesting the current time
79+
time get port timeCaller
80+
81+
@ Port for sending command registrations
82+
command reg port cmdRegOut
83+
84+
@ Port for receiving commands
85+
command recv port cmdIn
86+
87+
@ Port for sending command responses
88+
command resp port cmdResponseOut
89+
90+
@ Port for sending textual representation of events
91+
text event port logTextOut
92+
93+
@ Port for sending events to downlink
94+
event port logOut
95+
}
96+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// ======================================================================
2+
// \title RtcManager.hpp
3+
// \brief hpp file for RtcManager component implementation class
4+
// ======================================================================
5+
6+
#ifndef Components_RtcManager_HPP
7+
#define Components_RtcManager_HPP
8+
9+
#include "FprimeZephyrReference/Components/Drv/RtcManager/RtcManagerComponentAc.hpp"
10+
11+
#include <cerrno>
12+
#include <string>
13+
#include <vector>
14+
15+
#include <Fw/Logger/Logger.hpp>
16+
17+
#include <zephyr/device.h>
18+
#include <zephyr/drivers/rtc.h>
19+
#include <zephyr/drivers/sensor.h>
20+
#include <zephyr/kernel.h>
21+
#include <zephyr/sys/timeutil.h>
22+
23+
namespace Drv {
24+
25+
class RtcManager final : public RtcManagerComponentBase {
26+
public:
27+
// ----------------------------------------------------------------------
28+
// Component construction and destruction
29+
// ----------------------------------------------------------------------
30+
31+
//! Construct RtcManager object
32+
RtcManager(const char* const compName //!< The component name
33+
);
34+
35+
//! Destroy RtcManager object
36+
~RtcManager();
37+
38+
private:
39+
// ----------------------------------------------------------------------
40+
// Handler implementations for typed input ports
41+
// ----------------------------------------------------------------------
42+
43+
//! Handler implementation for timeGetPort
44+
//!
45+
//! Port to retrieve time
46+
void timeGetPort_handler(FwIndexType portNum, //!< The port number
47+
Fw::Time& time //!< Reference to Time object
48+
) override;
49+
50+
private:
51+
// ----------------------------------------------------------------------
52+
// Handler implementations for commands
53+
// ----------------------------------------------------------------------
54+
55+
//! Handler implementation for command TIME_SET
56+
//!
57+
//! TIME_SET command to set the time on the RTC
58+
void TIME_SET_cmdHandler(FwOpcodeType opCode, //!< The opcode
59+
U32 cmdSeq, //!< The command sequence number
60+
Drv::TimeData t //!< Set the time
61+
) override;
62+
63+
private:
64+
// ----------------------------------------------------------------------
65+
// Private helper methods
66+
// ----------------------------------------------------------------------
67+
68+
//! Validate time data
69+
bool timeDataIsValid(Drv::TimeData t);
70+
71+
//! device stores the initialized Zephyr RTC device
72+
const struct device* dev;
73+
};
74+
75+
} // namespace Drv
76+
77+
#endif

0 commit comments

Comments
 (0)