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:
parent
64c22a8e65
commit
f97ead8bb5
@ -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
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -19,6 +19,18 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <trezor_types.h>
|
||||
|
||||
typedef struct {
|
||||
uint16_t year; /**< Full year (e.g., 2025) */
|
||||
uint8_t month; /**< Month (1–12) */
|
||||
uint8_t day; /**< Day of the month (1–31) */
|
||||
uint8_t hour; /**< Hour (0–23) */
|
||||
uint8_t minute; /**< Minute (0–59) */
|
||||
uint8_t second; /**< Second (0–59) */
|
||||
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 (1–12).
|
||||
* @param day Day of the month (1–31).
|
||||
* @param hour Hour (0–23).
|
||||
* @param minute Minute (0–59).
|
||||
* @param second Second (0–59).
|
||||
* @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);
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user