Pycardium is our micropython port. You can find it [here](https://git.card10.badge.events.ccc.de/card10/firmware/tree/master/pycardium).
This page gives an overview on adding new C modules to pycardium. These modules are mostly meant to make use of the [Epicardium API](./epicardium_api_development) to enable python scripts to interact with card10.
## Basic Structure
#### Module Source
Modules live in [`pycardium/modules`](https://git.card10.badge.events.ccc.de/card10/firmware/tree/master/pycardium/modules). To add a new module, create a file in there containing the following example content. This module is named `example` but you should of course replace that with your own name:
Next, you need to add your module to [`pycardium/meson.build`](https://git.card10.badge.events.ccc.de/card10/firmware/blob/master/pycardium/meson.build). There is a list of module sources at the very top called `modsrc` where you need to add your c file (`modules/example.c`).
#### QSTR Definitions
If you now run `ninja -C build/`, you will hit a few errors regarding missing QSTR definitions. With the example module, those will look similar to
```text
../pycardium/modules/example.c:15:46: error: 'MP_QSTR_example' undeclared here (not in a function)
To fix those, you need to add all of the missing QSTRs to [`pycardium/modules/qstrdefs.h`](https://git.card10.badge.events.ccc.de/card10/firmware/blob/master/pycardium/modules/qstrdefs.h). Add a section for your module with all the necessary definitions (ideally sorted):
```c
/* example */
Q(example)
Q(hello)
```
Each of these `Q(...)` will expand to a define for `MP_QSTR_...`. So `Q(example)` corresponds to `MP_QSTR_example`.
What are QSTRs? Take a look at the [QSTR](#qstr) section of this page.
#### Enable Module
Last step is to enable your module in the MicroPython config header [`pycardium/mpconfigport.h`](https://git.card10.badge.events.ccc.de/card10/firmware/blob/master/pycardium/mpconfigport.h). Search for the list of existing modules and add yours in there as well. The line should look similar to this:
```c
#define MODULE_EXAMPLE_ENABLED (1)
```
## Wrapping Epicardium API
Most modules will probably make use of the Epicardium API. Doing so does not require any extra work apart from adding
```c
#include"epicardium.h"
staticmp_obj_tmp_example_hello(mp_obj_tnumber)
{
charbuf[80];
snprintf(buf,"Hello from example: %d\n",num);
/* Call an Epicardium API function */
epic_uart_write_str(buf,strlen(buf));
returnmp_const_none;
}
```
## QSTR
QSTRs are so called "interned strings". This means they are not allocated like normal python objects but instead live in flash and are indexed. This allow MicroPython to very efficiently use them as identifiers. According to them, comparing two QSTR is as fast as comparing integers.
Unfortunately, the way these QSTRs are collected from the source files is quite weird. MicroPython comes with a few python scripts (namely [`makeqstrdefs.py`](https://github.com/micropython/micropython/blob/master/py/makeqstrdefs.py) and [`makeqstrdata.py`](https://github.com/micropython/micropython/blob/master/py/makeqstrdata.py)) that parse the C source files and search for uses of `MP_QSTR_*`. These are then sorted and indexed into a header file called `qstrdefs.collected.h`. This is closely tied in with their Makefiles.
As we use our own build system, we had to somehow wrap this generation to work for us as well. This is done using a few scripts in [`lib/micropython`](https://git.card10.badge.events.ccc.de/card10/firmware/tree/master/lib/micropython).
Currently, our build system does **not** parse the module sources to search for QSTRs. Instead all QSTRs needed by modules need to be defined in the header [`pycardium/modules/qstrdefs.h`](https://git.card10.badge.events.ccc.de/card10/firmware/blob/master/pycardium/modules/qstrdefs.h).