luat_lib_max30102.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. /*
  2. @module max30102
  3. @summary 心率模块(MAX30102)
  4. @version 1.0
  5. @date 2023.2.28
  6. @tag LUAT_USE_MAX30102
  7. */
  8. #include "luat_base.h"
  9. #include "luat_mem.h"
  10. #include "luat_timer.h"
  11. #include "luat_gpio.h"
  12. #include "luat_rtos.h"
  13. #include "MAX30102.h"
  14. #include "algorithm.h"
  15. #define LUAT_LOG_TAG "max30102"
  16. #include "luat_log.h"
  17. uint8_t max30102_i2c_id;
  18. static uint8_t max30102_int;
  19. static uint64_t max30102_idp;
  20. #define MAX30102_CHIP_ID 0x15
  21. #define SAMP_BUFF_LEN 1000
  22. #define AVG_BUFF_LEN 37
  23. /*
  24. 初始化MAX30102传感器
  25. @api max30102.init(i2c_id,int)
  26. @int 传感器所在的i2c总线id,默认为0
  27. @int int引脚
  28. @return bool 成功返回true, 否则返回nil或者false
  29. @usage
  30. if max30102.init(0,pin.PC05) then
  31. log.info("max30102", "init ok")
  32. else
  33. log.info("max30102", "init fail")
  34. end
  35. */
  36. static int l_max30102_init(lua_State *L){
  37. uint8_t cmd,uch_dummy;
  38. max30102_i2c_id = luaL_optinteger(L, 1 , 0);
  39. max30102_int = luaL_checkinteger(L, 2);
  40. maxim_max30102_read_reg(REG_PART_ID, &cmd);
  41. if (cmd == MAX30102_CHIP_ID){
  42. luat_gpio_mode(max30102_int,LUAT_GPIO_INPUT, LUAT_GPIO_PULLUP, LUAT_GPIO_HIGH);
  43. maxim_max30102_reset();
  44. luat_timer_mdelay(20);
  45. maxim_max30102_read_reg(REG_INTR_STATUS_1,&uch_dummy);
  46. maxim_max30102_init(); //initializes the MAX30102
  47. luat_timer_mdelay(20);
  48. lua_pushboolean(L, 1);
  49. return 1;
  50. }
  51. return 0;
  52. }
  53. luat_rtos_task_handle max30102_task_handle = NULL;
  54. static int32_t l_max30102_callback(lua_State *L, void* ptr){
  55. rtos_msg_t* msg = (rtos_msg_t*)lua_topointer(L, -1);
  56. lua_pushboolean(L, 1);
  57. lua_pushinteger(L, msg->arg1);
  58. lua_pushinteger(L, msg->arg2);
  59. luat_cbcwait(L, max30102_idp, 3);
  60. max30102_idp = 0;
  61. return 0;
  62. }
  63. void max30102_task(void *param){
  64. uint64_t red_sum = 0, ir_sum = 0;
  65. uint8_t red_avg_len = 0,ir_avg_len = 0;
  66. int32_t red_min = 0x3FFFF, red_max = 0,ir_min = 0x3FFFF, ir_max = 0, HR = 0,SpO2 = 0;
  67. uint32_t* samples_buffer = luat_heap_malloc(sizeof(uint32_t) * SAMP_BUFF_LEN * 2);
  68. if (samples_buffer == NULL) {
  69. LLOGE("out of memory");
  70. return;
  71. }
  72. int32_t* avg_buffer = luat_heap_malloc(sizeof(int32_t) * AVG_BUFF_LEN * 2);
  73. if (avg_buffer == NULL) {
  74. LLOGE("out of memory");
  75. luat_heap_free(samples_buffer);
  76. return;
  77. }
  78. for(size_t i=0;i<SAMP_BUFF_LEN;i++){
  79. int timeout = 30;
  80. while(luat_gpio_get(max30102_int) == 1){
  81. luat_timer_mdelay(1);
  82. timeout --;
  83. if (timeout == 0) {
  84. LLOGE("超时了,读取失败");
  85. }
  86. } //wait until the interrupt pin asserts
  87. maxim_max30102_read_fifo((samples_buffer+i), (samples_buffer+SAMP_BUFF_LEN+i)); //read from MAX30102 FIFO
  88. }
  89. for (size_t i = 0; i < AVG_BUFF_LEN; i++){
  90. int32_t sp02,heart;
  91. int8_t spo2_valid = 0,heart_valid = 0;
  92. maxim_heart_rate_and_oxygen_saturation(samples_buffer+SAMP_BUFF_LEN+i*25, 100, samples_buffer+i*25, &sp02, &spo2_valid, &heart, &heart_valid);
  93. if (heart_valid == 1 && heart > 30 && heart < 150){
  94. avg_buffer[red_avg_len] = heart;
  95. red_avg_len++;
  96. if (heart<red_min) red_min = heart;
  97. if (heart>red_max) red_max = heart;
  98. red_sum += heart;
  99. }
  100. if (spo2_valid == 1 && sp02 > 90 && sp02 < 100){
  101. avg_buffer[ir_avg_len + AVG_BUFF_LEN] = sp02;
  102. ir_avg_len++;
  103. if (sp02<ir_min) ir_min = sp02;
  104. if (sp02>ir_max) ir_max = sp02;
  105. ir_sum += sp02;
  106. }
  107. }
  108. if (red_avg_len){
  109. HR = (red_sum - red_min - red_max) / (red_avg_len-2);
  110. }
  111. if (ir_avg_len){
  112. SpO2 = (ir_sum - ir_min - ir_max) / (ir_avg_len-2);
  113. }
  114. luat_heap_free(samples_buffer);
  115. luat_heap_free(avg_buffer);
  116. if (HR!=0 && SpO2!=0){
  117. rtos_msg_t msg = {
  118. .handler = l_max30102_callback,
  119. .arg1 = HR,
  120. .arg2 = SpO2
  121. };
  122. luat_msgbus_put(&msg, 0);
  123. }else{
  124. luat_cbcwait_noarg(max30102_idp);
  125. max30102_idp = 0;
  126. }
  127. luat_rtos_task_delete(max30102_task_handle);
  128. }
  129. /*
  130. 获取心率血氧(大概需要10s时间测量)
  131. @api max30102.get()
  132. @return bool 成功返回true, 否则返回nil或者false
  133. @return number 心率
  134. @return number 血氧
  135. */
  136. static int l_max30102_get(lua_State *L) {
  137. if (max30102_idp){
  138. lua_pushboolean(L, 0);
  139. luat_pushcwait_error(L,1);
  140. }else{
  141. max30102_idp = luat_pushcwait(L);
  142. int ret = luat_rtos_task_create(&max30102_task_handle, 3*1024, 10, "max30102", max30102_task, NULL, 0);
  143. if (ret) {
  144. LLOGE("max30102线程启动失败 %d", ret);
  145. luat_pushcwait_error(L,1);
  146. }
  147. }
  148. return 1;
  149. }
  150. // /*
  151. // 获取max30102温度
  152. // @api max30102.temp()
  153. // @return number 温度
  154. // */
  155. // static int l_max30102_temp(lua_State *L) {
  156. // int8_t temp_intr,temp_frac;
  157. // float temp;
  158. // maxim_max30102_read_reg(REG_TEMP_INTR, &temp_intr);
  159. // maxim_max30102_read_reg(REG_TEMP_FRAC, &temp_frac);
  160. // LLOGD("l_max30102_temp %d %d",temp_intr,temp_frac);
  161. // temp = temp_intr + temp_frac * 0.0625;
  162. // lua_pushnumber(L, temp);
  163. // return 1;
  164. // }
  165. /*
  166. 关闭max30102
  167. @api max30102.shutdown()
  168. */
  169. static int l_max30102_shutdown(lua_State *L) {
  170. maxim_max30102_shutdown();
  171. return 0;
  172. }
  173. #include "rotable2.h"
  174. static const rotable_Reg_t reg_max30102[] =
  175. {
  176. {"init", ROREG_FUNC(l_max30102_init)},
  177. {"get", ROREG_FUNC(l_max30102_get)},
  178. // {"temp", ROREG_FUNC(l_max30102_temp)},
  179. {"shutdown", ROREG_FUNC(l_max30102_shutdown)},
  180. { NULL, ROREG_INT(0) }
  181. };
  182. LUAMOD_API int luaopen_max30102( lua_State *L ) {
  183. luat_newlib2(L, reg_max30102);
  184. return 1;
  185. }