diff --git a/ports/psoc6/machine_rtc.c b/ports/psoc6/machine_rtc.c index 0a6745299d8e..c3ef9c27f602 100644 --- a/ports/psoc6/machine_rtc.c +++ b/ports/psoc6/machine_rtc.c @@ -61,12 +61,13 @@ #define RTC_INIT_DST 0 #define TM_YEAR_BASE (1900u) +#define rtc_assert_raise(msg, ret) if (ret != CY_RSLT_SUCCESS) { \ + mp_raise_ValueError(MP_ERROR_TEXT(msg)); \ +} -cyhal_rtc_t psoc6_rtc; -bool rtc_memory = false; -static void rtc_irq_handler1(void *callback, cyhal_rtc_event_t event); -static void rtc_irq_handler2(void *callback, cyhal_rtc_event_t event); +cyhal_rtc_t psoc6_rtc; +static bool rtc_memory = false; typedef struct _machine_rtc_obj_t { mp_obj_base_t base; @@ -78,25 +79,21 @@ typedef struct _machine_rtc_obj_t { } machine_rtc_obj_t; // singleton RTC object -static machine_rtc_obj_t machine_rtc_obj; +static machine_rtc_obj_t machine_rtc_obj = {.base = {&machine_rtc_type}}; bool rtc_memory_write_enabled() { return rtc_memory; } /* This function is run from main.c to init the RTC at boot time. This will set the RTC to PSoC default time: 1st Jan 2000*/ -void rtc_init(void) { +void mod_rtc_init(void) { cy_rslt_t result = cyhal_rtc_init(&psoc6_rtc); - - if (CY_RSLT_SUCCESS != result) { - mp_raise_ValueError(MP_ERROR_TEXT("cyhal_rtc_init failed !")); - } + rtc_assert_raise("cyhal_rtc_init failed !", result); } -static inline void rtc_enable() { - bool r = cyhal_rtc_is_enabled(&psoc6_rtc); - if (!r) { - rtc_init(); +void mod_rtc_deinit() { + if (rtc_memory_write_enabled() == false) { + cyhal_rtc_free(&psoc6_rtc); } } @@ -105,9 +102,7 @@ static mp_obj_t machine_rtc_datetime_helper(mp_obj_t self_in, mp_uint_t n_args, struct tm current_date_time; if (n_args == 1) { cy_rslt_t result = cyhal_rtc_read(&psoc6_rtc, ¤t_date_time); - if (CY_RSLT_SUCCESS != result) { - mp_raise_ValueError(MP_ERROR_TEXT("cyhal_rtc_read failed !")); - } + rtc_assert_raise("cyhal_rtc_read failed !", result); mp_obj_t tuple[8] = { mp_obj_new_int(current_date_time.tm_year + TM_YEAR_BASE), @@ -133,10 +128,7 @@ static mp_obj_t machine_rtc_datetime_helper(mp_obj_t self_in, mp_uint_t n_args, current_date_time.tm_sec = mp_obj_get_int(items[6]); cy_rslt_t result = cyhal_rtc_write(&psoc6_rtc, ¤t_date_time); - - if (CY_RSLT_SUCCESS != result) { - mp_raise_ValueError(MP_ERROR_TEXT("cyhal_rtc_write failed ! Check if field values entered are within the specified range.")); - } + rtc_assert_raise("cyhal_rtc_write failed ! Check if field values entered are within the specified range.", result); } return mp_const_none; } @@ -175,16 +167,22 @@ static inline uint64_t rtc_get_current_time_in_sec() { } -void rtc_irq_handler1(void *callback, cyhal_rtc_event_t event) { - mp_call_function_1((mp_obj_t)callback, mp_obj_new_int(event)); -} +static void rtc_irq_handler(void *self, cyhal_rtc_event_t event); -void rtc_irq_handler2(void *callback, cyhal_rtc_event_t event) { - machine_rtc_obj_t *self = (machine_rtc_obj_t *)callback; - cyhal_rtc_register_callback(&psoc6_rtc, (cyhal_rtc_event_callback_t)rtc_irq_handler2, self); - cyhal_rtc_enable_event(&psoc6_rtc, CYHAL_RTC_ALARM, 3, true); +static void rtc_alarm_setup(machine_rtc_obj_t *self) { cyhal_rtc_set_alarm_by_seconds(&psoc6_rtc, mp_obj_get_int(self->alarm_period_s)); - mp_call_function_1((mp_obj_t)self->callback, mp_obj_new_int(event)); + cyhal_rtc_register_callback(&psoc6_rtc, (cyhal_rtc_event_callback_t)rtc_irq_handler, self); + cyhal_rtc_enable_event(&psoc6_rtc, CYHAL_RTC_ALARM, 3, true); +} + +void rtc_irq_handler(void *self_in, cyhal_rtc_event_t event) { + machine_rtc_obj_t *self = (machine_rtc_obj_t *)self_in; + if (self->callback != NULL) { + if (self->repeat) { + rtc_alarm_setup(self); + } + mp_call_function_1((mp_obj_t)self->callback, mp_obj_new_int(event)); + } } static inline void rtc_get_dtime_struct(const mp_obj_t datetime, struct tm *dtime) { @@ -211,16 +209,19 @@ static inline void rtc_get_dtime_struct(const mp_obj_t datetime, struct tm *dtim // RTC constructor static mp_obj_t machine_rtc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 0, 0, false); - machine_rtc_obj_t *self = &machine_rtc_obj; - self->base.type = &machine_rtc_type; - return MP_OBJ_FROM_PTR(self); + return (mp_obj_t)&machine_rtc_obj; } // RTC.init(datetime) static mp_obj_t machine_rtc_init(mp_obj_t self_in, mp_obj_t datetime) { + machine_rtc_obj_t *self = (machine_rtc_obj_t *)self_in; + self->alarm_elapse_time_s = NULL; + self->alarm_period_s = NULL; + self->alarmset = false; + self->callback = NULL; + self->repeat = false; + mp_obj_t args[2] = {self_in, datetime}; - // Check if RTC is correctly initialized already through main - rtc_enable(); machine_rtc_datetime_helper(args[0], 2, args); return mp_const_none; } @@ -246,9 +247,8 @@ static mp_obj_t machine_rtc_deinit(mp_obj_t self_in) { .tm_isdst = RTC_INIT_DST }; cy_rslt_t result = cyhal_rtc_write(&psoc6_rtc, &reset_date_time); - if (CY_RSLT_SUCCESS != result) { - mp_raise_ValueError(MP_ERROR_TEXT("cyhal_rtc_write failed during RTC deinitialization!")); - } + rtc_assert_raise("cyhal_rtc_write failed during RTC deinitialization!", result); + return mp_const_none; } static MP_DEFINE_CONST_FUN_OBJ_1(machine_rtc_deinit_obj, machine_rtc_deinit); @@ -296,7 +296,7 @@ static mp_obj_t machine_rtc_alarm(size_t n_args, const mp_obj_t *pos_args, mp_ma cyhal_rtc_set_alarm(&psoc6_rtc, &dtime, alarm_active); } else { // then it must be an integer self->alarm_period_s = mp_obj_new_int_from_uint(mp_obj_get_int(args[0].u_obj) / 1000); - cyhal_rtc_set_alarm_by_seconds(&psoc6_rtc, mp_obj_get_int(args[0].u_obj) / 1000); + rtc_alarm_setup(self); } self->alarm_elapse_time_s = mp_obj_new_int_from_uint(alarm_set_time_s + mp_obj_get_int(self->alarm_period_s)); self->alarmset = true; @@ -308,7 +308,7 @@ static MP_DEFINE_CONST_FUN_OBJ_KW(machine_rtc_alarm_obj, 1, machine_rtc_alarm); static mp_obj_t machine_rtc_alarm_left(size_t n_args, const mp_obj_t *args) { machine_rtc_obj_t *self = args[0]; // only alarm id 0 is available - if (n_args > 1 && mp_obj_get_int(args[1]) != 0) { + if (n_args > 1 && mp_obj_get_int(args[1]) != CYHAL_RTC_ALARM) { mp_raise_OSError(MP_ENODEV); } if (self->alarmset) { @@ -322,7 +322,7 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_rtc_alarm_left_obj, 1, 2, mac // RTC.cancel() static mp_obj_t machine_rtc_cancel(size_t n_args, const mp_obj_t *args) { // only alarm id 0 is available - if (n_args > 1 && mp_obj_get_int(args[1]) != 0) { + if (n_args > 1 && mp_obj_get_int(args[1]) != CYHAL_RTC_ALARM) { mp_raise_OSError(MP_ENODEV); } // disable the alarm @@ -345,27 +345,31 @@ static mp_obj_t machine_rtc_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_ enum { ARG_trigger, ARG_handler, ARG_wake}; static const mp_arg_t allowed_args[] = { { MP_QSTR_trigger, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = CYHAL_RTC_ALARM} }, - { MP_QSTR_handler, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, - { MP_QSTR_wake, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} } + { MP_QSTR_handler, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_wake, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} } }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); machine_rtc_obj_t *self = pos_args[0]; + self->callback = args[ARG_handler].u_obj; + if (args[ARG_handler].u_obj == mp_const_none) { + self->callback = NULL; + } - if (self->repeat) { - cyhal_rtc_register_callback(&psoc6_rtc, (cyhal_rtc_event_callback_t)rtc_irq_handler2, self); - } else { - cyhal_rtc_register_callback(&psoc6_rtc, (cyhal_rtc_event_callback_t)rtc_irq_handler1, self->callback); + if (args[ARG_trigger].u_int != CYHAL_RTC_ALARM) { + mp_raise_OSError(MP_ENODEV); + } + + if (args[ARG_wake].u_int != -1) { + mp_raise_NotImplementedError(MP_ERROR_TEXT("wake not implemented!\n")); } - cyhal_rtc_enable_event(&psoc6_rtc, args[ARG_trigger].u_int, 3u, true); return mp_const_none; } static MP_DEFINE_CONST_FUN_OBJ_KW(machine_rtc_irq_obj, 1, machine_rtc_irq); - static const mp_rom_map_elem_t machine_rtc_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_rtc_init_obj) }, { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_rtc_deinit_obj) }, @@ -389,7 +393,3 @@ MP_DEFINE_CONST_OBJ_TYPE( make_new, machine_rtc_make_new, locals_dict, &machine_rtc_locals_dict ); - -void mod_rtc_deinit() { - cyhal_rtc_free(&psoc6_rtc); -} diff --git a/ports/psoc6/main.c b/ports/psoc6/main.c index 0dd4719a1240..b836990be372 100644 --- a/ports/psoc6/main.c +++ b/ports/psoc6/main.c @@ -50,7 +50,7 @@ extern uint8_t __StackTop, __StackLimit; __attribute__((section(".bss"))) static char gc_heap[MICROPY_GC_HEAP_SIZE]; #endif -extern void rtc_init(void); +extern void mod_rtc_init(void); extern void time_init(void); extern void os_init(void); extern void network_init(void); @@ -113,12 +113,11 @@ void mpy_task(void *arg) { // Initialize modules. Or to be redone after a reset and therefore to be placed next to machine_init below ? os_init(); - rtc_init(); time_init(); - soft_reset: + mod_rtc_init(); mp_init(); // ANSI ESC sequence for clear screen. Refer to https://stackoverflow.com/questions/517970/how-to-clear-the-interpreter-console @@ -188,9 +187,9 @@ void mpy_task(void *arg) { mod_i2c_deinit(); mod_pwm_deinit(); mod_spi_deinit(); - if (rtc_memory_write_enabled() == false) { - mod_rtc_deinit(); - } + // if (rtc_memory_write_enabled() == false) { + mod_rtc_deinit(); + // } mod_pin_phy_deinit(); #if MICROPY_PY_NETWORK mod_network_deinit(); diff --git a/tests/psoc6/rtc.py b/tests/psoc6/rtc.py index 0334cd1504d2..9704913c08c4 100644 --- a/tests/psoc6/rtc.py +++ b/tests/psoc6/rtc.py @@ -29,14 +29,23 @@ def reset_rtc(): def set_alarm_ms(rtc, alarm_type, period_ms): rtc.datetime(initial_dtime) + rtc_irq = rtc.irq(handler=cback) rtc.alarm(period_ms, repeat=alarm_type) - rtc_irq = rtc.irq(trigger=RTC.ALARM0, handler=cback) def set_alarm_datetime(rtc, alarm_type, datetime): rtc.datetime(initial_dtime) - rtc.alarm(datetime, repeat=alarm_type) rtc_irq = rtc.irq(trigger=RTC.ALARM0, handler=cback) + rtc.alarm(datetime, repeat=alarm_type) + + +def wait_for_cback(timeout, exp_counter): + global irq_counter + start = time.ticks_ms() + while irq_counter < exp_counter: + time.sleep_ms(5) + if time.ticks_diff(time.ticks_ms(), start) > cback_call_wait_time: + break print("*** RTC Tests ***") @@ -51,30 +60,35 @@ def set_alarm_datetime(rtc, alarm_type, datetime): time.sleep_ms(1008) print("\ndatetime is accurate: \t", rtc.now() == exp_dtime) - print("\n1. Setting periodic short alarm to be triggered repeatedly in few ms in future") -set_alarm_ms(rtc, periodic_alarm, 3000) +timeout = 1000 +cback_call_wait_time = timeout + 200 +set_alarm_ms(rtc, periodic_alarm, timeout) print("Alarm period set to (ms): ", rtc.alarm_left()) -time.sleep_ms(3008) +wait_for_cback(cback_call_wait_time, 1) print("Alarm expired : ", irq_counter == 1) print("Alarm set again...") -time.sleep_ms(3008) +wait_for_cback(cback_call_wait_time, 2) print("Alarm expired : ", irq_counter == 2) rtc.cancel() -time.sleep_ms(3008) +wait_for_cback(cback_call_wait_time, 2) print("Alarm cancelled successfully : ", irq_counter == 2) irq_counter = 0 print("\n2. Setting one-shot short alarm to be triggered in few ms in future") -set_alarm_ms(rtc, one_shot_alarm, 1000) -time.sleep_ms(1008) +timeout = 1000 +cback_call_wait_time = timeout + 500 +set_alarm_ms(rtc, one_shot_alarm, timeout) +wait_for_cback(cback_call_wait_time, 1) print("Alarm expired : ", 0 == rtc.alarm_left()) print("Entered Cback :", irq_counter == 1) irq_counter = 0 print("\n3. Setting one-shot alarm to be triggered at specified date-time") -set_alarm_datetime(rtc, one_shot_alarm, (2023, 1, 1, 0, 0, 1, 0, 0)) -time.sleep_ms(1008) +timeout = 1 +cback_call_wait_time = timeout * 1000 + 500 +set_alarm_datetime(rtc, one_shot_alarm, (2023, 1, 1, 0, 0, timeout, 0, 0)) +wait_for_cback(cback_call_wait_time, 1) print("Alarm expired : ", 0 == rtc.alarm_left()) print("Entered Cback :", irq_counter == 1) irq_counter = 0 @@ -87,6 +101,9 @@ def set_alarm_datetime(rtc, alarm_type, datetime): irq_counter = 0 +rtc1 = RTC() +print("\n5.RTC constructor return singleton: ", rtc1 == rtc) + reset_rtc() check_rtc_mem_write() diff --git a/tests/psoc6/rtc.py.exp b/tests/psoc6/rtc.py.exp index bc77ef5ff731..3399427070fe 100644 --- a/tests/psoc6/rtc.py.exp +++ b/tests/psoc6/rtc.py.exp @@ -5,7 +5,7 @@ RTC init successful: True datetime is accurate: True 1. Setting periodic short alarm to be triggered repeatedly in few ms in future -Alarm period set to (ms): 3000 +Alarm period set to (ms): 1000 Alarm expired : True Alarm set again... Alarm expired : True @@ -22,6 +22,8 @@ Entered Cback : True 4. Setting periodic alarm to be triggered at specified date-time should fail invalid argument(s) value +5.RTC constructor return singleton: True + RTC reset done: True datetime to be retrieved post soft-reset : (2023, 1, 1, 0, 0, 0, 0, 0) diff --git a/tests/psoc6/rtc_memory_write_check.py b/tests/psoc6/rtc_memory_write_check.py index b08d1dafb39f..7d937ab4d4a8 100644 --- a/tests/psoc6/rtc_memory_write_check.py +++ b/tests/psoc6/rtc_memory_write_check.py @@ -4,5 +4,5 @@ rtc = RTC() print( "\ndatetime retrieved post soft-reset is same as previously set : ", - rtc.memory() <= (2023, 1, 1, 0, 0, 2, 0, 0), + rtc.memory() >= (2023, 1, 1, 0, 0, 0, 0, 0), )