You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
130 lines
4.4 KiB
Markdown
130 lines
4.4 KiB
Markdown
# Generic and functions bodes
|
|
|
|
The generic and function nodes are the basic nodes that you use to create other kind of nodes in the graph.
|
|
|
|
There are 3 generic classes provided by the framework to be used to create new nodes :
|
|
|
|
* `GenericSource`
|
|
* `GenericNode`
|
|
* `GenericSink`
|
|
|
|
They are defined in `cmsisdsp.cg.scheduler`
|
|
|
|
There are 3 other classes that can be used to create new nodes from functions:
|
|
|
|
* `Unary`
|
|
* `Binary`
|
|
* `Dsp`
|
|
|
|
## Generic Nodes
|
|
|
|
Any new kind of node must inherit from one of those classes. Those classes are providing the methods `addInput` and/or `addOutput` to define new IOs.
|
|
|
|
The method `typeName` from the parent class must be overridden.
|
|
|
|
A new kind of node is generally defined as:
|
|
|
|
```python
|
|
class ProcessingNode(GenericNode):
|
|
def __init__(self,name,theType,inLength,outLength):
|
|
GenericNode.__init__(self,name)
|
|
self.addInput("i",theType,inLength)
|
|
self.addOutput("o",theType,outLength)
|
|
|
|
@property
|
|
def typeName(self):
|
|
return "ProcessingNode"
|
|
```
|
|
|
|
See the [simple](../examples/simple/README.md) example for more explanation about how to define a new node.
|
|
|
|
### Methods
|
|
|
|
The constructor of the node is using the `addInput` and/or `addOutput` to define new IOs.
|
|
|
|
```python
|
|
def addInput(self,name,theType,theLength):
|
|
```
|
|
|
|
* `name` is the name of the input. It will becomes a property of the Python object so it must not conflict with existing properties. If `name` is, for instance, "i" then it can be accessed with `node.i` in the code
|
|
* `theType` is the datatype of the IO. It must inherit from `CGStaticType` (see below for more details about defining the types)
|
|
* `theLength` is the amount of **samples** consumed by this IO at each execution of the node
|
|
|
|
```python
|
|
def addOutput(self,name,theType,theLength):
|
|
```
|
|
|
|
* `name` is the name of the input. It will becomes a property of the Python object so it must not conflict with existing properties. If `name` is, for instance, "o" then it can be accessed with `node.o` in the code
|
|
* `theType` is the datatype of the IO. It must inherit from `CGStaticType` (see below for more details about defining the types)
|
|
* `theLength` is the amount of **samples** produced by this IO at each execution of the node
|
|
|
|
```python
|
|
@property
|
|
def typeName(self):
|
|
return "ProcessingNode"
|
|
```
|
|
|
|
This method defines the name of the C++ class implementing the wrapper for this node.
|
|
|
|
### Datatypes
|
|
|
|
Datatypes for the IOs are inheriting from `CGStaticType`.
|
|
|
|
Currently there are two classes defined:
|
|
|
|
* `CType` for the standard CMSIS-DSP types
|
|
* `CStructType` for a C struct
|
|
|
|
#### CType
|
|
|
|
You create such a type with `CType(id)` where `id` is one of the constant coming from the Python wrapper:
|
|
|
|
* F64
|
|
* F32
|
|
* F16
|
|
* Q31
|
|
* Q15
|
|
* Q7
|
|
* UINT32
|
|
* UINT16
|
|
* UINT8
|
|
* SINT32
|
|
* SINT16
|
|
* SINT8
|
|
|
|
For instance, to define a `float32_t` type for an IO you can use `CType(F32)`
|
|
|
|
#### CStructType
|
|
|
|
The constructor has the following definition
|
|
|
|
```python
|
|
def __init__(self,name,python_name,size_in_bytes):
|
|
```
|
|
|
|
* `name` is the name of the C struct
|
|
* `python_name` is the name of the Python class implementing this type (when you generate a Python schedule)
|
|
* `size_in_bytes` is the size of the struct. It should take into account padding. It is used in case of buffer sharing since the datatype of the shared buffer is `int8_t`. The Python script must be able to compute the size of those buffers and needs to know the size of the structure.
|
|
|
|
In Python, there is no `struct`. This datatype is mapped to an object. Object have reference type. Compute graph FIFOs are assuming a value type semantic.
|
|
|
|
As consequence, in Python side you should never copy those structs since it would copy the reference. You should instead copy the members of the struct.
|
|
|
|
If you don't plan on generating a Python scheduler, you can just use whatever name you want for the `python_name`. It will be ignored by the C++ code generation.
|
|
|
|
## Function and constant nodes
|
|
|
|
A Compute graph C++ wrapper is useful when the software components you use have a state that needs to be initialized in the C++ constructor, and preserved between successive calls to the `run` method of the wrapper.
|
|
|
|
Most CMSIS-DSP functions have no state. The compute graph framework is providing some ways to easily use functions in the graph without having to write a wrapper.
|
|
|
|
This feature is relying on the nodes:
|
|
|
|
* `Unary`
|
|
* `Binary`
|
|
* `Dsp`
|
|
* `Constant`
|
|
|
|
All of this is explained in detail in the [simple example with CMSIS-DSP](../examples/simpledsp/README.md).
|
|
|