Skip to content
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

Rtc tests refactor #134

Merged
merged 1 commit into from
May 27, 2024
Merged
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
104 changes: 52 additions & 52 deletions ports/psoc6/machine_rtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
}
}

Expand All @@ -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, &current_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),
Expand All @@ -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, &current_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;
}
Expand Down Expand Up @@ -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) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But where is this initialized as NULL? Should be done in cases where there is no alarm or there is alarm but no callback associated.

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) {
Expand All @@ -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;
}
Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand All @@ -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) {
Expand All @@ -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
Expand All @@ -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) },
Expand All @@ -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);
}
11 changes: 5 additions & 6 deletions ports/psoc6/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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();
Expand Down
39 changes: 28 additions & 11 deletions tests/psoc6/rtc.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 ***")
Expand All @@ -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
Expand All @@ -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()
4 changes: 3 additions & 1 deletion tests/psoc6/rtc.py.exp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
2 changes: 1 addition & 1 deletion tests/psoc6/rtc_memory_write_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -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),
)
Loading