On Fri, 18 Jul 2014 07:44:13 +0200 Sascha Hauer <s.hauer@xxxxxxxxxxxxxx> wrote: > On Tue, Jul 15, 2014 at 12:48:35AM +0400, Antony Pavlov wrote: > > The hwclock command allows to query or set the hardware clock (RTC). > > > > Signed-off-by: Antony Pavlov <antonynpavlov@xxxxxxxxx> > > --- > > commands/Kconfig | 8 +++ > > commands/Makefile | 1 + > > commands/hwclock.c | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++++ > > 3 files changed, 160 insertions(+) > > > > diff --git a/commands/Kconfig b/commands/Kconfig > > index 61816f5..6a75f85 100644 > > --- a/commands/Kconfig > > +++ b/commands/Kconfig > > @@ -1691,6 +1691,14 @@ config CMD_GPIO > > > > Usage: gpio_set_value GPIO VALUE > > > > +config CMD_HWCLOCK > > + bool > > + depends on RTC_CLASS > > + prompt "hwclock command" > > + default y > > + help > > + The hwclock command allows to query or set the hardware clock (RTC). > > + > > config CMD_I2C > > bool > > depends on I2C > > diff --git a/commands/Makefile b/commands/Makefile > > index d42aca5..44dd9d4 100644 > > --- a/commands/Makefile > > +++ b/commands/Makefile > > @@ -100,3 +100,4 @@ obj-$(CONFIG_CMD_MENUTREE) += menutree.o > > obj-$(CONFIG_CMD_2048) += 2048.o > > obj-$(CONFIG_CMD_REGULATOR) += regulator.o > > obj-$(CONFIG_CMD_LSPCI) += lspci.o > > +obj-$(CONFIG_CMD_HWCLOCK) += hwclock.o > > diff --git a/commands/hwclock.c b/commands/hwclock.c > > new file mode 100644 > > index 0000000..511973a > > --- /dev/null > > +++ b/commands/hwclock.c > > @@ -0,0 +1,151 @@ > > +#include <common.h> > > +#include <command.h> > > +#include <getopt.h> > > +#include <linux/err.h> > > +#include <linux/ctype.h> > > +#include <rtc.h> > > +#include <linux/rtc.h> > > +#include <string.h> > > +#include <environment.h> > > + > > +static char *strchrnul(const char *s, int c) > > +{ > > + while (*s != '\0' && *s != c) > > + s++; > > + > > + return (char *)s; > > +} > > + > > +static int sscanf_two_digits(char *s, int *res) > > +{ > > + char buf[3]; > > + unsigned long t; > > + > > + if (!isdigit(s[0]) || !isdigit(s[1])) { > > + return -EINVAL; > > + } > > + > > + buf[0] = s[0]; > > + buf[1] = s[1]; > > + buf[2] = '\0'; > > + > > + t = simple_strtoul(buf, NULL, 10); > > + *res = t; > > + > > + return 0; > > +} > > + > > +static int parse_datestr(char *date_str, struct rtc_time *ptm) > > +{ > > + char end = '\0'; > > + int len = strchrnul(date_str, '.') - date_str; > > + int year; > > + > > + /* ccyymmddHHMM[.SS] */ > > + if (len != 12) { > > + return -EINVAL; > > + } > > + > > + if (sscanf_two_digits(date_str, &year) || > > + sscanf_two_digits(&date_str[2], &ptm->tm_year)) { > > + return -EINVAL; > > + } > > + > > + ptm->tm_year = year * 100 + ptm->tm_year; > > + > > + /* Adjust years */ > > + ptm->tm_year -= 1900; > > + > > + if (sscanf_two_digits(&date_str[4], &ptm->tm_mon) || > > + sscanf_two_digits(&date_str[6], &ptm->tm_mday) || > > + sscanf_two_digits(&date_str[8], &ptm->tm_hour) || > > + sscanf_two_digits(&date_str[10], &ptm->tm_min)) { > > + return -EINVAL; > > + } > > + > > + /* Adjust month from 1-12 to 0-11 */ > > + ptm->tm_mon -= 1; > > + > > + end = date_str[12]; > > + > > + if (end == '.') { > > + /* xxx.SS */ > > + if (!sscanf_two_digits(&date_str[13], &ptm->tm_sec)) { > > + end = '\0'; > > + } > > + /* else end != NUL and we error out */ > > + } > > + > > + if (end != '\0') { > > + return -EINVAL; > > + } > > + > > + return 0; > > +} > > + > > +static int do_hwclock(int argc, char *argv[]) > > +{ > > + struct rtc_device *r; > > + struct rtc_time tm; > > + struct rtc_time stm; > > + char rtc_name[16] = "rtc0"; > > + char *env_name = NULL; > > + int opt; > > + int set = 0; > > + > > + while ((opt = getopt(argc, argv, "f:s:e:")) > 0) { > > + switch (opt) { > > + case 'f': > > + strncpy(rtc_name, optarg, 16); > > + break; > > + case 's': > > + memset(&stm, 0, sizeof(stm)); > > + parse_datestr(optarg, &stm); > > + set = 1; > > + break; > > + case 'e': > > + env_name = optarg; > > + break; > > + } > > + } > > + > > + r = rtc_lookup(rtc_name); > > + if (IS_ERR(r)) > > + return PTR_ERR(r); > > + > > + if (set) { > > + rtc_set_time(r, &stm); > > + return 0; > > + } > > + > > + rtc_read_time(r, &tm); > > + > > + if (env_name) { > > + unsigned long time; > > + char t[12]; > > + > > + rtc_tm_to_time(&tm, &time); > > + snprintf(t, 12, "%lu", time); > > + setenv(env_name, t); > > I thought more about a globalvar_add(), like globalvar.date, so that no > command has to be executed to get the date. But then again maybe it's > better to have it in a command since it allows us to add different > formats without much hassle. > > > + } else { > > + printf("%02d:%02d:%02d %02d-%02d-%04d\n", > > + tm.tm_hour, tm.tm_min, tm.tm_sec, > > + tm.tm_mday, tm.tm_mon + 1, tm.tm_year + 1900); > > + } > > + > > + return 0; > > +} > > + > > +BAREBOX_CMD_HELP_START(hwclock) > > +BAREBOX_CMD_HELP_TEXT("Options:") > > +BAREBOX_CMD_HELP_OPT ("-f NAME\t\t\t", "RTC device name (default rtc0)") > > +BAREBOX_CMD_HELP_OPT ("-e VARNAME\t\t", "store RTC readout into variable VARNAME") > > +BAREBOX_CMD_HELP_OPT ("-s ccyymmddHHMM[.SS]\t", "set time") > > It's much more logical to have the year first, but the format documented > in 'man date' is MMDDhhmm[[CC]YY][.ss]. Of course we are free to choose > another format, but maybe we should rather use a format someone other > uses aswell? The format MMDDhhmm[[CC]YY][.ss] forces me to add additional logic. It the command hwclock is invoked with MMDDhhmm argument (without CCYY) then i have to read RTC to get current year and only after that set RTC new time. If you insist on MMDDhhmm[[CC]YY][.ss] then I can steal appropriate ready-to-use code from busybox for handling "weird format with completely unnatural placement of year between minutes and seconds" (quote from busybox code :). -- Best regards, Antony Pavlov _______________________________________________ barebox mailing list barebox@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/barebox