MCUmgr: OS: fix set datetime millisecond handling

According to the docs the millis were in the format `.SSSSSS`. In
reality though, it only accepted exactly `.SSS`, not `.SS` or `.SSSS`
and specifically also not `.SSSSSS`, contrary to the docs. Further, it did
not fail with an error message but simply produced the wrong value.

With this change it accepts everything from `.` to `.SSSSSS` and
produces the correct result. This is compatible with the previous
behavior, with the documentation and with everything in between.

Signed-off-by: Martin Stumpf <finomnis@gmail.com>
(cherry picked from commit ffb046b797)
This commit is contained in:
Martin Stumpf
2025-11-21 13:41:14 +01:00
committed by Dan Kalowsky
parent a9bfe57bf1
commit 7923ccc486

View File

@@ -18,6 +18,7 @@
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <zcbor_common.h>
#include <zcbor_encode.h>
@@ -117,8 +118,6 @@ struct datetime_parser {
#define RTC_DATETIME_MINUTE_MAX 59
#define RTC_DATETIME_SECOND_MIN 0
#define RTC_DATETIME_SECOND_MAX 59
#define RTC_DATETIME_MILLISECOND_MIN 0
#define RTC_DATETIME_MILLISECOND_MAX 999
/* Size used for datetime creation buffer */
#ifdef CONFIG_MCUMGR_GRP_OS_DATETIME_MS
@@ -129,7 +128,7 @@ struct datetime_parser {
/* Minimum/maximum size of a datetime string that a client can provide */
#define RTC_DATETIME_MIN_STRING_SIZE 19
#define RTC_DATETIME_MAX_STRING_SIZE 26
#define RTC_DATETIME_MAX_STRING_SIZE 31
#endif
/* Specifies what the "all" ('a') of info parameter shows */
@@ -965,7 +964,7 @@ static int os_mgmt_datetime_write(struct smp_streamer *ctxt)
bool ok = true;
char *pos;
char *new_pos;
char date_string[RTC_DATETIME_MAX_STRING_SIZE];
char date_string[RTC_DATETIME_MAX_STRING_SIZE + 1];
struct rtc_time new_time = {
.tm_wday = -1,
.tm_yday = -1,
@@ -1020,7 +1019,7 @@ static int os_mgmt_datetime_write(struct smp_streamer *ctxt)
if (zcbor_map_decode_bulk(zsd, datetime_decode, ARRAY_SIZE(datetime_decode), &decoded)) {
return MGMT_ERR_EINVAL;
} else if (datetime.len < RTC_DATETIME_MIN_STRING_SIZE ||
datetime.len >= RTC_DATETIME_MAX_STRING_SIZE) {
datetime.len > RTC_DATETIME_MAX_STRING_SIZE) {
return MGMT_ERR_EINVAL;
}
@@ -1056,16 +1055,20 @@ static int os_mgmt_datetime_write(struct smp_streamer *ctxt)
}
#ifdef CONFIG_MCUMGR_GRP_OS_DATETIME_MS
if (*(pos - 1) == '.' && *pos != '\0') {
/* Provided value has a ms value, extract it */
new_time.tm_nsec = strtol(pos, &new_pos, RTC_DATETIME_NUMERIC_BASE);
if (*(pos - 1) == '.') {
uint32_t msec = 0;
uint32_t mul = 100; /* first digit: 10^-1 second = 100 ms */
if (new_time.tm_nsec < RTC_DATETIME_MILLISECOND_MIN ||
new_time.tm_nsec > RTC_DATETIME_MILLISECOND_MAX) {
return MGMT_ERR_EINVAL;
/* Parse up to 3 fractional digits */
while (isdigit((unsigned char)*pos) && mul >= 1) {
msec += (uint32_t)(*pos - '0') * mul;
mul /= 10;
pos++;
}
new_time.tm_nsec *= RTC_DATETIME_MS_TO_NS;
/* "." without digits yields 0 µs */
new_time.tm_nsec = msec * RTC_DATETIME_MS_TO_NS;
}
#endif