summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--examples/natmod/features1/Makefile14
-rw-r--r--examples/natmod/features1/features1.c106
-rw-r--r--examples/natmod/features2/Makefile14
-rw-r--r--examples/natmod/features2/main.c83
-rw-r--r--examples/natmod/features2/prod.c9
-rw-r--r--examples/natmod/features2/prod.h1
-rw-r--r--examples/natmod/features2/test.py26
7 files changed, 253 insertions, 0 deletions
diff --git a/examples/natmod/features1/Makefile b/examples/natmod/features1/Makefile
new file mode 100644
index 0000000000..010640daf9
--- /dev/null
+++ b/examples/natmod/features1/Makefile
@@ -0,0 +1,14 @@
+# Location of top-level MicroPython directory
+MPY_DIR = ../../..
+
+# Name of module
+MOD = features1
+
+# Source files (.c or .py)
+SRC = features1.c
+
+# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
+ARCH = x64
+
+# Include to get the rules for compiling and linking the module
+include $(MPY_DIR)/py/dynruntime.mk
diff --git a/examples/natmod/features1/features1.c b/examples/natmod/features1/features1.c
new file mode 100644
index 0000000000..1bfbe50b95
--- /dev/null
+++ b/examples/natmod/features1/features1.c
@@ -0,0 +1,106 @@
+/* This example demonstrates the following features in a native module:
+ - defining simple functions exposed to Python
+ - defining local, helper C functions
+ - defining constant integers and strings exposed to Python
+ - getting and creating integer objects
+ - creating Python lists
+ - raising exceptions
+ - allocating memory
+ - BSS and constant data (rodata)
+ - relocated pointers in rodata
+*/
+
+// Include the header file to get access to the MicroPython API
+#include "py/dynruntime.h"
+
+// BSS (zero) data
+uint16_t data16[4];
+
+// Constant data (rodata)
+const uint8_t table8[] = { 0, 1, 1, 2, 3, 5, 8, 13 };
+const uint16_t table16[] = { 0x1000, 0x2000 };
+
+// Constant data pointing to BSS/constant data
+uint16_t *const table_ptr16a[] = { &data16[0], &data16[1], &data16[2], &data16[3] };
+const uint16_t *const table_ptr16b[] = { &table16[0], &table16[1] };
+
+// A simple function that adds its 2 arguments (must be integers)
+STATIC mp_obj_t add(mp_obj_t x_in, mp_obj_t y_in) {
+ mp_int_t x = mp_obj_get_int(x_in);
+ mp_int_t y = mp_obj_get_int(y_in);
+ return mp_obj_new_int(x + y);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(add_obj, add);
+
+// A local helper function (not exposed to Python)
+STATIC mp_int_t fibonacci_helper(mp_int_t x) {
+ if (x < MP_ARRAY_SIZE(table8)) {
+ return table8[x];
+ } else {
+ return fibonacci_helper(x - 1) + fibonacci_helper(x - 2);
+ }
+}
+
+// A function which computes Fibonacci numbers
+STATIC mp_obj_t fibonacci(mp_obj_t x_in) {
+ mp_int_t x = mp_obj_get_int(x_in);
+ if (x < 0) {
+ mp_raise_ValueError("can't compute negative Fibonacci number");
+ }
+ return mp_obj_new_int(fibonacci_helper(x));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(fibonacci_obj, fibonacci);
+
+// A function that accesses the BSS data
+STATIC mp_obj_t access(size_t n_args, const mp_obj_t *args) {
+ if (n_args == 0) {
+ // Create a list holding all items from data16
+ mp_obj_list_t *lst = MP_OBJ_TO_PTR(mp_obj_new_list(MP_ARRAY_SIZE(data16), NULL));
+ for (int i = 0; i < MP_ARRAY_SIZE(data16); ++i) {
+ lst->items[i] = mp_obj_new_int(data16[i]);
+ }
+ return MP_OBJ_FROM_PTR(lst);
+ } else if (n_args == 1) {
+ // Get one item from data16
+ mp_int_t idx = mp_obj_get_int(args[0]) & 3;
+ return mp_obj_new_int(data16[idx]);
+ } else {
+ // Set one item in data16 (via table_ptr16a)
+ mp_int_t idx = mp_obj_get_int(args[0]) & 3;
+ *table_ptr16a[idx] = mp_obj_get_int(args[1]);
+ return mp_const_none;
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(access_obj, 0, 2, access);
+
+// A function that allocates memory and creates a bytearray
+STATIC mp_obj_t make_array(void) {
+ uint16_t *ptr = m_new(uint16_t, MP_ARRAY_SIZE(table_ptr16b));
+ for (int i = 0; i < MP_ARRAY_SIZE(table_ptr16b); ++i) {
+ ptr[i] = *table_ptr16b[i];
+ }
+ return mp_obj_new_bytearray_by_ref(sizeof(uint16_t) * MP_ARRAY_SIZE(table_ptr16b), ptr);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(make_array_obj, make_array);
+
+// This is the entry point and is called when the module is imported
+mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
+ // This must be first, it sets up the globals dict and other things
+ MP_DYNRUNTIME_INIT_ENTRY
+
+ // Messages can be printed as usualy
+ mp_printf(&mp_plat_print, "initialising module self=%p\n", self);
+
+ // Make the functions available in the module's namespace
+ mp_store_global(MP_QSTR_add, MP_OBJ_FROM_PTR(&add_obj));
+ mp_store_global(MP_QSTR_fibonacci, MP_OBJ_FROM_PTR(&fibonacci_obj));
+ mp_store_global(MP_QSTR_access, MP_OBJ_FROM_PTR(&access_obj));
+ mp_store_global(MP_QSTR_make_array, MP_OBJ_FROM_PTR(&make_array_obj));
+
+ // Add some constants to the module's namespace
+ mp_store_global(MP_QSTR_VAL, MP_OBJ_NEW_SMALL_INT(42));
+ mp_store_global(MP_QSTR_MSG, MP_OBJ_NEW_QSTR(MP_QSTR_HELLO_MICROPYTHON));
+
+ // This must be last, it restores the globals dict
+ MP_DYNRUNTIME_INIT_EXIT
+}
diff --git a/examples/natmod/features2/Makefile b/examples/natmod/features2/Makefile
new file mode 100644
index 0000000000..4fd23c6879
--- /dev/null
+++ b/examples/natmod/features2/Makefile
@@ -0,0 +1,14 @@
+# Location of top-level MicroPython directory
+MPY_DIR = ../../..
+
+# Name of module
+MOD = features2
+
+# Source files (.c or .py)
+SRC = main.c prod.c test.py
+
+# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
+ARCH = x64
+
+# Include to get the rules for compiling and linking the module
+include $(MPY_DIR)/py/dynruntime.mk
diff --git a/examples/natmod/features2/main.c b/examples/natmod/features2/main.c
new file mode 100644
index 0000000000..de83bf2bed
--- /dev/null
+++ b/examples/natmod/features2/main.c
@@ -0,0 +1,83 @@
+/* This example demonstrates the following features in a native module:
+ - using floats
+ - defining additional code in Python (see test.py)
+ - have extra C code in a separate file (see prod.c)
+*/
+
+// Include the header file to get access to the MicroPython API
+#include "py/dynruntime.h"
+
+// Include the header for auxiliary C code for this module
+#include "prod.h"
+
+// Automatically detect if this module should include double-precision code.
+// If double precision is supported by the target architecture then it can
+// be used in native module regardless of what float setting the target
+// MicroPython runtime uses (being none, float or double).
+#if defined(__i386__) || defined(__x86_64__) || (defined(__ARM_FP) && (__ARM_FP & 8))
+#define USE_DOUBLE 1
+#else
+#define USE_DOUBLE 0
+#endif
+
+// A function that uses the default float type configured for the current target
+// This default can be overridden by specifying MICROPY_FLOAT_IMPL at the make level
+STATIC mp_obj_t add(mp_obj_t x, mp_obj_t y) {
+ return mp_obj_new_float(mp_obj_get_float(x) + mp_obj_get_float(y));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(add_obj, add);
+
+// A function that explicitly uses single precision floats
+STATIC mp_obj_t add_f(mp_obj_t x, mp_obj_t y) {
+ return mp_obj_new_float_from_f(mp_obj_get_float_to_f(x) + mp_obj_get_float_to_f(y));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(add_f_obj, add_f);
+
+#if USE_DOUBLE
+// A function that explicitly uses double precision floats
+STATIC mp_obj_t add_d(mp_obj_t x, mp_obj_t y) {
+ return mp_obj_new_float_from_d(mp_obj_get_float_to_d(x) + mp_obj_get_float_to_d(y));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(add_d_obj, add_d);
+#endif
+
+// A function that computes the product of floats in an array.
+// This function uses the most general C argument interface, which is more difficult
+// to use but has access to the globals dict of the module via self->globals.
+STATIC mp_obj_t productf(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
+ // Check number of arguments is valid
+ mp_arg_check_num(n_args, n_kw, 1, 1, false);
+
+ // Extract buffer pointer and verify typecode
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_RW);
+ if (bufinfo.typecode != 'f') {
+ mp_raise_ValueError("expecting float array");
+ }
+
+ // Compute product, store result back in first element of array
+ float *ptr = bufinfo.buf;
+ float prod = prod_array(bufinfo.len / sizeof(*ptr), ptr);
+ ptr[0] = prod;
+
+ return mp_const_none;
+}
+
+// This is the entry point and is called when the module is imported
+mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
+ // This must be first, it sets up the globals dict and other things
+ MP_DYNRUNTIME_INIT_ENTRY
+
+ // Make the functions available in the module's namespace
+ mp_store_global(MP_QSTR_add, MP_OBJ_FROM_PTR(&add_obj));
+ mp_store_global(MP_QSTR_add_f, MP_OBJ_FROM_PTR(&add_f_obj));
+ #if USE_DOUBLE
+ mp_store_global(MP_QSTR_add_d, MP_OBJ_FROM_PTR(&add_d_obj));
+ #endif
+
+ // The productf function uses the most general C argument interface
+ mp_store_global(MP_QSTR_productf, MP_DYNRUNTIME_MAKE_FUNCTION(productf));
+
+ // This must be last, it restores the globals dict
+ MP_DYNRUNTIME_INIT_EXIT
+}
diff --git a/examples/natmod/features2/prod.c b/examples/natmod/features2/prod.c
new file mode 100644
index 0000000000..7791dcad1d
--- /dev/null
+++ b/examples/natmod/features2/prod.c
@@ -0,0 +1,9 @@
+#include "prod.h"
+
+float prod_array(int n, float *ar) {
+ float ans = 1;
+ for (int i = 0; i < n; ++i) {
+ ans *= ar[i];
+ }
+ return ans;
+}
diff --git a/examples/natmod/features2/prod.h b/examples/natmod/features2/prod.h
new file mode 100644
index 0000000000..f27dd8d033
--- /dev/null
+++ b/examples/natmod/features2/prod.h
@@ -0,0 +1 @@
+float prod_array(int n, float *ar);
diff --git a/examples/natmod/features2/test.py b/examples/natmod/features2/test.py
new file mode 100644
index 0000000000..2e9db00f44
--- /dev/null
+++ b/examples/natmod/features2/test.py
@@ -0,0 +1,26 @@
+# This Python code will be merged with the C code in main.c
+
+import array
+
+def isclose(a, b):
+ return abs(a - b) < 1e-3
+
+def test():
+ tests = [
+ isclose(add(0.1, 0.2), 0.3),
+ isclose(add_f(0.1, 0.2), 0.3),
+ ]
+
+ ar = array.array('f', [1, 2, 3.5])
+ productf(ar)
+ tests.append(isclose(ar[0], 7))
+
+ if 'add_d' in globals():
+ tests.append(isclose(add_d(0.1, 0.2), 0.3))
+
+ print(tests)
+
+ if not all(tests):
+ raise SystemExit(1)
+
+test()