9.3. Event callback mechanism
9.3.1. Overview
The PikaPython kernel provides an event callback mechanism that supports triggering Python defined callback functions in C events/interrupts.
Note: requires kernel version no less than: v1.8.7
9.3.2. Headers
#include "PikaObj.h"
9.3.3. Data types
typedef PikaObj PikaEventListener;
The event callback mechanism relies on the PikaEventListener event listener, which records the ID of each registered event. When a signal is sent to the event listener, the event listener will call the corresponding Python callback function based on the event ID, and pass the semaphore.
9.3.4. The Event Model
The core of the event model is the PikaEventListener event listener.

The PikaEventListener model is shown above. After registering an event to the event listener, an event item Event Item will be recorded inside the PikaEventListener, including.
Event IDthe unique ID of the eventEvent Handler Objectevent object, which records all the information about the event itemEvent CallBackevent callback function ( Python function )
When the Event Signal event signal arrives, the event listener will match the Event ID to find the corresponding event item, then pass the signal code Event Code to Event CallBak to trigger the callback function.

9.3.5. Event callback mechanism flow
Initialize the event listener
register callback functions in Python
Signal the event listener in C (usually in an interrupt or a callback in C)
the callback function registered in Python is executed
9.3.6. Support event callbacks via PikaStdDevice
Inheriting PikaStdDevice is the easiest way to support event callbacks, the PikaStdDevice.BaseDev device base class already supports the event registration method addEventCallBack.
class BaseDev:
def addEventCallBack(self, eventCallback: any): ...
# need override
def platformGetEventId(self): ...
The device classes in
PikaStdDevice(e.g. GPIO) all inherit fromBaseDev, so they all get theaddEventCallBackmethod and can register callbacks.
/package/PikaStdDevice/PikaStdDevice.pyi
class GPIO(BaseDev):
...
After the platform driver inherits from PikaStdDevice.GPIO, it also gets the addEventCallBack method.
/package/TemplateDevice/TemplateDevice.pyi
# TemplateDevice.pyi
class GPIO(PikaStdDevice.GPIO):
# overrid
...
def platformGetEventId(self): ...
...
Just override the platformGetEventId platform method to be able to support registration callbacks.
For example.
/package/TemplateDevice/TemplateDevice_GPIO.c
const uint32_t GPIO_PA8_EVENT_ID = 0x08;
void TemplateDevice_GPIO_platformGetEventId(PikaObj* self) {
char* pin = obj_getStr(self, "pin");
if (strEqu(pin, "PA8")) {
obj_setInt(self, "eventId", GPIO_PA8_EVENT_ID);
}
}
9.3.7. Registering callback functions in Python
Define a callback function
callBack1that takes an input parametersignal,signalcan receive the incoming signal number.
/examples/TemplateDevice/gpio_cb.py
import TemplateDevice
io1 = TemplateDevice.GPIO()
io1.setPin('PA8')
io1.setMode('in')
io1.enable()
EVENT_SIGAL_IO_RISING_EDGE = 0x01
EVENT_SIGAL_IO_FALLING_EDGE = 0x02
def callBack1(signal):
if signal == EVENT_SIGAL_IO_RISING_EDGE:
print('get rising edge!')
elif signal == EVENT_SIGAL_IO_FALLING_EDGE:
print('get falling edge!')
io1.addEventCallBack(callBack1)
9.3.8. Signal triggering
Send a signal to PikaEventListener when an event callback needs to be triggered.
Example: /port/linux/test/event-test.cpp
Get the event listener provided by
PikaStdDeviceviaextern PikaEventListener* g_pika_device_event_listener.Send
eventIDandsignal codeviapks_eventLisener_sendSignal.
extern PikaEventListener* g_pika_device_event_listener;
#define EVENT_SIGAL_IO_RISING_EDGE 0x01
#define EVENT_SIGAL_IO_FALLING_EDGE 0x02
#define GPIO_PA8_EVENT_ID 0x08
TEST(event, gpio) {
/* init */
PikaObj* pikaMain = newRootObj("pikaMain", New_PikaMain);
/* run */
pikaVM_runFile(pikaMain, "... /... /examples/TemplateDevice/gpio_cb.py");
/* simulate run in the call back */
pks_eventLisener_sendSignal(g_pika_device_event_listener, GPIO_PA8_EVENT_ID,
EVENT_SIGAL_IO_RISING_EDGE);
pks_eventLisener_sendSignal(g_pika_device_event_listener, GPIO_PA8_EVENT_ID,
EVENT_SIGAL_IO_FALLING_EDGE);
...
}
Running results.
get rising edge!
get falling edg!
9.3.8.1. Waiting for the return value
Event callback functions can have return values, such as returning signal directly.
def callBack1(signal):
return signal
io1.addEventCallBack(callBack1)
This function requires OS support, and the __platform_thread_delay() method needs to be overridden to be able to dispatch events to the main process while waiting for a return value.
If a return value is required, the trigger event can use pks_eventLisener_sendSignalAwaitResult to get the return value of the callback function, which is an ``Arg*` type.
Arg* res_123 = pks_eventLisener_sendSignalAwaitResult(
g_pika_device_event_listener, GPIO_PA8_EVENT_ID, 123);
int res = arg_getInt(res_123);
Note: requires kernel version
>= v1.11.7
9.3.9. Advanced: Custom event registration functions
In addition to event callbacks supported by
PikaStdDevice, you can also customize event registration functions, which is an advanced part.Custom event registration requires a better understanding of PikaPython’s C-module mechanism and object mechanism.
Define a Python interface to a C module that receives incoming event callback functions.
For example.
/package/PikaStdDevice/PikaStdDevice.pyi
class BaseDev:
def addEventCallBack(self, eventCallback: any): ...
The type annotation for the event callback function is any.
Registering events in the C module implementation
Example: /package/PikaStdDevice/PikaStdDevice_BaseDev.c
PikaEventListener* g_pika_device_event_listener;
void PikaStdDevice_BaseDev_addEventCallBack(PikaObj* self, Arg* eventCallBack) {
obj_setArg(self, "eventCallBack", eventCallBack);
/* init event_listener for the first time */
if (NULL == g_pika_device_event_listener) {
pks_eventLisener_init(&g_pika_device_event_listener);
}
if (PIKA_RES_OK != obj_runNativeMethod(self, "platformGetEventId", NULL)) {
obj_setErrorCode(self, 1);
__platform_printf("Error: Method %s no found.\r\n",
"platformGetEventId");
}
uint32_t eventId = obj_getInt(self, "eventId");
pks_eventLicener_registEvent(g_pika_device_event_listener, eventId, self);
}
Create a global
PikaEventListener:g_pika_device_event_listener.Pass
selfasevent handler objectandevnetCallBackintoself.Get
evnetID.This example gets the
eventIDby calling theplatformGetEventId()platform function, which requiresBaseDevinheritance, then rewritesplatformGetEventId()and setsself. eventIdin the overriddenplatformGetEventId().For example: /package/TemplateDevice/TemplateDevice_GPIO.c
Call
pks_eventLicener_registEventto registereventIdandselfinto the event listener.