From dbdcb58d6413a907e5f4aed25eee85073ff7e575 Mon Sep 17 00:00:00 2001 From: Daniel Campora Date: Tue, 22 Sep 2015 23:20:29 +0200 Subject: [PATCH] cc3200: New irq API, affects all classes that provide the irq method. --- cc3200/application.mk | 2 +- cc3200/boards/cc3200_prefix.c | 26 +- cc3200/hal/prcm.c | 68 ++++- cc3200/hal/prcm.h | 1 + cc3200/misc/{mpcallback.c => mpirq.c} | 147 +++++------ cc3200/misc/{mpcallback.h => mpirq.h} | 46 ++-- cc3200/mods/modutime.c | 11 +- cc3200/mods/modwlan.c | 110 ++++---- cc3200/mods/modwlan.h | 30 +++ cc3200/mods/pybpin.c | 331 +++++++++++++----------- cc3200/mods/pybpin.h | 8 +- cc3200/mods/pybrtc.c | 352 ++++++++++++++++---------- cc3200/mods/pybrtc.h | 24 +- cc3200/mods/pybsd.c | 2 +- cc3200/mods/pybsleep.c | 157 ++++++------ cc3200/mods/pybsleep.h | 5 +- cc3200/mods/pybtimer.c | 260 +++++++++---------- cc3200/mods/pybuart.c | 162 ++++++------ cc3200/mods/pybuart.h | 1 - cc3200/mpconfigport.h | 2 +- cc3200/mptask.c | 9 +- cc3200/qstrdefsport.h | 13 +- cc3200/util/random.c | 12 +- tests/wipy/pin_irq.py | 116 +++++++++ tests/wipy/pin_irq.py.exp | 19 ++ tests/wipy/rtc.py | 21 +- tests/wipy/rtc.py.exp | 3 + tests/wipy/rtc_irq.py | 89 +++++++ tests/wipy/rtc_irq.py.exp | 18 ++ tests/wipy/uart_irq.py | 149 +++++++++++ tests/wipy/uart_irq.py.exp | 33 +++ 31 files changed, 1437 insertions(+), 790 deletions(-) rename cc3200/misc/{mpcallback.c => mpirq.c} (52%) rename cc3200/misc/{mpcallback.h => mpirq.h} (68%) create mode 100644 tests/wipy/pin_irq.py create mode 100644 tests/wipy/pin_irq.py.exp create mode 100644 tests/wipy/rtc_irq.py create mode 100644 tests/wipy/rtc_irq.py.exp create mode 100644 tests/wipy/uart_irq.py create mode 100644 tests/wipy/uart_irq.py.exp diff --git a/cc3200/application.mk b/cc3200/application.mk index 6663a6185..4d4e03da1 100644 --- a/cc3200/application.mk +++ b/cc3200/application.mk @@ -78,7 +78,7 @@ APP_MISC_SRC_C = $(addprefix misc/,\ antenna.c \ FreeRTOSHooks.c \ help.c \ - mpcallback.c \ + mpirq.c \ mperror.c \ mpexception.c \ mpsystick.c \ diff --git a/cc3200/boards/cc3200_prefix.c b/cc3200/boards/cc3200_prefix.c index 520ea2c5d..971285745 100644 --- a/cc3200/boards/cc3200_prefix.c +++ b/cc3200/boards/cc3200_prefix.c @@ -52,16 +52,18 @@ #define PIN(p_pin_name, p_port, p_bit, p_pin_num, p_af_list, p_num_afs) \ { \ { &pin_type }, \ - .name = MP_QSTR_ ## p_pin_name, \ - .port = PORT_A ## p_port, \ - .af_list = (p_af_list), \ - .pull = PIN_TYPE_STD, \ - .bit = (p_bit), \ - .pin_num = (p_pin_num), \ - .af = PIN_MODE_0, \ - .strength = PIN_STRENGTH_4MA, \ - .mode = GPIO_DIR_MODE_IN, \ - .num_afs = (p_num_afs), \ - .value = 0, \ - .used = false, \ + .name = MP_QSTR_ ## p_pin_name, \ + .port = PORT_A ## p_port, \ + .af_list = (p_af_list), \ + .pull = PIN_TYPE_STD, \ + .bit = (p_bit), \ + .pin_num = (p_pin_num), \ + .af = PIN_MODE_0, \ + .strength = PIN_STRENGTH_4MA, \ + .mode = GPIO_DIR_MODE_IN, \ + .num_afs = (p_num_afs), \ + .value = 0, \ + .used = false, \ + .irq_trigger = 0, \ + .irq_flags = 0, \ } diff --git a/cc3200/hal/prcm.c b/cc3200/hal/prcm.c index 773fc90fb..4b66c0ff1 100644 --- a/cc3200/hal/prcm.c +++ b/cc3200/hal/prcm.c @@ -112,17 +112,17 @@ // following wrapper can be used to convert the value from cycles to // millisecond: // -// CYCLES_U16MS(cycles) ((cycles *1000)/ 1024), +// CYCLES_U16MS(cycles) ((cycles * 1000) / 1024), // // Similarly, before setting the value, it must be first converted (from ms to // cycles). // -// U16MS_CYCLES(msec) ((msec *1024)/1000) +// U16MS_CYCLES(msec) ((msec * 1024) / 1000) // // Note: There is a precision loss of 1 ms with the above scheme. // // -#define SCC_U64MSEC_GET() (MAP_PRCMSlowClkCtrGet() >> 5) +#define SCC_U64MSEC_GET() (RTCFastDomainCounterGet() >> 5) #define SCC_U64MSEC_MATCH_SET(u64Msec) (MAP_PRCMSlowClkCtrMatchSet(u64Msec << 5)) #define SCC_U64MSEC_MATCH_GET() (MAP_PRCMSlowClkCtrMatchGet() >> 5) @@ -208,6 +208,39 @@ static void RTCU32SecRegWrite(unsigned long u32Msec) MAP_PRCMHIBRegWrite(RTC_SECS_U32_REG_ADDR, u32Msec); } +//***************************************************************************** +// Fast function to get the most accurate RTC counter value +//***************************************************************************** +static unsigned long long RTCFastDomainCounterGet (void) { + + #define BRK_IF_RTC_CTRS_ALIGN(c2, c1) if (c2 - c1 <= 1) { \ + itr++; \ + break; \ + } + + unsigned long long rtc_count1, rtc_count2, rtc_count3; + unsigned int itr; + + do { + rtc_count1 = PRCMSlowClkCtrFastGet(); + rtc_count2 = PRCMSlowClkCtrFastGet(); + rtc_count3 = PRCMSlowClkCtrFastGet(); + itr = 0; + + BRK_IF_RTC_CTRS_ALIGN(rtc_count2, rtc_count1); + BRK_IF_RTC_CTRS_ALIGN(rtc_count3, rtc_count2); + BRK_IF_RTC_CTRS_ALIGN(rtc_count3, rtc_count1); + + // Consistent values in two consecutive reads implies a correct + // value of the counter. Do note, the counter does not give the + // calendar time but a hardware that ticks upwards continuously. + // The 48-bit counter operates at 32,768 HZ. + + } while (true); + + return (1 == itr) ? rtc_count2 : rtc_count3; +} + //***************************************************************************** // Macros //***************************************************************************** @@ -1245,6 +1278,35 @@ unsigned long long PRCMSlowClkCtrGet(void) return ullRTCVal; } +//***************************************************************************** +// +//! Gets the current value of the internal slow clock counter +//! +//! This function is similar to \sa PRCMSlowClkCtrGet() but reads the counter +//! value from a relatively faster interface using an auto-latch mechainsm. +//! +//! \note Due to the nature of implemetation of auto latching, when using this +//! API, the recommendation is to read the value thrice and identify the right +//! value (as 2 out the 3 read values will always be correct and with a max. of +//! 1 LSB change) +//! +//! \return 64-bit current counter vlaue. +// +//***************************************************************************** +unsigned long long PRCMSlowClkCtrFastGet(void) +{ + unsigned long long ullRTCVal; + + // + // Read as 2 32-bit values + // + ullRTCVal = HWREG(HIB1P2_BASE + HIB1P2_O_HIB_RTC_TIMER_MSW_1P2); + ullRTCVal = ullRTCVal << 32; + ullRTCVal |= HWREG(HIB1P2_BASE + HIB1P2_O_HIB_RTC_TIMER_LSW_1P2); + + return ullRTCVal; + +} //***************************************************************************** // diff --git a/cc3200/hal/prcm.h b/cc3200/hal/prcm.h index 110d8326e..2f700ae2c 100644 --- a/cc3200/hal/prcm.h +++ b/cc3200/hal/prcm.h @@ -247,6 +247,7 @@ extern void PRCMHibernateWakeupSourceDisable(unsigned long ulHIBWakupSrc); extern void PRCMHibernateIntervalSet(unsigned long long ullTicks); extern unsigned long long PRCMSlowClkCtrGet(void); +extern unsigned long long PRCMSlowClkCtrFastGet(void); extern void PRCMSlowClkCtrMatchSet(unsigned long long ullTicks); extern unsigned long long PRCMSlowClkCtrMatchGet(void); diff --git a/cc3200/misc/mpcallback.c b/cc3200/misc/mpirq.c similarity index 52% rename from cc3200/misc/mpcallback.c rename to cc3200/misc/mpirq.c index 8e7a9f740..e780c78b6 100644 --- a/cc3200/misc/mpcallback.c +++ b/cc3200/misc/mpirq.c @@ -34,46 +34,51 @@ #include "inc/hw_types.h" #include "interrupt.h" #include "pybsleep.h" -#include "mpcallback.h" #include "mpexception.h" #include "mperror.h" +#include "mpirq.h" /****************************************************************************** - DEFINE PUBLIC DATA + DECLARE PUBLIC DATA ******************************************************************************/ -const mp_arg_t mpcallback_init_args[] = { - { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, +const mp_arg_t mp_irq_init_args[] = { + { MP_QSTR_trigger, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_priority, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, // the lowest priority { MP_QSTR_handler, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { MP_QSTR_priority, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, - { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { MP_QSTR_wake_from, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = PYB_PWR_MODE_ACTIVE} }, + { MP_QSTR_wake, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, }; +/****************************************************************************** + DECLARE PRIVATE DATA + ******************************************************************************/ +STATIC uint8_t mp_irq_priorities[] = { INT_PRIORITY_LVL_7, INT_PRIORITY_LVL_6, INT_PRIORITY_LVL_5, INT_PRIORITY_LVL_4, + INT_PRIORITY_LVL_3, INT_PRIORITY_LVL_2, INT_PRIORITY_LVL_1 }; + /****************************************************************************** DEFINE PUBLIC FUNCTIONS ******************************************************************************/ -void mpcallback_init0 (void) { +void mp_irq_init0 (void) { // initialize the callback objects list - mp_obj_list_init(&MP_STATE_PORT(mpcallback_obj_list), 0); + mp_obj_list_init(&MP_STATE_PORT(mp_irq_obj_list), 0); } -mp_obj_t mpcallback_new (mp_obj_t parent, mp_obj_t handler, const mp_cb_methods_t *methods, bool enable) { - mpcallback_obj_t *self = m_new_obj(mpcallback_obj_t); - self->base.type = &pyb_callback_type; +mp_obj_t mp_irq_new (mp_obj_t parent, mp_obj_t handler, const mp_irq_methods_t *methods) { + mp_irq_obj_t *self = m_new_obj(mp_irq_obj_t); + self->base.type = &mp_irq_type; self->handler = handler; self->parent = parent; - self->methods = (mp_cb_methods_t *)methods; - self->isenabled = enable; + self->methods = (mp_irq_methods_t *)methods; + self->isenabled = true; // remove it in case it was already registered - mpcallback_remove(parent); - mp_obj_list_append(&MP_STATE_PORT(mpcallback_obj_list), self); + mp_irq_remove(parent); + mp_obj_list_append(&MP_STATE_PORT(mp_irq_obj_list), self); return self; } -mpcallback_obj_t *mpcallback_find (mp_obj_t parent) { - for (mp_uint_t i = 0; i < MP_STATE_PORT(mpcallback_obj_list).len; i++) { - mpcallback_obj_t *callback_obj = ((mpcallback_obj_t *)(MP_STATE_PORT(mpcallback_obj_list).items[i])); +mp_irq_obj_t *mp_irq_find (mp_obj_t parent) { + for (mp_uint_t i = 0; i < MP_STATE_PORT(mp_irq_obj_list).len; i++) { + mp_irq_obj_t *callback_obj = ((mp_irq_obj_t *)(MP_STATE_PORT(mp_irq_obj_list).items[i])); if (callback_obj->parent == parent) { return callback_obj; } @@ -81,58 +86,40 @@ mpcallback_obj_t *mpcallback_find (mp_obj_t parent) { return NULL; } -void mpcallback_wake_all (void) { +void mp_irq_wake_all (void) { // re-enable all active callback objects one by one - for (mp_uint_t i = 0; i < MP_STATE_PORT(mpcallback_obj_list).len; i++) { - mpcallback_obj_t *callback_obj = ((mpcallback_obj_t *)(MP_STATE_PORT(mpcallback_obj_list).items[i])); + for (mp_uint_t i = 0; i < MP_STATE_PORT(mp_irq_obj_list).len; i++) { + mp_irq_obj_t *callback_obj = ((mp_irq_obj_t *)(MP_STATE_PORT(mp_irq_obj_list).items[i])); if (callback_obj->isenabled) { callback_obj->methods->enable(callback_obj->parent); } } } -void mpcallback_disable_all (void) { +void mp_irq_disable_all (void) { // re-enable all active callback objects one by one - for (mp_uint_t i = 0; i < MP_STATE_PORT(mpcallback_obj_list).len; i++) { - mpcallback_obj_t *callback_obj = ((mpcallback_obj_t *)(MP_STATE_PORT(mpcallback_obj_list).items[i])); + for (mp_uint_t i = 0; i < MP_STATE_PORT(mp_irq_obj_list).len; i++) { + mp_irq_obj_t *callback_obj = ((mp_irq_obj_t *)(MP_STATE_PORT(mp_irq_obj_list).items[i])); callback_obj->methods->disable(callback_obj->parent); } } -void mpcallback_remove (const mp_obj_t parent) { - mpcallback_obj_t *callback_obj; - if ((callback_obj = mpcallback_find(parent))) { - mp_obj_list_remove(&MP_STATE_PORT(mpcallback_obj_list), callback_obj); +void mp_irq_remove (const mp_obj_t parent) { + mp_irq_obj_t *callback_obj; + if ((callback_obj = mp_irq_find(parent))) { + mp_obj_list_remove(&MP_STATE_PORT(mp_irq_obj_list), callback_obj); } } -uint mpcallback_translate_priority (uint priority) { - if (priority < 1 || priority > 7) { +uint mp_irq_translate_priority (uint priority) { + if (priority < 1 || priority > MP_ARRAY_SIZE(mp_irq_priorities)) { nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); } - - switch (priority) { - case 1: - return INT_PRIORITY_LVL_7; - case 2: - return INT_PRIORITY_LVL_6; - case 3: - return INT_PRIORITY_LVL_5; - case 4: - return INT_PRIORITY_LVL_4; - case 5: - return INT_PRIORITY_LVL_3; - case 6: - return INT_PRIORITY_LVL_2; - case 7: - return INT_PRIORITY_LVL_1; - default: - return INT_PRIORITY_LVL_7; - } + return mp_irq_priorities[priority - 1]; } -void mpcallback_handler (mp_obj_t self_in) { - mpcallback_obj_t *self = self_in; +void mp_irq_handler (mp_obj_t self_in) { + mp_irq_obj_t *self = self_in; if (self && self->handler != mp_const_none) { // when executing code within a handler we must lock the GC to prevent // any memory allocations. @@ -159,59 +146,57 @@ void mpcallback_handler (mp_obj_t self_in) { /******************************************************************************/ // Micro Python bindings -/// \method init() -/// Initializes the interrupt callback. With no parameters passed, everything will default -/// to the values assigned to mpcallback_init_args[]. -STATIC mp_obj_t callback_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - mpcallback_obj_t *self = pos_args[0]; +STATIC mp_obj_t mp_irq_init (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + mp_irq_obj_t *self = pos_args[0]; // this is a bit of a hack, but it let us reuse the callback_create method from our parent ((mp_obj_t *)pos_args)[0] = self->parent; self->methods->init (n_args, pos_args, kw_args); return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_KW(callback_init_obj, 1, callback_init); +MP_DEFINE_CONST_FUN_OBJ_KW(mp_irq_init_obj, 1, mp_irq_init); -/// \method enable() -/// Enables the interrupt callback -STATIC mp_obj_t callback_enable (mp_obj_t self_in) { - mpcallback_obj_t *self = self_in; +STATIC mp_obj_t mp_irq_enable (mp_obj_t self_in) { + mp_irq_obj_t *self = self_in; self->methods->enable(self->parent); self->isenabled = true; return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(callback_enable_obj, callback_enable); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_irq_enable_obj, mp_irq_enable); -/// \method disable() -/// Disables the interrupt callback -STATIC mp_obj_t callback_disable (mp_obj_t self_in) { - mpcallback_obj_t *self = self_in; +STATIC mp_obj_t mp_irq_disable (mp_obj_t self_in) { + mp_irq_obj_t *self = self_in; self->methods->disable(self->parent); self->isenabled = false; return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(callback_disable_obj, callback_disable); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_irq_disable_obj, mp_irq_disable); -/// \method \call() -/// Triggers the interrupt callback -STATIC mp_obj_t callback_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { +STATIC mp_obj_t mp_irq_flags (mp_obj_t self_in) { + mp_irq_obj_t *self = self_in; + return mp_obj_new_int(self->methods->flags(self->parent)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_irq_flags_obj, mp_irq_flags); + +STATIC mp_obj_t mp_irq_call (mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 0, 0, false); - mpcallback_handler (self_in); + mp_irq_handler (self_in); return mp_const_none; } -STATIC const mp_map_elem_t callback_locals_dict_table[] = { +STATIC const mp_map_elem_t mp_irq_locals_dict_table[] = { // instance methods - { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&callback_init_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_enable), (mp_obj_t)&callback_enable_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_disable), (mp_obj_t)&callback_disable_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&mp_irq_init_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_enable), (mp_obj_t)&mp_irq_enable_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_disable), (mp_obj_t)&mp_irq_disable_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_flags), (mp_obj_t)&mp_irq_flags_obj }, }; -STATIC MP_DEFINE_CONST_DICT(callback_locals_dict, callback_locals_dict_table); +STATIC MP_DEFINE_CONST_DICT(mp_irq_locals_dict, mp_irq_locals_dict_table); -const mp_obj_type_t pyb_callback_type = { +const mp_obj_type_t mp_irq_type = { { &mp_type_type }, - .name = MP_QSTR_callback, - .call = callback_call, - .locals_dict = (mp_obj_t)&callback_locals_dict, + .name = MP_QSTR_irq, + .call = mp_irq_call, + .locals_dict = (mp_obj_t)&mp_irq_locals_dict, }; diff --git a/cc3200/misc/mpcallback.h b/cc3200/misc/mpirq.h similarity index 68% rename from cc3200/misc/mpcallback.h rename to cc3200/misc/mpirq.h index cc15a3ac6..3fd21ee09 100644 --- a/cc3200/misc/mpcallback.h +++ b/cc3200/misc/mpirq.h @@ -24,50 +24,52 @@ * THE SOFTWARE. */ -#ifndef MPCALLBACK_H_ -#define MPCALLBACK_H_ +#ifndef MPIRQ_H_ +#define MPIRQ_H_ /****************************************************************************** DEFINE CONSTANTS ******************************************************************************/ -#define mpcallback_INIT_NUM_ARGS 5 +#define mp_irq_INIT_NUM_ARGS 4 /****************************************************************************** DEFINE TYPES ******************************************************************************/ -typedef void (*mp_cb_method_t) (mp_obj_t self); -typedef mp_obj_t (*mp_cb_init_t) (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +typedef mp_obj_t (*mp_irq_init_t) (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +typedef void (*mp_irq_void_method_t) (mp_obj_t self); +typedef int (*mp_irq_int_method_t) (mp_obj_t self); typedef struct { - mp_cb_init_t init; - mp_cb_method_t enable; - mp_cb_method_t disable; -} mp_cb_methods_t; + mp_irq_init_t init; + mp_irq_void_method_t enable; + mp_irq_void_method_t disable; + mp_irq_int_method_t flags; +} mp_irq_methods_t; typedef struct { mp_obj_base_t base; mp_obj_t parent; mp_obj_t handler; - mp_cb_methods_t *methods; + mp_irq_methods_t *methods; bool isenabled; -} mpcallback_obj_t; +} mp_irq_obj_t; /****************************************************************************** DECLARE EXPORTED DATA ******************************************************************************/ -extern const mp_arg_t mpcallback_init_args[]; -extern const mp_obj_type_t pyb_callback_type; +extern const mp_arg_t mp_irq_init_args[]; +extern const mp_obj_type_t mp_irq_type; /****************************************************************************** DECLARE PUBLIC FUNCTIONS ******************************************************************************/ -void mpcallback_init0 (void); -mp_obj_t mpcallback_new (mp_obj_t parent, mp_obj_t handler, const mp_cb_methods_t *methods, bool enable); -mpcallback_obj_t *mpcallback_find (mp_obj_t parent); -void mpcallback_wake_all (void); -void mpcallback_disable_all (void); -void mpcallback_remove (const mp_obj_t parent); -void mpcallback_handler (mp_obj_t self_in); -uint mpcallback_translate_priority (uint priority); +void mp_irq_init0 (void); +mp_obj_t mp_irq_new (mp_obj_t parent, mp_obj_t handler, const mp_irq_methods_t *methods); +mp_irq_obj_t *mp_irq_find (mp_obj_t parent); +void mp_irq_wake_all (void); +void mp_irq_disable_all (void); +void mp_irq_remove (const mp_obj_t parent); +void mp_irq_handler (mp_obj_t self_in); +uint mp_irq_translate_priority (uint priority); -#endif /* MPCALLBACK_H_ */ +#endif /* MPIRQ_H_ */ diff --git a/cc3200/mods/modutime.c b/cc3200/mods/modutime.c index 189956599..05e7b5dca 100644 --- a/cc3200/mods/modutime.c +++ b/cc3200/mods/modutime.c @@ -56,7 +56,7 @@ /// Convert a time expressed in seconds since Jan 1, 2000 into an 8-tuple which /// contains: (year, month, mday, hour, minute, second, weekday, yearday) /// If secs is not provided or None, then the current time from the RTC is used. -/// year includes the century (for example 2014) +/// year includes the century (for example 2015) /// month is 1-12 /// mday is 1-31 /// hour is 0-23 @@ -67,14 +67,9 @@ STATIC mp_obj_t time_localtime(mp_uint_t n_args, const mp_obj_t *args) { if (n_args == 0 || args[0] == mp_const_none) { timeutils_struct_time_t tm; - uint32_t seconds; - uint16_t mseconds; - - // get the seconds and the milliseconds from the RTC - MAP_PRCMRTCGet(&seconds, &mseconds); - mseconds = RTC_CYCLES_U16MS(mseconds); - timeutils_seconds_since_2000_to_struct_time(seconds, &tm); + // get the seconds from the RTC + timeutils_seconds_since_2000_to_struct_time(pyb_rtc_get_seconds(), &tm); mp_obj_t tuple[8] = { mp_obj_new_int(tm.tm_year), mp_obj_new_int(tm.tm_mon), diff --git a/cc3200/mods/modwlan.c b/cc3200/mods/modwlan.c index 1c3e63710..b7ff7b594 100644 --- a/cc3200/mods/modwlan.c +++ b/cc3200/mods/modwlan.c @@ -51,7 +51,7 @@ #include "serverstask.h" #endif #include "mpexception.h" -#include "mpcallback.h" +#include "mpirq.h" #include "pybsleep.h" #include "antenna.h" @@ -88,31 +88,6 @@ typedef enum{ // the ping operation } e_StatusBits; -typedef struct _wlan_obj_t { - mp_obj_base_t base; - uint32_t status; - - uint32_t ip; - - int8_t mode; - uint8_t security; - uint8_t channel; - uint8_t antenna; - - // my own ssid, key and mac - uint8_t ssid[33]; - uint8_t key[65]; - uint8_t mac[SL_MAC_ADDR_LEN]; - - // the sssid (or name) and mac of the other device - uint8_t ssid_o[33]; - uint8_t bssid[6]; - -#if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP) - bool servers_enabled; -#endif -} wlan_obj_t; - /****************************************************************************** DEFINE CONSTANTS ******************************************************************************/ @@ -181,7 +156,7 @@ STATIC wlan_obj_t wlan_obj = { #endif }; -STATIC const mp_cb_methods_t wlan_cb_methods; +STATIC const mp_irq_methods_t wlan_irq_methods; /****************************************************************************** DECLARE PUBLIC DATA @@ -199,8 +174,8 @@ STATIC void wlan_get_sl_mac (void); STATIC void wlan_wep_key_unhexlify(const char *key, char *key_out); STATIC modwlan_Status_t wlan_do_connect (const char* ssid, uint32_t ssid_len, const char* bssid, uint8_t sec, const char* key, uint32_t key_len, uint32_t timeout); -STATIC void wlan_lpds_callback_enable (mp_obj_t self_in); -STATIC void wlan_lpds_callback_disable (mp_obj_t self_in); +STATIC void wlan_lpds_irq_enable (mp_obj_t self_in); +STATIC void wlan_lpds_irq_disable (mp_obj_t self_in); STATIC bool wlan_scan_result_is_unique (const mp_obj_list_t *nets, _u8 *bssid); //***************************************************************************** @@ -793,13 +768,19 @@ arg_error: } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wlan_iwconfig_obj, 1, wlan_iwconfig); -STATIC void wlan_lpds_callback_enable (mp_obj_t self_in) { - mp_obj_t _callback = mpcallback_find(self_in); - pybsleep_set_wlan_lpds_callback (_callback); +STATIC void wlan_lpds_irq_enable (mp_obj_t self_in) { + wlan_obj_t *self = self_in; + self->irq_enabled = true; } -STATIC void wlan_lpds_callback_disable (mp_obj_t self_in) { - pybsleep_set_wlan_lpds_callback (NULL); +STATIC void wlan_lpds_irq_disable (mp_obj_t self_in) { + wlan_obj_t *self = self_in; + self->irq_enabled = false; +} + +STATIC int wlan_irq_flags (mp_obj_t self_in) { + wlan_obj_t *self = self_in; + return self->irq_flags; } STATIC bool wlan_scan_result_is_unique (const mp_obj_list_t *nets, _u8 *bssid) { @@ -829,6 +810,7 @@ STATIC mp_obj_t wlan_make_new (mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_k mp_map_init_fixed_table(&kw_args, n_kw, args); wlan_iwconfig(n_args + 1, (const mp_obj_t *)&wlan_obj, &kw_args); } + pybsleep_set_wlan_obj(&wlan_obj); return &wlan_obj; } @@ -1086,34 +1068,34 @@ STATIC mp_obj_t wlan_scan(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(wlan_scan_obj, wlan_scan); -/// \method callback(handler, pwrmode) -/// Create a callback object associated with the WLAN subsystem -/// Only takes one argument (wake_from) -STATIC mp_obj_t wlan_callback (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - mp_arg_val_t args[mpcallback_INIT_NUM_ARGS]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mpcallback_INIT_NUM_ARGS, mpcallback_init_args, args); +/// \method irq(trigger, priority, handler, wake) +STATIC mp_obj_t wlan_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + mp_arg_val_t args[mp_irq_INIT_NUM_ARGS]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mp_irq_INIT_NUM_ARGS, mp_irq_init_args, args); wlan_obj_t *self = pos_args[0]; - mp_obj_t _callback = mpcallback_find(self); - // check if any parameters were passed - if (kw_args->used > 0) { - // check the power mode - if (args[4].u_int != PYB_PWR_MODE_LPDS) { - // throw an exception since WLAN only supports LPDS mode - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); - } - // create the callback - _callback = mpcallback_new (self, args[1].u_obj, &wlan_cb_methods, true); - - // enable network wakeup - pybsleep_set_wlan_lpds_callback (_callback); - } else if (!_callback) { - _callback = mpcallback_new (self, mp_const_none, &wlan_cb_methods, false); + // check the trigger, only one type is supported + if (mp_obj_get_int(args[0].u_obj) != MODWLAN_WIFI_EVENT_ANY) { + goto invalid_args; } - return _callback; + + // check the power mode + if (mp_obj_get_int(args[3].u_obj) != PYB_PWR_MODE_LPDS) { + goto invalid_args; + } + + // create the callback + mp_obj_t _irq = mp_irq_new (self, args[2].u_obj, &wlan_irq_methods); + self->irq_obj = _irq; + + return _irq; + +invalid_args: + // throw an exception since WLAN only supports LPDS mode + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); } -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wlan_callback_obj, 1, wlan_callback); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wlan_irq_obj, 1, wlan_irq); /// \method mac() /// returns the MAC address @@ -1150,7 +1132,7 @@ STATIC const mp_map_elem_t wlan_locals_dict_table[] = { #if MICROPY_PORT_WLAN_URN { MP_OBJ_NEW_QSTR(MP_QSTR_urn), (mp_obj_t)&wlan_urn_obj }, #endif - { MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&wlan_callback_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_irq), (mp_obj_t)&wlan_irq_obj }, // class constants { MP_OBJ_NEW_QSTR(MP_QSTR_STA), MP_OBJ_NEW_SMALL_INT(ROLE_STA) }, @@ -1161,6 +1143,7 @@ STATIC const mp_map_elem_t wlan_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_WPA2), MP_OBJ_NEW_SMALL_INT(SL_SEC_TYPE_WPA_WPA2) }, { MP_OBJ_NEW_QSTR(MP_QSTR_INTERNAL), MP_OBJ_NEW_SMALL_INT(ANTENNA_TYPE_INTERNAL) }, { MP_OBJ_NEW_QSTR(MP_QSTR_EXTERNAL), MP_OBJ_NEW_SMALL_INT(ANTENNA_TYPE_EXTERNAL) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ANY_EVENT), MP_OBJ_NEW_SMALL_INT(MODWLAN_WIFI_EVENT_ANY) }, }; STATIC MP_DEFINE_CONST_DICT(wlan_locals_dict, wlan_locals_dict_table); @@ -1173,10 +1156,11 @@ const mod_network_nic_type_t mod_network_nic_type_wlan = { }, }; -STATIC const mp_cb_methods_t wlan_cb_methods = { - .init = wlan_callback, - .enable = wlan_lpds_callback_enable, - .disable = wlan_lpds_callback_disable, +STATIC const mp_irq_methods_t wlan_irq_methods = { + .init = wlan_irq, + .enable = wlan_lpds_irq_enable, + .disable = wlan_lpds_irq_disable, + .flags = wlan_irq_flags, }; /******************************************************************************/ @@ -1373,7 +1357,7 @@ int wlan_socket_ioctl (mod_network_socket_obj_t *s, mp_uint_t request, mp_uint_t tv.tv_usec = 1; int32_t nfds = sl_Select(sd + 1, &rfds, &wfds, &xfds, &tv); - // check for error + // check for errors if (nfds == -1) { *_errno = nfds; return -1; diff --git a/cc3200/mods/modwlan.h b/cc3200/mods/modwlan.h index 6693209d7..1386d2d19 100644 --- a/cc3200/mods/modwlan.h +++ b/cc3200/mods/modwlan.h @@ -35,6 +35,8 @@ #define SL_STOP_TIMEOUT 35 #define SL_STOP_TIMEOUT_LONG 575 +#define MODWLAN_WIFI_EVENT_ANY 0x01 + /****************************************************************************** DEFINE TYPES ******************************************************************************/ @@ -45,6 +47,34 @@ typedef enum { MODWLAN_ERROR_UNKNOWN = -3, } modwlan_Status_t; +typedef struct _wlan_obj_t { + mp_obj_base_t base; + mp_obj_t irq_obj; + uint32_t status; + + uint32_t ip; + + int8_t mode; + uint8_t security; + uint8_t channel; + uint8_t antenna; + + // my own ssid, key and mac + uint8_t ssid[33]; + uint8_t key[65]; + uint8_t mac[SL_MAC_ADDR_LEN]; + + // the sssid (or name) and mac of the other device + uint8_t ssid_o[33]; + uint8_t bssid[6]; + uint8_t irq_flags; + bool irq_enabled; + +#if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP) + bool servers_enabled; +#endif +} wlan_obj_t; + /****************************************************************************** DECLARE PUBLIC DATA ******************************************************************************/ diff --git a/cc3200/mods/pybpin.c b/cc3200/mods/pybpin.c index 82143128e..02b5fbfd3 100644 --- a/cc3200/mods/pybpin.c +++ b/cc3200/mods/pybpin.c @@ -45,9 +45,9 @@ #include "gpio.h" #include "interrupt.h" #include "pybpin.h" +#include "mpirq.h" #include "pins.h" #include "pybsleep.h" -#include "mpcallback.h" #include "mpexception.h" #include "mperror.h" @@ -66,8 +66,8 @@ STATIC void pin_free_af_from_pins (uint8_t fn, uint8_t unit, uint8_t type); STATIC void pin_deassign (pin_obj_t* pin); STATIC void pin_obj_configure (const pin_obj_t *self); STATIC void pin_get_hibernate_pin_and_idx (const pin_obj_t *self, uint *wake_pin, uint *idx); -STATIC void pin_extint_enable (mp_obj_t self_in); -STATIC void pin_extint_disable (mp_obj_t self_in); +STATIC void pin_irq_enable (mp_obj_t self_in); +STATIC void pin_irq_disable (mp_obj_t self_in); STATIC void pin_extint_register(pin_obj_t *self, uint32_t intmode, uint32_t priority); STATIC void pin_validate_mode (uint mode); STATIC void pin_validate_pull (uint pull); @@ -88,6 +88,11 @@ DEFINE CONSTANTS #define GPIO_DIR_MODE_ALT 0x00000002 // Pin is NOT controlled by the PGIO module #define GPIO_DIR_MODE_ALT_OD 0x00000003 // Pin is NOT controlled by the PGIO module and is in open drain mode +#define PYB_PIN_FALLING_EDGE 0x01 +#define PYB_PIN_RISING_EDGE 0x02 +#define PYB_PIN_LOW_LEVEL 0x04 +#define PYB_PIN_HIGH_LEVEL 0x08 + /****************************************************************************** DEFINE TYPES ******************************************************************************/ @@ -100,7 +105,7 @@ typedef struct { /****************************************************************************** DECLARE PRIVATE DATA ******************************************************************************/ -STATIC const mp_cb_methods_t pin_cb_methods; +STATIC const mp_irq_methods_t pin_irq_methods; STATIC pybpin_wake_pin_t pybpin_wake_pin[PYBPIN_NUM_WAKE_PINS] = { {.active = false, .lpds = PYBPIN_WAKES_NOT, .hib = PYBPIN_WAKES_NOT}, {.active = false, .lpds = PYBPIN_WAKES_NOT, .hib = PYBPIN_WAKES_NOT}, @@ -334,7 +339,7 @@ STATIC void pin_get_hibernate_pin_and_idx (const pin_obj_t *self, uint *hib_pin, } } -STATIC void pin_extint_enable (mp_obj_t self_in) { +STATIC void pin_irq_enable (mp_obj_t self_in) { const pin_obj_t *self = self_in; uint hib_pin, idx; @@ -366,7 +371,7 @@ STATIC void pin_extint_enable (mp_obj_t self_in) { } } -STATIC void pin_extint_disable (mp_obj_t self_in) { +STATIC void pin_irq_disable (mp_obj_t self_in) { const pin_obj_t *self = self_in; uint hib_pin, idx; @@ -385,6 +390,11 @@ STATIC void pin_extint_disable (mp_obj_t self_in) { MAP_GPIOIntDisable(self->port, self->bit); } +STATIC int pin_irq_flags (mp_obj_t self_in) { + const pin_obj_t *self = self_in; + return self->irq_flags; +} + STATIC void pin_extint_register(pin_obj_t *self, uint32_t intmode, uint32_t priority) { void *handler; uint32_t intnum; @@ -467,14 +477,22 @@ STATIC void EXTI_Handler(uint port) { uint32_t bits = MAP_GPIOIntStatus(port, true); MAP_GPIOIntClear(port, bits); - // might be that we have more than one Pin interrupt pending + // might be that we have more than one pin interrupt pending // therefore we must loop through all of the 8 possible bits for (int i = 0; i < 8; i++) { uint32_t bit = (1 << i); if (bit & bits) { pin_obj_t *self = (pin_obj_t *)pin_find_pin_by_port_bit(&pin_board_pins_locals_dict, port, bit); - mp_obj_t _callback = mpcallback_find(self); - mpcallback_handler(_callback); + if (self->irq_trigger == (PYB_PIN_FALLING_EDGE | PYB_PIN_RISING_EDGE)) { + // read the pin value (hoping that the pin level has remained stable) + self->irq_flags = MAP_GPIOPinRead(self->port, self->bit) ? PYB_PIN_RISING_EDGE : PYB_PIN_FALLING_EDGE; + } else { + // same as the triggers + self->irq_flags = self->irq_trigger; + } + mp_irq_handler(mp_irq_find(self)); + // always clear the flags after leaving the user handler + self->irq_flags = 0; } } } @@ -484,7 +502,7 @@ STATIC void EXTI_Handler(uint port) { // Micro Python bindings STATIC const mp_arg_t pin_init_args[] = { - { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_mode, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_pull, MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_drive, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = PIN_STRENGTH_4MA} }, @@ -498,8 +516,14 @@ STATIC mp_obj_t pin_obj_init_helper(pin_obj_t *self, mp_uint_t n_args, const mp_ mp_arg_parse_all(n_args, pos_args, kw_args, pin_INIT_NUM_ARGS, pin_init_args, args); // get the io mode - uint mode = args[0].u_int; - pin_validate_mode(mode); + uint mode; + // default is input + if (args[0].u_obj == MP_OBJ_NULL) { + mode = GPIO_DIR_MODE_IN; + } else { + mode = mp_obj_get_int(args[0].u_obj); + pin_validate_mode (mode); + } // get the pull type uint pull; @@ -609,12 +633,9 @@ STATIC mp_obj_t pin_make_new(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, // Run an argument through the mapper and return the result. pin_obj_t *pin = (pin_obj_t *)pin_find(args[0]); - if (n_args > 1 || n_kw > 0) { - // pin af given, so configure it - mp_map_t kw_args; - mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); - pin_obj_init_helper(pin, n_args - 1, args + 1, &kw_args); - } + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + pin_obj_init_helper(pin, n_args - 1, args + 1, &kw_args); return (mp_obj_t)pin; } @@ -726,136 +747,147 @@ STATIC mp_obj_t pin_alt_list(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_alt_list_obj, pin_alt_list); -STATIC mp_obj_t pin_callback (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - mp_arg_val_t args[mpcallback_INIT_NUM_ARGS]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mpcallback_INIT_NUM_ARGS, mpcallback_init_args, args); - +/// \method irq(trigger, priority, handler, wake) +STATIC mp_obj_t pin_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + mp_arg_val_t args[mp_irq_INIT_NUM_ARGS]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mp_irq_INIT_NUM_ARGS, mp_irq_init_args, args); pin_obj_t *self = pos_args[0]; - // check if any parameters were passed - mp_obj_t _callback = mpcallback_find(self); - if (kw_args->used > 0) { - // convert the priority to the correct value - uint priority = mpcallback_translate_priority (args[2].u_int); - // verify the interrupt mode - uint intmode = args[0].u_int; - if (intmode == (GPIO_FALLING_EDGE | GPIO_RISING_EDGE)) { - intmode = GPIO_BOTH_EDGES; - } - else if (intmode != GPIO_FALLING_EDGE && intmode != GPIO_RISING_EDGE && - intmode != GPIO_LOW_LEVEL && intmode != GPIO_HIGH_LEVEL) { + + // convert the priority to the correct value + uint priority = mp_irq_translate_priority (args[1].u_int); + + // verify and translate the interrupt mode + uint mp_trigger = mp_obj_get_int(args[0].u_obj); + uint trigger; + if (mp_trigger == (PYB_PIN_FALLING_EDGE | PYB_PIN_RISING_EDGE)) { + trigger = GPIO_BOTH_EDGES; + } else { + switch (mp_trigger) { + case PYB_PIN_FALLING_EDGE: + trigger = GPIO_FALLING_EDGE; + break; + case PYB_PIN_RISING_EDGE: + trigger = GPIO_RISING_EDGE; + break; + case PYB_PIN_LOW_LEVEL: + trigger = GPIO_LOW_LEVEL; + break; + case PYB_PIN_HIGH_LEVEL: + trigger = GPIO_HIGH_LEVEL; + break; + default: goto invalid_args; } - - uint pwrmode = args[4].u_int; - if (pwrmode > (PYB_PWR_MODE_ACTIVE | PYB_PWR_MODE_LPDS | PYB_PWR_MODE_HIBERNATE)) { - goto invalid_args; - } - - // get the wake info from this pin - uint hib_pin, idx; - pin_get_hibernate_pin_and_idx ((const pin_obj_t *)self, &hib_pin, &idx); - if (pwrmode & PYB_PWR_MODE_LPDS) { - if (idx >= PYBPIN_NUM_WAKE_PINS) { - goto invalid_args; - } - // wake modes are different in LDPS - uint wake_mode; - switch (intmode) { - case GPIO_FALLING_EDGE: - wake_mode = PRCM_LPDS_FALL_EDGE; - break; - case GPIO_RISING_EDGE: - wake_mode = PRCM_LPDS_RISE_EDGE; - break; - case GPIO_LOW_LEVEL: - wake_mode = PRCM_LPDS_LOW_LEVEL; - break; - case GPIO_HIGH_LEVEL: - wake_mode = PRCM_LPDS_HIGH_LEVEL; - break; - default: - goto invalid_args; - break; - } - - // first clear the lpds value from all wake-able pins - for (uint i = 0; i < PYBPIN_NUM_WAKE_PINS; i++) { - pybpin_wake_pin[i].lpds = PYBPIN_WAKES_NOT; - } - - // enable this pin as a wake-up source during LPDS - pybpin_wake_pin[idx].lpds = wake_mode; - } - else { - // this pin was the previous LPDS wake source, so disable it completely - if (pybpin_wake_pin[idx].lpds != PYBPIN_WAKES_NOT) { - MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_GPIO); - } - pybpin_wake_pin[idx].lpds = PYBPIN_WAKES_NOT; - } - - if (pwrmode & PYB_PWR_MODE_HIBERNATE) { - if (idx >= PYBPIN_NUM_WAKE_PINS) { - goto invalid_args; - } - // wake modes are different in hibernate - uint wake_mode; - switch (intmode) { - case GPIO_FALLING_EDGE: - wake_mode = PRCM_HIB_FALL_EDGE; - break; - case GPIO_RISING_EDGE: - wake_mode = PRCM_HIB_RISE_EDGE; - break; - case GPIO_LOW_LEVEL: - wake_mode = PRCM_HIB_LOW_LEVEL; - break; - case GPIO_HIGH_LEVEL: - wake_mode = PRCM_HIB_HIGH_LEVEL; - break; - default: - goto invalid_args; - break; - } - - // enable this pin as wake-up source during hibernate - pybpin_wake_pin[idx].hib = wake_mode; - } - else { - pybpin_wake_pin[idx].hib = PYBPIN_WAKES_NOT; - } - - // we need to update the callback atomically, so we disable the - // interrupt before we update anything. - pin_extint_disable(self); - if (pwrmode & PYB_PWR_MODE_ACTIVE) { - // register the interrupt - pin_extint_register((pin_obj_t *)self, intmode, priority); - if (idx < PYBPIN_NUM_WAKE_PINS) { - pybpin_wake_pin[idx].active = true; - } - } - else if (idx < PYBPIN_NUM_WAKE_PINS) { - pybpin_wake_pin[idx].active = false; - } - - // all checks have passed, now we can create the callback - _callback = mpcallback_new (self, args[1].u_obj, &pin_cb_methods, true); - if (pwrmode & PYB_PWR_MODE_LPDS) { - pybsleep_set_gpio_lpds_callback (_callback); - } - - // enable the interrupt just before leaving - pin_extint_enable(self); - } else if (!_callback) { - _callback = mpcallback_new (self, mp_const_none, &pin_cb_methods, false); } - return _callback; + + uint8_t pwrmode = (args[3].u_obj == mp_const_none) ? PYB_PWR_MODE_ACTIVE : mp_obj_get_int(args[3].u_obj); + if (pwrmode > (PYB_PWR_MODE_ACTIVE | PYB_PWR_MODE_LPDS | PYB_PWR_MODE_HIBERNATE)) { + goto invalid_args; + } + + // get the wake info from this pin + uint hib_pin, idx; + pin_get_hibernate_pin_and_idx ((const pin_obj_t *)self, &hib_pin, &idx); + if (pwrmode & PYB_PWR_MODE_LPDS) { + if (idx >= PYBPIN_NUM_WAKE_PINS) { + goto invalid_args; + } + // wake modes are different in LDPS + uint wake_mode; + switch (trigger) { + case GPIO_FALLING_EDGE: + wake_mode = PRCM_LPDS_FALL_EDGE; + break; + case GPIO_RISING_EDGE: + wake_mode = PRCM_LPDS_RISE_EDGE; + break; + case GPIO_LOW_LEVEL: + wake_mode = PRCM_LPDS_LOW_LEVEL; + break; + case GPIO_HIGH_LEVEL: + wake_mode = PRCM_LPDS_HIGH_LEVEL; + break; + default: + goto invalid_args; + break; + } + + // first clear the lpds value from all wake-able pins + for (uint i = 0; i < PYBPIN_NUM_WAKE_PINS; i++) { + pybpin_wake_pin[i].lpds = PYBPIN_WAKES_NOT; + } + + // enable this pin as a wake-up source during LPDS + pybpin_wake_pin[idx].lpds = wake_mode; + } else if (idx < PYBPIN_NUM_WAKE_PINS) { + // this pin was the previous LPDS wake source, so disable it completely + if (pybpin_wake_pin[idx].lpds != PYBPIN_WAKES_NOT) { + MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_GPIO); + } + pybpin_wake_pin[idx].lpds = PYBPIN_WAKES_NOT; + } + + if (pwrmode & PYB_PWR_MODE_HIBERNATE) { + if (idx >= PYBPIN_NUM_WAKE_PINS) { + goto invalid_args; + } + // wake modes are different in hibernate + uint wake_mode; + switch (trigger) { + case GPIO_FALLING_EDGE: + wake_mode = PRCM_HIB_FALL_EDGE; + break; + case GPIO_RISING_EDGE: + wake_mode = PRCM_HIB_RISE_EDGE; + break; + case GPIO_LOW_LEVEL: + wake_mode = PRCM_HIB_LOW_LEVEL; + break; + case GPIO_HIGH_LEVEL: + wake_mode = PRCM_HIB_HIGH_LEVEL; + break; + default: + goto invalid_args; + break; + } + + // enable this pin as wake-up source during hibernate + pybpin_wake_pin[idx].hib = wake_mode; + } else if (idx < PYBPIN_NUM_WAKE_PINS) { + pybpin_wake_pin[idx].hib = PYBPIN_WAKES_NOT; + } + + // we need to update the callback atomically, so we disable the + // interrupt before we update anything. + pin_irq_disable(self); + if (pwrmode & PYB_PWR_MODE_ACTIVE) { + // register the interrupt + pin_extint_register((pin_obj_t *)self, trigger, priority); + if (idx < PYBPIN_NUM_WAKE_PINS) { + pybpin_wake_pin[idx].active = true; + } + } else if (idx < PYBPIN_NUM_WAKE_PINS) { + pybpin_wake_pin[idx].active = false; + } + + // all checks have passed, we can create the irq object + mp_obj_t _irq = mp_irq_new (self, args[2].u_obj, &pin_irq_methods); + if (pwrmode & PYB_PWR_MODE_LPDS) { + pybsleep_set_gpio_lpds_callback (_irq); + } + + // save the mp_trigge for later + self->irq_trigger = mp_trigger; + + // enable the interrupt just before leaving + pin_irq_enable(self); + + return _irq; invalid_args: nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); } -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pin_callback_obj, 1, pin_callback); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pin_irq_obj, 1, pin_irq); STATIC const mp_map_elem_t pin_locals_dict_table[] = { // instance methods @@ -867,7 +899,7 @@ STATIC const mp_map_elem_t pin_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_pull), (mp_obj_t)&pin_pull_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_drive), (mp_obj_t)&pin_drive_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_alt_list), (mp_obj_t)&pin_alt_list_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&pin_callback_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_irq), (mp_obj_t)&pin_irq_obj }, // class attributes { MP_OBJ_NEW_QSTR(MP_QSTR_board), (mp_obj_t)&pin_board_pins_obj_type }, @@ -883,10 +915,10 @@ STATIC const mp_map_elem_t pin_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_LOW_POWER), MP_OBJ_NEW_SMALL_INT(PIN_STRENGTH_2MA) }, { MP_OBJ_NEW_QSTR(MP_QSTR_MED_POWER), MP_OBJ_NEW_SMALL_INT(PIN_STRENGTH_4MA) }, { MP_OBJ_NEW_QSTR(MP_QSTR_HIGH_POWER), MP_OBJ_NEW_SMALL_INT(PIN_STRENGTH_6MA) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_FALLING), MP_OBJ_NEW_SMALL_INT(GPIO_FALLING_EDGE) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_RISING), MP_OBJ_NEW_SMALL_INT(GPIO_RISING_EDGE) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_LOW_LEVEL), MP_OBJ_NEW_SMALL_INT(GPIO_LOW_LEVEL) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_HIGH_LEVEL), MP_OBJ_NEW_SMALL_INT(GPIO_HIGH_LEVEL) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_FALLING), MP_OBJ_NEW_SMALL_INT(PYB_PIN_FALLING_EDGE) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_RISING), MP_OBJ_NEW_SMALL_INT(PYB_PIN_RISING_EDGE) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_LOW_LEVEL), MP_OBJ_NEW_SMALL_INT(PYB_PIN_LOW_LEVEL) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_HIGH_LEVEL), MP_OBJ_NEW_SMALL_INT(PYB_PIN_HIGH_LEVEL) }, }; STATIC MP_DEFINE_CONST_DICT(pin_locals_dict, pin_locals_dict_table); @@ -900,10 +932,11 @@ const mp_obj_type_t pin_type = { .locals_dict = (mp_obj_t)&pin_locals_dict, }; -STATIC const mp_cb_methods_t pin_cb_methods = { - .init = pin_callback, - .enable = pin_extint_enable, - .disable = pin_extint_disable, +STATIC const mp_irq_methods_t pin_irq_methods = { + .init = pin_irq, + .enable = pin_irq_enable, + .disable = pin_irq_disable, + .flags = pin_irq_flags, }; STATIC void pin_named_pins_obj_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { diff --git a/cc3200/mods/pybpin.h b/cc3200/mods/pybpin.h index 72a90874c..3e7784926 100644 --- a/cc3200/mods/pybpin.h +++ b/cc3200/mods/pybpin.h @@ -110,9 +110,11 @@ typedef struct { int8_t af; uint8_t strength; uint8_t mode; // this is now a combination of type and mode - uint8_t num_afs: 6; // up to 63 AFs - uint8_t value : 1; - uint8_t used : 1; + const uint8_t num_afs; // 255 AFs + uint8_t value; + uint8_t used; + uint8_t irq_trigger; + uint8_t irq_flags; } pin_obj_t; extern const mp_obj_type_t pin_type; diff --git a/cc3200/mods/pybrtc.c b/cc3200/mods/pybrtc.c index cc2e26f3a..6eb9b7651 100644 --- a/cc3200/mods/pybrtc.c +++ b/cc3200/mods/pybrtc.c @@ -37,8 +37,8 @@ #include "rom_map.h" #include "prcm.h" #include "pybrtc.h" +#include "mpirq.h" #include "pybsleep.h" -#include "mpcallback.h" #include "timeutils.h" #include "simplelink.h" #include "modnetwork.h" @@ -48,88 +48,148 @@ /// \moduleref pyb /// \class RTC - real time clock -/****************************************************************************** - DEFINE TYPES - ******************************************************************************/ -typedef struct _pyb_rtc_obj_t { - mp_obj_base_t base; - byte prwmode; - bool alarmset; - bool repeat; -} pyb_rtc_obj_t; - /****************************************************************************** DECLARE PRIVATE DATA ******************************************************************************/ -STATIC const mp_cb_methods_t pybrtc_cb_methods; -STATIC pyb_rtc_obj_t pyb_rtc_obj = {.prwmode = 0, .alarmset = false, .repeat = false}; +STATIC const mp_irq_methods_t pyb_rtc_irq_methods; +STATIC pyb_rtc_obj_t pyb_rtc_obj; + +/****************************************************************************** + FUNCTION-LIKE MACROS + ******************************************************************************/ +#define RTC_U16MS_CYCLES(msec) ((msec * 1024) / 1000) +#define RTC_CYCLES_U16MS(cycles) ((cycles * 1000) / 1024) /****************************************************************************** DECLARE PRIVATE FUNCTIONS ******************************************************************************/ -STATIC uint32_t pyb_rtc_reset (mp_obj_t self_in); -STATIC void pyb_rtc_callback_enable (mp_obj_t self_in); -STATIC void pyb_rtc_callback_disable (mp_obj_t self_in); +STATIC void pyb_rtc_set_time (uint32_t secs, uint16_t msecs); +STATIC uint32_t pyb_rtc_reset (void); +STATIC void pyb_rtc_disable_interupt (void); +STATIC void pyb_rtc_irq_enable (mp_obj_t self_in); +STATIC void pyb_rtc_irq_disable (mp_obj_t self_in); +STATIC int pyb_rtc_irq_flags (mp_obj_t self_in); +STATIC uint pyb_rtc_datetime_s_us(const mp_obj_t datetime, uint32_t *seconds); STATIC mp_obj_t pyb_rtc_datetime(mp_obj_t self, const mp_obj_t datetime); +STATIC void pyb_rtc_set_alarm (pyb_rtc_obj_t *self, uint32_t seconds, uint16_t mseconds); +STATIC void rtc_msec_add(uint16_t msecs_1, uint32_t *secs, uint16_t *msecs_2); /****************************************************************************** DECLARE PUBLIC FUNCTIONS ******************************************************************************/ __attribute__ ((section (".boot"))) void pyb_rtc_pre_init(void) { - // if the RTC was previously set, leave it alone + // only if comming out of a power-on reset if (MAP_PRCMSysResetCauseGet() == PRCM_POWER_ON) { // Mark the RTC in use first MAP_PRCMRTCInUseSet(); // reset the time and date - pyb_rtc_reset((mp_obj_t)&pyb_rtc_obj); + pyb_rtc_reset(); } } +void pyb_rtc_get_time (uint32_t *secs, uint16_t *msecs) { + uint16_t cycles; + MAP_PRCMRTCGet (secs, &cycles); + *msecs = RTC_CYCLES_U16MS(cycles); +} + uint32_t pyb_rtc_get_seconds (void) { uint32_t seconds; uint16_t mseconds; - MAP_PRCMRTCGet(&seconds, &mseconds); + pyb_rtc_get_time(&seconds, &mseconds); return seconds; } +void pyb_rtc_calc_future_time (uint32_t a_mseconds, uint32_t *f_seconds, uint16_t *f_mseconds) { + uint32_t c_seconds; + uint16_t c_mseconds; + // get the current time + pyb_rtc_get_time(&c_seconds, &c_mseconds); + // calculate the future seconds + *f_seconds = c_seconds + (a_mseconds / 1000); + // calculate the "remaining" future mseconds + *f_mseconds = a_mseconds % 1000; + // add the current milliseconds + rtc_msec_add (c_mseconds, f_seconds, f_mseconds); +} + +void pyb_rtc_repeat_alarm (pyb_rtc_obj_t *self) { + if (self->repeat) { + uint32_t f_seconds, c_seconds; + uint16_t f_mseconds, c_mseconds; + + pyb_rtc_get_time(&c_seconds, &c_mseconds); + + // substract the time elapsed between waking up and setting up the alarm again + int32_t wake_ms = ((c_seconds * 1000) + c_mseconds) - ((self->alarm_time_s * 1000) + self->alarm_time_ms); + int32_t next_alarm = self->alarm_ms - wake_ms; + next_alarm = next_alarm > 0 ? next_alarm : PYB_RTC_MIN_ALARM_TIME_MS; + pyb_rtc_calc_future_time (next_alarm, &f_seconds, &f_mseconds); + + // now configure the alarm + pyb_rtc_set_alarm (self, f_seconds, f_mseconds); + } +} + +void pyb_rtc_disable_alarm (void) { + pyb_rtc_obj.alarmset = false; + pyb_rtc_disable_interupt(); +} + /****************************************************************************** DECLARE PRIVATE FUNCTIONS ******************************************************************************/ -STATIC uint32_t pyb_rtc_reset (mp_obj_t self_in) { +STATIC void pyb_rtc_set_time (uint32_t secs, uint16_t msecs) { + // add the RTC access time + rtc_msec_add(RTC_ACCESS_TIME_MSEC, &secs, &msecs); + // convert from mseconds to cycles + msecs = RTC_U16MS_CYCLES(msecs); + // now set the time + MAP_PRCMRTCSet(secs, msecs); +} + +STATIC uint32_t pyb_rtc_reset (void) { // fresh reset; configure the RTC Calendar // set the date to 1st Jan 2015 // set the time to 00:00:00 uint32_t seconds = timeutils_seconds_since_2000(2015, 1, 1, 0, 0, 0); - // Now set the RTC calendar seconds - MAP_PRCMRTCSet(seconds, 0); + // disable any running alarm + pyb_rtc_disable_alarm(); + // Now set the RTC calendar time + pyb_rtc_set_time(seconds, 0); return seconds; } -STATIC void pyb_rtc_callback_enable (mp_obj_t self_in) { - pyb_rtc_obj_t *self = self_in; - // check the wake from param - if (self->prwmode & PYB_PWR_MODE_ACTIVE) { - // enable the slow clock interrupt - MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR); - } else { - // just in case it was already enabled before - MAP_PRCMIntDisable(PRCM_INT_SLOW_CLK_CTR); - } - pybsleep_configure_timer_wakeup (self->prwmode); +STATIC void pyb_rtc_disable_interupt (void) { + uint primsk = disable_irq(); + MAP_PRCMIntDisable(PRCM_INT_SLOW_CLK_CTR); + (void)MAP_PRCMIntStatus(); + enable_irq(primsk); } -STATIC void pyb_rtc_callback_disable (mp_obj_t self_in) { +STATIC void pyb_rtc_irq_enable (mp_obj_t self_in) { pyb_rtc_obj_t *self = self_in; - // check the wake from param - if (self->prwmode & PYB_PWR_MODE_ACTIVE) { - // disable the slow clock interrupt + // we always need interrupts if repeat is enabled + if ((self->pwrmode & PYB_PWR_MODE_ACTIVE) || self->repeat) { + MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR); + } else { // just in case it was already enabled before MAP_PRCMIntDisable(PRCM_INT_SLOW_CLK_CTR); } - // disable wake from ldps and hibernate - pybsleep_configure_timer_wakeup (PYB_PWR_MODE_ACTIVE); - // read the interrupt status to clear any pending interrupt - (void)MAP_PRCMIntStatus(); + self->irq_enabled = true; +} + +STATIC void pyb_rtc_irq_disable (mp_obj_t self_in) { + pyb_rtc_obj_t *self = self_in; + self->irq_enabled = false; + if (!self->repeat) { // we always need interrupts if repeat is enabled + pyb_rtc_disable_interupt(); + } +} + +STATIC int pyb_rtc_irq_flags (mp_obj_t self_in) { + pyb_rtc_obj_t *self = self_in; + return self->irq_flags; } STATIC uint pyb_rtc_datetime_s_us(const mp_obj_t datetime, uint32_t *seconds) { @@ -177,15 +237,15 @@ STATIC uint pyb_rtc_datetime_s_us(const mp_obj_t datetime, uint32_t *seconds) { /// /// (year, month, day, hours, minutes, seconds, milliseconds, tzinfo=None) /// -STATIC mp_obj_t pyb_rtc_datetime(mp_obj_t self, const mp_obj_t datetime) { +STATIC mp_obj_t pyb_rtc_datetime(mp_obj_t self_in, const mp_obj_t datetime) { uint32_t seconds; uint32_t useconds; if (datetime != MP_OBJ_NULL) { useconds = pyb_rtc_datetime_s_us(datetime, &seconds); - MAP_PRCMRTCSet(seconds, RTC_U16MS_CYCLES(useconds / 1000)); + pyb_rtc_set_time (seconds, useconds / 1000); } else { - seconds = pyb_rtc_reset(self); + seconds = pyb_rtc_reset(); } // set WLAN time and date, this is needed to verify certificates @@ -193,6 +253,32 @@ STATIC mp_obj_t pyb_rtc_datetime(mp_obj_t self, const mp_obj_t datetime) { return mp_const_none; } +STATIC void pyb_rtc_set_alarm (pyb_rtc_obj_t *self, uint32_t seconds, uint16_t mseconds) { + // disable the interrupt before updating anything + if (self->irq_enabled) { + MAP_PRCMIntDisable(PRCM_INT_SLOW_CLK_CTR); + } + // set the match value + MAP_PRCMRTCMatchSet(seconds, RTC_U16MS_CYCLES(mseconds)); + self->alarmset = true; + self->alarm_time_s = seconds; + self->alarm_time_ms = mseconds; + // enabled the interrupts again if applicable + if (self->irq_enabled || self->repeat) { + MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR); + } +} + +STATIC void rtc_msec_add (uint16_t msecs_1, uint32_t *secs, uint16_t *msecs_2) { + if (msecs_1 + *msecs_2 >= 1000) { // larger than one second + *msecs_2 = (msecs_1 + *msecs_2) - 1000; + *secs += 1; // carry flag + } else { + // simply add the mseconds + *msecs_2 = msecs_1 + *msecs_2; + } +} + /******************************************************************************/ // Micro Python bindings @@ -219,6 +305,9 @@ STATIC mp_obj_t pyb_rtc_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n // set the time and date pyb_rtc_datetime((mp_obj_t)&pyb_rtc_obj, args[1].u_obj); + // pass it to the sleep module + pybsleep_set_rtc_obj (self); + // return constant object return (mp_obj_t)&pyb_rtc_obj; } @@ -236,9 +325,8 @@ STATIC mp_obj_t pyb_rtc_now (mp_obj_t self_in) { uint32_t seconds; uint16_t mseconds; - // get the seconds and the milliseconds from the RTC - MAP_PRCMRTCGet(&seconds, &mseconds); - mseconds = RTC_CYCLES_U16MS(mseconds); + // get the time from the RTC + pyb_rtc_get_time(&seconds, &mseconds); timeutils_seconds_since_2000_to_struct_time(seconds, &tm); mp_obj_t tuple[8] = { @@ -256,7 +344,7 @@ STATIC mp_obj_t pyb_rtc_now (mp_obj_t self_in) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_rtc_now_obj, pyb_rtc_now); STATIC mp_obj_t pyb_rtc_deinit (mp_obj_t self_in) { - pyb_rtc_reset (self_in); + pyb_rtc_reset(); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_rtc_deinit_obj, pyb_rtc_deinit); @@ -264,7 +352,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_rtc_deinit_obj, pyb_rtc_deinit); STATIC mp_obj_t pyb_rtc_alarm (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { STATIC const mp_arg_t allowed_args[] = { { MP_QSTR_id, MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_time, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_time, MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_repeat, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, }; @@ -278,114 +366,97 @@ STATIC mp_obj_t pyb_rtc_alarm (mp_uint_t n_args, const mp_obj_t *pos_args, mp_ma nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); } - uint32_t a_seconds; - uint16_t a_mseconds; + uint32_t f_seconds; + uint16_t f_mseconds; + bool repeat = args[2].u_bool; if (MP_OBJ_IS_TYPE(args[1].u_obj, &mp_type_tuple)) { // datetime tuple given - a_mseconds = pyb_rtc_datetime_s_us (args[1].u_obj, &a_seconds) / 1000; - } else { // then it must be an integer or MP_OBJ_NULL - uint32_t c_seconds; - uint16_t c_mseconds; - if (MP_OBJ_IS_INT(args[1].u_obj)) { - a_seconds = 0, a_mseconds = mp_obj_get_int(args[1].u_obj); - } else { - a_seconds = 1, a_mseconds = 0; + // repeat cannot be used with a datetime tuple + if (repeat) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); } - // get the seconds and the milliseconds from the RTC - MAP_PRCMRTCGet(&c_seconds, &c_mseconds); - a_mseconds += RTC_CYCLES_U16MS(c_mseconds); - // calculate the future time - a_seconds += c_seconds + (a_mseconds / 1000); - a_mseconds -= ((a_mseconds / 1000) * 1000); + f_mseconds = pyb_rtc_datetime_s_us (args[1].u_obj, &f_seconds) / 1000; + } else { // then it must be an integer + self->alarm_ms = mp_obj_get_int(args[1].u_obj); + pyb_rtc_calc_future_time (self->alarm_ms, &f_seconds, &f_mseconds); } - // disable the interrupt before updating anything - pyb_rtc_callback_disable((mp_obj_t)self); + // store the repepat flag + self->repeat = repeat; - // set the match value - MAP_PRCMRTCMatchSet(a_seconds, a_mseconds); - - // enabled it again (according to the power mode) - pyb_rtc_callback_enable((mp_obj_t)self); - - // set the alarmset flag and store the repeat one - self->alarmset = true; - self->repeat = args[2].u_bool; + // now configure the alarm + pyb_rtc_set_alarm (self, f_seconds, f_mseconds); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_rtc_alarm_obj, 1, pyb_rtc_alarm); -STATIC mp_obj_t pyb_rtc_alarm_left (mp_obj_t self_in) { - pyb_rtc_obj_t *self = self_in; - uint32_t a_seconds, c_seconds; - uint16_t a_mseconds, c_mseconds; +STATIC mp_obj_t pyb_rtc_alarm_left (mp_uint_t n_args, const mp_obj_t *args) { + pyb_rtc_obj_t *self = args[0]; int32_t ms_left; + uint32_t c_seconds; + uint16_t c_mseconds; + + // only alarm id 0 is available + if (n_args > 1 && mp_obj_get_int(args[1]) != 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); + } - // get the alarm time - MAP_PRCMRTCMatchGet(&a_seconds, &a_mseconds); - a_mseconds = RTC_CYCLES_U16MS(a_mseconds); // get the current time - MAP_PRCMRTCGet(&c_seconds, &c_mseconds); - c_mseconds = RTC_CYCLES_U16MS(c_mseconds); + pyb_rtc_get_time(&c_seconds, &c_mseconds); + // calculate the ms left - ms_left = ((a_seconds * 1000) + a_mseconds) - ((c_seconds * 1000) + c_mseconds); + ms_left = ((self->alarm_time_s * 1000) + self->alarm_time_ms) - ((c_seconds * 1000) + c_mseconds); if (!self->alarmset || ms_left < 0) { ms_left = 0; } return mp_obj_new_int(ms_left); } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_rtc_alarm_left_obj, pyb_rtc_alarm_left); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_alarm_left_obj, 1, 2, pyb_rtc_alarm_left); -/// \method callback(handler, value, pwrmode) -/// Creates a callback object associated with the real time clock -/// min num of arguments is 1 (value). The value is the alarm time -/// in the future, in msec -/// FIXME -STATIC mp_obj_t pyb_rtc_callback (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - mp_arg_val_t args[mpcallback_INIT_NUM_ARGS]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mpcallback_INIT_NUM_ARGS, mpcallback_init_args, args); +STATIC mp_obj_t pyb_rtc_alarm_cancel (mp_uint_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) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); + } + // disable the alarm + pyb_rtc_disable_alarm(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_alarm_cancel_obj, 1, 2, pyb_rtc_alarm_cancel); + +/// \method irq(trigger, priority, handler, wake) +STATIC mp_obj_t pyb_rtc_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + mp_arg_val_t args[mp_irq_INIT_NUM_ARGS]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mp_irq_INIT_NUM_ARGS, mp_irq_init_args, args); pyb_rtc_obj_t *self = pos_args[0]; - // check if any parameters were passed - mp_obj_t _callback = mpcallback_find((mp_obj_t)&pyb_rtc_obj); - if (kw_args->used > 0) { - uint32_t f_mseconds = MAX(1, mp_obj_get_int(args[3].u_obj)); - uint32_t seconds; - uint16_t mseconds; - // get the seconds and the milliseconds from the RTC - MAP_PRCMRTCGet(&seconds, &mseconds); - mseconds = RTC_CYCLES_U16MS(mseconds); - - // configure the rtc alarm accordingly - seconds += f_mseconds / 1000; - mseconds += f_mseconds - ((f_mseconds / 1000) * 1000); - - // disable the interrupt before updating anything - pyb_rtc_callback_disable((mp_obj_t)&pyb_rtc_obj); - - // set the match value - MAP_PRCMRTCMatchSet(seconds, mseconds); - - // save the power mode data for later - self->prwmode = args[4].u_int; - - // create the callback - _callback = mpcallback_new ((mp_obj_t)&pyb_rtc_obj, args[1].u_obj, &pybrtc_cb_methods, true); - - // set the lpds callback - pybsleep_set_timer_lpds_callback(_callback); - - // the interrupt priority is ignored since it's already set to to highest level by the sleep module - // to make sure that the wakeup callbacks are always called first when resuming from sleep - - // enable the interrupt - pyb_rtc_callback_enable((mp_obj_t)&pyb_rtc_obj); - } else if (!_callback) { - _callback = mpcallback_new ((mp_obj_t)&pyb_rtc_obj, mp_const_none, &pybrtc_cb_methods, false); + // save the power mode data for later + uint8_t pwrmode = (args[3].u_obj == mp_const_none) ? PYB_PWR_MODE_ACTIVE : mp_obj_get_int(args[3].u_obj); + if (pwrmode > (PYB_PWR_MODE_ACTIVE | PYB_PWR_MODE_LPDS | PYB_PWR_MODE_HIBERNATE)) { + goto invalid_args; } - return _callback; + + // check the trigger + if (mp_obj_get_int(args[0].u_obj) == PYB_RTC_ALARM0) { + self->pwrmode = pwrmode; + pyb_rtc_irq_enable((mp_obj_t)self); + } else { + goto invalid_args; + } + + // the interrupt priority is ignored since it's already set to to highest level by the sleep module + // to make sure that the wakeup irqs are always called first when resuming from sleep + + // create the callback + mp_obj_t _irq = mp_irq_new ((mp_obj_t)self, args[2].u_obj, &pyb_rtc_irq_methods); + self->irq_obj = _irq; + + return _irq; + +invalid_args: + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); } -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_rtc_callback_obj, 1, pyb_rtc_callback); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_rtc_irq_obj, 1, pyb_rtc_irq); STATIC const mp_map_elem_t pyb_rtc_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_rtc_init_obj }, @@ -393,7 +464,11 @@ STATIC const mp_map_elem_t pyb_rtc_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_now), (mp_obj_t)&pyb_rtc_now_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_alarm), (mp_obj_t)&pyb_rtc_alarm_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_alarm_left), (mp_obj_t)&pyb_rtc_alarm_left_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&pyb_rtc_callback_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_alarm_cancel), (mp_obj_t)&pyb_rtc_alarm_cancel_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_irq), (mp_obj_t)&pyb_rtc_irq_obj }, + + // class constants + { MP_OBJ_NEW_QSTR(MP_QSTR_ALARM0), MP_OBJ_NEW_SMALL_INT(PYB_RTC_ALARM0) }, }; STATIC MP_DEFINE_CONST_DICT(pyb_rtc_locals_dict, pyb_rtc_locals_dict_table); @@ -404,8 +479,9 @@ const mp_obj_type_t pyb_rtc_type = { .locals_dict = (mp_obj_t)&pyb_rtc_locals_dict, }; -STATIC const mp_cb_methods_t pybrtc_cb_methods = { - .init = pyb_rtc_callback, - .enable = pyb_rtc_callback_enable, - .disable = pyb_rtc_callback_disable, +STATIC const mp_irq_methods_t pyb_rtc_irq_methods = { + .init = pyb_rtc_irq, + .enable = pyb_rtc_irq_enable, + .disable = pyb_rtc_irq_disable, + .flags = pyb_rtc_irq_flags }; diff --git a/cc3200/mods/pybrtc.h b/cc3200/mods/pybrtc.h index 06c4868db..5111b78f7 100644 --- a/cc3200/mods/pybrtc.h +++ b/cc3200/mods/pybrtc.h @@ -28,12 +28,32 @@ #ifndef PYBRTC_H_ #define PYBRTC_H_ -#define RTC_U16MS_CYCLES(msec) ((msec * 1024) / 1000) -#define RTC_CYCLES_U16MS(cycles) ((cycles * 1000) / 1024) +// RTC triggers +#define PYB_RTC_ALARM0 (0x01) + +#define RTC_ACCESS_TIME_MSEC (5) +#define PYB_RTC_MIN_ALARM_TIME_MS (RTC_ACCESS_TIME_MSEC * 2) + +typedef struct _pyb_rtc_obj_t { + mp_obj_base_t base; + mp_obj_t irq_obj; + uint32_t irq_flags; + uint32_t alarm_ms; + uint32_t alarm_time_s; + uint16_t alarm_time_ms; + byte pwrmode; + bool alarmset; + bool repeat; + bool irq_enabled; +} pyb_rtc_obj_t; extern const mp_obj_type_t pyb_rtc_type; extern void pyb_rtc_pre_init(void); +extern void pyb_rtc_get_time (uint32_t *secs, uint16_t *msecs); extern uint32_t pyb_rtc_get_seconds (void); +extern void pyb_rtc_calc_future_time (uint32_t a_mseconds, uint32_t *f_seconds, uint16_t *f_mseconds); +extern void pyb_rtc_repeat_alarm (pyb_rtc_obj_t *self); +extern void pyb_rtc_disable_alarm (void); #endif // PYBRTC_H_ diff --git a/cc3200/mods/pybsd.c b/cc3200/mods/pybsd.c index 864db513b..55dc98ae8 100644 --- a/cc3200/mods/pybsd.c +++ b/cc3200/mods/pybsd.c @@ -54,7 +54,7 @@ /****************************************************************************** DECLARE PUBLIC DATA ******************************************************************************/ -pybsd_obj_t pybsd_obj = {.pin_clk = MP_OBJ_NULL, .enabled = false}; +pybsd_obj_t pybsd_obj; /****************************************************************************** DECLARE PRIVATE DATA diff --git a/cc3200/mods/pybsleep.c b/cc3200/mods/pybsleep.c index 0b6a29b3f..d7a8e439d 100644 --- a/cc3200/mods/pybsleep.c +++ b/cc3200/mods/pybsleep.c @@ -43,6 +43,7 @@ #include "spi.h" #include "pin.h" #include "pybsleep.h" +#include "mpirq.h" #include "pybpin.h" #include "simplelink.h" #include "modnetwork.h" @@ -50,12 +51,12 @@ #include "osi.h" #include "debug.h" #include "mpexception.h" -#include "mpcallback.h" #include "mperror.h" #include "sleeprestore.h" #include "serverstask.h" #include "antenna.h" #include "cryptohash.h" +#include "pybrtc.h" /****************************************************************************** DECLARE PRIVATE CONSTANTS @@ -70,8 +71,8 @@ #define WAKEUP_TIME_LPDS (LPDS_UP_TIME + LPDS_DOWN_TIME + USER_OFFSET) // 20 msec #define WAKEUP_TIME_HIB (32768) // 1 s -#define FORCED_TIMER_INTERRUPT_MS (1) -#define FAILED_SLEEP_DELAY_MS (FORCED_TIMER_INTERRUPT_MS * 3) +#define FORCED_TIMER_INTERRUPT_MS (PYB_RTC_MIN_ALARM_TIME_MS) +#define FAILED_SLEEP_DELAY_MS (FORCED_TIMER_INTERRUPT_MS * 2) /****************************************************************************** DECLARE PRIVATE TYPES @@ -113,10 +114,9 @@ typedef struct { } pybsleep_obj_t; typedef struct { - mp_obj_t wlan_lpds_wake_cb; - mp_obj_t timer_lpds_wake_cb; - mp_obj_t gpio_lpds_wake_cb; - uint timer_wake_pwrmode; + mp_obj_t gpio_lpds_wake_cb; + wlan_obj_t *wlan_obj; + pyb_rtc_obj_t *rtc_obj; } pybsleep_data_t; /****************************************************************************** @@ -124,7 +124,7 @@ typedef struct { ******************************************************************************/ STATIC const mp_obj_type_t pybsleep_type; STATIC nvic_reg_store_t *nvic_reg_store; -STATIC pybsleep_data_t pybsleep_data = {NULL, NULL, NULL, 0}; +STATIC pybsleep_data_t pybsleep_data = {NULL, NULL, NULL}; volatile arm_cm4_core_regs_t vault_arm_registers; STATIC pybsleep_reset_cause_t pybsleep_reset_cause = PYB_SLP_PWRON_RESET; STATIC pybsleep_wake_reason_t pybsleep_wake_reason = PYB_SLP_WAKED_PWRON; @@ -224,20 +224,16 @@ void pybsleep_remove (const mp_obj_t obj) { } } -void pybsleep_set_wlan_lpds_callback (mp_obj_t cb_obj) { - pybsleep_data.wlan_lpds_wake_cb = cb_obj; -} - void pybsleep_set_gpio_lpds_callback (mp_obj_t cb_obj) { pybsleep_data.gpio_lpds_wake_cb = cb_obj; } -void pybsleep_set_timer_lpds_callback (mp_obj_t cb_obj) { - pybsleep_data.timer_lpds_wake_cb = cb_obj; +void pybsleep_set_wlan_obj (mp_obj_t wlan_obj) { + pybsleep_data.wlan_obj = (wlan_obj_t *)wlan_obj; } -void pybsleep_configure_timer_wakeup (uint pwrmode) { - pybsleep_data.timer_wake_pwrmode = pwrmode; +void pybsleep_set_rtc_obj (mp_obj_t rtc_obj) { + pybsleep_data.rtc_obj = (pyb_rtc_obj_t *)rtc_obj; } pybsleep_reset_cause_t pybsleep_get_reset_cause (void) { @@ -410,7 +406,7 @@ void pybsleep_suspend_exit (void) { pybsleep_obj_wakeup(); // reconfigure all the previously enabled interrupts - mpcallback_wake_all(); + mp_irq_wake_all(); // we need to init the crypto hash engine again CRYPTOHASH_Init(); @@ -425,25 +421,35 @@ void pybsleep_suspend_exit (void) { STATIC void PRCMInterruptHandler (void) { // reading the interrupt status automatically clears the interrupt if (PRCM_INT_SLOW_CLK_CTR == MAP_PRCMIntStatus()) { - // this interrupt is triggered during active mode - mpcallback_handler(pybsleep_data.timer_lpds_wake_cb); - } - else { + // reconfigure it again (if repeat is true) + pyb_rtc_repeat_alarm (pybsleep_data.rtc_obj); + pybsleep_data.rtc_obj->irq_flags = PYB_RTC_ALARM0; + // need to check if irq's are enabled from the user point of view + if (pybsleep_data.rtc_obj->irq_enabled && (pybsleep_data.rtc_obj->pwrmode & PYB_PWR_MODE_ACTIVE)) { + mp_irq_handler(pybsleep_data.rtc_obj->irq_obj); + } + pybsleep_data.rtc_obj->irq_flags = 0; + } else { // interrupt has been triggered while waking up from LPDS switch (MAP_PRCMLPDSWakeupCauseGet()) { case PRCM_LPDS_HOST_IRQ: - mpcallback_handler(pybsleep_data.wlan_lpds_wake_cb); + pybsleep_data.wlan_obj->irq_flags = MODWLAN_WIFI_EVENT_ANY; + mp_irq_handler(pybsleep_data.wlan_obj->irq_obj); pybsleep_wake_reason = PYB_SLP_WAKED_BY_WLAN; + pybsleep_data.wlan_obj->irq_flags = 0; break; case PRCM_LPDS_GPIO: - mpcallback_handler(pybsleep_data.gpio_lpds_wake_cb); + mp_irq_handler(pybsleep_data.gpio_lpds_wake_cb); pybsleep_wake_reason = PYB_SLP_WAKED_BY_GPIO; break; case PRCM_LPDS_TIMER: - // disable the timer as wake-up source - pybsleep_data.timer_wake_pwrmode &= ~PYB_PWR_MODE_LPDS; + // reconfigure it again if repeat is true + pyb_rtc_repeat_alarm (pybsleep_data.rtc_obj); + pybsleep_data.rtc_obj->irq_flags = PYB_RTC_ALARM0; + // next one clears the wake cause flag MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER); - mpcallback_handler(pybsleep_data.timer_lpds_wake_cb); + mp_irq_handler(pybsleep_data.rtc_obj->irq_obj); + pybsleep_data.rtc_obj->irq_flags = 0; pybsleep_wake_reason = PYB_SLP_WAKED_BY_RTC; break; default: @@ -473,9 +479,9 @@ STATIC void pybsleep_iopark (bool hibernate) { break; #endif default: - // enable a weak pull-down if the pin is unused + // enable a weak pull-up if the pin is unused if (!pin->used) { - MAP_PinConfigSet(pin->pin_num, pin->strength, PIN_TYPE_STD_PD); + MAP_PinConfigSet(pin->pin_num, pin->strength, PIN_TYPE_STD_PU); } if (hibernate) { // make it an input @@ -517,71 +523,70 @@ STATIC void pybsleep_iopark (bool hibernate) { } STATIC bool setup_timer_lpds_wake (void) { - uint64_t t_match, t_curr, t_remaining; + uint64_t t_match, t_curr; + int64_t t_remaining; // get the time remaining for the RTC timer to expire t_match = MAP_PRCMSlowClkCtrMatchGet(); t_curr = MAP_PRCMSlowClkCtrGet(); - if (t_match > t_curr) { - // get the time remaining in terms of slow clocks - t_remaining = (t_match - t_curr); - if (t_remaining > WAKEUP_TIME_LPDS) { - // subtract the time it takes for wakeup from lpds - t_remaining -= WAKEUP_TIME_LPDS; - t_remaining = (t_remaining > 0xFFFFFFFF) ? 0xFFFFFFFF: t_remaining; - // setup the LPDS wake time - MAP_PRCMLPDSIntervalSet((uint32_t)t_remaining); - // enable the wake source - MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_TIMER); - return true; - } - } - else { - // setup a timer interrupt immediately - MAP_PRCMRTCMatchSet(0, FORCED_TIMER_INTERRUPT_MS); + // get the time remaining in terms of slow clocks + t_remaining = (t_match - t_curr); + if (t_remaining > WAKEUP_TIME_LPDS) { + // subtract the time it takes to wakeup from lpds + t_remaining -= WAKEUP_TIME_LPDS; + t_remaining = (t_remaining > 0xFFFFFFFF) ? 0xFFFFFFFF: t_remaining; + // setup the LPDS wake time + MAP_PRCMLPDSIntervalSet((uint32_t)t_remaining); + // enable the wake source + MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_TIMER); + return true; } // disable the timer as wake source MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER); - // LPDS wake by timer was not possible, force - // an interrupt in active mode instead + uint32_t f_seconds; + uint16_t f_mseconds; + // setup a timer interrupt immediately + pyb_rtc_calc_future_time (FORCED_TIMER_INTERRUPT_MS, &f_seconds, &f_mseconds); + MAP_PRCMRTCMatchSet(f_seconds, f_mseconds); + // LPDS wake by timer was not possible, force an interrupt in active mode instead MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR); return false; } STATIC bool setup_timer_hibernate_wake (void) { - uint64_t t_match, t_curr, t_remaining; + uint64_t t_match, t_curr; + int64_t t_remaining; // get the time remaining for the RTC timer to expire t_match = MAP_PRCMSlowClkCtrMatchGet(); t_curr = MAP_PRCMSlowClkCtrGet(); - if (t_match > t_curr) { - // get the time remaining in terms of slow clocks - t_remaining = (t_match - t_curr); - if (t_remaining > WAKEUP_TIME_HIB) { - // subtract the time it takes for wakeup from hibernate - t_remaining -= WAKEUP_TIME_HIB; - // setup the LPDS wake time - MAP_PRCMHibernateIntervalSet((uint32_t)t_remaining); - // enable the wake source - MAP_PRCMHibernateWakeupSourceEnable(PRCM_HIB_SLOW_CLK_CTR); - return true; - } - } - else { - // setup a timer interrupt immediately - MAP_PRCMRTCMatchSet(0, FORCED_TIMER_INTERRUPT_MS); + // get the time remaining in terms of slow clocks + t_remaining = (t_match - t_curr); + if (t_remaining > WAKEUP_TIME_HIB) { + // subtract the time it takes for wakeup from hibernate + t_remaining -= WAKEUP_TIME_HIB; + // setup the LPDS wake time + MAP_PRCMHibernateIntervalSet((uint32_t)t_remaining); + // enable the wake source + MAP_PRCMHibernateWakeupSourceEnable(PRCM_HIB_SLOW_CLK_CTR); + return true; } + // disable the timer as wake source MAP_PRCMLPDSWakeupSourceDisable(PRCM_HIB_SLOW_CLK_CTR); - // hibernate wake by timer was not possible, force - // an interrupt in active mode instead + uint32_t f_seconds; + uint16_t f_mseconds; + // setup a timer interrupt immediately + pyb_rtc_calc_future_time (FORCED_TIMER_INTERRUPT_MS, &f_seconds, &f_mseconds); + MAP_PRCMRTCMatchSet(f_seconds, f_mseconds); + // LPDS wake by timer was not possible, force an interrupt in active mode instead MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR); return false; @@ -605,21 +610,22 @@ STATIC mp_obj_t pyb_sleep_suspend (mp_obj_t self_in) { nlr_buf_t nlr; // check if we should enable timer wake-up - if (pybsleep_data.timer_wake_pwrmode & PYB_PWR_MODE_LPDS) { + if (pybsleep_data.rtc_obj->irq_enabled && (pybsleep_data.rtc_obj->pwrmode & PYB_PWR_MODE_LPDS)) { if (!setup_timer_lpds_wake()) { // lpds entering is not possible, wait for the forced interrupt and return - pybsleep_data.timer_wake_pwrmode &= ~PYB_PWR_MODE_LPDS; HAL_Delay (FAILED_SLEEP_DELAY_MS); return mp_const_none; } + } else { + // disable the timer as wake source + MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER); } // do we need network wake-up? - if (pybsleep_data.wlan_lpds_wake_cb) { + if (pybsleep_data.wlan_obj->irq_enabled) { MAP_PRCMLPDSWakeupSourceEnable (PRCM_LPDS_HOST_IRQ); server_sleep_sockets(); - } - else { + } else { MAP_PRCMLPDSWakeupSourceDisable (PRCM_LPDS_HOST_IRQ); } @@ -643,14 +649,17 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_sleep_suspend_obj, pyb_sleep_suspend); /// calling this method. STATIC mp_obj_t pyb_sleep_hibernate (mp_obj_t self_in) { // check if we should enable timer wake-up - if (pybsleep_data.timer_wake_pwrmode & PYB_PWR_MODE_HIBERNATE) { + if (pybsleep_data.rtc_obj->irq_enabled && (pybsleep_data.rtc_obj->pwrmode & PYB_PWR_MODE_HIBERNATE)) { if (!setup_timer_hibernate_wake()) { // hibernating is not possible, wait for the forced interrupt and return - pybsleep_data.timer_wake_pwrmode &= ~PYB_PWR_MODE_HIBERNATE; HAL_Delay (FAILED_SLEEP_DELAY_MS); return mp_const_none; } + } else { + // disable the timer as hibernate wake source + MAP_PRCMLPDSWakeupSourceDisable(PRCM_HIB_SLOW_CLK_CTR); } + wlan_stop(SL_STOP_TIMEOUT); pybsleep_flash_powerdown(); // must be done just before entering hibernate mode diff --git a/cc3200/mods/pybsleep.h b/cc3200/mods/pybsleep.h index c27cf39c5..6deb09ba6 100644 --- a/cc3200/mods/pybsleep.h +++ b/cc3200/mods/pybsleep.h @@ -67,10 +67,9 @@ void pybsleep_init0 (void); void pybsleep_signal_soft_reset (void); void pybsleep_add (const mp_obj_t obj, WakeUpCB_t wakeup); void pybsleep_remove (const mp_obj_t obj); -void pybsleep_set_wlan_lpds_callback (mp_obj_t cb_obj); void pybsleep_set_gpio_lpds_callback (mp_obj_t cb_obj); -void pybsleep_set_timer_lpds_callback (mp_obj_t cb_obj); -void pybsleep_configure_timer_wakeup (uint pwrmode); +void pybsleep_set_wlan_obj (mp_obj_t wlan_obj); +void pybsleep_set_rtc_obj (mp_obj_t rtc_obj); pybsleep_reset_cause_t pybsleep_get_reset_cause (void); #endif /* PYBSLEEP_H_ */ diff --git a/cc3200/mods/pybtimer.c b/cc3200/mods/pybtimer.c index bd3a93565..e59934533 100644 --- a/cc3200/mods/pybtimer.c +++ b/cc3200/mods/pybtimer.c @@ -44,8 +44,8 @@ #include "prcm.h" #include "timer.h" #include "pybtimer.h" +#include "mpirq.h" #include "pybsleep.h" -#include "mpcallback.h" #include "mpexception.h" @@ -96,7 +96,8 @@ typedef struct _pyb_timer_obj_t { mp_obj_base_t base; uint32_t timer; uint32_t config; - uint16_t intflags; + uint16_t irq_trigger; + uint16_t irq_flags; uint8_t peripheral; uint8_t id; } pyb_timer_obj_t; @@ -114,7 +115,7 @@ typedef struct _pyb_timer_channel_obj_t { /****************************************************************************** DEFINE PRIVATE DATA ******************************************************************************/ -STATIC const mp_cb_methods_t pyb_timer_channel_cb_methods; +STATIC const mp_irq_methods_t pyb_timer_channel_irq_methods; STATIC pyb_timer_obj_t pyb_timer_obj[PYBTIMER_NUM_TIMERS] = {{.timer = TIMERA0_BASE, .peripheral = PRCM_TIMERA0}, {.timer = TIMERA1_BASE, .peripheral = PRCM_TIMERA1}, {.timer = TIMERA2_BASE, .peripheral = PRCM_TIMERA2}, @@ -124,7 +125,7 @@ STATIC const mp_obj_type_t pyb_timer_channel_type; /****************************************************************************** DECLARE PRIVATE FUNCTIONS ******************************************************************************/ -STATIC mp_obj_t pyb_timer_channel_callback (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +STATIC mp_obj_t pyb_timer_channel_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); STATIC void timer_disable (pyb_timer_obj_t *tim); STATIC void TIMER0AIntHandler(void); STATIC void TIMER0BIntHandler(void); @@ -142,18 +143,26 @@ void timer_init0 (void) { mp_obj_list_init(&MP_STATE_PORT(pyb_timer_channel_obj_list), 0); } -void pyb_timer_channel_callback_enable (mp_obj_t self_in) { +/****************************************************************************** + DEFINE PRIVATE FUNCTIONS + ******************************************************************************/ +STATIC void pyb_timer_channel_irq_enable (mp_obj_t self_in) { pyb_timer_channel_obj_t *self = self_in; - MAP_TimerIntClear(self->timer->timer, self->timer->intflags & self->channel); - MAP_TimerIntEnable(self->timer->timer, self->timer->intflags & self->channel); + MAP_TimerIntClear(self->timer->timer, self->timer->irq_trigger & self->channel); + MAP_TimerIntEnable(self->timer->timer, self->timer->irq_trigger & self->channel); } -void pyb_timer_channel_callback_disable (mp_obj_t self_in) { +STATIC void pyb_timer_channel_irq_disable (mp_obj_t self_in) { pyb_timer_channel_obj_t *self = self_in; - MAP_TimerIntDisable(self->timer->timer, self->timer->intflags & self->channel); + MAP_TimerIntDisable(self->timer->timer, self->timer->irq_trigger & self->channel); } -pyb_timer_channel_obj_t *pyb_timer_channel_find (uint32_t timer, uint16_t channel_n) { +STATIC int pyb_timer_channel_irq_flags (mp_obj_t self_in) { + pyb_timer_channel_obj_t *self = self_in; + return self->timer->irq_flags; +} + +STATIC pyb_timer_channel_obj_t *pyb_timer_channel_find (uint32_t timer, uint16_t channel_n) { for (mp_uint_t i = 0; i < MP_STATE_PORT(pyb_timer_channel_obj_list).len; i++) { pyb_timer_channel_obj_t *ch = ((pyb_timer_channel_obj_t *)(MP_STATE_PORT(pyb_timer_channel_obj_list).items[i])); // any 32-bit timer must be matched by any of its 16-bit versions @@ -164,14 +173,14 @@ pyb_timer_channel_obj_t *pyb_timer_channel_find (uint32_t timer, uint16_t channe return MP_OBJ_NULL; } -void pyb_timer_channel_remove (pyb_timer_channel_obj_t *ch) { +STATIC void pyb_timer_channel_remove (pyb_timer_channel_obj_t *ch) { pyb_timer_channel_obj_t *channel; if ((channel = pyb_timer_channel_find(ch->timer->timer, ch->channel))) { mp_obj_list_remove(&MP_STATE_PORT(pyb_timer_channel_obj_list), channel); } } -void pyb_timer_channel_add (pyb_timer_channel_obj_t *ch) { +STATIC void pyb_timer_channel_add (pyb_timer_channel_obj_t *ch) { // remove it in case it already exists pyb_timer_channel_remove(ch); mp_obj_list_append(&MP_STATE_PORT(pyb_timer_channel_obj_list), ch); @@ -180,8 +189,8 @@ void pyb_timer_channel_add (pyb_timer_channel_obj_t *ch) { STATIC void timer_disable (pyb_timer_obj_t *tim) { // disable all timers and it's interrupts MAP_TimerDisable(tim->timer, TIMER_A | TIMER_B); - MAP_TimerIntDisable(tim->timer, tim->intflags); - MAP_TimerIntClear(tim->timer, tim->intflags); + MAP_TimerIntDisable(tim->timer, tim->irq_trigger); + MAP_TimerIntClear(tim->timer, tim->irq_trigger); MAP_PRCMPeripheralClkDisable(tim->peripheral, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); memset(&pyb_timer_obj[tim->id], 0, sizeof(pyb_timer_obj_t)); } @@ -509,10 +518,11 @@ const mp_obj_type_t pyb_timer_type = { .locals_dict = (mp_obj_t)&pyb_timer_locals_dict, }; -STATIC const mp_cb_methods_t pyb_timer_channel_cb_methods = { - .init = pyb_timer_channel_callback, - .enable = pyb_timer_channel_callback_enable, - .disable = pyb_timer_channel_callback_disable, +STATIC const mp_irq_methods_t pyb_timer_channel_irq_methods = { + .init = pyb_timer_channel_irq, + .enable = pyb_timer_channel_irq_enable, + .disable = pyb_timer_channel_irq_disable, + .flags = pyb_timer_channel_irq_flags, }; STATIC void TIMERGenericIntHandler(uint32_t timer, uint16_t channel) { @@ -522,8 +532,7 @@ STATIC void TIMERGenericIntHandler(uint32_t timer, uint16_t channel) { if ((self = pyb_timer_channel_find(timer, channel))) { status = MAP_TimerIntStatus(self->timer->timer, true) & self->channel; MAP_TimerIntClear(self->timer->timer, status); - mp_obj_t _callback = mpcallback_find(self); - mpcallback_handler(_callback); + mp_irq_handler(mp_irq_find(self)); } } @@ -716,130 +725,107 @@ STATIC mp_obj_t pyb_timer_channel_duty_cycle(mp_uint_t n_args, const mp_obj_t *a } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_duty_cycle_obj, 1, 3, pyb_timer_channel_duty_cycle); -/// \method callback(handler, priority, value) -/// create a callback object associated with the timer channel -STATIC mp_obj_t pyb_timer_channel_callback (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - mp_arg_val_t args[mpcallback_INIT_NUM_ARGS]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mpcallback_INIT_NUM_ARGS, mpcallback_init_args, args); - +/// \method irq(trigger, priority, handler, wake) +/// FIXME triggers!! +STATIC mp_obj_t pyb_timer_channel_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + mp_arg_val_t args[mp_irq_INIT_NUM_ARGS]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mp_irq_INIT_NUM_ARGS, mp_irq_init_args, args); pyb_timer_channel_obj_t *ch = pos_args[0]; - mp_obj_t _callback = mpcallback_find(ch); - if (kw_args->used > 0) { - // convert the priority to the correct value - uint priority = mpcallback_translate_priority (args[2].u_int); - // validate the power mode - uint pwrmode = args[4].u_int; - if (pwrmode != PYB_PWR_MODE_ACTIVE) { - goto invalid_args; - } + // convert the priority to the correct value + uint priority = mp_irq_translate_priority (args[1].u_int); - uint32_t _config = (ch->channel == TIMER_B) ? ((ch->timer->config & TIMER_B) >> 8) : (ch->timer->config & TIMER_A); - uint32_t c_value = mp_obj_get_int(args[3].u_obj); - - // validate and set the value if we are in edge count mode - if (_config == TIMER_CFG_A_CAP_COUNT) { - if (!c_value || c_value > 0xFFFF) { - // zero or exceeds the maximum value of a 16-bit timer - goto invalid_args; - } - MAP_TimerMatchSet(ch->timer->timer, ch->channel, c_value); - } - - // disable the callback first - pyb_timer_channel_callback_disable(ch); - - uint8_t shift = (ch->channel == TIMER_B) ? 8 : 0; - switch (_config) { - case TIMER_CFG_A_ONE_SHOT: - case TIMER_CFG_A_PERIODIC: - ch->timer->intflags |= TIMER_TIMA_TIMEOUT << shift; - break; - case TIMER_CFG_A_CAP_COUNT: - ch->timer->intflags |= TIMER_CAPA_MATCH << shift; - // set the match value and make 1 the minimum - MAP_TimerMatchSet(ch->timer->timer, ch->channel, MAX(1, c_value)); - break; - case TIMER_CFG_A_CAP_TIME: - ch->timer->intflags |= TIMER_CAPA_EVENT << shift; - break; - case TIMER_CFG_A_PWM: - // special case for the PWM match interrupt - ch->timer->intflags |= ((ch->channel & TIMER_A) == TIMER_A) ? TIMER_TIMA_MATCH : TIMER_TIMB_MATCH; - break; - default: - break; - } - // special case for a 32-bit timer - if (ch->channel == (TIMER_A | TIMER_B)) { - ch->timer->intflags |= (ch->timer->intflags << 8); - } - - void (*pfnHandler)(void); - uint32_t intregister; - switch (ch->timer->timer) { - case TIMERA0_BASE: - if (ch->channel == TIMER_B) { - pfnHandler = &TIMER0BIntHandler; - intregister = INT_TIMERA0B; - } else { - pfnHandler = &TIMER0AIntHandler; - intregister = INT_TIMERA0A; - } - break; - case TIMERA1_BASE: - if (ch->channel == TIMER_B) { - pfnHandler = &TIMER1BIntHandler; - intregister = INT_TIMERA1B; - } else { - pfnHandler = &TIMER1AIntHandler; - intregister = INT_TIMERA1A; - } - break; - case TIMERA2_BASE: - if (ch->channel == TIMER_B) { - pfnHandler = &TIMER2BIntHandler; - intregister = INT_TIMERA2B; - } else { - pfnHandler = &TIMER2AIntHandler; - intregister = INT_TIMERA2A; - } - break; - default: - if (ch->channel == TIMER_B) { - pfnHandler = &TIMER3BIntHandler; - intregister = INT_TIMERA3B; - } else { - pfnHandler = &TIMER3AIntHandler; - intregister = INT_TIMERA3A; - } - break; - } - - // register the interrupt and configure the priority - MAP_IntPrioritySet(intregister, priority); - MAP_TimerIntRegister(ch->timer->timer, ch->channel, pfnHandler); - - // create the callback - _callback = mpcallback_new (ch, args[1].u_obj, &pyb_timer_channel_cb_methods, true); - - // reload the timer - uint32_t period_c; - uint32_t match; - compute_prescaler_period_and_match_value(ch, &period_c, &match); - MAP_TimerLoadSet(ch->timer->timer, ch->channel, period_c); - - // enable the callback before returning - pyb_timer_channel_callback_enable(ch); - } else if (!_callback) { - _callback = mpcallback_new (ch, mp_const_none, &pyb_timer_channel_cb_methods, false); + // validate the power mode + uint8_t pwrmode = (args[3].u_obj == mp_const_none) ? PYB_PWR_MODE_ACTIVE : mp_obj_get_int(args[3].u_obj); + if (pwrmode != PYB_PWR_MODE_ACTIVE) { + goto invalid_args; } - return _callback; + + // disable the callback first + pyb_timer_channel_irq_disable(ch); + + uint8_t shift = (ch->channel == TIMER_B) ? 8 : 0; + uint32_t _config = (ch->channel == TIMER_B) ? ((ch->timer->config & TIMER_B) >> 8) : (ch->timer->config & TIMER_A); + switch (_config) { + case TIMER_CFG_A_ONE_SHOT: + case TIMER_CFG_A_PERIODIC: + ch->timer->irq_trigger |= TIMER_TIMA_TIMEOUT << shift; + break; + case TIMER_CFG_A_CAP_COUNT: + ch->timer->irq_trigger |= TIMER_CAPA_MATCH << shift; + break; + case TIMER_CFG_A_CAP_TIME: + ch->timer->irq_trigger |= TIMER_CAPA_EVENT << shift; + break; + case TIMER_CFG_A_PWM: + // special case for the PWM match interrupt + ch->timer->irq_trigger |= ((ch->channel & TIMER_A) == TIMER_A) ? TIMER_TIMA_MATCH : TIMER_TIMB_MATCH; + break; + default: + break; + } + // special case for a 32-bit timer + if (ch->channel == (TIMER_A | TIMER_B)) { + ch->timer->irq_trigger |= (ch->timer->irq_trigger << 8); + } + + void (*pfnHandler)(void); + uint32_t intregister; + switch (ch->timer->timer) { + case TIMERA0_BASE: + if (ch->channel == TIMER_B) { + pfnHandler = &TIMER0BIntHandler; + intregister = INT_TIMERA0B; + } else { + pfnHandler = &TIMER0AIntHandler; + intregister = INT_TIMERA0A; + } + break; + case TIMERA1_BASE: + if (ch->channel == TIMER_B) { + pfnHandler = &TIMER1BIntHandler; + intregister = INT_TIMERA1B; + } else { + pfnHandler = &TIMER1AIntHandler; + intregister = INT_TIMERA1A; + } + break; + case TIMERA2_BASE: + if (ch->channel == TIMER_B) { + pfnHandler = &TIMER2BIntHandler; + intregister = INT_TIMERA2B; + } else { + pfnHandler = &TIMER2AIntHandler; + intregister = INT_TIMERA2A; + } + break; + default: + if (ch->channel == TIMER_B) { + pfnHandler = &TIMER3BIntHandler; + intregister = INT_TIMERA3B; + } else { + pfnHandler = &TIMER3AIntHandler; + intregister = INT_TIMERA3A; + } + break; + } + + // register the interrupt and configure the priority + MAP_IntPrioritySet(intregister, priority); + MAP_TimerIntRegister(ch->timer->timer, ch->channel, pfnHandler); + + // create the callback + mp_obj_t _irq = mp_irq_new (ch, args[2].u_obj, &pyb_timer_channel_irq_methods); + + // enable the callback before returning + pyb_timer_channel_irq_enable(ch); + + return _irq; invalid_args: nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); } -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_channel_callback_obj, 1, pyb_timer_channel_callback); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_channel_irq_obj, 1, pyb_timer_channel_irq); STATIC const mp_map_elem_t pyb_timer_channel_locals_dict_table[] = { // instance methods @@ -849,7 +835,7 @@ STATIC const mp_map_elem_t pyb_timer_channel_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_event_count), (mp_obj_t)&pyb_timer_channel_event_count_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_event_time), (mp_obj_t)&pyb_timer_channel_event_time_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_duty_cycle), (mp_obj_t)&pyb_timer_channel_duty_cycle_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&pyb_timer_channel_callback_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_irq), (mp_obj_t)&pyb_timer_channel_irq_obj }, }; STATIC MP_DEFINE_CONST_DICT(pyb_timer_channel_locals_dict, pyb_timer_channel_locals_dict_table); diff --git a/cc3200/mods/pybuart.c b/cc3200/mods/pybuart.c index 73cf661bc..fca534458 100644 --- a/cc3200/mods/pybuart.c +++ b/cc3200/mods/pybuart.c @@ -45,9 +45,9 @@ #include "prcm.h" #include "uart.h" #include "pybuart.h" +#include "mpirq.h" #include "pybioctl.h" #include "pybsleep.h" -#include "mpcallback.h" #include "mpexception.h" #include "py/mpstate.h" #include "osi.h" @@ -69,13 +69,13 @@ #define PYBUART_TX_WAIT_US(baud) ((PYBUART_FRAME_TIME_US(baud)) + 1) #define PYBUART_TX_MAX_TIMEOUT_MS (5) -#define PYBUART_RX_BUFFER_LEN (128) +#define PYBUART_RX_BUFFER_LEN (256) // interrupt triggers -#define E_UART_TRIGGER_RX_ANY (0x01) -#define E_UART_TRIGGER_RX_HALF (0x02) -#define E_UART_TRIGGER_RX_FULL (0x04) -#define E_UART_TRIGGER_TX_DONE (0x08) +#define UART_TRIGGER_RX_ANY (0x01) +#define UART_TRIGGER_RX_HALF (0x02) +#define UART_TRIGGER_RX_FULL (0x04) +#define UART_TRIGGER_TX_DONE (0x08) /****************************************************************************** DECLARE PRIVATE FUNCTIONS @@ -83,12 +83,12 @@ STATIC void uart_init (pyb_uart_obj_t *self); STATIC bool uart_rx_wait (pyb_uart_obj_t *self); STATIC void uart_check_init(pyb_uart_obj_t *self); +STATIC mp_obj_t uart_irq_new (pyb_uart_obj_t *self, byte trigger, mp_int_t priority, mp_obj_t handler); STATIC void UARTGenericIntHandler(uint32_t uart_id); STATIC void UART0IntHandler(void); STATIC void UART1IntHandler(void); -STATIC void uart_callback_enable (mp_obj_t self_in); -STATIC void uart_callback_disable (mp_obj_t self_in); -STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in); +STATIC void uart_irq_enable (mp_obj_t self_in); +STATIC void uart_irq_disable (mp_obj_t self_in); /****************************************************************************** DEFINE PRIVATE TYPES @@ -105,7 +105,8 @@ struct _pyb_uart_obj_t { uint16_t read_buf_tail; // indexes first full slot (not full if equals head) byte peripheral; byte irq_trigger; - bool callback_enabled; + bool irq_enabled; + byte irq_flags; }; /****************************************************************************** @@ -113,7 +114,7 @@ struct _pyb_uart_obj_t { ******************************************************************************/ STATIC pyb_uart_obj_t pyb_uart_obj[PYB_NUM_UARTS] = { {.reg = UARTA0_BASE, .baudrate = 0, .read_buf = NULL, .peripheral = PRCM_UARTA0}, {.reg = UARTA1_BASE, .baudrate = 0, .read_buf = NULL, .peripheral = PRCM_UARTA1} }; -STATIC const mp_cb_methods_t uart_cb_methods; +STATIC const mp_irq_methods_t uart_irq_methods; STATIC const mp_obj_t pyb_uart_def_pin[PYB_NUM_UARTS][2] = { {&pin_GP1, &pin_GP2}, {&pin_GP3, &pin_GP4} }; @@ -176,28 +177,6 @@ void uart_tx_strn_cooked(pyb_uart_obj_t *self, const char *str, uint len) { } } -mp_obj_t uart_callback_new (pyb_uart_obj_t *self, mp_obj_t handler, mp_int_t priority, byte trigger) { - // disable the uart interrupts before updating anything - uart_callback_disable (self); - - if (self->uart_id == PYB_UART_0) { - MAP_IntPrioritySet(INT_UARTA0, priority); - MAP_UARTIntRegister(self->reg, UART0IntHandler); - } else { - MAP_IntPrioritySet(INT_UARTA1, priority); - MAP_UARTIntRegister(self->reg, UART1IntHandler); - } - - // create the callback - mp_obj_t _callback = mpcallback_new ((mp_obj_t)self, handler, &uart_cb_methods, true); - - // enable the interrupts now - self->irq_trigger = trigger; - uart_callback_enable (self); - - return _callback; -} - /****************************************************************************** DEFINE PRIVATE FUNCTIONS ******************************************************************************/ @@ -248,15 +227,37 @@ STATIC bool uart_rx_wait (pyb_uart_obj_t *self) { } } +STATIC mp_obj_t uart_irq_new (pyb_uart_obj_t *self, byte trigger, mp_int_t priority, mp_obj_t handler) { + // disable the uart interrupts before updating anything + uart_irq_disable (self); + + if (self->uart_id == PYB_UART_0) { + MAP_IntPrioritySet(INT_UARTA0, priority); + MAP_UARTIntRegister(self->reg, UART0IntHandler); + } else { + MAP_IntPrioritySet(INT_UARTA1, priority); + MAP_UARTIntRegister(self->reg, UART1IntHandler); + } + + // create the callback + mp_obj_t _irq = mp_irq_new ((mp_obj_t)self, handler, &uart_irq_methods); + + // enable the interrupts now + self->irq_trigger = trigger; + uart_irq_enable (self); + return _irq; +} + STATIC void UARTGenericIntHandler(uint32_t uart_id) { pyb_uart_obj_t *self; uint32_t status; - bool exec_callback = false; self = &pyb_uart_obj[uart_id]; status = MAP_UARTIntStatus(self->reg, true); // receive interrupt if (status & (UART_INT_RX | UART_INT_RT)) { + // set the flags + self->irq_flags = UART_TRIGGER_RX_ANY; MAP_UARTIntClear(self->reg, UART_INT_RX | UART_INT_RT); while (UARTCharsAvail(self->reg)) { int data = MAP_UARTCharGetNonBlocking(self->reg); @@ -274,17 +275,16 @@ STATIC void UARTGenericIntHandler(uint32_t uart_id) { } } } - - if (self->irq_trigger & E_UART_TRIGGER_RX_ANY) { - exec_callback = true; - } - - if (exec_callback && self->callback_enabled) { - // call the user defined handler - mp_obj_t _callback = mpcallback_find(self); - mpcallback_handler(_callback); - } } + + // check the flags to see if the user handler should be called + if ((self->irq_trigger & self->irq_flags) && self->irq_enabled) { + // call the user defined handler + mp_irq_handler(mp_irq_find(self)); + } + + // clear the flags + self->irq_flags = 0; } STATIC void uart_check_init(pyb_uart_obj_t *self) { @@ -302,19 +302,24 @@ STATIC void UART1IntHandler(void) { UARTGenericIntHandler(1); } -STATIC void uart_callback_enable (mp_obj_t self_in) { +STATIC void uart_irq_enable (mp_obj_t self_in) { pyb_uart_obj_t *self = self_in; // check for any of the rx interrupt types - if (self->irq_trigger & (E_UART_TRIGGER_RX_ANY | E_UART_TRIGGER_RX_HALF | E_UART_TRIGGER_RX_FULL)) { + if (self->irq_trigger & (UART_TRIGGER_RX_ANY | UART_TRIGGER_RX_HALF | UART_TRIGGER_RX_FULL)) { MAP_UARTIntClear(self->reg, UART_INT_RX | UART_INT_RT); MAP_UARTIntEnable(self->reg, UART_INT_RX | UART_INT_RT); } - self->callback_enabled = true; + self->irq_enabled = true; } -STATIC void uart_callback_disable (mp_obj_t self_in) { +STATIC void uart_irq_disable (mp_obj_t self_in) { pyb_uart_obj_t *self = self_in; - self->callback_enabled = false; + self->irq_enabled = false; +} + +STATIC int uart_irq_flags (mp_obj_t self_in) { + pyb_uart_obj_t *self = self_in; + return self->irq_flags; } /******************************************************************************/ @@ -430,7 +435,9 @@ STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, const mp_arg_val_t *a // register it with the sleep module pybsleep_add ((const mp_obj_t)self, (WakeUpCB_t)uart_init); // enable the callback - uart_callback_new (self, mp_const_none, INT_PRIORITY_LVL_3, E_UART_TRIGGER_RX_ANY); + uart_irq_new (self, UART_TRIGGER_RX_ANY, INT_PRIORITY_LVL_3, mp_const_none); + // disable the irq (from the user point of view) + uart_irq_disable(self); return mp_const_none; @@ -531,33 +538,37 @@ STATIC mp_obj_t pyb_uart_sendbreak(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_sendbreak_obj, pyb_uart_sendbreak); -STATIC mp_obj_t pyb_uart_callback (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - mp_arg_val_t args[mpcallback_INIT_NUM_ARGS]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mpcallback_INIT_NUM_ARGS, mpcallback_init_args, args); +/// \method irq(trigger, priority, handler, wake) +STATIC mp_obj_t pyb_uart_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + mp_arg_val_t args[mp_irq_INIT_NUM_ARGS]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mp_irq_INIT_NUM_ARGS, mp_irq_init_args, args); // check if any parameters were passed pyb_uart_obj_t *self = pos_args[0]; uart_check_init(self); - mp_obj_t _callback = mpcallback_find((mp_obj_t)self); - if (kw_args->used > 0) { - // convert the priority to the correct value - uint priority = mpcallback_translate_priority (args[2].u_int); + // convert the priority to the correct value + uint priority = mp_irq_translate_priority (args[1].u_int); - // check the power mode - if (PYB_PWR_MODE_ACTIVE != args[4].u_int) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); - } - - // register a new callback - // FIXME triggers!! - return uart_callback_new (self, args[1].u_obj, mp_obj_get_int(args[3].u_obj), priority); - } else if (!_callback) { - _callback = mpcallback_new (self, mp_const_none, &uart_cb_methods, false); + // check the power mode + uint8_t pwrmode = (args[3].u_obj == mp_const_none) ? PYB_PWR_MODE_ACTIVE : mp_obj_get_int(args[3].u_obj); + if (PYB_PWR_MODE_ACTIVE != pwrmode) { + goto invalid_args; } - return _callback; + + // check the trigger + uint trigger = mp_obj_get_int(args[0].u_obj); + if (!trigger || trigger > (UART_TRIGGER_RX_ANY | UART_TRIGGER_RX_HALF | UART_TRIGGER_RX_FULL | UART_TRIGGER_TX_DONE)) { + goto invalid_args; + } + + // register a new callback + return uart_irq_new (self, trigger, priority, args[2].u_obj); + +invalid_args: + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); } -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_callback_obj, 1, pyb_uart_callback); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_callback_obj, 1, pyb_uart_irq); STATIC const mp_map_elem_t pyb_uart_locals_dict_table[] = { // instance methods @@ -565,7 +576,7 @@ STATIC const mp_map_elem_t pyb_uart_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&pyb_uart_deinit_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_any), (mp_obj_t)&pyb_uart_any_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_sendbreak), (mp_obj_t)&pyb_uart_sendbreak_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&pyb_uart_callback_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_irq), (mp_obj_t)&pyb_uart_callback_obj }, /// \method read([nbytes]) { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj }, @@ -581,7 +592,7 @@ STATIC const mp_map_elem_t pyb_uart_locals_dict_table[] = { // class constants { MP_OBJ_NEW_QSTR(MP_QSTR_EVEN), MP_OBJ_NEW_SMALL_INT(UART_CONFIG_PAR_EVEN) }, { MP_OBJ_NEW_QSTR(MP_QSTR_ODD), MP_OBJ_NEW_SMALL_INT(UART_CONFIG_PAR_ODD) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_RX_ANY), MP_OBJ_NEW_SMALL_INT(E_UART_TRIGGER_RX_ANY) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_RX_ANY), MP_OBJ_NEW_SMALL_INT(UART_TRIGGER_RX_ANY) }, }; STATIC MP_DEFINE_CONST_DICT(pyb_uart_locals_dict, pyb_uart_locals_dict_table); @@ -654,10 +665,11 @@ STATIC const mp_stream_p_t uart_stream_p = { .is_text = false, }; -STATIC const mp_cb_methods_t uart_cb_methods = { - .init = pyb_uart_callback, - .enable = uart_callback_enable, - .disable = uart_callback_disable, +STATIC const mp_irq_methods_t uart_irq_methods = { + .init = pyb_uart_irq, + .enable = uart_irq_enable, + .disable = uart_irq_disable, + .flags = uart_irq_flags }; const mp_obj_type_t pyb_uart_type = { diff --git a/cc3200/mods/pybuart.h b/cc3200/mods/pybuart.h index 89f3edc0e..74871cbab 100644 --- a/cc3200/mods/pybuart.h +++ b/cc3200/mods/pybuart.h @@ -43,6 +43,5 @@ int uart_rx_char(pyb_uart_obj_t *uart_obj); bool uart_tx_char(pyb_uart_obj_t *self, int c); bool uart_tx_strn(pyb_uart_obj_t *uart_obj, const char *str, uint len); void uart_tx_strn_cooked(pyb_uart_obj_t *uart_obj, const char *str, uint len); -mp_obj_t uart_callback_new (pyb_uart_obj_t *self, mp_obj_t handler, mp_int_t priority, byte trigger); #endif // PYBUART_H_ diff --git a/cc3200/mpconfigport.h b/cc3200/mpconfigport.h index aed07bdca..7c0a69327 100644 --- a/cc3200/mpconfigport.h +++ b/cc3200/mpconfigport.h @@ -160,7 +160,7 @@ extern const struct _mp_obj_module_t mp_module_ussl; mp_obj_t mp_const_user_interrupt; \ mp_obj_t pyb_config_main; \ mp_obj_list_t pybsleep_obj_list; \ - mp_obj_list_t mpcallback_obj_list; \ + mp_obj_list_t mp_irq_obj_list; \ mp_obj_list_t pyb_timer_channel_obj_list; \ mp_obj_list_t mount_obj_list; \ struct _pyb_uart_obj_t *pyb_uart_objs[2]; \ diff --git a/cc3200/mptask.c b/cc3200/mptask.c index ec342e2d0..4f01a66eb 100644 --- a/cc3200/mptask.c +++ b/cc3200/mptask.c @@ -64,8 +64,8 @@ #include "pins.h" #include "pybsleep.h" #include "pybtimer.h" -#include "mpcallback.h" #include "cryptohash.h" +#include "mpirq.h" #include "updater.h" #include "moduos.h" @@ -126,7 +126,7 @@ soft_reset: // execute all basic initializations mpexception_init0(); - mpcallback_init0(); + mp_irq_init0(); pybsleep_init0(); pin_init0(); mperror_init0(); @@ -234,7 +234,10 @@ soft_reset_exit: // disable all callbacks to avoid undefined behaviour // when coming out of a soft reset - mpcallback_disable_all(); + mp_irq_disable_all(); + + // cancel the RTC alarm which might be running independent of the irq state + pyb_rtc_disable_alarm(); // flush the serial flash buffer sflash_disk_flush(); diff --git a/cc3200/qstrdefsport.h b/cc3200/qstrdefsport.h index 9ccdf829f..5c619e1cd 100644 --- a/cc3200/qstrdefsport.h +++ b/cc3200/qstrdefsport.h @@ -179,10 +179,12 @@ Q(RTC) Q(init) Q(alarm) Q(alarm_left) +Q(alarm_cancel) Q(now) Q(deinit) Q(datetime) Q(repeat) +Q(ALARM0) // for time class Q(time) @@ -292,6 +294,7 @@ Q(WPA) Q(WPA2) Q(INTERNAL) Q(EXTERNAL) +Q(ANY_EVENT) // for WDT class Q(WDT) @@ -303,16 +306,16 @@ Q(HeartBeat) Q(enable) Q(disable) -// for callback class +// for irq class +Q(irq) Q(init) Q(enable) Q(disable) -Q(callback) +Q(flags) +Q(trigger) Q(handler) -Q(mode) -Q(value) Q(priority) -Q(wake_from) +Q(wake) // for Sleep class Q(Sleep) diff --git a/cc3200/util/random.c b/cc3200/util/random.c index 470d95d3a..baa2db62e 100644 --- a/cc3200/util/random.c +++ b/cc3200/util/random.c @@ -32,14 +32,13 @@ #include "inc/hw_ints.h" #include "inc/hw_memmap.h" #include "rom_map.h" -#include "prcm.h" +#include "pybrtc.h" #include "simplelink.h" #include "modnetwork.h" #include "modwlan.h" #include "random.h" #include "debug.h" - /****************************************************************************** * LOCAL TYPES ******************************************************************************/ @@ -57,16 +56,19 @@ static uint32_t s_seed; /****************************************************************************** * LOCAL FUNCTION DECLARATIONS ******************************************************************************/ -static uint32_t lfsr (uint32_t input); +STATIC uint32_t lfsr (uint32_t input); /****************************************************************************** * PRIVATE FUNCTIONS ******************************************************************************/ -static uint32_t lfsr (uint32_t input) { +STATIC uint32_t lfsr (uint32_t input) { assert( input != 0 ); return (input >> 1) ^ (-(input & 0x01) & 0x00E10000); } +/******************************************************************************/ +// Micro Python bindings; + STATIC mp_obj_t pyb_rng_get(void) { return mp_obj_new_int(rng_get()); } @@ -81,7 +83,7 @@ void rng_init0 (void) { uint16_t mseconds; // get the seconds and the milliseconds from the RTC - MAP_PRCMRTCGet(&seconds, &mseconds); + pyb_rtc_get_time(&seconds, &mseconds); wlan_get_mac (juggler.id8); diff --git a/tests/wipy/pin_irq.py b/tests/wipy/pin_irq.py new file mode 100644 index 000000000..75a7f090d --- /dev/null +++ b/tests/wipy/pin_irq.py @@ -0,0 +1,116 @@ +''' +Pin IRQ test for the CC3200 based boards. +''' + +from pyb import Pin +from pyb import Sleep +import os +import time + +machine = os.uname().machine +if 'LaunchPad' in machine: + pins = ['GP16', 'GP13'] +elif 'WiPy' in machine: + pins = ['GP16', 'GP13'] +else: + raise Exception('Board not supported!') + +pin0 = Pin(pins[0], mode=Pin.OUT, value=1) +pin1 = Pin(pins[1], mode=Pin.IN, pull=Pin.PULL_UP) + +def pin_handler (pin_o): + global pin_irq_count_trigger + global pin_irq_count_total + global _trigger + if _trigger & pin1_irq.flags(): + pin_irq_count_trigger += 1 + pin_irq_count_total += 1 + +pin_irq_count_trigger = 0 +pin_irq_count_total = 0 +_trigger = Pin.IRQ_FALLING +pin1_irq = pin1.irq(trigger=_trigger, handler=pin_handler) +for i in range (0, 10): + pin0.toggle() + time.sleep_ms(5) +print(pin_irq_count_trigger == 5) +print(pin_irq_count_total == 5) + +pin_irq_count_trigger = 0 +pin_irq_count_total = 0 +_trigger = Pin.IRQ_RISING +pin1_irq = pin1.irq(trigger=_trigger, handler=pin_handler) +for i in range (0, 200): + pin0.toggle() + time.sleep_ms(5) +print(pin_irq_count_trigger == 100) +print(pin_irq_count_total == 100) + +pin1_irq.disable() +pin0(1) +pin_irq_count_trigger = 0 +pin_irq_count_total = 0 +_trigger = Pin.IRQ_FALLING +pin1_irq.init(trigger=_trigger, handler=pin_handler) +pin0(0) +time.sleep_us(50) +print(pin_irq_count_trigger == 1) +print(pin_irq_count_total == 1) +pin0(1) +time.sleep_us(50) +print(pin_irq_count_trigger == 1) +print(pin_irq_count_total == 1) + +# check the call method +pin1_irq() +print(pin_irq_count_trigger == 1) # no flags since the irq was manually triggered +print(pin_irq_count_total == 2) + +pin1_irq.disable() +pin_irq_count_trigger = 0 +pin_irq_count_total = 0 +for i in range (0, 10): + pin0.toggle() + time.sleep_ms(5) +print(pin_irq_count_trigger == 0) +print(pin_irq_count_total == 0) + +# test waking up from suspended mode on low level +pin0(0) +t0 = time.ticks_ms() +pin1_irq.init(trigger=Pin.IRQ_LOW_LEVEL, wake=Sleep.SUSPENDED) +Sleep.suspend() +print(time.ticks_ms() - t0 < 10) +print('Awake') + +# test waking up from suspended mode on high level +pin0(1) +t0 = time.ticks_ms() +pin1_irq.init(trigger=Pin.IRQ_HIGH_LEVEL, wake=Sleep.SUSPENDED) +Sleep.suspend() +print(time.ticks_ms() - t0 < 10) +print('Awake') + +# check for memory leaks +for i in range(0, 1000): + pin0_irq = pin0.irq(trigger=_trigger, handler=pin_handler) + pin1_irq = pin1.irq(trigger=_trigger, handler=pin_handler) + +# next ones must raise +try: + pin1_irq.init(trigger=123456, handler=pin_handler) +except: + print('Exception') + +try: + pin1_irq.init(trigger=Pin.IRQ_LOW_LEVEL, wake=1789456) +except: + print('Exception') + +try: + pin0_irq = pin0.irq(trigger=Pin.IRQ_RISING, wake=Sleep.SUSPENDED) # GP16 can't wake up from DEEPSLEEP +except: + print('Exception') + +pin0_irq.disable() +pin1_irq.disable() diff --git a/tests/wipy/pin_irq.py.exp b/tests/wipy/pin_irq.py.exp new file mode 100644 index 000000000..458bd9566 --- /dev/null +++ b/tests/wipy/pin_irq.py.exp @@ -0,0 +1,19 @@ +True +True +True +True +True +True +True +True +True +True +True +True +True +Awake +True +Awake +Exception +Exception +Exception diff --git a/tests/wipy/rtc.py b/tests/wipy/rtc.py index 4114796db..9f4a0f673 100644 --- a/tests/wipy/rtc.py +++ b/tests/wipy/rtc.py @@ -66,17 +66,22 @@ rtc.alarm(0, 5000) rtc.alarm(time=2000) time.sleep_ms(1000) left = rtc.alarm_left() -print(abs(left-1000) < 20) +print(abs(left-1000) <= 10) time.sleep_ms(1000) print(rtc.alarm_left() == 0) time.sleep_ms(100) -print(rtc.alarm_left() == 0) +print(rtc.alarm_left(0) == 0) + +rtc.alarm(time=1000, repeat=True) +time.sleep_ms(1500) +left = rtc.alarm_left() +print(abs(left-500) <= 15) rtc.init((2015, 8, 29, 9, 0, 0, 0, None)) rtc.alarm(time=(2015, 8, 29, 9, 0, 45)) time.sleep_ms(1000) left = rtc.alarm_left() -print(abs(left-44000) < 100) +print(abs(left-44000) <= 90) # next ones must raise try: @@ -84,6 +89,16 @@ try: except: print('Exception') +try: + rtc.alarm_left(1) +except: + print('Exception') + +try: + rtc.alarm_cancel(1) +except: + print('Exception') + try: rtc.alarm(5000) except: diff --git a/tests/wipy/rtc.py.exp b/tests/wipy/rtc.py.exp index 8225f4602..44f8f8b81 100644 --- a/tests/wipy/rtc.py.exp +++ b/tests/wipy/rtc.py.exp @@ -28,6 +28,9 @@ True True True True +True +Exception +Exception Exception Exception Exception diff --git a/tests/wipy/rtc_irq.py b/tests/wipy/rtc_irq.py new file mode 100644 index 000000000..1c9ea93f1 --- /dev/null +++ b/tests/wipy/rtc_irq.py @@ -0,0 +1,89 @@ +''' +RTC IRQ test for the CC3200 based boards. +''' + +from pyb import RTC +from pyb import Sleep +import os +import time + +machine = os.uname().machine +if not 'LaunchPad' in machine and not 'WiPy' in machine: + raise Exception('Board not supported!') + +def rtc_ticks_ms(rtc): + timedate = rtc.now() + return (timedate[5] * 1000) + (timedate[6] // 1000) + +rtc_irq_count = 0 + +def alarm_handler (rtc_o): + global rtc_irq + global rtc_irq_count + if rtc_irq.flags() & RTC.ALARM0: + rtc_irq_count += 1 + +rtc = RTC() +rtc.alarm(time=500, repeat=True) +rtc_irq = rtc.irq(trigger=RTC.ALARM0, handler=alarm_handler) + +# active mode +time.sleep_ms(1000) +rtc.alarm_cancel() +print(rtc_irq_count == 2) +rtc_irq_count = 0 +rtc.alarm(time=200, repeat=True) +time.sleep_ms(1000) +rtc.alarm_cancel() +print(rtc_irq_count == 5) + +rtc_irq_count = 0 +rtc.alarm(time=100, repeat=True) +time.sleep_ms(1000) +rtc.alarm_cancel() +print(rtc_irq_count == 10) + +# deep sleep mode +rtc.alarm_cancel() +rtc_irq_count = 0 +rtc.alarm(time=50, repeat=True) +rtc_irq.init(trigger=RTC.ALARM0, handler=alarm_handler, wake=Sleep.SUSPENDED | Sleep.ACTIVE) +while rtc_irq_count < 3: + Sleep.suspend() +print(rtc_irq_count == 3) + +# no repetition +rtc.alarm_cancel() +rtc_irq_count = 0 +rtc.alarm(time=100, repeat=False) +time.sleep_ms(250) +print(rtc_irq_count == 1) + +rtc.alarm_cancel() +t0 = rtc_ticks_ms(rtc) +rtc.alarm(time=500, repeat=False) +Sleep.suspend() +t1 = rtc_ticks_ms(rtc) +print(abs(t1 - t0 - 500) < 20) + +# deep sleep repeated mode +rtc.alarm_cancel() +rtc_irq_count = 0 +rtc.alarm(time=250, repeat=True) +t0 = rtc_ticks_ms(rtc) +rtc_irq = rtc.irq(trigger=RTC.ALARM0, handler=alarm_handler, wake=Sleep.SUSPENDED) +while rtc_irq_count < 10: + Sleep.suspend() + t1 = rtc_ticks_ms(rtc) + print(abs(t1 - t0 - (250 * rtc_irq_count)) < 25) + +# next ones must raise +try: + rtc_irq = rtc.irq(trigger=10, handler=alarm_handler) +except: + print('Exception') + +try: + rtc_irq = rtc.irq(trigger=RTC.ALARM0, wake=1789456) +except: + print('Exception') diff --git a/tests/wipy/rtc_irq.py.exp b/tests/wipy/rtc_irq.py.exp new file mode 100644 index 000000000..a9ef48c7a --- /dev/null +++ b/tests/wipy/rtc_irq.py.exp @@ -0,0 +1,18 @@ +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +Exception +Exception diff --git a/tests/wipy/uart_irq.py b/tests/wipy/uart_irq.py new file mode 100644 index 000000000..3f1084cce --- /dev/null +++ b/tests/wipy/uart_irq.py @@ -0,0 +1,149 @@ +''' +UART IRQ test for the CC3200 based boards. +''' + +from pyb import UART +import os +import pyb +import time + +machine = os.uname().machine +if 'LaunchPad' in machine: + uart_pins = [[('GP12', 'GP13'), ('GP12', 'GP13', 'GP7', 'GP6')], [('GP16', 'GP17'), ('GP16', 'GP17', 'GP7', 'GP6')]] +elif 'WiPy' in machine: + uart_pins = [[('GP12', 'GP13'), ('GP12', 'GP13', 'GP7', 'GP6')], [('GP16', 'GP17'), ('GP16', 'GP17', 'GP7', 'GP6')]] +else: + raise Exception('Board not supported!') + +# just in case we have stdio duplicated on any of the uarts +pyb.repl_uart(None) + +uart0 = UART(0, 1000000, pins=uart_pins[0][0]) +uart1 = UART(1, 1000000, pins=uart_pins[1][0]) + +uart0_int_count = 0 +uart1_int_count = 0 + +def uart0_handler (uart_o): + global uart0_irq + global uart0_int_count + if (uart0_irq.flags() & UART.RX_ANY): + uart0_int_count += 1 + +def uart1_handler (uart_o): + global uart1_irq + global uart1_int_count + if (uart1_irq.flags() & UART.RX_ANY): + uart1_int_count += 1 + +uart0_irq = uart0.irq(trigger=UART.RX_ANY, handler=uart0_handler) +uart1_irq = uart1.irq(trigger=UART.RX_ANY, handler=uart1_handler) + +uart0.write(b'123') +# wait for the characters to be received +while not uart1.any(): + pass + +time.sleep_us(100) +print(uart1.any() == 3) +print(uart1_int_count > 0) +print(uart1_irq.flags() == 0) +print(uart0_irq.flags() == 0) +print(uart1.read() == b'123') + +uart1.write(b'12345') +# wait for the characters to be received +while not uart0.any(): + pass + +time.sleep_us(100) +print(uart0.any() == 5) +print(uart0_int_count > 0) +print(uart0_irq.flags() == 0) +print(uart1_irq.flags() == 0) +print(uart0.read() == b'12345') + +# do it again +uart1_int_count = 0 +uart0.write(b'123') +# wait for the characters to be received +while not uart1.any(): + pass + +time.sleep_us(100) +print(uart1.any() == 3) +print(uart1_int_count > 0) +print(uart1_irq.flags() == 0) +print(uart0_irq.flags() == 0) +print(uart1.read() == b'123') + +# disable the interrupt +uart1_irq.disable() +# do it again +uart1_int_count = 0 +uart0.write(b'123') +# wait for the characters to be received +while not uart1.any(): + pass + +time.sleep_us(100) +print(uart1.any() == 3) +print(uart1_int_count == 0) # no interrupt triggered this time +print(uart1_irq.flags() == 0) +print(uart0_irq.flags() == 0) +print(uart1.read() == b'123') + +# enable the interrupt +uart1_irq.enable() +# do it again +uart1_int_count = 0 +uart0.write(b'123') +# wait for the characters to be received +while not uart1.any(): + pass + +time.sleep_us(100) +print(uart1.any() == 3) +print(uart1_int_count > 0) +print(uart1_irq.flags() == 0) +print(uart0_irq.flags() == 0) +print(uart1.read() == b'123') + +uart1_irq.init(trigger=UART.RX_ANY, handler=None) # No handler +# do it again +uart1_int_count = 0 +uart0.write(b'123') +# wait for the characters to be received +while not uart1.any(): + pass + +time.sleep_us(100) +print(uart1.any() == 3) +print(uart1_int_count == 0) # no interrupt handler called +print(uart1_irq.flags() == 0) +print(uart0_irq.flags() == 0) +print(uart1.read() == b'123') + +# check for memory leaks +for i in range(0, 1000): + uart0_irq = uart0.irq(trigger=UART.RX_ANY, handler=uart0_handler) + uart1_irq = uart1.irq(trigger=UART.RX_ANY, handler=uart1_handler) + +# next ones must raise +try: + uart0_irq = uart0.irq(trigger=100, handler=uart0_handler) +except: + print('Exception') + +try: + uart0_irq = uart0.irq(trigger=0) +except: + print('Exception') + +try: + uart0_irq = uart0.irq(trigger=UART.RX_ANY, wake=Sleep.SUSPENDED) +except: + print('Exception') + +uart0_irq.disable() +uart1_irq.disable() diff --git a/tests/wipy/uart_irq.py.exp b/tests/wipy/uart_irq.py.exp new file mode 100644 index 000000000..b165e824a --- /dev/null +++ b/tests/wipy/uart_irq.py.exp @@ -0,0 +1,33 @@ +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +Exception +Exception +Exception