8000 Add natmod examples · jepler/circuitpython@2bcfe21 · GitHub
[go: up one dir, main page]

Skip to content

Commit 2bcfe21

Browse files
committed
Add natmod examples
At least features0 works, and was useful in fixing the related native test
1 parent 68d4682 commit 2bcfe21

File tree

23 files changed

+774
-0
lines changed

23 files changed

+774
-0
lines changed

examples/natmod/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.mpy

examples/natmod/btree/Makefile

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1 67E6 +
# Location of top-level MicroPython directory
2+
MPY_DIR = ../../..
3+
4+
# Name of module (different to built-in btree so it can coexist)
5+
MOD = btree_$(ARCH)
6+
7+
# Source files (.c or .py)
8+
SRC = btree_c.c btree_py.py
9+
10+
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
11+
ARCH = x64
12+
13+
BTREE_DIR = $(MPY_DIR)/lib/berkeley-db-1.xx
14+
BTREE_DEFS = -D__DBINTERFACE_PRIVATE=1 -Dmpool_error="(void)" -Dabort=abort_ "-Dvirt_fd_t=void*" $(BTREE_DEFS_EXTRA)
15+
CFLAGS += -I$(BTREE_DIR)/PORT/include
16+
CFLAGS += -Wno-old-style-definition -Wno-sign-compare -Wno-unused-parameter $(BTREE_DEFS)
17+
18+
SRC += $(addprefix $(realpath $(BTREE_DIR))/,\
19+
btree/bt_close.c \
20+
btree/bt_conv.c \
21+
btree/bt_delete.c \
22+
btree/bt_get.c \
23+
btree/bt_open.c \
24+
btree/bt_overflow.c \
25+
btree/bt_page.c \
26+
btree/bt_put.c \
27+
btree/bt_search.c \
28+
btree/bt_seq.c \
29+
btree/bt_split.c \
30+
btree/bt_utils.c \
31+
mpool/mpool.c \
32+
)
33+
34+
include $(MPY_DIR)/py/dynruntime.mk
35+
36+
# btree needs gnu99 defined
37+
CFLAGS += -std=gnu99

