1 /* ----------------------------------------------------------------------
2  * Project:      CMSIS DSP Python Wrapper
3  * Title:        cmsismodule.c
4  * Description:  C code for the CMSIS-DSP Python wrapper
5  *
6  * $Date:        27 April 2021
7  * $Revision:    VV1.0
8  *
9  * Target Processor: Cortex-M cores
10  * -------------------------------------------------------------------- */
11 /*
12  * Copyright (C) 2010-2021 ARM Limited or its affiliates. All rights reserved.
13  *
14  * SPDX-License-Identifier: Apache-2.0
15  *
16  * Licensed under the Apache License, Version 2.0 (the License); you may
17  * not use this file except in compliance with the License.
18  * You may obtain a copy of the License at
19  *
20  * www.apache.org/licenses/LICENSE-2.0
21  *
22  * Unless required by applicable law or agreed to in writing, software
23  * distributed under the License is distributed on an AS IS BASIS, WITHOUT
24  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25  * See the License for the specific language governing permissions and
26  * limitations under the License.
27  */
28 #ifndef CMSISMODULE_H
29 #define CMSISMODULE_H
30 #define NPY_NO_DEPRECATED_API NPY_1_23_API_VERSION
31 
32 #include <numpy/numpyconfig.h>
33 
34 // Check it is built with right version
35 // (should be backward compatible down to 1.23.5)
36 // https://github.com/numpy/numpy/blob/main/numpy/_core/include/numpy/numpyconfig.h
37 #if (NPY_API_VERSION != NPY_2_0_API_VERSION  )
38 #error("Error building with wrong NumPy API version")
39 #endif
40 
41 #ifdef WIN
42 #pragma warning( disable : 4013 )
43 #pragma warning( disable : 4244 )
44 #endif
45 
46 #include <Python.h>
47 
48 #define CAT1(A,B) A##B
49 #define CAT(A,B) CAT1(A,B)
50 
51 
52 #include "arm_math.h"
53 
54 
55 #include <numpy/arrayobject.h>
56 #include <numpy/ndarraytypes.h>
57 
58 #if PY_MAJOR_VERSION >= 3
59 #define IS_PY3K
60 #endif
61 
62 struct module_state {
63     PyObject *error;
64 };
65 
66 #if PY_MAJOR_VERSION >= 3
67 #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
68 #else
69 #define GETSTATE(m) (&_state)
70 static struct module_state _state;
71 #endif
72 
73 static PyObject *
error_out(PyObject * m)74 error_out(PyObject *m) {
75     struct module_state *st = GETSTATE(m);
76     PyErr_SetString(st->error, "something bad happened");
77     return NULL;
78 }
79 
80 #define DSPType(name,thenewfunc,deallocfunc,initfunc,methods)\
81 static PyTypeObject dsp_##name##Type = {          \
82     PyVarObject_HEAD_INIT(NULL, 0)               \
83     .tp_name=MODNAME"." #name,                   \
84     .tp_basicsize = sizeof(dsp_##name##Object),   \
85     .tp_itemsize = 0,                            \
86     .tp_dealloc = (destructor)deallocfunc,       \
87     .tp_flags =  Py_TPFLAGS_DEFAULT,           \
88     .tp_doc = #name,                             \
89     .tp_init = (initproc)initfunc,               \
90     .tp_new = (newfunc)thenewfunc,                \
91     .tp_methods = methods  \
92    };
93 
94 
95 #define MEMCPY(DST,SRC,NB,FORMAT) \
96 for(memCpyIndex = 0; memCpyIndex < (NB) ; memCpyIndex++)\
97 {                                \
98   (DST)[memCpyIndex] = (FORMAT)(SRC)[memCpyIndex];       \
99 }
100 
101 #define GETFIELD(NAME,FIELD,FORMAT)                                           \
102 static PyObject *                                                             \
103 Method_##NAME##_##FIELD(dsp_##NAME##Object *self, PyObject *ignored)\
104 {                                                                             \
105     return(Py_BuildValue(FORMAT,self->instance->FIELD));                      \
106 }
107 
108 #define GETFIELDARRAY(NAME,FIELD,FORMAT)                                           \
109 static PyObject *                                                             \
110 Method_##NAME##_##FIELD(dsp_##NAME##Object *self, PyObject *ignored)\
111 {                                                                             \
112     return(specific_##NAME##_##FIELD(self->instance));                      \
113 }
114 
115 #define INITARRAYFIELD(FIELD,FORMAT,SRCFORMAT,DSTFORMAT)                         \
116     if (FIELD)                                                                \
117     {                                                                         \
118        PyArray_Descr *desct=PyArray_DescrFromType(FORMAT);                    \
119        PyArrayObject *FIELD##c = (PyArrayObject *)PyArray_FromAny(FIELD,desct,\
120         1,0,NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_ALIGNED | NPY_ARRAY_FORCECAST, \
121         NULL);                                                                \
122        if (FIELD##c)                                                          \
123        {                                                                      \
124            uint32_t memCpyIndex; \
125            SRCFORMAT *f=(SRCFORMAT*)PyArray_DATA(FIELD##c);                   \
126            uint32_t n = PyArray_SIZE(FIELD##c);                               \
127            self->instance->FIELD =PyMem_Malloc(sizeof(DSTFORMAT)*n);                \
128            MEMCPY((DSTFORMAT*)self->instance->FIELD ,f,n,DSTFORMAT);                      \
129            Py_DECREF(FIELD##c);                                               \
130        }                                                                      \
131     }
132 #define GETCARRAY(PYVAR,CVAR,FORMAT,SRCFORMAT,DSTFORMAT)                                \
133     if (PYVAR)                                                                \
134     {                                                                         \
135        PyArray_Descr *desct=PyArray_DescrFromType(FORMAT);                    \
136        PyArrayObject *PYVAR##c = (PyArrayObject *)PyArray_FromAny(PYVAR,desct,\
137         1,0,NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_ALIGNED | NPY_ARRAY_FORCECAST, \
138         NULL);                                                                \
139        if (PYVAR##c)                                                          \
140        {                                                                      \
141            uint32_t memCpyIndex; \
142            SRCFORMAT *f=(SRCFORMAT*)PyArray_DATA(PYVAR##c);                         \
143            uint32_t n = PyArray_SIZE(PYVAR##c);                               \
144            CVAR =PyMem_Malloc(sizeof(DSTFORMAT)*n);                                 \
145            MEMCPY(CVAR ,f,n,DSTFORMAT);                               \
146            Py_DECREF(PYVAR##c);                                               \
147        }                                                                      \
148     }
149 
150 #define GETARGUMENT(FIELD,FORMAT,SRCFORMAT,DSTFORMAT)                          \
151     uint32_t arraySize##FIELD=0;                                               \
152     if (FIELD)                                                                 \
153     {                                                                          \
154        PyArray_Descr *desct=PyArray_DescrFromType(FORMAT);                     \
155        PyArrayObject *FIELD##c = (PyArrayObject *)PyArray_FromAny(FIELD,desct, \
156         1,0,NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_ALIGNED | NPY_ARRAY_FORCECAST,  \
157         NULL);                                                                 \
158        if (FIELD##c)                                                           \
159        {                                                                       \
160            uint32_t memCpyIndex; \
161            SRCFORMAT *f=(SRCFORMAT*)PyArray_DATA(FIELD##c);                    \
162            arraySize##FIELD = PyArray_SIZE(FIELD##c);                          \
163            FIELD##_converted =PyMem_Malloc(sizeof(DSTFORMAT)*arraySize##FIELD);\
164            MEMCPY(FIELD##_converted ,f,arraySize##FIELD,DSTFORMAT);            \
165            Py_DECREF(FIELD##c);                                                \
166        }                                                                       \
167     }
168 
169 #define FREEARGUMENT(FIELD) \
170     PyMem_Free(FIELD)
171 
172 #ifdef IS_PY3K
173 #define ADDTYPE(name)                                               \
174     if (PyType_Ready(&dsp_##name##Type) < 0)                         \
175         return;                                              \
176                                                                     \
177     Py_INCREF(&dsp_##name##Type);                                    \
178     PyModule_AddObject(module, #name, (PyObject *)&dsp_##name##Type);
179 #else
180 #define ADDTYPE(name)                                               \
181     if (PyType_Ready(&dsp_##name##Type) < 0)                         \
182         return;                                                     \
183                                                                     \
184     Py_INCREF(&dsp_##name##Type);                                    \
185     PyModule_AddObject(module, #name, (PyObject *)&dsp_##name##Type);
186 #endif
187 
capsule_cleanup(PyObject * capsule)188 void capsule_cleanup(PyObject *capsule) {
189     void *memory = PyCapsule_GetPointer(capsule, "cmsisdsp capsule");
190     PyMem_Free(memory);
191 }
192 
193 #define FLOATARRAY2(OBJ,NB1,NB2,DATA)                                                       \
194     npy_intp dims##OBJ[2];                                                                       \
195     dims##OBJ[0]=NB1;                                                                            \
196     dims##OBJ[1]=NB2;                                                                            \
197     const int ND##OBJ=2;                                                                         \
198     PyArrayObject *OBJ=(PyArrayObject*)PyArray_SimpleNewFromData(ND##OBJ, dims##OBJ, NPY_FLOAT, DATA);\
199     PyObject *capsule##OBJ = PyCapsule_New(DATA, "cmsisdsp capsule",capsule_cleanup);                       \
200     PyArray_SetBaseObject(OBJ, capsule##OBJ);
201 
202 #define FLOATARRAY1(OBJ,NB1,DATA)                                                                     \
203     npy_intp dims##OBJ[1];                                                                            \
204     dims##OBJ[0]=NB1;                                                                                 \
205     const int ND##OBJ=1;                                                                              \
206     PyArrayObject *OBJ=(PyArrayObject*)PyArray_SimpleNewFromData(ND##OBJ, dims##OBJ, NPY_FLOAT, DATA);\
207     PyObject *capsule##OBJ = PyCapsule_New(DATA, "cmsisdsp capsule",capsule_cleanup);                       \
208     PyArray_SetBaseObject(OBJ, capsule##OBJ);
209 
210 #define FLOAT64ARRAY1(OBJ,NB1,DATA)                                                          \
211     npy_intp dims##OBJ[1];                                                                        \
212     dims##OBJ[0]=NB1;                                                                             \
213     const int ND##OBJ=1;                                                                          \
214     PyArrayObject *OBJ=(PyArrayObject*)PyArray_SimpleNewFromData(ND##OBJ, dims##OBJ, NPY_DOUBLE, DATA);\
215     PyObject *capsule##OBJ = PyCapsule_New(DATA, "cmsisdsp capsule",capsule_cleanup);                       \
216     PyArray_SetBaseObject(OBJ, capsule##OBJ);
217 
218 #define UINT32ARRAY1(OBJ,NB1,DATA)                                                           \
219     npy_intp dims##OBJ[1];                                                                        \
220     dims##OBJ[0]=NB1;                                                                             \
221     const int ND##OBJ=1;                                                                          \
222     PyArrayObject *OBJ=(PyArrayObject*)PyArray_SimpleNewFromData(ND##OBJ, dims##OBJ, NPY_UINT32, DATA);\
223     PyObject *capsule##OBJ = PyCapsule_New(DATA, "cmsisdsp capsule",capsule_cleanup);                       \
224     PyArray_SetBaseObject(OBJ, capsule##OBJ);
225 
226 #define INT32ARRAY1(OBJ,NB1,DATA)                                                           \
227     npy_intp dims##OBJ[1];                                                                       \
228     dims##OBJ[0]=NB1;                                                                            \
229     const int ND##OBJ=1;                                                                         \
230     PyArrayObject *OBJ=(PyArrayObject*)PyArray_SimpleNewFromData(ND##OBJ, dims##OBJ, NPY_INT32, DATA);\
231     PyObject *capsule##OBJ = PyCapsule_New(DATA, "cmsisdsp capsule",capsule_cleanup);                       \
232     PyArray_SetBaseObject(OBJ, capsule##OBJ);
233 
234 #define INT16ARRAY1(OBJ,NB1,DATA)                                                           \
235     npy_intp dims##OBJ[1];                                                                       \
236     dims##OBJ[0]=NB1;                                                                            \
237     const int ND##OBJ=1;                                                                         \
238     PyArrayObject *OBJ=(PyArrayObject*)PyArray_SimpleNewFromData(ND##OBJ, dims##OBJ, NPY_INT16, DATA);\
239     PyObject *capsule##OBJ = PyCapsule_New(DATA, "cmsisdsp capsule",capsule_cleanup);                       \
240     PyArray_SetBaseObject(OBJ, capsule##OBJ);
241 
242 #define INT8ARRAY1(OBJ,NB1,DATA)                                                           \
243     npy_intp dims##OBJ[1];                                                                      \
244     dims##OBJ[0]=NB1;                                                                           \
245     const int ND##OBJ=1;                                                                        \
246     PyArrayObject *OBJ=(PyArrayObject*)PyArray_SimpleNewFromData(ND##OBJ, dims##OBJ, NPY_BYTE, DATA);\
247     PyObject *capsule##OBJ = PyCapsule_New(DATA, "cmsisdsp capsule",capsule_cleanup);                       \
248     PyArray_SetBaseObject(OBJ, capsule##OBJ);
249 
250 #define TYP_ARRAY1(OBJ,NB1,DATA,NPYTYPE)                                                  \
251     npy_intp dims##OBJ[1];                                                                     \
252     dims##OBJ[0]=NB1;                                                                          \
253     const int ND##OBJ=1;                                                                       \
254     PyArrayObject *OBJ=(PyArrayObject*)PyArray_SimpleNewFromData(ND##OBJ, dims##OBJ, NPYTYPE, DATA);\
255     PyObject *capsule##OBJ = PyCapsule_New(DATA, "cmsisdsp capsule",capsule_cleanup);                       \
256     PyArray_SetBaseObject(OBJ, capsule##OBJ);
257 
258 #define MATRIXFROMNUMPY(EXT,TYP,SRCTYPE,NUMPYTYPE)                                   \
259 void EXT##MatrixFromNumpy(arm_matrix_instance_##EXT *s,PyObject *o)                   \
260 {                                                                            \
261     s->pData=NULL;                                                           \
262     s->numRows=0;                                                            \
263     s->numCols=0;                                                            \
264                                                                              \
265     PyArray_Descr *desct=PyArray_DescrFromType(NUMPYTYPE);                    \
266     PyArrayObject *cdata = (PyArrayObject *)PyArray_FromAny(o,desct,         \
267         1,0,NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_ALIGNED | NPY_ARRAY_FORCECAST, \
268         NULL);                                                                \
269     if (cdata)                                                               \
270     {                                                                        \
271            uint32_t memCpyIndex;                                             \
272            SRCTYPE *f=(SRCTYPE*)PyArray_DATA(cdata);                           \
273            s->numRows=PyArray_DIM(cdata,0);                                  \
274            s->numCols=PyArray_DIM(cdata,1);                                  \
275            uint32_t nb = PyArray_SIZE(cdata);                                \
276            s->pData = PyMem_Malloc(sizeof(TYP)*nb);                                \
277            MEMCPY(s->pData ,f,nb,TYP);                                       \
278            Py_DECREF(cdata);                                                 \
279     }                                                                        \
280                                                                              \
281                                                                              \
282                                                                              \
283 }
284 
285 
286 
287 #define CREATEMATRIX(EXT,TYP)                                        \
288 void create##EXT##Matrix(arm_matrix_instance_##EXT *s,uint32_t r,uint32_t c)\
289 {                                                                    \
290                                                                      \
291     s->pData=PyMem_Malloc(sizeof(TYP)*r*c);                                \
292     s->numRows=r;                                                    \
293     s->numCols=c;                                                    \
294 }
295 
296 #define FREEMATRIX(s) PyMem_Free((s)->pData)
297 
298 #define NUMPYVECTORFROMBUFFER(EXT,CTYPE,NUMPYTYPE_FROMC)                                          \
299 PyObject *NumpyVectorFrom##EXT##Buffer(CTYPE *ptr,int nb)                                         \
300 {                                                                                                 \
301     npy_intp dims[1];                                                                             \
302     const int ND=1;                                                                               \
303     dims[0]=nb;                                                                                   \
304                                                                                                   \
305     void *pDst=PyMem_Malloc(sizeof(CTYPE) *nb);                                                   \
306     memcpy((void*)pDst,(void*)ptr,sizeof(CTYPE)*nb);                                              \
307                                                                                                   \
308     PyArrayObject *OBJ=(PyArrayObject*)PyArray_SimpleNewFromData(ND, dims, NUMPYTYPE_FROMC, pDst);\
309     PyObject *capsule = PyCapsule_New(pDst, "cmsisdsp capsule",capsule_cleanup);                             \
310     PyArray_SetBaseObject(OBJ, capsule);                                                          \
311     PyObject *pythonResult = Py_BuildValue("O",OBJ);                                              \
312     Py_DECREF(OBJ);                                                                               \
313     return(pythonResult);                                                                         \
314 }
315 
316 
317 
318 
319 #define NUMPYARRAYFROMMATRIX(EXT,NUMPYTYPE_FROMC)                                                       \
320 PyObject *NumpyArrayFrom##EXT##Matrix(arm_matrix_instance_##EXT *mat)                                   \
321 {                                                                                                       \
322     npy_intp dims[2];                                                                                   \
323     dims[0]=mat->numRows;                                                                               \
324     dims[1]=mat->numCols;                                                                               \
325     const int ND=2;                                                                                     \
326     PyArrayObject *OBJ=(PyArrayObject*)PyArray_SimpleNewFromData(ND, dims, NUMPYTYPE_FROMC, mat->pData);\
327     PyObject *capsule = PyCapsule_New(mat->pData, "cmsisdsp capsule",capsule_cleanup);                  \
328     PyArray_SetBaseObject(OBJ, capsule);                                                                \
329     PyObject *pythonResult = Py_BuildValue("O",OBJ);                                                    \
330     Py_DECREF(OBJ);                                                                                     \
331     return(pythonResult);                                                                               \
332 }
333 
334 
335 
336 
337 
338 
339 #endif /* #ifndef CMSISMODULE_H */
340