LCOV - code coverage report
Current view: top level - examples/usercmodule/cexample - examplemodule.c (source / functions) Hit Total Coverage
Test: unix_coverage_v1.24.0-161-gc73204128.info Lines: 33 33 100.0 %
Date: 2024-12-23 07:29:41 Functions: 5 5 100.0 %
Branches: 8 10 80.0 %

           Branch data     Line data    Source code
       1                 :            : // Include MicroPython API.
       2                 :            : #include "py/runtime.h"
       3                 :            : 
       4                 :            : // Used to get the time in the Timer class example.
       5                 :            : #include "py/mphal.h"
       6                 :            : 
       7                 :            : // This is the function which will be called from Python as cexample.add_ints(a, b).
       8                 :          2 : static mp_obj_t example_add_ints(mp_obj_t a_obj, mp_obj_t b_obj) {
       9                 :            :     // Extract the ints from the micropython input objects.
      10                 :          2 :     int a = mp_obj_get_int(a_obj);
      11                 :          2 :     int b = mp_obj_get_int(b_obj);
      12                 :            : 
      13                 :            :     // Calculate the addition and convert to MicroPython object.
      14                 :          2 :     return mp_obj_new_int(a + b);
      15                 :            : }
      16                 :            : // Define a Python reference to the function above.
      17                 :            : static MP_DEFINE_CONST_FUN_OBJ_2(example_add_ints_obj, example_add_ints);
      18                 :            : 
      19                 :            : // This structure represents Timer instance objects.
      20                 :            : typedef struct _example_Timer_obj_t {
      21                 :            :     // All objects start with the base.
      22                 :            :     mp_obj_base_t base;
      23                 :            :     // Everything below can be thought of as instance attributes, but they
      24                 :            :     // cannot be accessed by MicroPython code directly. In this example we
      25                 :            :     // store the time at which the object was created.
      26                 :            :     mp_uint_t start_time;
      27                 :            : } example_Timer_obj_t;
      28                 :            : 
      29                 :            : // This is the Timer.time() method. After creating a Timer object, this
      30                 :            : // can be called to get the time elapsed since creating the Timer.
      31                 :         12 : static mp_obj_t example_Timer_time(mp_obj_t self_in) {
      32                 :            :     // The first argument is self. It is cast to the *example_Timer_obj_t
      33                 :            :     // type so we can read its attributes.
      34                 :         12 :     example_Timer_obj_t *self = MP_OBJ_TO_PTR(self_in);
      35                 :            : 
      36                 :            :     // Get the elapsed time and return it as a MicroPython integer.
      37                 :         12 :     mp_uint_t elapsed = mp_hal_ticks_ms() - self->start_time;
      38                 :         12 :     return mp_obj_new_int_from_uint(elapsed);
      39                 :            : }
      40                 :            : static MP_DEFINE_CONST_FUN_OBJ_1(example_Timer_time_obj, example_Timer_time);
      41                 :            : 
      42                 :            : // This represents Timer.__new__ and Timer.__init__, which is called when
      43                 :            : // the user instantiates a Timer object.
      44                 :          6 : static mp_obj_t example_Timer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
      45                 :            :     // Allocates the new object and sets the type.
      46                 :          6 :     example_Timer_obj_t *self = mp_obj_malloc(example_Timer_obj_t, type);
      47                 :            : 
      48                 :            :     // Initializes the time for this Timer instance.
      49                 :          6 :     self->start_time = mp_hal_ticks_ms();
      50                 :            : 
      51                 :            :     // The make_new function always returns self.
      52                 :          6 :     return MP_OBJ_FROM_PTR(self);
      53                 :            : }
      54                 :            : 
      55                 :            : // This collects all methods and other static class attributes of the Timer.
      56                 :            : // The table structure is similar to the module table, as detailed below.
      57                 :            : static const mp_rom_map_elem_t example_Timer_locals_dict_table[] = {
      58                 :            :     { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&example_Timer_time_obj) },
      59                 :            : };
      60                 :            : static MP_DEFINE_CONST_DICT(example_Timer_locals_dict, example_Timer_locals_dict_table);
      61                 :            : 
      62                 :            : // This defines the type(Timer) object.
      63                 :            : MP_DEFINE_CONST_OBJ_TYPE(
      64                 :            :     example_type_Timer,
      65                 :            :     MP_QSTR_Timer,
      66                 :            :     MP_TYPE_FLAG_NONE,
      67                 :            :     make_new, example_Timer_make_new,
      68                 :            :     locals_dict, &example_Timer_locals_dict
      69                 :            :     );
      70                 :            : 
      71                 :            : // What follows is a *separate* class definition that demonstrates more
      72                 :            : // advanced techniques to implement other Python-like features, such as:
      73                 :            : //
      74                 :            : // - A custom representation for __repr__ and __str__.
      75                 :            : // - Custom attribute handling to create a read/write "property".
      76                 :            : //
      77                 :            : // It re-uses some of the elements of the basic Timer class. This is allowed
      78                 :            : // because they both use example_Timer_obj_t as the instance structure.
      79                 :            : 
      80                 :            : // Handles AdvancedTimer.__repr__, AdvancedTimer.__str__.
      81                 :          4 : static void example_AdvancedTimer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
      82                 :            : 
      83                 :            :     // Get the elapsed time. In this case, it's also a demonstration of calling
      84                 :            :     // the equivalent of self.time() in the C API. This is not usually very
      85                 :            :     // efficient, but it can sometimes be useful.
      86                 :          4 :     mp_uint_t elapsed = mp_obj_get_int(example_Timer_time(self_in));
      87                 :            : 
      88                 :            :     // We'll make all representations print at least the class name.
      89                 :          4 :     mp_printf(print, "%q()", MP_QSTR_AdvancedTimer);
      90                 :            : 
      91                 :            :     // Decide what else to print based on print kind.
      92         [ +  + ]:          4 :     if (kind == PRINT_STR) {
      93                 :            :         // For __str__, let's attempt to make it more readable.
      94                 :          2 :         mp_printf(print, "  # created %d seconds ago", elapsed / 1000);
      95                 :            :     }
      96                 :          4 : }
      97                 :            : 
      98                 :            : // Handles AdvancedTimer.seconds for reading and writing.
      99                 :         12 : static void example_AdvancedTimer_attribute_handler(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
     100                 :            : 
     101                 :            :     // In this example, we only want to handle the .seconds attribute in a
     102                 :            :     // special way.
     103         [ +  + ]:         12 :     if (attr != MP_QSTR_seconds) {
     104                 :            :         // Attribute not found, continue lookup in locals dict. This way,
     105                 :            :         // methods like .time() will be handled normally.
     106                 :          2 :         dest[1] = MP_OBJ_SENTINEL;
     107                 :          2 :         return;
     108                 :            :     }
     109                 :            : 
     110                 :            :     // Get reference to AdvancedTimer instance.
     111                 :         10 :     example_Timer_obj_t *self = MP_OBJ_TO_PTR(self_in);
     112                 :            : 
     113                 :            :     // Check if this is a read operation.
     114         [ +  + ]:         10 :     if (dest[0] == MP_OBJ_NULL) {
     115                 :            :         // It's read, so "return" elapsed seconds by storing it in dest[0].
     116                 :          6 :         mp_uint_t elapsed = mp_hal_ticks_ms() - self->start_time;
     117                 :          6 :         dest[0] = mp_obj_new_int_from_uint(elapsed / 1000);
     118                 :          6 :         return;
     119                 :            :     }
     120                 :            :     // Check if this is a delete or store operation.
     121         [ +  - ]:          4 :     else if (dest[0] == MP_OBJ_SENTINEL) {
     122                 :            :         // It's delete or store. Now check which one.
     123         [ +  - ]:          4 :         if (dest[1] == MP_OBJ_NULL) {
     124                 :            :             // It's delete. But in this example we don't want to allow it
     125                 :            :             // so we just return.
     126                 :            :             return;
     127                 :            :         } else {
     128                 :            :             // It's write. First, get the value that the user is trying to set.
     129                 :          4 :             mp_uint_t desired_ms = mp_obj_get_int(dest[1]) * 1000;
     130                 :            :             // Use it to update the start time. This way, the next read will
     131                 :            :             // report the updated time.
     132                 :          2 :             self->start_time = mp_hal_ticks_ms() - desired_ms;
     133                 :            : 
     134                 :            :             // Indicate successful store.
     135                 :          2 :             dest[0] = MP_OBJ_NULL;
     136                 :          2 :             return;
     137                 :            :         }
     138                 :            :     }
     139                 :            : }
     140                 :            : 
     141                 :            : // This defines the type(AdvancedTimer) object.
     142                 :            : MP_DEFINE_CONST_OBJ_TYPE(
     143                 :            :     example_type_AdvancedTimer,
     144                 :            :     MP_QSTR_AdvancedTimer,
     145                 :            :     MP_TYPE_FLAG_NONE,
     146                 :            :     attr, example_AdvancedTimer_attribute_handler,
     147                 :            :     print, example_AdvancedTimer_print,
     148                 :            :     make_new, example_Timer_make_new,
     149                 :            :     locals_dict, &example_Timer_locals_dict
     150                 :            :     );
     151                 :            : 
     152                 :            : // Define all attributes of the module.
     153                 :            : // Table entries are key/value pairs of the attribute name (a string)
     154                 :            : // and the MicroPython object reference.
     155                 :            : // All identifiers and strings are written as MP_QSTR_xxx and will be
     156                 :            : // optimized to word-sized integers by the build system (interned strings).
     157                 :            : static const mp_rom_map_elem_t example_module_globals_table[] = {
     158                 :            :     { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_cexample) },
     159                 :            :     { MP_ROM_QSTR(MP_QSTR_add_ints), MP_ROM_PTR(&example_add_ints_obj) },
     160                 :            :     { MP_ROM_QSTR(MP_QSTR_Timer),    MP_ROM_PTR(&example_type_Timer) },
     161                 :            :     { MP_ROM_QSTR(MP_QSTR_AdvancedTimer),    MP_ROM_PTR(&example_type_AdvancedTimer) },
     162                 :            : };
     163                 :            : static MP_DEFINE_CONST_DICT(example_module_globals, example_module_globals_table);
     164                 :            : 
     165                 :            : // Define module object.
     166                 :            : const mp_obj_module_t example_user_cmodule = {
     167                 :            :     .base = { &mp_type_module },
     168                 :            :     .globals = (mp_obj_dict_t *)&example_module_globals,
     169                 :            : };
     170                 :            : 
     171                 :            : // Register the module to make it available in Python.
     172                 :            : MP_REGISTER_MODULE(MP_QSTR_cexample, example_user_cmodule);

Generated by: LCOV version 1.15-5-g462f71d