examples/natmod/btree/btree_c.c

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
#define MICROPY_PY_BTREE (1)
2+
3+
#include "py/dynruntime.h"
4+
5+
#include <unistd.h>
6+
7+
#if !defined(_ F438 _linux__)
8+
void *memcpy(void *dst, const void *src, size_t n) {
9+
return mp_fun_table.memmove_(dst, src, n);
10+
}
11+
void *memset(void *s, int c, size_t n) {
12+
return mp_fun_table.memset_(s, c, n);
13+
}
14+
#endif
15+
16+
void *memmove(void *dest, const void *src, size_t n) {
17+
return mp_fun_table.memmove_(dest, src, n);
18+
}
19+
20+
void *malloc(size_t n) {
21+
void *ptr = m_malloc(n);
22+
return ptr;
23+
}
24+
void *realloc(void *ptr, size_t n) {
25+
mp_printf(&mp_plat_print, "UNDEF %d\n", __LINE__);
26+
return NULL;
27+
}
28+
void *calloc(size_t n, size_t m) {
29+
void *ptr = m_malloc(n * m);
30+
// memory already cleared by conservative GC
31+
return ptr;
32+
}
33+
34+
void free(void *ptr) {
35+
m_free(ptr);
36+
}
37+
38+
void abort_(void) {
39+
nlr_raise(mp_obj_new_exception(mp_load_global(MP_QSTR_RuntimeError)));
40+
}
41+
42+
int native_errno;
43+
#if defined(__linux__)
44+
int *__errno_location (void)
45+
#else
46+
int *__errno (void)
47+
#endif
48+
{
49+
return &native_errno;
50+
}
51+
52+
ssize_t mp_stream_posix_write(void *stream, const void *buf, size_t len) {
53+
mp_obj_base_t* o = stream;
54+
const mp_stream_p_t *stream_p = o->type->protocol;
55+
mp_uint_t out_sz = stream_p->write(MP_OBJ_FROM_PTR(stream), buf, len, &native_errno);
56+
if (out_sz == MP_STREAM_ERROR) {
57+
return -1;
58+
} else {
59+
return out_sz;
60+
}
61+
}
62+
63+
ssize_t mp_stream_posix_read(void *stream, void *buf, size_t len) {
64+
mp_obj_base_t* o = stream;
65+
const mp_stream_p_t *stream_p = o->type->protocol;
66+
mp_uint_t out_sz = stream_p->read(MP_OBJ_FROM_PTR(stream), buf, len, &native_errno);
67+
if (out_sz == MP_STREAM_ERROR) {
68+
return -1;
69+
} else {
70+
return out_sz;
71+
}
72+
}
73+
74+
off_t mp_stream_posix_lseek(void *stream, off_t offset, int whence) {
75+
const mp_obj_base_t* o = stream;
76+
const mp_stream_p_t *stream_p = o->type->protocol;
77+
struct mp_stream_seek_t seek_s;
78+
seek_s.offset = offset;
79+
seek_s.whence = whence;
80+
mp_uint_t res = stream_p->ioctl(MP_OBJ_FROM_PTR(stream), MP_STREAM_SEEK, (mp_uint_t)(uintptr_t)&seek_s, &native_errno);
81+
if (res == MP_STREAM_ERROR) {
82+
return -1;
83+
}
84+
return seek_s.offset;
85+
}
86+
87+
int mp_stream_posix_fsync(void *stream) {
88+
mp_obj_base_t* o = stream;
89+
const mp_stream_p_t *stream_p = o->type->protocol;
90+
mp_uint_t res = stream_p->ioctl(MP_OBJ_FROM_PTR(stream), MP_STREAM_FLUSH, 0, &native_errno);
91+
if (res == MP_STREAM_ERROR) {
92+
return -1;
93+
}
94+
return res;
95+
}
96+
97+
mp_obj_type_t btree_type;
98+
99+
#include "extmod/modbtree.c"
100+
101+
mp_map_elem_t btree_locals_dict_table[8];
102+
STATIC MP_DEFINE_CONST_DICT(btree_locals_dict, btree_locals_dict_table);
103+
104+
STATIC mp_obj_t btree_open(size_t n_args, const mp_obj_t *args) {
105+
// Make sure we got a stream object
106+
mp_get_stream_raise(args[0], MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);
107+
108+
BTREEINFO openinfo = {0};
109+
openinfo.flags = mp_obj_get_int(args[1]);
110+
openinfo.cachesize = mp_obj_get_int(args[2]);
111+
openinfo.psize = mp_obj_get_int(args[3]);
112+
openinfo.minkeypage = mp_obj_get_int(args[4]);
113+
DB *db = __bt_open(MP_OBJ_TO_PTR(args[0]), &btree_stream_fvtable, &openinfo, 0);
114+
if (db == NULL) {
115+
mp_raise_OSError(native_errno);
116+
}
117+
118+
return MP_OBJ_FROM_PTR(btree_new(db, args[0]));
119+
}
120+
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(btree_open_obj, 5, 5, btree_open);
121+
122+
mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
123+
MP_DYNRUNTIME_INIT_ENTRY
124+
125+
btree_type.base.type = (void*)&mp_fun_table.type_type;
126+
btree_type.name = MP_QSTR_btree;
127+
btree_type.print = btree_print;
128+
btree_type.getiter = btree_getiter;
129+
btree_type.iternext = btree_iternext;
130+
btree_type.binary_op = btree_binary_op;
131+
btree_type.subscr = btree_subscr;
132+
btree_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_close), MP_OBJ_FROM_PTR(&btree_close_obj) };
133+
btree_locals_dict_table[1] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_flush), MP_OBJ_FROM_PTR(&btree_flush_obj) };
134+
btree_locals_dict_table[2] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_get), MP_OBJ_FROM_PTR(&btree_get_obj) };
135+
btree_locals_dict_table[3] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_put), MP_OBJ_FROM_PTR(&btree_put_obj) };
136+
btree_locals_dict_table[4] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_seq), MP_OBJ_FROM_PTR(&btree_seq_obj) };
137+
btree_locals_dict_table[5] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_keys), MP_OBJ_FROM_PTR(&btree_keys_obj) };
138+
btree_locals_dict_table[6] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_values), MP_OBJ_FROM_PTR(&btree_values_obj) };
139+
btree_locals_dict_table[7] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_items), MP_OBJ_FROM_PTR(&btree_items_obj) };
140+
btree_type.locals_dict = (void*)&btree_locals_dict;
141+
142+
mp_store_global(MP_QSTR__open, MP_OBJ_FROM_PTR(&btree_open_obj));
143+
mp_store_global(MP_QSTR_INCL, MP_OBJ_NEW_SMALL_INT(FLAG_END_KEY_INCL));
144+
mp_store_global(MP_QSTR_DESC, MP_OBJ_NEW_SMALL_INT(FLAG_DESC));
145+
146+
MP_DYNRUNTIME_INIT_EXIT
147+
}

