| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901 |
- /*
- * Copyright (c) 2006-2021, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2024-08-16 RuoFeng the first version
- */
- /*********************↓ define ↓************************/
- #define DBG_ENABLE
- #define DBG_COLOR
- #define DBG_TAG "sy2"
- #define DBG_LEVEL DBG_INFO
- #include <rtdbg.h>
- #define LOG_INR 10 // 默认的log打印间隔(作用域在本文件)
- #define RTU_OFF_MAX 180
- #define WAIT_NET_MAX 150
- #define ENABLE_WORK (Check_Allow_Work() == res_ok)
- #define NEW_TIMESTAMP tm_to_timestamp()
- /*********************↑ define ↑************************/
- /**
- *
- *
- *
- *
- * */
- /*********************↓ include ↓************************/
- #include <Work_SY2.h>
- #include "rs485.h"
- #include "control.h"
- #include "test.h"
- #include <easyflash.h>
- #include "dtu_uart2.h"
- /*********************↑ include ↑************************/
- /**
- *
- *
- *
- *
- * */
- /*********************↓ extern ↓************************/
- extern Temporal_list Check_Work_time_period(uint8_t coll_ch);
- extern works_def ws_now;
- extern Device_Status_typedef device_status;
- extern void HMI_WRITE(char *fmt, ...);
- extern JD_Test_Sta jts;
- extern Res_def Mtor_Control_ZP(Motor_Ctl_type mct, int8_t ctime);
- extern Sensor sensor[MAX_SENSOR_NUM];
- extern Temporal_list Check_Work_time_period_0oclock(void);
- extern RTC_DateTypeDef GetDate;
- extern RTC_TimeTypeDef GetTime;
- extern uint8_t ReFlash_RTC(void);
- extern void CTL_CAM1(void);
- extern void CTL_CAM0(void);
- extern uint32_t tm_to_timestamp(void);
- extern char Demo_Mode_NEW;
- /*********************↑ extern ↑************************/
- /**
- *
- *
- *
- *
- * */
- /********************↓ declaration ↓***********************/
- static void rtu1(void);
- static void rtu0(void);
- static char rturead(void);
- void Request_ntp(void);
- static void Photo_Base_Save(uint32_t v); // 拍照基点持久化(ENV + RTC备份寄存器)
- static uint32_t Photo_Base_Load(void); // 拍照基点恢复
- /********************↑ declaration ↑***********************/
- /**
- *
- *
- *
- *
- * */
- /*********************↓ global variables ↓************************/
- static uint16_t takephoto_cnt = 0; // 拍照触发计数
- static uint16_t wait_data_cnt = 0; // 上报数据计数
- static uint32_t tm_data = 0; // 计算数据时间
- static uint32_t tm_photo = 0; // 计算图片时间
- volatile SYSCFG syscfg = {0}; // 系统配置
- volatile Limit limit = {0}; // 各种控的开关和参数
- volatile wm_Def workmode = TypeMAX_wx; // 工作模式
- WorkMode_Def WorkModeList[TypeMAX_wx] = // 工作模式类型
- {
- {RunTime_wx, "时控间隔模式"}};
- volatile uint16_t RayTigCnt = 0; // 红外触发计数
- volatile static char RayTiged = 0; // 红外已触发过
- volatile static char RayOneLess = 0; // 红外触发记录
- volatile char CamFree = 1; // 相机空闲状态
- volatile uint16_t INR_PIC = 0; // 图片上传间隔
- volatile uint16_t INR_DAT = 0; // 图片上传间隔
- volatile char stop_getinfo = 0; // dtuwrite时暂停 getinfo
- static uint8_t rain_exit = 0; // 雨控退出进度
- volatile char errcnt_getinfo = 0; // err计数
- // volatile char RTUGetUp = 0; // RTU上电开机
- /*********************↑ global variables ↑************************/
- /**
- *
- *
- *
- *
- * */
- /**
- * @brief
- *
- * @return int8_t -1(超时) >1(进度百分比)
- */
- // int8_t Get_luxworkTime(void)
- //{
- // // ReFlash_RTC();
- // //
- // // uint32_t start = 0, now = 0;
- // //
- // // start = lwork.start_time.Hours * 60 + lwork.start_time.Minutes;
- // // now = GetTime.Hours * 60 + GetTime.Minutes;
- // //
- // // if (abs(GetTime.Hours - lwork.start_time.Hours) >= 10 && GetTime.Hours < lwork.start_time.Hours)
- // // {
- // // now += 1440;
- // // }
- // // if ((now - start) > (limit.LuxTime * 60))
- // // {
- // // return -2;
- // // }
- // // else
- // // {
- // // LOG_I("luxtime %d%% \n", ((now - start) * 100) / (limit.LuxTime * 60));
- // // return ((now - start) * 100) / (limit.LuxTime * 60);
- // // }
- //
- // return -1;
- // }
- /**
- * @brief Get the Coll Info object
- *
- * @return uint8_t persen
- */
- uint8_t GetCollInfo(void)
- {
- // uint16_t inr = 0;
- // (syscfg.photim >= 5) ? (inr = syscfg.photim - 1) : (inr = TakeINR);
- /* 直接按原始时间戳计算秒差, 不再调用 math_timestampe_NEW(避免其超窗时重置 tm_photo) */
- ReFlash_RTC();
- uint32_t now = NEW_TIMESTAMP;
- uint32_t last = tm_photo;
- uint32_t diff = (now > last) ? (now - last) : 0;
- if (INR_PIC == 0)
- {
- return 0;
- }
- return (diff * 100) / (INR_PIC);
- }
- /**
- * @brief 获取晨曦模式工作进度 不在工作范围 返回负数
- *
- * @return int8_t val(-1 未开始工作 -2 参数校验失败)
- */
- int8_t Get_swork_percent(void)
- {
- uint32_t start = 0, end = 0, temp1 = 0, now = 0;
- now = GetTime.Hours * 3600 + GetTime.Minutes * 60 + GetTime.Seconds;
- start = device_status.collecting_sh1 * 3600;
- end = device_status.collecting_eh1 * 3600;
- if (now < start && now > end)
- {
- return -1;
- }
- if (device_status.collecting_sh1 > device_status.collecting_eh1)
- {
- end += (24 * 3600);
- }
- temp1 = end - start;
- // rt_kprintf("now %d ALL %d\n" , (now - start) , temp1);
- if (((now - start) > temp1) || ((now - start) * 100 / temp1) > 100)
- {
- return -3;
- }
- return (now - start) * 100 / temp1;
- }
- /**
- * @brief 确认当前工作模式
- *
- */
- void Get_work_mode(void)
- {
- /**
- * @brief 开始确认
- *
- */
- static uint8_t ENPrint = 1;
- wm_Def bak = workmode;
- if (syscfg.en_tigmode == 0)
- {
- workmode = RunTime_wx;
- if (ENPrint || bak != workmode)
- {
- rt_kprintf("\n 时控间隔模式 %d-%d 时 > %d\n\n", device_status.collecting_sh1, device_status.collecting_eh1, ws_now);
- bak = workmode;
- ENPrint = 0;
- }
- }
- }
- #define Temp_Tig_MX 20
- /**
- * @brief 检查是否允许工作
- *
- * @return Caw_def 校验值
- */
- Caw_def Check_Allow_Work(void)
- {
- uint16_t log_en_inr = LOG_INR * 3; // 打印log的速度 数值越小 打印越频繁
- static int16_t log_en_cnt = -1;
- rt_thread_mdelay(15);
- Get_work_mode();
- /**
- * @brief 雨控
- *
- */
- // if (device_status.rain_update == 1) // 还需要再改
- // {
- // LOG_W("CAW:雨控\n");
- // device_status.rain_update = 0;
- // if (device_status.rain_status == 0)
- // {
- // device_status.rain_status = 1;
- // Mtor_Control_CM(mct_Foreward); // 关仓门
- // {
- // Recode_e_code(e_rain_tig, 0, "进入雨控 关仓门");
- // char *rain_tig = makeJson_Warn("Rain Tig In", "STA");
- // DTU_Write("%s", rain_tig);
- // rt_free(rain_tig);
- // }
- // }
- // rain_exit = 90;
- // rt_thread_mdelay(1000);
- // return res_Rain;
- // }
- // else if (rain_exit > 0)
- // {
- // rain_exit--;
- // if (rain_exit == 0)
- // {
- // LOG_W(" exit rain , open the door\n");
- // //Mtor_Control_CM(mct_Reversal); // 开仓门
- // {
- // Recode_e_code(e_rain_tig, 1, "退出雨控 开仓门");
- // device_status.rain_status = 0;
- // char *rain_tig = makeJson_Warn("Rain Tig Out", "STA");
- // DTU_Write("%s", rain_tig);
- // rt_free(rain_tig);
- // }
- // }
- // else
- // {
- // LOG_W("ready to exit rain > %d\n", rain_exit);
- // }
- // rt_thread_mdelay(500);
- // return res_Rain;
- // }
- if (device_status.ds != 1) // 250327 新增 关机状态
- {
- if (chk_log_time)
- {
- LOG_I("CAW:ds == 0\n");
- }
- return res_PwrOff;
- }
- switch (workmode)
- {
- /**
- * @brief 时控模式
- *
- */
- case RunTime_wx:
- if ((device_status.collecting_sh1 == device_status.collecting_eh1) ||
- (device_status.collecting_sh1 == 0 && device_status.collecting_eh1 == 24)) // 全天候牛马
- {
- if (chk_log_time)
- {
- LOG_I("CAW:全天候牛马\n");
- }
- }
- else if (device_status.collecting_eh1 < device_status.collecting_sh1) // 跨0点牛马
- {
- if (Check_Work_time_period_0oclock() != tl_Center)
- {
- if (chk_log_time)
- {
- LOG_I("CAW:未在工作时间 0点\n");
- }
- return res_Time;
- }
- }
- else // 正常牛马
- {
- if (Check_Work_time_period(1) != tl_Center)
- {
- if (chk_log_time)
- {
- LOG_I("CAW:未在工作时间\n");
- }
- return res_Time;
- }
- }
- break;
- default:
- break;
- }
- static uint8_t temp_up_cnt = 0;
- static uint8_t temp_dn_cnt = 0;
- /**
- * @brief 温湿度
- *
- */
- // rt_kprintf("sensor[s_Temp].value %d Luxlimit %d\n" , sensor[s_Temp].value , limit.temp_up);
- int32_t temp = 0;
- if (sensor[s_Temp].online >= 1)
- {
- temp = sensor[s_Temp].value;
- }
- else
- {
- temp = atoi(device_status.tempture);
- }
- if (sensor[s_Temp].online >= 1 && temp > (limit.temp_up * 10) && limit.temhumEN == ON)
- {
- if (temp_up_cnt >= Temp_Tig_MX)
- {
- LOG_I("CAW:触发温控上限 %d\n", temp_up_cnt);
- return res_Temp;
- }
- temp_up_cnt++;
- rt_thread_mdelay(1000);
- if (temp_up_cnt >= Temp_Tig_MX)
- {
- if (device_status.temp_status == 0)
- {
- LOG_I("CAW:触发温控上限 %d (%d > %d)\n", temp_up_cnt, temp, limit.temp_up * 10);
- }
- device_status.temp_status = 1;
- return res_Temp;
- }
- }
- else if (temp_up_cnt > 0)
- {
- temp_up_cnt--;
- rt_thread_mdelay(1000);
- if (temp_up_cnt == 0)
- {
- if (device_status.temp_status > 0)
- LOG_I("CAW:解除温控上限\n");
- device_status.temp_status = 0;
- }
- }
- if (sensor[s_Temp].online >= 1 && temp < (limit.temp_dw * 10) && limit.temhumEN == ON)
- {
- if (temp_dn_cnt >= Temp_Tig_MX)
- {
- return res_Temp;
- }
- temp_dn_cnt++;
- rt_thread_mdelay(1000);
- if (temp_dn_cnt >= Temp_Tig_MX)
- {
- if (device_status.temp_status == 0)
- {
- LOG_I("CAW:触发温控下限 %d (%d < %d)\n", temp_dn_cnt, temp, limit.temp_dw * 10);
- }
- device_status.temp_status = 2;
- return res_Temp;
- }
- }
- else if (temp_dn_cnt > 0)
- {
- temp_dn_cnt--;
- rt_thread_mdelay(1000);
- if (temp_dn_cnt == 0)
- {
- if (device_status.temp_status > 0)
- LOG_I("CAW:解除温控下限\n");
- device_status.temp_status = 0;
- }
- }
- /**
- * @brief 温湿度
- *
- */
- Check_TestFree();
- return res_ok;
- }
- extern uint8_t stopreflashTakePhoto;
- extern uint8_t holdon_stareflash;
- /**
- * @brief 刷新工作状态
- *
- */
- void ReflashWorkSta(void)
- {
- if (ws_now >= ws_typemax)
- {
- rt_kprintf("ReflashWorkSta illegl wstype\n");
- }
- if (holdon_stareflash)
- {
- return;
- }
- work_day_def work_day = {0};
- switch (ws_now)
- {
- case ws_standby:
- HMI_WRITE("workSta.workinfo.txt=\"待机中...\"");
- break;
- // res_ok = 0, // 没问题
- // res_Time, // 时控
- // res_Light, // 光控
- // res_TempH, // 温湿度
- // res_Rain // 雨控
- case ws_wait0:
- switch (Check_Allow_Work())
- {
- case res_ok:
- HMI_WRITE("workSta.workinfo.txt=\"达到工作条件\"");
- break;
- case res_Time:
- HMI_WRITE("workSta.workinfo.txt=\"未达工作条件 - 时控\"");
- break;
- case res_Light:
- HMI_WRITE("workSta.workinfo.txt=\"未达工作条件 - 光控\"");
- break;
- case res_Temp:
- HMI_WRITE("workSta.workinfo.txt=\"未达工作条件 - 温控\"");
- break;
- case res_Humi:
- HMI_WRITE("workSta.workinfo.txt=\"未达工作条件 - 湿控\"");
- break;
- case res_Temp_D:
- HMI_WRITE("workSta.workinfo.txt=\"未达工作条件 - 温控(基于定位)\"");
- break;
- case res_Humi_D:
- HMI_WRITE("workSta.workinfo.txt=\"未达工作条件 - 湿控 (基于定位)\"");
- break;
- case res_Rain:
- HMI_WRITE("workSta.workinfo.txt=\"未达工作条件 - 雨控\"");
- break;
- default:
- HMI_WRITE("workSta.workinfo.txt=\"未达到工作条件 %d\"", Check_Allow_Work());
- break;
- }
- break;
- case ws_start_coll:
- HMI_WRITE("workSta.workinfo.txt=\"STEP1:收集开始\"");
- break;
- case ws_wait_coll:
- HMI_WRITE("workSta.workinfo.txt=\"STEP2:等待收集完成 %d%%\"", GetCollInfo());
- break;
- case ws_takephoto:
- HMI_WRITE("workSta.workinfo.txt=\"STEP3:开始拍照\"");
- break;
- case ws_jumptake:
- HMI_WRITE("workSta.workinfo.txt=\"STEP4:采集中途退出 %d\"", Check_Allow_Work());
- break;
- case ws_flap:
- HMI_WRITE("workSta.workinfo.txt=\"STEP5:翻板中\"");
- break;
- case ws_once_finsh:
- HMI_WRITE("workSta.workinfo.txt=\"STEP6:单次工作循环结束\"");
- break;
- case ws_finsh:
- ef_get_env_blob("work_day", &work_day, sizeof(work_day), NULL);
- HMI_WRITE("workSta.workinfo.txt=\"今日工作周期结束 %02d.%02d.%02d\"", work_day.year % 100, work_day.month, work_day.day);
- break;
- default:
- break;
- }
- }
- static void TigTakePho(void)
- {
- device_status.work_status = 3;
- LOG_W("STEP3 :takephoto");
- ws_now = ws_takephoto;
- ctr_led(ON);
- DTU_Write("takephoto.mp3");
- // 延时
- rt_thread_delay(1000);
- Hk_Take_io(1);
- Request_ntp();
- if (jts.switchled_test != ON && RunTime_wx == workmode)
- {
- ctr_led(OFF);
- }
- else
- {
- LOG_W("STEP4 :jump takephoto");
- ws_now = ws_jumptake;
- rt_thread_delay(3000);
- if (jts.switchled_test != ON && RunTime_wx == workmode)
- {
- ctr_led(OFF);
- }
- }
- takephoto_cnt = 0;
- }
- /**
- * @brief 执行一次主要功能
- *
- */
- void work_mode_pkg(void)
- {
- #define cleek_A 3
- #define cleek_B 9
- ctr_led(ON);
- for (char a = 0; a < 24; a++)
- {
- rt_thread_mdelay(1000);
- rt_kprintf("work_mode_pkg waiting %d \n" , a);
- }
-
- Mtor_Control_CM(mct_Foreward, 1500); // 复位
- LOG_W("STEP3 :Mtor_Control_ZP A1");
- Mtor_Control_ZP(mct_Foreward, 0);
- rt_thread_mdelay(1500);
- LOG_W("STEP3 :Mtor_Control_ZP A2");
- Mtor_Control_ZP(mct_Foreward, 0);
- Mtor_Control_CM(mct_Reversal, 1500); // 顶住
- LOG_W("STEP4 :takephoto A");
- rt_thread_mdelay(3500);
- TigTakePho();
- Mtor_Control_CM(mct_Foreward, 1500); // 复位
- LOG_W("STEP5 : Mtor_Control_ZP B1");
- Mtor_Control_ZP(mct_Foreward, 0);
- rt_thread_mdelay(1000);
- LOG_W("STEP5 : Mtor_Control_ZP B2");
- Mtor_Control_ZP(mct_Foreward, 0);
- rt_thread_mdelay(1000);
- LOG_W("STEP5 : Mtor_Control_ZP B3");
- Mtor_Control_ZP(mct_Foreward, 0);
- rt_thread_mdelay(1000);
- LOG_W("STEP5 : Mtor_Control_ZP B4");
- Mtor_Control_ZP(mct_Foreward, 0);
- rt_thread_mdelay(1000);
- LOG_W("STEP6 :takephoto B");
- TigTakePho();
- Mtor_Control_CM(mct_Foreward, 1500); // 复位
- // rt_thread_mdelay(1000);
- LOG_W("STEP5 : Mtor_Control_ZP B5");
- Mtor_Control_ZP(mct_Foreward, 0);
- Mtor_Control_CM(mct_Reversal, 1500); // 顶住
- LOG_W("STEP7 :one cycle finsh");
- ws_now = ws_once_finsh;
- rt_thread_mdelay(1000);
- }
- /**
- * @brief 记录当前时刻
- *
- * @param time 时间戳
- */
- void recode_timestampe_NEW(uint32_t *tim)
- {
- ReFlash_RTC();
- // 拍照基点只能由"定时触发"推进(工作窗口内到点 / 待机定点 / 退出窗口补拍);
- // 手动与测试拍照(按键手动模式、立即拍照测试、一键测试)一律不得改动基点,
- // 否则会把下次定时拍照的时间基准带偏。
- if (tim == &tm_photo &&
- (ws_now == ws_KeyTig || jts.takephoto_test == ON || jts.autotest == ON))
- {
- LOG_W("photo base NOT advance (manual/test mode)\n");
- rt_thread_mdelay(1000);
- return;
- }
- *tim = NEW_TIMESTAMP;
- if (tim == &tm_photo)
- {
- rt_kprintf("recode_timestampe (photo) > %d sec\n", *tim);
- Photo_Base_Save(*tim); // 持久化拍照时间基点: ENV + RTC备份寄存器(重启/升级都不丢)
- }
- else if (tim == &tm_data)
- {
- rt_kprintf("recode_timestampe (data ) > %d sec\n", *tim);
- }
- rt_thread_mdelay(1000);
- }
- /**
- * @brief 计算差值
- *
- * @param time 时间戳
- * @return uint32_t 差值
- */
- uint32_t math_timestampe_NEW(uint32_t *tim)
- {
- // uint16_t log_en_inr = LOG_INR * 3; // 打印log的速度 数值越小 打印越频繁
- // static int16_t log_en_cnt = -1;
- static struct tm tm_bak;
- static char err_cnt = 0;
- char time_bak[30] = {0};
- if (*tim == NEW_TIMESTAMP)
- {
- rt_thread_mdelay(1000);
- }
- ReFlash_RTC();
- uint32_t now = NEW_TIMESTAMP;
- uint32_t val = (now - *tim);
- if (val > 0 && val < ((syscfg.dattim + syscfg.photim) * 60))
- {
- // if (chk_log_time)
- // {
- // if (tim == &tm_photo)
- // {
- // rt_kprintf("math_timestampe (photo) > %d sec\n", val);
- // }
- // else
- // {
- // rt_kprintf("math_timestampe (data ) > %d sec\n", val);
- // }
- // }
- tm_bak.tm_year = GetDate.Year;
- tm_bak.tm_mon = GetDate.Month;
- tm_bak.tm_yday = GetDate.Date;
- tm_bak.tm_hour = GetTime.Hours;
- tm_bak.tm_min = GetTime.Minutes;
- tm_bak.tm_sec = GetTime.Seconds;
- err_cnt = 0;
- return val;
- }
- else
- {
- if (GetDate.Year > 200)
- {
- sprintf(time_bak, "%02d-%02d-%02d %02d:%02d:%02d",
- tm_bak.tm_year,
- tm_bak.tm_mon,
- tm_bak.tm_yday,
- tm_bak.tm_hour,
- tm_bak.tm_min,
- tm_bak.tm_sec);
- if (tm_bak.tm_year > 0 && tm_bak.tm_year < 200)
- {
- LOG_W("Write bak time %s!", time_bak);
- EXE_NTP_SETTIME(&tm_bak);
- }
- err_cnt++;
- if (err_cnt == 5)
- {
- Recode_e_code(e_rtc_fail, 0x9D, time_bak);
- }
- if (err_cnt > 30)
- {
- rt_hw_cpu_reset();
- }
- }
- if (tim == &tm_photo)
- {
- rt_kprintf("math_timestampe fail (photo) > %d (now : %d >>> tim : %d) \n", val, now, *tim);
- recode_timestampe_NEW(tim);
- }
- else
- {
- rt_kprintf("math_timestampe fail (data ) > %d (now : %d >>> tim : %d) \n", val, now, *tim);
- recode_timestampe_NEW(tim);
- }
- }
- return 0;
- }
- /* ==================== 拍照定时触发(间隔N天 + 指定时分) ==================== */
- #define TIMESTAMP_2000 946684800UL // 2000-01-01 00:00:00 (Unix秒), 时间戳有效性判定下限
- #define TIMESTAMP_MAX_VALID 4102444800UL // 2100-01-01 00:00:00, 有效性上限(防备份区掉电读出0xFFFFFFFF)
- #define PHO_NEAR_SEC 300 // 接近拍照时刻提前量(秒), 用于保持RTU上电
- /* ==================== 拍照基点持久化 ==================== */
- #define PHO_BASE_MAGIC 0x5048U // BKP有效性魔数('P''H'), 备份区被清/掉电后内容不可信, 靠它判定
- /**
- * @brief 写入拍照基点(ENV 与 RTC备份寄存器双写)
- *
- * ENV : 内部Flash分区 -> 整机断电(含VBAT)也不丢; 但固件升级可能擦掉
- * BKP : RTC备份区 -> 升级不受影响; 但靠VBAT供电, 电池耗尽/更换会丢
- * 两处同时写同一值, 任一处失效都能从另一处恢复。F1备份寄存器为16位, 故拆高低两个。
- * 魔数最后写: 备份区被清/掉电后内容不可信, 只有魔数匹配才认那两个寄存器的值。
- */
- static void Photo_Base_Save(uint32_t v)
- {
- if (ef_set_env_blob("tm_photo", &v, sizeof(v)) != EF_NO_ERR)
- {
- LOG_E("tm_photo ENV save FAIL\n");
- }
- BSP_Write_RTC_Reg(PhotoBase_DR10, Reg_Low_16, 0); // 先失效, 防止读到半更新的值
- BSP_Write_RTC_Reg(PhotoBase_DR8, Reg_Low_16, v & 0xFFFFUL);
- BSP_Write_RTC_Reg(PhotoBase_DR9, Reg_Low_16, (v >> 16) & 0xFFFFUL);
- BSP_Write_RTC_Reg(PhotoBase_DR10, Reg_Low_16, PHO_BASE_MAGIC); // 再提交
- }
- /**
- * @brief 读取拍照基点(ENV + RTC备份寄存器双源)
- *
- * 取两者中"合法且较大"的那个: 基点是单调递增的时间戳, 取大者即最近一次成功写入。
- * 这样 ENV 被升级擦掉、或 BKP 因VBAT掉电变成垃圾值, 都能自动绕开。
- *
- * @return uint32_t 基点(Unix秒); 两处均无效时返回 0
- */
- static uint32_t Photo_Base_Load(void)
- {
- uint32_t env_v = 0;
- uint32_t bkp_v = 0;
- if (ef_get_env_blob("tm_photo", &env_v, sizeof(env_v), NULL) != sizeof(env_v))
- {
- env_v = 0;
- }
- if (BSP_Read_RTC_Reg(PhotoBase_DR10, Reg_Low_16) == PHO_BASE_MAGIC) // 魔数不符视为无记录
- {
- bkp_v = ((BSP_Read_RTC_Reg(PhotoBase_DR9, Reg_Low_16) & 0xFFFFUL) << 16)
- | (BSP_Read_RTC_Reg(PhotoBase_DR8, Reg_Low_16) & 0xFFFFUL);
- }
- if (env_v < TIMESTAMP_2000 || env_v > TIMESTAMP_MAX_VALID)
- {
- env_v = 0;
- }
- if (bkp_v < TIMESTAMP_2000 || bkp_v > TIMESTAMP_MAX_VALID)
- {
- bkp_v = 0;
- }
- return (env_v > bkp_v) ? env_v : bkp_v;
- }
- /**
- * @brief 计算本次拍照的目标触发时刻(Unix秒, 本地时间)
- *
- * 判定基准: 取上次拍照结束【当天 00:00:00】+ 间隔天数 + 目标时分。
- * - 基于Unix秒连续运算, 跨月/跨年/闰年天然正确;
- * - 基准取"当天0点"而非"拍照完成时刻", 拍照耗时不影响下次触发时刻, 周期稳定。
- *
- * @return uint32_t 目标时刻; RTC未同步或上次拍照时间戳无效时返回 0
- */
- static uint32_t Get_Photo_Target(void)
- {
- if (GetDate.Year <= 20) // RTC 未同步(年<2021), 不计算
- {
- return 0;
- }
- uint32_t last = tm_photo; // 上次拍照结束时间戳
- if (last < TIMESTAMP_2000) // 上次拍照时间戳无效(未初始化/异常)
- {
- return 0;
- }
- /* 参数兜底(正常流程由开机校验保证合法, 此处仅防御) */
- uint32_t day = (syscfg.pho_inr_day >= PHO_INR_DAY_MIN && syscfg.pho_inr_day <= PHO_INR_DAY_MAX) ? syscfg.pho_inr_day : PHO_INR_DAY_DEF;
- uint32_t hour = (syscfg.pho_t_hour <= 23) ? syscfg.pho_t_hour : PHO_T_HOUR_DEF;
- uint32_t min = (syscfg.pho_t_min <= 59) ? syscfg.pho_t_min : PHO_T_MIN_DEF;
- uint32_t last_day0 = last - (last % 86400UL); // 上次拍照当天 00:00:00(本地无夏令时)
- return last_day0 + day * 86400UL
- + hour * 3600UL + min * 60UL;
- }
- /**
- * @brief 时间戳(Unix秒, 本地) 格式化为 "MM-DD HH:MM:SS"
- *
- * 与 tm_to_timestamp() / Get_Photo_Target() 同一时基(本地, 无夏令时)。
- */
- static void Photo_Tm_Str(uint32_t tm, char *buf, uint16_t len)
- {
- if (tm < TIMESTAMP_2000)
- {
- rt_snprintf(buf, len, "--");
- return;
- }
- uint32_t days = tm / 86400UL;
- uint32_t sec = tm % 86400UL;
- uint16_t year = 1970;
- while (1)
- {
- uint16_t dy = ((year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? 366 : 365);
- if (days < dy)
- {
- break;
- }
- days -= dy;
- year++;
- }
- const uint8_t mdays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
- uint8_t mon = 0;
- while (1)
- {
- uint8_t dy = mdays[mon];
- if (mon == 1 && (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)))
- {
- dy = 29;
- }
- if (days < dy)
- {
- break;
- }
- days -= dy;
- mon++;
- }
- rt_snprintf(buf, len, "%02d-%02d %02d:%02d:%02d",
- mon + 1, (uint8_t)(days + 1),
- (uint8_t)(sec / 3600UL), (uint8_t)((sec % 3600UL) / 60UL), (uint8_t)(sec % 60UL));
- }
- /**
- * @brief 是否到达拍照触发时刻
- *
- * @return uint8_t 1-应触发拍照 0-未到时刻
- */
- uint8_t Check_Photo_Trigger(void)
- {
- ReFlash_RTC();
- uint32_t target = Get_Photo_Target();
- if (target == 0)
- {
- return 0;
- }
- uint32_t now = NEW_TIMESTAMP;
- return (now >= target) ? 1 : 0;
- }
- /**
- * @brief 是否接近拍照触发时刻(提前 PHO_NEAR_SEC 秒)
- *
- * 用于数据上报后"接近拍照时刻不再断电", 避免拍照前重新给RTU上电。
- *
- * @return uint8_t 1-接近拍照时刻 0-远离
- */
- uint8_t Check_Photo_Near(void)
- {
- ReFlash_RTC();
- uint32_t target = Get_Photo_Target();
- if (target == 0)
- {
- return 0;
- }
- uint32_t now = NEW_TIMESTAMP;
- return (now + PHO_NEAR_SEC >= target) ? 1 : 0;
- }
- /**
- * @brief 拍照定时参数合法性校验(开机读取后调用)
- *
- * 三个参数全为0 -> 恢复默认(间隔1天 21:00);
- * 单个参数越界 -> 恢复默认值并保存。
- */
- void Check_Photo_Param_Valid(void)
- {
- uint8_t save = 0;
- if (syscfg.pho_inr_day == 0 && syscfg.pho_t_hour == 0 && syscfg.pho_t_min == 0)
- {
- syscfg.pho_inr_day = PHO_INR_DAY_DEF;
- syscfg.pho_t_hour = PHO_T_HOUR_DEF;
- syscfg.pho_t_min = PHO_T_MIN_DEF;
- save = 1;
- LOG_W("photo param all-zero, SET DEF (%d天 %02d:%02d)", syscfg.pho_inr_day, syscfg.pho_t_hour, syscfg.pho_t_min);
- }
- else
- {
- if (syscfg.pho_inr_day < PHO_INR_DAY_MIN || syscfg.pho_inr_day > PHO_INR_DAY_MAX)
- {
- syscfg.pho_inr_day = PHO_INR_DAY_DEF;
- save = 1;
- LOG_W("pho_inr_day invalid, SET DEF");
- }
- if (syscfg.pho_t_hour > 23)
- {
- syscfg.pho_t_hour = PHO_T_HOUR_DEF;
- save = 1;
- LOG_W("pho_t_hour invalid, SET DEF");
- }
- if (syscfg.pho_t_min > 59)
- {
- syscfg.pho_t_min = PHO_T_MIN_DEF;
- save = 1;
- LOG_W("pho_t_min invalid, SET DEF");
- }
- }
- if (save)
- {
- ef_set_env_blob("syscfg", &syscfg, sizeof(syscfg));
- }
- }
- /**
- * @brief 定点拍照的拦截条件(与时控窗口无关, 只为硬安全)
- *
- * @return char * NULL-可拍照; 否则返回被拦截的中文原因
- */
- static char *Photo_Block_Reason(void)
- {
- if (device_status.ds != 1)
- {
- return "设备已关机";
- }
- if (Demo_Mode_NEW == 1)
- {
- return "演示模式";
- }
- if (ws_now == ws_KeyTig)
- {
- return "手动触发模式";
- }
- if (device_status.bat_status == 1)
- {
- return "电池保护";
- }
- // 测试进行中不得掺和: 否则基点不推进(见 recode_timestampe_NEW 的护栏)会导致反复触发
- if (jts.takephoto_test == ON || jts.autotest == ON)
- {
- return "测试进行中";
- }
- return RT_NULL;
- }
- /**
- * @brief 时控窗口外的定点拍照(间隔N天 + 指定时分)
- *
- * 拍照不再受工作时控窗口约束: 到点即自管上电 -> 执行一次工作包 -> 下电。
- * 触发判定只用 syscfg.pho_inr_day / pho_t_hour / pho_t_min, 不看时控时间。
- * 被硬安全条件拦截时不重置基点, 条件解除后仍会补拍。
- *
- * @return uint8_t 1-本次执行了拍照 0-未到触发时刻或被拦截
- */
- static uint8_t Photo_Pkg_OnStandby(void)
- {
- if (Check_Photo_Trigger() == 0)
- {
- return 0;
- }
- char *block = Photo_Block_Reason();
- if (block != RT_NULL)
- {
- LOG_W("STANDBY :photo blocked by %s\n", block);
- return 0;
- }
- LOG_I("STANDBY :photo trig , out of work window\n");
- /* 拍照前把 RTU/相机/补光灯拉起(与工作窗口内同一套时序) */
- if (rt_pin_read(CAM_CTL) != ON || rt_pin_read(RTU_DTU) != ON)
- {
- ctr_RTU_DTU(ON);
- CTL_CAM1();
- ctr_led(ON);
- for (uint16_t a = 0; a < 45; a++)
- {
- rt_thread_mdelay(1000);
- rt_kprintf("wait for RTU start S1\n");
- }
- }
- /* 基点先重置: 不论成败都按本次起算, 避免失败后每秒重入 */
- recode_timestampe_NEW(&tm_photo);
- Recode_e_code(e_work_mode_pkg, 2, "时控外执行一次工作包");
- work_mode_pkg(); // 执行一次工作包
- ctr_RTU_DTU(OFF);
- CTL_CAM0();
- ctr_led(OFF);
- return 1;
- }
- /**
- * @brief 简易的数据上报,用于在等待图片上报过程中检查是否需要数据上报
- *
- */
- void Updata_INR_Simple(void)
- {
- INR_DAT = syscfg.dattim * 60 - 10; // 减去30 消除上报所耗时间
- if (math_timestampe_NEW(&tm_data) > INR_DAT)
- {
- LOG_I(" >>> watting mode > STEP A start report data C\n");
- recode_timestampe_NEW(&tm_data); // 此时重置时间戳
- wait_data_cnt = 0;
- UpLoad_Data(0);
- }
- }
- /**
- * @brief Construct a new Updata_INR object
- *
- * @param type > enable power off
- */
- static uint16_t Updata_INR(uint8_t type)
- {
- static uint16_t rtuon_cnt = 0; // 非工作模式时 rtu上电时间记录
- static char Once_poweroff = 1;
- /**
- * @brief ↓↓↓ 不在工作模式的时候 间隔上线上报数据 在此处实现 ↓↓↓
- *
- */
- INR_DAT = syscfg.dattim * 60 - 10; // 减去30 消除上报所耗时间
- wait_data_cnt++;
- if (wait_data_cnt >= INR_DAT || (math_timestampe_NEW(&tm_data) > INR_DAT))
- {
- if (wait_data_cnt >= INR_DAT)
- {
- LOG_I(" >>> watting mode > STEP A start report data A\n");
- }
- else
- {
- LOG_I(" >>> watting mode > STEP A start report data B\n");
- }
- recode_timestampe_NEW(&tm_data); // 此时重置时间戳
- // recode_timestampe(&tm_photo); // 记录数据上报开始时间
- wait_data_cnt = 0;
- ctr_RTU_DTU(ON);
- sprintf(device_status.net, "1"); // 去掉网络状态
- while (++wait_data_cnt < (WAIT_NET_MAX / 2))
- {
- SendReadInfo('D');
- if (atoi(device_status.net) == 0)
- {
- LOG_I(" >>> watting mode > STEP B1 RTU net get up\n");
- rt_thread_mdelay(2000);
- rt_thread_mdelay(10000); // 留有指令下发时间
- UpLoad_Data(0);
- rt_thread_mdelay(2000);
- break;
- }
- rt_thread_mdelay(1000);
- }
- if (wait_data_cnt >= (WAIT_NET_MAX / 2))
- {
- UpLoad_Data(0);
- LOG_W(" >>> watting mode > STEP B2 RTU net get failed\n");
- Recode_e_code(e_rtu_net_fail, 1, "间隔上报时联网失败 > B2");
- rt_thread_mdelay(5000);
- }
- wait_data_cnt = 0;
- if (Check_Photo_Near() && (Check_Allow_Work() == res_ok)) // 接近拍照时刻 不再断电
- {
- LOG_I("CLOSE UP_PIC , JUMP RTU0");
- }
- else
- {
- ctr_RTU_DTU(OFF);
- }
- Request_ntp();
- }
- if (math_timestampe_NEW(&tm_data) == 0)
- {
- LOG_W("math_timestampe_NEW tm_data fail ,SET NOW");
- }
- /**
- * @brief ↑↑↑ 不在工作模式的时候 间隔上线上报数据 在此处实现 ↑↑↑
- *
- */
- /**
- * @brief ↓↓↓ 首次上电后 留有三分钟数据上报 指令下发时间 ↓↓↓
- *
- */
- if (rturead() && Once_poweroff)
- {
- rtuon_cnt++;
- if (rtuon_cnt >= RTU_OFF_MAX)
- {
- LOG_I("RTU ON Time out of range , now turn it off A\n\n");
- ctr_RTU_DTU(OFF);
- rtuon_cnt = 0;
- Once_poweroff = 0;
- }
- }
- /**
- * @brief ↑↑↑ 首次上电后 留有三分钟数据上报 指令下发时间 ↑↑↑
- *
- */
- return wait_data_cnt;
- }
- void KeyTigCheck(void)
- {
- #define manual_mode_MX 60
- #define demo_mode_MX 120
- uint16_t log_en_inr = LOG_INR * 5; // 打印log的速度 数值越小 打印越频繁
- static int16_t log_en_cnt = -1;
- uint32_t cnt = 0;
- if (ws_now == ws_KeyTig)
- {
- Recode_e_code(e_manual_mode, 0, "进入手动触发模式");
- while (cnt++ < 60 * manual_mode_MX)
- {
- rt_thread_mdelay(1000);
- if (ws_now != ws_KeyTig)
- {
- break;
- }
- if (chk_log_time)
- rt_kprintf("处于手动触发模式 %d/%d\n", cnt, manual_mode_MX * 60);
- if (cnt % 30 == 0)
- {
- SendReadInfo('E');
- }
- }
- Recode_e_code(e_manual_mode, 1, "退出手动触发模式");
- }
- if (Demo_Mode_NEW == 1)
- {
- Recode_e_code(e_demo_mode, 0, "进入演示模式");
- cnt = 0;
- rt_kprintf("演示模式 暂停工作 %d / %d\n", cnt, demo_mode_MX * 60);
- while (cnt++ < demo_mode_MX * 60)
- {
- rt_thread_mdelay(1000);
- if (Demo_Mode_NEW == 0)
- {
- break;
- }
- if (cnt % 100 == 0)
- {
- rt_kprintf("演示模式 暂停工作 %d / %d\n", cnt, demo_mode_MX * 60);
- }
- ws_now = ws_demo;
- ctr_RTU_DTU(ON);
- CTL_CAM1();
- }
- Demo_Mode_NEW = 0;
- Recode_e_code(e_demo_mode, 1, "退出演示模式");
- }
- }
- /**
- * @brief 天牛工作流程
- *
- */
- void WorkTask_SY2(void)
- {
- uint16_t log_en_inr = LOG_INR * 5; // 打印log的速度 数值越小 打印越频繁
- static int16_t log_en_cnt = -1;
- LOG_I(" WorkTask_SY2 ");
- if (Check_Allow_Work() != res_ok)
- {
- if (jts.switchled_test != ON)
- {
- ctr_led(OFF);
- }
- }
- rt_thread_mdelay(1000);
- /* 从 ENV + RTC备份寄存器 双源恢复拍照基点(重启/升级/掉电都不丢, 不推迟下次拍照) */
- tm_photo = Photo_Base_Load();
- if (tm_photo == 0)
- {
- LOG_W("photo base invalid in ENV & BKP\n"); // 老设备/首次, 下方以当前时间起算
- }
- /* 数据上报基点: 仅存内存, 0则重置(频繁上报无需持久化) */
- if (tm_data == 0 && GetDate.Year > 20)
- {
- recode_timestampe_NEW(&tm_data);
- }
- /* 拍照基点: 双源均无有效记录时, 以当前时间起算并持久化 */
- if (tm_photo == 0 && GetDate.Year > 20)
- {
- recode_timestampe_NEW(&tm_photo);
- LOG_I("recode_timestampe INIT");
- }
- while (Check_Allow_Work() != res_ok) // 新增数据上报逻辑(开启rtu 上报一次数据)
- {
- log_en_inr = LOG_INR * 5;
- rt_thread_mdelay(1000);
- KeyTigCheck();
- ws_now = ws_wait0; // 待机
- if (chk_log_time)
- {
- LOG_I("STEP0 :wait work start");
- }
- Photo_Pkg_OnStandby(); // 定点拍照(不受时控窗口约束)
- Updata_INR(1);
- }
- rt_thread_mdelay(1000);
- uint16_t tig_cnt = 0;
- char last_once = 0;
- while (Check_Allow_Work() == res_ok)
- {
- LOG_W("STEP1 :start work > %d > %d ", workmode, takephoto_cnt);
- rt_thread_mdelay(1000);
- device_status.work_status = 1;
- (syscfg.photim >= 5) ? (INR_PIC = (syscfg.photim * 60)) : (INR_PIC = (TakeINR * 60));
- switch (workmode)
- {
- case RunTime_wx:
- log_en_inr = LOG_INR * 5;
- while ((Check_Allow_Work() == res_ok) && (workmode == RunTime_wx))
- {
- if (chk_log_time)
- {
- LOG_W("STEP2 :wait coll finsh %d%%", GetCollInfo());
- }
- KeyTigCheck();
- ws_now = ws_wait_coll;
- rt_thread_mdelay(1000);
- if (Check_Photo_Trigger()) // 拍照部分(间隔N天 + 指定时分)
- {
- LOG_I("Read to takephoto\n");
- recode_timestampe_NEW(&tm_photo);
- if (rt_pin_read(CAM_CTL) != ON || rt_pin_read(RTU_DTU) != ON)
- {
- rt_kprintf("检测到拍照前未开启RTU");
- ctr_RTU_DTU(ON);
- CTL_CAM1();
- ctr_led(ON);
- for (uint16_t a = 0; a < 45; a++)
- {
- rt_thread_mdelay(1000);
- rt_kprintf("wait for RTU start A2\n");
- }
- }
- Recode_e_code(e_work_mode_pkg , 0 ,"执行一次工作包 A");
- work_mode_pkg(); // 执行一次工作包
- last_once = 1;
- takephoto_cnt = 0;
- if (math_timestampe_NEW(&tm_data) > (INR_DAT - 30)) // 接近数据上报 不再断电
- {
- LOG_I("CLOSE UPDATA , JUMP RTU0");
- }
- else
- {
- ctr_RTU_DTU(OFF);
- }
- }
- // else if (math_timestampe_NEW(&tm_photo) >= ((INR_PIC)-WAIT_NET_MAX)) // RTU提前上电
- // {
- // // rt_kprintf("takephoto_cnt close >> %d\n",math_timestampe_NEW(&tm_photo));
- // ctr_RTU_DTU(ON);
- // CTL_CAM1();
- // ctr_led(ON);
- // } USB工业相机 开启速度极快 不需要这么麻烦了
- else // 数据部分
- {
- Updata_INR(0);
- }
- if (GetDate.Year <= 20) // RTC 未同步, 拍照等待(RTC恢复后自动继续)
- {
- LOG_W("RTC not ready , photo wait\n");
- }
- }
- // 时控模式退出后 本次未拍照且已到拍照时刻 则补拍一次(与主触发同一判定, 保持间隔语义)
- if (last_once == 0 && Check_Photo_Trigger())
- {
- recode_timestampe_NEW(&tm_photo);
- if (rt_pin_read(CAM_CTL) != ON || rt_pin_read(RTU_DTU) != ON)
- {
- rt_kprintf("检测到拍照前未开启RTU");
- ctr_RTU_DTU(ON);
- CTL_CAM1();
- ctr_led(ON);
- for (uint16_t a = 0; a < 45; a++)
- {
- rt_thread_mdelay(1000);
- rt_kprintf("wait for RTU start A3\n");
- }
- }
- Recode_e_code(e_work_mode_pkg , 1 ,"执行一次工作包 B");
- work_mode_pkg(); // 执行一次工作包
- takephoto_cnt = 0;
- ctr_RTU_DTU(OFF);
- CTL_CAM0();
- ctr_led(OFF);
- }
- else
- {
- rt_kprintf("photo not trigger, last_once %d\n\n", last_once);
- }
- last_once = 0;
- // rt_kprintf("takephoto_cnt >> %d > %d > %d\n" ,inr , inr * 60 , ((inr * 60) - WAIT_NET_MAX));
- break;
- default:
- break;
- }
- }
- if (jts.switchled_test != ON)
- {
- ctr_led(OFF);
- }
- device_status.work_status = 0;
- device_status.traplampsta = 0;
- }
- MSH_CMD_EXPORT(work_mode_pkg , work_mode_pkg);
- static void TigRay(void)
- {
- RayTiged = 1;
- }
- MSH_CMD_EXPORT(TigRay, TigRay)
- /********** 红外触发驱动 ************/
- /* 触发标志位(Ray开头) */
- static volatile rt_bool_t RayTrigFlagA = RT_FALSE;
- static volatile rt_bool_t RayTrigFlagB = RT_FALSE;
- static rt_timer_t RayDebounceTimer; // 防抖定时器
- static rt_timer_t RaySequenceTimer; // 序列检测定时器(新增)
- /* 防抖定时器回调 */
- static void RayDebounceHandler(void *param)
- {
- // rt_kprintf("[Ray] <%d:%d> Flags cleared by debounce\n", RayTrigFlagA, RayTrigFlagB);
- }
- /* 序列检测定时器回调(新增) */
- static void RaySequenceHandler(void *param)
- {
- rt_kprintf("[Ray] Sequence timeout, flags cleared [A%d | B%d]\n", RayTrigFlagA, RayTrigFlagB);
- RayTrigFlagA = RT_FALSE;
- RayTrigFlagB = RT_FALSE;
- rt_timer_stop(RaySequenceTimer);
- }
- /****************** 优化后的中断回调 ******************/
- /* RayTigA中断回调 */
- static rt_err_t RayIrqHandlerA(void *args)
- {
- if (!RayTrigFlagA)
- {
- RayTrigFlagA = RT_TRUE;
- rt_kprintf("RayIrqHandlerA triggered\n");
- // 如果B已经触发且在50ms内
- if (RayTrigFlagB)
- {
- RayTigCnt++;
- RayTiged = RT_TRUE;
- RayOneLess = RT_TRUE;
- rt_kprintf("[Ray] Item detected! Count: %d\n", RTC_GET_TigVal());
- // 清除标志和定时器
- RayTrigFlagA = RT_FALSE;
- RayTrigFlagB = RT_FALSE;
- rt_timer_stop(RayDebounceTimer);
- rt_timer_stop(RaySequenceTimer);
- }
- else
- {
- // 启动防抖定时器
- rt_timer_start(RayDebounceTimer);
- }
- }
- return RT_EOK;
- }
- /* RayTigB中断回调 */
- static rt_err_t RayIrqHandlerB(void *args)
- {
- if (!RayTrigFlagB)
- {
- RayTrigFlagB = RT_TRUE;
- rt_kprintf("RayIrqHandlerB triggered\n");
- // 启动序列检测定时器(50ms)
- rt_timer_control(RaySequenceTimer, RT_TIMER_CTRL_SET_TIME, (void *)50);
- rt_timer_start(RaySequenceTimer);
- RayTrigFlagA = RT_FALSE;
- // 启动防抖定时器
- rt_timer_start(RayDebounceTimer);
- }
- return RT_EOK;
- }
- /****************** 初始化函数 ******************/
- int RayDualTriggerInit(void)
- {
- /* GPIO模式配置 */
- rt_pin_mode(RayTigA, PIN_MODE_INPUT_PULLDOWN);
- rt_pin_mode(RayTigB, PIN_MODE_INPUT_PULLDOWN);
- /* 创建防抖定时器 */
- RayDebounceTimer = rt_timer_create("RayDebounce",
- RayDebounceHandler,
- RT_NULL,
- 10, // 10ms防抖
- RT_TIMER_FLAG_ONE_SHOT);
- /* 创建序列检测定时器(新增) */
- RaySequenceTimer = rt_timer_create("RaySequence",
- RaySequenceHandler,
- RT_NULL,
- 200, // 初始50ms超时
- RT_TIMER_FLAG_ONE_SHOT);
- /* 绑定双中断 */
- rt_pin_attach_irq(RayTigA, PIN_IRQ_MODE_RISING, RayIrqHandlerA, RT_NULL);
- rt_pin_attach_irq(RayTigB, PIN_IRQ_MODE_RISING, RayIrqHandlerB, RT_NULL);
- /* 使能中断 */
- rt_pin_irq_enable(RayTigA, PIN_IRQ_ENABLE);
- rt_pin_irq_enable(RayTigB, PIN_IRQ_ENABLE);
- /* 读出保存的数据 */
- RayTigCnt = RTC_GET_TigVal();
- rt_kprintf("[Ray] Dual trigger initialized! Current count: %d\n", RayTigCnt);
- return RT_EOK;
- }
- /* 命令导出(命名统一) */
- // MSH_CMD_EXPORT(RayDualTriggerInit, Ray dual trigger demo);
- /********** 红外触发驱动 ************/
- void ChangeInrMode(void)
- {
- syscfg.en_tigmode = 0;
- ef_set_env_blob("syscfg", (const char *)&syscfg, sizeof(syscfg));
- rt_kprintf("Change Workmod Inr OK\n");
- }
- void ChangeTigMode(void)
- {
- syscfg.en_tigmode = 1;
- ef_set_env_blob("syscfg", (const char *)&syscfg, sizeof(syscfg));
- rt_kprintf("Change Workmod Tig OK\n");
- }
- MSH_CMD_EXPORT(ChangeInrMode, ChangeInrMode);
- MSH_CMD_EXPORT(ChangeTigMode, ChangeTigMode);
- /********** RTU Power Ctl ************/
- static void rtu1(void)
- {
- ctr_RTU_DTU(ON);
- }
- static void rtu0(void)
- {
- ctr_RTU_DTU(OFF);
- }
- static char rturead(void)
- {
- char res = rt_pin_read(RTU_DTU);
- // res ? rt_kprintf("RTU power supply : ON\n") : rt_kprintf("RTU power supply : OFF\n");
- return res;
- }
- static char readrtu(void)
- {
- char res = rt_pin_read(RTU_DTU);
- res ? rt_kprintf("RTU power supply : ON\n") : rt_kprintf("RTU power supply : OFF\n");
- return res;
- }
- MSH_CMD_EXPORT(rtu1, rtu1)
- MSH_CMD_EXPORT(rtu0, rtu0)
- MSH_CMD_EXPORT(readrtu, readrtu)
- /********** RTU Power Ctl ************/
- static char temp[64] = {0};
- #include "cJSON.h"
- extern uint8_t get_mem_per(void);
- void status_Pri(uint8_t type)
- {
- rt_kprintf("CAM_CTL >> %d \n", rt_pin_read(CAM_CTL));
- rt_kprintf("RTU_DTU >> %d \n", rt_pin_read(RTU_DTU));
- // 创建根对象
- cJSON *root = cJSON_CreateObject();
- if (root == NULL)
- {
- // rt_kprintf("return A\n");
- return;
- }
- // 添加 cmd 字段
- cJSON_AddStringToObject(root, "cmd", "data");
- // 创建 ext 对象
- cJSON *ext = cJSON_CreateObject();
- if (ext == NULL)
- {
- cJSON_Delete(root);
- // rt_kprintf("return B\n");
- return;
- }
- sprintf(temp, "%02d-%02d-%02d %02d:%02d:%02d",
- GetDate.Year, GetDate.Month, GetDate.Date,
- GetTime.Hours, GetTime.Minutes, GetTime.Seconds);
- cJSON_AddStringToObject(ext, "当前时间", temp);
- if (workmode != TypeMAX_wx)
- {
- cJSON_AddStringToObject(ext, "工作模式", WorkModeList[workmode].keyword);
- }
- // rt_kprintf("mark A\n");
- switch (workmode)
- {
- case RunTime_wx:
- sprintf(temp, "%d - %d", device_status.collecting_sh1, device_status.collecting_eh1);
- cJSON_AddStringToObject(ext, "时控时间", temp);
- break;
- default:
- break;
- }
- // rt_kprintf("mark B\n");
- sprintf(temp, "未在工作 %d ", Check_Allow_Work());
- (Check_Allow_Work() == res_ok) ? cJSON_AddStringToObject(ext, "当前状态", "工作中") : cJSON_AddStringToObject(ext, "当前状态", temp);
- sprintf(temp, "%d 分 (%d / %d)",
- syscfg.dattim,
- math_timestampe_NEW(&tm_data), INR_DAT);
- cJSON_AddStringToObject(ext, "数据间隔", temp);
- sprintf(temp, "%d天 %02d:%02d",
- syscfg.pho_inr_day, syscfg.pho_t_hour, syscfg.pho_t_min);
- cJSON_AddStringToObject(ext, "照片间隔", temp);
- sprintf(temp, "%d%%", get_mem_per());
- cJSON_AddStringToObject(ext, "内存使用", temp);
- sprintf(temp, "%d-%d", device_status.rain_status, rain_exit);
- cJSON_AddStringToObject(ext, "雨控状态", temp);
- sprintf(temp, "%d-%d", RTC_GET_TigVal() , Get_REMAIN());
- cJSON_AddStringToObject(ext, "卷带计数", temp);
- /* 拍照诊断: 基点 / 下次时刻 / 距触发剩余 / 上次结果(判断"为什么没拍/拍了失败") */
- {
- char tbuf[32] = {0};
- uint32_t tgt = Get_Photo_Target();
- uint32_t now = NEW_TIMESTAMP;
- if (GetDate.Year <= 20)
- {
- cJSON_AddStringToObject(ext, "拍照基点", "时间未同步");
- cJSON_AddStringToObject(ext, "下次拍照", "时间未同步");
- cJSON_AddStringToObject(ext, "距拍照", "--");
- }
- else if (tm_photo < TIMESTAMP_2000)
- {
- cJSON_AddStringToObject(ext, "拍照基点", "未定");
- cJSON_AddStringToObject(ext, "下次拍照", "未定");
- cJSON_AddStringToObject(ext, "距拍照", "--");
- }
- else
- {
- Photo_Tm_Str(tm_photo, tbuf, sizeof(tbuf));
- cJSON_AddStringToObject(ext, "拍照基点", tbuf);
- Photo_Tm_Str(tgt, tbuf, sizeof(tbuf));
- cJSON_AddStringToObject(ext, "下次拍照", tbuf);
- if (tgt <= now)
- {
- sprintf(temp, "已到点 %u 秒 (待触发)", (unsigned int)(now - tgt));
- }
- else
- {
- sprintf(temp, "%u 秒后", (unsigned int)(tgt - now));
- }
- cJSON_AddStringToObject(ext, "距拍照", temp);
- }
- if (photo_stat.res == 0)
- {
- cJSON_AddStringToObject(ext, "上次拍照", "无记录");
- }
- else
- {
- char *r = "未知";
- switch (photo_stat.res)
- {
- case 1:
- r = "成功";
- break;
- case 2:
- r = "失败(图像传输超时)";
- break;
- case 3:
- r = "未执行(相机忙)";
- break;
- case 4:
- r = "进行中";
- break;
- default:
- break;
- }
- Photo_Tm_Str(photo_stat.res_tm ? photo_stat.res_tm : photo_stat.tig_tm, tbuf, sizeof(tbuf));
- sprintf(temp, "%s %s", r, tbuf);
- cJSON_AddStringToObject(ext, "上次拍照", temp);
- }
- /* 到点却没拍时, 这里能看出被哪条硬安全条件拦住 */
- char *blk = Photo_Block_Reason();
- cJSON_AddStringToObject(ext, "拍照拦截", blk ? blk : "无");
- }
- if (type == 2)
- {
- cJSON_AddStringToObject(ext, "测试", "翻板测试开始");
- }
- if (type == 3)
- {
- cJSON_AddStringToObject(ext, "测试", "上仓门测试开始");
- }
- // rt_kprintf("mark C\n");
- // 将 ext 对象添加到根对象
- cJSON_AddItemToObject(root, "ext", ext);
- // 生成 JSON 字符串
- char *json_str = cJSON_Print(root);
- rt_kprintf("status_Pri > %s", json_str);
- if (json_str != NULL)
- free(json_str);
- if (type != 1)
- {
- char *json_strU = cJSON_PrintUnformatted(root);
- DTU_Write(json_strU);
- if (json_strU != NULL)
- free(json_strU);
- }
- // 清理
- cJSON_Delete(root);
- }
- extern works_def ws_now;
- static void status_(void)
- {
- rt_kprintf("ws_now > %d \n", ws_now);
- status_Pri(1);
- }
- MSH_CMD_EXPORT(status_, status_);
- void Request_ntp(void)
- {
- rt_thread_mdelay(600);
- char readinfo[] = "{\"request\":\"ntp_time\"}";
- DTU_Write("%s", readinfo);
- rt_kprintf("Request_ntp > %s\n", readinfo);
- rt_thread_mdelay(600);
- }
- void ctr_RTU_DTU(uint8_t status_rtu)
- {
- static uint32_t protect_ON = 0;
- static uint32_t protect_OFF = 0;
- static uint8_t protect_sec = 8;
- uint8_t now = 0;
- if (protect_ON == 0)
- {
- recode_timestampe_NEW(&protect_ON);
- }
- if (protect_OFF == 0)
- {
- recode_timestampe_NEW(&protect_OFF);
- }
- rt_pin_mode(RTU_DTU, PIN_MODE_OUTPUT);
- if (status_rtu == ON)
- {
- now = math_timestampe_NEW(&protect_OFF);
- while (now < protect_sec)
- {
- LOG_W("ctr_RTU_DTU ON wait for %d sec", protect_sec - now);
- rt_thread_mdelay(1000);
- now++;
- }
- rt_pin_write(RTU_DTU, ON);
- recode_timestampe_NEW(&protect_ON);
- }
- else if (Demo_Mode_NEW == 0 && ws_now != ws_KeyTig && (syscfg.not_poweroff == 0)) // 这两种情况下 不允许断电
- {
- now = math_timestampe_NEW(&protect_ON);
- while (now < protect_sec)
- {
- LOG_W("ctr_RTU_DTU OFF wait for %d sec", protect_sec - now);
- rt_thread_mdelay(1000);
- now++;
- }
- LOG_W("RTU电源复位!!!");
- rt_pin_write(RTU_DTU, OFF);
- CTL_CAM0();
- syscfg.rtu_sta = 0;
- sprintf(device_status.net, "1"); // 断电的时候 网络状态置为断开
- recode_timestampe_NEW(&protect_OFF);
- }
- else
- {
- LOG_W("RTU电源复位被打断 ws_now %d , Demo_mode %d\n", ws_now, Demo_Mode_NEW);
- }
- }
- static void tig_plus(void)
- {
- RayTigCnt++;
- }
- MSH_CMD_EXPORT(tig_plus, tig_plus);
|