drivers: rtc: rtc_shell: rtc shell command suite
For now clock can be read and written. Clock can be set in full iso8601 time format, like 2023-12-24T12:45:56 or by just providing either data or time Alarms not accessible Signed-off-by: Kim Bøndergaard <kim.bondergaard@prevas.dk>
This commit is contained in:
parent
05467ad6c6
commit
eed23e8cb3
3 changed files with 247 additions and 0 deletions
|
@ -11,3 +11,4 @@ zephyr_library_sources_ifdef(CONFIG_RTC_PCF8523 rtc_pcf8523.c)
|
|||
zephyr_library_sources_ifdef(CONFIG_RTC_PCF8563 rtc_pcf8563.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_RTC_MOTOROLA_MC146818 rtc_mc146818.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_RTC_STM32 rtc_ll_stm32.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_RTC_SHELL rtc_shell.c)
|
||||
|
|
|
@ -35,6 +35,12 @@ config RTC_CALIBRATION
|
|||
This is an option which enables driver support for RTC clock
|
||||
calibration.
|
||||
|
||||
config RTC_SHELL
|
||||
bool "RTC Shell commands"
|
||||
depends on SHELL
|
||||
help
|
||||
RTC Shell commands
|
||||
|
||||
source "drivers/rtc/Kconfig.emul"
|
||||
source "drivers/rtc/Kconfig.pcf8523"
|
||||
source "drivers/rtc/Kconfig.pcf8563"
|
||||
|
|
240
drivers/rtc/rtc_shell.c
Normal file
240
drivers/rtc/rtc_shell.c
Normal file
|
@ -0,0 +1,240 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Prevas A/S <kim.bondergaard@prevas.dk>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/shell/shell.h>
|
||||
#include <zephyr/drivers/rtc.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Formats accepted when setting date and/or time */
|
||||
static const char format_iso8601[] = "%FT%T";
|
||||
static const char format_time[] = "%T"; /* hh:mm:ss */
|
||||
static const char format_date[] = " %F"; /* yyyy-mm-dd */
|
||||
|
||||
#if !defined CONFIG_BOARD_NATIVE_POSIX
|
||||
|
||||
static const char *consume_chars(const char *s, char *dest, unsigned int cnt)
|
||||
{
|
||||
if (strlen(s) < cnt) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(dest, s, cnt);
|
||||
dest[cnt] = '\0';
|
||||
|
||||
return s + cnt;
|
||||
}
|
||||
|
||||
static const char *consume_char(const char *s, char ch)
|
||||
{
|
||||
if (*s != ch) {
|
||||
return NULL;
|
||||
}
|
||||
return ++s;
|
||||
}
|
||||
|
||||
static const char *consume_date(const char *s, struct tm *tm_time)
|
||||
{
|
||||
char year[4 + 1];
|
||||
char month[2 + 1];
|
||||
char day[2 + 1];
|
||||
|
||||
s = consume_chars(s, year, 4);
|
||||
if (!s) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s = consume_char(s, '-');
|
||||
if (!s) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s = consume_chars(s, month, 2);
|
||||
if (!s) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s = consume_char(s, '-');
|
||||
if (!s) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s = consume_chars(s, day, 2);
|
||||
if (!s) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tm_time->tm_year = atoi(year) - 1900;
|
||||
tm_time->tm_mon = atoi(month) - 1;
|
||||
tm_time->tm_mday = atoi(day);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static const char *consume_time(const char *s, struct tm *tm_time)
|
||||
{
|
||||
char hour[2 + 1];
|
||||
char minute[2 + 1];
|
||||
char second[2 + 1];
|
||||
|
||||
s = consume_chars(s, hour, 2);
|
||||
if (!s) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s = consume_char(s, ':');
|
||||
if (!s) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s = consume_chars(s, minute, 2);
|
||||
if (!s) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s = consume_char(s, ':');
|
||||
if (!s) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s = consume_chars(s, second, 2);
|
||||
if (!s) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tm_time->tm_hour = atoi(hour);
|
||||
tm_time->tm_min = atoi(minute);
|
||||
tm_time->tm_sec = atoi(second);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static char *strptime(const char *s, const char *format, struct tm *tm_time)
|
||||
{
|
||||
/* Reduced implementation of strptime -
|
||||
* accepting only the 3 different format strings
|
||||
*/
|
||||
if (!strcmp(format, format_iso8601)) {
|
||||
s = consume_date(s, tm_time);
|
||||
if (!s) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s = consume_char(s, 'T');
|
||||
if (!s) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s = consume_time(s, tm_time);
|
||||
if (!s) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (char *)s;
|
||||
|
||||
} else if (!strcmp(format, format_time)) {
|
||||
return (char *)consume_time(s, tm_time);
|
||||
|
||||
} else if (!strcmp(format, format_date)) {
|
||||
return (char *)consume_date(s, tm_time);
|
||||
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int cmd_set(const struct shell *sh, size_t argc, char **argv)
|
||||
{
|
||||
const struct device *dev = device_get_binding(argv[1]);
|
||||
|
||||
if (!device_is_ready(dev)) {
|
||||
shell_error(sh, "device %s not ready", argv[1]);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
struct rtc_time rtctime = {0};
|
||||
struct tm *tm_time = rtc_time_to_tm(&rtctime);
|
||||
|
||||
(void)rtc_get_time(dev, &rtctime);
|
||||
|
||||
const char *format;
|
||||
|
||||
if (strchr(argv[1], 'T')) {
|
||||
format = format_iso8601;
|
||||
} else if (strchr(argv[1], '-')) {
|
||||
format = format_date;
|
||||
} else {
|
||||
format = format_time;
|
||||
}
|
||||
|
||||
char *parseRes = strptime(argv[1], format, tm_time);
|
||||
|
||||
if (!parseRes || *parseRes != '\0') {
|
||||
shell_error(sh, "Error in argument format");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int res = rtc_set_time(dev, &rtctime);
|
||||
|
||||
if (-EINVAL == res) {
|
||||
shell_error(sh, "error in time");
|
||||
return -EINVAL;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int cmd_get(const struct shell *sh, size_t argc, char **argv)
|
||||
{
|
||||
const struct device *dev = device_get_binding(argv[1]);
|
||||
|
||||
printk("in RTC Shell Get\n");
|
||||
|
||||
if (!device_is_ready(dev)) {
|
||||
shell_error(sh, "device %s not ready", argv[1]);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
struct rtc_time rtctime;
|
||||
|
||||
int res = rtc_get_time(dev, &rtctime);
|
||||
|
||||
if (-ENODATA == res) {
|
||||
shell_print(sh, "RTC not set");
|
||||
return 0;
|
||||
}
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
shell_print(sh, "%04d-%02d-%02dT%02d:%02d:%02d:%06d", rtctime.tm_year + 1900,
|
||||
rtctime.tm_mon + 1, rtctime.tm_mday, rtctime.tm_hour, rtctime.tm_min,
|
||||
rtctime.tm_sec, rtctime.tm_nsec / 1000000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define RTC_GET_HELP \
|
||||
("Get current time (UTC)\n" \
|
||||
"Usage: rtc get <device>")
|
||||
|
||||
#define RTC_SET_HELP \
|
||||
("Set UTC time\n" \
|
||||
"Usage: rtc set <device> <YYYY-MM-DDThh:mm:ss> | <YYYY-MM-DD> | <hh:mm:ss>")
|
||||
|
||||
SHELL_STATIC_SUBCMD_SET_CREATE(sub_rtc,
|
||||
/* Alphabetically sorted */
|
||||
SHELL_CMD_ARG(set, NULL, RTC_SET_HELP, cmd_set, 3, 0),
|
||||
SHELL_CMD_ARG(get, NULL, RTC_GET_HELP, cmd_get, 2, 0),
|
||||
SHELL_SUBCMD_SET_END);
|
||||
|
||||
SHELL_CMD_REGISTER(rtc, &sub_rtc, "RTC commands", NULL);
|
Loading…
Add table
Add a link
Reference in a new issue