├── .gitignore ├── LICENSE ├── README.md ├── examples ├── basics │ ├── eventEmiter.c │ ├── eventEmiter_sync.c │ ├── nextTick.c │ ├── requestAnimationFrame.c │ ├── setInterval.c │ ├── setTimeout.c │ └── tasks.c ├── custom_button_events │ └── main.c └── peripheral │ └── button.c └── src ├── build.h ├── core ├── async.c ├── async.h ├── emiter.c ├── emiter.h ├── event_loop.c ├── event_loop.h ├── util.c └── util.h ├── eos.h ├── peripheral ├── bmp180 │ ├── bmp180.c │ └── bmp180.h ├── button │ ├── button.c │ └── button.h ├── buzzer │ ├── buzzer.c │ └── buzzer.h ├── led │ ├── led.c │ └── led.h └── peripheral.h ├── sys_global.h └── transplant ├── bsp_inc.h └── stm32_hal ├── bsp.c └── bsp.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 zx1923 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # eventloop-mcu 2 | 一个在单片机上运行的事件循环模型库,参考了JavaScript的事件循环模型,并做了简化,使其可以在单片机上顺利运行,基于此模型,可以在单片机上实现类似 JavaScript 的异步编程。 3 | 4 | ## Features 5 | 6 | - 多任务,基于异步实现的多任务,类似于运行了 RTOS 操作系统; 7 | - 轻量,核心部分占用的 RAM 小于 1Kb; 8 | - JavaScript like; 9 | - 拥有 el_setTimeout 、el_setInterval 、el_nextTick 和 el_requestAnimationFrame 等异步函数; 10 | - 拥有异步延时函数 el_delay,等待期间可继续执行其他任务; 11 | - 事件驱动,基于异步编程,可以通过事件驱动各种应用; 12 | - 移植方便,两个函数即可实现核心功能的移植; 13 | 14 | ## 移植 15 | 16 | 移植核心部分只需要实现两个函数: 17 | 18 | - **Bsp_Get_Tick**:获取嘀嗒定时器的 tick ,即系统启动后的毫秒时间戳; 19 | - **Bsp_Delay_Ms**:阻塞式延时函数; 20 | 21 | eos 要求 **Bsp_Get_Tick** 达到 **1ms** 的精度,所以请确保定时器中断能产生 1ms 的嘀嗒周期。 22 | 23 | ### STM32 HAL 24 | 25 | 以 stm32 为例,如果工程是通过 STM32CubeMX 创建,默认是开启系统嘀嗒定时器的,且滴答定时器的终端周期是 1ms ,那么在 stm32 hal 项目上移植就非常简单,在 bsp.h 中做一下定义即可: 26 | 27 | ```c 28 | // stm32_hal/bsp.h 29 | /* Time-delay function and tick timer definition */ 30 | #define Bsp_Get_Tick HAL_GetTick 31 | #define Bsp_Delay_Ms HAL_Delay 32 | ``` 33 | 34 | ### Arduino 35 | 36 | Arduino 的移植也非常简单,由于 arduino 标准函数中默认就带了 **millis** 和 **delay** 两个函数,所以移植只需要做一下映射定义即可: 37 | 38 | ```c 39 | // arduino/bsp.h 40 | /* Time-delay function and tick timer definition */ 41 | #define Bsp_Get_Tick millis 42 | #define Bsp_Delay_Ms delay 43 | ``` 44 | 45 | ## 构建配置 46 | 47 | 与编译构建有关的配置全部定义在 **build.h** 文件中,文件如下: 48 | 49 | ```c 50 | #ifndef __USER_EL_BUILD_H__ 51 | #define __USER_EL_BUILD_H__ 52 | 53 | // 选择需要使能的平台,当前开启了 STM32 HAL 54 | #define BSP_USE_ARM_STM32_HAL 55 | 56 | // eventloop 相关 buffer 长度定义 57 | #define DF_MAX_TASK_LEN 32 58 | #define DF_EVENT_BUF_LEN 32 59 | #define DF_MAX_LISTENERS 16 60 | 61 | // 是否启用下面的基本外设驱动 62 | #define ENABLE_PWM_DRIVER 63 | #define ENABLE_GPIO_DRIVER 64 | 65 | // 是否启用按键监听 66 | #define ENABLE_BUTTON_DEVICE 67 | #ifdef ENABLE_BUTTON_DEVICE 68 | #define DF_BUTTON_COUNTER 4 69 | #endif // ENABLE_BUTTON_DEVICE 70 | 71 | // ... 72 | 73 | #endif 74 | ``` 75 | 76 | ## 示例 77 | 78 | 在单片机中使用事件循环模型只需要引入 **eos.h** 头文件即可: 79 | 80 | ```c 81 | #include "eos.h" 82 | ``` 83 | 84 | 当然,为了能编译成功,还需要将 **eos.h** 所在的目录加入到 **Include Paths** 中。 85 | 86 | ### 周期任务 87 | 88 | 使用 **el_setInterval** 定义的任务为周期任务,类似于 JavaScript 中的 **setInterval** 函数。 89 | 90 | ```c 91 | #include 92 | #include "main.h" 93 | #include "eos.h" 94 | 95 | void echoCounter() 96 | { 97 | static uint16_t count = 0; 98 | printf("Count: %d\r\n", count++); 99 | } 100 | 101 | int main(void) 102 | { 103 | // ... 104 | 105 | /** 106 | * @brief 每隔 1 秒执行一次 echoCounter 函数 107 | * 108 | * 依次输出: 109 | * Count: 0 110 | * Count: 1 111 | * Count: 2 112 | * ... 113 | */ 114 | el_setInerval(echoCounter, 1000, NULL, IMMEDIATE_N); 115 | // 启动事件循环 116 | el_startLoop(); 117 | // ... 118 | } 119 | ``` 120 | 121 | ### 延时任务 122 | 123 | **el_setTimeout** 用于定义一个延时任务,与 JavaScript 中的 **setTimeout** 表现类似,表示在一段时间后尽快执行回调函数,回调函数执行完成后会立即从内存中释放。 124 | 125 | ```c 126 | #include 127 | #include "main.h" 128 | #include "eos.h" 129 | 130 | void helloWorld() 131 | { 132 | printf("hello world!\r\n"); 133 | } 134 | 135 | int main(void) 136 | { 137 | // ... 138 | 139 | /** 140 | * @brief 一秒钟后执行 helloWorld 函数 141 | * 142 | * 输出: 143 | * hello world! 144 | */ 145 | el_setTimeout(helloWorld, 1000, NULL); 146 | // 启动事件循环 147 | el_startLoop(startTestTasks); 148 | // ... 149 | } 150 | 151 | ``` 152 | 153 | ### 事件监听 154 | 155 | 事件监听可以分为同步监听和异步监听,同步监听是立即执行的,异步监听则会在下一个 tick 中处理事件回调时执行。 156 | 157 | #### 同步事件监听 158 | 159 | 同步事件监听其实是同步的发布订阅模式,当事件被触发后,会直接执行回调函数,不必等到下一个 tick ,这是与异步不同的地方。 160 | 161 | 假设有 **EVENT_SELF_ADD** 自定义事件,以同步事件的方式触发该事件: 162 | 163 | ```c 164 | #include 165 | #include "main.h" 166 | #include "eos.h" 167 | 168 | void helloWorld() 169 | { 170 | printf("hello world!\r\n"); 171 | } 172 | int main(void) 173 | { 174 | // ... 175 | el_addEventListener(EVENT_SELF_ADD, helloWorld); 176 | el_emitEvent(EVENT_SELF_ADD, NULL); 177 | // 启动事件循环 178 | el_startLoop(); 179 | // ... 180 | } 181 | ``` 182 | 183 | 由代码可以发现,通过 **el_addEventListener** 函数可以定义事件的回调函数,同步触发就是直接通过 **el_emitEvent** 触发事件回调函数,这一过程没有任务异步操作,所以是同步触发。 184 | 185 | #### 异步事件监听 186 | 187 | 异步事件监听的表现与 JavaScript DOM 事件比较类似。 188 | 189 | 异步事件被一个事件消息队列维护,当事件被触发时,并不会立刻执行事件的回调函数,而是将事件推入事件队列中,在下一个 tick 中依次处理事件队列中的事件,触发回调函数。 190 | 191 | > 需要注意,与 JavaScript 不同的是,eos 的事件监听只绑定事件和回调,并不绑定实例(触发源),这是出于节省资源的考虑,所以需要在回调函数中通过回调参数来判断事件源。 192 | 193 | 在 **eos** 中,当系统就绪并准备开始事件循环时,会触发 **EVENT_EL_LOAD** 事件,用户可以监听该事件,以便知道事件循环何时开始。 194 | 195 | 由于 **eos** 中的所有事件默认都是异步的,**EVENT_EL_LOAD** 也不例外,当第一轮 tick 的微任务执行完毕后,才会开始执行 **EVENT_EL_LOAD** 的回调函数。 196 | 197 | ```c 198 | #include 199 | #include "main.h" 200 | #include "eos.h" 201 | 202 | void onLoad() 203 | { 204 | printf("eventloop loaded\r\n"); 205 | } 206 | 207 | void helloWorld() 208 | { 209 | printf("hello world!\r\n"); 210 | } 211 | 212 | int main(void) 213 | { 214 | // ... 215 | el_addEventListener(EVENT_EL_LOAD, onLoad); 216 | el_nextTick(helloWorld, NULL); 217 | // 启动事件循环 218 | el_startLoop(); 219 | // ... 220 | } 221 | 222 | ``` 223 | 224 | 由于在每一个 tick 中,微任务会先被执行,所以 HelloWorld 函数比 onLoad 先执行,上面的例子最终输出为: 225 | 226 | ```shell 227 | hello world! 228 | eventloop loaded 229 | ``` 230 | 231 | #### 自定义事件 232 | 233 | 与 JavaScript 类似,你也可以定义自己的事件,然后在需要的时候触发该事件的回调。自定义事件时只需要在 **bsp.h** 文件中扩展 **et_type_t** 类型的枚举值即可,见: 234 | 235 | ```c 236 | // bsp.h 237 | // ... 238 | typedef enum 239 | { 240 | EVENT_NONE = 0, 241 | EVENT_EL_LOAD, 242 | #ifdef ENABLE_BUTTON_DEVICE 243 | EVENT_BTN_PRESS, 244 | EVENT_BTN_LONG_PRESS, 245 | EVENT_BTN_RELEASE, 246 | EVENT_BTN_CLICK, 247 | EVENT_BTN_DCLICK, 248 | #endif // ENABLE_BUTTON_DEVICE 249 | // ... 250 | // Add other event enumeration values here 251 | // ... 252 | } et_type_t; 253 | // ... 254 | ``` 255 | 256 | 需要注意得失,有效事件的枚举值不能为 0 ,所以请确保枚举值 **EVENT_NONE 始终等于 0** ,不要删除该枚举值。 257 | 258 | ### nextTick 259 | 260 | **eos** 中也有 **nextTick** 函数,其名称为 **el_nextTick** ,与 JavaScript(node环境)的 **process.nextTick** 功能类似。**el_nextTick** 中的回调函数总是会在下一次 tick 中优先执行。 261 | 262 | ```c 263 | #include 264 | #include "main.h" 265 | #include "eos.h" 266 | 267 | void echoCounter() 268 | { 269 | static uint16_t count = 0; 270 | printf("Count: %d\r\n", count++); 271 | } 272 | 273 | void helloWorld() 274 | { 275 | printf("hello world!\r\n"); 276 | } 277 | 278 | int main(void) 279 | { 280 | // ... 281 | 282 | /** 283 | * @brief el_nextTick 的回调函数执行早于 el_setTimeout 的回调函数 284 | * el_nextTick 的回调会被放入微任务队列,el_setTimeout 的回调会被放入宏任务队列 285 | * 每次 tick 中微任务总是先于宏任务执行 286 | * 287 | * 输出: 288 | * hello world! 289 | * Count: 0 290 | */ 291 | el_setTimeout(echoCounter, 0, NULL); 292 | el_nextTick(helloWorld, NULL); 293 | // 启动事件循环 294 | el_startLoop(startTestTasks); 295 | // ... 296 | } 297 | ``` 298 | 299 | ### requestAnimationFrame 300 | 301 | **eos** 中也支持 **requestAnimationFrame** 函数,名称为 **el_requestAnimationFrame** ,使用效果与 web 端的 **requestAnimationFrame** 函数类似,但原理不同。 302 | 303 | 在单片机中,**el_requestAnimationFrame** 可用于需要周期性刷新显示的场景,比如需要让一块屏幕按照给定的帧率进行刷新时,就可以通过该函数设置刷新函数以及期望的帧率。 304 | 305 | 下面的示例代码,表示以每秒 30 帧的速度执行 helloWorld 函数: 306 | 307 | ```c 308 | #include 309 | #include "main.h" 310 | #include "eos.h" 311 | 312 | void helloWorld() 313 | { 314 | printf("hello world!\r\n"); 315 | } 316 | 317 | int main(void) 318 | { 319 | // ... 320 | el_requestAnimationFrame(helloWorld, 30, NULL); 321 | // 启动事件循环 322 | el_startLoop(); 323 | // ... 324 | } 325 | ``` 326 | 327 | > 要让 el_requestAnimationFrame 设置的回调函数顺利执行,还需要在 MCU 的 tickTimer 中断函数中调用 el_onIncTick 函数,由于这不是该段代码的主要目的,所以不在这里展开。 328 | 329 | ### 多任务/多线程 330 | 331 | eos 允许用户定义多个周期任务,这与 JavaScript 表现一直,所以借助 el_setInterval 可以实现多任务。多任务的执行效果类似于多线程,但本质上不是多线程,只是单线程非阻塞模型的一种异步表现,也是该模型的特性之一。 332 | 333 | 下面的例子将创建两个周期任务,分别控制两个 led 闪烁。 334 | 335 | ```c 336 | #include 337 | #include "main.h" 338 | #include "eos.h" 339 | 340 | void ledBlink(fun_params_t p[]) 341 | { 342 | // 假设已定义 el_led_on 和 el_led_off 两个函数 343 | el_led_t *led = (el_led_t *)p[0].param.pointer; 344 | uint32_t onMs = (uint32_t)p[1].param.int32Data; 345 | if (onMs == 0) 346 | return; 347 | el_led_on(led); 348 | fun_params_t *params = (fun_params_t *)malloc(sizeof(el_led_t)); 349 | memcpy(params, led, sizeof(el_led_t)); 350 | // 点亮一段时间后熄灭LED 351 | el_setTimeout(el_led_off, onMs, params); 352 | } 353 | 354 | int main(void) 355 | { 356 | // ... 357 | el_led_t *ledR = el_led_regist(GPIOB, GPIO_PIN_0, "Red", EL_PIN_LOW); 358 | el_led_t *ledG = el_led_regist(GPIOB, GPIO_PIN_5, "Green", EL_PIN_LOW); 359 | 360 | fun_params_t *blinkParamsR = (fun_params_t *)malloc(sizeof(fun_params_t) * 2); 361 | blinkParamsR[0].param.pointer = (uint32_t)ledR; 362 | blinkParamsR[1].param.int32Data = 10; 363 | el_setInterval(ledBlink, 1000, blinkParamsR, IMMEDIATE_N); 364 | 365 | fun_params_t *blinkParamsG = (fun_params_t *)malloc(sizeof(fun_params_t) * 2); 366 | blinkParamsG[0].param.pointer = (uint32_t)ledG; 367 | blinkParamsG[1].param.int32Data = 20; 368 | el_setInterval(ledBlink, 2000, blinkParamsG, IMMEDIATE_N); 369 | 370 | // 启动事件循环 371 | el_startLoop(); 372 | // ... 373 | } 374 | ``` 375 | 376 | 上面的例子编译执行后,可以看到 Red 和 Green 两个 led 分别按照 1 秒和 2 秒为周期点亮,每次点亮 10ms ,这两个周期任务互相没有干扰,独自执行,类似于两个线程在分别运行。 377 | 378 | ### 监听用户输入 379 | 380 | #### 按钮点击事件 381 | 382 | **eso** 的外设库中实现了一个简单的按钮驱动,使用轮训的方式处理用户点击,支持的事件有: 383 | 384 | - **EVENT_BTN_PRESS**:按钮被按下时触发; 385 | - **EVENT_BTN_RELEASE**:按钮被释放后触发; 386 | - **EVENT_BTN_LONG_PRESS**:按钮被按下并保持一段时间后触发; 387 | - **EVENT_BTN_CLICK**:按钮完成一次单击后触发; 388 | - **EVENT_BTN_DCLICK**:按钮完成一次双击后触发; 389 | 390 | 假设项目构建时已经启用了按键监听,并且启用了 GPIO 驱动,且在 bsp.c 中完成了对应的函数实现,例如对于按键而言,由于其依赖 GPIO 驱动,所以需要实现 GPIO 读写函数,对应在 stm32_hal 的 bsp.c 中为如下(已实现): 391 | 392 | ```c 393 | // stm32_hal/bsp.c 394 | #include "bsp.h" 395 | 396 | // ... 397 | 398 | // Define gpio read and write functions 399 | #ifdef ENABLE_GPIO_DRIVER 400 | extern void __user_el_gpio_writePin(el_btn_port_def *port, el_btn_pin_def pin, el_pin_set_t state) 401 | { 402 | HAL_GPIO_WritePin(port, pin, (GPIO_PinState)state); 403 | } 404 | 405 | extern el_pin_set_t __user_el_gpio_readPin(el_btn_port_def *port, el_btn_pin_def pin) 406 | { 407 | return (el_pin_set_t)HAL_GPIO_ReadPin(port, pin); 408 | } 409 | #endif // ENABLE_GPIO_DRIVER 410 | 411 | // ... 412 | ``` 413 | 414 | 实现对按钮的长按和单击监听,示例如下: 415 | 416 | ```c 417 | #include 418 | #include "main.h" 419 | #include "eos.h" 420 | 421 | void onLongPress(fun_params_t p[]) 422 | { 423 | char *btnName = (char *)params[0].param.stringData; 424 | printf("[%s] long press\r\n"); 425 | } 426 | 427 | void onClick(fun_params_t p[]) 428 | { 429 | char *btnName = (char *)params[0].param.stringData; 430 | printf("[%s] clicked\r\n"); 431 | } 432 | 433 | int main(void) 434 | { 435 | // ... 436 | 437 | el_btn_t *btn1 = el_button_regist(GPIOB, GPIO_PIN_0, "Btn1", EL_PIN_LOW); 438 | el_btn_t *btn2 = el_button_regist(GPIOB, GPIO_PIN_1, "Btn2", EL_PIN_HIGH); 439 | el_addEventListener(EVENT_BTN_LONG_PRESS, onLongPress); 440 | el_addEventListener(EVENT_BTN_CLICK, onClick); 441 | // 每隔 10ms 扫描一次按键 442 | el_setInterval(el_button_scan, 10, NULL, IMMEDIATE_N); 443 | 444 | // 启动事件循环 445 | el_startLoop(); 446 | // ... 447 | } 448 | 449 | ``` 450 | 451 | 当用户对注册的按钮进行操作时,就会触发 **EVENT_BTN_LONG_PRESS** 或 **EVENT_BTN_CLICK** 事件,通过回调函数即可处理该事件。 452 | 453 | 按键的事件回调会传入两个参数,分别是: 454 | 455 | - 按键名,即按键注册时传入的按键名; 456 | - 触发时间,即触发该事件时的毫秒时间戳; 457 | 458 | 回调函数的参数会通过一个 **fun_params_t** 类型的指针传入,回调函数对入参进行结构,拿到参数即可。 459 | -------------------------------------------------------------------------------- /examples/basics/eventEmiter.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "main.h" 3 | #include "eos.h" 4 | 5 | void onLoad() 6 | { 7 | printf("eventloop loaded\r\n"); 8 | } 9 | 10 | void helloWorld() 11 | { 12 | printf("hello world!\r\n"); 13 | } 14 | 15 | int main(void) 16 | { 17 | // ... 18 | el_addEventListener(EVENT_EL_LOAD, onLoad); 19 | el_nextTick(helloWorld, EL_PARAMS_NULL); 20 | // 启动事件循环 21 | el_startLoop(); 22 | // ... 23 | } 24 | -------------------------------------------------------------------------------- /examples/basics/eventEmiter_sync.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "main.h" 3 | #include "eos.h" 4 | 5 | void helloWorld() 6 | { 7 | printf("hello world!\r\n"); 8 | } 9 | int main(void) 10 | { 11 | // ... 12 | el_addEventListener(EVENT_SELF_ADD, helloWorld); 13 | el_emitEvent(EVENT_SELF_ADD, EL_PARAMS_NULL); 14 | // 启动事件循环 15 | el_startLoop(); 16 | // ... 17 | } 18 | -------------------------------------------------------------------------------- /examples/basics/nextTick.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "main.h" 3 | #include "eos.h" 4 | 5 | void echoCounter() 6 | { 7 | static uint16_t count = 0; 8 | printf("Count: %d\r\n", count++); 9 | } 10 | 11 | void helloWorld() 12 | { 13 | printf("hello world!\r\n"); 14 | } 15 | 16 | int main(void) 17 | { 18 | // ... 19 | 20 | /** 21 | * @brief el_nextTick 的回调函数执行早于 el_setTimeout 的回调函数 22 | * el_nextTick 的回调会被放入微任务队列,el_setTimeout 的回调会被放入宏任务队列 23 | * 每次 tick 中微任务总是先于宏任务执行 24 | * 25 | * 输出: 26 | * hello world! 27 | * Count: 0 28 | */ 29 | el_setTimeout(NULL, echoCounter, 0, EL_PARAMS_NULL); 30 | el_nextTick(helloWorld, EL_PARAMS_NULL); 31 | // 启动事件循环 32 | el_startLoop(); 33 | // ... 34 | } 35 | -------------------------------------------------------------------------------- /examples/basics/requestAnimationFrame.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "main.h" 3 | #include "eos.h" 4 | 5 | void helloWorld() 6 | { 7 | printf("hello world!\r\n"); 8 | } 9 | 10 | int main(void) 11 | { 12 | // ... 13 | el_requestAnimationFrame(helloWorld, 30, EL_PARAMS_NULL); 14 | // 启动事件循环 15 | el_startLoop(); 16 | // ... 17 | } 18 | -------------------------------------------------------------------------------- /examples/basics/setInterval.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "main.h" 3 | #include "eos.h" 4 | 5 | void echoCounter() 6 | { 7 | static uint16_t count = 0; 8 | printf("Count: %d\r\n", count++); 9 | } 10 | 11 | int main(void) 12 | { 13 | // ... 14 | 15 | /** 16 | * @brief 每隔 1 秒执行一次 echoCounter 函数 17 | * 18 | * 依次输出: 19 | * Count: 0 20 | * Count: 1 21 | * Count: 2 22 | * ... 23 | */ 24 | el_setInerval(NULL, echoCounter, 1000, EL_PARAMS_NULL, IMMEDIATE_N); 25 | // 启动事件循环 26 | el_startLoop(); 27 | // ... 28 | } -------------------------------------------------------------------------------- /examples/basics/setTimeout.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "main.h" 3 | #include "eos.h" 4 | 5 | void helloWorld() 6 | { 7 | printf("hello world!\r\n"); 8 | } 9 | 10 | int main(void) 11 | { 12 | // ... 13 | /** 14 | * @brief 一秒钟后执行 helloWorld 函数 15 | * 16 | * 输出: 17 | * hello world! 18 | */ 19 | el_setTimeout(NULL, helloWorld, 1000, EL_PARAMS_NULL); 20 | // 启动事件循环 21 | el_startLoop(); 22 | // ... 23 | } 24 | -------------------------------------------------------------------------------- /examples/basics/tasks.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "main.h" 3 | #include "eos.h" 4 | 5 | void ledBlink(fun_params_t p[]) 6 | { 7 | // 假设已定义 el_led_on 和 el_led_off 两个函数 8 | el_led_t *led = (el_led_t *)p[0].param.pointer; 9 | uint32_t onMs = (uint32_t)p[1].param.int32Data; 10 | if (onMs == 0) 11 | return; 12 | el_led_on(led); 13 | fun_params_t *params = (fun_params_t *)malloc(sizeof(el_led_t)); 14 | memcpy(params, led, sizeof(el_led_t)); 15 | // 点亮一段时间后熄灭LED 16 | el_setTimeout(el_led_off, onMs, params); 17 | } 18 | 19 | int main(void) 20 | { 21 | // ... 22 | el_led_t *ledR = el_led_regist(GPIOB, GPIO_PIN_0, "Red", EL_PIN_LOW); 23 | el_led_t *ledG = el_led_regist(GPIOB, GPIO_PIN_5, "Green", EL_PIN_LOW); 24 | 25 | fun_params_t *blinkParamsR = (fun_params_t *)malloc(sizeof(fun_params_t) * 2); 26 | blinkParamsR[0].param.pointer = (uint32_t)ledR; 27 | blinkParamsR[1].param.int32Data = 10; 28 | el_setInterval(NULL, ledBlink, 1000, blinkParamsR, IMMEDIATE_N); 29 | 30 | fun_params_t *blinkParamsG = (fun_params_t *)malloc(sizeof(fun_params_t) * 2); 31 | blinkParamsG[0].param.pointer = (uint32_t)ledG; 32 | blinkParamsG[1].param.int32Data = 20; 33 | el_setInterval(NULL, ledBlink, 2000, blinkParamsG, IMMEDIATE_N); 34 | 35 | // 启动事件循环 36 | el_startLoop(); 37 | // ... 38 | } 39 | -------------------------------------------------------------------------------- /examples/custom_button_events/main.c: -------------------------------------------------------------------------------- 1 | /* Includes ------------------------------------------------------------------*/ 2 | #include "main.h" 3 | #include "usart.h" 4 | #include "gpio.h" 5 | 6 | /* Private includes ----------------------------------------------------------*/ 7 | /* USER CODE BEGIN Includes */ 8 | #include 9 | #include "eos.h" 10 | /* USER CODE END Includes */ 11 | 12 | // ... 13 | 14 | void onBtnPressed(fun_params_t params[]) 15 | { 16 | uint8_t btnId = (uint8_t)params[0].param.uint8Data; 17 | printf("[%0.8d] Btn%x pressed\r\n", el_getMillis(), btnId); 18 | } 19 | 20 | void onBtnReleased(fun_params_t params[]) 21 | { 22 | uint8_t btnId = (uint8_t)params[0].param.uint8Data; 23 | printf("[%0.8d] Btn%x released\r\n", el_getMillis(), btnId); 24 | } 25 | 26 | void helloWorld() { 27 | printf("[%0.8d] hello world\r\n", Sys_GetMillis()); 28 | } 29 | 30 | void startTestTasks() 31 | { 32 | fun_params_t *blinkParams = (fun_params_t *)malloc(sizeof(fun_params_t) * 2); 33 | blinkParams[0].param.int32Data = 20; 34 | blinkParams[1].param.int32Data = 0; 35 | // 周期任务:每隔 2000ms LED_R 点亮 50ms 36 | el_setInterval(LedR_Blink, blinkParams, 2000, IMMEDIATE_N); 37 | // 一次性任务:在下一个 tick 打印出 hello world 38 | el_nextTick(helloWorld, EL_PARAMS_NULL); 39 | // 周期任务:每 10ms 执行 observBtnState 函数观察按钮状态 40 | el_setInterval(NULL, observBtnState, EL_PARAMS_NULL, 10, IMMEDIATE_Y); 41 | 42 | // 监听按钮 press 和 release 事件 43 | el_addEventListener(EVENT_BTN_PRESS, onBtnPressed); 44 | el_addEventListener(EVENT_BTN_RELEASE, onBtnReleased); 45 | } 46 | /* USER CODE END 0 */ 47 | 48 | // ... 49 | 50 | int main(void) 51 | { 52 | // ... 53 | // 启动任务,不设置帧率,将 startTestTasks 作为入口函数,按最高频率进行事件循环 54 | el_startLoop(startTestTasks, NULL); 55 | // ... 56 | } 57 | -------------------------------------------------------------------------------- /examples/peripheral/button.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "main.h" 3 | #include "eos.h" 4 | 5 | void onLongPress(fun_params_t p[]) 6 | { 7 | char *btnName = (char *)params[0].param.stringData; 8 | printf("[%s] long press\r\n"); 9 | } 10 | 11 | void onClick(fun_params_t p[]) 12 | { 13 | char *btnName = (char *)params[0].param.stringData; 14 | printf("[%s] clicked\r\n"); 15 | } 16 | 17 | int main(void) 18 | { 19 | // ... 20 | 21 | el_btn_t *btn1 = el_button_regist(GPIOB, GPIO_PIN_0, "Btn1", EL_PIN_LOW); 22 | el_btn_t *btn2 = el_button_regist(GPIOB, GPIO_PIN_1, "Btn2", EL_PIN_HIGH); 23 | el_addEventListener(EVENT_BTN_LONG_PRESS, onLongPress); 24 | el_addEventListener(EVENT_BTN_CLICK, onClick); 25 | // 每隔 10ms 扫描一次按键 26 | el_setInterval(NULL, el_button_scan, 10, EL_PARAMS_NULL, IMMEDIATE_N); 27 | 28 | // 启动事件循环 29 | el_startLoop(); 30 | // ... 31 | } 32 | -------------------------------------------------------------------------------- /src/build.h: -------------------------------------------------------------------------------- 1 | #ifndef __USER_EL_BUILD_H__ 2 | #define __USER_EL_BUILD_H__ 3 | 4 | // bsp 5 | #define BSP_USE_STM32_HAL 6 | #define DF_HEAP_SIZE 0x300 7 | #define DF_HEAP_BUF_LEN (DF_HEAP_SIZE / 8 + 1) 8 | 9 | // Related buffer definitions 10 | #define DF_MAX_TASK_LEN 32 11 | #define DF_EVENT_BUF_LEN 32 12 | #define DF_MAX_LISTENERS 16 13 | 14 | #define ENABLE_PWM_DRIVER 15 | #define ENABLE_GPIO_DRIVER 16 | #define ENABLE_HEAP_MAP 17 | 18 | // module/device 19 | #define ENABLE_BUTTON_DEVICE 20 | #ifdef ENABLE_BUTTON_DEVICE 21 | #define DF_BUTTON_COUNTER 4 22 | #endif // ENABLE_BUTTON_DEVICE 23 | 24 | #define ENABLE_BUZZER_DEVICE 25 | #define ENABLE_LED_DEVICE 26 | 27 | // i2c sensor 28 | #define ENABLE_I2C_SENSOR 29 | #ifdef ENABLE_I2C_SENSOR 30 | #define ENABLE_SENSOR_BMP180_I2C 31 | #define ENABLE_SENSOR_LIS3DH_I2C 32 | #define ENABLE_SENSOR_BMP280_I2C 33 | #endif // ENABLE_I2C_SENSOR 34 | 35 | #include "transplant/bsp_inc.h" 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /src/core/async.c: -------------------------------------------------------------------------------- 1 | #include "eos.h" 2 | #include "util.h" 3 | 4 | static el_task_t AnimationFrameTask = {EL_NULL}; 5 | static uint16_t AnimationFrameTime = 0; 6 | 7 | el_ret_t _clearAsyncTask(el_task_t *taskInstance) 8 | { 9 | if (taskInstance != NULL) 10 | { 11 | taskInstance->status = EL_CLEAR; 12 | return EL_OK; 13 | } 14 | return EL_ERR; 15 | } 16 | 17 | el_task_t *_setAsyncTask(el_task_t *handler, void callback(), fun_params_t *p, el_time_t runAt, el_time_t interval, el_ret_t (*pushFn)(el_task_t *)) 18 | { 19 | el_task_t *task = handler == NULL ? (el_task_t *)el_malloc(sizeof(el_task_t)) : handler; 20 | task->params = p; 21 | task->handler = callback; 22 | task->interval = interval; 23 | task->runAt = runAt; 24 | task->status = EL_IDLE; 25 | return pushFn(task) == EL_FULL ? NULL : task; 26 | } 27 | 28 | el_task_t *el_setTimeout(el_task_t *handler, void callback(), el_time_t ms, fun_params_t *p) 29 | { 30 | return _setAsyncTask(handler, callback, p, el_getMillis() + ms, INTERVAL_NONE, el_pushMacroTask); 31 | } 32 | 33 | el_task_t *el_setInterval(el_task_t *handler, void callback(), el_time_t ms, fun_params_t *p, task_immediate_t immediate) 34 | { 35 | el_time_t runAt = immediate == IMMEDIATE_N ? el_getMillis() + ms : 0; 36 | return _setAsyncTask(handler, callback, p, runAt, ms, el_pushMacroTask); 37 | } 38 | 39 | el_ret_t el_clearTimeout(el_task_t *taskInstance) 40 | { 41 | return _clearAsyncTask(taskInstance); 42 | } 43 | 44 | el_ret_t el_clearInterval(el_task_t *taskInstance) 45 | { 46 | return _clearAsyncTask(taskInstance); 47 | } 48 | 49 | el_task_t *el_nextTick(void callback(), fun_params_t *p) 50 | { 51 | return _setAsyncTask(NULL, callback, p, 0, 0, el_pushMicroTask); 52 | } 53 | 54 | el_ret_t el_requestAnimationFrame(void callback(), uint8_t fps, fun_params_t params[]) 55 | { 56 | if (fps == 0) 57 | { 58 | return EL_ERR; 59 | } 60 | AnimationFrameTask.status = EL_IDLE; 61 | AnimationFrameTask.handler = callback; 62 | AnimationFrameTask.params = params; 63 | AnimationFrameTime = 1000 / fps; 64 | return EL_OK; 65 | } 66 | 67 | void el_onIncTick() 68 | { 69 | if (AnimationFrameTime == 0 || AnimationFrameTask.status != EL_IDLE) 70 | { 71 | return; 72 | } 73 | if (el_getMillis() % AnimationFrameTime == 0) 74 | { 75 | AnimationFrameTask.status = EL_RUNNING; 76 | AnimationFrameTask.handler(AnimationFrameTask.params); 77 | AnimationFrameTask.status = EL_IDLE; 78 | } 79 | } 80 | 81 | void el_delay(uint32_t ms) 82 | { 83 | uint32_t endTime = el_getMillis() + ms; 84 | while (el_getMillis() < endTime) 85 | { 86 | el_runTasks(); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/core/async.h: -------------------------------------------------------------------------------- 1 | #ifndef __USER_EL_ASYNC_H__ 2 | #define __USER_EL_ASYNC_H__ 3 | 4 | #include "sys_global.h" 5 | #include "event_loop.h" 6 | 7 | #define INTERVAL_NONE 0 8 | 9 | el_task_t *el_setTimeout(el_task_t *handler, void callback(), el_time_t ms, fun_params_t *params); 10 | el_ret_t el_clearTimeout(el_task_t *taskInstance); 11 | el_task_t *el_setInterval(el_task_t *handler, void callback(), el_time_t ms, fun_params_t *params, task_immediate_t immediate); 12 | el_ret_t el_clearInterval(el_task_t *taskInstance); 13 | el_task_t *el_nextTick(void callback(), fun_params_t *params); 14 | el_ret_t el_requestAnimationFrame(void callback(), uint8_t fps, fun_params_t *params); 15 | void el_delay(el_time_t ms); 16 | void el_onIncTick(void); 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /src/core/emiter.c: -------------------------------------------------------------------------------- 1 | #include "emiter.h" 2 | #include "util.h" 3 | 4 | static et_dep_t EventDeps; 5 | 6 | el_ret_t el_addEventListener(et_type_t eventType, void handler()) 7 | { 8 | if (EventDeps.size >= DF_MAX_LISTENERS) 9 | { 10 | return EL_FULL; 11 | } 12 | et_subs_t *sub = (et_subs_t *)el_malloc(sizeof(et_subs_t)); 13 | sub->eventType = eventType; 14 | sub->handler = handler; 15 | EventDeps.subs[EventDeps.wp++] = sub; 16 | EventDeps.wp = EventDeps.wp >= DF_MAX_LISTENERS ? 0 : EventDeps.wp; 17 | EventDeps.size++; 18 | return EL_OK; 19 | } 20 | 21 | el_ret_t el_emitEvent(et_type_t eventType, fun_params_t *params) 22 | { 23 | if (EventDeps.size <= 0) 24 | { 25 | return EL_EMPTY; 26 | } 27 | for (uint8_t i = 0; i < EventDeps.size; i++) 28 | { 29 | if (EventDeps.subs[i]->eventType == eventType) 30 | { 31 | EventDeps.subs[i]->handler(params); 32 | } 33 | } 34 | return EL_OK; 35 | } 36 | -------------------------------------------------------------------------------- /src/core/emiter.h: -------------------------------------------------------------------------------- 1 | #ifndef __USER_EL_EMITER_H__ 2 | #define __USER_EL_EMITER_H__ 3 | 4 | #include "sys_global.h" 5 | 6 | typedef struct 7 | { 8 | et_type_t eventType; 9 | void (*handler)(fun_params_t *p); 10 | } et_subs_t; 11 | 12 | typedef struct 13 | { 14 | et_subs_t *subs[DF_MAX_LISTENERS]; 15 | uint8_t rp; 16 | uint8_t wp; 17 | uint8_t size; 18 | } et_dep_t; 19 | 20 | typedef struct 21 | { 22 | et_type_t eventType; 23 | fun_params_t *params; 24 | uint32_t occuredTime; 25 | } et_body_t; 26 | 27 | // void el_Init(void); 28 | el_ret_t el_addEventListener(et_type_t eventType, void handler()); 29 | el_ret_t el_emitEvent(et_type_t eventType, fun_params_t *params); 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /src/core/event_loop.c: -------------------------------------------------------------------------------- 1 | #include "event_loop.h" 2 | #include "util.h" 3 | 4 | static el_task_buf_t MacroTasksBuffer; 5 | static el_task_buf_t MicroTasksBuffer; 6 | static el_event_buf_t EventQueueBuffer; 7 | 8 | el_ret_t _pushTask(el_task_buf_t *taskBuf, el_task_t *task); 9 | el_task_t *_shiftTask(el_task_buf_t *taskBuf); 10 | el_ret_t _callTaskHandler(el_task_t *task); 11 | el_ret_t _walkTaskBuf(el_task_buf_t *taskBuf); 12 | el_ret_t _pushEvent(el_event_buf_t *eventBuf, et_body_t *eventBody); 13 | et_body_t *_shiftEvent(el_event_buf_t *eventBuf); 14 | 15 | void _freeTask(el_task_t *task) 16 | { 17 | el_free(task->params); 18 | el_free(task); 19 | } 20 | 21 | void _freeEventBody(et_body_t *eventBody) 22 | { 23 | el_free(eventBody->params); 24 | el_free(eventBody); 25 | } 26 | 27 | el_ret_t _pushTask(el_task_buf_t *taskBuf, el_task_t *task) 28 | { 29 | if (taskBuf->size >= DF_MAX_TASK_LEN) 30 | { 31 | _freeTask(task); 32 | return EL_FULL; 33 | } 34 | taskBuf->buf[taskBuf->wp++] = task; 35 | taskBuf->wp = taskBuf->wp >= DF_MAX_TASK_LEN ? 0 : taskBuf->wp; 36 | taskBuf->size++; 37 | return EL_OK; 38 | } 39 | 40 | el_task_t *_shiftTask(el_task_buf_t *taskBuf) 41 | { 42 | if (taskBuf->size <= 0) 43 | { 44 | return NULL; 45 | } 46 | el_task_t *task = taskBuf->buf[taskBuf->rp++]; 47 | taskBuf->rp = taskBuf->rp >= DF_MAX_TASK_LEN ? 0 : taskBuf->rp; 48 | taskBuf->size--; 49 | return task; 50 | } 51 | 52 | el_ret_t _pushEvent(el_event_buf_t *eventBuf, et_body_t *eventBody) 53 | { 54 | if (eventBuf->size >= DF_EVENT_BUF_LEN) 55 | { 56 | _freeEventBody(eventBody); 57 | return EL_FULL; 58 | } 59 | eventBuf->buf[eventBuf->wp++] = eventBody; 60 | eventBuf->wp = eventBuf->wp >= DF_EVENT_BUF_LEN ? 0 : eventBuf->wp; 61 | eventBuf->size++; 62 | return EL_OK; 63 | } 64 | 65 | et_body_t *_shiftEvent(el_event_buf_t *eventBuf) 66 | { 67 | if (eventBuf->size <= 0) 68 | { 69 | return NULL; 70 | } 71 | et_body_t *eventBody = eventBuf->buf[eventBuf->rp++]; 72 | eventBuf->rp = eventBuf->rp >= DF_EVENT_BUF_LEN ? 0 : eventBuf->rp; 73 | eventBuf->size--; 74 | return eventBody; 75 | } 76 | 77 | el_ret_t _callTaskHandler(el_task_t *task) 78 | { 79 | if (task->status == EL_NULL) 80 | { 81 | return EL_ERR; 82 | } 83 | if (task->status == EL_CLEAR) 84 | { 85 | _freeTask(task); 86 | return EL_OK; 87 | } 88 | if (el_getMillis() < task->runAt) 89 | { 90 | el_pushMacroTask(task); 91 | return EL_OK; 92 | } 93 | task->status = EL_RUNNING; 94 | task->handler(task->params); 95 | task->status = EL_DONE; 96 | 97 | // 周期任务 98 | if (task->interval > 0) 99 | { 100 | task->status = EL_IDLE; 101 | task->runAt = el_getMillis() + task->interval; 102 | el_pushMacroTask(task); 103 | return EL_OK; 104 | } 105 | 106 | _freeTask(task); 107 | return EL_OK; 108 | } 109 | 110 | el_ret_t _walkTaskBuf(el_task_buf_t *taskBuf) 111 | { 112 | el_task_t *task = _shiftTask(taskBuf); 113 | if (task == NULL) 114 | { 115 | return EL_EMPTY; 116 | } 117 | return _callTaskHandler(task); 118 | } 119 | 120 | el_ret_t _walkEventBuf(el_event_buf_t *eventBuf) 121 | { 122 | et_body_t *eventBody = _shiftEvent(eventBuf); 123 | if (eventBody == NULL) 124 | { 125 | return EL_EMPTY; 126 | } 127 | el_ret_t res = el_emitEvent(eventBody->eventType, eventBody->params); 128 | _freeEventBody(eventBody); 129 | return res; 130 | } 131 | 132 | el_ret_t el_pushMacroTask(el_task_t *task) 133 | { 134 | return _pushTask(&MacroTasksBuffer, task); 135 | } 136 | 137 | el_ret_t el_pushMicroTask(el_task_t *task) 138 | { 139 | return _pushTask(&MicroTasksBuffer, task); 140 | } 141 | 142 | el_ret_t el_pushEvent(et_type_t eventType, fun_params_t params[]) 143 | { 144 | et_body_t *eventBody = (et_body_t *)el_malloc(sizeof(et_body_t)); 145 | eventBody->eventType = eventType; 146 | eventBody->params = params; 147 | eventBody->occuredTime = el_getMillis(); 148 | return _pushEvent(&EventQueueBuffer, eventBody); 149 | } 150 | 151 | el_bool_t el_isEventQueueValid() 152 | { 153 | return EventQueueBuffer.size < DF_EVENT_BUF_LEN ? EL_TRUE : EL_FALSE; 154 | } 155 | 156 | el_bool_t el_isMacroTaskQueueValid(void) 157 | { 158 | return MacroTasksBuffer.size < DF_MAX_TASK_LEN ? EL_TRUE : EL_FALSE; 159 | } 160 | 161 | el_bool_t el_isMicroTaskQueueValid(void) 162 | { 163 | return MicroTasksBuffer.size < DF_MAX_TASK_LEN ? EL_TRUE : EL_FALSE; 164 | } 165 | 166 | void el_runTasks() 167 | { 168 | static uint8_t step = 0; 169 | static uint8_t size = 0; 170 | 171 | if (step > 2) 172 | step = 0; 173 | switch (step) 174 | { 175 | case 0: 176 | if (size == 0) 177 | size = MicroTasksBuffer.size; 178 | _walkTaskBuf(&MicroTasksBuffer); 179 | size--; 180 | if (size == 0) 181 | step++; 182 | break; 183 | case 1: 184 | if (size == 0) 185 | size = EventQueueBuffer.size; 186 | _walkEventBuf(&EventQueueBuffer); 187 | size--; 188 | if (size == 0) 189 | step++; 190 | break; 191 | case 2: 192 | if (size == 0) 193 | size = MacroTasksBuffer.size; 194 | _walkTaskBuf(&MacroTasksBuffer); 195 | size--; 196 | if (size == 0) 197 | step++; 198 | break; 199 | }; 200 | } 201 | 202 | void el_startLoop() 203 | { 204 | el_emitEvent(EVENT_EL_LOAD, NULL); 205 | while (1) 206 | { 207 | el_runTasks(); 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /src/core/event_loop.h: -------------------------------------------------------------------------------- 1 | #ifndef __USER_EL_EVENT_LOOP_H__ 2 | #define __USER_EL_EVENT_LOOP_H__ 3 | 4 | #include "sys_global.h" 5 | #include "emiter.h" 6 | 7 | typedef enum 8 | { 9 | IMMEDIATE_N = 0, 10 | IMMEDIATE_Y, 11 | } task_immediate_t; 12 | 13 | typedef enum 14 | { 15 | EL_NULL = 0, 16 | EL_IDLE, 17 | EL_RUNNING, 18 | EL_DONE, 19 | EL_CLEAR, 20 | } el_status_t; 21 | 22 | typedef struct 23 | { 24 | el_status_t status; 25 | uint8_t taskId; 26 | void (*handler)(fun_params_t *p); 27 | fun_params_t *params; 28 | el_time_t interval; 29 | el_time_t runAt; 30 | } el_task_t; 31 | 32 | typedef struct 33 | { 34 | el_task_t *buf[DF_MAX_TASK_LEN]; 35 | uint8_t wp; // 写指针 36 | uint8_t rp; // 读指针 37 | uint8_t size; // 缓冲区的最大长度 38 | } el_task_buf_t; 39 | 40 | typedef struct 41 | { 42 | et_body_t *buf[DF_EVENT_BUF_LEN]; 43 | uint8_t wp; 44 | uint8_t rp; 45 | uint8_t size; 46 | } el_event_buf_t; 47 | 48 | el_ret_t el_pushMacroTask(el_task_t *task); 49 | el_ret_t el_pushMicroTask(el_task_t *task); 50 | el_ret_t el_pushEvent(et_type_t eventType, fun_params_t params[]); 51 | el_bool_t el_isEventQueueValid(void); 52 | el_bool_t el_isMacroTaskQueueValid(void); 53 | el_bool_t el_isMicroTaskQueueValid(void); 54 | void el_runTasks(void); 55 | void el_startLoop(void); 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /src/core/util.c: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | #include "emiter.h" 3 | 4 | #ifdef ENABLE_HEAP_MAP 5 | static int FreeSize = DF_HEAP_SIZE; 6 | 7 | static el_heap_map_t HeapMap = {0, 0}; 8 | 9 | void _heapPush(void *p, size_t n) 10 | { 11 | HeapMap.p[HeapMap.wp] = p; 12 | HeapMap.size[HeapMap.wp++] = n; 13 | if (HeapMap.wp >= DF_HEAP_BUF_LEN) 14 | { 15 | HeapMap.wp = 0; 16 | } 17 | } 18 | 19 | uint16_t _heapFind(void *p) 20 | { 21 | uint16_t size = 0; 22 | for (uint16_t i = 0; i < DF_HEAP_BUF_LEN; i++) 23 | { 24 | if (p == HeapMap.p[i]) 25 | { 26 | size = HeapMap.size[i]; 27 | HeapMap.p[i] = NULL; 28 | HeapMap.size[i] = 0; 29 | return size; 30 | } 31 | } 32 | return 0; 33 | } 34 | 35 | el_heap_info_t el_getHeapInfo(void) 36 | { 37 | el_heap_info_t heapInfo; 38 | heapInfo.total = DF_HEAP_SIZE; 39 | heapInfo.free = FreeSize; 40 | heapInfo.usage = FreeSize <= 0 ? 1.0 : (1 - FreeSize * 1.0 / DF_HEAP_SIZE); 41 | return heapInfo; 42 | } 43 | #endif // ENABLE_HEAP_MAP 44 | 45 | void *el_malloc(size_t n) 46 | { 47 | void *p = malloc(n); 48 | if (p == NULL) 49 | { 50 | el_emitEvent(EVENT_HEAP_INVALID, NULL); 51 | return NULL; 52 | } 53 | #ifdef ENABLE_HEAP_MAP 54 | uint16_t realSize = (n / 8 * 8) + 8; 55 | FreeSize -= realSize; 56 | _heapPush(p, realSize); 57 | #endif // ENABLE_HEAP_MAP 58 | return p; 59 | } 60 | 61 | void el_free(void *p) 62 | { 63 | #ifdef ENABLE_HEAP_MAP 64 | FreeSize += _heapFind(p); 65 | #endif // ENABLE_HEAP_MAP 66 | free(p); 67 | } 68 | -------------------------------------------------------------------------------- /src/core/util.h: -------------------------------------------------------------------------------- 1 | #ifndef __USER_EL_UTIL_H__ 2 | #define __USER_EL_UTIL_H__ 3 | 4 | #include "sys_global.h" 5 | #include 6 | 7 | typedef struct 8 | { 9 | el_pointer_t total; 10 | el_pointer_t free; 11 | float usage; 12 | } el_heap_info_t; 13 | 14 | typedef struct 15 | { 16 | void *p[DF_HEAP_BUF_LEN]; 17 | uint16_t size[DF_HEAP_BUF_LEN]; 18 | uint8_t wp; 19 | } el_heap_map_t; 20 | 21 | el_heap_info_t el_getHeapInfo(void); 22 | void *el_malloc(size_t n); 23 | void el_free(void *p); 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/eos.h: -------------------------------------------------------------------------------- 1 | #ifndef __USER_EL_FRAMEWORK_H__ 2 | #define __USER_EL_FRAMEWORK_H__ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include "build.h" 9 | #include "sys_global.h" 10 | #include "core/util.h" 11 | #include "core/event_loop.h" 12 | #include "core/async.h" 13 | #include "core/emiter.h" 14 | #include "peripheral/peripheral.h" 15 | 16 | #ifdef __cplusplus 17 | } 18 | #endif 19 | 20 | #endif 21 | 22 | -------------------------------------------------------------------------------- /src/peripheral/bmp180/bmp180.c: -------------------------------------------------------------------------------- 1 | #include "bmp180.h" 2 | #ifdef ENABLE_SENSOR_BMP180_I2C 3 | 4 | uint8_t _i2c_readOneByte(el_bmp180_t *device, uint16_t memAddress); 5 | uint16_t _i2c_readTwoBytes(el_bmp180_t *device, uint16_t memAddress); 6 | el_io_status_t _i2c_readBytes(el_bmp180_t *device, uint16_t memAddress, uint8_t pdata[], uint8_t len); 7 | el_io_status_t _bmp180ReadChipId(el_bmp180_t *device); 8 | void _i2c_writeOneByte(el_bmp180_t *device, uint16_t memAddress, uint8_t data); 9 | void _bmp180ReadCalibration(el_bmp180_t *device); 10 | void _bmp180ReadUP(el_bmp180_t *device); 11 | void _bmp180ReadUT(el_bmp180_t *device); 12 | void _bmp180ReadUpAndUt(el_bmp180_t *device); 13 | 14 | uint8_t _i2c_readOneByte(el_bmp180_t *device, uint16_t memAddress) 15 | { 16 | uint8_t data; 17 | __user_el_i2c_read_bytes(device->hi2c, device->addressR, memAddress, &data, 1); 18 | return data; 19 | } 20 | 21 | uint16_t _i2c_readTwoBytes(el_bmp180_t *device, uint16_t memAddress) 22 | { 23 | uint8_t data[2]; 24 | __user_el_i2c_read_bytes(device->hi2c, device->addressR, memAddress, data, 2); 25 | return (data[0] << 8) | data[1]; 26 | } 27 | 28 | el_io_status_t _i2c_readBytes(el_bmp180_t *device, uint16_t memAddress, uint8_t pdata[], uint8_t len) 29 | { 30 | return __user_el_i2c_read_bytes(device->hi2c, device->addressR, memAddress, pdata, len); 31 | } 32 | 33 | void _i2c_writeOneByte(el_bmp180_t *device, uint16_t memAddress, uint8_t data) 34 | { 35 | __user_el_i2c_write_bytes(device->hi2c, device->addressW, memAddress, &data, 1); 36 | } 37 | 38 | void _bmp180ReadUP(el_bmp180_t *device) 39 | { 40 | uint8_t pData[3]; 41 | _i2c_writeOneByte(device, BMP180_ADDRESS_MEM, BMP180_REG_CMD_PRESS + (BMP180_OSS << 6)); 42 | el_delay(10); 43 | _i2c_readBytes(device, BMP180_REG_R_MEM, pData, 3); 44 | device->calibration->up = ((pData[0] << 16) | (pData[1] << 8) | pData[2]) >> (8 - BMP180_OSS); 45 | } 46 | 47 | void _bmp180ReadUT(el_bmp180_t *device) 48 | { 49 | _i2c_writeOneByte(device, BMP180_ADDRESS_MEM, BMP180_REG_CMD_TEMP); 50 | el_delay(5); 51 | device->calibration->ut = _i2c_readTwoBytes(device, BMP180_REG_R_MEM); 52 | } 53 | 54 | void _bmp180ReadUpAndUt(el_bmp180_t *device) 55 | { 56 | _bmp180ReadUT(device); 57 | _bmp180ReadUP(device); 58 | } 59 | 60 | el_io_status_t _bmp180ReadChipId(el_bmp180_t *device) 61 | { 62 | uint8_t chip_id = _i2c_readOneByte(device, BMP180_REG_R_CHIP_ID); 63 | return chip_id == BMP180_CHIP_ID ? EL_IO_OK : EL_IO_ERROR; 64 | } 65 | 66 | void _bmp180ReadCalibration(el_bmp180_t *device) 67 | { 68 | device->calibration->cd_ac1 = _i2c_readTwoBytes(device, BMP180_REG_R_AC1); 69 | device->calibration->cd_ac2 = _i2c_readTwoBytes(device, BMP180_REG_R_AC2); 70 | device->calibration->cd_ac3 = _i2c_readTwoBytes(device, BMP180_REG_R_AC3); 71 | 72 | device->calibration->cd_ac4 = _i2c_readTwoBytes(device, BMP180_REG_R_AC4); 73 | device->calibration->cd_ac5 = _i2c_readTwoBytes(device, BMP180_REG_R_AC5); 74 | device->calibration->cd_ac6 = _i2c_readTwoBytes(device, BMP180_REG_R_AC6); 75 | 76 | device->calibration->cd_b1 = _i2c_readTwoBytes(device, BMP180_REG_R_B1); 77 | device->calibration->cd_b2 = _i2c_readTwoBytes(device, BMP180_REG_R_B2); 78 | 79 | device->calibration->cd_mb = _i2c_readTwoBytes(device, BMP180_REG_R_MB); 80 | device->calibration->cd_mc = _i2c_readTwoBytes(device, BMP180_REG_R_MC); 81 | device->calibration->cd_md = _i2c_readTwoBytes(device, BMP180_REG_R_MD); 82 | } 83 | 84 | el_bmp180_t *el_bmp180_regist(el_i2c_def *hi2c, const char* deviceName, uint16_t address7Bit) 85 | { 86 | uint16_t targetAddress = address7Bit == NULL ? DF_BMP180_ADDRESS_7BIT : address7Bit; 87 | el_bmp180_calibration_t *cali = (el_bmp180_calibration_t *)el_malloc(sizeof(el_bmp180_calibration_t)); 88 | el_bmp180_t *device = (el_bmp180_t *)el_malloc(sizeof(el_bmp180_t)); 89 | device->hi2c = hi2c; 90 | device->addressR = targetAddress << 1; 91 | device->addressW = (targetAddress << 1) | 0x01; 92 | device->name = deviceName; 93 | device->calibration = cali; 94 | // chip id 95 | if (_bmp180ReadChipId(device) != EL_IO_OK) 96 | { 97 | printf("BMP180 check id faild\r\n"); 98 | return NULL; 99 | } 100 | // calibration 101 | _bmp180ReadCalibration(device); 102 | return device; 103 | } 104 | 105 | void el_bmp180_readStart(el_bmp180_t *device) 106 | { 107 | _bmp180ReadUpAndUt(device); 108 | } 109 | 110 | float el_bmp180_readTemperature(el_bmp180_t *device) 111 | { 112 | int32_t x1 = ((device->calibration->ut - device->calibration->cd_ac6) * device->calibration->cd_ac5) >> 15; 113 | int32_t x2 = (device->calibration->cd_mc << 11) / (x1 + device->calibration->cd_md); 114 | device->calibration->cd_b5 = x1 + x2; 115 | device->temperature = ((device->calibration->cd_b5 + 8) >> 4) * 0.1; 116 | return device->temperature; 117 | } 118 | 119 | long el_bmp180_readPressure(el_bmp180_t *device) 120 | { 121 | long p = 0; 122 | device->calibration->cd_b6 = device->calibration->cd_b5 - 4000; 123 | long x1 = (device->calibration->cd_b2 * ((device->calibration->cd_b6 * device->calibration->cd_b6) >> 12)) >> 11; 124 | long x2 = (device->calibration->cd_ac2 * device->calibration->cd_b6) >> 11; 125 | long x3 = x1 + x2; 126 | device->calibration->cd_b3 = (((device->calibration->cd_ac1 * 4 + x3) << BMP180_OSS) + 2) / 4; 127 | x1 = (device->calibration->cd_ac3 * device->calibration->cd_b6) >> 13; 128 | x2 = (device->calibration->cd_b1 * ((device->calibration->cd_b6 * device->calibration->cd_b6) >> 12)) >> 16; 129 | x3 = ((x1 + x2) + 2) / 4; 130 | device->calibration->cd_b4 = (device->calibration->cd_ac4 * (unsigned long)(x3 + 32768)) >> 15; 131 | device->calibration->cd_b7 = ((unsigned long)device->calibration->up - device->calibration->cd_b3) * (50000 >> BMP180_OSS); 132 | if (device->calibration->cd_b7 < 0x80000000) { 133 | p = (device->calibration->cd_b7 * 2) / device->calibration->cd_b4; 134 | } else { 135 | p = (device->calibration->cd_b7 / device->calibration->cd_b4) * 2; 136 | } 137 | x1 = (p >> 8) * (p >> 8); 138 | x1 = (x1 * 3038) >> 16; 139 | x2 = (-7357 * p) >> 16; 140 | p = p + ((x1 + x2 + 3791) >> 4); 141 | device->pressure = p; 142 | return device->pressure; 143 | } 144 | 145 | #endif // ENABLE_SENSOR_BMP180_I2C 146 | -------------------------------------------------------------------------------- /src/peripheral/bmp180/bmp180.h: -------------------------------------------------------------------------------- 1 | #ifndef __USER_EL_BMP180_H__ 2 | #define __USER_EL_BMP180_H__ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include "eos.h" 9 | #ifdef ENABLE_SENSOR_BMP180_I2C 10 | 11 | typedef struct { 12 | short cd_ac1; 13 | short cd_ac2; 14 | short cd_ac3; 15 | unsigned short cd_ac4; 16 | unsigned short cd_ac5; 17 | unsigned short cd_ac6; 18 | short cd_b1; 19 | short cd_b2; 20 | short cd_mb; 21 | short cd_mc; 22 | short cd_md; 23 | long cd_b3; 24 | unsigned long cd_b4; 25 | long cd_b5; 26 | long cd_b6; 27 | unsigned long cd_b7; 28 | long ut; 29 | long up; 30 | } el_bmp180_calibration_t; 31 | 32 | typedef struct 33 | { 34 | el_i2c_def *hi2c; 35 | const char* name; 36 | uint16_t addressR; 37 | uint16_t addressW; 38 | float temperature; 39 | long pressure; 40 | el_bmp180_calibration_t *calibration; 41 | } el_bmp180_t; 42 | 43 | #define BMP180_CHIP_ID 0x55 44 | #define BMP180_TEMP_STEP 0.1 45 | #define BMP180_REG_R_CHIP_ID 0xD0 46 | 47 | // power mode 48 | #define BMP180_POWER_MODE 0x01 49 | 50 | // 1 byte write 51 | #define BMP180_ADDRESS_MEM 0xF4 52 | 53 | // 1 byte cmd to rite 54 | #define BMP180_REG_CMD_TEMP 0x2E 55 | #define BMP180_REG_R_MEM 0xF6 56 | #define BMP180_REG_CMD_PRESS 0x34 57 | 58 | // 不同 power mode 下会有所不同 59 | #define BMP180_OSS 0 60 | 61 | // 2 bytes words 62 | #define BMP180_REG_R_AC1 0xAA 63 | #define BMP180_REG_R_AC2 0xAC 64 | #define BMP180_REG_R_AC3 0xAE 65 | #define BMP180_REG_R_AC4 0xB0 66 | #define BMP180_REG_R_AC5 0xB2 67 | #define BMP180_REG_R_AC6 0xB4 68 | #define BMP180_REG_R_B1 0xB6 69 | #define BMP180_REG_R_B2 0xB8 70 | #define BMP180_REG_R_MB 0xBA 71 | #define BMP180_REG_R_MC 0xBC 72 | #define BMP180_REG_R_MD 0xBE 73 | 74 | extern el_io_status_t __user_el_i2c_read_bytes(el_i2c_def *hi2c, uint16_t devAddress, uint16_t memAddress, uint8_t *pData, uint16_t pLen); 75 | extern el_io_status_t __user_el_i2c_write_bytes(el_i2c_def *hi2c, uint16_t devAddress, uint16_t memAddress, uint8_t *pData, uint16_t pLen); 76 | 77 | el_bmp180_t *el_bmp180_regist(el_i2c_def *hi2c, const char* deviceName, uint16_t address7Bit); 78 | void el_bmp180_readStart(el_bmp180_t *device); 79 | float el_bmp180_readTemperature(el_bmp180_t *device); 80 | long el_bmp180_readPressure(el_bmp180_t *device); 81 | 82 | #endif // ENABLE_SENSOR_BMP180_I2C 83 | 84 | #ifdef __cplusplus 85 | } 86 | #endif 87 | 88 | #endif // __USER_EL_BMP180_H__ 89 | 90 | -------------------------------------------------------------------------------- /src/peripheral/button/button.c: -------------------------------------------------------------------------------- 1 | #include "button.h" 2 | 3 | #ifdef ENABLE_BUTTON_DEVICE 4 | 5 | static el_btn_group_t Buttons; 6 | 7 | el_ret_t _pushBtnEvent(el_btn_t *btn, el_btn_status_t status, et_type_t eventType); 8 | void _clearDclickEvent(fun_params_t p[]); 9 | el_btn_status_t _readBtnStatus(el_btn_t *btn); 10 | 11 | el_ret_t _pushBtnEvent(el_btn_t *btn, el_btn_status_t status, et_type_t eventType) 12 | { 13 | if (el_isEventQueueValid() == EL_FALSE) 14 | { 15 | return EL_FULL; 16 | } 17 | btn->lastStatus = status; 18 | btn->lastEventTime = el_getMillis(); 19 | fun_params_t *params = (fun_params_t *)el_malloc(sizeof(fun_params_t)); 20 | params[0].stringData = btn->name; 21 | return el_pushEvent(eventType, params); 22 | } 23 | 24 | void _clearDclickEvent(fun_params_t p[]) 25 | { 26 | el_btn_t *btn = (el_btn_t *)p[0].pointer; 27 | if (btn != NULL) 28 | { 29 | btn->lockEvent = EVENT_NONE; 30 | } 31 | } 32 | 33 | el_btn_status_t _readBtnStatus(el_btn_t *btn) 34 | { 35 | return __user_el_gpio_readPin(btn->port, btn->pin) == btn->pressPinSet ? EL_BTN_PRESS : EL_BTN_RELEASE; 36 | } 37 | 38 | el_ret_t el_button_postEvent(el_btn_t *btn) 39 | { 40 | el_time_t lastEventTime = btn->lastEventTime; 41 | // press 42 | if (btn->lastStatus == EL_BTN_RELEASE && _readBtnStatus(btn) == EL_BTN_PRESS) 43 | { 44 | return _pushBtnEvent(btn, EL_BTN_PRESS, EVENT_BTN_PRESS); 45 | } 46 | 47 | // long press 48 | if (btn->lastStatus == EL_BTN_PRESS && _readBtnStatus(btn) == EL_BTN_PRESS) 49 | { 50 | if (el_getMillis() - lastEventTime >= DF_BTN_LONG_PRESS_TIME) 51 | { 52 | btn->lockEvent = EVENT_BTN_LONG_PRESS; 53 | return _pushBtnEvent(btn, EL_BTN_PRESS, EVENT_BTN_LONG_PRESS); 54 | } 55 | } 56 | 57 | // release/click 58 | if (btn->lastStatus == EL_BTN_PRESS && _readBtnStatus(btn) == EL_BTN_RELEASE) 59 | { 60 | el_ret_t res = EL_OK; 61 | res = _pushBtnEvent(btn, EL_BTN_RELEASE, EVENT_BTN_RELEASE); 62 | if (btn->lockEvent == EVENT_BTN_LONG_PRESS) 63 | { 64 | btn->lockEvent = EVENT_NONE; 65 | return res; 66 | } 67 | // double click 68 | if (btn->lockEvent == EVENT_BTN_CLICK && el_getMillis() - lastEventTime < DF_BTN_DCLICK_DELAY) 69 | { 70 | btn->lockEvent = EVENT_NONE; 71 | res = _pushBtnEvent(btn, EL_BTN_RELEASE, EVENT_BTN_DCLICK); 72 | return res; 73 | } 74 | btn->lockEvent = EVENT_BTN_CLICK; 75 | res = _pushBtnEvent(btn, EL_BTN_RELEASE, EVENT_BTN_CLICK); 76 | 77 | // setTimeout => clear dclick handler 78 | fun_params_t *params = (fun_params_t *)el_malloc(sizeof(fun_params_t)); 79 | params[0].pointer = (el_pointer_t)btn; 80 | el_setTimeout(NULL, _clearDclickEvent, DF_BTN_DCLICK_DELAY, params); 81 | return res; 82 | } 83 | return EL_EMPTY; 84 | } 85 | 86 | el_btn_t *el_button_regist(el_gpio_port_def *port, el_gpio_pin_def pin, const char* name, el_pin_set_t pressPinSet) 87 | { 88 | if (Buttons.wp >= DF_BUTTON_COUNTER) 89 | { 90 | return NULL; 91 | } 92 | el_btn_t *btn = (el_btn_t *)el_malloc(sizeof(el_btn_t)); 93 | btn->name = name; 94 | btn->port = port; 95 | btn->pin = pin; 96 | btn->lastStatus = EL_BTN_RELEASE; 97 | btn->pressPinSet = pressPinSet; 98 | btn->lastEventTime = 0; 99 | Buttons.btns[Buttons.wp++] = btn; 100 | return btn; 101 | } 102 | 103 | void el_button_scan() 104 | { 105 | if (Buttons.wp <= 0) 106 | { 107 | return; 108 | } 109 | for (uint8_t i = 0; i < Buttons.wp; i++) 110 | { 111 | el_button_postEvent(Buttons.btns[i]); 112 | } 113 | } 114 | 115 | #endif // ENABLE_BUTTON_DEVICE 116 | -------------------------------------------------------------------------------- /src/peripheral/button/button.h: -------------------------------------------------------------------------------- 1 | #ifndef __USER_EL_BUTTON_H__ 2 | #define __USER_EL_BUTTON_H__ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include "eos.h" 9 | #ifdef ENABLE_BUTTON_DEVICE 10 | #ifndef ENABLE_GPIO_DRIVER 11 | #error "Please enable the GPIO driver!" 12 | #endif // !ENABLE_GPIO_DRIVER 13 | 14 | typedef enum 15 | { 16 | EL_BTN_PRESS, 17 | EL_BTN_RELEASE, 18 | } el_btn_status_t; 19 | 20 | typedef struct 21 | { 22 | const char* name; 23 | el_gpio_port_def *port; 24 | el_gpio_pin_def pin; 25 | el_btn_status_t lastStatus; 26 | el_pin_set_t pressPinSet; 27 | el_time_t lastEventTime; 28 | et_type_t lockEvent; 29 | } el_btn_t; 30 | 31 | typedef struct 32 | { 33 | el_btn_t *btns[DF_BUTTON_COUNTER]; 34 | uint8_t wp; 35 | } el_btn_group_t; 36 | 37 | extern el_pin_set_t __user_el_gpio_readPin(el_gpio_port_def *port, el_gpio_pin_def pin); 38 | 39 | el_btn_t *el_button_regist(el_gpio_port_def *port, el_gpio_pin_def pin, const char* name, el_pin_set_t pressPinSet); 40 | el_ret_t el_button_postEvent(el_btn_t *btn); 41 | void el_button_scan(void); 42 | 43 | #endif 44 | 45 | #ifdef __cplusplus 46 | } 47 | #endif 48 | 49 | #endif // ENABLE_BUTTON_DEVICE 50 | 51 | -------------------------------------------------------------------------------- /src/peripheral/buzzer/buzzer.c: -------------------------------------------------------------------------------- 1 | #include "buzzer.h" 2 | 3 | #ifdef ENABLE_BUZZER_DEVICE 4 | 5 | void _resetBuzzerCompareState(fun_params_t p[]) 6 | { 7 | el_buzzer_t *buzzer = (el_buzzer_t *)p[0].pointer; 8 | __user_el_buzzer_setTimCompare(buzzer->htim, buzzer->channel, 0); 9 | } 10 | 11 | el_buzzer_t *el_buzzer_regist(el_tim_def *htim, el_channel_def channel, const char *name, uint16_t initState) 12 | { 13 | el_buzzer_t *buzzer = (el_buzzer_t *)el_malloc(sizeof(el_buzzer_t)); 14 | buzzer->name = name; 15 | buzzer->htim = htim; 16 | buzzer->channel = channel; 17 | buzzer->compare = initState; 18 | __user_el_buzzer_start(htim, channel); 19 | return buzzer; 20 | } 21 | 22 | void el_buzzer_setState(el_buzzer_t *buzzer, uint16_t period, el_time_t duration) 23 | { 24 | __user_el_buzzer_setTimPeriod(buzzer->htim, period); 25 | __user_el_buzzer_setTimCompare(buzzer->htim, buzzer->channel, buzzer->compare); 26 | fun_params_t *params = (fun_params_t *)el_malloc(sizeof(fun_params_t)); 27 | params[0].pointer = (el_pointer_t)buzzer; 28 | el_setTimeout(NULL, _resetBuzzerCompareState, duration, params); 29 | } 30 | #endif // ENABLE_BUZZER_DEVICE 31 | -------------------------------------------------------------------------------- /src/peripheral/buzzer/buzzer.h: -------------------------------------------------------------------------------- 1 | #ifndef __USER_EL_BUZZER_H__ 2 | #define __USER_EL_BUZZER_H__ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include "eos.h" 9 | #ifdef ENABLE_BUZZER_DEVICE 10 | typedef struct 11 | { 12 | const char *name; 13 | el_tim_def *htim; 14 | el_channel_def channel; 15 | uint16_t compare; 16 | } el_buzzer_t; 17 | 18 | extern void __user_el_buzzer_start(el_tim_def *tim, el_channel_def channel); 19 | extern void __user_el_buzzer_stop(el_tim_def *tim, el_channel_def channel); 20 | extern void __user_el_buzzer_setTimCompare(el_tim_def *tim, el_channel_def channel, uint16_t value); 21 | extern void __user_el_buzzer_setTimPeriod(el_tim_def *tim, uint16_t period); 22 | 23 | el_buzzer_t *el_buzzer_regist(el_tim_def *htim, el_channel_def channel, const char *name, uint16_t initState); 24 | void el_buzzer_setState(el_buzzer_t *buzzer, uint16_t period, el_time_t duration); 25 | 26 | #endif 27 | 28 | #ifdef __cplusplus 29 | } 30 | #endif // ENABLE_BUZZER_DEVICE 31 | 32 | #endif // __USER_EL_BUZZER_H__ 33 | -------------------------------------------------------------------------------- /src/peripheral/led/led.c: -------------------------------------------------------------------------------- 1 | #include "led.h" 2 | #include 3 | 4 | #ifdef ENABLE_LED_DEVICE 5 | 6 | el_led_t *el_led_regist(el_gpio_port_def *port, el_gpio_pin_def pin, const char *name, el_pin_set_t onPinSet) 7 | { 8 | el_led_t *led = (el_led_t *)el_malloc(sizeof(el_led_t)); 9 | led->name = name; 10 | led->port = port; 11 | led->pin = pin; 12 | led->onPinSet = onPinSet; 13 | led->status = EL_LED_STATUS_UNKNOWN; 14 | return led; 15 | } 16 | 17 | void el_led_on(el_led_t *led) 18 | { 19 | __user_el_gpio_writePin(led->port, led->pin, led->onPinSet); 20 | led->status = EL_LED_STATUS_ON; 21 | } 22 | 23 | void el_led_off(el_led_t *led) 24 | { 25 | __user_el_gpio_writePin(led->port, led->pin, (el_pin_set_t)!led->onPinSet); 26 | led->status = EL_LED_STATUS_OFF; 27 | } 28 | 29 | void el_led_blink(el_led_t *led, el_time_t onMs) 30 | { 31 | if (onMs == 0) 32 | return; 33 | el_led_on(led); 34 | fun_params_t *params = (fun_params_t *)el_malloc(sizeof(el_led_t)); 35 | memcpy(params, led, sizeof(el_led_t)); 36 | el_setTimeout(NULL, el_led_off, onMs, params); 37 | } 38 | 39 | #endif // ENABLE_LED_DEVICE 40 | -------------------------------------------------------------------------------- /src/peripheral/led/led.h: -------------------------------------------------------------------------------- 1 | #ifndef __USER_EL_LED_H__ 2 | #define __USER_EL_LED_H__ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include "eos.h" 9 | #ifdef ENABLE_LED_DEVICE 10 | #ifndef ENABLE_GPIO_DRIVER 11 | #error "Please enable the GPIO driver!" 12 | #endif // !ENABLE_GPIO_DRIVER 13 | 14 | typedef enum 15 | { 16 | EL_LED_STATUS_UNKNOWN, 17 | EL_LED_STATUS_ON, 18 | EL_LED_STATUS_OFF, 19 | } el_led_status_t; 20 | 21 | typedef struct 22 | { 23 | const char *name; 24 | el_gpio_port_def *port; 25 | el_gpio_pin_def pin; 26 | el_pin_set_t onPinSet; 27 | el_led_status_t status; 28 | } el_led_t; 29 | 30 | extern void __user_el_gpio_writePin(el_gpio_port_def *port, el_gpio_pin_def pin, el_pin_set_t state); 31 | 32 | el_led_t *el_led_regist(el_gpio_port_def *port, el_gpio_pin_def pin, const char *name, el_pin_set_t onPinSet); 33 | void el_led_on(el_led_t *led); 34 | void el_led_off(el_led_t *led); 35 | void el_led_blink(el_led_t *led, el_time_t onMs); 36 | 37 | #ifdef ENABLE_PWM_DRIVER 38 | extern void __user_el_pwm_setValue(el_gpio_port_def *port, el_gpio_pin_def pin, el_pin_set_t value); 39 | #endif // ENABLE_PWM_DRIVER 40 | 41 | #endif // ENABLE_LED_DEVICE 42 | 43 | #ifdef __cplusplus 44 | } 45 | #endif 46 | 47 | #endif // __USER_EL_LED_H__ 48 | -------------------------------------------------------------------------------- /src/peripheral/peripheral.h: -------------------------------------------------------------------------------- 1 | #ifndef __USER_EL_PERIPHERA_H__ 2 | #define __USER_EL_PERIPHERA_H__ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include "eos.h" 9 | 10 | #ifdef ENABLE_BUTTON_DEVICE 11 | #include "peripheral/button/button.h" 12 | #endif // ENABLE_BUTTON_DEVICE 13 | 14 | #ifdef ENABLE_BUZZER_DEVICE 15 | #include "peripheral/buzzer/buzzer.h" 16 | #endif // ENABLE_BUZZER_DEVICE 17 | 18 | #ifdef ENABLE_LED_DEVICE 19 | #include "peripheral/led/led.h" 20 | #endif // ENABLE_LED_DEVICE 21 | 22 | #ifdef ENABLE_SENSOR_BMP180_I2C 23 | #include "peripheral/bmp180/bmp180.h" 24 | #endif // ENABLE_SENSOR_BMP180_I2C 25 | 26 | #ifdef __cplusplus 27 | } 28 | #endif 29 | 30 | #endif // __USER_EL_PERIPHERA_H__ 31 | -------------------------------------------------------------------------------- /src/sys_global.h: -------------------------------------------------------------------------------- 1 | #ifndef __USER_EL_SYS_GLOBAL_H__ 2 | #define __USER_EL_SYS_GLOBAL_H__ 3 | 4 | #include 5 | #include 6 | #include "build.h" 7 | 8 | #define EL_PARAMS_NULL NULL 9 | #define el_getMillis Bsp_Get_Tick 10 | #define el_delaySync Bsp_Delay_Ms 11 | 12 | typedef enum 13 | { 14 | EL_OK = 1, 15 | EL_ERR, 16 | EL_BUSY, 17 | EL_FULL, 18 | EL_EMPTY, 19 | } el_ret_t; 20 | 21 | typedef enum 22 | { 23 | EL_IO_OK = 0x00U, 24 | EL_IO_ERROR = 0x01U, 25 | EL_IO_BUSY = 0x02U, 26 | EL_IO_TIMEOUT = 0x03U 27 | } el_io_status_t; 28 | 29 | typedef enum 30 | { 31 | EL_PIN_LOW = 0, 32 | EL_PIN_HIGH, 33 | } el_pin_set_t; 34 | 35 | typedef enum 36 | { 37 | EL_FALSE = 0, 38 | EL_TRUE, 39 | } el_bool_t; 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /src/transplant/bsp_inc.h: -------------------------------------------------------------------------------- 1 | #ifndef __USER_EL_BSPINC_H__ 2 | #define __USER_EL_BSPINC_H__ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include "build.h" 9 | 10 | #ifdef BSP_USE_STM32_HAL 11 | #include "transplant/stm32_hal/bsp.h" 12 | #endif // BSP_USE_STM32_HAL 13 | 14 | #ifdef BSP_USE_STM8_SPL 15 | #include "transplant/stm8_spl/bsp.h" 16 | #endif // BSP_USE_STM8_SPL 17 | 18 | #ifdef BSP_USE_ARDUINO 19 | #include "transplant/arduino/bsp.h" 20 | #endif // BSP_USE_ARDUINO 21 | 22 | #ifdef __cplusplus 23 | } 24 | #endif 25 | 26 | #endif // __USER_EL_BSPINC_H__ 27 | -------------------------------------------------------------------------------- /src/transplant/stm32_hal/bsp.c: -------------------------------------------------------------------------------- 1 | #include "bsp.h" 2 | 3 | // Define gpio read and write functions 4 | #ifdef ENABLE_GPIO_DRIVER 5 | extern void __user_el_gpio_writePin(el_gpio_port_def *port, el_gpio_pin_def pin, el_pin_set_t state) 6 | { 7 | HAL_GPIO_WritePin(port, pin, (GPIO_PinState)state); 8 | } 9 | 10 | extern el_pin_set_t __user_el_gpio_readPin(el_gpio_port_def *port, el_gpio_pin_def pin) 11 | { 12 | return (el_pin_set_t)HAL_GPIO_ReadPin(port, pin); 13 | } 14 | #endif // ENABLE_GPIO_DRIVER 15 | 16 | #ifdef ENABLE_BUZZER_DEVICE 17 | __weak void __user_el_buzzer_setTimCompare(el_tim_def *tim, el_channel_def channel, uint16_t value) 18 | { 19 | __HAL_TIM_SetCompare(tim, channel, value); 20 | } 21 | 22 | __weak void __user_el_buzzer_setTimPeriod(el_tim_def *tim, uint16_t period) 23 | { 24 | __HAL_TIM_SetAutoreload(tim, period); 25 | } 26 | 27 | __weak void __user_el_buzzer_start(el_tim_def *tim, el_channel_def channel) 28 | { 29 | HAL_TIM_PWM_Start(tim, channel); 30 | } 31 | 32 | __weak void __user_el_buzzer_stop(el_tim_def *tim, el_channel_def channel) 33 | { 34 | HAL_TIMEx_PWMN_Stop(tim, channel); 35 | } 36 | #endif // ENABLE_BUZZER_DEVICE 37 | 38 | // Define i2c read and write functions 39 | #ifdef ENABLE_I2C_SENSOR 40 | __weak el_io_status_t __user_el_i2c_read_bytes(el_i2c_def *hi2c, uint16_t devAddress, uint16_t memAddress, uint8_t *pData, uint16_t pLen) 41 | { 42 | return (el_io_status_t)HAL_I2C_Mem_Read(hi2c, devAddress, memAddress, I2C_MEMADD_SIZE_8BIT, pData, pLen, DF_I2C_TIMEOUT); 43 | } 44 | __weak el_io_status_t __user_el_i2c_write_bytes(el_i2c_def *hi2c, uint16_t devAddress, uint16_t memAddress, uint8_t *pData, uint16_t pLen) 45 | { 46 | return (el_io_status_t)HAL_I2C_Mem_Write(hi2c, devAddress, memAddress, I2C_MEMADD_SIZE_8BIT, pData, pLen, DF_I2C_TIMEOUT); 47 | } 48 | #endif // ENABLE_I2C_SENSOR 49 | 50 | -------------------------------------------------------------------------------- /src/transplant/stm32_hal/bsp.h: -------------------------------------------------------------------------------- 1 | #ifndef __USER_EL_BSP_H__ 2 | #define __USER_EL_BSP_H__ 3 | 4 | #include "stm32f4xx_hal.h" 5 | #include "sys_global.h" 6 | 7 | #ifndef NULL 8 | #define NULL ((void *)0) 9 | #endif // NULL 10 | 11 | /* Time-delay function and tick timer definition */ 12 | #define Bsp_Get_Tick HAL_GetTick 13 | #define Bsp_Delay_Ms HAL_Delay 14 | 15 | /* Timestamp and pointer type definitions */ 16 | #define el_time_t uint32_t 17 | #define el_pointer_t uint32_t 18 | 19 | typedef union 20 | { 21 | uint8_t uint8Data; 22 | const char* stringData; 23 | el_time_t timestamp; 24 | el_pointer_t pointer; 25 | // ... 26 | // Add a custom type here 27 | // ... 28 | } fun_params_t; 29 | 30 | typedef enum 31 | { 32 | EVENT_NONE = 0, 33 | EVENT_EL_LOAD, 34 | EVENT_HEAP_INVALID, 35 | #ifdef ENABLE_BUTTON_DEVICE 36 | EVENT_BTN_PRESS, 37 | EVENT_BTN_LONG_PRESS, 38 | EVENT_BTN_RELEASE, 39 | EVENT_BTN_CLICK, 40 | EVENT_BTN_DCLICK, 41 | #endif // ENABLE_BUTTON_DEVICE 42 | EVENT_SELF_ADD, 43 | // ... 44 | // Add other event enumeration values here 45 | // ... 46 | } et_type_t; 47 | 48 | /** 49 | * @brief Enabling the GPIO driver 50 | * el_gpio_port_def: If not(like arduino), it can be defined as NULL 51 | * el_gpio_pin_def: Data type of pin number 52 | */ 53 | #ifdef ENABLE_GPIO_DRIVER 54 | #define el_gpio_port_def GPIO_TypeDef 55 | #define el_gpio_pin_def uint16_t 56 | #endif // ENABLE_GPIO_DRIVER 57 | 58 | /** 59 | * @brief Enabling the user button driver 60 | * 61 | * DF_BTN_LONG_PRESS_TIME: Wait time to trigger the button long press event 62 | * DF_BTN_DCLICK_DELAY: Double-click time trigger time 63 | */ 64 | #ifdef ENABLE_BUTTON_DEVICE 65 | #define DF_BTN_LONG_PRESS_TIME 1000 66 | #define DF_BTN_DCLICK_DELAY 300 67 | #endif // ENABLE_BUTTON_DEVICE 68 | 69 | /* Enable buzzer driver */ 70 | #ifdef ENABLE_BUZZER_DEVICE 71 | #define el_tim_def TIM_HandleTypeDef 72 | #define el_channel_def uint16_t 73 | #endif // ENABLE_BUZZER_DEVICE 74 | 75 | /* Enabling i2c protocol */ 76 | #ifdef ENABLE_I2C_SENSOR 77 | #define el_i2c_def I2C_HandleTypeDef 78 | #define DF_I2C_TIMEOUT 1000 79 | #endif // ENABLE_I2C_SENSOR 80 | 81 | /* Enables the bmp180 sensor, using the i2c driver protocol */ 82 | #ifdef ENABLE_SENSOR_BMP180_I2C 83 | #define DF_BMP180_ADDRESS_7BIT 0x77 84 | #endif // ENABLE_SENSOR_BMP180_I2C 85 | 86 | #endif // __USER_EL_BSP_H__ 87 | --------------------------------------------------------------------------------