From 663a7d2fe021db018642e12d8b6e7efbe6631ba0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20V=C3=B6r=C3=B6s?= Date: Fri, 5 Mar 2021 15:25:46 +0100 Subject: [PATCH] add from_int16_buffer, from_uint16_buffer functions --- code/ulab.h | 8 +++ code/utils/utils.c | 113 +++++++++++++++++++++++++----- docs/manual/source/ulab-utils.rst | 32 ++++++++- docs/ulab-utils.ipynb | 28 +++++++- 4 files changed, 159 insertions(+), 22 deletions(-) diff --git a/code/ulab.h b/code/ulab.h index 498a4ff..7ff07de 100644 --- a/code/ulab.h +++ b/code/ulab.h @@ -619,6 +619,14 @@ #define ULAB_HAS_UTILS_MODULE (1) #endif +#ifndef ULAB_UTILS_HAS_FROM_INT16_BUFFER +#define ULAB_UTILS_HAS_FROM_INT16_BUFFER (1) +#endif + +#ifndef ULAB_UTILS_HAS_FROM_UINT16_BUFFER +#define ULAB_UTILS_HAS_FROM_UINT16_BUFFER (1) +#endif + #ifndef ULAB_UTILS_HAS_FROM_INT32_BUFFER #define ULAB_UTILS_HAS_FROM_INT32_BUFFER (1) #endif diff --git a/code/utils/utils.c b/code/utils/utils.c index d06c30e..2b7dc09 100644 --- a/code/utils/utils.c +++ b/code/utils/utils.c @@ -19,11 +19,13 @@ #if ULAB_HAS_UTILS_MODULE enum UTILS_BUFFER_TYPE { + UTILS_INT16_BUFFER, + UTILS_UINT16_BUFFER, UTILS_INT32_BUFFER, UTILS_UINT32_BUFFER, }; -#if ULAB_UTILS_HAS_FROM_INT32_BUFFER | ULAB_UTILS_HAS_FROM_UINT32_BUFFER +#if ULAB_UTILS_HAS_FROM_INT16_BUFFER | ULAB_UTILS_HAS_FROM_UINT16_BUFFER | ULAB_UTILS_HAS_FROM_INT32_BUFFER | ULAB_UTILS_HAS_FROM_UINT32_BUFFER static mp_obj_t utils_from_intbuffer_helper(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, uint8_t buffer_type) { static const mp_arg_t allowed_args[] = { { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_rom_obj = mp_const_none } } , @@ -52,8 +54,15 @@ static mp_obj_t utils_from_intbuffer_helper(size_t n_args, const mp_obj_t *pos_a if(bufinfo.len < offset) { mp_raise_ValueError(translate("offset is too large")); } - size_t len = (bufinfo.len - offset) / sizeof(int32_t); - if((len * sizeof(int32_t)) != (bufinfo.len - offset)) { + uint8_t sz = sizeof(int16_t); + #if ULAB_UTILS_HAS_FROM_INT32_BUFFER | ULAB_UTILS_HAS_FROM_UINT32_BUFFER + if((buffer_type == UTILS_INT32_BUFFER) || (buffer_type == UTILS_UINT32_BUFFER)) { + sz = sizeof(int32_t); + } + #endif + + size_t len = (bufinfo.len - offset) / sz; + if((len * sz) != (bufinfo.len - offset)) { mp_raise_ValueError(translate("buffer size must be a multiple of element size")); } if(mp_obj_get_int(args[1].u_obj) > 0) { @@ -76,52 +85,118 @@ static mp_obj_t utils_from_intbuffer_helper(size_t n_args, const mp_obj_t *pos_a mp_float_t *array = (mp_float_t *)ndarray->array; if(args[4].u_obj == mp_const_true) { // swap the bytes before conversion - uint8_t *tmpbuff = m_new(uint8_t, sizeof(int32_t)); - for(size_t i = 0; i < len; i++) { - tmpbuff += sizeof(int32_t); - for(uint8_t j = 0; j < sizeof(int32_t); j++) { - memcpy(--tmpbuff, buffer++, 1); - } - if(buffer_type == UTILS_INT32_BUFFER) { - *array++ = (mp_float_t)(*(int32_t *)tmpbuff); - } else { - *array++ = (mp_float_t)(*(uint32_t *)tmpbuff); + uint8_t *tmpbuff = m_new(uint8_t, sz); + #if ULAB_UTILS_HAS_FROM_INT16_BUFFER | ULAB_UTILS_HAS_FROM_UINT16_BUFFER + if((buffer_type == UTILS_INT16_BUFFER) || (buffer_type == UTILS_UINT16_BUFFER)) { + for(size_t i = 0; i < len; i++) { + tmpbuff += sz; + for(uint8_t j = 0; j < sz; j++) { + memcpy(--tmpbuff, buffer++, 1); + } + if(buffer_type == UTILS_INT16_BUFFER) { + *array++ = (mp_float_t)(*(int16_t *)tmpbuff); + } else { + *array++ = (mp_float_t)(*(uint16_t *)tmpbuff); + } } } + #endif + #if ULAB_UTILS_HAS_FROM_INT32_BUFFER | ULAB_UTILS_HAS_FROM_UINT32_BUFFER + if((buffer_type == UTILS_INT32_BUFFER) || (buffer_type == UTILS_UINT32_BUFFER)) { + for(size_t i = 0; i < len; i++) { + tmpbuff += sz; + for(uint8_t j = 0; j < sz; j++) { + memcpy(--tmpbuff, buffer++, 1); + } + if(buffer_type == UTILS_INT32_BUFFER) { + *array++ = (mp_float_t)(*(int32_t *)tmpbuff); + } else { + *array++ = (mp_float_t)(*(uint32_t *)tmpbuff); + } + } + } + #endif } else { + #if ULAB_UTILS_HAS_FROM_INT16_BUFFER + if(buffer_type == UTILS_INT16_BUFFER) { + for(size_t i = 0; i < len; i++) { + *array++ = (mp_float_t)(*(int16_t *)buffer); + buffer += sz; + } + } + #endif + #if ULAB_UTILS_HAS_FROM_UINT16_BUFFER + if(buffer_type == UTILS_UINT16_BUFFER) { + for(size_t i = 0; i < len; i++) { + *array++ = (mp_float_t)(*(uint16_t *)buffer); + buffer += sz; + } + } + #endif + #if ULAB_UTILS_HAS_FROM_INT32_BUFFER if(buffer_type == UTILS_INT32_BUFFER) { for(size_t i = 0; i < len; i++) { *array++ = (mp_float_t)(*(int32_t *)buffer); - buffer += sizeof(int32_t); - } - } else { - for(size_t i = 0; i < len; i++) { - *array++ = (mp_float_t)(*(uint32_t *)buffer); - buffer += sizeof(int32_t); + buffer += sz; } } + #endif + #if ULAB_UTILS_HAS_FROM_UINT32_BUFFER + if(buffer_type == UTILS_UINT32_BUFFER) { + for(size_t i = 0; i < len; i++) { + *array++ = (mp_float_t)(*(uint32_t *)buffer); + buffer += sz; + } + } + #endif } return MP_OBJ_FROM_PTR(ndarray); } return mp_const_none; } +#ifdef ULAB_UTILS_HAS_FROM_INT16_BUFFER +static mp_obj_t utils_from_int16_buffer(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return utils_from_intbuffer_helper(n_args, pos_args, kw_args, UTILS_INT16_BUFFER); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(utils_from_int16_buffer_obj, 1, utils_from_int16_buffer); +#endif + +#ifdef ULAB_UTILS_HAS_FROM_UINT16_BUFFER +static mp_obj_t utils_from_uint16_buffer(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return utils_from_intbuffer_helper(n_args, pos_args, kw_args, UTILS_UINT16_BUFFER); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(utils_from_uint16_buffer_obj, 1, utils_from_uint16_buffer); +#endif + +#ifdef ULAB_UTILS_HAS_FROM_INT32_BUFFER static mp_obj_t utils_from_int32_buffer(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { return utils_from_intbuffer_helper(n_args, pos_args, kw_args, UTILS_INT32_BUFFER); } MP_DEFINE_CONST_FUN_OBJ_KW(utils_from_int32_buffer_obj, 1, utils_from_int32_buffer); +#endif +#ifdef ULAB_UTILS_HAS_FROM_UINT32_BUFFER static mp_obj_t utils_from_uint32_buffer(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { return utils_from_intbuffer_helper(n_args, pos_args, kw_args, UTILS_UINT32_BUFFER); } MP_DEFINE_CONST_FUN_OBJ_KW(utils_from_uint32_buffer_obj, 1, utils_from_uint32_buffer); +#endif #endif static const mp_rom_map_elem_t ulab_utils_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_utils) }, + #if ULAB_UTILS_HAS_FROM_INT16_BUFFER + { MP_OBJ_NEW_QSTR(MP_QSTR_from_int16_buffer), (mp_obj_t)&utils_from_int16_buffer_obj }, + #endif + #if ULAB_UTILS_HAS_FROM_UINT16_BUFFER + { MP_OBJ_NEW_QSTR(MP_QSTR_from_uint16_buffer), (mp_obj_t)&utils_from_uint16_buffer_obj }, + #endif #if ULAB_UTILS_HAS_FROM_INT32_BUFFER { MP_OBJ_NEW_QSTR(MP_QSTR_from_int32_buffer), (mp_obj_t)&utils_from_int32_buffer_obj }, #endif diff --git a/docs/manual/source/ulab-utils.rst b/docs/manual/source/ulab-utils.rst index 4206c98..15cf978 100644 --- a/docs/manual/source/ulab-utils.rst +++ b/docs/manual/source/ulab-utils.rst @@ -6,8 +6,29 @@ There might be cases, when the format of your data does not conform to ``ulab``, i.e., there is no obvious way to map the data to any of the five supported ``dtype``\ s. A trivial example is an ADC or microphone signal with 32-bit resolution. For such cases, ``ulab`` defines the -``utils`` module, which, at the moment, has two functions that are not -``numpy`` compatible. +``utils`` module, which, at the moment, has four functions that are not +``numpy`` compatible, but which should ease interfacing ``ndarray``\ s +to peripheral devices. + +The ``utils`` module can be enabled by setting the +``ULAB_HAS_UTILS_MODULE`` constant to 1 in +`ulab.h `__: + +.. code:: c + + #ifndef ULAB_HAS_UTILS_MODULE + #define ULAB_HAS_UTILS_MODULE (1) + #endif + +This still does not compile any functions into the firmware. You can add +a function by setting the corresponding pre-processor constant to 1. +E.g., + +.. code:: c + + #ifndef ULAB_UTILS_HAS_FROM_INT16_BUFFER + #define ULAB_UTILS_HAS_FROM_INT16_BUFFER (1) + #endif from_int32_buffer, from_uint32_buffer ------------------------------------- @@ -109,6 +130,13 @@ microcontroller, ``from_(u)intbuffer`` allows a conversion via the +from_int16_buffer, from_uint16_buffer +------------------------------------- + +These two functions are identical to ``utils.from_int32_buffer``, and +``utils.from_uint32_buffer``, with the exception that they convert +16-bit integers to floating point ``ndarray``\ s. + .. code:: # code to be run in CPython diff --git a/docs/ulab-utils.ipynb b/docs/ulab-utils.ipynb index 0ca23d6..4fddc53 100644 --- a/docs/ulab-utils.ipynb +++ b/docs/ulab-utils.ipynb @@ -225,7 +225,24 @@ "source": [ "# ulab utilities\n", "\n", - "There might be cases, when the format of your data does not conform to `ulab`, i.e., there is no obvious way to map the data to any of the five supported `dtype`s. A trivial example is an ADC or microphone signal with 32-bit resolution. For such cases, `ulab` defines the `utils` module, which, at the moment, has two functions that are not `numpy` compatible. " + "\n", + "There might be cases, when the format of your data does not conform to `ulab`, i.e., there is no obvious way to map the data to any of the five supported `dtype`s. A trivial example is an ADC or microphone signal with 32-bit resolution. For such cases, `ulab` defines the `utils` module, which, at the moment, has four functions that are not `numpy` compatible, but which should ease interfacing `ndarray`s to peripheral devices. \n", + "\n", + "The `utils` module can be enabled by setting the `ULAB_HAS_UTILS_MODULE` constant to 1 in [ulab.h](https://github.com/v923z/micropython-ulab/blob/master/code/ulab.h):\n", + "\n", + "```c\n", + "#ifndef ULAB_HAS_UTILS_MODULE\n", + "#define ULAB_HAS_UTILS_MODULE (1)\n", + "#endif\n", + "```\n", + "\n", + "This still does not compile any functions into the firmware. You can add a function by setting the corresponding pre-processor constant to 1. E.g., \n", + "\n", + "```c\n", + "#ifndef ULAB_UTILS_HAS_FROM_INT16_BUFFER\n", + "#define ULAB_UTILS_HAS_FROM_INT16_BUFFER (1)\n", + "#endif\n", + "```" ] }, { @@ -366,6 +383,15 @@ "print('buffer with byteswapping: ', utils.from_uint32_buffer(a, byteswap=True))" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## from_int16_buffer, from_uint16_buffer\n", + "\n", + "These two functions are identical to `utils.from_int32_buffer`, and `utils.from_uint32_buffer`, with the exception that they convert 16-bit integers to floating point `ndarray`s. " + ] + }, { "cell_type": "code", "execution_count": null,