1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-07-28 17:38:35 +00:00

feat(core/prodtest): add functions for setting and getting RTC datetime

[no changelog]
This commit is contained in:
tychovrahe 2025-07-03 21:26:01 +02:00 committed by TychoVrahe
parent 64c22a8e65
commit f97ead8bb5
4 changed files with 201 additions and 2 deletions

View File

@ -1066,7 +1066,30 @@ rtc-timestamp
OK 1886533
```
### rtc-set
Sets the current RTC date and time.
`rtc-set <year> <month> <day> <hour> <minute> <second>`
Example:
```
rtc-set 2025 07 03 14 23 00
OK
```
### rtc-get
Reads the current RTC date and time.
Response format:
`OK <year> <month> <day> <hour> <minute> <second> <day-of-week>`, where `day-of-week` is a number from 1 (Monday) to 7 (Sunday).
Where:
Example:
```
rtc-get
OK 2025 07 03 14 23 00 4
```

View File

@ -38,6 +38,47 @@ static void prodtest_rtc_timestamp(cli_t* cli) {
cli_ok(cli, "%u", timestamp);
}
static void prodtest_rtc_set(cli_t* cli) {
if (cli_arg_count(cli) != 6) {
cli_error_arg_count(cli);
return;
}
uint32_t year, month, day, hour, minute, second;
if (!cli_arg_uint32(cli, "year", &year) ||
!cli_arg_uint32(cli, "month", &month) ||
!cli_arg_uint32(cli, "day", &day) ||
!cli_arg_uint32(cli, "hour", &hour) ||
!cli_arg_uint32(cli, "minute", &minute) ||
!cli_arg_uint32(cli, "second", &second)) {
cli_error_arg(cli, "Invalid date/time values");
return;
}
if (!rtc_set(year, month, day, hour, minute, second)) {
cli_error(cli, CLI_ERROR, "Failed to set RTC time");
return;
}
cli_ok(cli, "");
}
static void prodtest_rtc_get(cli_t* cli) {
if (cli_arg_count(cli) > 0) {
cli_error_arg_count(cli);
return;
}
rtc_datetime_t datetime;
if (!rtc_get(&datetime)) {
cli_error(cli, CLI_ERROR, "Failed to get RTC time");
return;
}
cli_ok(cli, "%04u %02u %02u %02u %02u %02u %02u", datetime.year,
datetime.month, datetime.day, datetime.hour, datetime.minute,
datetime.second, datetime.weekday);
}
// clang-format off
PRODTEST_CLI_CMD(
.name = "rtc-timestamp",
@ -46,4 +87,20 @@ PRODTEST_CLI_CMD(
.args = ""
);
PRODTEST_CLI_CMD(
.name = "rtc-set",
.func = prodtest_rtc_set,
.info = "Set RTC date/time",
.args = "<year> <month> <day> <hour> <minute> <second>",
);
PRODTEST_CLI_CMD(
.name = "rtc-get",
.func = prodtest_rtc_get,
.info = "Get RTC date/time",
.args = "",
);
#endif

View File

@ -19,6 +19,18 @@
#pragma once
#include <trezor_types.h>
typedef struct {
uint16_t year; /**< Full year (e.g., 2025) */
uint8_t month; /**< Month (112) */
uint8_t day; /**< Day of the month (131) */
uint8_t hour; /**< Hour (023) */
uint8_t minute; /**< Minute (059) */
uint8_t second; /**< Second (059) */
uint8_t weekday; /**< Weekday (1=Monday to 7=Sunday) */
} rtc_datetime_t;
/**
* @brief Initialize the RTC driver
*
@ -67,3 +79,32 @@ bool rtc_wakeup_timer_start(uint32_t seconds, rtc_wakeup_callback_t callback,
* @brief Stop the RTC wakeup timer
*/
void rtc_wakeup_timer_stop(void);
/**
* @brief Set the RTC using discrete time values
*
* Sets the RTC date and time using individual components: year, month, day,
* hour, minute, and second. The weekday is automatically calculated based on
* the given date.
*
* @param year Full year (e.g., 2025). Must be between 2000 and 2099.
* @param month Month (112).
* @param day Day of the month (131).
* @param hour Hour (023).
* @param minute Minute (059).
* @param second Second (059).
* @return true if the time was successfully set, false otherwise
*/
bool rtc_set(uint16_t year, uint8_t month, uint8_t day, uint8_t hour,
uint8_t minute, uint8_t second);
/**
* @brief Get the current RTC time as a structured date and time
*
* Reads the RTC date and time registers and returns the result in a
* structured format.
*
* @param datetime Pointer to an rtc_datetime_t struct to hold the result.
* @return true if the time was successfully retrieved, false otherwise
*/
bool rtc_get(rtc_datetime_t* datetime);

View File

@ -87,7 +87,7 @@ bool rtc_get_timestamp(uint32_t* timestamp) {
// Get current time and date,
// Important: GetTime has to be called before the GetDate in order to unlock
// the values in higher-order callendar.
// the values in higher-order calendar.
if (HAL_OK != HAL_RTC_GetTime(&drv->hrtc, &time, RTC_FORMAT_BCD)) {
return false;
}
@ -221,4 +221,82 @@ static uint32_t rtc_calendar_to_timestamp(const RTC_DateTypeDef* date,
return seconds + 946684800;
}
bool rtc_set(uint16_t year, uint8_t month, uint8_t day, uint8_t hour,
uint8_t minute, uint8_t second) {
rtc_driver_t* drv = &g_rtc_driver;
if (!drv->initialized) {
return false;
}
// Validate inputs
if (year < 2000 || year > 2099 || month < 1 || month > 12 || day < 1 ||
day > 31 || hour > 23 || minute > 59 || second > 59) {
return false;
}
// --- Weekday calculation using Zeller's Congruence ---
// Adjust month/year for Zeller's algorithm
int y = (month <= 2) ? year - 1 : year;
int m = (month <= 2) ? month + 12 : month;
int d = day;
int K = y % 100;
int J = y / 100;
int h = (d + 13 * (m + 1) / 5 + K + K / 4 + J / 4 + 5 * J) % 7;
// Convert Zeller's output to RTC weekday (1 = Monday, ..., 7 = Sunday)
// Zeller: 0 = Saturday, 1 = Sunday, 2 = Monday, ..., 6 = Friday
uint8_t weekday = ((h + 5) % 7) + 1;
RTC_TimeTypeDef time = {.Hours = hour,
.Minutes = minute,
.Seconds = second,
.TimeFormat = RTC_HOURFORMAT_24,
.DayLightSaving = RTC_DAYLIGHTSAVING_NONE,
.StoreOperation = RTC_STOREOPERATION_RESET};
if (HAL_OK != HAL_RTC_SetTime(&drv->hrtc, &time, RTC_FORMAT_BIN)) {
return false;
}
RTC_DateTypeDef date = {
.Year = year - 2000, .Month = month, .Date = day, .WeekDay = weekday};
if (HAL_OK != HAL_RTC_SetDate(&drv->hrtc, &date, RTC_FORMAT_BIN)) {
return false;
}
return true;
}
bool rtc_get(rtc_datetime_t* datetime) {
rtc_driver_t* drv = &g_rtc_driver;
if (!drv->initialized || datetime == NULL) {
return false;
}
RTC_DateTypeDef date;
RTC_TimeTypeDef time;
// Get current time before date (important for consistency)
if (HAL_OK != HAL_RTC_GetTime(&drv->hrtc, &time, RTC_FORMAT_BIN)) {
return false;
}
if (HAL_OK != HAL_RTC_GetDate(&drv->hrtc, &date, RTC_FORMAT_BIN)) {
return false;
}
datetime->year = 2000 + date.Year;
datetime->month = date.Month;
datetime->day = date.Date;
datetime->hour = time.Hours;
datetime->minute = time.Minutes;
datetime->second = time.Seconds;
datetime->weekday = date.WeekDay;
return true;
}
#endif // KERNEL_MODE