selfcheck.c 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823
  1. /*Includes ----------------------------------------------*/
  2. #include "tool.h"
  3. #include "MahonyAHRS.h"
  4. #include "ble_comm.h"
  5. #include "nrf_delay.h"
  6. #include "bsp_pwm.h"
  7. #include "bsp_time.h"
  8. #include "bsp_adc.h"
  9. #include "bsp_wdt.h"
  10. #include "exception.h"
  11. #include "selfcheck.h"
  12. #include "system.h"
  13. #include "drv_qma7981.h"
  14. #include "hal_led.h"
  15. #include "hal_battery.h"
  16. #include "bll_imu.h"
  17. #include "app_flash.h"
  18. /*Private macro ------------------------------------------------------------------------------------------------------------------------------------*/
  19. #define SELFCHECK_FLOW_TOOLING_BOARD_PROCESS_CYCLE LowPower_Interval //工装自检线程周期,单位:ms
  20. #define SELFCHECK_FLOW_COMPLETE_BOARD_PROCESS_1_CYCLE 2000 //完整板自检线程1周期,单位:ms
  21. #define SELFCHECK_FLOW_COMPLETE_BOARD_PROCESS_2_CYCLE LowPower_Interval //完整板自检线程2周期,单位:ms
  22. #define SELFCHECK_SCAN_DEVICE_NAME "123" //需要扫描的设备名
  23. #define SELFCHECK_SCAN_DEVICE_RSSI_MIN_THRESHOLD -100 //需要扫描的设备的RSSI最小阈值
  24. #define SELFCHECK_LED_ENABLE 0 //LED灯开
  25. #define SELFCHECK_LED_DISABLE 1 //LED灯关
  26. #define SELFCHECK_THRESHOLD_IS_MET(MIN,VALUE,MAX) ((MIN <= VALUE && VALUE <= MAX)?true:false) //阈值匹配
  27. #define SELFCHECK_PAIR_PIN_ADC_MIN_THRESHOLD 100 //配对引脚的最小ADC阈值
  28. #define SELFCHECK_PAIR_PIN_ADC_MAX_THRESHOLD 200 //配对引脚的最大ADC阈值
  29. #define SELFCHECK_CHARGE_CHIP_PIN_ADC_MIN_THRESHOLD 100 //充电芯片引脚的最小ADC阈值
  30. #define SELFCHECK_CHARGE_CHIP_PIN_ADC_MAX_THRESHOLD 200 //充电芯片引脚的最大ADC阈值
  31. #define SELFCHECK_BATTERY_PIN_ADC_MIN_THRESHOLD 100 //电池分压电阻的最小ADC阈值
  32. #define SELFCHECK_BATTERY_PIN_ADC_MAX_THRESHOLD 200 //电池分压电阻的最大ADC阈值
  33. #define SELFCHECK_MIDDLE_ACC_ROLL_MIN_THRESHOLD 5 //中间加速度ROLL值最小阈值
  34. #define SELFCHECK_MIDDLE_ACC_ROLL_MAX_THRESHOLD 10 //中间加速度ROLL值最大阈值
  35. #define SELFCHECK_WEAR_INSOLE_MAG_NORM_MIN_THRESHOLD 100 //穿鞋垫的地磁norm值最小阈值
  36. #define SELFCHECK_WEAR_INSOLE_MAG_NORM_MAX_THRESHOLD 200 //穿鞋垫的地磁norm值最大阈值
  37. /*STRUCTION ------------------------------------------------------------------------------------------------------------------------------------*/
  38. typedef enum {
  39. SELFCHECK_RESULT_SUCCESS, //自检成功
  40. SELFCHECK_RESULT_ERR_ADV_INIT, //自检失败——广播初始化
  41. SELFCHECK_RESULT_ERR_RSSI, //自检失败——RSSI
  42. SELFCHECK_RESULT_ERR_READ_ADC, //自检失败——ADC读取失败
  43. SELFCHECK_RESULT_ERR_PAIR_PIN_ADC, //自检失败——配对引脚ADC
  44. SELFCHECK_RESULT_ERR_CHARGE_CHIP_PIN_ADC, //自检失败——充电芯片引脚ADC
  45. SELFCHECK_RESULT_ERR_BATTERY_PIN_ADC, //自检失败——电池分压电阻ADC
  46. SELFCHECK_RESULT_ERR_MIDDLE_SENSOR_CONFIG, //自检失败——中间传感器配置
  47. SELFCHECK_RESULT_ERR_FRONT_SENSOR_CONFIG, //自检失败——前脚传感器配置
  48. SELFCHECK_RESULT_ERR_BACK_SENSOR_CONFIG, //自检失败——后脚传感器配置
  49. SELFCHECK_RESULT_ERR_MIDDLE_NO_DATA, //自检失败——中间传感器没数据
  50. SELFCHECK_RESULT_ERR_FRONT_NO_DATA, //自检失败——前脚传感器没数据
  51. SELFCHECK_RESULT_ERR_BACK_NO_DATA, //自检失败——后脚传感器没数据
  52. SELFCHECK_RESULT_ERR_MIDDLE_ACC_ROLL, //自检失败——中间传感器加速度roll值
  53. SELFCHECK_RESULT_ERR_FLASH_WRITE, //自检失败——写flash
  54. } SELFCHECK_RESULT_e;
  55. typedef struct _selfcheck
  56. {
  57. uint32_t selfcheck_result; //自检结果
  58. uint32_t selfcheck_result_led_color; //自检结果的led灯颜色
  59. int16_t max_rssi; //最大的RSSI值
  60. fml_imu_data_t f_data; //前脚传感器数据
  61. fml_imu_data_t b_data; //后脚传感器数据
  62. qma_data_t m_data; //中间传感器数据
  63. bool f_is_read_data; //前脚传感器是否读到数据标志位
  64. bool b_is_read_data; //后脚传感器是否读到数据标志位
  65. } SelfCheck_t;
  66. /*Local Variable ------------------------------------------------------------------------------------------------------------------------------------*/
  67. static SelfCheck_t ob_selfcheck;
  68. static const bll_imu_one_way_param_t game_front_param={
  69. .acc_power_mode = FML_IMU_ACC_POWER_MODE_NORMAL, //前脚 - 加速度正常模式
  70. .gry_power_mode = FML_IMU_GRY_POWER_MODE_NORMAL, //前脚 - 陀螺仪正常模式
  71. .timestamp_resolution = FML_IMU_TIMESTAMP_25US, //前脚 - 时间戳25US精度
  72. .timestamp_switch = FML_IMU_TIMESTAMP_ON, //前脚 - 时间戳开启
  73. .acc_fs = FML_IMU_ACC_FS_16G, //前脚 - 加速度量程 - 16G
  74. .gry_fs = FML_IMU_GRY_FS_2000DPS, //前脚 - 陀螺仪量程 - 2000DPS
  75. .mag_fs = FML_IMU_MAG_FS_30GS, //前脚 - 地磁计量程 - 30GS
  76. .acc_odr = FML_IMU_ACC_ODR_416HZ, //前脚 - 加速度采样频率 - 104HZ
  77. .gry_odr = FML_IMU_GRY_ODR_416HZ, //前脚 - 陀螺仪采样频率 - 104HZ
  78. .mag_odr = FML_IMU_MAG_ODR_200HZ, //前脚 - 地磁计采样频率 - 200HZ
  79. .fifo_odr = FML_IMU_FIFO_ODR_416HZ,
  80. };
  81. static const bll_imu_one_way_param_t game_back_param={
  82. .acc_power_mode = FML_IMU_ACC_POWER_MODE_NORMAL, //后脚 - 加速度正常模式
  83. .gry_power_mode = FML_IMU_GRY_POWER_MODE_NORMAL, //后脚 - 陀螺仪正常模式
  84. .timestamp_resolution = FML_IMU_TIMESTAMP_25US, //后脚 - 时间戳25US精度
  85. .timestamp_switch = FML_IMU_TIMESTAMP_OFF, //后脚 - 时间戳关闭
  86. .acc_fs = FML_IMU_ACC_FS_16G, //后脚 - 加速度量程 - 16G
  87. .gry_fs = FML_IMU_GRY_FS_2000DPS, //后脚 - 陀螺仪量程 - 2000DPS
  88. .mag_fs = FML_IMU_MAG_FS_30GS, //后脚 - 地磁计量程 - 30GS
  89. .acc_odr = FML_IMU_ACC_ODR_OFF, //后脚 - 加速度采样频率 - 关闭
  90. .gry_odr = FML_IMU_GRY_ODR_OFF, //后脚 - 陀螺仪采样频率 - 关闭
  91. .mag_odr = FML_IMU_MAG_ODR_200HZ, //后脚 - 地磁计采样频率 - 200HZ
  92. .fifo_odr = FML_IMU_FIFO_ODR_OFF,
  93. };
  94. static const bll_imu_param_t game_bll_imu_param_t={
  95. .config_param[FML_IMU_DIR_FRONT] = &game_front_param,
  96. .config_param[FML_IMU_DIR_BACK] = &game_back_param,
  97. };
  98. /*Local Functions ------------------------------------------------------------------------------------------------------------------------------------*/
  99. static uint8_t sleep_duration_control_low_power_interval(void)
  100. {
  101. return 1;
  102. }
  103. static void UART0_SendChar(unsigned char ch)//发送一位数锯
  104. {
  105. NRF_UART0->TXD = (unsigned int)ch;
  106. while(NRF_UART0->EVENTS_TXDRDY == 0x0UL);
  107. NRF_UART0->EVENTS_TXDRDY = 0x0UL;
  108. }
  109. static uint32_t get_baud(uint32_t baud)
  110. {
  111. switch(baud){
  112. case 1200: return UART_BAUDRATE_BAUDRATE_Baud1200;
  113. case 2400: return UART_BAUDRATE_BAUDRATE_Baud2400;
  114. case 4800: return UART_BAUDRATE_BAUDRATE_Baud4800;
  115. case 9600: return UART_BAUDRATE_BAUDRATE_Baud9600;
  116. case 14400: return UART_BAUDRATE_BAUDRATE_Baud14400;
  117. case 19200: return UART_BAUDRATE_BAUDRATE_Baud19200;
  118. case 28800: return UART_BAUDRATE_BAUDRATE_Baud28800;
  119. case 31250: return UART_BAUDRATE_BAUDRATE_Baud31250;
  120. case 38400: return UART_BAUDRATE_BAUDRATE_Baud38400;
  121. case 56000: return UART_BAUDRATE_BAUDRATE_Baud56000;
  122. case 57600: return UART_BAUDRATE_BAUDRATE_Baud57600;
  123. case 76800: return UART_BAUDRATE_BAUDRATE_Baud76800;
  124. case 115200: return UART_BAUDRATE_BAUDRATE_Baud115200;
  125. case 230400: return UART_BAUDRATE_BAUDRATE_Baud230400;
  126. case 250000: return UART_BAUDRATE_BAUDRATE_Baud250000;
  127. case 460800: return UART_BAUDRATE_BAUDRATE_Baud460800;
  128. case 921600: return UART_BAUDRATE_BAUDRATE_Baud921600;
  129. case 1000000: return UART_BAUDRATE_BAUDRATE_Baud1M;
  130. default: return UART_BAUDRATE_BAUDRATE_Baud115200;
  131. }
  132. }
  133. static void UART0_Init(uint32_t txd, uint32_t rxd, uint32_t baud)
  134. {
  135. NRF_UART0->INTENCLR = UART_INTENCLR_CTS_Msk | UART_INTENCLR_RXTO_Msk | UART_INTENCLR_NCTS_Msk | UART_INTENCLR_ERROR_Msk;
  136. NRF_UART0->INTENSET = UART_INTENSET_RXDRDY_Enabled << UART_INTENSET_RXDRDY_Pos;
  137. NRF_UART0->PSELTXD = txd;
  138. NRF_UART0->PSELRXD = rxd;
  139. NRF_UART0->BAUDRATE = get_baud(baud);
  140. NRF_UART0->ENABLE |= UART_ENABLE_ENABLE_Enabled;
  141. NRF_UART0->TASKS_STARTTX = 0XFFFFFFFF;
  142. NRF_UART0->TASKS_STARTRX = 0XFFFFFFFF;
  143. NVIC_SetPriority(UARTE0_UART0_IRQn, UART0_IRQ_PRIORITY);
  144. NVIC_EnableIRQ(UARTE0_UART0_IRQn);
  145. NRF_UART0->EVENTS_TXDRDY = 0x0UL;
  146. }
  147. static void scan_report_cb(uint8_t *adv_data, uint16_t adv_data_len,int8_t rssi)
  148. {
  149. if(mFlash.selfcheck_flow == SELFCHECK_FLOW_TOOLING_BOARD)
  150. {
  151. uint8_t *device_name = ble_advdata_parse(adv_data,adv_data_len,BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME);
  152. if(!device_name)
  153. {
  154. device_name = ble_advdata_parse(adv_data,adv_data_len,BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME);
  155. }
  156. if(device_name)
  157. {
  158. char device_name_buff[128] = {0};
  159. uint16_t data_len = (adv_data + adv_data_len - device_name) / sizeof(uint8_t);
  160. memcpy(device_name_buff, device_name, data_len);
  161. //广播名匹配
  162. if(memcmp(device_name_buff,SELFCHECK_SCAN_DEVICE_NAME,strlen(SELFCHECK_SCAN_DEVICE_NAME)) == 0)
  163. {
  164. //筛选最大的RSSI
  165. ob_selfcheck.max_rssi = (ob_selfcheck.max_rssi > rssi)?ob_selfcheck.max_rssi : rssi;
  166. }
  167. }
  168. }
  169. else if(mFlash.selfcheck_flow == SELFCHECK_FLOW_COMPLETE_BOARD)
  170. {
  171. static uint32_t last_tim = 0;
  172. if(TIME_GetTicks()-last_tim >= 1000)
  173. {
  174. last_tim = TIME_GetTicks();
  175. ob_selfcheck.max_rssi = -120;
  176. }
  177. ob_selfcheck.max_rssi = (ob_selfcheck.max_rssi > rssi)?ob_selfcheck.max_rssi:rssi;
  178. }
  179. }
  180. static void fb_data_notify_cb(uint32_t dir_bit)
  181. {
  182. int data_len;
  183. if((dir_bit >> BLL_IMU_DIR_FRONT) & 0x01)
  184. {
  185. memset(&ob_selfcheck.f_data,0,sizeof(ob_selfcheck.f_data));
  186. data_len = bll_imu_get_data_num(BLL_IMU_DIR_FRONT);
  187. for(int i=0; i<data_len;i++)
  188. {
  189. bll_imu_get_data(BLL_IMU_DIR_FRONT, i, &ob_selfcheck.f_data);
  190. // DEBUG_LOG("front acc:%d,%d,%d; gry:%d,%d,%d; mag:%d,%d,%d; tp:%d diff:%d len:%d\n",f_data.acc[0],f_data.acc[1],f_data.acc[2], \
  191. // f_data.gry[0],f_data.gry[1],f_data.gry[2], \
  192. // f_data.mag[0],f_data.mag[1],f_data.mag[2], \
  193. // f_data.fifo_timestamp,f_data.fifo_timestamp - last_tp,data_len);
  194. }
  195. }
  196. if((dir_bit >> BLL_IMU_DIR_BACK) & 0x01)
  197. {
  198. memset(&ob_selfcheck.b_data,0,sizeof(ob_selfcheck.b_data));
  199. data_len = bll_imu_get_data_num(BLL_IMU_DIR_BACK);
  200. for(int i=0; i<data_len;i++)
  201. {
  202. bll_imu_get_data(BLL_IMU_DIR_BACK, i, &ob_selfcheck.b_data);
  203. // DEBUG_LOG("back mag:%d,%d,%d;\n",b_data.mag[0],b_data.mag[1],b_data.mag[2]);
  204. }
  205. }
  206. if(((dir_bit >> BLL_IMU_DIR_FRONT) & 0x01))
  207. {
  208. ob_selfcheck.f_is_read_data = true;
  209. }
  210. if((dir_bit >> BLL_IMU_DIR_BACK))
  211. {
  212. ob_selfcheck.b_is_read_data = true;
  213. }
  214. }
  215. static void selfcheck_flow_tooling_board_process(void)
  216. {
  217. int16_t rol;
  218. static uint32_t t_count = 0;
  219. //喂狗
  220. feed_watchdog();
  221. //-----读取中间传感器数据,检测加速度roll值
  222. if(drv_qma_get_acc_data(&ob_selfcheck.m_data) != 0)ob_selfcheck.selfcheck_result |= (1 << SELFCHECK_RESULT_ERR_MIDDLE_NO_DATA);
  223. Mahony_process(0,0,0,ob_selfcheck.m_data.acc[0],ob_selfcheck.m_data.acc[1],ob_selfcheck.m_data.acc[2],0,0,0);
  224. t_count++;
  225. switch(t_count)
  226. {
  227. case (2000/LowPower_Interval): //第2秒查看前后传感器是否配置且读取成功
  228. if(bll_imu_query_config_param_is_ready(BLL_IMU_DIR_FRONT,&game_bll_imu_param_t) != BLL_IMU_CONFIG_FINISH)ob_selfcheck.selfcheck_result |= (1 << SELFCHECK_RESULT_ERR_FRONT_SENSOR_CONFIG);
  229. if(bll_imu_query_config_param_is_ready(BLL_IMU_DIR_BACK,&game_bll_imu_param_t) != BLL_IMU_CONFIG_FINISH)ob_selfcheck.selfcheck_result |= (1 << SELFCHECK_RESULT_ERR_BACK_SENSOR_CONFIG);
  230. if(ob_selfcheck.f_is_read_data != true)ob_selfcheck.selfcheck_result |= (1 << SELFCHECK_RESULT_ERR_FRONT_NO_DATA);
  231. if(ob_selfcheck.b_is_read_data != true)ob_selfcheck.selfcheck_result |= (1 << SELFCHECK_RESULT_ERR_BACK_NO_DATA);
  232. break;
  233. case (4000/LowPower_Interval): //第4秒检测加速度roll值
  234. rol = (int16_t)(getRoll()*1);
  235. if(!(SELFCHECK_THRESHOLD_IS_MET(SELFCHECK_MIDDLE_ACC_ROLL_MIN_THRESHOLD,rol,SELFCHECK_MIDDLE_ACC_ROLL_MAX_THRESHOLD)))ob_selfcheck.selfcheck_result |= (1 << SELFCHECK_RESULT_ERR_MIDDLE_ACC_ROLL);
  236. break;
  237. case (10000/LowPower_Interval): //第10秒能否读取到任意广播名字,且最小的RSSI是否满足条件
  238. if(SELFCHECK_SCAN_DEVICE_RSSI_MIN_THRESHOLD >= ob_selfcheck.max_rssi)ob_selfcheck.selfcheck_result |= (1 << SELFCHECK_RESULT_ERR_RSSI);
  239. //若自检结果为通过,则将自检流程标志位改为“整体自检”,flash保存(先保存,再发送。不然发送完,还没保存就断电,导致没进入下个阶段就被拿去装鞋)
  240. if(ob_selfcheck.selfcheck_result == SELFCHECK_RESULT_SUCCESS)
  241. {
  242. mFlash.selfcheck_flow = SELFCHECK_FLOW_COMPLETE_BOARD;
  243. mBackup.selfcheck_flow = SELFCHECK_FLOW_COMPLETE_BOARD;
  244. if(Flash_SaveInfomation()!= ZONE_OP_SUCCESS)ob_selfcheck.selfcheck_result |= (1 << SELFCHECK_RESULT_ERR_FLASH_WRITE);
  245. if(Flash_SaveBackup() != ZONE_OP_SUCCESS)ob_selfcheck.selfcheck_result |= (1 << SELFCHECK_RESULT_ERR_FLASH_WRITE);
  246. }
  247. break;
  248. }
  249. //-----持续将自检结果发送给单片机3分钟,之后重启。(快速进入下一阶段,而不是等断电进入下一阶段,以防flash失败导致自检流程标志位异常)
  250. if(t_count > (10000/LowPower_Interval) && t_count < (15000/LowPower_Interval))
  251. {
  252. UART0_SendChar(ob_selfcheck.selfcheck_result);
  253. }
  254. else if(t_count > (15000/LowPower_Interval))
  255. {
  256. NVIC_SystemReset();
  257. }
  258. }
  259. static bool is_wear_insole(void)
  260. {
  261. uint16_t front_mag_norm = sqrt((double)(ob_selfcheck.f_data.mag[0]*ob_selfcheck.f_data.mag[0]) + (double)(ob_selfcheck.f_data.mag[1]*ob_selfcheck.f_data.mag[1]) + (double)(ob_selfcheck.f_data.mag[2]*ob_selfcheck.f_data.mag[2]));
  262. uint16_t back_mag_norm = sqrt((double)(ob_selfcheck.b_data.mag[0]*ob_selfcheck.b_data.mag[0]) + (double)(ob_selfcheck.b_data.mag[1]*ob_selfcheck.b_data.mag[1]) + (double)(ob_selfcheck.b_data.mag[2]*ob_selfcheck.b_data.mag[2]));
  263. return (SELFCHECK_THRESHOLD_IS_MET(SELFCHECK_WEAR_INSOLE_MAG_NORM_MIN_THRESHOLD,front_mag_norm,SELFCHECK_WEAR_INSOLE_MAG_NORM_MAX_THRESHOLD) && \
  264. SELFCHECK_THRESHOLD_IS_MET(SELFCHECK_WEAR_INSOLE_MAG_NORM_MIN_THRESHOLD,back_mag_norm,SELFCHECK_WEAR_INSOLE_MAG_NORM_MAX_THRESHOLD))?true:false;
  265. }
  266. static bool is_charge_chip_can_used(void)
  267. {
  268. #define SELFCHECK_BATTERY_VOL_THRESHOLD_MIN 2500 //2.5V
  269. #define SELFCHECK_BATTERY_VOL_THRESHOLD_MAX 4000 //4V
  270. #define SELFCHECK_CHARGE_VOL_THRESHOLD 80 //充电前和充电期间的充电电压变化值,单位mv
  271. //监测电池和充电数据
  272. int16_t bat_vol;
  273. int16_t charge_vol;
  274. int16_t charge_threshold;
  275. uint32_t ch = nrf_gpio_pin_read(PIN_CHARGING);
  276. static uint32_t charge_cycle = 20;
  277. static int16_t before_charge_vol; //充电前的电压值
  278. static int16_t charge_vol_max; //充电期间最大的电压值
  279. bool ret = true;
  280. if(!ch)//没充电
  281. {
  282. charge_vol = ADC_RESULT_IN_MILLI_VOLTS(ADC_GetValue(PIN_ADC_CHARGMEASURE_CHANNEL));
  283. before_charge_vol = before_charge_vol > charge_vol ? charge_vol : before_charge_vol;
  284. charge_vol_max = 0;
  285. charge_cycle = 20;
  286. }
  287. else //充电
  288. {
  289. /* 过筛20轮 */
  290. if(charge_cycle != 0){
  291. charge_vol = ADC_RESULT_IN_MILLI_VOLTS(ADC_GetValue(PIN_ADC_CHARGMEASURE_CHANNEL));
  292. charge_vol_max = charge_vol_max < charge_vol ? charge_vol : charge_vol_max;
  293. charge_cycle--;
  294. return ret;
  295. }
  296. charge_vol = ADC_RESULT_IN_MILLI_VOLTS(ADC_GetValue(PIN_ADC_CHARGMEASURE_CHANNEL));
  297. charge_vol_max = charge_vol_max < charge_vol ? charge_vol : charge_vol_max;
  298. bat_vol = ADC_RESULT_IN_MILLI_VOLTS(ADC_GetValue(PIN_ADC_BAT_CHANNEL))*5/3;
  299. //当电池电量没满,充电(经测试,电量没满的充电电压跟电池电压有关,最小充电电压100+mv)
  300. charge_threshold = charge_vol_max - before_charge_vol; //充电前和充电期间的充电电压变化值
  301. if(charge_threshold < SELFCHECK_CHARGE_VOL_THRESHOLD && bat_vol < SELFCHECK_BATTERY_VOL_THRESHOLD_MAX)
  302. {
  303. ret = false;
  304. }
  305. }
  306. return ret;
  307. }
  308. static void selfcheck_flow_complete_board_process_2(void)
  309. {
  310. uint8_t buf[256];
  311. uint8_t L=0;
  312. static uint32_t t_count = 0;
  313. uint32_t t_threshold = (3000/LowPower_Interval);
  314. static uint8_t led_control = 0;
  315. static uint8_t wdt_count = 2;
  316. //喂狗
  317. feed_watchdog();
  318. if(t_count != t_threshold)t_count++;
  319. //-----计算中间传感器的roll值
  320. drv_qma_get_acc_data(&ob_selfcheck.m_data);
  321. Mahony_process(0,0,0,ob_selfcheck.m_data.acc[0],ob_selfcheck.m_data.acc[1],ob_selfcheck.m_data.acc[2],0,0,0);
  322. //-----当电量未满4.0V时,充电芯片的充电电压是否超过阈值,若未超过,证明充电芯片异常,设置对应的失败灯
  323. if(is_charge_chip_can_used() == false)ob_selfcheck.selfcheck_result_led_color = COLOR_BLUE;
  324. if(t_count == t_threshold)
  325. {
  326. //-----上报中间传感器的加速度值和roll值
  327. L=0;
  328. int16_t rol = (int16_t)(getRoll()*100);
  329. //-----roll值若有异常,则设置对应的失败灯。
  330. if(!(SELFCHECK_THRESHOLD_IS_MET(SELFCHECK_MIDDLE_ACC_ROLL_MIN_THRESHOLD,(rol/100),SELFCHECK_MIDDLE_ACC_ROLL_MAX_THRESHOLD)))ob_selfcheck.selfcheck_result_led_color = COLOR_LIGHPURPLE;
  331. int16_t pitch = (int16_t)(getPitch()*100);
  332. int16_t yaw = (int16_t)(getYaw()*100);
  333. buf[L++] = (uint8_t)(rol>>8);
  334. buf[L++] = (uint8_t)(rol>>0);
  335. buf[L++] = (uint8_t)(pitch>>8);
  336. buf[L++] = (uint8_t)(pitch>>0);
  337. buf[L++] = (uint8_t)(yaw>>8);
  338. buf[L++] = (uint8_t)(yaw>>0);
  339. buf[L++] = 0;
  340. buf[L++] = 0;
  341. buf[L++] = 0;
  342. buf[L++] = 0;
  343. buf[L++] = 0;
  344. buf[L++] = 0;
  345. buf[L++] = 0;
  346. Mahony_send_ANO(0x01,buf,L);
  347. L=0;
  348. int32_t middle_acc_x = ob_selfcheck.m_data.acc[0];
  349. int32_t middle_acc_y = ob_selfcheck.m_data.acc[1];
  350. int16_t middle_acc_z = ob_selfcheck.m_data.acc[2];
  351. middle_acc_x *= 100;
  352. middle_acc_y *= 100;
  353. middle_acc_z *= 10;
  354. buf[L++] = (uint8_t)(middle_acc_x>>24);
  355. buf[L++] = (uint8_t)(middle_acc_x>>16);
  356. buf[L++] = (uint8_t)(middle_acc_x>>8);
  357. buf[L++] = (uint8_t)(middle_acc_x>>0);
  358. buf[L++] = (uint8_t)(middle_acc_y>>24);
  359. buf[L++] = (uint8_t)(middle_acc_y>>16);
  360. buf[L++] = (uint8_t)(middle_acc_y>>8);
  361. buf[L++] = (uint8_t)(middle_acc_y>>0);
  362. buf[L++] = (uint8_t)(middle_acc_z>>8);
  363. buf[L++] = (uint8_t)(middle_acc_z>>0);
  364. Mahony_send_ANO(0x07,buf,L);
  365. //-----上报前脚传感器的加速度数据、陀螺仪数据、地磁计开平方和数据
  366. //-----上报后脚传感器的地磁计开平方和数据
  367. //-----上报扫描到的任意广播的rssi值
  368. L=0;
  369. buf[L++] = (uint8_t)(ob_selfcheck.f_data.acc[0]>>8);
  370. buf[L++] = (uint8_t)(ob_selfcheck.f_data.acc[0]>>0);
  371. buf[L++] = (uint8_t)(ob_selfcheck.f_data.acc[1]>>8);
  372. buf[L++] = (uint8_t)(ob_selfcheck.f_data.acc[1]>>0);
  373. buf[L++] = (uint8_t)(ob_selfcheck.f_data.acc[2]>>8);
  374. buf[L++] = (uint8_t)(ob_selfcheck.f_data.acc[2]>>0);
  375. buf[L++] = (uint8_t)(ob_selfcheck.f_data.gry[0]>>8);
  376. buf[L++] = (uint8_t)(ob_selfcheck.f_data.gry[0]>>0);
  377. buf[L++] = (uint8_t)(ob_selfcheck.f_data.gry[1]>>8);
  378. buf[L++] = (uint8_t)(ob_selfcheck.f_data.gry[1]>>0);
  379. buf[L++] = (uint8_t)(ob_selfcheck.f_data.gry[2]>>8);
  380. buf[L++] = (uint8_t)(ob_selfcheck.f_data.gry[2]>>0);
  381. uint16_t front_mag_norm = sqrt((double)(ob_selfcheck.f_data.mag[0]*ob_selfcheck.f_data.mag[0]) + (double)(ob_selfcheck.f_data.mag[1]*ob_selfcheck.f_data.mag[1]) + (double)(ob_selfcheck.f_data.mag[2]*ob_selfcheck.f_data.mag[2]));
  382. uint16_t back_mag_norm = sqrt((double)(ob_selfcheck.b_data.mag[0]*ob_selfcheck.b_data.mag[0]) + (double)(ob_selfcheck.b_data.mag[1]*ob_selfcheck.b_data.mag[1]) + (double)(ob_selfcheck.b_data.mag[2]*ob_selfcheck.b_data.mag[2]));
  383. buf[L++] = (uint8_t)(front_mag_norm>>8);
  384. buf[L++] = (uint8_t)(front_mag_norm>>0);
  385. buf[L++] = (uint8_t)(back_mag_norm>>8);
  386. buf[L++] = (uint8_t)(back_mag_norm>>0);
  387. buf[L++] = (uint8_t)(ob_selfcheck.max_rssi>> 8);
  388. buf[L++] = (uint8_t)(ob_selfcheck.max_rssi>>0);
  389. Mahony_send_ANO(0x02,buf,L);
  390. //-----第1个100毫秒亮灯,连续9个100毫秒灭灯
  391. led_control++;
  392. if(led_control == 1)
  393. {
  394. nrf_gpio_pin_write(PIN_LED_ENABLE,LED_ENABLE);
  395. Pwm_Initialize();
  396. nrf_delay_ms(5);
  397. WS2812_DisplayDot(ob_selfcheck.selfcheck_result_led_color);
  398. WS2812_Pwm_Play();
  399. }
  400. else
  401. {
  402. nrf_gpio_pin_write(PIN_LED_ENABLE,LED_DISABLE);
  403. Pwm_UnInitialize();
  404. }
  405. if(led_control == 10)led_control = 0;
  406. //-----检测到充电,震动200ms一次。
  407. if(nrf_gpio_pin_read(PIN_CHARGING))
  408. {
  409. if(wdt_count){nrf_gpio_cfg_output(PIN_MT_EN);nrf_gpio_pin_write(PIN_MT_EN,1);wdt_count--;}
  410. else nrf_gpio_pin_write(PIN_MT_EN,0);
  411. }
  412. else
  413. {
  414. wdt_count = 2;
  415. }
  416. }
  417. }
  418. static void selfcheck_flow_complete_board_process_1(void)
  419. {
  420. int ret = -1;
  421. BLL_IMU_CONFIG_RESULT config_result;
  422. //喂狗
  423. feed_watchdog();
  424. config_result = bll_imu_query_config_param_is_ready(BLL_IMU_DIR_FRONT,&game_bll_imu_param_t);
  425. //-----判断前后脚IMU配置是否成功,若成功,进行下一步判断;若失败,设置对应的失败灯,且重新配置前后脚。
  426. if(config_result != BLL_IMU_CONFIG_FINISH)
  427. {
  428. if(config_result == BLL_IMU_CONFIG_FAIL_FRONT_MAG)ob_selfcheck.selfcheck_result_led_color = COLOR_LIGHRED;//前脚mag配置失败
  429. if(config_result == BLL_IMU_CONFIG_FAIL_BACK_MAG)ob_selfcheck.selfcheck_result_led_color = COLOR_WHITE;//后脚mag配置失败
  430. if(config_result == BLL_IMU_CONFIG_FAIL_FRONT_SIX_AXIS)ob_selfcheck.selfcheck_result_led_color = COLOR_RED;//前脚lsm配置失败
  431. //重新配置
  432. bll_imu_close();
  433. bll_imu_Init();
  434. bll_imu_register_data_notify_callback(BLL_IMU_DATA_NOTIFY_CB_PRIORITY_1, fb_data_notify_cb);
  435. bll_imu_Resume_config_param(&game_bll_imu_param_t);
  436. return;
  437. }
  438. //-----判断是否正常读取前脚IMU数据,若成功,进行下一步判断,若失败,设置对应的失败灯,且重新配置前后脚。
  439. if(ob_selfcheck.f_is_read_data == false)
  440. {
  441. ob_selfcheck.selfcheck_result_led_color = COLOR_CYAN;
  442. //重新配置
  443. bll_imu_close();
  444. bll_imu_Init();
  445. bll_imu_register_data_notify_callback(BLL_IMU_DATA_NOTIFY_CB_PRIORITY_1, fb_data_notify_cb);
  446. bll_imu_Resume_config_param(&game_bll_imu_param_t);
  447. return;
  448. }
  449. else
  450. {
  451. ob_selfcheck.f_is_read_data = false;
  452. }
  453. //-----判断是否正常读取后脚IMU数据,若成功,进行下一步判断,若失败,设置对应的失败灯,且重新配置前后脚。
  454. if(ob_selfcheck.b_is_read_data == false)
  455. {
  456. ob_selfcheck.selfcheck_result_led_color = COLOR_YELLOW;
  457. //重新配置
  458. bll_imu_close();
  459. bll_imu_Init();
  460. bll_imu_register_data_notify_callback(BLL_IMU_DATA_NOTIFY_CB_PRIORITY_1, fb_data_notify_cb);
  461. bll_imu_Resume_config_param(&game_bll_imu_param_t);
  462. return;
  463. }
  464. else
  465. {
  466. ob_selfcheck.b_is_read_data = false;
  467. }
  468. //-----判断是否正常读取中间IMU数据,若成功,进行下一步判断,若失败,设置对应的失败灯,且重新配置中间IMU。
  469. memset(&ob_selfcheck.m_data,0,sizeof(ob_selfcheck.m_data));
  470. ret = drv_qma_get_acc_data(&ob_selfcheck.m_data);
  471. if(ret != 0)
  472. {
  473. ob_selfcheck.selfcheck_result_led_color = COLOR_PURPLE;
  474. //重新配置
  475. drv_qma_Init();
  476. nrf_delay_ms(20);
  477. drv_qma_set_acc_odr(QMA_ACC_ODR_104HZ);
  478. return;
  479. }
  480. //-----上述自检项目都通过,则判断当前是否充电,充电则设置橙灯,否则设置绿灯。
  481. if(nrf_gpio_pin_read(PIN_CHARGING))
  482. {
  483. ob_selfcheck.selfcheck_result_led_color = COLOR_PURPLE;
  484. }
  485. else
  486. {
  487. ob_selfcheck.selfcheck_result_led_color = COLOR_GREEN;
  488. }
  489. //-----根据前后脚地磁数据读取成功情况下,若判断为穿鞋垫,则将自检流程标志位改为“自检完成”,flash保存,重启。(避免到用户手上时,亮灯)
  490. if(is_wear_insole())
  491. {
  492. mFlash.selfcheck_flow = SELFCHECK_FLOW_DONE;
  493. mBackup.selfcheck_flow = SELFCHECK_FLOW_DONE;
  494. if(Flash_SaveInfomation()!= ZONE_OP_SUCCESS)
  495. {
  496. while(1)
  497. {
  498. //喂狗
  499. feed_watchdog();
  500. //打印错误信息
  501. DEBUG_LOG("selfcheck:Flash_SaveInfomation()!= ZONE_OP_SUCCESS\r\n");
  502. //除了配对信息等基础信息外,擦除整个区块,然后重新保存,保存成功,break,否则延时100毫秒
  503. Flash_DeleteAllInfor();
  504. if(mBackup.head == FLASH_HEAD)
  505. {
  506. uint8_t i =0;
  507. for(i=0;i<RecordMacAddrL;i++){
  508. mFlash.macHost[i] = mBackup.macAddr_L[i]; //主机地址
  509. mFlash.mClient.macAddr[i] = mBackup.macAddr_R[i];//从机地址
  510. }
  511. mFlash.mClient.hardVersion = mBackup.hardVersion;
  512. mFlash.mClient.sotfVersion = mBackup.sotfVersion;
  513. mFlash.mClient.isConfig = mBackup.isConfig;
  514. mFlash.isHost = mBackup.isHost;
  515. mFlash.LR_FLAG = mBackup.LR_FLAG;
  516. mFlash.selfcheck_flow = mBackup.selfcheck_flow;
  517. }
  518. if(Flash_SaveInfomation()== ZONE_OP_SUCCESS)break;else nrf_delay_ms(100);
  519. }
  520. }
  521. if(Flash_SaveBackup() != ZONE_OP_SUCCESS)
  522. {
  523. while(1)
  524. {
  525. //喂狗
  526. feed_watchdog();
  527. //打印错误信息
  528. DEBUG_LOG("selfcheck:Flash_SaveBackup()!= ZONE_OP_SUCCESS\r\n");
  529. //除了配对信息等基础信息外,擦除整个区块,然后重新保存,保存成功,break,否则延时100毫秒
  530. Flash_DeleteAllBackup();
  531. if(mFlash.head == FLASH_HEAD)
  532. {
  533. uint8_t i =0;
  534. for(i=0;i<RecordMacAddrL;i++){
  535. mBackup.macAddr_L[i] = mFlash.macHost[i]; //主机地址
  536. mBackup.macAddr_R[i] = mFlash.mClient.macAddr[i];//从机地址
  537. }
  538. mBackup.hardVersion = mFlash.mClient.hardVersion;
  539. mBackup.sotfVersion = mFlash.mClient.sotfVersion;
  540. mBackup.isConfig = mFlash.mClient.isConfig;
  541. mBackup.isHost = mFlash.isHost;
  542. mBackup.LR_FLAG = mFlash.LR_FLAG;
  543. mBackup.selfcheck_flow = mFlash.selfcheck_flow;
  544. }
  545. if(Flash_SaveBackup()== ZONE_OP_SUCCESS)break;else nrf_delay_ms(100);
  546. }
  547. }
  548. NVIC_SystemReset();
  549. }
  550. //-----完整板自检线程2
  551. Process_Start(SELFCHECK_FLOW_COMPLETE_BOARD_PROCESS_2_CYCLE,"selfcheck_flow_complete_board_process_2",selfcheck_flow_complete_board_process_2);
  552. }
  553. /*API ------------------------------------------------------------------------------------------------------------------------------------*/
  554. /**
  555. @brief 初始化自检
  556. @param 无
  557. @return 当前的自检流程
  558. */
  559. SELFCHECK_FLOW_e selfcheck_Init(void)
  560. {
  561. int error;
  562. int16_t adc_value;
  563. SELFCHECK_FLOW_e ret;
  564. //初始化结构体
  565. memset(&ob_selfcheck,0,sizeof(ob_selfcheck));
  566. ob_selfcheck.max_rssi = SELFCHECK_SCAN_DEVICE_RSSI_MIN_THRESHOLD;
  567. ob_selfcheck.selfcheck_result = SELFCHECK_RESULT_SUCCESS;
  568. ob_selfcheck.selfcheck_result_led_color = COLOR_BLACK;
  569. ob_selfcheck.f_is_read_data = false;
  570. ob_selfcheck.b_is_read_data = false;
  571. //读取flash的自检流程标志位,判断当前自检流程
  572. switch(mFlash.selfcheck_flow)
  573. {
  574. case SELFCHECK_FLOW_DONE: //自检完成
  575. //-----保留该case,以防后期需要在此添加需求。
  576. //-----自检流程标志位只有该应用可更改,其余应用不可更改。
  577. ret = SELFCHECK_FLOW_DONE;
  578. break;
  579. case SELFCHECK_FLOW_COMPLETE_BOARD: //完整板自检
  580. //-----震动电机200ms
  581. nrf_gpio_cfg_output(PIN_MT_EN);
  582. nrf_gpio_pin_write(PIN_MT_EN,1);
  583. nrf_delay_ms(200);
  584. nrf_gpio_pin_write(PIN_MT_EN,0);
  585. //-----开启扫描,上报扫描到的任意广播的rssi值
  586. ST_scan_stop();
  587. error = ST_scan_start();
  588. if(error != APP_SUCCESS)ob_selfcheck.selfcheck_result |= (1 << SELFCHECK_RESULT_ERR_ADV_INIT);
  589. advdata_report_Evt_Regist(scan_report_cb);
  590. //-----初始化LED灯
  591. LED_Init();
  592. //-----初始化前中后传感器
  593. bll_imu_Init();
  594. bll_imu_register_data_notify_callback(BLL_IMU_DATA_NOTIFY_CB_PRIORITY_1, fb_data_notify_cb);
  595. bll_imu_Resume_config_param(&game_bll_imu_param_t);
  596. error = drv_qma_Init();
  597. if(error == -1)ob_selfcheck.selfcheck_result |= (1 << SELFCHECK_RESULT_ERR_MIDDLE_SENSOR_CONFIG);
  598. nrf_delay_ms(20);
  599. error = drv_qma_set_acc_odr(QMA_ACC_ODR_104HZ);
  600. if(error == -1)ob_selfcheck.selfcheck_result |= (1 << SELFCHECK_RESULT_ERR_MIDDLE_SENSOR_CONFIG);
  601. //-----初始化计算roll值算法
  602. Mahony_Init(10);
  603. //-----完整板自检线程1
  604. Process_Start(SELFCHECK_FLOW_COMPLETE_BOARD_PROCESS_1_CYCLE,"selfcheck_flow_complete_board_process_1",selfcheck_flow_complete_board_process_1);
  605. ret = SELFCHECK_FLOW_COMPLETE_BOARD;
  606. break;
  607. case SELFCHECK_FLOW_TOOLING_BOARD: //工装板自检
  608. default:
  609. //-----将LGB_DATA引脚配置成串口发送
  610. UART0_Init(PIN_LED_CONTROL,0xFF,115200);
  611. //-----开启扫描,10秒内能否读取到任意广播名字,且最小的RSSI是否满足条件
  612. ST_scan_stop();
  613. error = ST_scan_start();
  614. if(error != APP_SUCCESS)ob_selfcheck.selfcheck_result |= (1 << SELFCHECK_RESULT_ERR_ADV_INIT);
  615. advdata_report_Evt_Regist(scan_report_cb);
  616. //-----打开LED电源输出
  617. nrf_gpio_cfg(
  618. PIN_LED_ENABLE,
  619. NRF_GPIO_PIN_DIR_OUTPUT,
  620. NRF_GPIO_PIN_INPUT_DISCONNECT,
  621. NRF_GPIO_PIN_NOPULL,
  622. NRF_GPIO_PIN_S0D1,
  623. NRF_GPIO_PIN_NOSENSE);
  624. nrf_gpio_pin_write(PIN_LED_ENABLE,SELFCHECK_LED_ENABLE);
  625. //-----电机引脚置高
  626. nrf_gpio_cfg_output(PIN_MT_EN); nrf_gpio_pin_write(PIN_MT_EN,1);
  627. //-----读取配对引脚的ADC值是否满足条件
  628. ADC_Disable();
  629. ADC_SetPinChannel(PIN_CHARGING, PIN_CHARGING_CHANNEL, NRF_GPIO_PIN_NOPULL);
  630. ADC_Initialize();
  631. error = ADC_Read(PIN_CHARGING_CHANNEL, &adc_value);
  632. if(error != ADC_OP_SUCCESS)ob_selfcheck.selfcheck_result |= (1 << SELFCHECK_RESULT_ERR_READ_ADC);
  633. else if(!(SELFCHECK_THRESHOLD_IS_MET(SELFCHECK_PAIR_PIN_ADC_MIN_THRESHOLD,adc_value,SELFCHECK_PAIR_PIN_ADC_MAX_THRESHOLD))){
  634. ob_selfcheck.selfcheck_result |= (1 << SELFCHECK_RESULT_ERR_PAIR_PIN_ADC);
  635. }
  636. //-----电池用电阻代替,读取ADC,测试充电芯片是否正常
  637. error = ADC_Read(PIN_ADC_CHARGMEASURE_CHANNEL, &adc_value);
  638. if(error != ADC_OP_SUCCESS)ob_selfcheck.selfcheck_result |= (1 << SELFCHECK_RESULT_ERR_READ_ADC);
  639. else if(!(SELFCHECK_THRESHOLD_IS_MET(SELFCHECK_CHARGE_CHIP_PIN_ADC_MIN_THRESHOLD,adc_value,SELFCHECK_CHARGE_CHIP_PIN_ADC_MAX_THRESHOLD))){
  640. ob_selfcheck.selfcheck_result |= (1 << SELFCHECK_RESULT_ERR_CHARGE_CHIP_PIN_ADC);
  641. }
  642. //-----电池用电阻代替,读取ADC,测试电池分压电阻是否正常
  643. error = ADC_Read(PIN_ADC_BAT_CHANNEL, &adc_value);
  644. if(error != ADC_OP_SUCCESS)ob_selfcheck.selfcheck_result |= (1 << SELFCHECK_RESULT_ERR_READ_ADC);
  645. else if(!(SELFCHECK_THRESHOLD_IS_MET(SELFCHECK_BATTERY_PIN_ADC_MIN_THRESHOLD,adc_value,SELFCHECK_BATTERY_PIN_ADC_MAX_THRESHOLD))){
  646. ob_selfcheck.selfcheck_result |= (1 << SELFCHECK_RESULT_ERR_BATTERY_PIN_ADC);
  647. }
  648. //-----配置前脚传感器、中间传感器、后脚传感器
  649. bll_imu_Init();
  650. bll_imu_register_data_notify_callback(BLL_IMU_DATA_NOTIFY_CB_PRIORITY_1, fb_data_notify_cb);
  651. bll_imu_Resume_config_param(&game_bll_imu_param_t);
  652. error = drv_qma_Init();
  653. if(error == -1)ob_selfcheck.selfcheck_result |= (1 << SELFCHECK_RESULT_ERR_MIDDLE_SENSOR_CONFIG);
  654. nrf_delay_ms(20);
  655. error = drv_qma_set_acc_odr(QMA_ACC_ODR_104HZ);
  656. if(error == -1)ob_selfcheck.selfcheck_result |= (1 << SELFCHECK_RESULT_ERR_MIDDLE_SENSOR_CONFIG);
  657. //-----初始化计算roll值算法
  658. Mahony_Init(10);
  659. //-----工装自检线程
  660. Process_Start(SELFCHECK_FLOW_TOOLING_BOARD_PROCESS_CYCLE,"selfcheck_flow_tooling_board_process",selfcheck_flow_tooling_board_process);
  661. ret = SELFCHECK_FLOW_TOOLING_BOARD;
  662. break;
  663. }
  664. //-----设置为低功耗休眠
  665. Sleep_Duration_Control_Regist(sleep_duration_control_low_power_interval);
  666. //开启看门狗
  667. watchdog_init();
  668. feed_watchdog();
  669. return ret;
  670. }