• 如何在python中实现capl语言里的回调函数


    CAPL:回调函数

    CAPL是一种程序语言,其中程序块的执行由事件控制。 这些程序块被称为事件程序。在事件程序中定义的程序代码在事件发生时执行。换句话说,事件程序就是事件函数,当事件函数关联的事件被触发时,会自动执行此事件函数函数体。事件函数也称为回调函数

    事件函数的标志就是关键字on,比如:

    • on key 表示当键盘按下小写字母a时触发此事件函数执行
    • on message 表示当接收到消息时触发此事件函数执行
    • on start 表示当canoe软件运行时触发此事件函数执行
    • on sysvar 表示系统变量值发生改变时触发此事件函数执行

    还有很多此类函数,你可以通过在capl文件的左侧的导航栏里右击插入不同类型的事件函数

    事件函数
    事件函数的作用是什么?

    就是在程序运行期间,可以随时监控某种事件的发生,执行对应的操作。比如你想在can总线上监测收到can消息0x11时获取can消息数据,就可以使用on message 0x11

    on message 0x11
    {
      byte msg_bytes[8];
      int i;
      for(i=0;i<8;i++)
      {
        msg_bytes[i] = this.byte(i);
      }
    }  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    那为什么把它称为回调函数呢?

    可能是虽然主程序里的代码在从上往下按顺序在执行,但是在这期间只要触发事件函数的条件发生改变,就会“回头”执行事件函数。当然,主程序和事件函数是异步执行

    这里有一些注意事项:

    • Simulation Setup仿真界面插入的Network Node网络节点,加载的capl脚本是没有主程序MainTest的
    • Test Modules和Test Units加载的capl脚本,是不允许使用system类型的事件函数的

    system类型的事件函数不允许使用

    Python:回调函数

    python执行回调函数,是在调用某个函数时,把回调函数指针当作参数传入要调用的函数中,在函数内部调用回调函数

    def OnEvent_1():
        print("callback up")
    
    def TriggerFunc(fn):
        fn()
    
    if __name__ == "__main__":
        TriggerFunc(OnEvent_1)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在执行TriggerFunc()时,通过传入OnEvent_1()函数指针作为参数,在TriggerFunc()函数体内部调用OnEvent_1()实现回调

    所以,OnEvent_1()函数是回调函数,执行TriggerFunc()函数就可以看作触发回调函数的条件

    这里有两个注意点:

    • 函数指针是指向函数的指针变量,用函数名表示,不能有括号“()”
    • 调用函数时函数名必须有括号“()”才能调用

    capl中的事件函数,有几个特点:

    • 函数体和触发条件定义明确
    • 无限循环监测触发条件是否触发
    • 和主函数异步执行

    所以在python中想实现这些特点,可以这样:

    import time
    import threading
    
    def OnEvent_1(): # 事件函数1
        print("OnEvent_1 up")
    
    def OnEvent_2(): # 事件函数2
        print("OnEvent_2 up")
    
    class RegistEvents(): # 全局变量,存入事件函数指针和对应的触发条件
        registEvents = {} # 存入key:value,key是事件函数指针,value是触发此事件函数的条件
    
    def TriggerFunc(): # 异步函数,用来监测触发条件是否触发,如果触发就执行对应的函数
        currentRegistEvents = {} # 当前的事件和对应条件存入这里
        for event in RegistEvents.registEvents.keys():
            currentRegistEvents[event] = RegistEvents.registEvents[event]
        while True:
            time.sleep(0.01)
            for event in RegistEvents.registEvents.keys():
                if currentRegistEvents[event] != RegistEvents.registEvents[event]:
                    event()
                    currentRegistEvents[event] = RegistEvents.registEvents[event]
    
    if __name__ == "__main__":
        RegistEvents.registEvents[OnEvent_1] = 0 # 对事件函数OnEvent_1和它的条件进行委托
        RegistEvents.registEvents[OnEvent_2] = 0 # 对事件函数OnEvent_2和它的条件进行委托
        t = threading.Thread(target = TriggerFunc) # 对监测触发条件的函数创建线程,异步执行
        t.start()
        time.sleep(1)
        RegistEvents.registEvents[OnEvent_1] = 1 # 触发条件本来是0,现在设置为1
        RegistEvents.registEvents[OnEvent_2] = 1
        time.sleep(1)
        RegistEvents.registEvents[OnEvent_1] = 2 # 触发条件本来是1,现在设置为2
        RegistEvents.registEvents[OnEvent_2] = 2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    由于python中并没有像capl中那样对不同类型触发的事件函数进行定义(on key/on message等),所以这里我们可以借鉴c sharp语言中的委托,定义委托,然后注册事件,最后执行

    这里用一个字典来注册(存入)事件和对应的触发条件,key是事件函数指针,value是触发条件(其实是事件函数指针关联的一个值)

    为什么不是key是触发条件,value是函数指针呢?

    因为事件函数的触发条件需要改变,而字典中的key写入后是无法改变的,但是value是可以改变的,所以value作为触发条件会更好


  • 相关阅读:
    正则表达式在Java中的使用
    飞桨模型部署至docker并使用FastAPI调用(五)-WordPress展示页面
    模块化打包工具-Webpack插件与其他功能
    冰冰学习笔记:gcc、gdb等工具的使用
    WPSpell将拼写检查添加到VCL应用程序
    代码随想录二刷 | 链表 | 删除链表的倒数第N个节点
    一些显示和画图的小命令函数用法
    【Mock】Neo4j知识图谱数据集Mock、问答训练数据集mock
    Educational Codeforces Round 41 (Rated for Div. 2) E. Tufurama
    【计算机网络笔记四】应用层(一)DNS域名解析
  • 原文地址:https://blog.csdn.net/wjz110201/article/details/126182532