Skip to content

Commit 23f94b7

Browse files
authored
Merge pull request #47 from emlearn/neighbors-usermod
neighbors: Support building as user module
2 parents fecb546 + 566de44 commit 23f94b7

4 files changed

Lines changed: 81 additions & 13 deletions

File tree

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
add_library(usermod_emlearn_neighbors INTERFACE)
2+
3+
execute_process(
4+
COMMAND python3 -c "import emlearn; print(emlearn.includedir)"
5+
OUTPUT_VARIABLE EMLEARN_DIR
6+
OUTPUT_STRIP_TRAILING_WHITESPACE
7+
)
8+
9+
target_sources(usermod_emlearn_neighbors INTERFACE
10+
${CMAKE_CURRENT_LIST_DIR}/neighbors.c
11+
)
12+
13+
target_include_directories(usermod_emlearn_neighbors INTERFACE
14+
${EMLEARN_DIR}
15+
)
16+
17+
target_link_libraries(usermod INTERFACE usermod_emlearn_neighbors)
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
MOD_DIR := $(USERMOD_DIR)
2+
3+
# Add all C files to SRC_USERMOD.
4+
SRC_USERMOD_C += $(MOD_DIR)/neighbors.c
5+
6+
EMLEARN_DIR := $(shell python3 -c "import emlearn; print(emlearn.includedir)")
7+
8+
# We can add our module folder to include paths if needed
9+
CFLAGS_USERMOD += -I$(EMLEARN_DIR)

src/emlearn_neighbors/neighbors.c

Lines changed: 54 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
// Include the header file to get access to the MicroPython API
2+
#ifdef MICROPY_ENABLE_DYNRUNTIME
23
#include "py/dynruntime.h"
4+
#else
5+
#include "py/runtime.h"
6+
#endif
37

48
#define EML_LOG_ENABLE 0
59
#if EML_LOG_ENABLE
@@ -11,6 +15,7 @@
1115

1216
#include <string.h>
1317

