该项目受 NodeJS 事件循环启发,旨在使用 C++11 或以上版本 在 AVR 8 单片机上实现一套简单的事件循环框架,如:
-
eventloop.setTimeout()
-
eventloop.nextTick()
-
eventloop.bindEventHandler()
avr-g++
至少支持编译 C++11 的版本
该项目使用了部分 stdc++ 库中的元编程模板,为此本项目自带了对所需模板非常粗糙的实现 (no_stdcpp_lib.h 污染 std 命名空间注意!)
如需完整的 stdc++ 库,可以考虑该项目曾采用的 modm-io 的 stdc++ 库,并取消 EventLoopAVR.h
中 USE_STDCPP_LIB
宏的注释,你也可以在 modm-io 组织下找到预编译的高版本 avr-g++
- 零动态内存分配
- 支持将自定义参数传入延迟执行的任务,而不需借助动态内存分配,如
eventloop.nextTick(make_task(some_function).setArgs(some_args_tuple))
或更为接近 js 的语法eventloop.nextTick([](int arg1, double arg2){ someWorkHere(); }, 114, 5.14)
- 支持设置超时任务,并可使用所计划的函数指针取消该超时任务
- 可为按键回调函数保存参数,实现类似闭包的效果
- (部分)简化IO设置,可在编译期确定引脚与按键的绑定、为串口提供流输出操作符等
- 支持 Arduino IDE
该项目由 Task<>
、CircularTaskQueue<>
、EventLoop<>
、Time
类为核心,实现了事件循环的框架,辅以 PinT<>
、Keys<>
、PipeIO<>
类提供对单片机IO的抽象
Task<>
类实现了对 某一函数的 函数指针 及 函数参数 的打包并进行类型擦除,为事件循环对函数的延迟执行提供了基础CircularTaskQueue<>
类实现了栈上对Task<>
对象的存储,避免了动态内存申请,并被设计为循环队列以配合事件循环的特性EventLoop<>
类实现了事件循环的主要功能,并使用CircularTaskQueue<>
类存储事件循环中的任务Time
类实现了一个紧凑的(48bit)时间格式,并具有全局时间等的静态成员与对其的操作,为事件循环提供时间标准PinT<>
模板类使得在模板中对任意端口的某一个引脚的操作成为了可能Keys<>
模板类在PinT<>
基础上更近一步,使得在编译期即可绑定引脚与按键,并生成对应的状态机函数,同时提供onClick
onDoubleClick
onPress
的回调(推荐 C++17, C++11 下效率不高)PipeIO<>
类对诸如 UART 等的外设提供了抽象,提供onData
等的回调
该项目的平台依赖性不强,兴许 可以移植至 STM32 等平台
引入 EventLoopAVR.h 即可,不过 Time
类的静态成员在编译时编译器会尝试加入线程安全相关代码,但 avr-libc 并没有提供,且也不需要,需使用 -fno-threadsafe-statics
编译器flag 关闭此功能
参考 examples/ 文件夹
- 如需要在中断中调用
nextTick
或setTimeout
,请务必务必注意这些函数的重入冲突问题;目前建议使用事件循环前会调用的preQueueProcess
函数根据事件所设置的 flag 再推入任务 Keys
对象提供.executeHandlers()
的成员函数完成对事件所设置 flag 的检查与更新,并在其中直接调用用户定义的回调函数,而不会使用nextTick
推迟执行,需考虑可能的阻塞问题- 事件循环在队列中没有任何任务与timeout队列也为空时会退出,可在
postQueueProcess
中加入队列空判断推入一个不做任何事的任务保活 - 该项目仍在建设中