diff --git a/.gitignore b/.gitignore index 50f3249..5ca0c96 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ venv/ .ipynb_checkpoints/ __pycache__/ +.mpy_ld_cache/ diff --git a/requirements.txt b/requirements.txt index 5d13c4b..6ee4e56 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -emlearn>=0.21.0 +emlearn>=0.21.1 scikit-learn>=1.0.0 ar>=1.0.0 pyelftools>=0.31 diff --git a/src/emlearn_iir/iir_filter.c b/src/emlearn_iir/iir_filter.c index ac62f31..0434ea6 100644 --- a/src/emlearn_iir/iir_filter.c +++ b/src/emlearn_iir/iir_filter.c @@ -1,5 +1,9 @@ // Include the header file to get access to the MicroPython API +#ifdef MICROPY_ENABLE_DYNRUNTIME #include "py/dynruntime.h" +#else +#include "py/runtime.h" +#endif #include @@ -29,7 +33,11 @@ typedef struct _mp_obj_iir_filter_t { EmlIIR filter; } mp_obj_iir_filter_t; +#if MICROPY_ENABLE_DYNRUNTIME mp_obj_full_type_t iir_filter_type; +#else +static const mp_obj_type_t iir_filter_type; +#endif // Create a new instance static mp_obj_t iir_filter_new(mp_obj_t array_obj) { @@ -55,17 +63,17 @@ static mp_obj_t iir_filter_new(mp_obj_t array_obj) { self->n_stages = n_values / 6; self->states_length = self->n_stages * 4; - self->states = (float *)m_malloc(sizeof(float)*self->states_length); + self->states = m_new(float, self->states_length); self->coefficients_length = n_values; - self->coefficients = (float *)m_malloc(sizeof(float)*self->coefficients_length); + self->coefficients = m_new(float, self->coefficients_length); memcpy((float *)self->coefficients, values, sizeof(float)*self->coefficients_length); const EmlError err = eml_iir_check(*self); if (err != EmlOk) { - m_free(self->states); - m_free((float *)self->coefficients); + m_del(float, self->states, self->states_length); + m_del(float, (float *)self->coefficients, self->coefficients_length); mp_raise_ValueError(MP_ERROR_TEXT("EmlError")); } @@ -80,9 +88,8 @@ static mp_obj_t iir_filter_del(mp_obj_t self_obj) { EmlIIR *self = &o->filter; // free allocated data - m_free(self->states); - m_free((float *)self->coefficients); - + m_del(float, self->states, self->states_length); + m_del(float, (float *)self->coefficients, self->coefficients_length); return mp_const_none; } @@ -114,6 +121,7 @@ static mp_obj_t iir_filter_run(mp_obj_t self_obj, mp_obj_t array_obj) { static MP_DEFINE_CONST_FUN_OBJ_2(iir_filter_run_obj, iir_filter_run); +#ifdef MICROPY_ENABLE_DYNRUNTIME mp_map_elem_t iir_locals_dict_table[2]; static MP_DEFINE_CONST_DICT(iir_locals_dict, iir_locals_dict_table); @@ -136,4 +144,35 @@ mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *a // This must be last, it restores the globals dict MP_DYNRUNTIME_INIT_EXIT } +#else + + +// Define a class +static const mp_rom_map_elem_t emlearn_iir_filter_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_run), MP_ROM_PTR(&iir_filter_run_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&iir_filter_del_obj) } +}; +static MP_DEFINE_CONST_DICT(emlearn_iir_filter_locals_dict, emlearn_iir_filter_locals_dict_table); + +static MP_DEFINE_CONST_OBJ_TYPE( + iir_filter_type, + MP_QSTR_emliir, + MP_TYPE_FLAG_NONE, + locals_dict, &emlearn_iir_filter_locals_dict +); +// Define module object. +static const mp_rom_map_elem_t emlearn_iir_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR_new), MP_ROM_PTR(&iir_filter_new_obj) }, +}; +static MP_DEFINE_CONST_DICT(emlearn_iir_globals, emlearn_iir_globals_table); + +const mp_obj_module_t emlearn_iir_cmodule = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&emlearn_iir_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_emlearn_iir, emlearn_iir_cmodule); + + +#endif diff --git a/src/emlearn_iir/micropython.mk b/src/emlearn_iir/micropython.mk new file mode 100644 index 0000000..40d8ad6 --- /dev/null +++ b/src/emlearn_iir/micropython.mk @@ -0,0 +1,9 @@ +MOD_DIR := $(USERMOD_DIR) + +# Add all C files to SRC_USERMOD. +SRC_USERMOD_C += $(MOD_DIR)/iir_filter.c + +EMLEARN_DIR := $(shell python3 -c "import emlearn; print(emlearn.includedir)") + +# We can add our module folder to include paths if needed +CFLAGS_USERMOD += -I$(EMLEARN_DIR) diff --git a/src/emlearn_trees/Makefile b/src/emlearn_trees/Makefile index d1a71cf..01220c9 100644 --- a/src/emlearn_trees/Makefile +++ b/src/emlearn_trees/Makefile @@ -32,6 +32,6 @@ $(DIST_FILE): $(MOD).mpy $(DIST_DIR) # Include to get the rules for compiling and linking the module include $(MPY_DIR)/py/dynruntime.mk -CFLAGS += -I$(EMLEARN_DIR) +CFLAGS += -I$(EMLEARN_DIR) -DDYNAMIC_RUNTIME=1 dist: $(DIST_FILE) diff --git a/src/emlearn_trees/micropython.mk b/src/emlearn_trees/micropython.mk new file mode 100644 index 0000000..066419a --- /dev/null +++ b/src/emlearn_trees/micropython.mk @@ -0,0 +1,9 @@ +MOD_DIR := $(USERMOD_DIR) + +# Add all C files to SRC_USERMOD. +SRC_USERMOD_C += $(MOD_DIR)/trees.c + +EMLEARN_DIR := $(shell python3 -c "import emlearn; print(emlearn.includedir)") + +# We can add our module folder to include paths if needed +CFLAGS_USERMOD += -I$(EMLEARN_DIR) diff --git a/src/emlearn_trees/trees.c b/src/emlearn_trees/trees.c index b98ac76..8cb3f45 100644 --- a/src/emlearn_trees/trees.c +++ b/src/emlearn_trees/trees.c @@ -1,5 +1,10 @@ // Include the header file to get access to the MicroPython API + +#ifdef MICROPY_ENABLE_DYNRUNTIME #include "py/dynruntime.h" +#else +#include "py/runtime.h" +#endif #define EML_TREES_REGRESSION_ENABLE 0 #include @@ -33,7 +38,11 @@ typedef struct _mp_obj_trees_builder_t { EmlTreesBuilder builder; } mp_obj_trees_builder_t; +#if MICROPY_ENABLE_DYNRUNTIME mp_obj_full_type_t trees_builder_type; +#else +static const mp_obj_type_t trees_builder_type; +#endif // Create a new tree builder static mp_obj_t builder_new(mp_obj_t trees_obj, mp_obj_t nodes_obj, mp_obj_t leaves_obj) { @@ -58,9 +67,9 @@ static mp_obj_t builder_new(mp_obj_t trees_obj, mp_obj_t nodes_obj, mp_obj_t lea self->max_leaves = max_leaves; // create storage for trees - EmlTreesNode *nodes = (EmlTreesNode *)m_malloc(sizeof(EmlTreesNode)*max_nodes); - int32_t *roots = (int32_t *)m_malloc(sizeof(int32_t)*max_trees); - uint8_t *leaves = (uint8_t *)m_malloc(sizeof(uint8_t)*max_leaves); + EmlTreesNode *nodes = m_new(EmlTreesNode, self->max_nodes); + int32_t *roots = m_new(int32_t, self->max_trees); + uint8_t *leaves = m_new(uint8_t, self->max_leaves); #if EMLEARN_MICROPYTHON_DEBUG mp_printf(&mp_plat_print, "emltrees nodes=%p roots=%p builder=%p\n", nodes, roots, self); @@ -91,9 +100,9 @@ static mp_obj_t builder_del(mp_obj_t trees_obj) { EmlTreesBuilder *self = &o->builder; // free allocated data - m_free(self->trees.nodes); - m_free(self->trees.tree_roots); - m_free(self->trees.leaves); + m_del(EmlTreesNode, self->trees.nodes, self->max_nodes); + m_del(int32_t, self->trees.tree_roots, self->max_nodes); + m_del(uint8_t, self->trees.leaves, self->max_leaves); #if EMLEARN_MICROPYTHON_DEBUG mp_printf(&mp_plat_print, "emltrees del \n"); @@ -261,6 +270,7 @@ static mp_obj_t builder_predict(mp_obj_t self_obj, mp_obj_t features_obj, mp_obj static MP_DEFINE_CONST_FUN_OBJ_3(builder_predict_obj, builder_predict); +#ifdef MICROPY_ENABLE_DYNRUNTIME mp_map_elem_t trees_locals_dict_table[7]; static MP_DEFINE_CONST_DICT(trees_locals_dict, trees_locals_dict_table); @@ -289,3 +299,40 @@ mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *a MP_DYNRUNTIME_INIT_EXIT } +#else + + +// Define the tree builder class +static const mp_rom_map_elem_t emlearn_trees_builder_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_predict), MP_ROM_PTR(&builder_predict_obj) }, + { MP_ROM_QSTR(MP_QSTR_addnode), MP_ROM_PTR(&builder_addnode_obj) }, + { MP_ROM_QSTR(MP_QSTR_addroot), MP_ROM_PTR(&builder_addroot_obj) }, + { MP_ROM_QSTR(MP_QSTR_addleaf), MP_ROM_PTR(&builder_addleaf_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&builder_del_obj) }, + { MP_ROM_QSTR(MP_QSTR_setdata), MP_ROM_PTR(&builder_setdata_obj) }, + { MP_ROM_QSTR(MP_QSTR_outputs), MP_ROM_PTR(&builder_get_outputs_obj) }, +}; +static MP_DEFINE_CONST_DICT(emlearn_trees_builder_locals_dict, emlearn_trees_builder_locals_dict_table); + +static MP_DEFINE_CONST_OBJ_TYPE( + trees_builder_type, + MP_QSTR_emltrees, + MP_TYPE_FLAG_NONE, + locals_dict, &emlearn_trees_builder_locals_dict +); + +// Define module object. +static const mp_rom_map_elem_t emlearn_trees_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR_new), MP_ROM_PTR(&builder_new_obj) }, +}; +static MP_DEFINE_CONST_DICT(emlearn_trees_globals, emlearn_trees_globals_table); + +const mp_obj_module_t emlearn_trees_cmodule = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&emlearn_trees_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_emlearn_trees, emlearn_trees_cmodule); + +#endif +