global.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. /* includes ----------------------------------------------------------*/
  2. #include "global.h"
  3. /* typedef -----------------------------------------------------------*/
  4. /* define ------------------------------------------------------------*/
  5. /* macro -------------------------------------------------------------*/
  6. /* variables ---------------------------------------------------------*/
  7. global_par s_global_par;
  8. /* function prototypes -----------------------------------------------*/
  9. /**
  10. * @brief 绑定车辆比对
  11. * @param NONE
  12. * @note NONE
  13. * @retval 绑定车辆比对,查看车辆VIN是否相同,若相同则不做处理,更换车辆则备份新的车辆数据
  14. */
  15. void VehicleCompare(void){
  16. param_boot *p_param_boot = &s_param_boot;
  17. rs485RecDate *p_rs485RecDate = &s_rs485RecDate;
  18. global_par *p_global_par = &s_global_par;
  19. if(s_comData.vinRecSuccess == 1) { // 成功获取到车辆数据
  20. // 检查指针是否有效
  21. if(p_param_boot != NULL && p_rs485RecDate != NULL && p_global_par != NULL) {
  22. // 只有在VIN码不同时才执行更新操作
  23. if(memcmp(p_param_boot->vin, p_rs485RecDate->VIN, 26) != 0) { // 比对不成功
  24. // 备份新的VIN码
  25. memcpy(p_param_boot->vin, p_rs485RecDate->VIN, 26);
  26. // 备份新的车辆数据
  27. p_param_boot->carTotalMileage = ((uint32_t)s_rs485RecDate.accTotalMileage_h << 16) | s_rs485RecDate.accTotalMileage_l;
  28. // 写入参数区
  29. Write_paramArea();
  30. // 置位中控板迁移事件
  31. BIT_SET(p_global_par->ctrEvent, CtrlPanelMigration);
  32. // 更新围栏数据
  33. p_global_par->fence_update = 1;
  34. }
  35. }
  36. }
  37. }
  38. /**
  39. * @brief 中控板初始化
  40. * @param p_param_boot : 参数区指针
  41. * @param p_rs485RecDate:485接收数据区的指针
  42. * @note NONE
  43. * @retval 无
  44. */
  45. void centralCtrSys_Init(param_boot *p_param_boot){
  46. uint8_t recBack = 0;
  47. rs485RecDate *p_rs485RecDate = &s_rs485RecDate;
  48. // 1. 从flash中读出存储参数
  49. Read_ParamArea(); // 读出参数区的所有数据
  50. // 3. 从备份数据中拿出初始VIN
  51. memcpy(p_rs485RecDate->VIN, p_param_boot->vin, 26);
  52. s_comData.vinRecSuccess = 1;
  53. // 4. 初始化4g模块 4g模块在这里不好处理 放在任务中,围栏数据也一样
  54. // 5. 读取96位(或者说是3个32位的字)的唯一ID
  55. GetUniqueID(s_messageDate.devId);
  56. // 6. 陀螺仪的初始化
  57. recBack = atk_ms6050_init();
  58. if(recBack != 0){
  59. // printf("ATK-MS6050 init failed!\r\n");
  60. BIT_SET(s_comData.Malfunction, gyroscope); // 置位陀螺仪数据异常故障
  61. }
  62. // printf("ATK-MS6050 init\r\n");
  63. recBack = atk_ms6050_dmp_init();
  64. if(recBack != 0){
  65. // printf("ATK-MS6050 DMP init failed!\r\n");
  66. BIT_SET(s_comData.Malfunction, gyroscope); // 置位陀螺仪数据异常故障
  67. }
  68. // printf("ATK-MS6050 DMP init!\r\n");
  69. // 7. 外部flash初始化
  70. norflash_init();
  71. }
  72. // 车本体故障判断
  73. void fault_car(rs485RecDate *p_rs485RecDate, comData *p_comData){
  74. uint16_t errorLevel = 0;
  75. /* 尝试获取互斥量,等待无限长时间 */
  76. if(osMutexAcquire(mutex_rs485RecDateHandle, 1000) == osOK)
  77. {
  78. errorLevel = p_rs485RecDate->alarmLevel;
  79. /* 访问完成,释放互斥量 */
  80. osMutexRelease(mutex_rs485RecDateHandle);
  81. }
  82. // 存在车故障
  83. if(errorLevel != 0){
  84. BIT_SET(s_comData.Malfunction, carError); // 置位车故障
  85. }else{
  86. BIT_CLEAR(s_comData.Malfunction, carError); // 清除车故障
  87. }
  88. }
  89. /**
  90. * @brief 中控板故障检测
  91. * @param p_global_par:global_par的全局参数指针
  92. * @note 周期为1s1次 清除除电池故障的其他故障
  93. * @retval 无
  94. */
  95. void faultDetection(global_par *p_global_par){
  96. // 参数定义
  97. static uint16_t timesCnt_gps = 0; // gps记时
  98. static uint8_t errorCnt_gyro = 0; // 陀螺仪数据故障滤波次数
  99. static uint16_t timesOut_ota = 0; // OTA超时计数
  100. static uint16_t timesCnt_runFence; // 超运行围栏计数
  101. static uint16_t timesCnt_outSpeed; // 超速计时器
  102. comData *p_comData = &s_comData;
  103. param_boot *p_param_boot = &s_param_boot;
  104. // 开启超级权限 不判断所有故障
  105. if(p_global_par->superUser == 1){
  106. p_comData->Malfunction = 0; // 清除所有故障
  107. return;
  108. }
  109. // 1. 车本体故障判断
  110. fault_car(&s_rs485RecDate, &s_comData); // 车故障判断
  111. // 2. 超出围栏故障判断
  112. if(p_comData->fenceStatus == 1){
  113. if(timesCnt_runFence < p_param_boot->fenceBreach_Timeout){
  114. timesCnt_runFence++;
  115. }else{
  116. timesCnt_runFence = p_param_boot->fenceBreach_Timeout;
  117. BIT_SET(s_comData.Malfunction, fence);
  118. }
  119. }else{
  120. timesCnt_runFence = 0;
  121. BIT_CLEAR(s_comData.Malfunction, fence);
  122. }
  123. // 3. GPS信号丢失
  124. // 获取gps失败,但陀螺仪数据正常的情况下,一分钟之后置位gps故障
  125. // 获取gps失败,陀螺仪数据异常,直接置位gps故障
  126. if((p_global_par->positionErrorCnt >= 3) && (BIT_CHECK(s_comData.Malfunction, fence) == 0)){
  127. if(timesCnt_gps < FILTER_TIME_GPS){ // 4分钟滤波时间
  128. timesCnt_gps++;
  129. }else{
  130. timesCnt_gps = FILTER_TIME_GPS;
  131. BIT_SET(s_comData.Malfunction, positionError);
  132. }
  133. }else if((p_global_par->positionErrorCnt >= 3) && (BIT_CHECK(s_comData.Malfunction, fence) == 1)){
  134. timesCnt_gps = 0;
  135. BIT_SET(s_comData.Malfunction, positionError);
  136. }else{
  137. timesCnt_gps = 0;
  138. }
  139. if(p_global_par->positionErrorCnt == 0){ // 清除gps故障
  140. BIT_CLEAR(s_comData.Malfunction, positionError);
  141. }
  142. // 4. MQTT通信异常
  143. if(p_global_par->mqttTimeoutCnt >= PUBLISH_TIME_MS){
  144. BIT_SET(s_comData.Malfunction, errorMqtt); // 置位MQTT故障
  145. }
  146. if(p_global_par->mqttTimeoutCnt == 0){ // 清除MQTT故障
  147. BIT_CLEAR(s_comData.Malfunction, errorMqtt);
  148. }
  149. // 5. 4G模块初始化故障
  150. if(p_global_par->InitFaultFlag_4G == 1){
  151. BIT_SET(s_comData.Malfunction, init_4G_error); // 置位4g模块初始化故障
  152. }else{
  153. BIT_CLEAR(s_comData.Malfunction, init_4G_error); // 清除4g模块初始化故障
  154. }
  155. // 6. 485通信故障
  156. if(p_global_par->timeoutCnt_485 >= TIMEOUT_485){
  157. BIT_SET(s_comData.Malfunction, com485); // 置位485通信故障
  158. }
  159. if(p_global_par->timeoutCnt_485 == 0){
  160. BIT_CLEAR(s_comData.Malfunction, com485); // 置位485通信故障
  161. }
  162. // 7. 陀螺仪数据故障-- 获取的姿态角数据全部为0
  163. if(p_global_par->gyroDataFaultFlag == 1){
  164. if(errorCnt_gyro < FILTER_TIME_gyro){
  165. errorCnt_gyro++;
  166. }else{
  167. errorCnt_gyro = FILTER_TIME_gyro;
  168. BIT_SET(s_comData.Malfunction, gyroscope); // 置位陀螺仪数据异常故障
  169. }
  170. }else{
  171. errorCnt_gyro = 0;
  172. BIT_CLEAR(s_comData.Malfunction, gyroscope);
  173. }
  174. // 8. 超速故障
  175. if(s_rs485RecDate.vehicleSpeed > s_param_boot.speed_limit){
  176. if(timesCnt_outSpeed < s_param_boot.overspeed_Timeout){
  177. timesCnt_outSpeed++;
  178. }else{
  179. timesCnt_outSpeed = s_param_boot.overspeed_Timeout;
  180. BIT_SET(s_comData.Malfunction, outSpeed); // 置位超速故障
  181. }
  182. }else{
  183. timesCnt_outSpeed = 0;
  184. BIT_CLEAR(s_comData.Malfunction, outSpeed); // 清零超速故障
  185. }
  186. // 9. 升级故障--开始升级后,开始记时,2分钟还未升级成功的话,置位升级故障,
  187. // 退出升级,此次升级失败,旧版本运行,清除升级状态变量、标志、数据,重启释放
  188. // OTA开始后任务周期为200ms
  189. if(p_global_par->otaUpgradeStartFlag == 1){
  190. if(timesOut_ota < TIME_OUT_OTA){
  191. timesOut_ota++;
  192. }else{
  193. timesOut_ota = TIME_OUT_OTA;
  194. BIT_SET(s_comData.Malfunction, OTA_fault); // 置位OTA异常故障
  195. }
  196. }
  197. // 10. 订阅主题失败
  198. if(p_global_par->subscribe_fail == 1){
  199. BIT_SET(s_comData.Malfunction, subscribeFail); // 置位订阅主题失败故障
  200. }else{
  201. BIT_CLEAR(s_comData.Malfunction, subscribeFail); // 清除订阅主题失败故障
  202. }
  203. // 11. 发布消息失败
  204. if((p_global_par->publish_fail == 1) || (s_global_par.reconnect_server_flag == 1)){
  205. BIT_SET(s_comData.Malfunction, publishFail); // 置位发布消息失败故障
  206. }else{
  207. BIT_CLEAR(s_comData.Malfunction, publishFail); // 清除发布消息失败故障
  208. }
  209. // 12. 获取定位信息失败
  210. if(p_global_par->get_location_error == 1){
  211. BIT_SET(s_comData.Malfunction, getLocationError); // 置位获取定位信息失败故障
  212. }else{
  213. BIT_CLEAR(s_comData.Malfunction, getLocationError); // 清除获取定位信息失败故障
  214. }
  215. }
  216. /**
  217. * @brief 控制蜂鸣器响停
  218. * @param count 当前计数
  219. * @param on_threshold 响的阈值
  220. * @param off_threshold 停的阈值
  221. * @retval 无
  222. */
  223. void beep_control(uint8_t count, uint8_t on_threshold, uint8_t off_threshold) {
  224. if (count < on_threshold) {
  225. GPIO_BEEP(GPIO_PIN_SET);
  226. } else if (count < off_threshold) {
  227. GPIO_BEEP(GPIO_PIN_RESET);
  228. }
  229. }
  230. /**
  231. * @brief 控制蜂鸣器响应
  232. * @note 根据不同条件控制蜂鸣器的响停 进入周期为100ms
  233. * @param 无
  234. * @retval 无
  235. */
  236. void control_beep_response(void) {
  237. global_par *p_global_par = &s_global_par;
  238. // 蜂鸣器计数器
  239. static uint8_t beep_count_fence = 0;
  240. // static uint8_t beep_count_fault = 0;
  241. static uint8_t beep_count_ota = 0;
  242. // 超出围栏 500ms频率响应
  243. if (BIT_CHECK(s_comData.Malfunction, fence)) {
  244. beep_control(beep_count_fence, 5, 10);
  245. beep_count_fence = (beep_count_fence >= 10) ? 0 : beep_count_fence + 1;
  246. }
  247. // OTA升级 2s的响应频率
  248. else if (p_global_par->otaUpgradeStartFlag == 1) {
  249. beep_control(beep_count_ota, 20, 40);
  250. beep_count_ota = (beep_count_ota >= 40) ? 0 : beep_count_ota + 1;
  251. }
  252. // 不存在蜂鸣器响应,蜂鸣器应关闭
  253. else{
  254. GPIO_BEEP(GPIO_PIN_RESET);
  255. }
  256. }
  257. // 格式转换函数
  258. void formatDateTimeAndMalfunction(uint16_t year, uint8_t month, uint8_t day,
  259. uint8_t hour, uint8_t minute, uint8_t sec,
  260. uint32_t malfunction, char *output) {
  261. // 确保提供的output数组足够大
  262. // 格式化字符串为 YYYYMMDD-HHMM:0xXXXXXXXX 格式
  263. sprintf(output, "%04u%02u%02u-%02u%02u%02u:0x%08X,",
  264. year, month, day, hour, minute, sec, malfunction);
  265. output[29] = '\0'; // 确保字符串以空字符结尾
  266. }
  267. /**
  268. * @brief 历史故障存储
  269. * @note 此函数1s1次
  270. * @param 无
  271. * @retval 无
  272. */
  273. void storeFaultRecord(void) {
  274. uint16_t id = 0;
  275. char storeFaultData[30] = {0};
  276. static uint32_t fault_log = 0; // 用来同当前故障数据对比,看是否产生故障变化
  277. static uint16_t timeCnt_delay = 0; // 存在故障
  278. id = norflash_read_id(); /* 读取FLASH ID */
  279. if((id == 0) || (id == 0XFFFF)) { // 检测不到FLASH芯片
  280. return;
  281. }
  282. // 检查是否存在故障
  283. if (s_comData.Malfunction == 0) {
  284. return; // 如果没有故障,直接返回
  285. }
  286. // 检查是否产生故障变化或者到达计时时间
  287. if((fault_log == s_comData.Malfunction) && (timeCnt_delay < FAULT_RECORD_TIME)){
  288. timeCnt_delay++;
  289. return; // 如果没有故障变化或者未到达计时时间,直接返回
  290. }else{
  291. // 更新计数值和故障log
  292. timeCnt_delay = 0;
  293. fault_log = s_comData.Malfunction;
  294. }
  295. // 存储格式转换成 这样的20240513-172203:0x0000000f,字符串数据
  296. formatDateTimeAndMalfunction(s_nmea_utc_time.year,s_nmea_utc_time.month,s_nmea_utc_time.date,
  297. s_nmea_utc_time.hour,s_nmea_utc_time.min,s_nmea_utc_time.sec,s_comData.Malfunction, storeFaultData);
  298. // 写入数据
  299. norflash_write((uint8_t *)storeFaultData, s_param_boot.nextFaultAddr, strlen(storeFaultData));
  300. // 更新索引
  301. s_param_boot.faultRecordIndex = (s_param_boot.faultRecordIndex < MAX_RECORDS) ? (s_param_boot.faultRecordIndex + 1) : 0 ;
  302. // 更新地址
  303. s_param_boot.nextFaultAddr += strlen(storeFaultData);
  304. if(s_param_boot.faultRecordIndex == 0){
  305. s_param_boot.nextFaultAddr = 0;
  306. }
  307. // 保存最新的索引和地址数据
  308. Write_paramArea();
  309. }
  310. /**
  311. * @brief 更新保存的时间信息
  312. * @note 此函数1s1次
  313. * @param 无
  314. * @retval 无
  315. */
  316. void refreshSavedTime(void){
  317. static uint8_t timesCnt = 0;
  318. // 未获取到时间数据,则不保存
  319. if(s_global_par.time_stamp_flag != 1){
  320. return;
  321. }
  322. s_param_boot.year = s_nmea_utc_time.year;
  323. s_param_boot.month = s_nmea_utc_time.month;
  324. s_param_boot.date = s_nmea_utc_time.date;
  325. s_param_boot.hour = s_nmea_utc_time.hour;
  326. s_param_boot.min = s_nmea_utc_time.min;
  327. s_param_boot.sec = s_nmea_utc_time.sec;
  328. // 10s保存一次时间数据,发生故障时保存一次,固件更新时保存一次
  329. if(timesCnt < times_10s){
  330. timesCnt++;
  331. }else{
  332. timesCnt = 0;
  333. Write_paramArea();
  334. }
  335. }
  336. // 车辆行驶里程计算
  337. // 参数:day
  338. // 参数2:累积行驶总里程 485下发的总里程
  339. void calculate_driving_distance(uint32_t totalMileage){
  340. param_boot *p_param_boot = &s_param_boot;
  341. // 问询的车辆总里程没有备份的大,则不做操作
  342. if(totalMileage <= p_param_boot->carTotalMileage){
  343. return;
  344. }
  345. // 1. 计算当日行驶里程
  346. p_param_boot->dailyMileage += totalMileage - p_param_boot->carTotalMileage;
  347. // 2. 备份总里程信息
  348. p_param_boot->carTotalMileage = totalMileage;
  349. }
  350. // 车辆行驶时长计算
  351. // 参数1 :单次行驶时长
  352. // 参数2 :当日行驶时长
  353. // 参数3 :累积行驶时长
  354. // 周期为1s1次
  355. void calculateDriveTime(void){
  356. static uint16_t run_sec = 0;
  357. param_boot *p_param_boot = &s_param_boot;
  358. // 数据累加 按s累加
  359. run_sec++;
  360. p_param_boot->dailyDriveTime++;
  361. p_param_boot->totalDriveTime++;
  362. // 计算本次行驶时长
  363. int hours = (run_sec % 86400) / 3600; // 计算剩余秒数对应的小时数
  364. int minutes = (run_sec % 3600) / 60; // 计算剩余秒数对应的分钟数
  365. s_rs485RecDate.runTime = (uint16_t)hours << 8 | minutes;
  366. }
  367. // 车辆状态参数数据迁移vehicle state data migration
  368. void vehStateDataMig(uint8_t timeDate){
  369. param_boot *p_param_boot = &s_param_boot;
  370. rs485RecDate *p_rs485RecDate = &s_rs485RecDate;
  371. // 判断没有在当日 跨天则当日行驶里程清零
  372. if(timeDate != p_param_boot->dailyDate){
  373. p_param_boot->dailyDriveTime = 0;
  374. p_param_boot->dailyMileage = 0;
  375. p_param_boot->dailyDate = timeDate; // 更新时间信息
  376. }
  377. p_rs485RecDate->dailyDrivMileage = p_param_boot->dailyMileage * 10; // 单位转换
  378. int hours = (p_param_boot->dailyDriveTime % 86400) / 3600; // 计算剩余秒数对应的小时数
  379. int minutes = (p_param_boot->dailyDriveTime % 3600) / 60; // 计算剩余秒数对应的分钟数
  380. p_rs485RecDate->dailyDrivTime = (uint16_t)hours << 8 | minutes;
  381. int days = p_param_boot->totalDriveTime / 86400; // 计算天数
  382. hours = (p_param_boot->totalDriveTime % 86400) / 3600; // 计算剩余秒数对应的小时数
  383. minutes = (p_param_boot->totalDriveTime % 3600) / 60; // 计算剩余秒数对应的分钟数
  384. p_rs485RecDate->accTotalDrivTime_day = days;
  385. p_rs485RecDate->accTotalDrivTime_h_min = (uint16_t)hours << 8 | minutes;
  386. }
  387. // 测试使用
  388. void fun(void){
  389. static uint8_t cnt = 0;
  390. uint32_t accTotalMileage = 0;
  391. accTotalMileage = (uint32_t)s_rs485RecDate.accTotalMileage_h << 16 | s_rs485RecDate.accTotalMileage_l;
  392. if(cnt < times_5s){
  393. cnt++;
  394. return;
  395. }else{
  396. cnt = 0;
  397. accTotalMileage++;
  398. }
  399. s_rs485RecDate.accTotalMileage_h = accTotalMileage >> 16;
  400. s_rs485RecDate.accTotalMileage_l = accTotalMileage & 0x0000FFFF; // 使用位与操作符
  401. }