18+
#ifdef MICROPY_ENABLE_DYNRUNTIME
1419
// memset is used by some standard C constructs
1520
#if !defined(__linux__)
1621
void *memcpy(void *dst, const void *src, size_t n) {
@@ -20,8 +25,7 @@ void *memset(void *s, int c, size_t n) {
2025
return mp_fun_table.memset_(s, c, n);
2126
}
2227
#endif
23-
24-
28+
#endif // MICROPY_ENABLE_DYNRUNTIME
2529

2630

2731
// MicroPython type for EmlNeighborsModel
@@ -31,7 +35,12 @@ typedef struct _mp_obj_neighbors_model_t {
3135
EmlNeighborsDistanceItem *distances;
3236
} mp_obj_neighbors_model_t;
3337

38+
#ifdef MICROPY_ENABLE_DYNRUNTIME
3439
mp_obj_full_type_t neighbors_model_type;
40+
#else
41+
static const mp_obj_type_t neighbors_model_type;
42+
#endif
43+
3544

3645
// Create a new instace
3746
static mp_obj_t neighbors_model_new(mp_obj_t items_obj, mp_obj_t features_obj, mp_obj_t neighbors_obj) {
@@ -71,9 +80,9 @@ static mp_obj_t neighbors_model_del(mp_obj_t self_obj) {
7180
EmlNeighborsModel *self = &o->model;
7281

7382
// free allocated memory
74-
m_free(self->data);
75-
m_free(self->labels);
76-
m_free(o->distances);
83+
m_del(int16_t, self->data, self->n_features*self->max_items);
84+
m_del(int16_t, self->labels, self->max_items);
85+
m_del(EmlNeighborsDistanceItem, o->distances, self->max_items);
7786

7887
return mp_const_none;
7988
}
@@ -145,17 +154,14 @@ static MP_DEFINE_CONST_FUN_OBJ_3(neighbors_model_get_item_obj, neighbors_model_g
145154

146155

147156
// Takes a integer array
148-
static mp_obj_t neighbors_model_predict(mp_obj_fun_bc_t *self_obj,
149-
size_t n_args, size_t n_kw, mp_obj_t *args) {
150-
// Check number of arguments is valid
151-
mp_arg_check_num(n_args, n_kw, 2, 2, false);
157+
static mp_obj_t neighbors_model_predict(mp_obj_t self_obj, mp_obj_t data_obj) {
152158

153-
mp_obj_neighbors_model_t *o = MP_OBJ_TO_PTR(args[0]);
159+
mp_obj_neighbors_model_t *o = MP_OBJ_TO_PTR(self_obj);
154160
EmlNeighborsModel *self = &o->model;
155161

156162
// Extract buffer pointer and verify typecode
157163
mp_buffer_info_t bufinfo;
158-
mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_RW);
164+
mp_get_buffer_raise(data_obj, &bufinfo, MP_BUFFER_RW);
159165
if (bufinfo.typecode != 'h') {
160166
mp_raise_ValueError(MP_ERROR_TEXT("expecting int16 array"));
161167
}
@@ -174,6 +180,7 @@ static mp_obj_t neighbors_model_predict(mp_obj_fun_bc_t *self_obj,
174180

175181
return mp_obj_new_int(out);
176182
}
183+
static MP_DEFINE_CONST_FUN_OBJ_2(neighbors_model_predict_obj, neighbors_model_predict);
177184

178185
// Access details about prediction result
179186
static mp_obj_t neighbors_model_get_result(mp_obj_t self_obj, mp_obj_t index_obj) {
@@ -200,7 +207,7 @@ static MP_DEFINE_CONST_FUN_OBJ_2(neighbors_model_get_result_obj, neighbors_model
200207

201208

202209

203-
210+
#ifdef MICROPY_ENABLE_DYNRUNTIME
204211
// Module setup
205212
mp_map_elem_t neighbors_model_locals_dict_table[5];
206213
static MP_DEFINE_CONST_DICT(neighbors_model_locals_dict, neighbors_model_locals_dict_table);
@@ -216,7 +223,7 @@ mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *a
216223
neighbors_model_type.flags = MP_TYPE_FLAG_ITER_IS_CUSTOM;
217224
neighbors_model_type.name = MP_QSTR_emlneighbors;
218225
// methods
219-
neighbors_model_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_predict), MP_DYNRUNTIME_MAKE_FUNCTION(neighbors_model_predict) };
226+
neighbors_model_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_predict), MP_OBJ_FROM_PTR(&neighbors_model_predict_obj) };
220227
neighbors_model_locals_dict_table[1] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_additem), MP_OBJ_FROM_PTR(&neighbors_model_additem_obj) };
221228
neighbors_model_locals_dict_table[2] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR___del__), MP_OBJ_FROM_PTR(&neighbors_model_del_obj) };
222229
neighbors_model_locals_dict_table[3] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_getresult), MP_OBJ_FROM_PTR(&neighbors_model_get_result_obj) };
@@ -227,4 +234,38 @@ mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *a
227234
// This must be last, it restores the globals dict
228235
MP_DYNRUNTIME_INIT_EXIT
229236
}
237+
#else
238+
239+
240+
// Define the class
241+
static const mp_rom_map_elem_t neighbors_model_locals_dict_table[] = {
242+
243+
{ MP_ROM_QSTR(MP_QSTR_predict), MP_ROM_PTR(&neighbors_model_predict_obj) },
244+
{ MP_ROM_QSTR(MP_QSTR_additem), MP_ROM_PTR(&neighbors_model_additem_obj) },
245+
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&neighbors_model_del_obj) },
246+
{ MP_ROM_QSTR(MP_QSTR_getresult), MP_ROM_PTR(&neighbors_model_get_result_obj) },
247+
{ MP_ROM_QSTR(MP_QSTR_getitem), MP_ROM_PTR(&neighbors_model_get_item_obj) }
248+
};
249+
static MP_DEFINE_CONST_DICT(neighbors_model_locals_dict, neighbors_model_locals_dict_table);
250+
251+
static MP_DEFINE_CONST_OBJ_TYPE(
252+
neighbors_model_type,
253+
MP_QSTR_emlneighbors,
254+
MP_TYPE_FLAG_NONE,
255+
locals_dict, &neighbors_model_locals_dict
256+
);
257+
258+
// Define module object.
259+
static const mp_rom_map_elem_t emlearn_neighbors_globals_table[] = {
260+
{ MP_ROM_QSTR(MP_QSTR_new), MP_ROM_PTR(&neighbors_model_new_obj) },
261+
};
262+
static MP_DEFINE_CONST_DICT(emlearn_neighbors_globals, emlearn_neighbors_globals_table);
263+
264+
const mp_obj_module_t emlearn_neighbors_cmodule = {
265+
.base = { &mp_type_module },
266+
.globals = (mp_obj_dict_t *)&emlearn_neighbors_globals,
267+
};
268+
269+
MP_REGISTER_MODULE(MP_QSTR_emlearn_neighbors, emlearn_neighbors_cmodule);
270+
#endif
230271

src/micropython.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@
22
include(${CMAKE_CURRENT_LIST_DIR}/emlearn_trees/micropython.cmake)
33
include(${CMAKE_CURRENT_LIST_DIR}/emlearn_fft/micropython.cmake)
44
include(${CMAKE_CURRENT_LIST_DIR}/emlearn_iir/micropython.cmake)
5+
include(${CMAKE_CURRENT_LIST_DIR}/emlearn_neighbors/micropython.cmake)
56
include(${CMAKE_CURRENT_LIST_DIR}/emlearn_arrayutils/micropython.cmake)
67
include(${CMAKE_CURRENT_LIST_DIR}/tinymaix_cnn/micropython.cmake)

0 commit comments

Comments
 (0)