diff options
author | Laurens Valk <laurens@pybricks.com> | 2022-12-05 16:51:20 +0100 |
---|---|---|
committer | Damien George <damien@micropython.org> | 2024-07-25 11:57:13 +1000 |
commit | 19b1333cb1376ef60376a07e8e76a41854014840 (patch) | |
tree | 71527e14bca10b0be10e2e52c655baa35f39dfe5 /examples/usercmodule/cexample/examplemodule.c | |
parent | 7fe8f030eea0015962e729eae1f1c309dc83a469 (diff) | |
download | micropython-19b1333cb1376ef60376a07e8e76a41854014840.tar.gz micropython-19b1333cb1376ef60376a07e8e76a41854014840.zip |
examples/usercmodule/cexample: Add more advanced native class.
This adds a separate `AdvancedTimer` class that demonstrates a few more
advanced concepts usch as custom handlers for printing and attributes.
Signed-off-by: Laurens Valk <laurens@pybricks.com>
Diffstat (limited to 'examples/usercmodule/cexample/examplemodule.c')
-rw-r--r-- | examples/usercmodule/cexample/examplemodule.c | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/examples/usercmodule/cexample/examplemodule.c b/examples/usercmodule/cexample/examplemodule.c index 2988fbd565..d13515e72c 100644 --- a/examples/usercmodule/cexample/examplemodule.c +++ b/examples/usercmodule/cexample/examplemodule.c @@ -68,6 +68,87 @@ MP_DEFINE_CONST_OBJ_TYPE( locals_dict, &example_Timer_locals_dict ); +// What follows is a *separate* class definition that demonstrates more +// advanced techniques to implement other Python-like features, such as: +// +// - A custom representation for __repr__ and __str__. +// - Custom attribute handling to create a read/write "property". +// +// It re-uses some of the elements of the basic Timer class. This is allowed +// because they both use example_Timer_obj_t as the instance structure. + +// Handles AdvancedTimer.__repr__, AdvancedTimer.__str__. +static void example_AdvancedTimer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + + // Get the elapsed time. In this case, it's also a demonstration of calling + // the equivalent of self.time() in the C API. This is not usually very + // efficient, but it can sometimes be useful. + mp_uint_t elapsed = mp_obj_get_int(example_Timer_time(self_in)); + + // We'll make all representations print at least the class name. + mp_printf(print, "%q()", MP_QSTR_AdvancedTimer); + + // Decide what else to print based on print kind. + if (kind == PRINT_STR) { + // For __str__, let's attempt to make it more readable. + mp_printf(print, " # created %d seconds ago", elapsed / 1000); + } +} + +// Handles AdvancedTimer.seconds for reading and writing. +static void example_AdvancedTimer_attribute_handler(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + + // In this example, we only want to handle the .seconds attribute in a + // special way. + if (attr != MP_QSTR_seconds) { + // Attribute not found, continue lookup in locals dict. This way, + // methods like .time() will be handled normally. + dest[1] = MP_OBJ_SENTINEL; + return; + } + + // Get reference to AdvancedTimer instance. + example_Timer_obj_t *self = MP_OBJ_TO_PTR(self_in); + + // Check if this is a read operation. + if (dest[0] == MP_OBJ_NULL) { + // It's read, so "return" elapsed seconds by storing it in dest[0]. + mp_uint_t elapsed = mp_hal_ticks_ms() - self->start_time; + dest[0] = mp_obj_new_int_from_uint(elapsed / 1000); + return; + } + // Check if this is a delete or store operation. + else if (dest[0] == MP_OBJ_SENTINEL) { + // It's delete or store. Now check which one. + if (dest[1] == MP_OBJ_NULL) { + // It's delete. But in this example we don't want to allow it + // so we just return. + return; + } else { + // It's write. First, get the value that the user is trying to set. + mp_uint_t desired_ms = mp_obj_get_int(dest[1]) * 1000; + // Use it to update the start time. This way, the next read will + // report the updated time. + self->start_time = mp_hal_ticks_ms() - desired_ms; + + // Indicate successful store. + dest[0] = MP_OBJ_NULL; + return; + } + } +} + +// This defines the type(AdvancedTimer) object. +MP_DEFINE_CONST_OBJ_TYPE( + example_type_AdvancedTimer, + MP_QSTR_AdvancedTimer, + MP_TYPE_FLAG_NONE, + attr, example_AdvancedTimer_attribute_handler, + print, example_AdvancedTimer_print, + make_new, example_Timer_make_new, + locals_dict, &example_Timer_locals_dict + ); + // Define all attributes of the module. // Table entries are key/value pairs of the attribute name (a string) // and the MicroPython object reference. @@ -77,6 +158,7 @@ static const mp_rom_map_elem_t example_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_cexample) }, { MP_ROM_QSTR(MP_QSTR_add_ints), MP_ROM_PTR(&example_add_ints_obj) }, { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&example_type_Timer) }, + { MP_ROM_QSTR(MP_QSTR_AdvancedTimer), MP_ROM_PTR(&example_type_AdvancedTimer) }, }; static MP_DEFINE_CONST_DICT(example_module_globals, example_module_globals_table); |