Skip to content

esp32: Fix RTC initialization from datetime. #16357

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 17 additions & 7 deletions ports/esp32/machine_rtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ static mp_obj_t machine_rtc_make_new(const mp_obj_type_t *type, size_t n_args, s
return (mp_obj_t)&machine_rtc_obj;
}

static mp_obj_t machine_rtc_datetime_helper(mp_uint_t n_args, const mp_obj_t *args) {
static mp_obj_t machine_rtc_datetime_helper(mp_uint_t n_args, const mp_obj_t *args, bool use_init_format) {
if (n_args == 1) {
// Get time

Expand All @@ -126,26 +126,36 @@ static mp_obj_t machine_rtc_datetime_helper(mp_uint_t n_args, const mp_obj_t *ar
return mp_obj_new_tuple(8, tuple);
} else {
// Set time

mp_obj_t *items;
mp_obj_get_array_fixed_n(args[1], 8, &items);

struct timeval tv = {0};
tv.tv_sec = timeutils_seconds_since_epoch(mp_obj_get_int(items[0]), mp_obj_get_int(items[1]), mp_obj_get_int(items[2]), mp_obj_get_int(items[4]), mp_obj_get_int(items[5]), mp_obj_get_int(items[6]));
tv.tv_usec = mp_obj_get_int(items[7]);
if (use_init_format) {
size_t seq_len;
mp_ob_get_array_min_max(args[1], 3, 8, &seq_len, &items);
mp_int_t hour = seq_len > 3 ? mp_obj_get_int(items[3]) : 0;
mp_int_t minute = seq_len > 4 ? mp_obj_get_int(items[4]) : 0;
mp_int_t second = seq_len > 5 ? mp_obj_get_int(items[5]) : 0;
mp_int_t subsecond = seq_len > 6 ? mp_obj_get_int(items[6]) : 0;
tv.tv_sec = timeutils_seconds_since_epoch(mp_obj_get_int(items[0]), mp_obj_get_int(items[1]), mp_obj_get_int(items[2]), hour, minute, second);
tv.tv_usec = subsecond;
} else {
mp_obj_get_array_fixed_n(args[1], 8, &items);
tv.tv_sec = timeutils_seconds_since_epoch(mp_obj_get_int(items[0]), mp_obj_get_int(items[1]), mp_obj_get_int(items[2]), mp_obj_get_int(items[4]), mp_obj_get_int(items[5]), mp_obj_get_int(items[6]));
tv.tv_usec = mp_obj_get_int(items[7]);
}
settimeofday(&tv, NULL);

return mp_const_none;
}
}
static mp_obj_t machine_rtc_datetime(size_t n_args, const mp_obj_t *args) {
return machine_rtc_datetime_helper(n_args, args);
return machine_rtc_datetime_helper(n_args, args, false);
}
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_rtc_datetime_obj, 1, 2, machine_rtc_datetime);

static mp_obj_t machine_rtc_init(mp_obj_t self_in, mp_obj_t date) {
mp_obj_t args[2] = {self_in, date};
machine_rtc_datetime_helper(2, args);
machine_rtc_datetime_helper(2, args, true);

return mp_const_none;
}
Expand Down
19 changes: 19 additions & 0 deletions py/obj.c
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,25 @@
}
}

void mp_ob_get_array_min_max(mp_obj_t o, size_t min_len, size_t max_len, size_t *len, mp_obj_t **items) {
mp_obj_get_array(o, len, items);
if (*len < min_len) {

Check warning on line 453 in py/obj.c

View check run for this annotation

Codecov / codecov/patch

py/obj.c#L451-L453

Added lines #L451 - L453 were not covered by tests
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_raise_ValueError(MP_ERROR_TEXT("tuple/list length too short"));
#else
mp_raise_msg_varg(&mp_type_ValueError,
MP_ERROR_TEXT("requested minimum length %d but object has length %d"), (int)min_len, (int)*len);

Check warning on line 458 in py/obj.c

View check run for this annotation

Codecov / codecov/patch

py/obj.c#L457-L458

Added lines #L457 - L458 were not covered by tests
#endif
} else if (*len > max_len) {

Check warning on line 460 in py/obj.c

View check run for this annotation

Codecov / codecov/patch

py/obj.c#L460

Added line #L460 was not covered by tests
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_raise_ValueError(MP_ERROR_TEXT("tuple/list length too long"));
#else
mp_raise_msg_varg(&mp_type_ValueError,
MP_ERROR_TEXT("requested maximum length %d but object has length %d"), (int)max_len, (int)*len);

Check warning on line 465 in py/obj.c

View check run for this annotation

Codecov / codecov/patch

py/obj.c#L464-L465

Added lines #L464 - L465 were not covered by tests
#endif
}
}

// is_slice determines whether the index is a slice index
size_t mp_get_index(const mp_obj_type_t *type, size_t len, mp_obj_t index, bool is_slice) {
mp_int_t i;
Expand Down
1 change: 1 addition & 0 deletions py/obj.h
Original file line number Diff line number Diff line change
Expand Up @@ -1045,6 +1045,7 @@ bool mp_obj_get_complex_maybe(mp_obj_t self_in, mp_float_t *real, mp_float_t *im
#endif
void mp_obj_get_array(mp_obj_t o, size_t *len, mp_obj_t **items); // *items may point inside a GC block
void mp_obj_get_array_fixed_n(mp_obj_t o, size_t len, mp_obj_t **items); // *items may point inside a GC block
void mp_ob_get_array_min_max(mp_obj_t o, size_t min_len, size_t max_len, size_t *len, mp_obj_t **items); // *items may point inside a GC block
size_t mp_get_index(const mp_obj_type_t *type, size_t len, mp_obj_t index, bool is_slice);
mp_obj_t mp_obj_id(mp_obj_t o_in);
mp_obj_t mp_obj_len(mp_obj_t o_in);
Expand Down
4 changes: 4 additions & 0 deletions tests/ports/esp32/machine_rtc_init.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
2024 12 26 3 6 30 20
2024 12 26 3
requested maximum length 8 but object has length 9
requested minimum length 3 but object has length 2
46 changes: 46 additions & 0 deletions tests/ports/esp32/machine_rtc_init.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Test init behaviour of machine.RTC.

try:
from machine import RTC
except ImportError:
print("SKIP")
raise SystemExit

rtc = RTC()

year = 2024
month = 12
day = 26
# weekday is 3 (Thursday)
hour = 6
minute = 30
second = 20
microsecond = 0
tzinfo = 0

# Save datetime.
orig_datetime = rtc.datetime()

# Set datetime to a known value using init.
rtc.init((year, month, day, hour, minute, second, microsecond, tzinfo))
now = rtc.datetime()
print(now[0], now[1], now[2], now[3], now[4], now[5], now[6])

# Test with date only.
rtc.init((year, month, day))
print(now[0], now[1], now[2], now[3])

# Test with too many arguments.
try:
rtc.init((year, month, day, hour, minute, second, microsecond, tzinfo, 1234))
except ValueError as e:
print(e)

# Test with too few arguments.
try:
rtc.init((year, month))
except ValueError as e:
print(e)

# Restore datetime.
rtc.datetime(orig_datetime)
Loading