examples/natmod/btree/btree_py.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Implemented in Python to support keyword arguments
2+
def open(stream, *, flags=0, cachesize=0, pagesize=0, minkeypage=0):
3+
return _open(stream, flags, cachesize, pagesize, minkeypage)

examples/natmod/features0/Makefile

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Location of top-level MicroPython directory
2+
MPY_DIR = ../../..
3+
4+
# Name of module
5+
MOD = features0
6+
7+
# Source files (.c or .py)
8+
SRC = features0.c
9+
10+
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
11+
ARCH = x64
12+
13+
# Include to get the rules for compiling and linking the module
14+
include $(MPY_DIR)/py/dynruntime.mk

examples/natmod/features0/features0.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/* This example demonstrates the following features in a native module:
2+
- defining a simple function exposed to Python
3+
- defining a local, helper C function
4+
- getting and creating integer objects
5+
*/
6+
7+
// Include the header file to get access to the MicroPython API
8+
#include "py/dynruntime.h"
9+
10+
// Helper function to compute factorial
11+
STATIC mp_int_t factorial_helper(mp_int_t x) {
12+
if (x == 0) {
13+
return 1;
14+
}
15+
return x * factorial_helper(x - 1);
16+
}
17+
18+
// This is the function which will be called from Python, as factorial(x)
19+
STATIC mp_obj_t factorial(mp_obj_t x_obj) {
20+
// Extract the integer from the MicroPython input object
21+
mp_int_t x = mp_obj_get_int(x_obj);
22+
// Calculate the factorial
23+
mp_int_t result = factorial_helper(x);
24+
// Convert the result to a MicroPython integer object and return it
25+
return mp_obj_new_int(result);
26+
}
27+
// Define a Python reference to the function above
28+
STATIC MP_DEFINE_CONST_FUN_OBJ_1(factorial_obj, factorial);
29+
30+
// This is the entry point and is called when the module is imported
31+
mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
32+
// This must be first, it sets up the globals dict and other things
33+
MP_DYNRUNTIME_INIT_ENTRY
34+
35+
// Make the function available in the module's namespace
36+
mp_store_global(MP_QSTR_factorial, MP_OBJ_FROM_PTR(&factorial_obj));
37+
38+
// This must be last, it restores the globals dict
39+
MP_DYNRUNTIME_INIT_EXIT
40+
}

examples/natmod/features1/Makefile

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Location of top-level MicroPython directory
2+
MPY_DIR = ../../..
3+
4+
# Name of module
5+
MOD = features1
6+
7+
# Source files (.c or .py)
8+
SRC = features1.c
9+
10+
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
11+
ARCH = x64
12+
13+
# Include to get the rules for compiling and linking the module
14+
include $(MPY_DIR)/py/dynruntime.mk

examples/natmod/features1/features1.c

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
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 usualy
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+
}

examples/natmod/features2/Makefile

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Location of top-level MicroPython directory
2+
MPY_DIR = ../../..
3+
4+
# Name of module
5+
MOD = features2
6+
7+
# Source files (.c or .py)
8+
SRC = main.c prod.c test.py
9+
10+
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
11+
ARCH = x64
12+
13+
# Include to get the rules for compiling and linking the module
14+
include $(MPY_DIR)/py/dynruntime.mk

0 commit comments

Comments
 (0)
0