|
| 1 | +/* This example demonstrates the following features in a native module: |
| 2 | + - defining simple functions exposed to Python |
| 3 | + - defining local, helper C functions |
| 4 | + - defining constant integers and strings exposed to Python |
| 5 | + - getting and creating integer objects |
| 6 | + - creating Python lists |
| 7 | + - raising exceptions |
| 8 | + - allocating memory |
| 9 | + - BSS and constant data (rodata) |
| 10 | + - relocated pointers in rodata |
| 11 | +*/ |
| 12 | + |
| 13 | +// Include the header file to get access to the MicroPython API |
| 14 | +#include "py/dynruntime.h" |
| 15 | + |
| 16 | +// BSS (zero) data |
| 17 | +uint16_t data16[4]; |
| 18 | + |
| 19 | +// Constant data (rodata) |
| 20 | +const uint8_t table8[] = { 0, 1, 1, 2, 3, 5, 8, 13 }; |
| 21 | +const uint16_t table16[] = { 0x1000, 0x2000 }; |
| 22 | + |
| 23 | +// Constant data pointing to BSS/constant data |
| 24 | +uint16_t *const table_ptr16a[] = { &data16[0], &data16[1], &data16[2], &data16[3] }; |
| 25 | +const uint16_t *const table_ptr16b[] = { &table16[0], &table16[1] }; |
| 26 | + |
| 27 | +// A simple function that adds its 2 arguments (must be integers) |
| 28 | +STATIC mp_obj_t add(mp_obj_t x_in, mp_obj_t y_in) { |
| 29 | + mp_int_t x = mp_obj_get_int(x_in); |
| 30 | + mp_int_t y = mp_obj_get_int(y_in); |
| 31 | + return mp_obj_new_int(x + y); |
| 32 | +} |
| 33 | +STATIC MP_DEFINE_CONST_FUN_OBJ_2(add_obj, add); |
| 34 | + |
| 35 | +// A local helper function (not exposed to Python) |
| 36 | +STATIC mp_int_t fibonacci_helper(mp_int_t x) { |
| 37 | + if (x < MP_ARRAY_SIZE(table8)) { |
| 38 | + return table8[x]; |
| 39 | + } else { |
| 40 | + return fibonacci_helper(x - 1) + fibonacci_helper(x - 2); |
| 41 | + } |
| 42 | +} |
| 43 | + |
| 44 | +// A function which computes Fibonacci numbers |
| 45 | +STATIC mp_obj_t fibonacci(mp_obj_t x_in) { |
| 46 | + mp_int_t x = mp_obj_get_int(x_in); |
| 47 | + if (x < 0) { |
| 48 | + mp_raise_ValueError(MP_ERROR_TEXT("can't compute negative Fibonacci number")); |
| 49 | + } |
| 50 | + return mp_obj_new_int(fibonacci_helper(x)); |
| 51 | +} |
| 52 | +STATIC MP_DEFINE_CONST_FUN_OBJ_1(fibonacci_obj, fibonacci); |
| 53 | + |
| 54 | +// A function that accesses the BSS data |
| 55 | +STATIC mp_obj_t access(size_t n_args, const mp_obj_t *args) { |
| 56 | + if (n_args == 0) { |
| 57 | + // Create a list holding all items from data16 |
| 58 | + mp_obj_list_t *lst = MP_OBJ_TO_PTR(mp_obj_new_list(MP_ARRAY_SIZE(data16), NULL)); |
| 59 | + for (int i = 0; i < MP_ARRAY_SIZE(data16); ++i) { |
| 60 | + lst->items[i] = mp_obj_new_int(data16[i]); |
| 61 | + } |
| 62 | + return MP_OBJ_FROM_PTR(lst); |
| 63 | + } else if (n_args == 1) { |
| 64 | + // Get one item from data16 |
| 65 | + mp_int_t idx = mp_obj_get_int(args[0]) & 3; |
| 66 | + return mp_obj_new_int(data16[idx]); |
| 67 | + } else { |
| 68 | + // Set one item in data16 (via table_ptr16a) |
| 69 | + mp_int_t idx = mp_obj_get_int(args[0]) & 3; |
| 70 | + *table_ptr16a[idx] = mp_obj_get_int(args[1]); |
| 71 | + return mp_const_none; |
| 72 | + } |
| 73 | +} |
| 74 | +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(access_obj, 0, 2, access); |
| 75 | + |
| 76 | +// A function that allocates memory and creates a bytearray |
| 77 | +STATIC mp_obj_t make_array(void) { |
| 78 | + uint16_t *ptr = m_new(uint16_t, MP_ARRAY_SIZE(table_ptr16b)); |
| 79 | + for (int i = 0; i < MP_ARRAY_SIZE(table_ptr16b); ++i) { |
| 80 | + ptr[i] = *table_ptr16b[i]; |
| 81 | + } |
| 82 | + return mp_obj_new_bytearray_by_ref(sizeof(uint16_t) * MP_ARRAY_SIZE(table_ptr16b), ptr); |
| 83 | +} |
| 84 | +STATIC MP_DEFINE_CONST_FUN_OBJ_0(make_array_obj, make_array); |
| 85 | + |
| 86 | +// This is the entry point and is called when the module is imported |
| 87 | +mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { |
| 88 | + // This must be first, it sets up the globals dict and other things |
| 89 | + MP_DYNRUNTIME_INIT_ENTRY |
| 90 | + |
| 91 | + // Messages can be printed as usually |
| 92 | + mp_printf(&mp_plat_print, "initialising module self=%p\n", self); |
| 93 | + |
| 94 | + // Make the functions available in the module's namespace |
| 95 | + mp_store_global(MP_QSTR_add, MP_OBJ_FROM_PTR(&add_obj)); |
| 96 | + mp_store_global(MP_QSTR_fibonacci, MP_OBJ_FROM_PTR(&fibonacci_obj)); |
| 97 | + mp_store_global(MP_QSTR_access, MP_OBJ_FROM_PTR(&access_obj)); |
| 98 | + mp_store_global(MP_QSTR_make_array, MP_OBJ_FROM_PTR(&make_array_obj)); |
| 99 | + |
| 100 | + // Add some constants to the module's namespace |
| 101 | + mp_store_global(MP_QSTR_VAL, MP_OBJ_NEW_SMALL_INT(42)); |
| 102 | + mp_store_global(MP_QSTR_MSG, MP_OBJ_NEW_QSTR(MP_QSTR_HELLO_MICROPYTHON)); |
| 103 | + |
| 104 | + // This must be last, it restores the globals dict |
| 105 | + MP_DYNRUNTIME_INIT_EXIT |
| 106 | +} |
0 commit comments