Work_TN.c 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639
  1. /*
  2. * Copyright (c) 2006-2021, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2024-08-16 RuoFeng the first version
  9. */
  10. /*********************↓ define ↓************************/
  11. #define DBG_ENABLE
  12. #define DBG_COLOR
  13. #define DBG_TAG "tn"
  14. #define DBG_LEVEL DBG_INFO
  15. #include <rtdbg.h>
  16. #define LOG_INR 10 // 默认的log打印间隔(作用域在本文件)
  17. #define RTU_OFF_MAX 180
  18. #define WAIT_NET_MAX 150
  19. #define ENABLE_WORK (Check_Allow_Work() == res_ok)
  20. #define NEW_TIMESTAMP tm_to_timestamp()
  21. /*********************↑ define ↑************************/
  22. /**
  23. *
  24. *
  25. *
  26. *
  27. * */
  28. /*********************↓ include ↓************************/
  29. #include "Work_TN.h"
  30. #include "rs485.h"
  31. #include "control.h"
  32. #include "test.h"
  33. #include <easyflash.h>
  34. #include "dtu_uart2.h"
  35. /*********************↑ include ↑************************/
  36. /**
  37. *
  38. *
  39. *
  40. *
  41. * */
  42. /*********************↓ extern ↓************************/
  43. extern Temporal_list Check_Work_time_period(uint8_t coll_ch);
  44. extern works_def ws_now;
  45. extern Device_Status_typedef device_status;
  46. extern void HMI_WRITE(char *fmt, ...);
  47. extern JD_Test_Sta jts;
  48. extern Res_def Mtor_Control_ZP(Motor_Ctl_type mct);
  49. extern Sensor sensor[MAX_SENSOR_NUM];
  50. extern Temporal_list Check_Work_time_period_0oclock(void);
  51. extern RTC_DateTypeDef GetDate;
  52. extern RTC_TimeTypeDef GetTime;
  53. extern uint8_t ReFlash_RTC(void);
  54. extern void CTL_CAM1(void);
  55. extern uint32_t tm_to_timestamp(void);
  56. /*********************↑ extern ↑************************/
  57. /**
  58. *
  59. *
  60. *
  61. *
  62. * */
  63. /********************↓ declaration ↓***********************/
  64. static void rtu1(void);
  65. static void rtu0(void);
  66. static char rturead(void);
  67. void Request_ntp(void);
  68. /********************↑ declaration ↑***********************/
  69. /**
  70. *
  71. *
  72. *
  73. *
  74. * */
  75. /*********************↓ global variables ↓************************/
  76. static uint16_t takephoto_cnt = 0; // 拍照触发计数
  77. static uint16_t wait_data_cnt = 0; // 上报数据计数
  78. static uint32_t tm_data = 0; // 计算数据时间
  79. static uint32_t tm_photo = 0; // 计算图片时间
  80. volatile SYSCFG syscfg = {0}; // 系统配置
  81. volatile Limit limit = {0}; // 各种控的开关和参数
  82. volatile wm_Def workmode = TypeMAX_wx; // 工作模式
  83. WorkMode_Def WorkModeList[TypeMAX_wx] = // 工作模式类型
  84. {
  85. {RunTime_wx, "时控间隔模式"},
  86. {RunTime_Tig_wx, "时控触发模式"}};
  87. volatile uint16_t RayTigCnt = 0; // 红外触发计数
  88. volatile static char RayTiged = 0; // 红外已触发过
  89. volatile static char RayOneLess = 0; // 红外触发记录
  90. volatile char CamFree = 1; // 相机空闲状态
  91. volatile uint32_t INR_PIC = 0; // 图片上传间隔
  92. volatile uint32_t INR_DAT = 0; // 图片上传间隔
  93. volatile char stop_getinfo = 0; // dtuwrite时暂停 getinfo
  94. static uint8_t rain_exit = 0; // 雨控退出进度
  95. volatile char errcnt_getinfo = 0; // err计数
  96. // volatile char RTUGetUp = 0; // RTU上电开机
  97. /*********************↑ global variables ↑************************/
  98. /**
  99. *
  100. *
  101. *
  102. *
  103. * */
  104. /**
  105. * @brief
  106. *
  107. * @return int8_t -1(超时) >1(进度百分比)
  108. */
  109. // int8_t Get_luxworkTime(void)
  110. //{
  111. // // ReFlash_RTC();
  112. // //
  113. // // uint32_t start = 0, now = 0;
  114. // //
  115. // // start = lwork.start_time.Hours * 60 + lwork.start_time.Minutes;
  116. // // now = GetTime.Hours * 60 + GetTime.Minutes;
  117. // //
  118. // // if (abs(GetTime.Hours - lwork.start_time.Hours) >= 10 && GetTime.Hours < lwork.start_time.Hours)
  119. // // {
  120. // // now += 1440;
  121. // // }
  122. // // if ((now - start) > (limit.LuxTime * 60))
  123. // // {
  124. // // return -2;
  125. // // }
  126. // // else
  127. // // {
  128. // // LOG_I("luxtime %d%% \n", ((now - start) * 100) / (limit.LuxTime * 60));
  129. // // return ((now - start) * 100) / (limit.LuxTime * 60);
  130. // // }
  131. //
  132. // return -1;
  133. // }
  134. /**
  135. * @brief Get the Coll Info object
  136. *
  137. * @return uint8_t persen
  138. */
  139. uint8_t GetCollInfo(void)
  140. {
  141. // uint16_t inr = 0;
  142. // (syscfg.photim >= 5) ? (inr = syscfg.photim - 1) : (inr = TakeINR);
  143. return (math_timestampe_NEW(&tm_photo) * 100) / (INR_PIC);
  144. }
  145. /**
  146. * @brief 获取晨曦模式工作进度 不在工作范围 返回负数
  147. *
  148. * @return int8_t val(-1 未开始工作 -2 参数校验失败)
  149. */
  150. int8_t Get_swork_percent(void)
  151. {
  152. uint32_t start = 0, end = 0, temp1 = 0, now = 0;
  153. now = GetTime.Hours * 3600 + GetTime.Minutes * 60 + GetTime.Seconds;
  154. start = device_status.collecting_sh1 * 3600;
  155. end = device_status.collecting_eh1 * 3600;
  156. if (now < start && now > end)
  157. {
  158. return -1;
  159. }
  160. if (device_status.collecting_sh1 > device_status.collecting_eh1)
  161. {
  162. end += (24 * 3600);
  163. }
  164. temp1 = end - start;
  165. // rt_kprintf("now %d ALL %d\n" , (now - start) , temp1);
  166. if (((now - start) > temp1) || ((now - start) * 100 / temp1) > 100)
  167. {
  168. return -3;
  169. }
  170. return (now - start) * 100 / temp1;
  171. }
  172. /**
  173. * @brief 确认当前工作模式
  174. *
  175. */
  176. void Get_work_mode(void)
  177. {
  178. /**
  179. * @brief 开始确认
  180. *
  181. */
  182. static uint8_t ENPrint = 1;
  183. wm_Def bak = workmode;
  184. if (syscfg.en_tigmode == 0)
  185. {
  186. workmode = RunTime_wx;
  187. if (ENPrint || bak != workmode)
  188. {
  189. rt_kprintf("\n 时控间隔模式 %d-%d 时 > %d\n\n", device_status.collecting_sh1, device_status.collecting_eh1, ws_now);
  190. bak = workmode;
  191. ENPrint = 0;
  192. }
  193. }
  194. else
  195. {
  196. workmode = RunTime_Tig_wx;
  197. if (ENPrint || bak != workmode)
  198. {
  199. rt_kprintf("\n 时控触发模式 %d-%d 时 > %d\n\n", device_status.collecting_sh1, device_status.collecting_eh1, ws_now);
  200. bak = workmode;
  201. ENPrint = 0;
  202. }
  203. }
  204. }
  205. #define Temp_Tig_MX 20
  206. /**
  207. * @brief 检查是否允许工作
  208. *
  209. * @return Caw_def 校验值
  210. */
  211. Caw_def Check_Allow_Work(void)
  212. {
  213. uint16_t log_en_inr = LOG_INR * 3; // 打印log的速度 数值越小 打印越频繁
  214. static int16_t log_en_cnt = -1;
  215. rt_thread_mdelay(15);
  216. Get_work_mode();
  217. /**
  218. * @brief 雨控
  219. *
  220. */
  221. if (device_status.rain_update == 1) // 还需要再改
  222. {
  223. LOG_W("CAW:雨控\n");
  224. device_status.rain_update = 0;
  225. if (device_status.rain_status == 0)
  226. {
  227. device_status.rain_status = 1;
  228. Mtor_Control_CM(mct_Foreward); // 关仓门
  229. {
  230. Recode_e_code(e_rain_tig, 0, "进入雨控 关仓门");
  231. char *rain_tig = makeJson_Warn("Rain Tig In", "STA");
  232. DTU_Write("%s", rain_tig);
  233. rt_free(rain_tig);
  234. }
  235. }
  236. rain_exit = 90;
  237. rt_thread_mdelay(1000);
  238. return res_Rain;
  239. }
  240. else if (rain_exit > 0)
  241. {
  242. rain_exit--;
  243. if (rain_exit == 0)
  244. {
  245. LOG_W(" exit rain , open the door\n");
  246. Mtor_Control_CM(mct_Reversal); // 开仓门
  247. {
  248. Recode_e_code(e_rain_tig, 1, "退出雨控 开仓门");
  249. device_status.rain_status = 0;
  250. char *rain_tig = makeJson_Warn("Rain Tig Out", "STA");
  251. DTU_Write("%s", rain_tig);
  252. rt_free(rain_tig);
  253. }
  254. }
  255. else
  256. {
  257. LOG_W("ready to exit rain > %d\n", rain_exit);
  258. }
  259. rt_thread_mdelay(500);
  260. return res_Rain;
  261. }
  262. if (device_status.ds != 1) // 250327 新增 关机状态
  263. {
  264. if (chk_log_time)
  265. {
  266. LOG_I("CAW:ds == 0\n");
  267. }
  268. return res_PwrOff;
  269. }
  270. switch (workmode)
  271. {
  272. /**
  273. * @brief 时控模式
  274. *
  275. */
  276. case RunTime_wx:
  277. if ((device_status.collecting_sh1 == device_status.collecting_eh1) ||
  278. (device_status.collecting_sh1 == 0 && device_status.collecting_eh1 == 24)) // 全天候牛马
  279. {
  280. if (chk_log_time)
  281. {
  282. LOG_I("CAW:全天候牛马\n");
  283. }
  284. }
  285. else if (device_status.collecting_eh1 < device_status.collecting_sh1) // 跨0点牛马
  286. {
  287. if (Check_Work_time_period_0oclock() != tl_Center)
  288. {
  289. if (chk_log_time)
  290. {
  291. LOG_I("CAW:未在工作时间 0点\n");
  292. }
  293. return res_Time;
  294. }
  295. }
  296. else // 正常牛马
  297. {
  298. if (Check_Work_time_period(1) != tl_Center)
  299. {
  300. if (chk_log_time)
  301. {
  302. LOG_I("CAW:未在工作时间\n");
  303. }
  304. return res_Time;
  305. }
  306. }
  307. break;
  308. /**
  309. * @brief 触发模式
  310. *
  311. */
  312. case RunTime_Tig_wx:
  313. if ((device_status.collecting_sh1 == device_status.collecting_eh1) ||
  314. (device_status.collecting_sh1 == 0 && device_status.collecting_eh1 == 24)) // 全天候牛马
  315. {
  316. if (chk_log_time)
  317. {
  318. LOG_I("CAW:全天候牛马\n");
  319. }
  320. }
  321. else if (device_status.collecting_eh1 < device_status.collecting_sh1) // 跨0点牛马
  322. {
  323. if (Check_Work_time_period_0oclock() != tl_Center)
  324. {
  325. if (chk_log_time)
  326. {
  327. LOG_I("CAW:未在工作时间 0点\n");
  328. }
  329. return res_Time;
  330. }
  331. }
  332. else // 正常牛马
  333. {
  334. if (Check_Work_time_period(1) != tl_Center)
  335. {
  336. if (chk_log_time)
  337. {
  338. LOG_I("CAW:未在工作时间\n");
  339. }
  340. return res_Time;
  341. }
  342. }
  343. break;
  344. default:
  345. break;
  346. }
  347. static uint8_t temp_up_cnt = 0;
  348. static uint8_t temp_dn_cnt = 0;
  349. /**
  350. * @brief 温湿度
  351. *
  352. */
  353. // rt_kprintf("sensor[s_Temp].value %d Luxlimit %d\n" , sensor[s_Temp].value , limit.temp_up);
  354. if (sensor[s_Temp].online >= 1 && (sensor[s_Temp].value) > (limit.temp_up * 10) && limit.temhumEN == ON)
  355. {
  356. if (temp_up_cnt >= Temp_Tig_MX)
  357. {
  358. LOG_I("CAW:触发温控上限 %d\n", temp_up_cnt);
  359. return res_Temp;
  360. }
  361. temp_up_cnt++;
  362. rt_thread_mdelay(1000);
  363. // if (chk_log_time || 1)
  364. // {
  365. // LOG_I("CAW:温控上限 …%d\n", temp_up_cnt);
  366. // }
  367. if (temp_up_cnt >= Temp_Tig_MX)
  368. {
  369. if (device_status.temp_status == 0)
  370. {
  371. LOG_I("CAW:触发温控上限 %d\n", temp_up_cnt);
  372. }
  373. device_status.temp_status = 1;
  374. return res_Temp;
  375. }
  376. }
  377. else if (temp_up_cnt > 0)
  378. {
  379. temp_up_cnt--;
  380. rt_thread_mdelay(1000);
  381. if (temp_up_cnt == 0)
  382. {
  383. if (device_status.temp_status > 0)
  384. LOG_I("CAW:解除温控上限\n");
  385. device_status.temp_status = 0;
  386. }
  387. }
  388. if (sensor[s_Temp].online >= 1 && (sensor[s_Temp].value) < (limit.temp_dw * 10) && limit.temhumEN == ON)
  389. {
  390. if (temp_dn_cnt >= Temp_Tig_MX)
  391. {
  392. return res_Temp;
  393. }
  394. // rt_kprintf("(sensor[s_Temp].value) %d (limit.temp_dw * 10) %d \n" , (sensor[s_Temp].value) , (limit.temp_dw * 10));
  395. temp_dn_cnt++;
  396. rt_thread_mdelay(1000);
  397. // if (chk_log_time || 1)
  398. // {
  399. // LOG_I("CAW:温控下限 …%d\n", temp_dn_cnt);
  400. // }
  401. if (temp_dn_cnt >= Temp_Tig_MX)
  402. {
  403. temp_dn_cnt = 0;
  404. if (device_status.temp_status == 0)
  405. {
  406. LOG_I("CAW:触发温控下限 %d\n", temp_dn_cnt);
  407. }
  408. device_status.temp_status = 2;
  409. return res_Temp;
  410. }
  411. }
  412. else if (temp_dn_cnt > 0)
  413. {
  414. temp_dn_cnt--;
  415. rt_thread_mdelay(1000);
  416. if (temp_dn_cnt == 0)
  417. {
  418. if (device_status.temp_status > 0)
  419. LOG_I("CAW:解除温控下限\n");
  420. device_status.temp_status = 0;
  421. }
  422. }
  423. /**
  424. * @brief 温湿度
  425. *
  426. */
  427. Check_TestFree();
  428. return res_ok;
  429. }
  430. extern uint8_t stopreflashTakePhoto;
  431. extern uint8_t holdon_stareflash;
  432. /**
  433. * @brief 刷新工作状态
  434. *
  435. */
  436. void ReflashWorkSta(void)
  437. {
  438. if (ws_now >= ws_typemax)
  439. {
  440. rt_kprintf("ReflashWorkSta illegl wstype\n");
  441. }
  442. if (holdon_stareflash)
  443. {
  444. return;
  445. }
  446. work_day_def work_day = {0};
  447. switch (ws_now)
  448. {
  449. case ws_standby:
  450. HMI_WRITE("workSta.workinfo.txt=\"待机中...\"");
  451. break;
  452. // res_ok = 0, // 没问题
  453. // res_Time, // 时控
  454. // res_Light, // 光控
  455. // res_TempH, // 温湿度
  456. // res_Rain // 雨控
  457. case ws_wait0:
  458. switch (Check_Allow_Work())
  459. {
  460. case res_ok:
  461. HMI_WRITE("workSta.workinfo.txt=\"达到工作条件\"");
  462. break;
  463. case res_Time:
  464. HMI_WRITE("workSta.workinfo.txt=\"未达工作条件 - 时控\"");
  465. break;
  466. case res_Light:
  467. HMI_WRITE("workSta.workinfo.txt=\"未达工作条件 - 光控\"");
  468. break;
  469. case res_Temp:
  470. HMI_WRITE("workSta.workinfo.txt=\"未达工作条件 - 温控\"");
  471. break;
  472. case res_Humi:
  473. HMI_WRITE("workSta.workinfo.txt=\"未达工作条件 - 湿控\"");
  474. break;
  475. case res_Temp_D:
  476. HMI_WRITE("workSta.workinfo.txt=\"未达工作条件 - 温控(基于定位)\"");
  477. break;
  478. case res_Humi_D:
  479. HMI_WRITE("workSta.workinfo.txt=\"未达工作条件 - 湿控 (基于定位)\"");
  480. break;
  481. case res_Rain:
  482. HMI_WRITE("workSta.workinfo.txt=\"未达工作条件 - 雨控\"");
  483. break;
  484. default:
  485. HMI_WRITE("workSta.workinfo.txt=\"未达到工作条件 %d\"", Check_Allow_Work());
  486. break;
  487. }
  488. break;
  489. case ws_start_coll:
  490. HMI_WRITE("workSta.workinfo.txt=\"STEP1:收集开始\"");
  491. break;
  492. case ws_wait_coll:
  493. HMI_WRITE("workSta.workinfo.txt=\"STEP2:等待收集完成 %d%%\"", GetCollInfo());
  494. break;
  495. case ws_takephoto:
  496. HMI_WRITE("workSta.workinfo.txt=\"STEP3:开始拍照\"");
  497. break;
  498. case ws_jumptake:
  499. HMI_WRITE("workSta.workinfo.txt=\"STEP4:采集中途退出 %d\"", Check_Allow_Work());
  500. break;
  501. case ws_flap:
  502. HMI_WRITE("workSta.workinfo.txt=\"STEP5:翻板中\"");
  503. break;
  504. case ws_once_finsh:
  505. HMI_WRITE("workSta.workinfo.txt=\"STEP6:单次工作循环结束\"");
  506. break;
  507. case ws_finsh:
  508. ef_get_env_blob("work_day", &work_day, sizeof(work_day), NULL);
  509. HMI_WRITE("workSta.workinfo.txt=\"今日工作周期结束 %02d.%02d.%02d\"", work_day.year % 100, work_day.month, work_day.day);
  510. break;
  511. default:
  512. break;
  513. }
  514. }
  515. static void TigTakePho(void)
  516. {
  517. device_status.work_status = 3;
  518. LOG_W("STEP3 :takephoto");
  519. ws_now = ws_takephoto;
  520. ctr_led(ON);
  521. DTU_Write("takephoto.mp3");
  522. // 延时
  523. rt_thread_delay(1000);
  524. Hk_Take_io();
  525. Request_ntp();
  526. if (jts.switchled_test != ON && RunTime_wx == workmode)
  527. {
  528. ctr_led(OFF);
  529. }
  530. else
  531. {
  532. LOG_W("STEP4 :jump takephoto");
  533. ws_now = ws_jumptake;
  534. rt_thread_delay(3000);
  535. if (jts.switchled_test != ON && RunTime_wx == workmode)
  536. {
  537. ctr_led(OFF);
  538. }
  539. }
  540. takephoto_cnt = 0;
  541. LOG_W("STEP5 :Flap");
  542. ws_now = ws_flap;
  543. Mtor_Control_ZP(mct_auto);
  544. Mtor_Control_ZP(mct_auto);
  545. // Mtor_Control_ZP(mct_Reversal);
  546. LOG_W("STEP6 :one cycle finsh");
  547. ws_now = ws_once_finsh;
  548. rt_thread_mdelay(1000);
  549. }
  550. /**
  551. * @brief 记录当前时刻
  552. *
  553. * @param time 时间戳
  554. */
  555. void recode_timestampe_NEW(uint32_t *tim)
  556. {
  557. ReFlash_RTC();
  558. *tim = NEW_TIMESTAMP;
  559. if (tim == &tm_photo)
  560. {
  561. rt_kprintf("recode_timestampe (photo) > %d sec\n", *tim);
  562. ef_set_env_blob("tm_photo" ,&tm_photo ,sizeof(tm_photo));
  563. }
  564. else if (tim == &tm_data)
  565. {
  566. rt_kprintf("recode_timestampe (data ) > %d sec\n", *tim);
  567. ef_set_env_blob("tm_data" ,&tm_data ,sizeof(tm_data));
  568. }
  569. rt_thread_mdelay(1000);
  570. }
  571. /**
  572. * @brief 计算差值
  573. *
  574. * @param time 时间戳
  575. * @return uint32_t 差值
  576. */
  577. uint32_t math_timestampe_NEW(uint32_t *tim)
  578. {
  579. // uint16_t log_en_inr = LOG_INR * 3; // 打印log的速度 数值越小 打印越频繁
  580. // static int16_t log_en_cnt = -1;
  581. static struct tm tm_bak;
  582. static char err_cnt = 0;
  583. char time_bak[30] = {0};
  584. if (*tim == NEW_TIMESTAMP)
  585. {
  586. rt_thread_mdelay(1000);
  587. }
  588. ReFlash_RTC();
  589. uint32_t now = NEW_TIMESTAMP;
  590. uint32_t val = (now - *tim);
  591. if (val > 0 && val < ((syscfg.dattim + syscfg.photim) * 60))
  592. {
  593. // if (chk_log_time)
  594. // {
  595. // if (tim == &tm_photo)
  596. // {
  597. // rt_kprintf("math_timestampe (photo) > %d sec\n", val);
  598. // }
  599. // else
  600. // {
  601. // rt_kprintf("math_timestampe (data ) > %d sec\n", val);
  602. // }
  603. // }
  604. tm_bak.tm_year = GetDate.Year;
  605. tm_bak.tm_mon = GetDate.Month;
  606. tm_bak.tm_yday = GetDate.Date;
  607. tm_bak.tm_hour = GetTime.Hours;
  608. tm_bak.tm_min = GetTime.Minutes;
  609. tm_bak.tm_sec = GetTime.Seconds;
  610. err_cnt = 0;
  611. return val;
  612. }
  613. else
  614. {
  615. if (GetDate.Year > 200)
  616. {
  617. sprintf(time_bak, "%02d-%02d-%02d %02d:%02d:%02d",
  618. tm_bak.tm_year,
  619. tm_bak.tm_mon,
  620. tm_bak.tm_yday,
  621. tm_bak.tm_hour,
  622. tm_bak.tm_min,
  623. tm_bak.tm_sec);
  624. if (tm_bak.tm_year > 0 && tm_bak.tm_year < 200)
  625. {
  626. LOG_W("Write bak time %s!", time_bak);
  627. EXE_NTP_SETTIME(&tm_bak);
  628. }
  629. err_cnt++;
  630. if (err_cnt == 5)
  631. {
  632. Recode_e_code(e_rtc_fail, 0x9D, time_bak);
  633. }
  634. if (err_cnt > 30)
  635. {
  636. rt_hw_cpu_reset();
  637. }
  638. }
  639. if (tim == &tm_photo)
  640. {
  641. rt_kprintf("math_timestampe fail (photo) > %d (now : %d >>> tim : %d) \n", val, now, *tim);
  642. recode_timestampe_NEW(tim);
  643. }
  644. else
  645. {
  646. rt_kprintf("math_timestampe fail (data ) > %d (now : %d >>> tim : %d) \n", val, now, *tim);
  647. recode_timestampe_NEW(tim);
  648. }
  649. }
  650. return 0;
  651. }
  652. /**
  653. * @brief 简易的数据上报,用于在等待图片上报过程中检查是否需要数据上报
  654. *
  655. */
  656. void Updata_INR_Simple(void)
  657. {
  658. INR_DAT = syscfg.dattim * 60 - 10; // 减去30 消除上报所耗时间
  659. if (math_timestampe_NEW(&tm_data) > INR_DAT)
  660. {
  661. LOG_I(" >>> watting mode > STEP A start report data C\n");
  662. recode_timestampe_NEW(&tm_data); // 此时重置时间戳
  663. wait_data_cnt = 0;
  664. UpLoad_Data(0);
  665. }
  666. }
  667. /**
  668. * @brief Construct a new Updata_INR object
  669. *
  670. * @param type > enable power off
  671. */
  672. static uint16_t Updata_INR(uint8_t type)
  673. {
  674. static uint16_t rtuon_cnt = 0; // 非工作模式时 rtu上电时间记录
  675. static char Once_poweroff = 1;
  676. /**
  677. * @brief ↓↓↓ 不在工作模式的时候 间隔上线上报数据 在此处实现 ↓↓↓
  678. *
  679. */
  680. INR_DAT = syscfg.dattim * 60 - 10; // 减去30 消除上报所耗时间
  681. wait_data_cnt++;
  682. if (wait_data_cnt >= INR_DAT || (math_timestampe_NEW(&tm_data) > INR_DAT))
  683. {
  684. if (wait_data_cnt >= INR_DAT)
  685. {
  686. LOG_I(" >>> watting mode > STEP A start report data A\n");
  687. }
  688. else
  689. {
  690. LOG_I(" >>> watting mode > STEP A start report data B\n");
  691. }
  692. recode_timestampe_NEW(&tm_data); // 此时重置时间戳
  693. // recode_timestampe(&tm_photo); // 记录数据上报开始时间
  694. wait_data_cnt = 0;
  695. ctr_RTU_DTU(ON);
  696. sprintf(device_status.net, "1"); // 去掉网络状态
  697. while (++wait_data_cnt < (WAIT_NET_MAX / 2))
  698. {
  699. SendReadInfo('D');
  700. if (atoi(device_status.net) == 0)
  701. {
  702. LOG_I(" >>> watting mode > STEP B1 RTU net get up\n");
  703. rt_thread_mdelay(2000);
  704. UpLoad_Data(0);
  705. rt_thread_mdelay(30000); // 留有指令下发时间
  706. break;
  707. }
  708. rt_thread_mdelay(1000);
  709. }
  710. if (wait_data_cnt >= (WAIT_NET_MAX / 2))
  711. {
  712. UpLoad_Data(0);
  713. LOG_W(" >>> watting mode > STEP B2 RTU net get failed\n");
  714. Recode_e_code(e_rtu_net_fail, 1, "间隔上报时联网失败 > B2");
  715. rt_thread_mdelay(5000);
  716. }
  717. wait_data_cnt = 0;
  718. if (math_timestampe_NEW(&tm_photo) > (INR_PIC - 60) && (Check_Allow_Work() == res_ok)) // 接近图片上报 不再断电
  719. {
  720. LOG_I("CLOSE UP_PIC , JUMP RTU0");
  721. }
  722. else
  723. {
  724. ctr_RTU_DTU(OFF);
  725. }
  726. Request_ntp();
  727. }
  728. if (math_timestampe_NEW(&tm_data) == 0)
  729. {
  730. LOG_W("math_timestampe_NEW tm_data fail ,SET NOW");
  731. }
  732. /**
  733. * @brief ↑↑↑ 不在工作模式的时候 间隔上线上报数据 在此处实现 ↑↑↑
  734. *
  735. */
  736. /**
  737. * @brief ↓↓↓ 首次上电后 留有三分钟数据上报 指令下发时间 ↓↓↓
  738. *
  739. */
  740. if (rturead() && Once_poweroff)
  741. {
  742. rtuon_cnt++;
  743. if (rtuon_cnt >= RTU_OFF_MAX)
  744. {
  745. LOG_I("RTU ON Time out of range , now turn it off A\n\n");
  746. ctr_RTU_DTU(OFF);
  747. rtuon_cnt = 0;
  748. Once_poweroff = 0;
  749. }
  750. }
  751. /**
  752. * @brief ↑↑↑ 首次上电后 留有三分钟数据上报 指令下发时间 ↑↑↑
  753. *
  754. */
  755. return wait_data_cnt;
  756. }
  757. extern char Demo_Mode_NEW;
  758. void KeyTigCheck(void)
  759. {
  760. #define manual_mode_MX 60
  761. #define demo_mode_MX 120
  762. uint16_t log_en_inr = LOG_INR * 5; // 打印log的速度 数值越小 打印越频繁
  763. static int16_t log_en_cnt = -1;
  764. uint32_t cnt = 0;
  765. if (ws_now == ws_KeyTig)
  766. {
  767. Recode_e_code(e_manual_mode, 0, "进入手动触发模式");
  768. while (cnt++ < 60 * manual_mode_MX)
  769. {
  770. rt_thread_mdelay(1000);
  771. if (ws_now != ws_KeyTig)
  772. {
  773. break;
  774. }
  775. if (chk_log_time)
  776. rt_kprintf("处于手动触发模式 %d/%d\n", cnt, manual_mode_MX * 60);
  777. if (cnt % 30 == 0)
  778. {
  779. SendReadInfo('E');
  780. }
  781. }
  782. Recode_e_code(e_manual_mode, 1, "退出手动触发模式");
  783. }
  784. if (Demo_Mode_NEW == 1)
  785. {
  786. Recode_e_code(e_demo_mode, 0, "进入演示模式");
  787. cnt = 0;
  788. rt_kprintf("演示模式 暂停工作 %d / %d\n", cnt, demo_mode_MX * 60);
  789. while (cnt++ < demo_mode_MX * 60)
  790. {
  791. rt_thread_mdelay(1000);
  792. if (Demo_Mode_NEW == 0)
  793. {
  794. break;
  795. }
  796. if (cnt % 100 == 0)
  797. {
  798. rt_kprintf("演示模式 暂停工作 %d / %d\n", cnt, demo_mode_MX * 60);
  799. }
  800. ws_now = ws_demo;
  801. ctr_RTU_DTU(ON);
  802. CTL_CAM1();
  803. }
  804. Demo_Mode_NEW = 0;
  805. Recode_e_code(e_demo_mode, 1, "退出演示模式");
  806. }
  807. }
  808. /**
  809. * @brief 天牛工作流程
  810. *
  811. */
  812. void WorkTask_TN(void)
  813. {
  814. uint16_t log_en_inr = LOG_INR * 5; // 打印log的速度 数值越小 打印越频繁
  815. static int16_t log_en_cnt = -1;
  816. LOG_I(" WorkTask_TN ");
  817. if (Check_Allow_Work() != res_ok)
  818. {
  819. if (jts.switchled_test != ON)
  820. {
  821. ctr_led(OFF);
  822. }
  823. }
  824. rt_thread_mdelay(1000);
  825. if (tm_data + tm_photo == 0 && GetDate.Year > 20)
  826. {
  827. ef_get_env_blob("tm_data" ,&tm_data ,sizeof(tm_data),NULL);
  828. ef_get_env_blob("tm_photo" ,&tm_data ,sizeof(tm_photo),NULL);
  829. if(tm_data + tm_photo == 0)
  830. {
  831. recode_timestampe_NEW(&tm_data);
  832. recode_timestampe_NEW(&tm_photo);
  833. Recode_e_code(e_tm_init ,(tm_data + tm_photo)%65536,"tm INIT A");
  834. }
  835. else
  836. {
  837. Recode_e_code(e_tm_init ,(tm_data + tm_photo)%65536,"tm INIT B");
  838. }
  839. LOG_I("recode_timestampe INIT");
  840. }
  841. while (Check_Allow_Work() != res_ok) // 新增数据上报逻辑(开启rtu 上报一次数据)
  842. {
  843. log_en_inr = LOG_INR * 5;
  844. rt_thread_mdelay(1000);
  845. KeyTigCheck();
  846. ws_now = ws_wait0; // 待机
  847. if (chk_log_time)
  848. {
  849. LOG_I("STEP0 :wait work start");
  850. }
  851. Updata_INR(1);
  852. }
  853. rt_thread_mdelay(1000);
  854. uint16_t tig_cnt = 0;
  855. char last_once = 0;
  856. while (Check_Allow_Work() == res_ok)
  857. {
  858. LOG_W("STEP1 :start work > %d > %d ", workmode, takephoto_cnt);
  859. rt_thread_mdelay(1000);
  860. device_status.work_status = 1;
  861. (syscfg.photim >= 5) ? (INR_PIC = (syscfg.photim * 60)) : (INR_PIC = (TakeINR * 60));
  862. switch (workmode)
  863. {
  864. case RunTime_wx:
  865. log_en_inr = LOG_INR * 5;
  866. while ((Check_Allow_Work() == res_ok) && (workmode == RunTime_wx))
  867. {
  868. if (chk_log_time)
  869. {
  870. LOG_W("STEP2 :wait coll finsh %d%%", GetCollInfo());
  871. }
  872. KeyTigCheck();
  873. ws_now = ws_wait_coll;
  874. rt_thread_mdelay(1000);
  875. if (math_timestampe_NEW(&tm_photo) >= (INR_PIC)) // 拍照部分
  876. {
  877. if (math_timestampe_NEW(&tm_photo) >= (INR_PIC))
  878. {
  879. LOG_I("Read to takephoto B\n");
  880. }
  881. else
  882. {
  883. LOG_I("Read to takephoto A\n");
  884. }
  885. last_once = 1;
  886. Recode_e_code(e_pic_tri , 0 , "工作流拍照");
  887. recode_timestampe_NEW(&tm_photo);
  888. if (rt_pin_read(CAM_CTL) != ON || rt_pin_read(RTU_DTU) != ON)
  889. {
  890. rt_kprintf("检测到拍照前未开启RTU");
  891. ctr_RTU_DTU(ON);
  892. CTL_CAM1();
  893. ctr_led(ON);
  894. for (uint16_t a = 0; a < 66; a++)
  895. {
  896. rt_thread_mdelay(1000);
  897. rt_kprintf("wait for RTU start A3\n");
  898. }
  899. }
  900. TigTakePho();
  901. takephoto_cnt = 0;
  902. if (math_timestampe_NEW(&tm_data) > (INR_DAT - 30)) // 接近数据上报 不再断电
  903. {
  904. LOG_I("CLOSE UPDATA , JUMP RTU0");
  905. }
  906. else
  907. {
  908. ctr_RTU_DTU(OFF);
  909. }
  910. }
  911. else if (math_timestampe_NEW(&tm_photo) >= ((INR_PIC)-WAIT_NET_MAX)) // RTU提前上电
  912. {
  913. // rt_kprintf("takephoto_cnt close >> %d\n",math_timestampe_NEW(&tm_photo));
  914. ctr_RTU_DTU(ON);
  915. CTL_CAM1();
  916. ctr_led(ON);
  917. }
  918. else // 数据部分
  919. {
  920. Updata_INR(0);
  921. }
  922. if (math_timestampe_NEW(&tm_photo) == 0)
  923. {
  924. LOG_W("math_timestampe_NEW tm_photo fail ,SET NOW");
  925. }
  926. }
  927. // 时控模式退出后 上报一次照片 需要间隔已经有至少一半
  928. if ((GetCollInfo() >= 60 && last_once == 0) || (GetCollInfo() >= 80))
  929. {
  930. recode_timestampe_NEW(&tm_photo);
  931. Recode_e_code(e_pic_last_once , 0 , "工作结束图片保护");
  932. if (rt_pin_read(CAM_CTL) != ON || rt_pin_read(RTU_DTU) != ON)
  933. {
  934. rt_kprintf("检测到拍照前未开启RTU");
  935. ctr_RTU_DTU(ON);
  936. CTL_CAM1();
  937. ctr_led(ON);
  938. for (uint16_t a = 0; a < 66; a++)
  939. {
  940. rt_thread_mdelay(1000);
  941. rt_kprintf("wait for RTU start A3\n");
  942. }
  943. }
  944. TigTakePho();
  945. takephoto_cnt = 0;
  946. ctr_RTU_DTU(OFF);
  947. CTL_CAM0();
  948. ctr_led(OFF);
  949. }
  950. // rt_kprintf("takephoto_cnt >> %d > %d > %d\n" ,inr , inr * 60 , ((inr * 60) - WAIT_NET_MAX));
  951. break;
  952. case RunTime_Tig_wx:
  953. log_en_inr = LOG_INR * 15;
  954. if (ENABLE_WORK && (rturead() == 0) && RayTiged)
  955. {
  956. rtu1();
  957. // 开相机供电
  958. rt_thread_mdelay(30 * 1000); // 等相机开机
  959. }
  960. rtu1();
  961. ctr_led(ON);
  962. while ((Check_Allow_Work() == res_ok) && (workmode == RunTime_Tig_wx))
  963. {
  964. rtu1();
  965. ctr_led(ON);
  966. rt_thread_mdelay(100);
  967. KeyTigCheck();
  968. ws_now = ws_waitTig; // 等待触发
  969. if (chk_log_time)
  970. {
  971. LOG_I("STEP2 :wait work start TigMod");
  972. }
  973. if (RayTiged && CamFree)
  974. {
  975. TigTakePho();
  976. RayTiged = 0;
  977. }
  978. }
  979. if (tig_cnt > 0 && CamFree && (Check_Allow_Work() != res_ok)) // 工作结束时 还有计数 拍一张收尾
  980. {
  981. TigTakePho();
  982. }
  983. else if (RayOneLess == 0 && CamFree)
  984. {
  985. TigTakePho();
  986. }
  987. if ((Check_Allow_Work() == res_ok) && (workmode == RunTime_wx))
  988. {
  989. // 工作模式切换
  990. rtu0();
  991. ctr_led(OFF);
  992. }
  993. RTC_SET_TigVal(0);
  994. tig_cnt = 0;
  995. RayOneLess = 0;
  996. break;
  997. default:
  998. break;
  999. }
  1000. }
  1001. if (jts.switchled_test != ON)
  1002. {
  1003. ctr_led(OFF);
  1004. }
  1005. device_status.work_status = 0;
  1006. device_status.traplampsta = 0;
  1007. }
  1008. static void TigRay(void)
  1009. {
  1010. RayTiged = 1;
  1011. }
  1012. MSH_CMD_EXPORT(TigRay, TigRay)
  1013. /********** 红外触发驱动 ************/
  1014. /* 触发标志位(Ray开头) */
  1015. static volatile rt_bool_t RayTrigFlagA = RT_FALSE;
  1016. static volatile rt_bool_t RayTrigFlagB = RT_FALSE;
  1017. static rt_timer_t RayDebounceTimer; // 防抖定时器
  1018. static rt_timer_t RaySequenceTimer; // 序列检测定时器(新增)
  1019. /* 防抖定时器回调 */
  1020. static void RayDebounceHandler(void *param)
  1021. {
  1022. // rt_kprintf("[Ray] <%d:%d> Flags cleared by debounce\n", RayTrigFlagA, RayTrigFlagB);
  1023. }
  1024. /* 序列检测定时器回调(新增) */
  1025. static void RaySequenceHandler(void *param)
  1026. {
  1027. rt_kprintf("[Ray] Sequence timeout, flags cleared [A%d | B%d]\n", RayTrigFlagA, RayTrigFlagB);
  1028. RayTrigFlagA = RT_FALSE;
  1029. RayTrigFlagB = RT_FALSE;
  1030. rt_timer_stop(RaySequenceTimer);
  1031. }
  1032. /****************** 优化后的中断回调 ******************/
  1033. /* RayTigA中断回调 */
  1034. static rt_err_t RayIrqHandlerA(void *args)
  1035. {
  1036. if (!RayTrigFlagA)
  1037. {
  1038. RayTrigFlagA = RT_TRUE;
  1039. rt_kprintf("RayIrqHandlerA triggered\n");
  1040. // 如果B已经触发且在50ms内
  1041. if (RayTrigFlagB)
  1042. {
  1043. RayTigCnt++;
  1044. RTC_SET_TigVal(RayTigCnt);
  1045. RayTiged = RT_TRUE;
  1046. RayOneLess = RT_TRUE;
  1047. rt_kprintf("[Ray] Item detected! Count: %d\n", RTC_GET_TigVal());
  1048. // 清除标志和定时器
  1049. RayTrigFlagA = RT_FALSE;
  1050. RayTrigFlagB = RT_FALSE;
  1051. rt_timer_stop(RayDebounceTimer);
  1052. rt_timer_stop(RaySequenceTimer);
  1053. }
  1054. else
  1055. {
  1056. // 启动防抖定时器
  1057. rt_timer_start(RayDebounceTimer);
  1058. }
  1059. }
  1060. return RT_EOK;
  1061. }
  1062. /* RayTigB中断回调 */
  1063. static rt_err_t RayIrqHandlerB(void *args)
  1064. {
  1065. if (!RayTrigFlagB)
  1066. {
  1067. RayTrigFlagB = RT_TRUE;
  1068. rt_kprintf("RayIrqHandlerB triggered\n");
  1069. // 启动序列检测定时器(50ms)
  1070. rt_timer_control(RaySequenceTimer, RT_TIMER_CTRL_SET_TIME, (void *)50);
  1071. rt_timer_start(RaySequenceTimer);
  1072. RayTrigFlagA = RT_FALSE;
  1073. // 启动防抖定时器
  1074. rt_timer_start(RayDebounceTimer);
  1075. }
  1076. return RT_EOK;
  1077. }
  1078. /****************** 初始化函数 ******************/
  1079. int RayDualTriggerInit(void)
  1080. {
  1081. /* GPIO模式配置 */
  1082. rt_pin_mode(RayTigA, PIN_MODE_INPUT_PULLDOWN);
  1083. rt_pin_mode(RayTigB, PIN_MODE_INPUT_PULLDOWN);
  1084. /* 创建防抖定时器 */
  1085. RayDebounceTimer = rt_timer_create("RayDebounce",
  1086. RayDebounceHandler,
  1087. RT_NULL,
  1088. 10, // 10ms防抖
  1089. RT_TIMER_FLAG_ONE_SHOT);
  1090. /* 创建序列检测定时器(新增) */
  1091. RaySequenceTimer = rt_timer_create("RaySequence",
  1092. RaySequenceHandler,
  1093. RT_NULL,
  1094. 200, // 初始50ms超时
  1095. RT_TIMER_FLAG_ONE_SHOT);
  1096. /* 绑定双中断 */
  1097. rt_pin_attach_irq(RayTigA, PIN_IRQ_MODE_RISING, RayIrqHandlerA, RT_NULL);
  1098. rt_pin_attach_irq(RayTigB, PIN_IRQ_MODE_RISING, RayIrqHandlerB, RT_NULL);
  1099. /* 使能中断 */
  1100. rt_pin_irq_enable(RayTigA, PIN_IRQ_ENABLE);
  1101. rt_pin_irq_enable(RayTigB, PIN_IRQ_ENABLE);
  1102. /* 读出保存的数据 */
  1103. RayTigCnt = RTC_GET_TigVal();
  1104. rt_kprintf("[Ray] Dual trigger initialized! Current count: %d\n", RayTigCnt);
  1105. return RT_EOK;
  1106. }
  1107. /* 命令导出(命名统一) */
  1108. // MSH_CMD_EXPORT(RayDualTriggerInit, Ray dual trigger demo);
  1109. /********** 红外触发驱动 ************/
  1110. void ChangeInrMode(void)
  1111. {
  1112. syscfg.en_tigmode = 0;
  1113. ef_set_env_blob("syscfg", (const char *)&syscfg, sizeof(syscfg));
  1114. rt_kprintf("Change Workmod Inr OK\n");
  1115. }
  1116. void ChangeTigMode(void)
  1117. {
  1118. syscfg.en_tigmode = 1;
  1119. ef_set_env_blob("syscfg", (const char *)&syscfg, sizeof(syscfg));
  1120. rt_kprintf("Change Workmod Tig OK\n");
  1121. }
  1122. MSH_CMD_EXPORT(ChangeInrMode, ChangeInrMode);
  1123. MSH_CMD_EXPORT(ChangeTigMode, ChangeTigMode);
  1124. /********** RTU Power Ctl ************/
  1125. static void rtu1(void)
  1126. {
  1127. ctr_RTU_DTU(ON);
  1128. }
  1129. static void rtu0(void)
  1130. {
  1131. ctr_RTU_DTU(OFF);
  1132. }
  1133. static char rturead(void)
  1134. {
  1135. char res = rt_pin_read(RTU_DTU);
  1136. // res ? rt_kprintf("RTU power supply : ON\n") : rt_kprintf("RTU power supply : OFF\n");
  1137. return res;
  1138. }
  1139. static char readrtu(void)
  1140. {
  1141. char res = rt_pin_read(RTU_DTU);
  1142. res ? rt_kprintf("RTU power supply : ON\n") : rt_kprintf("RTU power supply : OFF\n");
  1143. return res;
  1144. }
  1145. MSH_CMD_EXPORT(rtu1, rtu1)
  1146. MSH_CMD_EXPORT(rtu0, rtu0)
  1147. MSH_CMD_EXPORT(readrtu, readrtu)
  1148. /********** RTU Power Ctl ************/
  1149. static char temp[64] = {0};
  1150. #include "cJSON.h"
  1151. extern uint8_t get_mem_per(void);
  1152. void status_Pri(uint8_t type)
  1153. {
  1154. rt_kprintf("CAM_CTL >> %d \n", rt_pin_read(CAM_CTL));
  1155. rt_kprintf("RTU_DTU >> %d \n", rt_pin_read(RTU_DTU));
  1156. // 创建根对象
  1157. cJSON *root = cJSON_CreateObject();
  1158. if (root == NULL)
  1159. {
  1160. // rt_kprintf("return A\n");
  1161. return;
  1162. }
  1163. // 添加 cmd 字段
  1164. cJSON_AddStringToObject(root, "cmd", "data");
  1165. // 创建 ext 对象
  1166. cJSON *ext = cJSON_CreateObject();
  1167. if (ext == NULL)
  1168. {
  1169. cJSON_Delete(root);
  1170. // rt_kprintf("return B\n");
  1171. return;
  1172. }
  1173. sprintf(temp, "%02d-%02d-%02d %02d:%02d:%02d",
  1174. GetDate.Year, GetDate.Month, GetDate.Date,
  1175. GetTime.Hours, GetTime.Minutes, GetTime.Seconds);
  1176. cJSON_AddStringToObject(ext, "当前时间", temp);
  1177. if (workmode != TypeMAX_wx)
  1178. {
  1179. cJSON_AddStringToObject(ext, "工作模式", WorkModeList[workmode].keyword);
  1180. }
  1181. // rt_kprintf("mark A\n");
  1182. switch (workmode)
  1183. {
  1184. case RunTime_wx:
  1185. sprintf(temp, "%d - %d", device_status.collecting_sh1, device_status.collecting_eh1);
  1186. cJSON_AddStringToObject(ext, "时控时间", temp);
  1187. break;
  1188. case RunTime_Tig_wx:
  1189. sprintf(temp, "%d - %d", device_status.collecting_sh1, device_status.collecting_eh1);
  1190. cJSON_AddStringToObject(ext, "触发时间", temp);
  1191. break;
  1192. default:
  1193. break;
  1194. }
  1195. // rt_kprintf("mark B\n");
  1196. sprintf(temp, "未在工作 %d ", Check_Allow_Work());
  1197. (Check_Allow_Work() == res_ok) ? cJSON_AddStringToObject(ext, "当前状态", "工作中") : cJSON_AddStringToObject(ext, "当前状态", temp);
  1198. sprintf(temp, "%d 分 (%d / %d)",
  1199. syscfg.dattim,
  1200. math_timestampe_NEW(&tm_data), INR_DAT);
  1201. cJSON_AddStringToObject(ext, "数据间隔", temp);
  1202. sprintf(temp, "%d 分 (%d / %d)",
  1203. syscfg.photim,
  1204. math_timestampe_NEW(&tm_photo), INR_PIC);
  1205. cJSON_AddStringToObject(ext, "照片间隔", temp);
  1206. sprintf(temp, "%d%%", get_mem_per());
  1207. cJSON_AddStringToObject(ext, "内存使用", temp);
  1208. sprintf(temp, "%d-%d", device_status.rain_status, rain_exit);
  1209. cJSON_AddStringToObject(ext, "雨控状态", temp);
  1210. if (type == 2)
  1211. {
  1212. cJSON_AddStringToObject(ext, "测试", "翻板测试开始");
  1213. }
  1214. if (type == 3)
  1215. {
  1216. cJSON_AddStringToObject(ext, "测试", "上仓门测试开始");
  1217. }
  1218. // rt_kprintf("mark C\n");
  1219. // 将 ext 对象添加到根对象
  1220. cJSON_AddItemToObject(root, "ext", ext);
  1221. // 生成 JSON 字符串
  1222. char *json_str = cJSON_Print(root);
  1223. rt_kprintf("status_Pri > %s", json_str);
  1224. if (json_str != NULL)
  1225. free(json_str);
  1226. if (type != 1)
  1227. {
  1228. char *json_strU = cJSON_PrintUnformatted(root);
  1229. DTU_Write(json_strU);
  1230. if (json_strU != NULL)
  1231. free(json_strU);
  1232. }
  1233. // 清理
  1234. cJSON_Delete(root);
  1235. }
  1236. /**
  1237. * @brief 250826 测试整点匹配
  1238. *
  1239. */
  1240. int get_report_progress(int interval_minutes)
  1241. {
  1242. static uint32_t last_trigger_minute = 0xFFFFFFFF; // 上次触发上报的整点时间(总分钟数)
  1243. static uint32_t current_cycle_start = 0xFFFFFFFF; // 当前周期开始的整点时间
  1244. static uint8_t has_triggered = 0; // 标记当前周期是否已经触发过上报
  1245. int current_minute_total; // 当前时间转换为总分钟数(从0点开始)
  1246. int progress = 0;
  1247. // 刷新RTC时间
  1248. ReFlash_RTC();
  1249. // 计算当前时间从0点开始的总分钟数
  1250. current_minute_total = GetTime.Hours * 60 + GetTime.Minutes;
  1251. // 如果是第一次调用,初始化
  1252. if (last_trigger_minute == 0xFFFFFFFF)
  1253. {
  1254. last_trigger_minute = (current_minute_total / interval_minutes) * interval_minutes;
  1255. current_cycle_start = last_trigger_minute;
  1256. has_triggered = 0;
  1257. }
  1258. // 计算当前周期的期望上报整点时间
  1259. int expected_report_minute = current_cycle_start + interval_minutes;
  1260. if (expected_report_minute >= 1440)
  1261. {
  1262. expected_report_minute -= 1440;
  1263. }
  1264. // 检查是否进入新的周期
  1265. int is_new_cycle = 0;
  1266. if (current_minute_total >= expected_report_minute)
  1267. {
  1268. // 正常情况:当前时间已经超过期望上报时间
  1269. is_new_cycle = 1;
  1270. }
  1271. else if (expected_report_minute - current_minute_total > 1200)
  1272. {
  1273. // 跨天情况:期望上报时间在前一天,当前时间在第二天
  1274. is_new_cycle = 1;
  1275. }
  1276. if (is_new_cycle)
  1277. {
  1278. // 进入新的上报周期
  1279. if (!has_triggered)
  1280. {
  1281. // 新周期尚未触发过上报,返回>=100触发上报
  1282. progress = 100;
  1283. has_triggered = 1;
  1284. last_trigger_minute = expected_report_minute;
  1285. }
  1286. else
  1287. {
  1288. // 已经触发过上报,但可能线程处理较慢,继续返回>100确保不会漏报
  1289. // 计算超时分钟数
  1290. int overtime_minutes;
  1291. if (current_minute_total >= expected_report_minute)
  1292. {
  1293. overtime_minutes = current_minute_total - expected_report_minute;
  1294. }
  1295. else
  1296. {
  1297. overtime_minutes = (1440 - expected_report_minute) + current_minute_total;
  1298. }
  1299. progress = 100 + (overtime_minutes * 100 / interval_minutes);
  1300. }
  1301. // 检查是否需要更新周期开始时间(当超时时间超过一个完整周期时)
  1302. if (progress >= 200)
  1303. {
  1304. // 已经超时超过一个完整周期,需要跳到下一个周期
  1305. int overtime_cycles = (progress - 100) / 100;
  1306. current_cycle_start = expected_report_minute + (overtime_cycles * interval_minutes);
  1307. if (current_cycle_start >= 1440)
  1308. {
  1309. current_cycle_start %= 1440;
  1310. }
  1311. has_triggered = 0; // 重置触发标记,准备触发新的周期
  1312. }
  1313. }
  1314. else
  1315. {
  1316. // 还在当前周期内,计算正常进度
  1317. int elapsed_minutes;
  1318. if (current_minute_total >= current_cycle_start)
  1319. {
  1320. // 正常情况
  1321. elapsed_minutes = current_minute_total - current_cycle_start;
  1322. }
  1323. else
  1324. {
  1325. // 跨天情况:current_cycle_start在前一天,current_minute_total在第二天
  1326. elapsed_minutes = (1440 - current_cycle_start) + current_minute_total;
  1327. }
  1328. progress = elapsed_minutes * 100 / interval_minutes;
  1329. has_triggered = 0; // 重置触发标记
  1330. }
  1331. return progress;
  1332. }
  1333. /**
  1334. * @brief 250826 测试整点匹配
  1335. *
  1336. */
  1337. extern works_def ws_now;
  1338. static void status_(void)
  1339. {
  1340. rt_kprintf("ws_now > %d \n", ws_now);
  1341. rt_kprintf("test_match > %d \n", get_report_progress(3));
  1342. status_Pri(1);
  1343. }
  1344. MSH_CMD_EXPORT(status_, status_);
  1345. void Request_ntp(void)
  1346. {
  1347. rt_thread_mdelay(600);
  1348. char readinfo[] = "{\"request\":\"ntp_time\"}";
  1349. DTU_Write("%s", readinfo);
  1350. rt_kprintf("Request_ntp > %s\n", readinfo);
  1351. rt_thread_mdelay(600);
  1352. }
  1353. void ctr_RTU_DTU(uint8_t status_rtu)
  1354. {
  1355. static uint32_t protect_ON = 0;
  1356. static uint32_t protect_OFF = 0;
  1357. static uint8_t protect_sec = 8;
  1358. uint8_t now = 0;
  1359. if (protect_ON == 0)
  1360. {
  1361. recode_timestampe_NEW(&protect_ON);
  1362. }
  1363. if (protect_OFF == 0)
  1364. {
  1365. recode_timestampe_NEW(&protect_OFF);
  1366. }
  1367. rt_pin_mode(RTU_DTU, PIN_MODE_OUTPUT);
  1368. if (status_rtu == ON)
  1369. {
  1370. now = math_timestampe_NEW(&protect_OFF);
  1371. while (now < protect_sec)
  1372. {
  1373. LOG_W("ctr_RTU_DTU ON wait for %d sec", protect_sec - now);
  1374. rt_thread_mdelay(1000);
  1375. now++;
  1376. }
  1377. rt_pin_write(RTU_DTU, ON);
  1378. recode_timestampe_NEW(&protect_ON);
  1379. }
  1380. else if (Demo_Mode_NEW == 0 && ws_now != ws_KeyTig && (syscfg.not_poweroff == 0)) // 这两种情况下 不允许断电
  1381. {
  1382. now = math_timestampe_NEW(&protect_ON);
  1383. while (now < protect_sec)
  1384. {
  1385. LOG_W("ctr_RTU_DTU OFF wait for %d sec", protect_sec - now);
  1386. rt_thread_mdelay(1000);
  1387. now++;
  1388. }
  1389. LOG_W("RTU电源复位!!!");
  1390. rt_pin_write(RTU_DTU, OFF);
  1391. CTL_CAM0();
  1392. syscfg.rtu_sta = 0;
  1393. sprintf(device_status.net, "1"); // 断电的时候 网络状态置为断开
  1394. recode_timestampe_NEW(&protect_OFF);
  1395. }
  1396. else
  1397. {
  1398. LOG_W("RTU电源复位被打断 ws_now %d , Demo_mode %d\n", ws_now, Demo_Mode_NEW);
  1399. }
  1400. }
  1401. static void tig_plus(void)
  1402. {
  1403. RayTigCnt++;
  1404. }
  1405. MSH_CMD_EXPORT(tig_plus, tig_plus);