8.3. 事件回调机制

    注意:需要内核版本不低于: v1.8.7

    8.3.2. 头文件

    8.3.3. 数据类型

    事件回调机制主要依靠 PikaEventListener 事件监听器,事件监听器中记录了每个被注册的事件 ID,当有信号发送至事件监听器时,事件监听器将根据 事件 ID 将调用相应的 Python 回调函数,并传递信号量。

    事件模型的核心是 PikaEventListener 事件监听器。

    PikaEventListener 的模型如上图所示,向事件监听器中注册事件后,将会在 PikaEventListener 内部记录下一个事件项 Event Item,包括:

    • Event ID 事件的唯一 ID

    • Event Handler Object 事件对象,记录了事件项的全部信息

      • Event CallBack 事件回调函数 ( Python 函数 )

    Event Signal 事件信号到来时,事件监听器将会匹配 Event ID 找到相应的事件项,然后再将信号代码Event Code传递给 Event CallBak 然后触发回调函数。

    _images/image-20220619104053576.png

    8.3.5. 事件回调机制流程

    1. 初始化事件监听器

    2. 在 Python 中注册回调函数

    3. 在 C 中向事件监听器发送信号 (通常在中断或 C 的回调中)

    8.3.6. 通过 PikaStdDevice 支持事件回调

    继承 PikaStdDevice 是支持事件回调的最简单方式,PikaStdDevice.BaseDev 设备基本类已经支持了事件注册方法 addEventCallBack

    1. class BaseDev:
    2. def addEventCallBack(self, eventCallback: any): ...
    3. # need override
    4. def platformGetEventId(self):...
    • PikaStdDevice 中的设备类(如 GPIO)都继承了 BaseDev,因此都获得了 addEventCallBack 的方法,能够注册回调。

    /package/PikaStdDevice/PikaStdDevice.pyi

    平台驱动从 PikaStdDevice.GPIO 继承后,也获得了 addEventCallBack 方法。

    1. # TemplateDevice.pyi
    2. class GPIO(PikaStdDevice.GPIO):
    3. # overrid
    4. ···
    5. ···

    只需要重写 platformGetEventId 平台方法,就能够支持注册回调。

    例如:

    /package/TemplateDevice/TemplateDevice_GPIO.c

    1. const uint32_t GPIO_PA8_EVENT_ID = 0x08;
    2. char* pin = obj_getStr(self, "pin");
    3. if (strEqu(pin, "PA8")) {
    4. obj_setInt(self, "eventId", GPIO_PA8_EVENT_ID);
    5. }
    6. }
    • 定义一个回调函数 callBack1,接收一个输入参数 signalsignal能够接收传入的信号码。

    /examples/TemplateDevice/gpio_cb.py

    8.3.8. 信号触发

    在需要触发事件回调时向 PikaEventListener 发送信号。

    例如:/port/linux/test/event-test.cpp

    • 通过 extern PikaEventListener* g_pika_device_event_listener 得到 PikaStdDevice 提供的事件监听器。

    • 通过 pks_eventLisener_sendSignal 发送 eventIDsignal code

    1. extern PikaEventListener* g_pika_device_event_listener;
    2. #define EVENT_SIGAL_IO_RISING_EDGE 0x01
    3. #define EVENT_SIGAL_IO_FALLING_EDGE 0x02
    4. #define GPIO_PA8_EVENT_ID 0x08
    5. TEST(event, gpio) {
    6. /* init */
    7. PikaObj* pikaMain = newRootObj("pikaMain", New_PikaMain);
    8. /* run */
    9. pikaVM_runFile(pikaMain, "../../examples/TemplateDevice/gpio_cb.py");
    10. /* simulate run in the call back */
    11. pks_eventLisener_sendSignal(g_pika_device_event_listener, GPIO_PA8_EVENT_ID,
    12. EVENT_SIGAL_IO_RISING_EDGE);
    13. pks_eventLisener_sendSignal(g_pika_device_event_listener, GPIO_PA8_EVENT_ID,
    14. EVENT_SIGAL_IO_FALLING_EDGE);
    15. ...
    16. }
    1. get rising edge!
    2. get falling edge!

    8.3.9. 进阶:自定义事件注册函数

    • 自定义事件注册需要比较了解 PikaScript 的 C 模块机制和对象机制。

    • 定义一个 C 模块的 Python 接口,接收传入的事件回调函数。

    例如:

    /package/PikaStdDevice/PikaStdDevice.pyi

    事件回调函数的类型注解是 。

    • 在 C 模块的实现中注册事件

    例如:

    1. PikaEventListener* g_pika_device_event_listener;
    2. void PikaStdDevice_BaseDev_addEventCallBack(PikaObj* self, Arg* eventCallBack) {
    3. obj_setArg(self, "eventCallBack", eventCallBack);
    4. /* init event_listener for the first time */
    5. if (NULL == g_pika_device_event_listener) {
    6. pks_eventLisener_init(&g_pika_device_event_listener);
    7. }
    8. if (PIKA_RES_OK != obj_runNativeMethod(self, "platformGetEventId", NULL)) {
    9. obj_setErrorCode(self, 1);
    10. __platform_printf("Error: Method %s no found.\r\n",
    11. "platformGetEventId");
    12. }
    13. uint32_t eventId = obj_getInt(self, "eventId");
    14. pks_eventLicener_registEvent(g_pika_device_event_listener, eventId, self);
    15. }
    • 创建一个全局的 PikaEventListenerg_pika_device_event_listener

    • self 作为 Event Handler Object,将 evnetCallBack 传入 self

    • 获取 evnetID

      • 这个例子中通过调用 platformGetEventId() 平台函数来获得 eventID,需要 BaseDev 继承,然后重写 platformGetEventId(),在重写后的 platformGetEventId() 中设置 self.eventId

      • 例如:/package/TemplateDevice/TemplateDevice_GPIO.c